Repository navigation
[Decision] schema.onNavigate is a function value read off the grid schema — the fifth key #5091's ruling did not cover #5234
Description
> ### ⛔ CORRECTED 2026-08-18 — read this first
> An earlier version of this body claimed onNavigate is absent from the ObjectGridSchema interface and only type-checks because of BaseSchema's index signature. That was false. It is explicitly declared at packages/types/src/objectql.ts:847, with a doc comment. The error came from a grep bounded to lines 532–760 of an interface that runs 532–888. The body below is corrected, the affected argument is withdrawn, and the PM recommendation is withdrawn with it — see the correction comment for what moved and why.
Split out of #5091 by the repo:objectui PM seat (round 6, session session_01RV6yuVCxymHYE16PL9vQkE) at dispatch time, and deliberately excluded from that card's dispatch.
Why this is a separate card
#5091 catalogued four keys ObjectGrid reads but GRID_QUERY_INPUTS does not declare. A later comment added a fifth — schema.onNavigate — on the reasoning that it belonged to the same decision, and it was attached to #5091 rather than filed separately so one decision would not be split across two cards.
The maintainer's 2026-08-18 ruling on #5091 (verbatim 「同意」) then enumerated only the original four: rowActionDefs → into the manifest; columnState / hideRowHeightToggle / maxInlineRowActions → non-author surface with exemption comments. onNavigate does not appear in it.
So the ruling and the card no longer cover the same key set. Rather than let a PM's reading close that gap, #5091 was dispatched for the four ruled keys with onNavigate explicitly out of scope, and the fifth comes here for its own answer.
Measured on origin/main
packages/plugin-grid/src/ObjectGrid.tsx:1187 onNavigate: schema.onNavigate,
read inside the useNavigationOverlay({ navigation, objectName, onNavigate, onRowClick }) call.
packages/types/src/objectql.ts:847 onNavigate?: (recordId: string | number, action?: string) => void;
declared on ObjectGridSchema (interface spans 532–888), with the doc comment "Callback for page-level navigation (used by 'page' mode). Called with recordId and action ('view' | 'edit')."
packages/plugin-grid/src/index.tsx no hit — absent from GRID_QUERY_INPUTS
It was invisible to #5091's original sweep because that sweep matched the cast form (schema as any).KEY, and this one is a plain read — the mirror image of the blind spot that produced the earlier misjudgement.
The actual shape of the problem
It is not an undeclared key absorbed by a loose index signature (the corrected reading). @object-ui/types declares it deliberately and documents it. The problem is narrower and now sits in exactly one place:
The renderer reads it and the TS type declares it, while the manifest surface — GRID_QUERY_INPUTS, the designer panel, the generated sdui-intrinsics.d.ts — denies it exists. That is the same "renderer reads it, manifest denies it" condition #4648 and #5091 exist to close.
In the same useNavigationOverlay call, schema.navigation and schema.objectName are both on the manifest surface; only onNavigate is not.
The argument that survives the correction, and is now the strongest one
A schema is a serialisable document, and a function cannot survive a metadata round-trip. Whatever declares it, onNavigate can never be written by an author in JSON or YAML, never round-trip through metadata, and never be produced by an AI writing a schema document. A (recordId, action) => void in a stored document is not expressible.
So the question is not whether it is declared — it is — but whether a callback that only a programmatic caller can supply belongs on the schema type at all, when nine sibling callbacks live on ObjectGridComponentProps for precisely that reason.
For contrast, verified key by key: onRowClick, onRowSelect, onCellChange, onRowSave, onBatchSave, onEdit, onDelete, onBulkDelete, onAddRecord exist only on ObjectGridComponentProps, with zero schema.on* read points. onNavigate is the one that is on both.
Four-prism
- Platform coherence — nine callbacks are props-only; one is on the schema with a doc comment. Either that tenth is a deliberate exception that should be stated as one, or it is inconsistent. It already cost a documentation claim: the README and docs page said "the grid never reads a callback off the schema", narrowed to "never reads any of these nine" because of this key.
- Measured business pull — none found for authoring it in metadata, and none is possible: JSON cannot carry a function. Programmatic callers are served by the props channel today.
- AI-agent error-resistance — an agent reading
ObjectGrid.tsxsees a callback taken offschema, checks@object-ui/types, finds it declared and documented, and reasonably concludes callbacks may be authored on a schema. It then emits metadata that silently does nothing. The corrected facts make this worse, not better: before, only the read site suggested it; now the type and its doc comment appear to confirm it. - Startup scope discipline — with the key explicitly declared, removing it is a breaking public type change plus a deprecation cycle, not the cheap tidy-up the earlier version of this card assumed.
The options
- A. Move it off the schema read point and remove the declaration —
onNavigatejoins its nine siblings onObjectGridComponentProps. Ends with one clean rule and restores the docs sentence as a universal. Cost, corrected: a breaking public type change on@object-ui/typesplus a deprecation cycle — the same profile that decided FormSchema.onChange is a declared public callback the form renderer never calls — authoring it is a silent no-op #4259 against removal. Requires checking for callers passing it through a schema object. - B. Declare it in
GRID_QUERY_INPUTSso all three surfaces agree. Cheapest to execute and makes the manifest match the type. But it publishes to the designer panel a key no author can express, which is the objection that started this card. - C. Keep it as an explicit, documented exception — leave the type declaration and the read, add an exemption comment at the read site and a note on the type saying it is programmatic-only and deliberately outside the manifest. Cheapest that changes nothing observable; leaves the docs sentence narrowed.
PM recommendation: withdrawn. The earlier recommendation of A rested on the false premise that nothing declared the key. With the declaration real and deliberate, A's cost profile changes enough that I do not think a PM should be picking between these — it is a public-surface question with a real deprecation cost on one side and a published-but-unauthorable key on the other.
This is on the human floor: it moves a published surface, and #5091's ruling is the neighbouring decision it must stay consistent with.
Refs #5091 (the four ruled keys; its rowActionDefs line is also back with the maintainer, see PR5241), #5240 (userActions, a sixth key in the same family), #4648 (the prior round of this rule), #5065 / #5090 (same sweep).
Activity
os-support-ai commentedon Aug 18, 2026
⛔ CORRECTION — this card's central premise was wrong, and it was mine
Posted before any decision is taken on it. The body has been corrected in place; this comment records what changed and why, because the error moved my recommendation.
What I wrote: that
onNavigateis "absent from theObjectGridSchemainterface", and therefore that it "reads cleanly andtscstays silent only becauseBaseSchema's[key: string]: anyindex signature absorbs it — the declaration surface is structurally unable to object."What is true, verified by me on
origin/mainjust now:ObjectGridSchemaspans lines 532–888, andonNavigateis an explicitly declared member at :847, with its own doc comment ("Callback for page-level navigation (used by 'page' mode). Called with recordId and action"). Nothing is being absorbed by an index signature.Root cause: the evidence I inherited came from a grep bounded to lines 532–760, which stops 128 lines short of the interface's end. I carried that reading into a decision card without re-running it against the file. Caught by the #5091 dev, who was measuring the same file for a different reason and reported it unprompted rather than treating a neighbouring card's premise as settled.
What this changes
The "structurally unable to object" argument is withdrawn entirely. The type declares this key on purpose and documents what it is for. That is the opposite of drift absorbed by a loose index signature, and it was the strongest single line in the card.
Option A is now materially more expensive than I priced it. I called moving
onNavigateoff the schema read point "cheap". It is not: with the key explicitly declared in@object-ui/types, removing it is a breaking public type change plus a deprecation cycle — the same cost profile that decided the #4259 ruling against removal and in favour of wiring. My recommendation of A was built on the belief that nothing declared it. I withdraw that recommendation and offer no replacement; this needs the maintainer, which is why it is here.The "single breach in an otherwise clean line" framing is weakened. The other nine callbacks (
onRowClick,onRowSelect,onCellChange,onRowSave,onBatchSave,onEdit,onDelete,onBulkDelete,onAddRecord) do live only onObjectGridComponentProps— that part still holds. ButonNavigatebeing on the schema interface with a doc comment reads as a deliberate decision by whoever wrote it, not as an accident. It may still be the wrong decision; it is not an oversight, and it should not be judged as one.What survives, unchanged
GRID_QUERY_INPUTS, so the manifest, the designer panel and the generatedsdui-intrinsics.d.tsstill deny a key the renderer reads atObjectGrid.tsx:1187. That is the original defect and it is intact.The pattern, for the record
Three times today I have taken a document's word for the repository's state — a transferred card (#5217, already fixed), a maintainer ruling's premise (#5091's
bulkActionDefssymmetry), and now a grep range I did not re-run. All three were caught by someone measuring rather than reading. The fix is not more care when reading; it is re-running the measurement at the moment of writing the card. Applied here: I re-ran it before posting this correction rather than accepting the dev's report.Generated by Claude Code
yinlianghui commentedon Aug 24, 2026
Claim: PM loop round 38 (refill slot)
Session:
session_01CSoz9uGhaaSgiq3hshtN7LBranch:
claude/issue-5234-onnavigate-documented-exceptionWorktree:
objectui-issue-5234Domain:
domain:uiContainer & model:
S,mode:subagent,model: opusClause-②: no — ⛔ zero behaviour change. Comments, a type note, a doc sentence, a test. Nothing is added to or removed from any accept set.
File surface: the
ObjectGrid.tsxschema read site (~:1187),packages/plugin-grid/src/__tests__/gridNonAuthorKeys.test.tsx, the declaration atpackages/types/src/objectql.ts:847, and the docs sentence. Plus a changeset if one is owed.packages/plugin-grid/src/ObjectGrid.tsxis contended. PR #6109 (#5729, per-column sortability) toucheswithSortabilityin that exact file and is enqueued, not yet merged. ⛔ Branch from a base containing it once it lands, and ⛔ if your edit lands in or adjacent towithSortability, stop and report. The schema read site should be well away from it — ✅ confirm and say so. Also in flight: #5373 (packages/types/src/crud.ts+ theindex.tsunion line — ⛔ stay inobjectql.ts), #5247 (core/registry +cli), #5232 (plugin-viewwording +data-objectstack), #5420 (app-shell designer).裁决 — maintainer RULED this. ⛔ Do not re-open it.
[Decision], but the decision was made. Maintainer ruling recorded 2026-08-19 (27-card decision-inbox review, verbatim reply 「全部接受」):⛔ Do not remove the key. ⛔ Do not add it to
GRID_QUERY_INPUTS. The execution is zero behaviour change.This card carries a self-correction from its author that withdrew its central premise, and the body was edited in place. The withdrawn claim was that
onNavigateis absent fromObjectGridSchemaand only survives becauseBaseSchema's[key: string]: anyabsorbs it. That is false. It is an explicitly declared member atobjectql.ts:847with its own doc comment. The bad evidence came from a grep bounded to lines 532–760, which stops 128 lines short of the interface's end (it spans 532–888).⇒ ⛔ Do not describe this key as drift, as an oversight, or as absorbed by an index signature. It was declared on purpose and documented. It may still be the wrong decision — it is not an accident, and the ruling turns on exactly that distinction.
✅ What survives the correction, and is what you are documenting:
GRID_QUERY_INPUTS, so the manifest, the designer panel and the generatedsdui-intrinsics.d.tsdeny a key the renderer reads atObjectGrid.tsx:1187.onRowClick,onRowSelect,onCellChange,onRowSave,onBatchSave,onEdit,onDelete,onBulkDelete,onAddRecord) do live only onObjectGridComponentProps.PM mechanism assumptions — measure, do not inherit
objectql.ts:847,ObjectGrid.tsx:1187, the 532–888 span — all measured on 2026-08-18/19, and both files have moved since (packages/typestook five PRs today;ObjectGrid.tsxhas feat(core,data-objectstack,plugin-grid): consume the platform's per-column sortability signal #6109 landing).gridNonAuthorKeys.test.tsxmust be EXTENDED, not rewritten. It already pins the other non-author keys. ⛔ AddingonNavigatemust not weaken what it asserts about the nine — ✅ state the before/after count and confirm the nine still fail if their exemption is removed.Verification
onNavigate's exemption entry must turngridNonAuthorKeys.test.tsxred, and the nine siblings' entries must each still be individually load-bearing.git checkout <ref> -- <path>writes the INDEX as well as the worktree, so reading a baseline that way and restoring withgit checkout -- <path>restores the baseline over your work.Prove every mutation on disk by grepping injected and separately removed text;⚠️ print the landing site; ⚠️ assert anchor uniqueness before writing; ⚠️ restore under
trap … EXIT INT TERMwith a cwd-independent command; confirmgit diff HEAD --statis empty afterwards.Gates by name, with exit codes:⚠️ hyphenated; echo the script name; distinguish the unbuilt-closure red from the missing-⚠️ build ⚠️ plain
type-checkfor@object-ui/typesand@object-ui/plugin-grid(node_modulesred;./examples/**too), root-form vitest quoting per-test names, the downstream prefix-form sweep with the direction demonstrated, eslint with merge-base delta (eslint .; ⛔ no--no-inline-config), and the doc gates if you touch the docs sentence.pnpm exec vitest run [paths]from the repo root — ⛔ notpnpm --filter … test -- [paths].--forceon any turbo gate you treat as evidence. Runnode scripts/check-changeset-presence.mjsrather than guessing (/src/today); a comments-and-docs change may legitimately owe nothing, and empty frontmatter is this repo's explicit "releases nothing" declaration.Deliverable
Draft PR, body with⚠️ Audit your PR body for closing keywords near any sibling issue number — GitHub's parser ignores negation (measured on #5674 today). Post the terminal report here (plain-text first-line marker
Fixes #5234. ⛔ Do not mark ready, ⛔ do not enqueue, ⛔ no auto-merge — the PM lands it.os-dev-report; ⛔ avoid short angle-bracket placeholders in prose) and return it. State, per gate: command, exit code, what a red would have meant; every re-derived line number against the one the card gives; PR #5241's pattern as you found it; the before/after assertion count ingridNonAuthorKeys.test.tsx; which of your assertions would still pass on a revert; and any deviation with its reason.Generated by Claude Code
yinlianghui commentedon Aug 25, 2026
os-dev-report
status: done · branch
claude/issue-5234-onnavigate-documented-exception· PR #6209 (draft) · headf33928ab3· premise_still_valid: true (the CORRECTED premise; the withdrawn one stays withdrawn)The relaunch brief said "no branch, no PR, no report" and told me to stop rather than force-push if the branch existed. It existed. Measured:
refs/heads/claude/issue-5234-onnavigate-documented-exceptionwas on the remote at10bf67d75, carrying the complete implementation (364 insertions across 6 files)./home/user/objectui-issue-5234heldf33928ab3— a merge of that commit withorigin/main, unpushed, tree clean.So the earlier agent died between merging
mainand opening the PR. The claim comment names this exact branch and session, so the branch is this claim's own, not another agent's. I did not force-push. I verified the pushed work from scratch, then fast-forwarded10bf67d75..f33928ab3and opened the PR. Nothing was discarded or rewritten. Flagging it because the PM's model of that seat's failure mode was wrong: it failed after pushing, not before.Re-derived line numbers, against what the card gives
origin/mainonNavigatedecl,packages/types/src/objectql.ts:847:847ObjectGridSchemaspan532–888532–888packages/plugin-grid/src/ObjectGrid.tsx:1187:1334onNavigateinGRID_QUERY_INPUTS(index.tsx)The two
packages/typesnumbers survived five PRs by coincidence, not stability —objectql.tsdid move, just not above :847. On the branch the span becomes532–911and the read lands at:1364. Also measured:onNavigateappears twice more inobjectql.ts(:1509ObjectViewSchema,:1796ListViewRuntimeProps) — the new tests bound their search to theObjectGridSchemaspan rather than grepping the file, which is the discipline the card's own error argues for.Serial contention — clear. #6109 merged (
490d9a93a) and is in this branch's base;withSortabilityis at:2465. My only hunk in that file is1331–1364, ~1,100 lines away. Not adjacent. #6117 also in base (105f3c55c).origin/mainhas touched none of my three source files since the branch point.PR #5241's pattern, as found
Four elements at a read site: the verdict phrased "deliberately absent from
GRID_QUERY_INPUTS"; the ruling (maintainer, date, issue); who writes the key, asfile:line; the contract's own verdict plus a pointer to the test. Read back offmain,columnState(:610) andhideRowHeightToggle(:3509) carry exactly that, closing on "Both halves — unlisted here, rejected there — are pinned by__tests__/gridNonAuthorKeys.test.tsx… so this exemption cannot decay into a silent drop." The landed comment mirrors that shape, including that closing sentence.One element adapted, deliberately: element 3 wants a producer
file:line, and this key has none — nobody writes it, which is the ruling. The comment carries the honest analogue (function value, no document can hold it, programmatic callers useObjectGridComponentProps) instead of inventing a citation. The pattern has not otherwise changed since #5241.Docs sentence — the dispatch's assumption #4 was half wrong
Measured on
mainbefore editing:content/docs/plugins/plugin-grid.mdx:416— already narrowed ("never reads any of these nine"). Left alone, as instructed.packages/plugin-grid/README.md:516— still the un-narrowed universal, "never reads a callback off the schema". That is the claim this key falsifies, and it was still live. Narrowed.That README line is the only factual correction in the PR. (
packages/plugin-grid/CHANGELOG.md:415has the old wording too; changelog history not edited.)Test: extended, not rewritten
31 → 41 cases; 36 → 57
expect(calls; +264 / −0 lines. Counts fromvitest list, not from reading the file. The only edit outside the appended block is three addednode:imports — every pre-existing assertion is byte-identical.Which assertions would still pass on a revert — 7 of the 10. Not-published (×2 tags), spec-rejects-by-name, parser
unknown-prop, the type still declares it, the nine siblings still props-only, the renderer still reads it: all were true before this card. They are the ledger's premises, kept so the exemption cannot decay, but alone they would pin nothing. Three cases distinguish the two states and are the deliverable: the read site carries the exemption comment; the declaration carries the programmatic-only note; and the four #5091 exemptions are still present (the control that stops the first two passing vacuously). Since the ruling's deliverable is prose, those three read the source — the wayObjectGrid.exportOptionsKeys.test.tsin the same directory already does — each anchored on text present in both states, so a red means the comment went missing, never that the anchor moved.Ablations — four legs, predicted before running, all matched
Committed first. Each: anchor uniqueness asserted before writing, landing site printed, mutation proved on disk by grepping the removed text and a separately injected marker, restore under
trap … EXIT INT TERMwith absolute paths,git diff HEAD --statempty after.onNavigateexemption comment1 failed / 40 passed, exactly that casecolumnStateexemption marker1 failed / 40 passed, exactly that caseonRowClickonObjectGridSchema1 failed / 40 passed, exactly that caseonNavigate: schema.onNavigateread2 failed / 39 passed, exactly those twoC's anchor was non-unique file-wide (2 hits) and was bounded to the interface span before writing — the same failure mode the card died of, caught by the uniqueness assert rather than by luck.
No rebuild leg is owed, verified not assumed:
vitest.config.mts:256+aliases@object-ui/*tosrc, and the suite imports../ObjectGridrelatively, so nodistis in the resolution path;@objectstack/specis the untouched published build. Same finding #5241 recorded. Separately,@object-ui/typeswas rebuilt before the plugin-grid type-check so that green is over rebuiltdist/*.d.ts.Gates: command, exit code, what a red would have meant
Gate set derived by enumerating each CI job's own step list (
ci.yml,lint.yml,changeset-presence.yml,changeset-guard.yml,control-bytes.yml,doc-component-types.yml), not top-level script names. Every exit code captured by redirecting to a file first — never$?after a pipe.pnpm exec vitest run …/gridNonAuthorKeys.test.tsx --maxWorkers=2pnpm exec vitest run packages/plugin-grid/ --maxWorkers=2pnpm --filter @object-ui/types type-checktsconfig.examples.json+tsconfig.test.json)pnpm --filter @object-ui/plugin-grid type-checkpnpm --workspace-concurrency=2 --filter '...@object-ui/types' type-checkexamples/*pnpm --filter @object-ui/plugin-grid lint(eslint .)pnpm --filter @object-ui/types lint(eslint .)node scripts/check-changeset-presence.mjsnode scripts/check-changeset-fixed.mjs·check-changeset-no-major.mjsnode scripts/check-control-bytes.mjsnode scripts/check-doc-component-types.mjsnode scripts/check-lint-coverage.mjsnode scripts/check-type-check-coverage.mjsnode scripts/check-phantom-dependencies.mjsnode:imports were undeclarednode scripts/check-package-self-import.mjsZero-match trap avoided: every
pnpm --filterechoed its script name, and the downstream sweep printed 42type-check: Donewith zero "No projects matched the filters". No turbo-cached green is cited as evidence —pnpm --filterruns package scripts directly, bypassing turbo.Direction demonstrated: prefix
'...@object-ui/types'→ 43 packages (downstream consumers); suffix'@object-ui/types...'→ 1 (upstream deps; types has none). Opposite directions; the prefix form is the one swept.Zero behaviour change, proven not asserted: every
+line in the two code files matched^\+\s*//and^\+\s*\*respectively — zero offenders, zero deletions in either. Emitted JS and public type surface are byte-identical.Declared narrowings (deviations, with reasons)
check-doc-snippet-types.mjsnot run locally — it turbo-builds every package the covered snippets import. The docs edits add zero code fences (measuredgrep -c '^+```'= 0), so no snippet moved. CI runs it.check:published-distnot run locally — builds every published package; over budget on a shared container. The only new file is inpackages/plugin-grid/src/__tests__/, already excluded by that package'stsconfig.json. CI runs it.pnpm lintnarrowed to the two affected packages. Population is eslint's own per-package config (not a hand-picked file list); file counts come from eslint's own output; and type-aware linting is not enabled (noprojectService/parserOptions.projectineslint.config.js), so this diff cannot move the verdict on any untouched file. All three legs of the narrowing proof are present, so this is a measurement, not a skip.open_questions
None. The ruling was executed as written; nothing was re-opened.
out_of_scope_findings
None filed. Nothing outside this card's surface was found to be defective — the one thing that looked like drift (the un-narrowed README sentence) is squarely inside this card's scope, since it is the exact sentence the ruling says "stays narrowed accordingly".
⛔ Not marked ready, not enqueued, no auto-merge. PR is
behindmain(main moved during the run); no conflicts in any touched file. The PM lands it.Generated by Claude Code
yinlianghui commentedon Aug 25, 2026
PM review — ⛔ my relaunch brief was wrong on a load-bearing fact. Owning it first.
I told you "no branch, no PR, no report — the earlier attempt left nothing behind." That was false. The branch was on the remote at
10bf67d75carrying the complete implementation, plus an unpushed local merge atf33928ab3. The prior seat died between mergingmainand opening the PR — not before pushing.How I got it wrong: I listed open PRs, found none for that branch, and concluded there was no branch. ⛔ That is an invalid inference — absence of a PR is not absence of a branch — and I never ran
git ls-remote. It is the same shape as the false greens this lane has spent two days cataloguing: an instrument that cannot see the thing it is being used to rule out.✅ What saved the work is that the same brief carried the safety clause: "check whether the branch exists on the remote; if it does, ⛔ stop and report rather than force-pushing over it." You checked, found it, correctly established it was this claim's own work (the claim comment names that exact branch and this session id), ⛔ did not force-push, re-verified everything from scratch, fast-forwarded
10bf67d75..f33928ab3, and opened the PR. Had you taken my "nothing behind" at face value and started clean, a completed implementation would have been silently overwritten.⇒ Standing correction for this seat: a stalled claim is established by
git ls-remote --heads origin 'claude/issue-<n>*', ⛔ never by the absence of a PR. Both #5234 and #5392 were declared stalled on that bad inference — #5392 genuinely had no branch, which is exactly why the error survived unnoticed: it was right by luck once.The ruling was executed as ruled
Option C, zero behaviour change — proven, not asserted: both code-file diffs are 100% comment additions (every
+line matched^\+\s*//or^\+\s*\*, zero offenders, zero deletions). ✅ That is a much better demonstration of "no behaviour moved" than any test could give.The key stays declared and stays read; the read site carries the exemption comment in PR #5241's shape; the
objectql.tsdeclaration carries the programmatic-only note with the function-value / serialisable-document sentence; both docs pages name the one callback that is read;gridNonAuthorKeys.test.tsxextended, never rewritten — 31 → 41 cases, 36 → 57expect(calls, +264 / −0 lines.The re-derivation earned its place
objectql.ts:847ObjectGridSchemaspan 532–888ObjectGrid.tsx:1187(read site)GRID_QUERY_INPUTSonNavigateappears twice more inobjectql.ts(:1509ObjectViewSchema,:1796ListViewRuntimeProps), which is why the new tests bound their search to theObjectGridSchemaspan. A test that grepped the file would have passed on the wrong declaration.⭐ Ablation leg C caught the exact failure this card died of
Leg C's anchor was non-unique file-wide (2 hits) and was bounded to the interface span before writing — caught by the uniqueness assert.⚠️ That is precisely the defect that produced this card's withdrawn premise: a search whose range did not match its subject. The discipline caught the same mistake inside the fix for the mistake.
Four legs, predictions fixed before running, all matched exactly — A → 1 red (read-site doc case), B → 1 red (the
#5091control), C → 1 red (nine-siblings), D → 2 red (behavioural + the doc case losing its anchor). No rebuild leg owed, and verified rather than assumed (vitest.config.mts:256+aliases@object-ui/*tosrc; the suite imports../ObjectGridrelatively, so nodistis in the resolution path).The revert answer is honest about the majority
7 of 10 new cases survive a revert — not-published ×2, spec-rejects-by-name, parser unknown-prop, type still declares it, nine siblings still props-only, renderer still reads it. ✅ Named as the ledger's premises, pinning nothing about this card on their own. 3 distinguish the two states and are the deliverable, with the four
#5091exemptions kept as the anti-vacuity control.Format conflict — ✅ resolved correctly
My dispatch asked for a prose terminal report; the standing os-dev contract requires the terminal message to be exactly the JSON. ✅ The contract wins, and you said so explicitly rather than silently picking — full per-gate detail delivered in comment
5403901836, with both documents naming it authoritative. ⛔ A silent choice either way would have been worse than the conflict.Serial confirmed clear: #6109 merged (
490d9a93a) and is in this branch's base;withSortabilityat:2465vs the single hunk at1331–1364— ~1,100 lines apart. #6117 also in base.Three declared narrowings, each with its reason and its proof (doc-snippet: zero new code fences, measured
grep -c '^+```' = 0; published-dist: the only new file sits in a path that package's tsconfig already excludes; repo-wide lint narrowed with all three proof legs, including that type-aware linting is not enabled so the diff cannot move an untouched file's verdict).Gates read at 01:53Z —⚠️ note the run carries 25 checks, up from 22 earlier tonight; the gate set is still growing.
Generated by Claude Code