… the published README (objectui#9987)
The README's record-navigation paragraph told an author to write the
member that `@objectstack/spec` retired under ADR-0049
(objectstack-ai/objectstack#18619) — and then, in the same paragraph,
explained the mechanism by which an undeclared key rejects the whole
config. The first sentence caused what the second diagnosed. This file
is listed in `files[]`, so the instruction shipped in the npm tarball.
The instruction is replaced by the route the retirement actually leaves
standing, carried in from `@object-ui/react`'s `useNavigationOverlay`
docblock: assign a `record` page to the object and let `isDefault` pick
the one that opens. Deleting the sentence alone was not enough — it
answered a real authoring question, and a reader who loses the answer
goes looking and finds the retired key elsewhere.
The second sentence is kept byte-identical (modulo re-wrapping): it is
the only place this README tells an author why a typo costs them the
whole block. It just stops being a description of what the paragraph
above it told them to do.
`readme-navigation-example.test.ts` now measures the PROSE as well as
the fence. The fence tests could never have caught this — they extract
the ```json block, and the block never carried the key. The pinned
`@objectstack/spec@17.4.0` still declares `view`, so nothing
schema-derived can say it is retired in this tree; it is named by hand,
exactly as `basePath` already is, and the absence carries its own
control: the same detector is run over the sentence that used to carry
the instruction and must find it there.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018HrVaotisyhgmot9o2MLRq
Fixes #9987
Clause-②: no — a published README and the test that runs its example. It moves no exported symbol and no key on a published payload.
What the paragraph did
packages/plugin-gantt/README.mdis listed in that package'sfiles[], so it ships inside the npm tarball. Its record-navigation paragraph instructed an author to write the member@objectstack/specretired under ADR-0049 (objectstack-ai/objectstack#18619) — and then, in the same paragraph, explained the mechanism by which an undeclared key rejects the whole config. The first sentence caused what the second diagnosed, and a reader who stops at the instruction never reaches the contradiction.Premise re-taken on today's
origin/mainbefore any editAll three legs, each with its control lit in the same command:
packages/plugin-gantt/README.mdlines 54–62 on0c2eb5eee(the card cited1db82373f; the text, not the line number, is the anchor). Both quoted verbatim in the card matched byte for byte.README.mdreally is infiles[]—["dist", "README.md", "CHANGELOG.md", "LICENSE"]. ⭐ Control in the same reading:ROADMAP.mdsits in the same directory, has the same extension, and is not infiles[]— so the instrument distinguishes shipped from not-shipped rather than saying yes to every.mdin the folder.demo/,docs/,scripts/,src/and the two tsconfigs are likewise absent.main(cdedfb348)packages/spec/src/ui/view.zod.ts:1971readsview: retiredKey(NAVIGATION_VIEW_RETIRED), and the comment above it says why: the key stays in the shape sotsctypes itneverand a value reaching a parse raises the prescription instead of a bare unrecognized-key report. That distinction is load-bearing for this repair, and is why the surviving sentence below is not re-pointed atview.The repair
The instruction is gone. In its place is the route the retirement actually leaves standing, carried in from the carrier the card names —
@object-ui/react'suseNavigationOverlaydocblock — in the README's own voice, without restating the retirement's reasoning:modebeside it never takes effect either» is true and it is the only place this README tells an author why a typo costs them the whole block. Only its line wrapping moved — proved below. It now stands as the generic strictness warning it always was, and stops being a description of what the paragraph above it told the reader to do. ⛔ It is deliberately not re-pointed atview: after the retirementviewis a declared tombstone raising a prescription, not an undeclared key, so aiming this sentence at it would describe the failure wrongly.⛔ Neither neighbouring carrier is folded in.
packages/react/src/hooks/useNavigationOverlay.tsline 31 spells the same shape and the card checked it CLEAN — it is the tombstone's own account of past behaviour, with the replacement stated four lines below it.packages/types/src/objectql.tsis objectui#9938's site. Neither is touched by this diff.The test is the other half of the deliverable
packages/plugin-gantt/src/readme-navigation-example.test.tsexisted, was green, and would have stayed green through this defect for a structural reason worth stating: it extracts thejsonfence, and the fence never carried the key. The instruction lived entirely in prose. So the file now measures the prose as well.viewis retired in this tree. The pinned@objectstack/spec@17.4.0still DECLARES it — measured, not assumed:NavigationConfigSchema's shape reads["mode","view","preventNavigation","openNewTab","size","width"]andsafeParse({ mode: 'page', view: 'summary_view' })succeeds. SodeclaredMembers()reports the key legal, and every schema-derived statement about it would be vacuous here. It is therefore named by hand — exactly asbasePathalready is in this same file — and the empty result carries its own control:does not INSTRUCT the retired detail-view key, in prose or fence— no code span in the section equalsview, andsummary_viewappears nowhere in it.CONTROL: the same detector finds the key in the sentence that carried it— the samecodeSpans()is run over the removed sentence, verbatim, and must return['view']. If the detector ever stops firing there, the clean section above says nothing at all.still answers the question the retired instruction answered— the section must still namerecordandisDefault. These are identifiers, not wording: the sentence may be rewritten freely as long as it still hands the reader the route.Evidence
RED before / GREEN after, file state verified in the SAME command as each run:
The control test passed on both runs: the detector was lit before the repair and is still lit after, so the zero is a measurement and not a broken instrument.
The kept sentence is byte-identical, with its own control. Whitespace-normalised, the substring from
`navigation` is the spectoowns the member list.compares EQUAL betweenHEAD:packages/plugin-gantt/README.mdand the worktree — while the same instrument applied to the half that should have changed reports DIFFERENT. And the same fixed-string grep that finds the removed instruction (use the declared `view` member) once in the file at HEAD finds it zero times in the repaired file.No ablation was run, and that is a statement rather than an omission. Nothing in this diff is a guard whose failure mode needs proving by mutation — the RED-before run already is the "can this fail" leg, taken against the real published text rather than an injected one, and it failed for exactly the two reasons named.
Gates — re-run as the LAST action before the push
Tree verified equal to the pushed commit
9ef577d38,git status --porcelainempty, at the time of the run. Exit codes captured before any pipe.Gates that do select a package README (established by reading each script's own surface declaration, ⛔ not assumed):
check-doc-fence-languages.mjscheck-doc-snippet-types.mjscheck-doc-component-types.mjscheck-doc-example-types.mjscheck-readme-exports.mjscheck-doc-links.mjsSCAN_ROOTScarriespackages/*/README.mdcheck-doc-expression-carriage.mjscheck-doc-example-shared-reader.mjscheck-readme-exports.mjsFAILS by design on an unbuilt tree (population COLLAPSED -- this run proves nothing). The green above is from a run after all 39 packagedist/trees were built; the collapsed run is not being reported as a pass.⛔
check-doc-example-ids.mjsdoes not select package READMEs — its own header rules the population tocontent/docs/**on purpose — so it is not in the list above.Everything else run on the same tree:
check-changeset-presence0,check-changeset-claims0,check-pending-changeset-literals0,check-changeset-fixed0,check-changeset-no-major0,check-control-bytes0,check-new-cross-file-line-citations0,check-test-path-roots0,check-unreferenced-sources0,pnpm --filter @object-ui/plugin-gantt lint0 (0 errors, pre-existing warnings only),pnpm --filter @object-ui/plugin-gantt type-check0, and the package suite from the repo root —pnpm exec vitest run packages/plugin-gantt/— 69 files, 541 tests, all passing.Governed-surface guard, asked rather than assumed:
check-governed-queue-guard.mjs --testover the three changed paths returns NOT GOVERNED, withAGENTS.mdrun through the same command as a lit control returning the governed verdict.Changeset — decided by running the gate, not from memory
check-changeset-presence.mjsdemanded one, and the file it named is the test undersrc/, not the README: that gate subtracts*.mdfrom published source on purpose («published-but-not-code sits with the READMEs»), and its header answers a change confined to tests with the empty-frontmatter exemption in one line. So.changeset/9987-gantt-readme-navigation-view.mdcarries an EMPTY frontmatter and says so in prose, including the part that argues the other way — the README genuinely is in the tarball. No runtime behaviour, no export and no published-contract field moved, and every package here is in one fixed group, so the corrected README reaches npm with the next release either way. ⭐ A reviewer who wants this to carry apatchcan flip it in one line; the reasoning is written down rather than assumed.Acceptance notes
packages/react/src/hooks/useNavigationOverlay.tssays the key «was removed in@objectstack/spec17.5.0» while objectstackmainkeeps it as aretiredKeytombstone. Checked and it is not a defect: the spec's own tombstone string opens with those exact words, so the docblock is quoting its source faithfully. Recorded only so nobody re-reads it as drift. Carrier for the retire-vs-remove distinction in this repo: objectui#9684, whose PR is this tree's HEAD commit.summary_viewacross the tracked tree returns 20 hits and every one of them is a test fixture, a CHANGELOG entry or the retirement's own account (packages/react,packages/types,packages/plugin-grid,.changeset/9874-…) — all owned by objectui#9667 / finding(types): the publishedViewNavigationConfigdocblock teachesnavigation: { view: 'summary_view' }as legal authored metadata — the key ADR-0049 retired in spec 17.5.0, which typesneveron the bump #9938 / fix(react): the objectui#9874 disagreement row types its retired-viewfixture through the spec schema — the one diagnostic the Spec Main Shape Gate still reports #10080 / finding(react):useNavigationOverlaystill readsnavigation.view— removed in @objectstack/spec 17.5.0 — and substitutes the authored name for the navigation-MODE token #9874. Zero hits undercontent/docs, zero in any otherpackages/*/README.md, zero in the rootREADME.md; the 20 hits elsewhere are the lit control for that zero. No new card is owed.Generated by Claude Code