Uh oh!
There was an error while loading. Please reload this page.
feat(spec): retire contributes.routes (ruled Option B) and redirect its last two teaching sites to the http.server mount - #12417
Conversation
…ast dead member (ADR-0049, ruled Option B) retiredKey() tombstone (non-strict object; plain deletion would silently strip the key), ADR-0087 retired-key entry kernel/Manifest:contributes.routes + D3 semantic entry plugin-manifest-contributes-routes-retired (both under major 18, launch-window convention), liveness ledger row updated in place (tombstones keep the key in the drilled shape), pin tests (prescription as the specific zod issue + kinds-only survivor), regenerated docs projections, and the two spec docblocks that still said an authored entry 'parses cleanly' (dispatcher.zod.ts, app.zod.ts App.apis guidance) updated to state the removal. contributes.kinds — the block's sole live member — is untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E5LFCYBJ3q2s6yW6oMLxwy
…tes to the http.server mount The worked '@example Plugin Manifest' block in plugin-rest-api.zod.ts — a complete copy-pasteable manifest whose every route served nothing — becomes an imperative http.server mount example modeled on the live consumer (plugin-hono-server registers the service; app-showcase's recalc-endpoint mounts on kernel:ready), and the metadata-plugin.zod.ts 'router' delivered-form comments stop crediting contributes.routes as a delivered form. Projection regenerated (plugin-rest-api.mdx). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E5LFCYBJ3q2s6yW6oMLxwy
📓 Docs Drift CheckThis PR changes 1 package(s): 45 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 6 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 126 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 5984647b7ff736bb22f0f8ac80a0841f9d1b1e4c && git checkout 5984647b7ff736bb22f0f8ac80a0841f9d1b1e4c
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 2e24115710640fba45938baf24a31fd9cc80694f be433ecc36fbc265385d9854602053595e497039 && git checkout -B drift-repro 2e24115710640fba45938baf24a31fd9cc80694f && git merge --no-ff be433ecc36fbc265385d9854602053595e497039
node scripts/docs-audit/affected-docs.mjs --json 2e24115710640fba45938baf24a31fd9cc80694f
|
Uh oh!
There was an error while loading. Please reload this page.
…tree The merge of `main` into this branch left the `kernel/` count as OURS (274) — the `merge=os-regen` driver defers rather than text-merging, because a generator run mid-merge reads a half-merged tree. Regenerated from the fully merged sources, as that driver's pending marker requires. 277 at the merge base; this branch's DistributedStateConfig removal takes 3 (the def plus its inline `auth` and `replication` objects) and #12417's `contributes.routes` retirement on main takes 1, so 273 is the composition of both sides, not a choice between them. Predicted before the run; observed exactly. `check:strictness-ledger` green.
Fixes#10726
Fixes#11328
Family PR (chain head #10726 + folded member #11328), one commit per member. Executes the 2026-08-22 maintainer ruling on #10726 (Option B, accepted verbatim 「接受所有」): remove
contributes.routes; author-facing materials point at the imperativehttp.servermount. The ruling's cloud precondition is verified (#10812: cloud @5b5925a, zeromanifest.contributesreads, controls green). The four originally-enumerated doc sites landed earlier via PR #11327 and are not redone here.Member 1 — #10726, the tombstone half (commit 1)
packages/spec/src/kernel/manifest.zod.ts:contributes.routesbecomes aretiredKey()tombstone — neitherManifestSchemanor thecontributesobject is.strict(), so a plain deletion would silently strip the key (theloading/ Retire the nine dead members of the plugin-manifestcontributesblock (events/menus/themes/translations/actions/drivers/fieldTypes/functions/commands) — tombstone route,kindssurvives #10724 route). The block's fence comment now records TEN removed members and nameskindsas the sole survivor.contributes.kinds(live reader:packages/objectql/src/engine.ts→registry.registerKind) is untouched.kernel/Manifest:contributes.routes+ D3 semantic entryplugin-manifest-contributes-routes-retired, one file each underpackages/spec/src/migrations/entries/(major 18, the launch-window convention Retire the nine dead members of the plugin-manifestcontributesblock (events/menus/themes/translations/actions/drivers/fieldTypes/functions/commands) — tombstone route,kindssurvives #10724 established),registry.tsregions regenerated withgen:migration-registry. Deliberately no D2 conversion: a package manifest is not a stack collection member (PLURAL_TO_SINGULARhas nopackages/pluginsentry), so a conversion would be a transform with no seam that ever runs — thekernel/Manifest:loadingprecedent, recorded verbatim in the entry.packages/spec/liveness/manifest.jsonroutesrow re-graded RETIRED with the row STAYING (a tombstone keeps the key in the drilled shape — therls.priorityprecedent),_noteDISPOSITIONS and the README manifest row updated; counts unchanged (routeswas already counted among the dead members).manifest.test.ts): a rejection pin asserting the SPECIFIC zod issue (located atcontributes.routes, matching#10726+Delete the key+http.server), a kinds-only survivor pin withnot.toHaveProperty('routes'); the previous survivor pin assertingroutesparses — the exact opposite state — is replaced. The two assertions are mutually exclusive across this change, which is the red/green reverse evidence for the pin (old pin green on base, new pin green here; no dist resolution involved — the test imports./manifest.zodfrom src, so no ablation build applies)..changeset/manifest-contributes-routes-retired.md:minorper the launch-window convention (check-changeset-no-majorgreen), FROM → TO mapping, and the disposition markeradr-0087: registered plugin-manifest-contributes-routes-retired.Member 2 — #11328, the two remaining teaching sites (commit 2)
packages/spec/src/api/plugin-rest-api.zod.ts:31-63: the full worked@example Plugin Manifestblock — a complete, copy-pasteablecontributes.routesmanifest whose every route served nothing — replaced with an imperativehttp.servermount example modeled on the verified-live consumer (packages/plugins/plugin-hono-server/src/hono-plugin.ts:271registers the service;examples/app-showcase/src/system/server/recalc-endpoint.tsmountsPOST /api/v1/showcase/recalconkernel:ready).packages/spec/src/kernel/metadata-plugin.zod.ts: therouterdelivered-form comments stop creditingcontributes.routesas a delivered form. The text had drifted since Two more author-facing sites still teachcontributes.routes— a full worked manifest example inplugin-rest-api.zod.tsand therouterdelivered-form comments inmetadata-plugin.zod.ts#11328 was filed — re-measured at:118-122and:124-128on the branch base; both corrected to the imperative mount + declarativeapis:.Declared file-surface increment (bounded inline fix, same defect class)
packages/spec/src/api/dispatcher.zod.ts(protocol docblock) andpackages/spec/src/ui/app.zod.ts(App.apisretiredKey guidance) — both PR-#11327-corrected sites still said an authoredcontributes.routesentry "parses cleanly and serves nothing", a statement THIS PR falsifies (the entry is now loudly rejected). Both updated to state the removal. Evidence of boundedness: mechanical one-sentence corrections, non-governed spec sources, no schema shape or export change, covered by the samecheck:docsregeneration already in this diff, no other in-flight claim holds either file (checked at claim).Generated projections (never hand-edited)
Nine
content/docs/references/**pages viagen:docs,docs/audits/2026-07-unknown-key-strictness-ledger.counts.mdviagen:strictness-ledger,src/migrations/registry.tsmarked regions viagen:migration-registry— all viacheck:generated --fixafter a freshpnpm --filter @objectstack/spec build.Expected-reading notes for review
authorable-surface/,json-schema.manifest/,api-surface/is the CORRECT reading for this route: the surface walk classifieskernel/Manifest:contributesat one level, so members sit below the walk boundary (none of the nine Retire the nine dead members of the plugin-manifestcontributesblock (events/menus/themes/translations/actions/drivers/fieldTypes/functions/commands) — tombstone route,kindssurvives #10724 tombstones produced rows either); the Manifest def is not emitted intojson-schema.manifest/at all (0 occurrences of anycontributesmember there pre-change); no export was added or removed.spec-changes.jsonand the upgrade guide are unchanged and their gates are green: both project released majors only (protocolVersion: 17.0.0) — none of Retire the nine dead members of the plugin-manifestcontributesblock (events/menus/themes/translations/actions/drivers/fieldTypes/functions/commands) — tombstone route,kindssurvives #10724's nine major-18 keys appears in either file today, and this entry behaves identically.docs/adr/**,skills/**,.claude/**,AGENTS.md,CLAUDE.mdin the diff. One consequential staleness in a governed face is recorded as issue One sentence in the publishedobjectstack-apiskill goes stale when thecontributes.routestombstone lands — "parses but serves nothing" becomes "is rejected loudly" #12415 rather than edited here (skills/objectstack-api/SKILL.md:164will say a removed key "parses" once this lands; skills budget is PM-owned). One sentence in the publishedobjectstack-apiskill goes stale when thecontributes.routestombstone lands — "parses but serves nothing" becomes "is rejected loudly" #12415 remains open.Verification (all at final commit
be433ec; verdict lines from the gates' own output)pnpm --filter @objectstack/spec test→Test Files 431 passed (431) / Tests 11428 passed (11428); targetedvitest run src/kernel/manifest.test.ts→1 passed / 37 passed.pnpm --filter @objectstack/spec typecheck→ exit 0, includingcheck:test-typecheck(OK — @objectstack/spec's test layer compiles; the edited test file is insidetsconfig.test.json'ssrc/**/*.test.tsprogram).pnpm --filter @objectstack/spec check:generated(after--fix) → all 14 artifact gates in sync, includingcheck:migration-registry,check:spec-changes,check:upgrade-guide,check:authorable-surface,check:api-surface,check:docs,check:liveness,check:strictness-ledger.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(no paths passed — changeset derived from merge-base): 41 gates PASS atbe433ec, among themcheck:liveness,check:empty-state,check:skill-refs,check:variant-docs,check-adr-0087-registration,check-changeset-no-major,check-empty-changeset,check:changeset-gate-self-tests,check:objectui-changeset,check:nul-bytes,check:cross-package-test-inputs,check:engine-double-contract,check:merge-driver, doc-family gates,check-ci-filter-parity.check:skill-examples→ real PASS after building the client closure (260 prose examples type-check across 3 surface(s)).check:i18n(needs built CLI dist; this diff contains no i18n extraction inputs — no*.form.ts, no translations, no extract config) andcheck-dev-prereqs(reports the workspace-not-built precondition for packages this diff does not touch). CI measures both on a fresh build.pnpm lintnot run locally (CI-owned). Targeted measurement with all three pieces: (1) population = eslint's own config resolution over the 9 changed.tsfiles; (2)--format json→files linted: 9 | errors: 0 | warnings: 0; (3) invariance —eslint.config.mjsstates this repo never enables type-aware linting for ANY file, so this diff cannot move the verdict on any file it does not contain.Generated by Claude Code