Repository navigation
fix(spec): the object-kanban quickAdd retirement prescribes "delete the key", not the unregistered kanban-ui block - #21141
Conversation
… the unregistered kanban-ui block Claude-Session: https://claude.ai/code/session_017VaLJnYwhPsanVCe9dMCJU Co-authored-by: Claude <noreply@anthropic.com>
…kAdd tombstone Claude-Session: https://claude.ai/code/session_017VaLJnYwhPsanVCe9dMCJU Co-authored-by: Claude <noreply@anthropic.com>
…ickadd-prescription
…e the key, not that the control stays on kanban-ui Claude-Session: https://claude.ai/code/session_017VaLJnYwhPsanVCe9dMCJU Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check3 anchor(s) derived from 1 changed package(s); no hand-written page names any of them. What this run could not see
Coarse fallback — 137 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 1a6e0400f3fb6aebcb6109f6532785091cc54b5c && git checkout 1a6e0400f3fb6aebcb6109f6532785091cc54b5c
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin c6954d6d09080179d3af72c80a820c7c24cf6053 83d99268a356566efa67280cd4007a14b2989ea2 && git checkout -B drift-repro c6954d6d09080179d3af72c80a820c7c24cf6053 && git merge --no-ff 83d99268a356566efa67280cd4007a14b2989ea2
node scripts/docs-audit/affected-docs.mjs --json c6954d6d09080179d3af72c80a820c7c24cf6053 |
Contract reviewServed-tier: Rendered 2026-10-01T09:35Z by an isolated reviewer subagent from card #21017 (body and its four comments: the triage grade, the serial note, the claim, the os-dev-report), PR #21141 (body, its 8 files, the net diff against the merge-base ① Derived judgments
② Semver level
③ Boundary flags
Check-runs on the head, as read at 2026-10-01T09:33Z: 32 runs; 17 success (Auto Label, Build Core, Build Docs, Check Changeset, Check Documentation Links, Check PR Size, Dogfood Verify CLI, Flag docs affected by code changes, Governed Surface Queue Guard, No other open PR may claim the same issue, No other open PR may claim the same single-writer path, Part-of PR must not also close its card, Spec property liveness, The card this PR closes must claim this branch, Type Check · debt ledger, Type Check · source gates, filter); 2 skipped (Console Pin Gate, Packed-tarball smoke (opt-in)); 13 in progress (Dogfood Regression Gate 1/3, 2/3, 3/3; Lint & Repo Gates; Temporal Conformance (live PG + MySQL); Test Core 1/6 through 6/6; Type Check · consumer gates; Type Check · workspace). None failed. Implemented-by: VERDICT: PASS Generated by Claude Code |
…jectui-pin-single-zod component.zod.ts conflicted in two docblocks; both intents stack: main's #21005 (action:button / action:icon refuse `endpoint`) and #21141 (the quickAdd tombstone prescribes "delete the key") are kept verbatim, and the pin bump's citation updates at 31971ff1e are re-applied on top (`inputs` `:414-559` and the slice-2 `size` sentence; `e420df310` in the kanban-ui registration count). Regeneration follows as its own commit. Claude-Session: https://claude.ai/code/session_01MRdbfpy4sQT8bUjmMhxsN7 Co-authored-by: Claude <noreply@anthropic.com>
…ce in the vendored Console), add a single-zod canary to build-console.sh, and key the release console cache on the spec zod range (objectstack-ai#21149) Fixes objectstack-ai#21108 Clause-②: no Moves the console pin past objectstack-ai/objectui#11353, so the vendored Console bundles one zod instance again. Adds a single-zod canary to `scripts/build-console.sh`, and keys `release.yml`'s Console dist cache on the spec's declared zod range. ## Target: `31971ff1e28f`, the minimal containing commit `.objectui-sha` moves `e420df310f5b` -> `31971ff1e28f89cfc45f0c19bc5b05e443f28b79`. That is the merge commit of objectui#11353 itself, which closed objectui#11327. objectui `main` was `2124d0411175`, 2 commits further on, when I chose the target. Why not `main`: - The two later commits are objectui#11293 (standalone `object-kanban` / `object-calendar` honour `page` navigation through the host's record navigator) and objectui#11165 (a docs example and its test). Neither is needed by this card. - objectui#11293 rewrites `plugin-kanban/src/index.tsx` and `plugin-calendar/src/index.tsx`. Nine asserting pin-citation anchors in `packages/spec/src` read those two files. Taking it would turn this pin's citation re-measure into a navigation-claim change outside this card. - The procedure (`docs/releases-maintenance.md`) says the target is decided in the objectstack issue. The card's unlock criterion is "a commit that contains objectui#11353". The minimal containing commit meets it and drags in the least. Containment was measured on a private full clone of objectui (`rev-parse --is-shallow-repository` = false): | question | command | exit | |---|---|---| | pin is the objectui#11353 merge | `gh api …/pulls/11353` answers `merged: true`, `merge_commit_sha: 31971ff1e28f…` | — | | pin is on objectui `main` | `merge-base --is-ancestor 31971ff1e28f origin/main` | 0 | | old pin is inside the new range | `--is-ancestor e420df310f5b 31971ff1e28f` | 0 | | negative: new pin is not inside the old one | `--is-ancestor 31971ff1e28f e420df310f5b` | 1 | | control for that negative (deeper commit, same target) | `--is-ancestor db11afd4967c e420df310f5b` | 0 | | objectui#11293 is NOT in this pin | `--is-ancestor 2124d0411175 31971ff1e28f` | 1 | | control for that negative | `--is-ancestor e420df310f5b 31971ff1e28f` | 0 | The range `e420df310f5b..31971ff1e28f` is 44 commits. ## What changed - **`.objectui-sha` and `.changeset/console-31971ff1e28f.md`.** Written by `scripts/bump-objectui.sh 31971ff1e28f --no-commit` against the private clone, so the shared shallow `../objectui` was never deepened. The range has 56 releasing changesets, 12 declared breaking, and 3 commits carry no changeset. - objectui#11353, the fix this bump exists for, is one of those 3. So I added one lead sentence naming it; the digest would otherwise list it only under "declared nowhere". - The bump script's `adr-0087: TODO` placeholder is answered `not-required (no-migration-prescription)`. It is worded after the maintainer's ruling on the previous bump (objectstack-ai#20949) and fitted to this diff, and it names all 12 upstream entries. Three of them mirror ObjectStack keys that are already retired and registered here: `ui/ChartConfig:aria`, `ui/Page:assignedProfiles` and `ui/Action:aria`. The `object-form` / `object-map` / `object-gantt` / `object-chart` entries move objectui's validator onto the `properties` bag that the spec rows already declare. `showFilters` was never an ObjectStack key on `object-grid`. Please confirm this disposition; see the open question in the report on objectstack-ai#21108. - **`sdui.manifest.json` + `scripts/sdui-manifest.record.json`.** Produced by `node scripts/gen-sdui-manifest-node.mjs` over the tree `build-console.sh` built at the pin: 107 components, `@object-ui/core` 17.6.0. Eleven components changed their published inputs: `object-form`, `object-kanban`, `object-calendar`, `object-gantt`, `object-timeline`, `object-map`, `record:quick_actions`, `element:text`, `element:definition-list`, `element:repeater` and `action:button`. - **`packages/sdui-parser/objectui-lockstep.json`.** Re-recorded with `pnpm gen:sdui-lockstep` against the pin's own checkout: 214 grammar lines, 25 codes, containment predicate `76c18fb95d1f`. `check:sdui-lockstep` exits 0 with no port owed. - **`scripts/build-console.sh`: the single-zod canary.** Details in the next section. - **`.github/workflows/release.yml`: the Console dist key.** Details below. - **The 49 asserting pin citations in `packages/spec/src`.** Re-measured at the new pin (section below). This also regenerates `packages/spec/src/migrations/registry.ts` (`gen:migration-registry`) and `content/docs/references/ui/view.mdx` (`check:generated --fix`, the one artifact it proved stale), and adds `.changeset/objectui-pin-citations-31971ff1e28f.md` (`@objectstack/spec` patch). The `FormField.span` describe and six migration-entry descriptions name the pin, so the text change publishes. - **`origin/main` merged twice.** - First at `19cbfeba7d`: no file overlapped this diff, and no generated artifact moved. - Then `fbcc05f400`, at merge commit `8435a830eb`, through `scripts/pm/os-regen-merge.sh`. There was one textual conflict, in two docblocks of `packages/spec/src/ui/component.zod.ts`. main's objectstack-ai#21005 and objectstack-ai#21141 are kept verbatim, and the pin citations were re-applied and re-measured at `31971ff1e`. No regeneration commit is owed: `check:generated` reports 15/15. That merge also moved the spec's zod to `^4.6.5`; the console still bundles exactly one zod, `4.6.5`. ## The single-zod canary It sits beside the existing bundle canary. - It counts zod version literals across `packages/console/dist/assets/*.js`. Each zod 4 instance carries one version object (the `version` export of `zod/v4/core/versions`), minified as `{major:4,minor:6,patch:5}`. - It requires **exactly one** occurrence. It refuses two different versions (the shipped defect), one version found twice (two instances), and zero (a blind matcher, since the console always bundles zod). - The same function runs standalone as `scripts/build-console.sh --check-single-zod ASSETS_DIR`, which builds and writes nothing. That standalone mode is how both directions below were measured. | fixture | result | |---|---| | the real dist this PR's build produced at `31971ff1e28f` (2450 `assets/*.js`) | exit 0: `exactly one zod version literal {major:4,minor:6,patch:5} in vendor-objectstack-UrN_Az-7.js` | | the real `db11afd4967c` dist (the published two-zod split) | exit 1: `2 different zod versions` — `vendor-objectstack-CfLtdaY1.js:{major:4,minor:6,patch:1}`, `vendor-zod-CHLW1iCr.js:{major:4,minor:4,patch:3}` | | the new dist plus one chunk carrying `{major:4,minor:4,patch:3}` | exit 1, two different versions | | the new dist plus a second `{major:4,minor:6,patch:5}` chunk | exit 1: `2 copies of ONE zod version literal` | | the new dist with its one literal rewritten (`major` -> `MAJOR`; `grep -o` count 1 -> 0 before, 0 -> 1 after) | exit 1: the blind-matcher refusal | | no argument | exit 2, usage | The fixtures are copies in a scratch directory. No tracked file was mutated. ## `release.yml`: the key carries the spec's declared zod range, not the whole `package.json` The card suggested `hashFiles('packages/spec/package.json')`. I went with a narrower input: - A new step reads `dependencies.zod` out of `packages/spec/package.json`. It fails rather than emitting an empty or `undefined` range. - The restore, the `CONSOLE_DIST_CACHE_KEY` env and the save step all spell the same key, with `-zod-RANGE` appended (today `-zod-^4.6.5`, after the merge of `fbcc05f400`). Why not hash the whole file: its `version` field moves on every Version Packages merge, and that merge is the push that drives the publish lane. Hashing it would make every publish a cache miss and a cold console rebuild. The comment above the key records that design as deliberate. The declared range is the input the build actually judges: objectui#11353's parity assertion refuses a console zod outside it. `release.yml` is not a governed surface. `GOVERNED_SURFACES` in `scripts/pm/check-governed-merges.mjs` lists `docs/adr/**`, `.claude/**`, `skills/**`, `AGENTS.md`, `CLAUDE.md` and `docs/NORTH-STAR.md`. No workflow was run or dispatched. ## Pin-citation re-measure Each record was handled the same way: - Its anchors were mapped through the `e420df310f5b..31971ff1e28f` diff of each cited file and re-read at the new pin. - Block hashes (`git hash-object`) and corpus counts (`git grep -o -F` over the tracked tree, 9912 files) were taken again with the method each record names. The method reproduces every `e420df310` count exactly at the old pin: 9800 files, `objectstack` 15352, `@objectstack/spec` 6024, `timeout` 1293. - Earlier hops stay as history. - `check:objectui-pin-citations --verify-anchors`, run against the pin's checkout, reports 49 asserting citations matching `31971ff1e`, and 7 anchor content assertions verified. Records whose CLAIMS moved, not only their numbers. These want a human read: - **`object-calendar` `navigation`.** objectui#8652 declared the key on `ObjectCalendarSchema`. That removes the one `as any` cast objectui#8651 had left: the ledger comment `1008-1025` is replaced by a declaration note, and the read `1026` -> `1018` now says `schema.navigation ?? { mode: 'drawer' }`. - **`object-kanban` `navigation`.** The read is unchanged. It now compiles through a declared `ObjectKanbanSchema.navigation` member rather than `BaseSchema`'s index signature. - **`object-timeline`.** objectui#8654 declared `navigation`. The read lost its cast (`753-756` -> `793-796`), and both registrations gained a `navigation` input. The `schema.*` read set is unchanged, because `navigation` was already read and is already on this row. - **`action:button`.** objectui#11168 slice 2 makes the `size` input publish the five values the row declares. The `inputs` range grew `414-551` -> `414-559`. - **`record:quick_actions`.** objectui#10224 rewrote the fail-closed docblock: the bar is replaced by the notice, not hidden. The cited gate lines moved by 6 with their text byte-identical. - **`object-tree` optionality count.** By the record's own method, `plugin-map/src/index.tsx` now reads 4 `ElementDataSourceGate` hits, not 3. objectui#10859 batch 5 added a comment naming the gate, while the wiring is still three lines. The record now says so. - **Wrong when written.** The `object-timeline` data door's start/end-binding anchor `621-622` began one line early, on the `rawData.map` head, at `e420df310` too. It is re-pointed to `657-658` and the record says why. No key, default, enum member or export moves. ## Acceptance at the new pin **Build.** `scripts/build-console.sh` ran at `31971ff1e28f` with this tree's client and spec injected, under the shared verify lock: `VERDICT command-exit 0`. - The single-zod canary passed (above). `assert-console-spec-injection` passed: 21 of 21 injected-only descriptions are present and all 8 published-only ones are absent. - The dist is 63032 KB. - Environment, not a product change: objectui's `jsdom` requires Node `^22.22.2` under engine-strict, and this container's Node is 22.22.0. A verified Node 22.22.2 was prepended to `PATH` for the console build only. - The build ran before the manifest regeneration, as the procedure orders it. So that local dist ships the previous manifest bytes, and the build itself prints the re-run step. CI's Console Pin Gate builds fresh. **Boot.** `pnpm dev -- --fresh --ui --no-watch -p 41633` started the showcase with its own ephemeral DB and the seeded admin. `check:console-sha` reads `objectui@31971ff1e28f`. I drove it in headless Chromium (`/opt/pw-browsers/chromium`) from `localhost`: - **Studio "New package (writable base)"** (`/_console/studio`): the dialog renders **Display name (`name`)**, **Package ID (`id`)** and **Object namespace (`namespace`)**, plus Version, Type and Description. - I filled `Zod Probe` / `com.acme.zodprobe` / `zodprobe` and clicked Create package. The request was **`POST /api/v1/packages` -> 201**. - The Studio opened `/_console/studio/com.acme.zodprobe/data`. `GET /api/v1/packages/com.acme.zodprobe` answers 200 with `writable: true`. - **Dashboard inspector** (`/_console/apps/showcase_app/metadata/dashboard/showcase_ops_dashboard`): the spec-derived form renders Columns, Gap, Refresh Interval Seconds, Header, Show Title, Show Description and Actions. "Spec schema unavailable" appears 0 times. - **Report inspector** (`…/metadata/report/showcase_task_overview`): Label, Report type, Description and Blocks render, with 0 "Spec schema unavailable". - **Control for that absence:** the string is in the shipped bundle (`i18n-D40RWXZZ.js`, 3 occurrences), so 0 on screen is a reading, not a missing probe. - **Errors:** 0 page errors and 0 console errors across the drive. - **Non-2xx:** - `401 GET /api/v1/auth/get-session` before sign-in. - `404 GET /api/v1/usage/storage`, as at the previous pin. - `501 GET /api/v1/ai/usage`, with no AI provider configured. - `404 GET /api/v1/meta/{dashboard,report}/NAME?state=draft`, the no-draft probe of a code-loaded item. - **Teardown:** only the 7 PIDs I recorded were stopped. The port is free, and the `--fresh` tempdir went with the process. ## Gates and tests, at head `8435a830eb` (re-run in full after the merge: 151 derived, 151 run, 0 NOT-MEASURED, 0 UNRUN) - `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` derived 151 commands, all run sequentially with exit codes captured before any pipe. - 150 exit 0. - `pnpm check:pm-dispatch-gates` hit my 900 s runner timeout under contention (exit 124). Re-run alone with no timeout, it passed: exit 0, `dispatch-gates self-test: 1976 cases pass`, battery 1096.7 s. - `dispatch-gates --ran` reconciliation: `151 derived, 151 run, 0 NOT-MEASURED, 0 UNRUN`. - Highlights: `check:objectui-pin-citations` 49 matching, `check-sdui-manifest` intact at the live pin, `check:sdui-lockstep` OK, `check:console-sha`, `check:console-injection`, `check-adr-0087-registration` (2 declaring changesets, each with a disposition), `check:generated` (15 of 15 current), `check:docs` (227 in sync), `check:migration-registry`, `check:bash32-floor` (32 shell files), `check:nul-bytes`, `check-ci-filter-parity` and `check:published-files`. - `pnpm --filter @objectstack/spec test`: 591 files, 17368 passed and 1 todo, exit 0. `pnpm --filter @objectstack/spec typecheck`: exit 0. - NOT MEASURED, by CI only: the Console Pin Gate job's own steps and the workspace type-check lanes. The local equivalent of the Console Pin Gate is the build above. ## Acceptance notes - `scripts/check-console-injection.mjs`'s header still says release.yml's key "hashes the pin and the build script". That sentence is now incomplete, because the key also carries the spec's zod range. The file is outside this card's file surface. It is a comment, and nothing reads it. - objectui#11353 landed with no objectui changeset, so objectui's own CHANGELOG does not mention the zod fix. The console changeset here names it. --- _Generated by [Claude Code](https://claude.ai/code/session_01MRdbfpy4sQT8bUjmMhxsN7)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
…ntrol to the retired kanban-ui block (objectstack-ai#21224) Fixes objectstack-ai#21143 Clause-②: no ## What `packages/spec/CHANGELOG.md`, inside the released `@objectstack/spec` 17.5.0 entry for 48203ff (the `object-kanban` `quickAdd` retirement), told the reader four times that the quick-add control lives on objectui's `kanban-ui` block: - the ruling sentence: "the key leaves the board and stays only on the `kanban-ui` block, where a React host can supply the runtime function the control needs"; - the table row `kanban-ui` (objectui block), whose `after` cell read **unchanged**; - the "What to write instead" paragraph: "The control itself is not withdrawn from the platform. It stays on the `kanban-ui` block, which a React host renders directly and can hand the `onQuickAdd` slot to"; - the D2 conversion bullet: "scoped by component `type` so the live `kanban-ui` spelling stays out of its reach". objectui registers no `kanban-ui` block. objectui#8865 retired the registration (objectui#8257) on 2026-09-10T10:17Z. 48203ff landed on 2026-09-12T07:24Z, so the retirement came first. The sentences were true of the `.objectui-sha` pin the entry was measured at (`53ded82bf`). They are false of the pin 17.5.0 was versioned at (`dd3f7e1be`) and of today's pin (`31971ff1e`). This PR amends that one entry in place. It uses the shape this file's errata already use (`*Erratum, DATE — … (Corrected after publication, #N.)*`, 7 instances on `main`). The nearest precedent is 576afc1, which amended the 17.4.0 entry the same way: passages corrected in place, then one dated erratum line at the end of the entry that quotes the old phrasing. 1. The ruling sentence now reads "the key leaves the board. Delete the key; `object-kanban` offers no quick-add control." 2. The table row keeps its `before` cell. Its `after` cell now reads "**retired** in objectui (objectui#8257), not by this change: no block a document can name offers the control". The row is corrected rather than deleted, so a reader who greps `kanban-ui` lands on the corrected answer. 3. The "What to write instead" paragraph now says that no block a document can name offers the control. It also says the ruling kept the control on `kanban-ui` and that objectui has since retired that block. 4. The D2 bullet now gives the scoping reason that the conversion's own docblock on `main` gives: by component `type`, never by key name, so a node of any other type that authors the same key is left alone. 5. One dated erratum line ends the entry. It quotes the four old phrasings and says that the retirement, its tombstone and its D2 conversion are unchanged. No other entry and no other file is touched. The corrected wording matches what PR objectstack-ai#21141 put on every non-released copy: the tombstone prescription, the D2 summary and both migration entries. ## Changeset: none, labelled `skip-changeset` `CHANGELOG.md` is in `@objectstack/spec`'s `files[]`, so the next tarball carries this text. A changeset is still the wrong instrument. It would compile the correction into a new entry under a later version. That is the erratum-in-a-later-entry shape that the Documentation Guardrails row for `packages/*/CHANGELOG.md` rules out, and the PR declares no package change. `changeset version` prepends to this file and keeps the amended 17.5.0 entry. 105 pending changesets on `main` already bump `@objectstack/spec`, so the next release ships the corrected entry. This is the same disposition as 576afc1 (PR objectstack-ai#21014, labelled `skip-changeset`). ## Evidence | Reading | Result | |---|---| | `grep -c kanban-ui packages/spec/CHANGELOG.md` at the merge base `ce4e205e` | 4, at lines 1580, 1586, 1616 and 1629 | | npm tarball `@objectstack/spec` 17.5.0, `package/CHANGELOG.md` | the same 4 lines | | objectui registration-key lines (`'kanban-ui',` alone on a line, test files excluded) at the current pin `31971ff1e`, the 17.5.0 pin `dd3f7e1be` and the 48203ff pin `53ded82bf` | 0, 0 and 2 (`plugin-kanban/src/index.tsx:209` and `cli/src/utils/known-schema-types.ts:225` at `53ded82bf`). The firing control `'object-kanban',` on the same instrument reads 4, 4 and 3 | | `.objectui-sha` at 48203ff, and at 8c87d26 (`chore: version packages`, spec 17.5.0) | `53ded82bf`, then `dd3f7e1be` | | Dates | objectui#8865 merged 2026-09-10T10:17Z; 48203ff committed 2026-09-12T07:24Z; spec 17.5.0 published 2026-09-29T08:09Z (npm `time`) | | Other released copies | `kanban-ui` occurs in no other `*/CHANGELOG.md` and nowhere under `content/docs/releases/`. The 69 other CHANGELOGs that name 48203ff carry it only as `- Updated dependencies [48203ff]` | | After this PR | `grep -c kanban-ui packages/spec/CHANGELOG.md` reads 3: the corrected row, the corrected paragraph and the erratum line | ## Gates (on `ca8dffb4`, the final commit) `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` derived 55 commands for this one path. 51 ran and exited 0. They include `pnpm check:nul-bytes`, `pnpm check:published-files`, `pnpm check:release-notes`, `pnpm check:release-page-status`, `pnpm check:doc-authoring` and `node scripts/check-release-section-coverage.mjs --strict`. The `--ran` reconciliation reads: "55 derived famil(ies) accounted for — 51 run, 4 NOT-MEASURED (4 DERIVED from a recorded exit 3)", 0 UNRUN. NOT MEASURED (4): `check:dts-closure`, `check:dual-build-cjs-loads`, `check:lean-entry-closure` and `check:sourcemap-no-sources-content`. Each exited 3 (PREREQUISITE NOT MET) because it reads built `dist/` trees across the workspace, and this worktree built none. No build reads `CHANGELOG.md`. CI runs these four on a fresh build. Outside the derived set, two gates that read `packages/spec/CHANGELOG.md` also ran and exited 0: `pnpm check:future-spec-major` and `pnpm check:docs-image-tag`. `check:issue-citations` is green, but it read 0 files: `**/CHANGELOG.md` is one of its declared deferred surfaces. So the three citations this PR adds were read by hand. objectstack-ai#21143 is this card, objectui#8865 is the merged retirement PR and objectui#8257 is the card it answered. ## Acceptance notes - PR objectstack-ai#21141 corrected the source copies to the same wording. This PR is the released-text half that the Documentation Guardrails keep out of a code PR. - The pinned objectui still exports the `KanbanRenderer` React component, which reads the `quickAdd` / `onQuickAdd` pair (`plugin-kanban/src/index.tsx:345-346` at `31971ff1e`). The tombstone docblock on `main` already records this as "not withdrawn from objectui's React layer, but no metadata node reaches it". The amended entry says only what holds for metadata and does not name that component. Written by the `domain:spec` dev session `session_01UtnxvdiN376GF3sgXwAw4d`, dispatched by the PM loop on objectstack-ai#21143. --- _Generated by [Claude Code](https://claude.ai/code/session_01UtnxvdiN376GF3sgXwAw4d)_ Co-authored-by: Claude <noreply@anthropic.com>
Fixes #21017
Clause-②: no
The
object-kanbanquickAddretirement told authors the control "is unchanged on thekanban-uiblock". objectui retired that block (objectui#8257) and this spec never declared it as a component type, so a node written there saves clean and resolves no renderer. Every author-facing copy of the remedy now says one sentence: Delete the key;object-kanbanoffers no quick-add control. The refusal itself is unchanged: same key, sameinvalid_typecode at pathquickAdd, same accept set. Prose only.The copies
packages/spec/src/ui/component.zod.tsobject-kanban-quick-add-removedsummarypackages/spec/src/conversions/registry.tsobject-kanban-quick-add-retired:replacement,reason,acceptanceCriteria(whatos migrate metaprints)migrations/entries/semantic/18.object-kanban-quick-add-retired.ts, generated copy inmigrations/registry.tskanban-uiblock" is droppedrationalefragment (the paragraph the upgrade guide prints)migrations/registry.ts, the hand-written region outside the generated markersgit grepof the order's H2component.zod.ts, two inconversions/registry.ts, the retired-key entry's header, the pin test's headermigrations/registry.ts(gen:migration-registry),content/docs/references/ui/component.mdx(gen:docs)Measured before writing
e420df310f5band at main770cc5ba4d15: 0 code lines namingkanban-uiunderpackagesandappsoutside tests and CHANGELOGs; 22 comment lines in 6 files, all recording the retirement. Noregistercall carries the key.ObjectKanbanpasses neither half of the pair toKanbanBoardCore; objectui's own docblock there says "Anobject-kanbanboard draws no Quick Add control, whatever its document carries". The pair is read only by the exportedKanbanRendererReact component, which a host mounts directly, so no metadata node reaches it. No route to name, so triage's sentence stands.git grepofkanban-uiunderpackages/spec/srclists the files in the order plus the step 18 rationale fragment above. After this PR no author-facing text names the block; the remaining mentions are docblocks and comments that explain why it is not named.e420df310" qualification to the second docblock. That qualification is kept, re-wrapped, with the same facts and citations. The sentence just above it still said the control "stays onkanban-ui", contradicting it; that sentence is the one rewritten.PageComponentSchema.safeParseof a node with typekanban-uisucceeds (true), andComponentPropsMap['object-kanban'].safeParse({ objectName: 'task', quickAdd: true })fails with one issue, codeinvalid_type, pathquickAdd.Pin
ui/component.test.ts(ObjectKanbanPropsSchema quickAdd is retired): the existing refusal test now pins "Delete the key" in place of the block name, and one new test asserts that the refusal still carriesinvalid_typeatquickAdd, that the tombstone carries the sentence, and that none of the tombstone, the D2 summary, the D3 entry's three texts and the step 18 rationale containskanban-ui. The generated copies are held to their sources bycheck:migration-registry.Ablation, each leg through
scripts/ablation-replace.mjsin wrap mode against the committed fix: the tool printed anchor 1 to 0 and the blob hash changing before the run, andblob == HEADwith an emptygit diff HEADafter it. Direction in every leg was red, exactly one failing test: leg 1 the tombstone sentence reverted (assertion on the sentence), leg 2 the D2 summary reverted, leg 3 the generated semantic copy reverted, leg 4 the step 18 rationale reverted (each of the last three onnot.toContain('kanban-ui')). The test imports the sources by relative path, so nodist/is in the resolution path and no rebuild is owed between legs.Verified at head
83d99268apnpm --filter @objectstack/spec buildexit 0;check:generatedall 15 artifacts up to date, withcheck:migration-registry,check:spec-changes,check:upgrade-guide,check:docs,check:authorable-surfaceandcheck:api-surfacegreen.check:docswas stale after the tombstone edit and was regenerated: the diff ofcontent/docs/references/ui/component.mdxis the one sentence.dispatch-gates.mjs --commands --repo objectstack-ai/objectstackover the actual diff: 112 commands.--ranverdict: "112 derived famil(ies) accounted for — 112 run, 0 NOT-MEASURED", every recorded exit 0. The four artifact-roster gates whose roster sits under the touched paths (check:meta-url-spelling,check:authz-resolver,check:error-code-casing,check:filter-alias-parity) also exit 0. The seven gates that first answered exit 3 (workspace not built) were re-run afterturbo run buildof the closure and exit 0.pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/ui src/conversions src/migrations scripts/step18-rationale-merge.test.ts scripts/conversions-major18-merge.test.ts: 114 files, 4190 tests passed.pnpm --filter @objectstack/spec typecheckexit 0.origin/mainwas merged withscripts/pm/os-regen-merge.sh(main at8368f1c00); regenerating the migration registry afterwards changed nothing. The repo-wide lint union and the rest of the farm are CI's.Acceptance notes
packages/spec/CHANGELOG.md, the 17.5.0 entry for the retirement (about lines 1580-1629), carries the same prescription ("It stays on thekanban-uiblock ...", and "livekanban-uispelling"). It is release-owned and published, so it is not touched here; it needs an amendment in a dedicated docs-only PR. Carrier: none..changeset/objectui-pin-citations-e420df310f5b.mdalready says the block was retired in objectui and is correct; untouched..claude/**,skills/**, ADR or AGENTS.md). The claim records that the at-tier contract review of thepackages/spec/src/**face is owed before enqueue.patchfor@objectstack/spec,Clause-②: no. The diff widens no accept set and no public surface.Generated by Claude Code