feat(spec): retire preview mode — the RuntimeMode 'preview' value and the whole PreviewModeConfig block - #12718
Conversation
…ewModeConfig block Fixes #11846 (ADR-0049 enforce-or-remove; maintainer ruling 2026-08-27, Option A: remove). The declaration promised an auth bypass no layer implemented; zero consumers measured in objectstack, objectui and cloud. - 'preview' leaves the RuntimeMode enum; the prescription hangs on the enum's own error map (the HookBodyCapability precedent) - KernelContext.previewMode is tombstoned with retiredKey() (non-strict schema — a bare deletion would silently strip); the TenantRuntimeContext extend copy inherits it; both keys registered in RETIRED_KEYS_BY_MAJOR[18] - kernel/PreviewModeConfig leaves the emitted set whole (orphan value schema, #3950): RETIRED_DEFS_BY_MAJOR[18] + deliberate manifest deletion - no D2 conversion (host-constructed context, no stack seam — the kernel/Manifest:loading disposition); D3 semantic entry kernel-context-preview-mode-retired carries the prescription - pin tests for both rejection directions; regenerated authorable surface/defaults, api-surface, export-origins, docs, skill refs, strictness ledger; breaking changeset with the ADR-0087 marker Co-Authored-By: Claude <noreply@anthropic.com>
📓 Docs Drift Check10 anchor(s) derived from 1 changed package(s); no hand-written page names any of them. 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 5b6ab84ed90d7425f253117ac4c4a3950949e44f && git checkout 5b6ab84ed90d7425f253117ac4c4a3950949e44f
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 54e2d3692abd745e7582ec57af3a3c3daec043f0 dbbb7810cd468dc9b3edd60ec5401f53f2e28ce8 && git checkout -B drift-repro 54e2d3692abd745e7582ec57af3a3c3daec043f0 && git merge --no-ff dbbb7810cd468dc9b3edd60ec5401f53f2e28ce8
node scripts/docs-audit/affected-docs.mjs --json 54e2d3692abd745e7582ec57af3a3c3daec043f0 |
…tire-preview-mode
os-regen-merge four-step: merge commit first (deferral recorded), then the deliberate manifest + surface-baseline deletions re-applied on the merged tree and the whole chain regenerated with repo tooling. Both sides' sources verified present (retirement tombstone + registry entries; #12704 OrgScopingEntitlement tenancy-posture + capabilities). Co-Authored-By: Claude <noreply@anthropic.com>
|
Queue kick #2 disposition (spec seat, All 33 checks are green on head Generated by Claude Code |
|
Merging directly on the maintainer's explicit order — provenance: maintainer, 2026-08-28, live director session (session Why not the queue: the 2026-08-27 kick disposition on this PR stands — the Governed Surface Queue Guard's merge_group leg fails closed on the Generated by Claude Code |
Pre-fix sync for the export-origins patch round: origin/main moved 30 commits since the last merge (2b4178a head), including #12718 (preview-mode retirement, touches packages/spec/src/kernel/context.zod.ts and migrations) and unrelated pm/docs/engine work. Confirmed no overlap with this branch's four barrel edits before merging: diffing this branch against origin/main on src/{index,kernel,ai,ui}/index.ts shows exactly this branch's own additions and nothing else. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LpRNHxWZgSUgVnFT9mQQo4
Patch round on #12414/PR #12899: CI flagged check:export-origins STALE on ai.json/kernel.json/root.json/ui.json -- the seven re-exports this branch adds regenerated api-surface but not the sibling export-origins artifact when the branch was first merged with origin/main (the #12949 precedent this diff follows regenerates both). Root cause, precisely: merging origin/main (which had since landed #12718, retiring PreviewModeConfig) picked up main's source changes but the two GENERATED artifacts derived from that merged source were never rebuilt -- kernel.json's api-surface still listed the retired PreviewModeConfig/PreviewModeConfigParsed/PreviewModeConfigSchema, and export-origins hadn't gained entries for this branch's seven new re-exports at all. Fix: pnpm --filter @objectstack/spec build (fresh dist reflecting both this branch's re-exports and #12718's retirement), then gen:export-origins + gen:api-surface. Read the resulting diff per the gate's own #4411 dual-source-trap remedy: each of the seven names' newly-gained export-origins entry was cross-checked against its origin on every sibling entry that already carried it (root vs /system vs /ui, kernel vs /data, /ai and /ui vs /data and /automation) -- all match byte-for-byte, so this is the harmless re-export shape, never dual-source. kernel.json's api-surface diff is exactly the PreviewModeConfig removal #12718 made; nothing from this branch's own repair moved. Verified: check:export-origins, check:dual-source-exports and check:generated (14/14 generated artifacts) all green on the merged + rebuilt tree. Part of #12414 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LpRNHxWZgSUgVnFT9mQQo4
Fixes #11846
Executes the maintainer ruling of 2026-08-27 (decision-inbox batch 2, Option A: remove, recorded in comment 5434619628 on the card): the preview-mode declaration retires under ADR-0049 enforce-or-remove via the spec-property-retirement route. Dev session
session_01JvjTCjJQn9zSTXEhUKgT7s, branchclaude/issue-11846-retire-preview-mode, base15bf9e8.Day-of re-verification (dispatch constraint — zero-consumer readings, 2026-08-27 at origin/main 15bf9e8)
RuntimeModeenum atpackages/spec/src/kernel/context.zod.tsline 11,previewModeat line 133.packages/is a comment inpackages/runtime/src/domains/meta-read-principal-filtering.measurement.test.ts; the only non-spec file referencingRuntimeModeor theKernelContexttype is that same measurement test.KernelContextSchemais parsed only by its own unit test.previewModehits outside spec are the routing-only local variable inpackages/cli/src/commands/serve.ts(readsOS_PREVIEW_MODE, stays) and prose comments in two test files.kernel/PreviewModeConfighits inauthorable-surface.base.jsonand 5 inauthorable-defaults/kernel.json; nothing inpackages/spec/src/migrations/mentioned the block. All PM mechanism assumptions held; no live consumer found — no stop condition hit.What changed
Three retirement shapes, each with its own bookkeeping (the routes the gen:schema gate (a) remedy text and the retirement playbook prescribe):
'preview'leavesRuntimeMode. Prescription on the enum's own error map, dispatched by the offending input (theHookBodyCapability/crypto.hashprecedent): only the value that used to be legal gets the retirement message; a typo keeps zod's own message. Registers nothing in RETIRED_KEYS_BY_MAJOR by itself.previewModebecomesretiredKey(...)on the non-strictKernelContextSchema(a bare deletion would be a silent strip, ADR-0104). TheTenantRuntimeContextSchemaextend copy inherits it. Both walked-shape keys registered:kernel/KernelContext:previewModeandkernel/TenantRuntimeContext:previewModeinRETIRED_KEYS_BY_MAJOR[18](entry files undersrc/migrations/entries/retired-keys/).PreviewModeConfigSchemaand its two types are orphan value schema once the carrier key retires; the def leaves the emitted set.kernel/PreviewModeConfigregistered inRETIRED_DEFS_BY_MAJOR[18]; the manifest key deliberately deleted fromjson-schema.manifest/kernel.json. Route evidence from the build itself: the manifest deletion gate first refused the build with "1 previously published schema(s) disappeared from this build", then after the declared removal reported "1 schema(s) left the published set since 15bf9e8, each declared (json-schema.manifest.json 的「deliberate removal」删行仍是纪律而非门禁 —— #4650 的同类洞,上移一层(整 schema 级) #4725)" and "kernel/PreviewModeConfig:* (6 line(s)) — def no longer emitted by this build" as the authorable-surface 的 tombstone 门禁可被手编基线绕过 —— 删掉基线行就删掉了证据(#4638 / #4643 已两次这样过绿) #4650 proof for the six deleted baseline lines.Deliberately no D2 conversion: a kernel context is constructed by host code at boot — it is not a stack collection member and is never stored as a sys_metadata row, so the conversion chain has no seam that would ever see one (the
kernel/Manifest:loadingdisposition). The D3 semantic entrykernel-context-preview-mode-retiredcarries the full prescription, including the recorded fallback (a future preview capability re-declares fresh, production hard-refusal first). Consequently neither tombstone guidance string carries theos migrate metasentence (that sentence is owed only where a conversion covers the surface — the migrate-sentence pin holds).Registered under major 18, not 17: v17.0.0 was cut before this landed, so the removal ships on the 17.x line (launch-window convention) and the prescription lives at the major boundary where migrate-meta users look. This is also why
check:spec-changesandcheck:upgrade-guideare green with no artifact change —build-spec-changes.tsprojects majors only up to the current protocol major (17); the sibling major-18 entries behave identically.Docs:
content/docs/references/kernel/context.mdxis generated and was regenerated (mode enum narrowed in both tables, the key now shows the REMOVED prescription, the nested block sections are gone).content/docs/deployment/environment-variables.mdxwas measured, not assumed: itsOS_PREVIEW_MODErow reads "Preview deployment routing mode" — routing-only, no line ties preview mode to auth/identity — so it is untouched, as is the serve.ts trusted-origin consumer.OS_PREVIEW_MODEis NOT retired.Rejection pins — both directions (required by the dispatch)
packages/spec/src/kernel/preview-mode-retirement.test.tspins: authoredmode: 'preview'and an authoredpreviewModeblock each flip from silent parse to a loud, guidance-carrying rejection (issue code, path naming the site, and the prescription text pinned — including the routing-only OS_PREVIEW_MODE clause and the production-hard-refusal fallback); the extend copy rejects too; absence still parses with no phantom property; all three removed export names have zero holders on every public entry (export-origins testkit) while the carrier schemas survive; the enum options list is pinned exactly.Verification record (all heavy commands via scripts/pm/os-verify-lock.sh; exit codes captured before any pipe)
At final commit
d6551e4(cited from the runs themselves):pnpm --filter @objectstack/spec build— green after the declared manifest deletion; gate output quoted above is the route evidence.pnpm --filter @objectstack/spec test— "Test Files 436 passed (436), Tests 11543 passed (11543)".vitest run src/kernel/preview-mode-retirement.test.ts src/kernel/context.test.ts— "Test Files 2 passed (2), Tests 28 passed (28)".pnpm --filter @objectstack/spec typecheck— green, including "check:test-typecheck: OK"; tsc --listFiles counts both touched test files in the tsconfig.test.json population (2 hits), so the typecheck reading covers the new tests rather than excluding them.context.zod.tsto base 15bf9e8 (mutation proven on disk by anchored grep: old enum comment present 1, tombstone present 0) turned the pins RED — 7 failed (the 6 predeclared rejection/options pins plus the barrel-import pin, red because the old schema re-exports the retired name; the export-origins-artifact pin stayed green as predicted, since it reads the regenerated artifact). Restore proven byte-identical: git diff against HEAD empty and worktree blob hash equals the HEAD blob hash.dist/kernel/index.d.mts— the negative leg fails with exactly two diagnostics (TS2322 "preview" not assignable to the narrowed union; TS2322 the authored block not assignable to undefined), the control leg (legal context) compiles clean.pnpm --filter @objectstack/spec buildandpnpm --filter '@objectstack/client-react...' build("no new dual-source exports: 4982 names across 17 entry points").check:generatedfully green in an AND-joined chain (single verdict, exit 0) after regenerating exactly the five artifacts it proved stale (api-surface, export-origins, docs, skill-refs, strictness-ledger).pnpm --filter '@objectstack/dogfood^...' build && vitest run test/expression-conformance.test.ts— 3 passed.node scripts/pm/dispatch-gates.mjs(no paths passed; stderr names this repo at commit d6551e4) — 24 families; all run at d6551e4 in two AND-joined chains, both exit 0 (UNION-PART1-ALL-PASS, UNION-PART2-ALL-PASS), includingcheck-adr-0087-registration --base origin/main("1 declared-breaking changeset(s), each carrying an ADR-0087 disposition"),check-changeset-no-major(no major bump) andcheck-empty-changeset(1 declaring changeset added). Families beyond the dispatch-named set that the derivation added and I ran: agent-test-spelling, cross-package-test-inputs, doc-anchors, doc-authoring, doc-formula-expressions, doc-security-posture, docs-audit-scope, docs-redirects, docs-single-h1, merge-driver, objectql-double-limit, objectui-changeset, page-declaration-shape, pm-governed-merges, pm-half-states, published-files, published-readme-links, query-options-erasure, changeset-gate-self-tests.node scripts/check-nul-bytes.mjs— "OK (scanned 7061 text file(s) ... no raw ASCII control bytes)".pnpm lint) is CI's run and was not run locally; no local reading is claimed for it.skills/** readings (generated shrink, zero net growth)
skills/objectstack-platform/references/_index.md(touched by gen:skill-refs only): whole file 62 lines before, 62 after (one generated one-liner rewritten). Whole published package, sum of all SKILL.md files: 10515 lines before, 10515 after.Changeset
.changeset/kernel-context-preview-mode-retired.md—@objectstack/spec: minor(launch-window convention; a major bump is refused by check-changeset-no-major), BREAKING prose with the FROM to TO mapping and one-line fix, ADR-0087 disposition marker registeringkernel-context-preview-mode-retired.Related context, none closed by this PR: #11806 remains open (the measurement that surfaced this card); objectstack-ai/cloud#1651 is already closed with the cloud reading this PR relies on.
Generated by Claude Code
Generated by Claude Code