spec(ui): retire ObjectKanbanProps.quickAdd from object-kanban — tombstone, D2 conversion and baselines - #17792
Conversation
📓 Docs Drift CheckThis PR changes 1 package(s): 7 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 2 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 136 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 3632d2b06967d0faf471d7932bdbc030dae66513 && git checkout 3632d2b06967d0faf471d7932bdbc030dae66513
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 482d34d60c1d7bdc808c09a9d4edd152443bb101 10f206359fdf490336571717f8dc033b23080a9f && git checkout -B drift-repro 482d34d60c1d7bdc808c09a9d4edd152443bb101 && git merge --no-ff 10f206359fdf490336571717f8dc033b23080a9f
node scripts/docs-audit/affected-docs.mjs --json 482d34d60c1d7bdc808c09a9d4edd152443bb101
|
At-tier contract review — BLOCK on head
|
| question | verdict | the evidence that settles it |
|---|---|---|
| Is the narrowing exactly ruled option B? | ✅ | ⭐ A direct probe against the head's registry: a stack carrying quickAdd on object-kanban (region / nested / slot), kanban-ui (×3), kanban, kanban-enhanced, object-grid → after apply, only the three object-kanban sites lose the key; all others keep it. 3 notices, all at object-kanban paths |
Is kanban-ui still live? |
✅ | at the pinned sha: KanbanRenderer passes quickAdd/onQuickAdd, KanbanImpl gates on both — exactly what B preserves |
| Registration complete? | ✅ | ADR-0087 disposition, D2 conversion, RETIRED_KEYS_BY_MAJOR[18], D3 chain step, authorable-surface [RETIRED], docs row, 4 pin tests — and regenerating registry.ts produced 0 porcelain difference, so it is generated, not hand-edited |
Is Clause-②: yes correct? |
✅ | the prescription text reaches dist/ui/index.js and .mjs; positive control a shipped describe at the same 2 files, negative control test-only text at 0 |
| Collateral narrowing? | ✅ none | whole 8-file diff read hunk by hunk; neighbouring forwarded keys coverImageField / conditionalFormatting verified still live and still read at the pin |
| Do the pins discriminate? | ✅ | run against the merge-base schema: 2 of 4 fail — the two refusal pins flip, the other two guard the strip direction. ⛔ Not four green pins mistaken for four proofs |
⭐ A correction the review makes to the round's own reasoning
minor is the right level — but ⛔ not for the stated reason. "api-surface/ is unchanged, so no export leaves, therefore minor" conflates two ratchets: that test is right for the export ratchet and is not what licenses a key-level narrowing. What licenses it is the launch-window guard in check-changeset-no-major.mjs plus the three key-level carriers that did move — the authorable-surface [RETIRED] row, the RETIRED_KEYS entry, and the BREAKING banner. Same conclusion, sounder ground.
⛔ What the review could not measure — stated, not omitted
Lint & Repo Gates was still running · check:react-declaration-parity needs an external browser artifact (EXTERNAL_INPUT_REQUIRED) · objectui's interim module (PR #8922) predates both the pin and the sibling checkout, so not counted in either direction · out-of-repo authors of quickAdd, which the in-repo zero cannot speak to · the full 13,443-test suite was not re-run end to end (CI's shards all concluded success at this head).
⇒ Disposition: the fix is one line and has been sent back to the delivering round, which retains its full context. ⛔ The PR stays draft; no flip, no enqueue, no auto-merge. The next head owes a re-run of check:objectui-pin-citations and a re-confirmation that the four pins still discriminate —
domain:spec execution seat · session_01MkQhmuuJAVDjmeWNixwDDH · verdict adopted 2026-09-12T05:32Z
Generated by Claude Code
…and correct the ObjectKanban anchor
Scoped at-tier re-review of head
|
| re-measured because the fix touched it | reading |
|---|---|
| the 4 pin tests still discriminate | ablation on the tombstone: 2 failed / 2 passed — the two refusal pins flip, as before. Mutation proven on disk (quickAdd: retiredKey 1→0, marker 1, blob changed), restored byte-identical |
registry.ts generator-current |
exit 0, regen byte-identical |
| diff scope vs merge base | still exactly 8 files |
| ⭐ the anchor correction, verified at the pin | :930 is <KanbanRenderer schema={{, :931 is ...effectiveSchema, ⇒ :931 is right. All 7 occurrences across 6 files now read :931; ObjectKanban.tsx:930 tree-wide → 0, with the :931 probe as its control |
⇒ the round's decision to widen the fix from the one flagged site to all six was correct, and the widened anchor is right everywhere.
Relied on without re-deriving — and only because the delta is comment-only, which was measured rather than assumed: the type-scoped narrowing being exactly ruled option B, kanban-ui still live, registration completeness, the dist clause-② measurement, and minor as the level. ⛔ Had measure 1–3 come back otherwise, all five would be void.
Two NON-BINDING findings, neither blocking
⚠️ Pre-existing anchor imprecision the fix did not introduce: the entries file,migrations/registry.tsandcomponent.zod.ts:2834citeindex.tsx:196for bothquickAddandonQuickAdd; at the pin:196passes the first and:197the second. The substantive claim (both are forwarded together) holds. Outside the gate's population, so nothing would flag it — worth:196-197on a future touch.--verify-anchorslists the new entries file with 2 unasserted anchors on its coverage worklist; that floor is a ratchet, not a requirement on new records. Informational.
⛔ What the review could not measure — stated, not omitted
CI's own run of the pin gate was still in progress (Lint & Repo Gates, three Test Core shards); every completed check on the head is success, and the gate reading above is a local run at the exact sha with a lit control, ⛔ not CI's. --verify-anchors verified 0 anchor-content assertions because no record in the tree carries a quoted first line, so anchor correctness rests on the direct reads quoted above. The full spec suite was not re-run — out of the bounded scope, the delta being comment-only.
⇒ Disposition: cleared. The landing sequence is armed under its own guards — flip, re-read ④ after the flip (it re-triggers Check Changeset and the queue guard), arm only on a fresh GREEN. ⛔ Nothing is armed on this verdict alone.
domain:spec execution seat · session_01MkQhmuuJAVDjmeWNixwDDH · verdict adopted 2026-09-12T06:05Z
Generated by Claude Code
Carrier cleared —
|
| # | check | reading |
|---|---|---|
| ① | at-tier verdict (clause-② is yes) |
PASS_WITH_FINDINGS on the head that lands, linked above |
| ② | check-clause2-carriers.mjs --pair 17792 |
exit 0 — "the clause-② declaration is readable in the fixed spelling and both carriers agree" |
| ③ | check-governed-merges.mjs --test over all 8 final diff paths |
exit 0 — "0 of 8 path(s) hit the register (5 surfaces)" · ⭐ lit control: the same predicate with AGENTS.md appended → exit 3, GOVERNED. So the 0 is a verdict, not a predicate that answers NOT-governed to anything |
| ④ | every check green, newest run per check NAME | re-read after the strip, below |
⭐ One correction to my own instrument while I was at it: I first ran ③ as --branch <name>, which this script does not accept — it silently fell through to the repo-wide governed-merge sweep and exited 2 for both the target and the control. Two identical answers from a probe that was not aimed at the question. The flag is --test <paths…>, and it was the dead control that said so.
What I am doing now
Stripping needs:contract-review from both carriers — this PR and card #17260 — in an additive-removal write with a read-back diff, then re-arming. ⛔ No second review is being invented and ⛔ no label is being stripped "to get past the check": the verdict predates the enqueue by 14 minutes.
Generated by Claude Code
Fixes #17260
Executes the objectui#8285 director-seat ruling (comment 5583979207, decision batch #91, 2026-09-08, standing maintainer delegation) — ruled option B:
quickAddis retired from theobject-kanbanboard and stays only on thekanban-uiblock, where a React host can supply the runtime function the control needs. This PR is the tombstone half that ruling assigns to this repo. A vs B is not re-opened here.ObjectKanbanProps.quickAddis retired fromobject-kanban.The premise, re-measured rather than relayed
The card's body said an author writing
quickAdd: truegot "nothing, with no diagnostic". The filer corrected that themselves, and the correction is what holds — re-measured here at the objectui sha this repo pins (.objectui-sha=53ded82bf), not at that checkout's HEAD:onQuickAddinplugin-kanban/src/ObjectKanban.tsxonCardClick— 6quickAddin the same fileobjectName— 38object-kanbanregistrationinputs(index.tsx:421-431)objectName,columns—quickAddabsentobjectNamepresentThe board forwards the key —
ObjectKanban.tsx:931spreads the authored bag intoKanbanRenderer, which passesquickAdd={schema.quickAdd}alongsideonQuickAdd={schema.onQuickAdd}(index.tsx:196) — butKanbanImplgates the affordance on both (:355,:368), andonQuickAddis a host-supplied function JSON cannot carry and no producer puts on anobject-kanbannode. So the gate was permanently false: accepted-and-dropped, exactly as the card classifies it.Two readings the card's numbers came from could not be reproduced at the pin, and are reported as such rather than passed on:
OBJECT_KANBAN_INPUTS(the 13-key constant) and theinert-quick-addinterim diagnostic do not exist at53ded82bfat all — both are later objectui work.OBJECT_KANBAN_INPUTSdoes resolve at that checkout's HEAD (control lit, 3 files), and the registry-spec ledger records the key verbatim there asESCALATED (object-kanban.quickAdd — measured NOT honoured). The pin's own equivalent reading is theinputsrow in the table above, and it says the same thing.The retirement kit
ObjectKanbanPropsSchema.quickAddretiredKey()tombstone —tsctypes itnever, and a value reaching the parse raises the prescription instead of a bare unknown-key verdictquickAddamong the keys reached "via the forwarded schema" — true about the FORWARD, false about the READ, which is how the key kept re-authorizing itself. Corrected in the same strokesrc/conversions/registry.tsobject-kanban-quick-add-removed— a pure lossless delete (the key never had an effect to preserve), scoped by componenttypeso the LIVEkanban-uispelling stays out of its reachmigrations/entries/retired-keys/18.ui__ObjectKanbanProps__quickAdd.tsRETIRED_KEYS_BY_MAJOR[18]entryui/ObjectKanbanProps:quickAdd, plus the D3 chain-step wiring and rationaleauthorable-surface/ui.jsonui/ObjectKanbanProps:quickAdd [RETIRED]content/docs/references/ui/component.mdxsrc/ui/component.test.ts.changeset/17260-object-kanban-quick-add-retired.mdminor,adr-0087: registered object-kanban-quick-add-removedpackages/spec/src/ui/view.zod.tsis untouched — it is another round's declared face this batch. Thekanban-uiblock'squickAddis untouched by design: it is not a component type this spec declares at all, which is why the conversion is scoped bytyperather than by key name.Liveness — measured, with a lit control
Zero stored or example stacks in this repo carry
quickAdd, because noobject-kanbancomponent is authored anywhere underexamples/orapps/. The zero is a reading, not a dark probe: the same instrument over the same corpora returnsobject-grid3 andobject-metric8. Repo-wide,quickAddoccurred in exactly four places before this PR — the schema key, the docblock sentence, the ratchet row and the generated docs row — i.e. only the carriers being retired here. Out-of-repo authors are unknown and unknowable from here, which is what the D2 conversion and the prescription exist for.Verification
pnpm --filter @objectstack/spec buildVERDICT command-exit 0pnpm --filter @objectstack/spec testVERDICT command-exit 0— Test Files 473 passed (473), Tests 13443 passed (13443)pnpm --filter @objectstack/spec typecheckpnpm --filter @objectstack/spec check:generatedgen:migration-registry, then the build'sgen:schema, thengen:docs)pnpm --filter @objectstack/spec check:migration-registry✓ src/migrations/registry.ts is current (202 semantic, 168 retired-key, 178 retired-def)node scripts/check-adr-0087-registration.mjs --base origin/main✓ 1 declared-breaking changeset(s), each carrying an ADR-0087 disposition—registered object-kanban-quick-add-removed (new here)node scripts/check-changeset-no-major.mjs --base origin/main✓ This diff introduces no major bumppnpm check:nul-bytesThe registry was regenerated by the repo's own generator (
pnpm --filter @objectstack/spec gen:migration-registry→✓ wrote src/migrations/registry.ts), never by hand; the first build before that run failed loudly with1 key(s) were tombstoned with no registered retirement, which is the gate doing its job.Ablation — the pins can fail. On
HEAD: 4 passed. With the tombstone mutated back to a livez.boolean().optional()in source (mutation proven on disk: tombstone-call count 1 → 0, injected marker 1, blob hash106299e7…→e657a7e3…), the same run goes 2 failed / 2 passed: the two refusal pins are the discriminating half. Restored fromHEADand proven byte-identical (blob back to106299e7…,git diff HEADempty). Reported honestly: thenot.toHavePropertypin does not flip under that mutation — an optional key absent from the input is not materialized either way — so it guards the strip direction and not the refusal.Changeset — measured, not assumed
Owed, at
minor.dist— 2 hits,dist/ui/index.jsanddist/ui/index.mjs, both insidepackages/spec'sfiles[].component.test.ts— 0 hits indist.Level is
minor, notmajor:scripts/check-changeset-no-major.mjsforbidsmajorduring the launch window (lockstep versioning would promote ~70 packages), and the sibling retirement one entry over (ui/ObjectGridProps:defaultSort, #11805) is registered under protocol 18 on the same reading.api-surface/is unchanged and correctly so — it ratchets export existence, andObjectKanbanPropsstill exists, one key narrower.Not flipping this ready
An at-tier contract-review verdict is owed on the head that lands;
needs:contract-reviewrides this PR. Draft, not enqueued.Co-Authored-By: Claude noreply@anthropic.com
🤖 Generated with Claude Code
Generated by Claude Code
Generated by Claude Code