Skip to content

CL-6458: seed the template library on first read, not at boot behind an operator bench - #185

Merged
TheGreatAxios merged 3 commits into
mainfrom
cl-6458-seed-convergence
Aug 21, 2026
Merged

TheGreatAxios merged 3 commits into
mainfrom
cl-6458-seed-convergence

Conversation

@TheGreatAxios

Copy link
Copy Markdown
Contributor

Creating the code-review workbench 404d for every bench: GET /library/templates/code-review found nothing because the shelf never seeded.

What the operator-bench precondition was actually for

The boot seed signed in as the operator admin, looked for a bench named ORG_SLUG among that account's memberships, and only then wrote the shipped manifests. The lookup was only ever standing in for a scope to own the artifact rows — seedTemplateLibrary needs a {tenantId, principalId}.

Two things were wrong with that:

  • Dev onboarding never creates a bench named "workbench", so the precondition never became true: template library seed: not ready yet (operator bench "workbench" does not exist yet ...), forever.
  • Even satisfied, it seeds one bench. Template rows are tenant-scoped artifacts, so every other bench's picker still 404s. A single operator bench could never have been the right owner.

On top of that the retry gave up after a bounded window, so a bench onboarded after boot silently never seeded until the next restart.

The new trigger

The library read itself. createTemplateLibrarySeeder reconciles the shelf of the tenant being read, on GET /library/templates and GET /library/templates/:id — one pass per tenant per process, shared by concurrent first reads, and not remembered when it fails, so the next read retries instead of the shelf staying empty. No window to miss, no bench to wait for, any boot order.

Reconciliation semantics are unchanged: CL-6400/#162's content-hash markers still decide revise / keep / retire / restore, so re-running stays safe and a member's edits still win.

No dead-end picker

  • A read whose seed could not run answers 503, never a 404 that reads as "no such template".
  • The picker now offers only the kinds this bench's library actually serves; anything else renders as "Not set up on this bench yet" instead of being offered and then 404ing at create time. If the library can't be read at all, the list says so and offers the plain room.

Also removed

The boot seed published the @corbits/* tool tarballs for that one bench. Every tenant already gets them from seedTenant, which each provisioning path (workbench seed, onboarding provision, credential setup) runs — so this was redundant, not load-bearing. apps/hub/src/template-library-seed.ts is gone.

The evals harness no longer pre-seeds its scratch tenant either: Target.installTemplate's library read is now what converges the shelf, so a passing install is itself the convergence proof.

Red → green

Red first (packages/artifacts-hub/src/template-library.test.ts, apps/web/test/new-workbench-picker.test.tsx):

  • a never-seeded tenant's first list read seeds the shelf and serves it
  • a never-seeded tenant's first template read serves the template instead of 404ing (the exact live failure)
  • one pass per tenant; concurrent first reads share it; each tenant converges on its own read
  • a failed pass never latches — the next read retries
  • a seed the read could not run answers 503, not 404
  • a kind the library can't serve is not offered; an unreadable library says so

Scoped green: bun run typecheck (all packages), eslint + prettier on the touched tree, packages/artifacts-hub 55 pass, apps/hub 137 pass, apps/web 749 pass.

Fixes CL-6458

The bench library's template shelf never seeded in a real environment:
the boot seed waited for an operator bench that dev onboarding never
creates, and gave up after a bounded retry window. These tests state
what the shelf should do instead — converge per tenant on the first
library read, retry rather than latch on failure, and never leave the
new-workbench picker offering a kind the library cannot serve.
… an operator bench

The shelf never seeded in a real environment. The boot seed signed in as
the operator admin, looked for a bench named ORG_SLUG among that
account's memberships, and only then wrote the shipped manifests — a
precondition dev onboarding never satisfies, wrapped in a retry that
gave up after a bounded window. The result was a library that stayed
empty until the next restart, and a new-workbench picker whose "Code
review" row 404d at create time.

The bench lookup was only ever standing in for a scope to own the rows.
Template rows are tenant-scoped artifacts, so the tenant being read is
the honest owner, and every bench needs its own — one operator bench
could never have served the rest. Seeding now happens on the library
read itself: one reconciliation pass per tenant per process, shared by
concurrent first reads, not remembered when it fails, so the next read
retries. Reconciliation is unchanged (CL-6400's content-hash markers),
so re-running stays safe.

A read whose seed could not run answers 503, never a 404 that reads as
"no such template". The picker offers only the kinds this bench's
library can serve and shows the rest as not set up, so a kind is never
offered and then dead-ended at create time.

The boot seed also published the @corbits/* tool tarballs for that one
bench; every tenant already gets them from seedTenant, which each
provisioning path runs.
@TheGreatAxios
TheGreatAxios merged commit d52352d into main Aug 21, 2026
0 of 2 checks passed
@TheGreatAxios
TheGreatAxios deleted the cl-6458-seed-convergence branch August 25, 2026 15:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant