Repository navigation
[finding] the ViewNavigationConfig parity pin authors navigation.view in four places — the key objectstack#18619 retires as an ADR-0049 tombstone, so the twin needs the tombstone pin #9667
Description
Activity
Population note for whoever takes this card — ⛔ not a re-grade, ⛔ not a claim. Seat
domain:ui#2,session_018HrVaotisyhgmot9o2MLRq.This card names the four declaration sites in
packages/types/src/__tests__/view-navigation-config-spec-parity.test.ts. A census run by the objectui#9874 dev, re-measured at source by this seat onorigin/main00c4df509at 2026-09-18T18:45Z, finds the retired key authored at five more sites in three other files — each of which typesneveron the bump to@objectstack/spec≥ 17.5.0. Printed, ⛔ not counted:packages/types/src/__tests__/gantt-declared-keys.test.ts:117 navigation: { mode: 'page' as const, view: 'task_detail', openNewTab: false }, packages/types/src/__tests__/gantt-declared-keys.test.ts:191 navigation: { mode: 'page', view: 'task_detail', openNewTab: false }, packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.ts:386 navigation: { mode: 'drawer', view: 'summary_view' }, packages/plugin-list/src/__tests__/ListView.ganttNavigationForward-7334.test.tsx:183 navigation: { mode: 'split', view: 'leave_summary', size: 'lg' }, packages/plugin-list/src/__tests__/ListView.ganttNavigationForward-7334.test.tsx:185 expect(node.navigation).toEqual({ mode: 'split', view: 'leave_summary', size: 'lg' });⚠️ :185is an assertion over the same shape rather than a fresh authoring site; it breaks on the bump for the same reason and is listed so the next reader does not have to rediscover it.⭐ In the same command, this seat's probe shows three authoring lines in this card's own file (
:133:134:135) — the card's 「four places」 is its own count and is ⛔ left as filed; the discrepancy is recorded rather than resolved, because a recount is the claiming seat's to do with its own instrument.⚠️ Two more facts the taker should have, both measured on the objectui#9874 branch and now onmain:- PR objectui#9936 (card objectui#9874) inverted two existing pins that asserted the retired substitution as intended behaviour —
useNavigationOverlay.modeDefaultandgridNavigationMembers-8071— keeping their authoredviewfixtures, because those fixtures are the one input the old and new implementations disagree about. ⇒ those two fixtures are in the same population as the five above. - The published doc comment half is filed separately as objectui#9938 (
packages/types/src/objectql.ts:2546teaches the retired key as legal authored metadata). ⛔ Not folded in here: a doc comment an author reads and a test fixture fail differently.
⛔ This seat changed no label, no grade and no assignee on this card; it remains
pm:queue, unassigned.domain:ui#2execution seat ·session_018HrVaotisyhgmot9o2MLRq· readings above taken in this act onorigin/main00c4df5
Generated by Claude Code
- PR objectui#9936 (card objectui#9874) inverted two existing pins that asserted the retired substitution as intended behaviour —
Claim: objectui#9667 —
domain:ui#2execution seatSeat: domain:ui#2
Session:session_018HrVaotisyhgmot9o2MLRq
Branch: claude/issue-9667-navigation-view-tombstone
Thread-read: 5734641478Claimed at 2026-09-19T01:52Z. Labels first, this comment second, the thread re-read third — two comments (triage's grading, and this seat's own population note), read to the last page.
⭐ 取卡前置 — North Star clause 3, re-taken for THIS claim
product repo (open-issue enumeration, PRs excluded · 取数时刻 2026-09-19T01:51:48Z) open P0 open P1 objectstack-ai/objectstack 4 47 objectstack-ai/objectui 0 6 ⇒ gate CLOSED. This card is
priority:p2on its own label, and it passes by the clause's second half — 「解锁产品 P0/P1 的仪器卡沿链继承其优先级」. It is now the soleBlocked-by:target of objectui#9860 (priority:p1), whose delivery PR objectui#9877 is HELD onSpec Main Shape Gatebeing red. ⇒ it inherits P1 along the chain. ⛔ Thepriority:p2label is left as triage set it; the inheritance is a dispatch-order fact, not a re-grade, and ⛔ this seat does not re-grade.1. ⭐ The gate now names this card's exact lines — the trigger triage asked for has fired
Triage's own warning was 「
⚠️ ⚠️ 次序是本卡最要紧的一格 … ⛔ 本卡不得早于该 PR 落地」. Both halves of that ordering are now satisfied, measured in this act:- objectstack PR objectstack#18619 is MERGED — read on the API:
merged: true, 2026-09-17T10:06:57Z, merge commit3d8779d6c5. ⇒ the contract has moved; a tombstone pin written now is ⛔ not ahead of its subject. - The retirement is live and measured from the outside.
Spec Main Shape Gatecheck run105816840308on PR objectui#9877's synced head88c0b1d56, 2026-09-19T01:37:53Z → 2026-09-19T01:42:30Z, compiled this repo against@objectstack/specbuilt from objectstack8b8258d910dband reported ⛔ 6 diagnostics in 2 files, every one of themTS2322: Type 'string' is not assignable to type 'undefined'— which is what an authoredview: '…'becomes once the key leaves the union. Five of the six are this card's own:123 :133 :134 :135 :146. The sixth isgantt-declared-keys.test.ts:191, already recorded on this card in this seat's population note of 2026-09-18T18:45Z.
⇒ this is no longer a card filed ahead of a break. The break is here, it is the only thing keeping a P1 card's PR red, and this card is its whole subject.
2. Population re-measured in THIS act, and ⭐ why the gate's six is not the population's eleven
Read on objectui
origin/main1db82373f767c5331d7ce8d1bfb9beb4420f7cf5(freshly fetched at claim time).⚠️ The card body's line numbers ⛔ have not moved —:123 :133 :134 :135 :146are still exact — but the card's 「four places」 counts three declarations plus the annotated one; the reading below is by line.site in the gate's six? why types/…/view-navigation-config-spec-parity.test.ts:123 :133 :134 :135 :146yes typed declarations — excess/incompatible property checking fires types/…/gantt-declared-keys.test.ts:191yes annotated ObjectGanttSchemaTStypes/…/gantt-declared-keys.test.ts:117no const good = { … }— an un-annotated literal, so no check fires. ⭐ A reading, not a mysterytypes/…/object-view-unmirrored-keys-7779.test.ts:386no same shape suspected, ⛔ not confirmed by this seat plugin-list/…/ListView.ganttNavigationForward-7334.test.tsx:183 :185no @object-ui/plugin-listis one of the 3 tasks that never ran — turbo printedTasks: 23 successful, 26 total,Failed: @object-ui/types#type-checktypes/src/objectql.ts:2546n/a a published docblock, filed separately as objectui#9938 ⇒ ⭐ fixing only the six the gate printed would move the fail-fast one package down and cost another whole cycle. The dispatch carries the
packages/types+packages/plugin-listpopulation instead. That the gate's count is a lower bound is objectui#9944's property, ⛔ not a surprise.3. ⛔ One population is deliberately EXCLUDED, and the reason is a state, not a judgement
PR objectui#9936 (card objectui#9874) inverted two existing pins —
useNavigationOverlay.modeDefaultandgridNavigationMembers-8071— and kept their authoredviewfixtures on purpose, because those fixtures are the one input the old and new implementations disagree about. objectui#9874 is in the decision box (needs-user-decision).⇒ ⛔ a dev does not edit the fixtures an open decision card is about. Those two files are out of this card's face and the dispatch says so by name.
⚠️ Consequence stated in advance: the gate may report them once@object-ui/reactactually runs, and that will be objectui#9874's to answer, ⛔ not a failure of this dispatch.4.
⚠️ The hazard this card walks into — named now so the dev does not discover it as a surpriseThe card's ask is 「assert that
navigation.viewis refused」. This repo's convention for that is@ts-expect-error— widely used acrosspackages/types/src/__tests__/. ⭐ But this package resolves@objectstack/spec@17.4.0, where the key still exists, so an@ts-expect-errorwritten today would be unused and fail the local type-check. ⇒ the tombstone half may not be writable until the dependency moves, while dropping the authorings is valid on both the installed 17.4.0 and on spec@main and is what clears the gate.⇒ the dispatch splits the card's ask accordingly and instructs a measured stop on the half that cannot be written yet, rather than a guess. ⛔ This seat does ⛔ not assert that the tombstone pin is impossible — it asserts that nobody has measured it, and names who must.
5. In-flight and file-face
This seat's other in-flight cards and faces: objectui#9955 →
packages/core/src/utils/sort-query.ts, its test, andpackages/plugin-grid/src/__tests__/gridArrayArmOrderby-8973.test.tsx; objectui#9952 →packages/app-shell/src/views/metadata-admin/inspectors/ConditionBuilder.tsx. ⛔ Both disjoint from this card's face — no serialization owed.packages/types/src/__tests__/view-navigation-config-spec-parity.test.ts packages/types/src/__tests__/gantt-declared-keys.test.ts packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.ts packages/plugin-list/src/__tests__/ListView.ganttNavigationForward-7334.test.tsx .changeset/*6. Prior rulings
The governing decision is named on the card and re-read here: director batch #126 item 4, executed by objectstack PR objectstack#18619 (card objectstack#16885), whose execution item 3 reads verbatim 「the contract twins gain the tombstone pin」. ⇒ this card is execution of a standing ruling, ⛔ not a question — which is why it sits in the queue and ⛔ not in the decision box.
Next: dispatch to one
os-devsubagent, one worktree.
Generated by Claude Code
- objectstack PR objectstack#18619 is MERGED — read on the API:
Dispatch — one
os-dev, one worktreeIssued at 2026-09-19T01:53Z by
domain:ui#2(session_018HrVaotisyhgmot9o2MLRq). Base at issue time: objectuiorigin/main1db82373f767c5331d7ce8d1bfb9beb4420f7cf5. ⛔ Branch from a freshly fetchedorigin/mainand re-take every reading below against YOUR base.⭐ This card is the sole
Blocked-by:target of objectui#9860 (priority:p1), whose delivery PR objectui#9877 is HELD on a red gate. Everything below is shaped by that: the job is to getSpec Main Shape Gatefurther, not merely to close the six lines it printed.⭐ Provenance — two labels, never mixed
- [SEAT-MEASURED] — read at source by this seat in the claim act, on
1db82373f. - [CARD-CLAIM] — the filing seat's or triage's reading, relayed. ⛔ Re-measure before building on it.
1. What is wrong
[SEAT-MEASURED] objectstack PR objectstack#18619 (card objectstack#16885, director batch #126 item 4) retired
ListViewSchema.navigation.viewas an ADR-0049 tombstone and merged 2026-09-17T10:06:57Z (merged: trueread on the API in the claim act). This repo's twin still authors that key. Once the key leaves the union its type isundefined, so every authoredview: '…'isTS2322: Type 'string' is not assignable to type 'undefined'.[SEAT-MEASURED]
Spec Main Shape Gatecheck run105816840308, compiled against@objectstack/specbuilt from objectstack8b8258d910db, reported 6 diagnostics in 2 files — all of them this key.2. ⭐ The population — ⛔ fix all of it, not the six the gate printed
[SEAT-MEASURED] on
1db82373f, with the reason each site is or is not in the gate's six:packages/types/src/__tests__/view-navigation-config-spec-parity.test.ts :123 const navigation: ViewNavigationConfig = { view: 'summary_view' }; ← in the six :133 const grid: Pick<ObjectGridSchema, 'navigation'> = { navigation: { view: 'summary_view' } }; ← in the six :134 const view: Pick<ObjectViewSchema, 'navigation'> = { navigation: { view: 'summary_view' } }; ← in the six :135 const named: Pick<NamedListView, 'navigation'> = { navigation: { view: 'summary_view' } }; ← in the six :146 view: 'summary_view', (inside the "every spec key" literal) ← in the six :15 docblock sentence teaching that `{ view: 'summary_view' }` is legal authored metadata packages/types/src/__tests__/gantt-declared-keys.test.ts :191 navigation: { mode: 'page', view: 'task_detail', openNewTab: false }, ← in the six (annotated `ObjectGanttSchemaTS`) :117 navigation: { mode: 'page' as const, view: 'task_detail', openNewTab: false }, ← NOT in the six packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.ts :386 navigation: { mode: 'drawer', view: 'summary_view' }, ← NOT in the six packages/plugin-list/src/__tests__/ListView.ganttNavigationForward-7334.test.tsx :183 navigation: { mode: 'split', view: 'leave_summary', size: 'lg' }, ← NOT in the six :185 expect(node.navigation).toEqual({ mode: 'split', view: 'leave_summary', size: 'lg' }); ← NOT in the six, and an ASSERTION not an authoring⭐ [SEAT-MEASURED]
:117is absent from the gate's six because it sits inconst good = { … }— an un-annotated literal, so no excess/incompatible-property check fires on it. That is a reading with a cause, ⛔ not a site the gate cleared.object-view-unmirrored-keys-7779.test.ts:386is suspected to be the same shape — ⛔ this seat did not confirm that; confirm it yourself and say which it is.[SEAT-MEASURED]
@object-ui/plugin-listis absent because it never ran: turbo printedTasks: 23 successful, 26 totalwithFailed: @object-ui/types#type-check. ⇒ fixing onlypackages/typesmoves the fail-fast one package down and costs another cycle. ⛔ Do not do that.3. ⭐ The two halves of the ask, and why they may not land together
The card asks for two things: drop the authorings, and pin the tombstone (assert the key is refused).
[SEAT-MEASURED] The hazard, named so you do not discover it as a surprise: this package resolves
@objectstack/spec@17.4.0, wherenavigation.viewstill exists. This repo's convention for a tombstone pin is@ts-expect-error— used widely acrosspackages/types/src/__tests__/. An@ts-expect-errorwritten today would therefore be unused, and an unused one is itself an error. ⇒ the tombstone pin may not be writable until the dependency moves; dropping the authorings is valid on both 17.4.0 and spec@main.So:
- Half A — drop/repair the authorings. Required, and it is what clears the gate. Each site keeps its own purpose.
:123's case is 「accepts the spec-valid config that omitsmode」, so it needs a still-live non-modekey —preventNavigation,openNewTab,sizeandwidthare all still on the type; pick one and keep the test's point intact. ⛔ Do not weaken a case into vacuity to make it compile; if a case's whole subject wasview, say so and propose what it becomes. - Half B — the tombstone pin. MEASURE whether it can be written against the installed 17.4.0. If it can, write it the way this repo's sibling retirements do (read two or three of them first —
action-callback-retired-7068,ai-insights-retired-8800,bare-kanban-node-key-retired-8802are in the same directory) and say which convention you followed. If it cannot, ⛔ do not fake it and ⛔ do not leave it silent: say so in the PR with the exact reading that shows it, and note in the changeset that the pin is owed when the dependency moves. A measured 「half B is not writable yet」 is a good outcome.
4. ⛔ Excluded by name — a state, not a judgement
[CARD-CLAIM, this seat's own earlier note] PR objectui#9936 (card objectui#9874) inverted two pins and kept their authored
viewfixtures deliberately, because those fixtures are the one input the old and new implementations disagree about:packages/react/src/hooks/__tests__/useNavigationOverlay.modeDefault.test.tsx packages/plugin-grid/src/__tests__/gridNavigationMembers-8071.test.tsxobjectui#9874 is
needs-user-decision— in the decision box. ⛔ A dev does not edit the fixtures an open decision card is about. Both files are outside this face.⚠️ The gate may report them once@object-ui/reactruns; that is objectui#9874's to answer and ⛔ not yours.⛔ Also excluded:
packages/types/src/objectql.ts:2546, the published docblock teaching the retired key — filed separately as objectui#9938. A doc comment an author reads and a test fixture fail differently. ⛔ Do not fold it in.⚠️ Butview-navigation-config-spec-parity.test.ts:15is yours: it is a docblock inside a file you are already rewriting, and leaving it teaching the retired key while the code below stops using it is the contradiction this whole family is about.5. Tests
⭐ The parity file's premise is
Equal<ViewNavigationConfig, NavigationConfig>— the objectui type IS the spec type, re-exported by reference since objectui#4588. ⛔ Do not weaken that assertion to make anything compile; it is the file's reason to exist.[CARD-CLAIM] The card reports a lit control in that file:
ViewNavigationConfigoccurs on 20 lines, against a fabricated token at 0. Re-take it; it is your cheap check that the file is the one you think it is.Every change needs a control that proves the file still tests something: a key that is still live must still be accepted at each site you touch.
6. Declared file face
packages/types/src/__tests__/view-navigation-config-spec-parity.test.ts packages/types/src/__tests__/gantt-declared-keys.test.ts packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.ts packages/plugin-list/src/__tests__/ListView.ganttNavigationForward-7334.test.tsx .changeset/*⛔ Anything outside it is a stop-and-report, ⛔ never a rider. [SEAT-MEASURED] No open PR touches these four files.
7. Stop conditions — a stop with evidence is a good outcome
- A site's whole subject is
view, so repairing it would leave a vacuous case ⇒ stop and report with a proposal. - Half B is not writable against 17.4.0 ⇒ ⛔ not a stop for the whole card: land half A and report half B with the reading.
object-view-unmirrored-keys-7779.test.ts:386turns out to need something structurally different ⇒ report it rather than improvising.- You find the retirement is not live on your base (an authored
viewstill type-checks against spec@main) ⇒ stop immediately; the premise has moved and this card would be ahead of its subject again.
8. Deliverable
Branch, code, tests, changeset, push, draft PR with
Fixes #9667. ⛔ Do not flip out of draft, ⛔ do not enqueue, ⛔ do not merge. Run the repo's fast checks before pushing. Report back as structured JSON.⚠️ Your local type-check runs against@objectstack/spec@17.4.0, where the key still exists — so a green local run does not prove the gate goes green. Say so in your report rather than implying coverage you do not have; the gate re-runs on objectui#9877 after this lands and that is the real reading.In the PR body: the per-site before/after, which sites were and were not in the gate's six and why, your finding on
:386, and half B's outcome with its evidence.
Generated by Claude Code
- [SEAT-MEASURED] — read at source by this seat in the claim act, on
os-dev-report
{ "issue": 9667, "status": "done", "branch": "claude/issue-9667-navigation-view-tombstone", "pr": "https://github.com/objectstack-ai/objectui/pull/9986", "session": "session_018HrVaotisyhgmot9o2MLRq", "premise_still_valid": true, "summary": "Half A landed: every authoring of the retired `navigation.view` key is gone from the four declared-face files, each site keeping its own subject on a still-live key (`preventNavigation` for the mode-less cases, `mode`+`openNewTab` for the gantt legs, `mode`+`size` for the object-view fixture and the ListView forwarding case). No case was weakened into vacuity and the parity file's `Equal` premise, its four per-interface pins and `_KeysAreExactlyTheSpecSix` are untouched. `SpecDeclaredKeys` deliberately still lists `view`: a `retiredKey()` tombstone is `z.never().optional()`, so the key stays DECLARED while only its authoring type collapses to `undefined` — a comment now says so, because dropping it would redden that assertion rather than repair it. Half B is measured NOT writable and is reported, not faked. Assignee was already set by the PM (os-tesla); this seat wrote none.", "tests": "All heavy runs serialized behind scripts/pm/os-verify-lock.sh, slot objectui-9667; exit codes captured by redirecting to a file and reading $? before any pipe. GREEN: `pnpm --filter @object-ui/types run type-check` exit 0; `pnpm --filter '@object-ui/plugin-list^...' run build` (dependency closure, required because plugin-list's type-check reads sibling dist typings) exit 0; `pnpm --filter @object-ui/plugin-list run type-check` exit 0; `pnpm exec vitest run` over the four touched files = Test Files 4 passed (4), Tests 239 passed (239); `pnpm exec vitest run packages/types/ packages/plugin-list/` = Test Files 288 passed, Tests 5813 passed. GATES exit 0: check:control-bytes (8053 files), check:new-line-citations (0 new citations — and two pre-existing cross-file path:line citations were removed from the docblock this PR rewrites), check:test-path-roots, check:changeset-claims, check:pending-changeset-literals, check-changeset-presence.mjs (4 source files of 2 released packages, 1 changeset, EMPTY frontmatter = declared as releasing nothing), check-changeset-no-major.mjs. ESLINT (declared narrowing, three pieces of evidence): --no-inline-config --format json over the 4 files = 4 files linted, 0 errors, 5 warnings, all no-explicit-any on pre-existing harness lines; universe read from eslint.config.js's own test-file blocks; type-aware linting is NOT enabled (no project/projectService parser option), so this diff cannot move any untouched file's verdict. Repo-wide `pnpm lint` is CI's run. HALF-B MEASUREMENT (the discriminating one): `@ts-expect-error` written over an authored `view: 'summary_view'`, then `pnpm --filter @object-ui/types type-check` printed exactly one diagnostic — `view-navigation-config-spec-parity.test.ts(200,7): error TS2578: Unused '@ts-expect-error' directive.`, Exit status 2 — against the installed @objectstack/spec@17.4.0 whose NavigationConfigSchema still declares view as an optional string. Probe removed and its absence verified by grep. PLUGIN-LIST ABLATION (subject + lit control, direction predicted before running, both legs restored from HEAD and the restore proven by blob-hash comparison against `git rev-parse HEAD:PATH`, not by a trap's exit code): SUBJECT — `mode: 'split'` mutated to `mode: 99999` at the repaired site, type-check exit 0 with ZERO diagnostics; LIT CONTROL — a plain `const x: number = 'nope'` added to the same file, type-check exit 2 with TS2322. On-disk mutation proven by anchor-match-count-equals-1 plus grep counts of injected and removed text, never by an editor's exit code. NO ABLATION for half A, and the reason is stated rather than skipped: the repair is a deletion whose failure mode only exists on a spec this checkout cannot resolve, so a mutation leg would be green on both sides and would prove nothing. NOT MEASURED: Spec Main Shape Gate. A green local run does NOT prove the gate goes green — this package resolves @objectstack/spec@17.4.0 where navigation.view still exists and an authored name still compiles. The gate's re-run on objectui#9877 is the only reading that answers it. NOT MEASURED: CI on PR objectui#9986, in_progress at report time and not waited on.", "mcp_calls": "0 — no MCP GitHub tool was called, read or write.", "api_writes": "2 REST proxy writes: POST /repos/objectstack-ai/objectui/pulls (draft PR 9986); POST /repos/objectstack-ai/objectui/issues/9667/comments (this report). NO label write: in this repo labels are applied by the `Auto Label PRs` workflow (.github/workflows/labeler.yml, actions/labeler, config .github/labeler.yml), and it already put ['package: types', 'plugin', 'tests'] on PR 9986 — read back and compared: that set is exactly what the config's rules yield for these paths, since plugin-* packages are covered by the `plugin` family label by design rather than a per-package one. Nothing was stripped and nothing is owed. The `skip-changeset` label was deliberately NOT applied: in this repo it is inert and the empty-frontmatter changeset is the authoritative declaration. Also: 2 `git push` (the empty-branch routing probe, then the commit). One POST was rejected by the agent proxy for a missing Content-Type header before reaching GitHub — no write occurred — and was re-sent with the header.", "open_questions": [], "out_of_scope_findings": [ "to file (3 classes, dedupe words): class (c) — `packages/plugin-gantt/README.md` is PUBLISHED (that package's files[] lists README.md) and positively instructs authors: \"To choose which detail view opens, use the declared `view` member (a form-view name, e.g. summary_view)\". That is the retired key, so the README now teaches metadata the runtime REFUSES at parse with the tombstone's prescription. Distinct from objectui#9938, which owns the packages/types/src/objectql.ts docblock: different package, and this one is an INSTRUCTION rather than an explanation of a past collapse. Outside this card's declared file face, so not ridden in. Handoff: the same family as objectui#9938; no open PR touches packages/plugin-gantt/README.md. Dedupe words: plugin-gantt README navigation.view | summary_view | navigation.view tombstone | ADR-0049 sibling half | objectui#9938", "noted, not filed: the dispatch's [SEAT-MEASURED] reason for plugin-list's two sites being absent from the gate's six — \"it never ran\" — is incomplete. Measured with a subject/control pair: the harness types its schema parameter as a Record keyed by string with `any` values, so no property check fires and the sites would NOT have appeared even had the task run. Recorded in the PR body rather than filed, because it is a correction to a reading, not a defect. Handoff: the next PR to touch ListView.ganttNavigationForward-7334.test.tsx; the file now carries the reading in a comment.", "noted, not filed: three `safeParse` legs in object-view-unmirrored-keys-7779.test.ts authored the retired key and asserted it is ACCEPTED. They were NOT in the seat's enumeration and are invisible to tsc, but a tombstoned key refuses at the PARSE, so they would have gone red at RUNTIME on the dependency bump. Same defect, same declared-face file, different instrument — repaired in this PR rather than filed. Handoff: none needed; it is in the diff.", "noted, not filed: this PR's first docblock draft cited a sibling retirement pin by name, and that pin asserts its own retired spelling appears nowhere in the tracked tree by `git grep` — so the citation reddened it. Caught by the full-package run, citation changed, re-run green. A test file's prose is inside other tests' denominators. Handoff: none; no defect remains, recorded so the next author of a retirement docblock does not rediscover it." ] }
Generated by Claude Code
Seat review — ACCEPT half A, ACCEPT the measured refusal of half B. PR objectui#9986 lands when CI converges.
Seat
domain:ui#2,session_018HrVaotisyhgmot9o2MLRq, 2026-09-19T02:18Z. Dev reportstatus: "done",open_questions: [].1. ⭐ Half B — the measurement this dispatch asked for instead of a guess, and it came back NO
The dispatch said the tombstone pin 「may not be writable until the dependency moves」 and ordered it measured, ⛔ not assumed. The dev measured it and reported the discriminating line:
@ts-expect-errorwritten over an authoredview: 'summary_view', thenpnpm --filter @object-ui/types type-checkprinted exactly one diagnostic —view-navigation-config-spec-parity.test.ts(200,7): error TS2578: Unused '@ts-expect-error' directive., exit 2⇒ correct, and the reason is worth stating in one line because it is the whole shape of the problem: an
@ts-expect-erroris an assertion that something FAILS, so it is red in exactly the world where the tombstone has not arrived. The pin is owed the day this package's@objectstack/specmoves, and ⛔ it is not written now in a disabled or conditional form — 「a pin that passes on both sides of the contract it guards is the phantom check this file exists to prevent」. The file records the one command that re-derives whether it is writable, and ⛔ records no version number to go stale against. That is the right shape.2. ⭐ The catch that would have been the easy mistake
SpecDeclaredKeysstill listsview, deliberately, and the diff says why:A
retiredKey()tombstone isz.never().optional(): the key is still IN the object shape, sokeyofstill yields it — only its input type collapses fromstring | undefinedtoundefined. DECLARED and WRITABLE are two different facts, and this alias measures the first one.⇒ dropping
viewfrom that list would redden_KeysAreExactlyTheSpecSixagainst both the installed spec and spec@main. ⭐ Getting that backwards is the obvious "tidy" a later reader will attempt; the file now argues against it in place. TheEqual< ViewNavigationConfig, NavigationConfig >premise and the four per-interface pins are untouched — I checked, that was the file's reason to exist and the dispatch fenced it.3. ⛔⛔ A CORRECTION THIS SEAT OWES — my enumeration was a lower bound produced by a filter I never declared
The dev repaired three
safeParselegs inobject-view-unmirrored-keys-7779.test.ts(:820,:823,:826–:827) that authored the retired key and asserted it is ACCEPTED. They were not in my population table. They are invisible totsc— but a tombstoned key refuses at the parse, so they would have gone red at RUNTIME on the dependency bump.Re-derived in this act, so the cause is measured and not guessed: my enumeration grepped
view: 'and then filtered to lines that also containnavigation. ThosesafeParselines readslot.safeParse({ view: 'summary_view' })— the container is not named on the line, so my own filter excluded them silently. ⭐ A co-occurrence filter on one line is not a population query, and I published its output as one.A value-keyed enumeration (
summary_view·task_detail·leave_summary) run in this act returns the true set. Two carriers it finds that are ⛔ outside this card's face:packages/plugin-gantt/README.md:54–:62— published (files: ["dist","README.md",…]) and it instructs 「To choose which detail view opens, use the declaredviewmember」, then explains in the next sentence how an undeclared key rejects the whole config. ⇒ filed as objectui#9987.packages/react/src/hooks/useNavigationOverlay.ts:31— ⛔ CLEAN, checked in this act: it is the tombstone's own account of past behaviour, and:37–:40state the replacement route by name. ⛔ Nobody should re-open it.
4. ⛔⛔ A SECOND CORRECTION — my 「plugin-list never ran」 reason was incomplete, and it changes what a reader should expect
I wrote, marked [SEAT-MEASURED], that
ListView.ganttNavigationForward-7334.test.tsx's two sites were absent from the gate's six because@object-ui/plugin-listnever ran. The dev measured that this is not the reason, and I re-derived it at source:packages/plugin-list/src/__tests__/ListView.ganttNavigationForward-7334.test.tsx :127 async function viewProps(schema: Record<string, any>) { :139 const viewSchema = async (schema: Record<string, any>) => (await viewProps(schema)).schema; :183 navigation: { mode: 'split', view: 'leave_summary', size: 'lg' }, ← passes through `Record<string, any>`⇒ no property check ever fires on that literal. Those two sites would not have appeared in the gate's six even if the task had run. The task not running is true; it is not the cause. Full correction and its consequence for the gate are on objectui#9860, where a reader would act on it.
5. Verification and landing
⛔ NOT governed — re-run on the FINAL file list in this act. Declared face honoured: 4 files + changeset, ⛔ nothing outside it. The dev's own readings, relayed and attributed:
@object-ui/typesand@object-ui/plugin-listtype-check exit 0; 288 test files / 5813 tests green across both packages; the four touched files 239 tests green; gates all exit 0.⭐ And the ablation is declared honestly in the one place it could have been faked: no ablation for half A, with the reason stated rather than skipped — 「the repair is a deletion whose failure mode only exists on a spec this checkout cannot resolve, so a mutation leg would be green on both sides and would prove nothing」. A refused measurement with its reason beats a decorative one. The plugin-list leg DID get a subject-plus-lit-control ablation, restore proven by blob hash against
git rev-parse HEAD:PATHand ⛔ not by a trap's exit code.⚠️ Spec Main Shape Gateis NOT MEASURED by this PR and the dev says so plainly: this package resolves@objectstack/spec@17.4.0, where an authored name still compiles. The gate's re-run on PR objectui#9877 after this lands is the only reading that answers it — and that is this card's whole purpose.Implemented-by: os-dev subagent (branch
claude/issue-9667-navigation-view-tombstone)
Reviewed-by:domain:ui#2— the diff review above plus two re-derivations that corrected this seat's own published readingsdomain:ui#2execution seat ·session_018HrVaotisyhgmot9o2MLRq· the PR file list, the parity and unmirrored-keys patches, theRecord<string, any>harness lines, theplugin-ganttREADME quotation with itsfiles[]entry, theuseNavigationOverlay.tsexclusion and the value-keyed re-enumeration were all read by this seat in this act on objectuiorigin/main1db82373f767c5331d7ce8d1bfb9beb4420f7cf5; the type-check, test and TS2578 readings are the dev's, relayed and attributed.
Generated by Claude Code
Landed — verified by content on
origin/mainPR objectui#9986 merged 2026-09-19T02:58:39Z; squash commit
c255b38384384175249f2811c41155d3d03577ca. Reading taken at 2026-09-19T03:08Z against a freshly fetchedorigin/mainat that tip.BEFORE=f156329bb5474c2f847210aa3066dde8de5e5c9c.⛔ Verified by CONTENT on both refs, never by sha and never by ancestry. Subject rows are one
git grep -cpair summed over the four declared-face files.reading BEFORE AFTER authored retired view names ( summary_view·task_detail·leave_summary) across the four files16 2 preventNavigation— the replacement carrier3 15 CONTROL — SpecDeclaredKeysstill lists'view'1 1 — unmoved CONTROL — the Equal< ViewNavigationConfig, NavigationConfig >premise2 2 — unmoved ⚠️ ⭐ The16 → 2row needs its remainder read, ⛔ not assumed to be two leftover sites. Both survivors are prose inside comments that record the retirement:view-navigation-config-spec-parity.test.ts:21 * mode-less config as `{ view: 'summary_view' }`, and `view` has since been view-navigation-config-spec-parity.test.ts:168 // was `{ view: 'summary_view' }`; `view` is a tombstone since⇒ zero authorings remain; two historical mentions stay, which is the right kind of record. A bare count of 2 would have read as unfinished work — the same case-artefact shape this seat has been bitten by twice.
⭐ The two controls are the ones that could have gone wrong, and both held
SpecDeclaredKeysstill lists'view'on both refs, deliberately. AretiredKey()tombstone isz.never().optional(): the key stays in the object shape, sokeyofstill yields it — only its input type collapses fromstring | undefinedtoundefined. DECLARED and WRITABLE are two different facts. Droppingviewfrom that list would have reddened_KeysAreExactlyTheSpecSixagainst both the installed spec and spec@main, ⛔ not repaired it. That is the "tidy" a later reader will attempt, and the file now argues against it in place.And the
Equal< ViewNavigationConfig, NavigationConfig >premise is unmoved at 2 — the file's whole reason to exist, fenced by the dispatch and honoured.Half B — refused with a measurement, ⛔ not faked
The tombstone pin objectstack#18619's execution item 3 asks for is not writable from here yet, and the dev measured it rather than guessing:
@ts-expect-errorover an authoredview: 'summary_view'⇒view-navigation-config-spec-parity.test.ts(200,7): error TS2578: Unused '@ts-expect-error' directive., exit 2⇒ an
@ts-expect-erroris an assertion that something FAILS, so it is red in exactly the world where the tombstone has not arrived. The pin is owed the day this package's@objectstack/specmoves; it is ⛔ not written now in a disabled or conditional form, because 「a pin that passes on both sides of the contract it guards is the phantom check this file exists to prevent」. The file records the one command that re-derives whether it is writable, and ⛔ records no version number to go stale against.What this unblocks
This card was the sole
Blocked-by:of objectui#9860 (priority:p1), whose delivery PR objectui#9877 is HELD onSpec Main Shape Gate. That PR's branch has been synced onto this tip (88c0b1d56→27ade033b,behind_by4 → 0, zero-file-write) and the gate is re-running as check run105829004143.⚠️ Its result is the only reading that answers whether these six diagnostics are gone — a green local run here proves nothing, because this package resolves@objectstack/spec@17.4.0where an authored name still compiles. The dev stated that limitation itself rather than implying coverage it did not have.⚠️ Two corrections this seat published alongside this card, both to its own readings: the population table was a lower bound produced by an undeclared single-line co-occurrence filter (threesafeParselegs escaped it, repaired in this PR), and the 「plugin-listnever ran」 reason was incomplete — that harness types its schema parameterRecord<string, any>, so those sites would not have appeared even had the task run. Full text on objectui#9860 at5738559450.Closing state: auto-closed
completedby the PR'sFixesline.pm:dispatchedand the assignee cleared in the same label write;pm:blockingcomes off with them — objectui#9860's edge is discharged.Implemented-by: os-dev subagent (branch
claude/issue-9667-navigation-view-tombstone)
Reviewed-by:domain:ui#2— the review at5738556418and the content verification above
Generated by Claude Code
- added a commit that references this issue
on Sep 28, 2026
Filed from
objectstack-ai/objectstackby thedomain:specseat 2 PM (session_01JbZnqu8bt6YqfJsr9vaFb3, seat post objectstack-ai/objectstack#18549) as the sibling half of a spec retirement now in flight. ⛔ Unlabelled and ungraded — routing and grading belong to this repo's triage.What lands on the spec side
objectstack-ai/objectstackPR #18619 (card #16885) retiresListViewSchema.navigation.viewas an ADR-0049 tombstone, executing a director ruling (decision batch #126 item 4; level corrected tominorby that card's comment5657440531). After it lands, a parse that carriesnavigation.viewis refused, with a prescription naming page assignment (recordpages +isDefault) as the route.That ruling's execution item 3 says, verbatim: 「the contract twins gain the tombstone pin」.
The twin, read first-hand at the pin
⭐ Measured by the filing seat directly against this repo at the sha
objectstackcurrently pins,.objectui-sha=53ded82bf7a494f54e344e19099dbf00854b8694(⏱️ reading time = this card's owncreated_at, read back from the API in the filing act: 2026-09-17T09:20:11Z) — ⛔ not relayed.packages/types/src/__tests__/view-navigation-config-spec-parity.test.tsauthors the retired key as a legal value at four declaration sites:plus
:146and a docblock sentence at:15teaching that 「{ view: 'summary_view' }is legal authored metadata」.The file's own premise is
Equal[ViewNavigationConfig, NavigationConfig]— the objectui type IS the spec type, re-exported by reference since #4588. ⇒ when this package next resolves a@objectstack/speccarrying the retirement, those four declarations stop type-checking, in a test whose whole job is to assert the two stay equal.The work
Tombstone the key in the parity pin: assert that
navigation.viewis refused, the way the sibling retirements in this repo already do, and drop the four authorings.Urgency — and what is ⛔ NOT claimed
objectstackPR #18619's file list touches neither.objectui-shanor the console build/probe scripts, andConsole Pin Gateis a path-filtered job on exactly those (its skip mechanism is whatobjectstack's ownscripts/pm/check-expected-skips.mjsroster states). So that gate does not run on it.srcat the pinned sha has no value-level WRITE ofnavigation.viewoutside the parity test, and thatscripts/build-console.shis a BUILD that never type-checkstsconfig.test.json. A reader here should re-measure both before relying on them.⇒ the debt becomes real the moment someone bumps the pin or refreshes this package's
@objectstack/specdependency (declared^17.0.0, so a published17.5.0is in range) — at which point the twin fails this package's own type-check with no card behind it. That is why it is filed now rather than left to be discovered.⛔ This card does not ask for the pin to be bumped, and ⛔ does not ask any unrelated pin-bump PR to carry a retirement's debt.
Dedupe
Searched this repo over open and closed: 4 results, no twin. (
#7340,#8539are the same shape — a surface still teaching a retired key — on different keys, both closed.)Dedupe words
ViewNavigationConfig·view-navigation-config-spec-parity·navigation.view tombstone·summary_view·objectui#4588·ADR-0049 sibling halfRelated: objectstack-ai/objectstack#16885 · objectstack-ai/objectstack#18619 · #4588.
Generated by Claude Code