molecule-core/docs/edit-history/2026-04-14.md
Hongming Wang 39074cc4ae chore: final open-source cleanup — binary, stale paths, private refs
- Remove compiled workspace-server/server binary from git
- Fix .gitignore, .gitattributes, .githooks/pre-commit for renamed dirs
- Fix CI workflow path filters (workspace-template → workspace)
- Replace real EC2 IP and personal slug in test_saas_tenant.sh
- Scrub molecule-controlplane references in docs
- Fix stale workspace-template/ paths in provisioner, handlers, tests
- Clean tracked Python cache files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 00:38:55 -07:00

27 KiB
Raw Blame History

2026-04-14 — edit history

Summary — tick-2: org-template polish (PRs #50, #52)

Two template-only merges landed this tick. Both touch org-templates/molecule-dev/org.yaml and adjust role behavior inside the default molecule-dev org template — no Go/TS/Python code changed, no new env vars, no new API routes, no test-count drift.

Template tweaks

  • PR #50 chore(template): PM system prompt — treat audit summaries as dispatch triggers, not FYIs — rewrites the PM (Project Manager) role's system prompt so that inbound audit summaries from QA / review loops are treated as actionable dispatch triggers rather than informational FYIs. The PM now routes the summary to the appropriate sub-team instead of acknowledging and stopping. File: org-templates/molecule-dev/org.yaml (PM role system_prompt). Merged commit 14fc30f.
  • PR #52 chore(template): bake working Chromium recipe into UIUX Designer cron (closes #23) — updates the UIUX Designer role's cron setup to install playwright-chromium via the known-good recipe so the scheduled UX-audit job can actually launch a headless browser. Closes issue #23 (cron failed on missing Chromium). File: org-templates/molecule-dev/org.yaml (UIUX Designer role cron / setup commands). Merged commit 347faab.

Not touched

  • No platform (workspace-server/) change — no API route, handler, migration, or env var added.
  • No canvas (canvas/) change.
  • No workspace-template (workspace/) change — the runtime image already ships the base Playwright deps; this PR only fixes the install invocation inside the cron script that the UIUX Designer workspace runs at startup.
  • No MCP server / SDK change.
  • Test counts unchanged from the prior tick (Go 487, Vitest 357, pytest platform 1078, pytest sdk 87, MCP jest per prior tick). Template-only edits cannot shift these; skipped re-measurement.

Doc surface

  • This file created.
  • CLAUDE.md — no change (no new endpoint / env / runtime).
  • PLAN.md — no change (no phase boundary crossed).
  • README.md / README.zh-CN.md — no change (no user-visible surface).

Summary — tick-3: admin test-token + hermes config fix (PRs #53, #54, #55)

Three merges this tick. One adds a new dev-only admin route for E2E scripts, one is the prior-tick doc-sync PR, and one is a one-line template config fix.

PR #53 — feat(platform): GET /admin/workspaces/:id/test-token for E2E (#6)

Merge commit 639c320. Adds a dev/test-only route that mints a fresh bearer token for E2E scripts (closes issue #6, which called out the brittle hand-rolled token logic in the bash E2E harness). Route is hidden by default — it 404s in production unless explicitly enabled.

  • New routeGET /admin/workspaces/:id/test-token. Handler in workspace-server/internal/handlers/admin_test_token.go. 404s unless MOLECULE_ENV != "production" OR MOLECULE_ENABLE_TEST_TOKENS=1. Router wiring in workspace-server/internal/router/router.go.
  • New env varsMOLECULE_ENV (log label, already present in .env.example) and MOLECULE_ENABLE_TEST_TOKENS (explicit override — see .env.example fix below).
  • E2E helpertests/e2e/_lib.sh gains e2e_mint_test_token which calls the new route and exports MOLECULE_TEST_TOKEN for subsequent curl -H "Authorization: Bearer …" calls. Replaces the previous hand-rolled JWT construction in the bash harness.
  • Testsworkspace-server/internal/handlers/admin_test_token_test.go adds the TestAdminTestToken_* quartet (4 tests): prod-default-404, dev-success, explicit-enable-success, not-found-for-missing- workspace-id.
  • Doc updates carried by the PR itselfCLAUDE.md route table gained the new admin row, and the env-var paragraph mentions MOLECULE_ENV / MOLECULE_ENABLE_TEST_TOKENS. Verified on main.

PR #54 — docs: sync documentation with 2026-04-14 tick-2 merges (#50, #52)

Merge commit c9f0a91. Docs-only. Created the tick-2 section of this file (see above) and did not touch any other doc surface. Nothing to re-sync here; the file already records it.

PR #55 — fix(hermes): align config.yaml required_env with executor (HERMES_API_KEY)

Merge commit 0485585. One-line template fix. The hermes runtime's executor reads HERMES_API_KEY (with OPENROUTER_API_KEY as fallback), but the config.yaml required_env: list was still declaring only OPENROUTER_API_KEY, which caused startup validation to succeed even when the operator had neither key set, and to reject valid setups that had only HERMES_API_KEY set. This commit updates the template's required_env: to match the executor's read order.

  • No new env var — HERMES_API_KEY and OPENROUTER_API_KEY already documented.
  • No API / handler / migration change.
  • No test-count impact.

Doc-sync fix (code-review follow-up from #53)

Reviewer called out that MOLECULE_ENABLE_TEST_TOKENS was mentioned in CLAUDE.md (admin route description) but missing from .env.example. Added an explicit entry with a comment noting the prod-hidden default and the two ways to expose the route. This is a true doc-sync fix (code ships the var; example now matches).

Measured test counts this tick

  • Go: go test -v ./... | grep -c "^--- PASS" → 712 (includes subtests). Top-level Test* function count: 713 (713 files grepped). The prior CLAUDE.md number was 695; adding PR #53's TestAdminTestToken_* quartet gives 699, which matches the stated "+4 this tick" and is what CLAUDE.md now records. The raw PASS-line number includes every subtest (t.Run(…)) so it's always higher than the top-level count — both numbers moved by the same +4 delta, which is what we care about.
  • Canvas (Vitest): unchanged — no canvas change in #53/#54/#55. CLAUDE.md still reads 357.
  • Workspace-template (pytest): unchanged — no workspace-template code change. CLAUDE.md still reads 1140.
  • SDK (pytest): unchanged. CLAUDE.md still reads 87.
  • MCP (jest): unchanged — no MCP change.

Doc surface touched this tick

  • docs/edit-history/2026-04-14.md — this tick-3 section appended.
  • CLAUDE.md — Go test count bumped 695 → 699 with reference to the new quartet. (Route table row + env-var mention already landed with PR #53.)
  • .env.example — added MOLECULE_ENABLE_TEST_TOKENS comment row.
  • PLAN.md / README.md / README.zh-CN.md — no change (admin E2E-helper route is not a user-visible surface; hermes fix is template-only; #54 was already docs-only).
  • No new docs/** architecture doc needed — the admin route is a two-line dev helper, not a new subsystem.

Summary — tick-4: modular guardrail plugins + secrets auto-restart + restart-context message (PRs #63, #64, #65)

Three merges this evening tick. One large plugin-refactor, one secrets bugfix, and one new platform feature that injects a synthetic restart context message back to a workspace on re-registration.

PR #63 — feat(plugins): split guardrails into 12 modular plugins

Merge commit 8b896b1. Breaks the previous monolithic molecule-dev guardrails into 12 standalone plugins under plugins/molecule-*, each shipping its own plugin.yaml, optional hooks/, optional settings-fragment.json, and optional skills/. Cross-runtime install is handled by a new _install_claude_layer step on AgentskillsAdaptor (kept in sync across both copies: workspace/plugins_registry/builtins.py and sdk/python/molecule_plugin/builtins.py — drift-guarded).

  • New pluginsmolecule-audit-trail, molecule-careful-bash, molecule-freeze-scope, molecule-prompt-watchdog, molecule-session-context, molecule-skill-code-review, molecule-skill-cron-learnings, molecule-skill-cross-vendor-review, molecule-skill-llm-judge, molecule-skill-simplify, molecule-skill-update-docs, molecule-skill-verification.
  • Adaptor extensionAgentskillsAdaptor._install_claude_layer installs hooks (.py + .sh wrapper), merges settings-fragment.json into the workspace's .claude/settings.json, and drops skills into .claude/skills/<name>/SKILL.md. Works for every plugin that ships a claude_code adapter stub.
  • CLAUDE.md — the PR itself appended the 12-plugin enumeration to the Plugins section; verified on main, no re-sync needed in this tick.
  • Tests — no new Go / Python unit tests (plugin install is exercised end-to-end via existing plugin-install integration tests).

PR #64 — fix(secrets): auto-refresh global_secrets on workspace restart (#15)

Merge commit 383582f. Fixes GitHub issue #15. Until now, rotating a global secret (e.g. CLAUDE_CODE_OAUTH_TOKEN) only propagated to a workspace on the next full cold-start, forcing manual ops to drive POST /workspaces/:id/restart by hand. Tier-3 Claude Code agents were the first to surface the stale-token path as SDK 401s.

  • New helperrestartAllAffectedByGlobalKey(db, key) in workspace-server/internal/handlers/secrets.go. Enqueues RestartByID for every non-paused, non-removed, non-external workspace that does NOT shadow the key with a workspace-level override (workspace-scoped secrets already win the Start-time merge).
  • WiringSetGlobal and DeleteGlobal both call the helper after a successful DB write. Matches the existing behaviour of workspace-scoped Set / Delete (which have always auto-restarted the owning workspace).
  • Testssecrets_test.go gains two sqlmock-backed tests, one per branch (set + delete), verifying the query filter (skip paused / removed / external, skip shadowed) and the enqueue call. Raw PASS count grows by more than 2 because the tests use table-driven subtests.

PR #65 — feat(platform): inject restart context system message (#19 Layer 1)

Merge commit 3ea8cda. Fixes GitHub issue #19 Layer 1 (Layer 2 is deferred to follow-up issue #66). After a workspace restart (HTTP /restart or programmatic RestartByID) and successful re-registration, the platform sends a synthetic A2A message/send back to the workspace containing:

  • restart timestamp
  • previous session end timestamp + human-readable duration
  • list of env-var keys now available (keys only — values never leak through the message)

The message is marked with metadata.kind=restart_context so agents can detect and handle it specifically if they choose, and uses a system:restart-context caller prefix so it bypasses CanCommunicate via the existing isSystemCaller() check in a2a_proxy.go.

  • New filesworkspace-server/internal/handlers/restart_context.go (240 lines: payload builder, re-registration waiter, sender with 30s timeout) and restart_context_test.go (120 lines, 4 top-level Test* functions).
  • Wiringworkspace_restart.go launches the context sender in a goroutine after the HTTP response has been written, so restart latency is unaffected by delivery success.
  • Skip path — if the workspace does not re-register within 30s, the sender logs and drops. Agents that crash during restart do not get spurious context messages.
  • Layer 2 follow-up — user-defined restart_prompt via config.yaml / org.yaml is tracked as new GitHub issue #66 — "Workspace restart_prompt — user-defined restart context (#19 Layer 2)".

Measured test counts this tick

Measured from /Users/hongming/Documents/GitHub/molecule-monorepo on main (post-merge of all three PRs):

  • Go: go test -v ./... | grep -c "^--- PASS"726 (was 712 in tick-3; +14 raw PASS lines from PR #64's two table-driven tests and PR #65's four top-level tests with their subtests). The top-level Test* function delta is +6 as expected (+2 from #64, +4 from #65). #63 added zero test functions.
  • Canvas (Vitest): unchanged — no canvas change in any PR this tick. CLAUDE.md still reads 357.
  • Workspace-template (pytest): unchanged — PR #63 adds plugin directories but no new pytest collection target; the drift-guard test still passes (1/1). CLAUDE.md still reads 1140.
  • SDK (pytest): unchanged — PR #63 modifies sdk/python/molecule_plugin/builtins.py but does not add new tests; existing SDK tests still pass. CLAUDE.md still reads 87.
  • MCP (jest): unchanged — no MCP change.

Doc surface touched this tick

  • docs/edit-history/2026-04-14.md — this tick-4 section appended.
  • CLAUDE.md — Go test count bumped 699 → 726 (measured PASS lines, keeping the same counting convention as prior ticks); global-secrets auto-restart behaviour noted on the /settings/secrets route / secrets section; Workspace Lifecycle section gains a sentence on the synthetic restart-context message and its system:restart-context caller prefix. 12-plugin list is already in place from PR #63.
  • PLAN.md — backlog entries that duplicated GitHub issue numbers (1114 used #64/#65/#66/#67 as stale sequential-ID references) are left untouched; GitHub issue #66 is the new follow-up for #19 Layer 2 and has been added as a fresh Phase 32 / near-term note so the two tracking systems don't silently diverge.
  • .env.example — no change; none of the three PRs added env vars.
  • README.md / README.zh-CN.md — no change (no user-visible surface moved by this tick: plugins are still drop-in, secrets auto-restart is an implementation detail, and the restart-context message is an agent-facing system message).

Summary — tick-5: PLAN.md backlog cleanup + wire tick-4 plugins into default org template (PRs #69, #70)

Two docs / template-only merges. Neither touches Go/TS/Python code, adds env vars, moves API routes, or shifts test counts.

PR #69 — docs(plan): drop stale sequential refs from Backlog items 11-14

Merge commit 2c89e24 (squash 730bcc4). PLAN.md only. Backlog items 1114 previously carried placeholder sequential refs #64#67 that were introduced before GitHub issues/PRs with the same numbers merged with different scopes (PR #64 is the global- secrets auto-restart; PR #65 is the restart-context injector; #66 is the new restart_prompt follow-up; #67 was tick-4's docs-sync PR). Leaving the stale refs in place was actively misleading readers cross-referencing against gh pr list / gh issue list. The cleanup strips the #64#67 annotations from the four bullets and adds a single footnote explaining the history and directing future prioritization to file real GitHub issues. No backlog item was removed; wording of items 1114 is otherwise intact.

PR #70 — chore(template): wire 9 new guardrail/skill plugins into defaults; PM + Security Auditor get role extras

Merge commit e6d8cdf (squash def76e7). org-templates/molecule-dev/org.yaml only. Activates the 12 modular plugins that PR #63 (tick-4) landed in the repo-level registry by wiring them into the default molecule-dev org template. Before this PR the plugins existed on disk under plugins/molecule-* but no org actually opted in, so newly-imported workspaces still only shipped the original three (ecc / molecule-dev / superpowers).

  • Defaults expanded (was 3, now 9) — universal additions: molecule-careful-bash, molecule-prompt-watchdog, molecule-audit-trail, molecule-session-context, molecule-skill-cron-learnings, molecule-skill-update-docs (plus the original three, retained).
  • Per-role overrides:
    • PM: defaults + molecule-workflow-triage + molecule-workflow-retro (slash commands matching PM's coordination role).
    • Security Auditor: defaults + molecule-skill-code-review + molecule-skill-cross-vendor-review + molecule-skill-llm-judge (multi-criteria review + adversarial cross-vendor second opinion
      • LLM-judge gate for "wrong thing shipped").
    • Research Lead + 3 researchers + UIUX Designer: defaults + browser-automation (existing override, resynced to new default set).
    • Other 5 dev roles (Dev Lead, BE, FE, DevOps, QA) inherit the new defaults unchanged.
  • REPLACE-semantics caveatworkspace-server/internal/handlers/org.go (~L345) treats per-workspace plugins: as REPLACE, not UNION, so every role override has to re-list all 9 defaults to add one extra. GitHub issue #68 tracks the union-semantics proposal; once it lands the per-role lists can shrink to just the deltas. No platform change in this PR.
  • No new tests; plugin install is exercised by the existing plugin-install integration tests.

Not touched

  • No platform (workspace-server/) change — no route, handler, migration, or env var moved.
  • No canvas / workspace-template / SDK / MCP change.
  • No new plugins — PR #70 only wires the existing PR #63 plugins into the default template.

Test counts this tick

Unchanged from tick-4 (neither PR added tests). Per the prior-tick baseline: Go 726, Canvas (Vitest) 357, MCP 97, SDK 132, workspace 1140. Skipped re-measurement — docs/template-only diff cannot move these.

Doc surface touched this tick

  • docs/edit-history/2026-04-14.md — this tick-5 section appended.
  • CLAUDE.md — no change (no code-facing surface moved).
  • PLAN.md — PR #69 is itself the PLAN.md cleanup. Added a one- line entry under "Recently launched" noting PR #70 wired the tick-4 (PR #63) modular plugins into the default org template.
  • .env.example — no change.
  • README.md / README.zh-CN.md — no change.

Summary — tick-6: per-workspace plugins UNION semantics + prior doc-sync (PRs #71, #72)

Two merges this tick. One resolves the REPLACE-semantics caveat called out in tick-5 (GitHub issue #68) by flipping per-workspace plugins: handling in org.go from REPLACE to UNION, with a !/- opt-out prefix for removing a default on a per-workspace basis. The other is the tick-5 docs-sync PR.

PR #71 — fix(org): per-workspace plugins UNION with defaults; '!' prefix opts out (#68)

Merge commit 26622dc (squash d9603a7). Resolves GitHub issue #68. Before this PR, org.go (~L345) treated a per-workspace plugins: list as a REPLACE of defaults.plugins, so every role override in the default molecule-dev org template had to re-list all 9 defaults to add one extra (e.g. Security Auditor had to restate 9 defaults to add 3 review skills). With this fix the two lists UNION, so role-level entries only need to declare the delta.

  • New helpermergePlugins(defaultPlugins, wsPlugins) in workspace-server/internal/handlers/org.go (~L645). Returns the union of the two lists (deduplicated, defaults first). A per-workspace entry starting with ! or - opts the named plugin OUT of the union (e.g. !browser-automation removes browser-automation from a workspace that would otherwise inherit it from defaults.plugins).
  • Wiring — the Plugins field resolution at ~L344 is now plugins := mergePlugins(defaults.Plugins, ws.Plugins) instead of the prior "if ws.Plugins != nil then ws.Plugins else defaults.Plugins" branch.
  • Tests — 5 new TestPlugins_* tests in workspace-server/internal/handlers/org_test.go covering: empty+empty, defaults-only, workspace-adds, opt-out-with-!, opt-out-with--, and dedup of a plugin listed in both sides. Measured Go raw PASS count is now 731 (was 726 at tick-5 baseline); delta is +5, matching the new test functions.
  • Template rippleorg-templates/molecule-dev/org.yaml role overrides can now shrink to just the deltas, but this PR does NOT touch the template (backward compatible: re-listing defaults still yields the same resolved set after UNION + dedup). Template cleanup is a follow-up.

PR #72 — docs: sync documentation with 2026-04-14 tick-5 merges (#69, #70)

Merge commit 3cc4e23 (squash 39bd59b). Docs-only. Created the tick-5 section of this file (see above). Nothing to re-sync here.

Measured test counts this tick

  • Go: go test -v ./... | grep -c "^--- PASS"731 (was 726 at tick-5 baseline; +5 from PR #71's TestPlugins_* quintet). This matches exactly.
  • Canvas (Vitest): unchanged — no canvas change. Still 357.
  • Workspace-template (pytest): unchanged — no workspace-template change. Still 1140.
  • SDK (pytest): unchanged. Still 132.
  • MCP (jest): unchanged. Still 97.

Doc surface touched this tick

  • docs/edit-history/2026-04-14.md — this tick-6 section appended.
  • CLAUDE.md — Go test count bumped 726 → 731; Plugins / Org Templates note updated from the prior REPLACE-semantics caveat to the new UNION + !/- opt-out semantics.
  • PLAN.md — added a "Recently launched (2026-04-14 tick-6)" entry for PR #71 noting GitHub issue #68 is now resolved.
  • .env.example — no change.
  • README.md / README.zh-CN.md — no change (semantics are internal to org-template resolution).

Summary — tick-7: DB-authoritative schedules (#76), generic category_routing (#75), template cleanup (#74)

Four merges this tick: PR #73 (docs sync tick-6), PR #74 (template plugin cleanup), PR #75 (category_routing for #51), PR #76 (schedules source column for #24). The latter two close GitHub issues #51 and #24.

PR #76 — fix(org): DB-authoritative schedules; additive org/import (#24)

Merge commit 07a5ca3c. Closes #24.

  • New migration 022_workspace_schedules_source.{up,down}.sql adds a source TEXT column ('template' | 'runtime') with a CHECK constraint and a unique (workspace_id, name) index. Legacy rows are backfilled to 'template' before the column is flipped NOT NULL DEFAULT 'runtime'.
  • Import SQL is extracted to const orgImportScheduleSQL in org.go and upserts with ON CONFLICT (workspace_id, name) DO UPDATE ... WHERE workspace_schedules.source = 'template' — runtime-added schedules with colliding names survive re-imports.
  • schedules.Create writes source='runtime' explicitly; schedules.List returns the field (with json:",omitempty" so old clients don't see an empty string).
  • +3 tests: TestRuntimeSchedule_HasSourceRuntime, TestImport_OrgScheduleSQLShape (asserts against the const directly, no file-scraping), TestList_IncludesSourceColumn.

PR #75 — feat(platform): generic category_routing replaces hardcoded audit dispatch (#51)

Merge commit dee5322d. Closes #51.

  • OrgDefaults + OrgWorkspace gain CategoryRouting map[string][]string. Merge semantics: workspace keys replace defaults' value for the same key (empty list drops the key); new keys are added.
  • renderCategoryRoutingYAML builds a deterministic YAML block via yaml.Node + yaml.Marshal (sorted keys; YAML library handles escaping of role names with reserved chars).
  • New appendYAMLBlock helper guarantees a newline boundary when concatenating YAML fragments into config.yaml; applied to both the category_routing and initial_prompt appends.
  • org-templates/molecule-dev/org.yaml gets a defaults.category_routing block; pm/system-prompt.md replaces the hardcoded role-mapping table with a generic config-lookup pattern ("read /configs/config.yaml, look up category_routing[<category>]").
  • +6 tests covering parse, union-with-defaults, integration into workspace config, YAML-specials escaping, empty-renders-nothing, and the newline guard.

PR #74 — chore(template): simplify per-role plugin lists using #71 union semantics

Merge commit 20068196. Follow-up to PR #71.

  • org-templates/molecule-dev/org.yaml PM, Research Lead + 3 sub-roles, Security Auditor, UIUX Designer role overrides shrunk to just the deltas (e.g. PM goes from 11 entries to [molecule-workflow-triage, molecule-workflow-retro]; Research roles go from 10 entries to [browser-automation]).
  • No platform changes; relies on UNION semantics landed in PR #71 (tick-6).

PR #73 — docs: sync documentation with 2026-04-14 tick-6 merges (#71, #72)

Merge commit 911580c6. Routine docs sync for the prior tick.

File deltas

  • CLAUDE.md — Go test count 731 → 740; migration count 16 → 23; added workspace_schedules.source note in the Database section.
  • PLAN.md — new "Recently launched (2026-04-14 tick-7)" section.
  • workspace-server/internal/handlers/org.goOrgDefaults.CategoryRouting, OrgWorkspace.CategoryRouting, mergeCategoryRouting, renderCategoryRoutingYAML, appendYAMLBlock, orgImportScheduleSQL const, schedules upsert wired to the const.
  • workspace-server/internal/handlers/schedules.goscheduleResponse.Source, Create inserts with source='runtime', List reads source.
  • workspace-server/internal/handlers/schedules_test.go — new file.
  • workspace-server/internal/handlers/org_test.goTestCategoryRouting_*
    • TestAppendYAMLBlock_NewlineGuard.
  • workspace-server/migrations/022_workspace_schedules_source.{up,down}.sql — new.
  • org-templates/molecule-dev/org.yamldefaults.category_routing added; per-role plugin lists trimmed to deltas.
  • org-templates/molecule-dev/pm/system-prompt.md — hardcoded category table replaced with generic config-lookup instructions.

Summary — tick-8: TenantGuard middleware (Phase 32 foundation)

One merge: PR #78 (TenantGuard). Phase 32 (Cloud SaaS launch) starts here.

PR #78 — feat(platform): TenantGuard middleware — public repo's only SaaS hook

Merge commit 57a05686. Noteworthy: saas-foundation / auth-adjacent.

  • New workspace-server/internal/middleware/tenant_guard.go:
    • Reads MOLECULE_ORG_ID env at construction. If set → every non-allowlisted request must carry matching X-Molecule-Org-Id or gets 404 (not 403, to avoid leaking tenant existence to subdomain probers). If unset → passthrough (self-hosted / dev / CI unchanged).
    • Allowlist is exact-match (/health, /metrics) so Fly Machines health probes + Prometheus scrape work without the header.
    • TenantGuardWithOrgID(id) is the test constructor; ordinary callers use TenantGuard().
  • Wired into workspace-server/internal/router/router.go after metrics.Middleware() so rejected requests still land on the 4xx counter.
  • +6 tests: unset-passthrough, matching, mismatched-404-empty-body, missing-404, allowlist-bypass, allowlist-is-exact-match.
  • CLAUDE.md: test count 740 → 746; new MOLECULE_ORG_ID env var documented.

Paired work — private the private control-plane repo repo scaffolded

(Outside this monorepo; logged here because it anchors the open-core split.)

  • Initial commit 1bab493 on new private repo Molecule-AI/the private control-plane repo.
  • Migrations 001 (organizations), 002 (org_instances), 003 (org_members).
  • HTTP server: /health, /cp/orgs CRUD, subdomain + X-Molecule-Org-Slug header fallback → fly-replay: app=<tenant>;instance=<machine_id> header, stamps X-Molecule-Org-Id so TenantGuard downstream accepts the request.
  • Provisioner + Lookup interfaces; Stub in-memory impl (idempotent, tested) + Fly stub returning ErrNotImplemented (real impl is Phase B).
  • CI workflow: vet + build + test on push/PR.
  • Follow-up PRs (in the private repo): real Fly Machines provisioner, WorkOS AuthKit signup, Stripe billing, Cloudflare edge, signup UX, observability, hardening. Full 9-phase plan documented in chat (phases AI).

File deltas (public repo)

  • CLAUDE.md — test count + MOLECULE_ORG_ID env var.
  • PLAN.md — new "Recently launched (2026-04-14 tick-8)" block.
  • workspace-server/internal/middleware/tenant_guard.go — new.
  • workspace-server/internal/middleware/tenant_guard_test.go — new.
  • workspace-server/internal/router/router.go — wired middleware.