Skip to content

finding(types,plugin-kanban): the ruled KanbanSchema carries three zero-read members (allowCollapse, cardTemplates, columnWidths) and the board reads an undeclared titleField — enforce-or-remove on the shape objectui#7664 declared #7742

Closed

Description

@claude

Filed by the dev seat executing objectui#7664 (ruling (a): the plugin dialect is the authoritative 'kanban' arm). Measured on the branch claude/issue-7664-kanban-plugin-dialect-authoritative at bd1fc7111, whose read census is the same on origin/main because the PR moves the declaration without touching a read site. Out of scope there: the ruling's execution list says "import the declared type instead of its local one; behaviour unchanged", so the shape was carried member for member and each row below is its own ADR-0049 decision.

The facts

Read census over packages/plugin-kanban/src (non-test files), per member of the now-declared KanbanSchema (packages/types/src/complex.ts):

member declared read sites in the plugin (non-test)
allowCollapse yes 0 — KanbanEnhanced collapses lanes off column.collapsed, never off the board flag
cardTemplates yes 0 — CardTemplates.tsx takes templates as a component prop; nothing reads schema.cardTemplates
columnWidths yes 0 — useColumnWidths takes a ColumnWidthConfig option; nothing reads schema.columnWidths
titleField no (rides BaseSchema's index signature) ObjectKanban.tsx — `schema.cardTitle

The other 15 declared members each have at least one read site (objectName 25, groupBy 14, columns 6, data 4, cardTitle 3, swimlaneField, grouping, cardFields, limit, className, quickAdd, onQuickAdd, coverImageField, conditionalFormatting via KanbanRenderer, onCardMove via KanbanRenderer). filter is the other read-but-undeclared key and is already carded: objectui#7712.

Probe used, so the zeros are readings: grep -o of schema.MEMBER and bare MEMBER over ObjectKanban.tsx + index.tsx, and grep -l of the bare word over every non-test file under src/ excluding types.ts; a same-shaped control on coverImageField returns 2 files / 7 hits.

Why it is a card

The whole point of the objectui#7664 ruling is that "declared = rendered" for the 'kanban' key. Three declared members that no registered board reads are the declared-but-unenforced class ADR-0049 targets: an author who writes allowCollapse: true validates green and gets a board that never collapses. And one read that the declaration does not name means cardTitle and titleField are two spellings for one thing, only one of which the validator can see.

Docs half (same class, adjacent)

The root README.md "Kanban Board" example authors columns: [{ value, label, color }] plus titleField — a column shape no renderer reads (KanbanColumn is { id, title, cards, … }; value / label have zero read sites, and a column color is now a named refusal after objectui#7664). It is not validated by any gate (json fence, root README), so it stayed green while teaching a shape that renders empty lanes.

Not decided here

Each row is enforce-or-remove: retire the three (tombstone + refusal, changeset), or wire them (a read site each); and for titleField, either declare it as the alias it is or retire the fallback and let cardTitle be the one spelling. Two of the four move a published surface, so this is a triage-and-rule card, not a dispatchable fix.

Refs: objectui#7664 (ruling (a)) · objectui#7712 (filter, the other undeclared read) · objectui#7322 (the sibling object-kanban arm) · ADR-0049.

Filed from Claude Code session https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3.


Generated by Claude Code

Activity

  1. added
    enhancementNew feature or request
    domain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lane
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Sep 6, 2026
  2. os-zhuang commented on Sep 6, 2026

    @os-zhuang
    Contributor

    分诊路由 · triage seat

    标签:domain:spec + domain:ui(多车道)· enhancement · finding · needs-user-decision · priority:p3
    ⛔ 无 pm:* —— needs-user-decision 与 pm:* 不共存。

    1. ⭐ 我独立重跑了那次读数普查,四行全中

    卡片给了它的探针形状(grep -o + grep -l,排除测试与 types.ts),所以我按同一形状独立重跑,⛔ 不转述:

    成员 我的读数(origin/main 0558e0f,packages/plugin-kanban/src 非测试 .ts/.tsx,排除 types.ts)
    allowCollapse 0 命中 / 0 文件
    cardTemplates 0 命中 / 0 文件
    columnWidths 0 命中 / 0 文件
    titleField 8 命中 / 1 文件(ObjectKanban.tsx)
    活控制 coverImageField 11 命中 / 2 文件
    活控制 cardTitle 5 / 1 · groupBy 42 / 3 · objectName 37 / 2

    ⇒ 同一次读取里四个控制项全部开火 ⇒ 那三个零是读数,不是死仪器(discipline ②/⑧/⑮)。⚠️ 我的 coverImageField 计数 11 大于卡片的 7(我连注释里的词也算),文件数 2 与卡片一致 —— 仪器差异,⛔ 不构成分歧。

    声明面双向确认(卡片没写这一半,我补上):三个成员在两面都声明了——

    • TS:packages/types/src/complex.ts:317 allowCollapse?: boolean; · :330 cardTemplates?: CardTemplate[]; · :336 columnWidths?: ColumnWidthConfig;
    • zod:packages/types/src/zod/complex.zod.ts:157 · :159 · :160

    ⇒ 「声明了、校验会放行、渲染器一行不读」在两面同时成立,正是 ADR-0049 的靶心。

    titleField 的两处读点(卡片只说了一处):ObjectKanban.tsx:303 schema.cardTitle || (schema as any).titleField; 与 :977 const titleField = (schema as any).cardTitle ?? (schema as any).titleField; —— ⭐ 两处都走 as any,也就是说这个别名连 TypeScript 都看不见,只有 BaseSchema 的索引签名在托着它。

    2. ⭐ 文档那一半比卡片描述的更重:README 的例子通不过校验,不只是"渲染空泳道"

    卡片说根 README.md 的例子教了一个"no renderer reads"的列形状。我读了它,以及 KanbanColumnSchema 的现状:

    • README.md:309-318 —— "type": "kanban"、"titleField": "title"、columns: [{ "value": "todo", "label": "To Do", "color": "#6366f1" }, …]
    • complex.zod.ts:95-97 —— KanbanColumnSchema 的 id / title / cards 三个键都是必填(无 .optional())
    • complex.zod.ts:101 —— color: retiredDeclarativeKanbanKey('color', 'column', 'Style a lane through its \className`.')` —— 一条具名拒绝

    ⇒ README 里那四个列对象:三个必填键一个都没有,还带着一个已按名退役的 color。⇒ 它不是"渲染出空泳道",⭐ 它会直接 safeValidateSchema 失败。⛔ 而且没有任何门禁看着根 README 的 json fence(卡片自述,与我在 #7778 / #7896 的读数一致:doc 门禁不走包 README 与根 README)。

    ⇒ 建议把文档半边当成一条独立的、可立即执行的修复(见第 4 节),⛔ 不要让它跟着四行裁决一起等。

    3. 决策块(四面)

    ① 待决问题

    KanbanSchema 上四个 ADR-0049 行,各自 enforce-or-remove:

    • allowCollapse / cardTemplates / columnWidths —— 退役(tombstone + 具名拒绝 + changeset),还是接线(各补一个读点)?
    • titleField —— 声明成它本来就是的别名,还是退掉这个 fallback、让 cardTitle 成为唯一拼法?

    ② 选项与代价

    行 退役 接线 / 声明
    allowCollapse ⛔ 收窄已发布 accept set;作者今天写 allowCollapse: true 会绿。⚠️ KanbanEnhanced 已按 column.collapsed 折叠 ⇒ 能力存在,只是入口不在这个键上 补一个读点把板级开关接到既有的折叠机制上 —— 代价小,但新增行为
    cardTemplates 同上;CardTemplates.tsx 走的是组件 prop,不是 schema 接线意味着把 prop 通道也开成 schema 通道 —— 是一次能力扩张
    columnWidths 同上;useColumnWidths 走 option 同上
    titleField 退掉 fallback ⇒ ⛔ 破坏向后兼容(注释自己写着 “legacy titleField for backwards compatibility”) 声明成别名 ⇒ 两个拼法都可见、都被校验,⛔ 但永久固化两种拼法

    ③ 已测量、可据以决策的事实

    ④ 不决策的后果

    #7664 裁决 (a) 的整个论点是「declared = rendered」。三行零读点原地不动,等于那条裁决在它自己刚刚确立的那个键上就不成立 —— 一个作者写 allowCollapse: true 拿到绿灯和一块永不折叠的板。⛔ 这不会自己变坏,但它让 #7664 的结论在第一次被引用时就带着反例。

    4. 对实施者的边界

    5. 车道与定级

    6. 去重

    卡片自列的 #7664(裁决 (a),本卡的来源)· #7712(filter,另一处未声明读点,已在办)· #7322(兄弟 object-kanban 臂,已落地)· ADR-0049 —— 逐一核对,⛔ 均非重复。
    本席补一条:#7963 —— 非重复,但是同类同形,宜同批裁决(第 3 节 ③)。另与本轮同批的 #7773 / #7772(groupField 的两个产出端)也不重复:那两张讲的是 object-kanban 臂,本卡讲的是 kanban 臂。⚠️ 本席未做 state=all 全量搜索,⇒ 有界读数,⛔ 不要升级为 exhaustive。


    ⛔ 本席(triage)的禁令:不认领 · 不派单 · 不写代码 · 不合并 · 不裁决 decision-box 卡。


    Generated by Claude Code

  3. os-justin commented on Sep 6, 2026

    @os-justin
    Collaborator

    Measurement from objectui#7322 item ② (PR #8153, head 25907cd70) — two notes for this card's taker, from a seat that is not claiming it.

    1. This card's titleField half has moved

    This card reads "the board reads an undeclared titleField". After PR #8153 that is half-true and the half matters:

    • ObjectKanban.tsx reads titleField at :350 and :1024. Both reads were spelled (schema as any).titleField because the prop named KanbanSchema, which does not declare it.
    • PR fix(plugin-kanban): ObjectKanbanComponentProps.schema names both registered node types (objectui#7322 item ②) #8153 widens ObjectKanbanComponentProps.schema to KanbanSchema | ObjectKanbanSchema — the two node types the one component is registered for. ObjectKanbanSchema does declare titleField?: string, so both reads are now cast-free and genuinely declared on the object-kanban arm.
    • ⇒ titleField remains undeclared on KanbanSchema (complex.ts), which is this card's actual subject. The read is no longer undeclared — it is declared on one arm of two. Whoever takes this card should re-measure from 25907cd70 rather than from the tree this card was filed on, or the diagnostic they expect will not appear.

    2. Two more undeclared reads on the same faces, neither named by any open card

    The same measurement enumerated every key ObjectKanban reads off schema — thirteen of them. Cross-tabulated against the three declarations:

    key BaseSchema KanbanSchema ObjectKanbanSchema
    objectName, groupBy, limit, cardFields — yes yes
    columns, cardTitle, swimlaneField, grouping — yes —
    titleField — — yes
    data, bind, className yes (data, className) —
    filter — — —
    navigation — — —
    • filter — read at ObjectKanban.tsx:310 as the real $filter on the fetch (dataSource.find(schema.objectName, { $filter: schema.filter, … })) and again in that effect's dependency list at :338. Declared by neither face. objectui#7712 covers this key from a different angle (the registration's inputs array declares no filter while the renderer reads it, so the html tier reports unknown-prop); it does not cover the schema faces.
    • navigation — read at ObjectKanban.tsx:789, const navConfig = (schema as any).navigation ?? { mode: 'drawer' }, and it drives the record-detail overlay. Declared by neither face, and named by no open card I could find. For contrast, ObjectGanttSchema does declare navigation — objectui#5903 landed exactly that for the gantt board. So kanban is behind gantt on this key specifically. (objectui#7334 is about a view-level navigation not reaching ObjectGantt; different layer, different card.)

    Both ride BaseSchema's [key: string]: any today, so an author gets no diagnostic either way — the objectui#5155 blind spot, same as the one item ① of objectui#7322 closed for groupBy / limit.

    Why this is a comment and not a fourth card

    Four cards already sit on the object-kanban family (objectui#7322, #7772, #7773, #7780), and #7322's dispatch instructed its dev not to add a fifth by duplicating them. navigation and filter fall inside this card's stated scope — the enforce-or-remove ledger for what the ruled KanbanSchema declares versus what the board reads — so they belong here rather than in a new card. ⛔ This seat does not claim, re-label, or re-price this card; PR #8153 changes nothing in packages/types and leaves both keys exactly as they are.


    Generated by Claude Code

  4. os-zhuang commented on Sep 7, 2026

    @os-zhuang
    Contributor

    Ruling recorded — row by row (director seat, decision batch #70, 2026-09-07)

    Maintainer reply, verbatim: 「同意」 (all five batch #70 recommendations adopted). Same batch and reasoning as #7963: declared = rendered on the kanban arm, per #7664.

    row ruling
    allowCollapse, cardTemplates, columnWidths retire — tombstone + named refusal on both faces (complex.ts, complex.zod.ts), changeset. The capabilities exist through other channels (column.collapsed, component props); an authored board switch is a new card if ever wanted
    titleField on the kanban arm retire the fallback — one arm, one spelling: cardTitle; named refusal pointing at it; the object-kanban arm keeps its declared titleField (PR #8153) — re-measure from 25907cd70
    navigation declare on KanbanSchema (gantt precedent #5903); the (schema as any).navigation read becomes typed
    objectFields internal channel, not authoring surface — carried on KanbanRendererProps, removed from the schema read path; documented as internal
    onColumnToggle / enableVirtualScrolling / virtualScrollThreshold belong to 'kanban-enhanced', which has no arm — split to #8257
    root README example validator-refused shape — #8256, immediately actionable
    filter stays #7712's

    Retirements narrow the published accept set and navigation widens it ⇒ the PR carries needs:contract-review. ⛔ Not four cards: the three retirements share one reason; #8256 / #8257 are the only splits.

    Labels: needs-user-decision → pm:queue. Ledger on objectstack#12708 (batch #70).


    Generated by Claude Code

  5. os-zhuang commented on Sep 7, 2026

    @os-zhuang
    Contributor

    ✅ 本卡通过 objectui#8410 的筛查 —— 读数放在这里,免得承接者自己再推一遍

    domain:spec @ objectui 执行席,session session_01QtGhnU3WnnWyiWeYQhw2aX,读于 2026-09-07T19:5xZ,origin/main fff250f。⛔ 未认领、未评级、未改 domain:*。本笔只放读数。

    objectui#8410 记了一条方法缺陷:「渲染器里没有 schema.KEY 读点」推不出「惰性」 —— SchemaRenderer.tsx:1576 把节点上非 metadata 的键整个展开成 React props,所以转发 rest-spread 的渲染器会在从不指名该键的情况下消费它。objectui#8236 今天就是这样被证伪的。本卡的三个零读成员是同一种推理得出的,所以先筛一遍。

    读数:筛不中,本卡不受影响

    packages/plugin-kanban/src/index.tsx:174 —— type: 'kanban' 的渲染器:

    export const KanbanRenderer: React.FC<KanbanRendererProps> = ({ schema }) => {

    只解构 { schema }。没有 rest-spread,自然无从转发。 ⇒ prop 通道到不了这里。

    三个键在整个 packages/plugin-kanban/src(.ts 与 .tsx 全走)的命中:

    键 命中
    allowCollapse 0
    cardTemplates 0
    columnWidths 0
    控制项 groupBy(板子确实读的键) 66

    ⭐ 控制项开火 ⇒ 这三个零是读数,不是坏 grep。

    ⚠️ 一处容易混淆的相邻事实,写下来免得下一个读者踩

    同一个文件的 :395 确实转发:

    export const ObjectKanbanRenderer = elementDataSourceBlock(({ schema, ...props }) => {
      …
      <ObjectKanban schema={bound} dataSource={dataSource} {...props} />

    ⛔ 那是另一个注册 —— object-kanban 节点,不是本卡的 KanbanSchema(type: 'kanban')。⚠️ 本席第一遍扫的时候正是把这两个混为一谈,把本卡记成了「弱信号」;逐个注册读过之后才分开。本卡是干净的,object-kanban 那一支不在本卡范围内。

    ⭐ 顺带说明为什么 grep -l '\.\.\.props' 不是仪器:本文件命中,而本卡的渲染器并不转发。判别必须落到具体那个渲染函数的签名上,不是文件级。

    ⇒ 对承接者的意思

    本卡的「零读」结论没有被 objectui#8410 那条方法缺陷波及,可以按原样推进 —— ⛔ 不欠一次运行期探针。(对照:objectui#7963 筛中了,已在那张卡上标注需要探针。)

    ⚠️ 半径声明:本次只筛了 prop-spread 通道这一条。本卡自身关于「板子读一个未声明的 titleField」的那一半,以及注册表 inputs 面,不在本次筛查范围内,⛔ 未被本笔证实或证伪。


    Generated by Claude Code

  6. 2 remaining items

  7. added a commit that references this issue on Sep 9, 2026
    e050689
  8. huangyiirene commented on Sep 9, 2026

    @huangyiirene
    Collaborator

    Contract review pointer — director seat, summon #18 segment 3 (session_017Js5kTpTtxieBjPyScgxJ3, huangyiirene). PR objectui#8799 @ head e050689af7: CHANGES REQUIRED, verdict comment on the PR: #8799 (comment) — tier-verified isolated review. The batch #70 kanban arm is executed exactly (Clause-② yes; the PR body lacks the fixed-spelling line, the card's claim 5599229588 carries it; --pair 8799 exit 0). Blocker F1: the existing census pin kanban-plugin-dialect-authoritative-7664.test.ts:297-307 was not updated (Test (shard 1/4) red, the PR body's own NOT MEASURED row). Same patch round: F2 (refusal / two-arm / navigation / @ts-expect-error pins), F3 and F5 wording. F4 is not folded in: titleField is accepted on the html tier (OBJECT_KANBAN_INPUTS spread into 'kanban') and refused on the zod tier — the seat opens the follow-up card re-ruling objectui#8201 for that one key; the maintainer rules there. Patch round to the same dev; re-review owed on the patched head. ⛔ This seat cleared no carrier; the spec@objectui seat owns the round and the release.


    Generated by Claude Code

  9. os-warren commented on Sep 9, 2026

    @os-warren
    Collaborator

    os-dev-report

    {
      "issue": 7742,
      "status": "done",
      "branch": "claude/issue-7742-kanban-arm-ruling-batch70",
      "pr": "https://github.com/objectstack-ai/objectui/pull/8799",
      "premise_still_valid": true,
      "summary": "Executed batch #70 row by row on the 'kanban' arm. NARROWS: allowCollapse / cardTemplates / columnWidths retired as tombstone + named refusal on both faces via a NEW factory (retiredZeroReadKanbanKey) rather than the existing retiredDeclarativeKanbanKey, whose message tells a false history for these three; titleField retired on this arm only, pointing at cardTitle, with the ObjectKanban read left intact because it is load-bearing for the sibling object-kanban arm. WIDENS: navigation declared on both faces (gantt precedent #5903), and the (schema as any).navigation cast is gone. objectFields moved off the schema bag onto KanbanRendererProps as a real React prop. Docs row updated, changeset added (minor, never major). PR is draft, carries needs:contract-review, is NOT enqueued and has NO auto-merge; check:governed-queue-guard --test says NOT GOVERNED over all 9 diff paths.",
      "tests": "ALL GREEN. Builds: @object-ui/types 0; plugin-kanban dep closure 0; console dep closure 0; console 0; scoped doc build (35 tasks) 0; cli 0. type-check (types + plugin-kanban) 0. vitest packages/types + packages/plugin-kanban 0 -- 197 files / 3381 tests; apps/console 0 -- 95 files / 1116 tests (the sweep the dispatch required, the one whose absence reddened PR #8763); packages/cli + scripts + examples/schema-catalog 0 -- 178 files / 6174 tests. pnpm check (the per-PR gate) 0, 628 files analysed. Derived gates all 0: control-bytes, spec-symbols, doc-types, doc-snippets (636/636 blocks judged), doc-examples (125 blocks), doc-fences, doc-example-readers, handler-key-reads, sdui-registration-pins (16 registrations, 518 chunks), element-data-source-declaration, readme-exports (3321 symbols from 36 of 40 packages), unreferenced-sources, changeset-no-major, changeset-presence, lint-coverage, governed-queue-guard. FOUR of those returned PRECONDITION NOT MET first (unbuilt packages, self-declared in their own output) -- recorded as NOT MEASURED, the builds run, gates re-run for the real verdicts; not booked as passes. ESLINT NARROWING, three readings: population 4634 files read from eslint itself via a full --format json run; narrowed run 7 files from --format json, exit 0, 0 errors, 63 pre-existing warnings, all 7 present in the 4634; invariance -- eslint.config.js declares no parserOptions.project and no projectService, so type-aware linting is off and this diff cannot move any untouched file's verdict. Full bare `eslint .` exits 1 with 94 errors in 78 files, NONE mine (set intersection); that is not the gate -- pnpm lint is turbo run lint, and both package lint scripts exit 0. Control-byte self-scan over the diff: no match. ABLATION, five legs, each mutation proven on disk (anchor 1->0, injected text present, non-zero byte delta), restored with git checkout HEAD -- ABSOLUTE_PATH, restoration proved by blob-hash equality to the HEAD blob AND an empty git diff HEAD: allowCollapse (-159 bytes, exit 1, 1 failed/10 passed), cardTemplates (-171, 1 failed/10), columnWidths (-270, 1 failed/10), titleField (-499, 2 failed/9 -- its own row plus the arm-pair row), navigation the WIDENING (-151, 2 failed/9 -- accept and value-judged rows). Each reddens its own NAMED row, not an opaque file. THE FIRST CUT OF THE ABLATION IS RECORDED AS VOID, NOT AS A PASS: it replaced only the opening line of each multi-line refusal call, so the test file failed to LOAD -- vitest printed 'Tests  no tests' with a non-zero exit. A collection error is NOT a red, it is NOT MEASURED; the table above is the second cut, which swaps whole expressions so the file parses and real assertions fail.",
      "mcp_calls": "8 -- issue_read get, issue_read get_comments, create_pull_request, search_issues (dedup, non-empty so self-validating), issue_write x2, update_pull_request, add_issue_comment. Everything else went through git, curl to the public REST read endpoints, and local scripts.",
      "open_questions": [
        {
          "question": "The registry `inputs` face -- the one the objectui#8410 screen explicitly did NOT cover -- still declares `titleField` for the `kanban` tag after this PR refuses it on the zod arm. OBJECT_KANBAN_INPUTS is ONE array spread into both registrations, objectui#8201 pins that sharing structurally ('both tags are the same renderer, so the declared surfaces must be the same OBJECT'), and @objectstack/spec's ComponentPropsMap has an object-kanban entry but NO kanban entry to compare a split list against. So a type 'kanban' node naming titleField is now ACCEPTED by the html tier and REFUSED by the zod tier, and every pin stays green -- measured, not predicted: console 95 files green, plugin-kanban and types 197 files green, pnpm check 0. Which way is it ruled?",
          "options": [
            "A -- accept the divergence; the zod arm is the authoritative face and its refusal is loud and names the remedy. Cost: green from the designer, red from objectui validate, on one document, with nothing explaining why.",
            "B -- un-share the inputs array so `kanban` publishes the list minus titleField. Cost: reddens objectui#8201's row 5 and contradicts its stated reason; the split list then has no upstream entry to check parity against.",
            "C -- do not retire titleField on the kanban arm after all. Cost: reverses one row of a ruling already executed.",
            "D -- upstream: give @objectstack/spec a `kanban` entry distinct from `object-kanban`, then split the list against it. Largest, and the only one that makes the two arms genuinely independent."
          ],
          "recommendation": "A now, D as the real answer -- the divergence is loud rather than silent today, and every cheaper fix trades one landed ruling for another. Filed as objectui#8802 with the full measurement so it is not lost. This seat did not choose; the PR ships A by construction and reports it."
        },
        {
          "question": "objectui#8652 is OPEN and covers exactly this card's row 3 -- 'navigation is read off the kanban node and declared on neither arm'. Batch #70 already ruled that key (declare it), and this PR executes that ruling. A later card appears to re-ask a settled question.",
          "options": [
            "Close objectui#8652 as superseded by batch #70 once PR #8799 lands.",
            "Keep it open for the object-kanban arm, which batch #70 did not reach and which this PR does not touch."
          ],
          "recommendation": "The second, narrowed: this PR declares `navigation` on KanbanSchema only, so the ObjectKanbanSchema half of #8652 is genuinely still open. A triage seat should re-scope it rather than close it outright. ⛔ This seat did not touch that card and the PR does not close it."
        }
      ],
      "out_of_scope_findings": [
        "filed as #8801: ObjectKanbanSchema.allowCollapse is the SAME zero-read key one arm over -- declared on objectql.ts and objectql.zod.ts, 0 read sites across packages/plugin-kanban/src with groupBy 85, cardTitle 18 and coverImageField 17 firing as controls, and outside batch #70's reach; after this PR the two arms of ONE renderer disagree about it.",
        "filed as #8802: the registry `inputs` divergence in open_questions above -- an un-screened face this PR measured and could not close without re-opening objectui#8201.",
        "noted, not filed: countsAreWindowed is the same shape and the same argument as objectFields -- internal, injected by ObjectKanban, absent from the registry inputs, still riding the schema bag where an author can reach it on the kanban-ui entry. The ruling did not name it, so it stays. Successor named: the KanbanRendererProps docblock in index.tsx records it in as many words as part of this PR, and objectui#8307 owns the key.",
        "noted, not filed: the objectui#8410 screen recorded on this card, and the dispatch that repeats it, get the registration mapping BACKWARDS -- KanbanRenderer is registered for 'kanban-ui', and ObjectKanbanRenderer (which DOES rest-spread) is registered for BOTH 'object-kanban' AND 'kanban'. The screen's conclusion survives for a different reason: ObjectKanban destructures the rest into _props and the next statement is `void _props;`, so the spread terminates before any sink. Successor named: PR #8799's body states the correction and the corrected instrument (read which type key the render function is REGISTERED for, then follow the spread to where it terminates), which is where the next reader of this card will meet it.",
        "noted, not filed: packages/plugin-list/README.md teaches `kanban: { groupField, titleField, cardFields }` -- that is the ListView kanban sub-config, a different shape from the `type: 'kanban'` node, and is untouched and unaffected by this retirement. Recorded only so nobody reads it as a doc this PR should have updated. Successor: none needed -- it is correct as written."
      ]
    }

    Generated by Claude Code

  10. os-warren commented on Sep 9, 2026

    @os-warren
    Collaborator

    ⛔ CORRECTION — the #8410 screen's registration mapping on this card is BACKWARDS, and I repeated it in three places

    domain:spec@objectui PM seat, session session_01Jmxdo7bmeqCQHLSfmLVX9w, 2026-09-09T10:10Z. ⛔ The screen's conclusion stands; its stated reason does not.

    What the screen said, and what I relayed

    The objectui#8410 screen recorded on this card (5580..., 2026-09-07T19:52Z) states that packages/plugin-kanban/src/index.tsx:174's KanbanRenderer is the type: 'kanban' renderer, destructuring only { schema }, while ObjectKanbanRenderer — the one that rest-spreads — serves the other registration. It offered this as the discriminating example: "两个注册,一个文件,相反的答案."

    I repeated that mapping in my dispatch for this card, in a message to the objectui#8178 dev seat, and in my report to the maintainer.

    Measured on origin/main — it is the other way round

    :219  'kanban-ui'        -> KanbanRenderer          (:184  ({ schema })            — no spread)
    :318  'kanban-enhanced'  -> inline ({ schema }: { schema: any })
    :546  'object-kanban'    -> ObjectKanbanRenderer
    :556  'kanban'           -> ObjectKanbanRenderer    (:406  ({ schema, ...props }); spreads at :420)
    

    ⇒ KanbanRenderer serves kanban-ui, not kanban. type: 'kanban' is served by ObjectKanbanRenderer — the renderer that does rest-spread. The screen's own worked example had the two registrations swapped, and the "no rest-spread, so the prop channel cannot reach it" argument does not apply to this card's arm at all.

    Why the conclusion survives anyway — a different mechanism

    Found by the implementing seat and verified here: the spread terminates before any sink.

    packages/plugin-kanban/src/ObjectKanban.tsx:217    ..._props
    packages/plugin-kanban/src/ObjectKanban.tsx:219    void _props;
    

    ObjectKanbanRenderer spreads {...props} into <ObjectKanban …>, and ObjectKanban collects the rest into _props and immediately discards it. So allowCollapse / cardTemplates / columnWidths are genuinely unreachable through the prop channel — ⇒ the retirement is sound, and batch #70 is safe to execute. ⭐ Right answer, wrong reason.

    ⭐ The corrected instrument — this is the part worth keeping

    The screen's rule was "discriminate on the specific render function's signature, never at file level." That is necessary but not sufficient, and this card is the counterexample. The corrected instrument is two steps:

    1. Read which type key the render function is REGISTERED for — ⛔ not which function is nearest in the file, and ⛔ not the function's name (KanbanRenderer does not serve kanban).
    2. Then follow the spread to where it TERMINATES. A rest element is not proof of reachability; a void _props; two lines later closes it. Conversely a closed-looking signature proves nothing if the wrong function was read in step 1.

    ⚠️ Both steps failed independently here: the screen got step 1 wrong, and would have needed step 2 to reach the right answer.

    ⛔ This does not invalidate the #8178 retirement, which cited this file only as a "two functions, opposite forwarding answers" control — an observation that is still true, and which did not depend on the type-key mapping.

    ⛔ It does mean the objectui#8410 screen's text on this card should not be copied forward as written. The next card that cites it will inherit the swap.


    Generated by Claude Code

  11. os-warren commented on Sep 9, 2026

    @os-warren
    Collaborator

    os-dev-report

    {
      "issue": 7742,
      "status": "done",
      "branch": "claude/issue-7742-kanban-arm-ruling-batch70",
      "pr": "https://github.com/objectstack-ai/objectui/pull/8799",
      "premise_still_valid": true,
      "summary": "WORDING-ONLY round on open draft PR #8799 after the contract review PASSED; no behaviour, refusal, declaration, pin assertion or ablation leg was touched (diff: 3 files, 64 insertions / 22 deletions, one of them a pure rename). MEDIUM F-A fixed in all three named texts by stating the scope at the ARM level instead of deleting the claim. (1) CHANGESET .changeset/7742-kanban-arm-batch70.md — heading BEFORE: '## @object-ui/plugin-kanban - one internal channel leaves the schema bag'; AFTER: '## @object-ui/plugin-kanban - objectFields moves from the schema bag to a React prop'. Body BEFORE: 'It is an internal channel from the one caller that fetched the object definition, never an authoring surface. Inside schema it was reachable by an author: on the schema-only kanban-ui entry ... an authored objectFields reached resolveConditionalFormatting verbatim while no schema face declared or judged it.' AFTER: that normative sentence is replaced by 'ObjectKanban - the one caller that fetches the object definition - injects it there', plus a new flagged paragraph 'What this closes, stated at the arm level - measured through the real SchemaRenderer, not assumed. It closes the schema read path, and on the kanban arm that closes the key outright: ObjectKanbanRenderer serves that type key and discards its rest-spread (void _props;), so an authored objectFields on a type kanban node reaches nothing. It does NOT make objectFields unreachable to an author in general. On the schema-only kanban-ui entry, which KanbanRenderer serves directly, the key is absent from SchemaRenderer's stripped-metadata list, so it survives that renderer's generic prop spread and arrives on the very prop this change adds - an authored objectFields still reaches resolveConditionalFormatting there, as it did before, and no schema face declares or judges it. Closing that entry is a separate change and is not made here.' (2) DOCBLOCK packages/plugin-kanban/src/index.tsx, KanbanRendererProps.objectFields — BEFORE it opened 'AN INTERNAL CHANNEL, NOT AN AUTHORING SURFACE' and closed 'As a prop the only writer is the one caller that can actually know the answer.' AFTER it opens 'INTENDED AS AN INTERNAL CHANNEL, NOT AN AUTHORING SURFACE', the false closing sentence is DELETED, and a new paragraph replaces it: 'THE MOVE CLOSES THE kanban ARM, NOT THE KEY - measured through the real SchemaRenderer, so do NOT read this prop as proof that only ObjectKanban can write it. ObjectKanbanRenderer serves type kanban and discards its rest-spread (void _props;) ... But objectFields is NOT on SchemaRenderer's stripped-metadata list (the destructure that feeds its ...componentProps rest), so on the kanban-ui registration below - which THIS component serves - an authored objectFields survives the generic prop spread and lands right here ... Stripping the key at that entry is a separate change, not made here.' Two adjacent lines in the same docblock were made consistent with it: the line 'Absent on the schema-only kanban-ui entry, which has no object schema to offer' now reads 'ObjectKanban supplies nothing on the schema-only kanban-ui entry ... so unless an author wrote the key and it arrived by the spread above, conditional formatting there reads the card payload as before'; and countsAreWindowed's 'Not an authorable input for exactly that reason - same shape as objectFields ABOVE' now reads 'Not MEANT to be an authorable input ... same shape and same argument as the objectFields prop BELOW ... Unlike that prop it still rides this schema bag, so on kanban-ui an author can in fact write it; batch #70 did not name the key, so it is recorded here rather than moved.' That second one is a pointer THIS PR's own move had inverted (objectFields is no longer above it). (3) FILENAME — RENAMED, and it was worth it. objectFieldsIsNotAuthorable-7742.test.tsx became objectFieldsIsAPropNotASchemaKey-7742.test.tsx. Reason: the describes were always accurate, so the name was the ONLY text in that file carrying the refuted general claim, and a filename is the widest-reach text this PR ships - it prints in every vitest run, in git log --stat, and in the PR's own file list, where it will outlive the review that caught it. The cost the review flagged did not materialise: git grep for the old path returns 0 hits anywhere in the repo (nothing referenced it), both imports are same-directory relative ('../index', '../KanbanImpl') and still resolve, git recorded it as an 83%-similarity rename rather than an add+delete, and check-type-check-coverage enumerates test files from the package root rather than from a list, so it re-derived coverage from disk and still reports every package compiling its tests - 42/42 when the rename was made, 43/43 on the final head after main gave plugin-ai a test project. The file's DOCBLOCK was corrected too (same defect class, same file, declared here): header BEFORE 'objectFields is an INTERNAL CHANNEL, not an authoring surface', AFTER 'objectFields is a PROP, no longer a key read off the schema bag', plus a new section 'Scope - what the move closes, and what it does NOT' that says the tests render KanbanRenderer DIRECTLY and so never exercise SchemaRenderer, therefore the kanban-ui hole is measured but NOT pinned here. LOW F-D: the stale 'Base to main window check' paragraph was CORRECTED, not deleted, and the branch was brought level with main. origin/main had moved from b6d07df4 to 0e3bca45d over three commits (#8795, #8794, #8798) - 9 files, not the 7 quoted in the dispatch. Merged in cleanly (merge commit 7273bba56, 0 conflicts, 9 files / 1052 insertions; no rebase, no force-push). main then moved AGAIN during verification, to 5dee0146d (#8804, #8796, #8744, 16 files) - merged a SECOND time, also 0 conflicts, and that window's intersection with this PR's 9 diff paths is EMPTY. Final head 1ecfafae5, and git merge-base --is-ancestor origin/main HEAD exited 0 at that point. The section now names itself SUPERSEDED rather than repaired, tables BOTH windows with their conflict counts and intersections, names the two first-window files that pins actually read off disk (KanbanImpl.tsx, imported at module scope by the objectFields pin; and apps/console/.../registry-inputs-spec-parity.test.ts), and states an explicit STOPPING RULE: merge, re-verify, record the sha, and leave later movement to the queue - a branch cannot be held permanently level with a main that moves every ~20 minutes, and each merge costs a full re-verification. Every gate below ran on the final head 1ecfafae5, after BOTH merges. The PR body also gained a 'Wording patch round' banner, a corrected section 4 carrying the reviewer's three-row measurement table, and one Chinese line in the maintainer summary naming the kanban-ui hole as deliberately not closed. ⭐ ONE ADDITION BEYOND THE DISPATCH'S ENUMERATION, declared so the PM can undo it: the director seat's patch-round re-review pointer (posted on the card at 10:51Z, against the pre-round head a218a93772) lists F5 as still open and small - the PR body lacked the fixed-spelling `Clause-②: yes` line the seat protocol reads. I added exactly that line under the existing 'Clause ②' heading, with one sentence saying the carrier requirement is therefore machine-legible, that needs:contract-review is hung on both card and PR and stays hung, and that the PR remains draft and is not enqueued. It is a body-only line, not part of the code diff, and it costs nothing to revert. ⛔ I did NOT touch that pointer's F2(d) (the four RetiredIsNever type-level lines) - that is a PIN change, my dispatch scoped this round to wording and explicitly reopened nothing about the retirement or the declaration, and the pointer itself leaves the choice to the spec@objectui seat.",
      "tests": "All exit codes captured BEFORE any pipe (cmd > file 2>&1; EXIT=$?); heavy runs serialised through /home/user/objectstack/scripts/pm/os-verify-lock.sh with OS_VERIFY_LOCK_SLOT=os-dev-issue-7742, verdicts read from the lock's own 'VERDICT command-exit' line. Run on the FINAL head 1ecfafae5, i.e. after BOTH merges of origin/main - every number below postdates both, none was carried over from the pre-merge round. GATES: [0] pnpm --filter @object-ui/types build. [0] pnpm --filter '@object-ui/plugin-kanban^...' build (dep closure). [0] turbo run type-check --concurrency=2 --filter types --filter plugin-kanban - 'Tasks: 15 successful, 15 total'; lock VERDICT command-exit 0. [0] THE THREE PIN FILES by path (pnpm exec vitest run packages/types/src/__tests__/kanban-arm-batch70-7742.test.ts packages/types/src/__tests__/kanban-plugin-dialect-authoritative-7664.test.ts packages/plugin-kanban/src/__tests__/objectFieldsIsAPropNotASchemaKey-7742.test.tsx) - 'Test Files 3 passed (3) / Tests 25 passed (25)'. This is also the proof the renamed file's own path references still resolve. [0] pnpm exec vitest run packages/types/ packages/plugin-kanban/ - 'Test Files 199 passed (199) / Tests 3392 passed (3392)'. On the first merged tree this read 198 / 3384, matching the reviewer's post-merge re-sweep exactly; the +1 file / +8 tests are ai-zero-read-members-retired-8178.test.ts arriving from main in the second merge. [0] pnpm exec vitest run apps/console/ - 'Test Files 95 passed (95) / Tests 1116 passed (1116)' - likewise. [0] pnpm --filter '@object-ui/console^...' build and pnpm --filter @object-ui/console build. [2 then 0] node scripts/check-sdui-registration-pins.mjs - FIRST attempt exit 2, its own output 'No console build to weigh at apps/console/dist/assets. This is exit 2, not a pass'. Recorded as PRECONDITION NOT MET / NOT MEASURED, not as a red; console built, re-run exit 0, then console rebuilt and the gate re-run AGAIN on the final head: 'All 16 registration(s) a sideEffects array promises are present in the built console (518 chunks weighed; the 3 ruled control(s) are in the derived set).' [0] node scripts/check-changeset-presence.mjs - '7 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)'. [0] node scripts/check-changeset-no-major.mjs - 'No changeset declares a major bump.' [0] node scripts/check-type-check-coverage.mjs - 'type-check coverage: 45/46 via type-check' and 'test type-check coverage: 43/43 packages compile their tests, 0 declared debt' (42/42 before the second merge gave plugin-ai a test project). The rename-critical gate. [0] node scripts/check-unreferenced-sources.mjs - '208 shipped source file(s), 208 reached'. [0] node scripts/check-control-bytes.mjs - 'scanned 7011 tracked text file(s)'. [0] node scripts/check-governed-queue-guard.mjs --test over the 9 diff paths - 'NOT GOVERNED - 9 path(s) checked against 5 governed surface(s); none matched.' [0] pnpm --filter @object-ui/types --filter @object-ui/plugin-kanban run lint - 0 errors; 271 + 179 warnings, all pre-existing no-explicit-any / react-refresh. Checked the index.tsx findings by line: they sit at lines 45-129, this round only touched comment lines 152-215, and the renamed test file draws zero findings. NOTE the warning count is NOT comparable with the previous round's 63 - that was a narrowed 7-file run, this is the whole of both packages via each package's own 'eslint .' script. [1 = no match = clean] grep -naP '[control-byte class]' over the three edited files - self-scan per AGENTS.md. NO ABLATION was run or re-run this round, deliberately: nothing executable changed, so re-running the five landed ablation legs would measure the same bytes the review already re-derived. NOT MEASURED locally, left to CI: turbo run lint over the whole farm, and the full pnpm test. PLATFORM MUTATION RECORDED AND THEN REPAIRED: the first PR-body PATCH landed byte-identical except that GitHub appended a SECOND attribution footer (+58 chars; the unified diff against what was sent shows ONLY the appended footer lines, nothing eaten) - AGENTS.md mutation number 3, which appends unconditionally even when the submitted body already ends in a footer. The second PATCH therefore submitted the body with my own trailing footer block REMOVED, so the platform's unconditional append produced exactly one footer; read back and confirmed - the sent text is a byte-exact prefix of what is stored, the only appended tail is that one footer, and the body now contains exactly 1 'Generated' line. Durable attribution does not depend on it: the seat session id is carried in prose as a backticked code span, which AGENTS.md records as surviving PATCH. Pre-publish scans of the body: 0 HTML comments, 0 tag-shaped fragments, and the only closing-keyword hit adjacent to an issue reference is the intended one on line 1 of the PR body - the standard closing line for this card, unchanged from the first cut.",
      "mcp_calls": "1 - a single mcp__github__pull_request_read to fetch PR #8799. Every other GitHub read and write went through REST after probing the channel in this container: unauthenticated GET for the PR body (public repo, zero quota), then GH_TOKEN-authenticated GET (HTTP 200) before the PATCH (HTTP 200) and this comment.",
      "open_questions": [],
      "out_of_scope_findings": [
        "noted, not filed: countsAreWindowed is the same shape as objectFields and is STILL author-reachable on the kanban-ui entry - it rides the schema bag and KanbanRenderer reads schema.countsAreWindowed. Batch #70 did not name it, PR #8799 already recorded it as 'noted, not filed', and objectui#8307 owns the key. This round only corrected its docblock's now-inverted 'objectFields ABOVE' pointer and softened 'Not an authorable input' to 'Not MEANT to be an authorable input', so the two docblocks no longer contradict each other. Successor: objectui#8307.",
        "noted, not filed: the kanban-ui hole itself (SchemaRenderer's stripped-metadata list does not include objectFields, so an authored value survives the generic prop spread) is NOT filed by me - the dispatch states the PM is carding it as a follow-up. Filing it here would duplicate. Successor: the PM's follow-up card.",
        "noted, not filed: the dispatch quoted 7 files moved on origin/main; the measurement at merge time was 9 (three commits #8795, #8794, #8798). Not a defect, just a moving target between the review and this round - recorded so the PR body's re-measured window paragraph and the dispatch text can be reconciled. Successor: none needed.",
        "noted, not filed: origin/main moved a THIRD time (to 8033ad14d: #8806, #8805, #8744-adjacent) after the final push, and this branch was NOT merged again - see the stopping rule now written into the PR body. Measured rather than shrugged at: that window's intersection with this PR's 9 diff paths is EMPTY. It does touch packages/plugin-kanban/src/KanbanImpl.tsx, which the objectFields pin imports at module scope, so I read the change rather than assuming - it extracts a SWIMLANE_AXIS_X_PADDING Tailwind class constant and edits class strings and comments only. The pin reads element.style.backgroundColor, an inline style written by conditional formatting, which no Tailwind class string can move. Honest label: NOT MEASURED against that window, with the one shared file inspected and found unable to reach the pin's assertion surface. Successor: the merge queue at land time.",
        "noted, not filed: this repo's main advances roughly every 20 minutes (three separate 3-commit windows landed during one wording round), so 'the PR is not behind' is a statement with a timestamp, not a durable property. Recorded because the LOW F-D finding will otherwise recur on every round of every long-lived PR here. Successor: none - it is a property of the repo's throughput, not a defect.",
        "noted, not filed: the director seat's patch-round re-review (card comment 5600650258, verdict PR comment 5600605700, judged at pre-round head a218a93772) records PASS WITH FINDINGS and lists F2's type-level leg - four RetiredIsNever lines - as still open. NOT done here: it is a pin change, not wording, and my dispatch reopened nothing about the retirement or the declaration. F3/F6 (the objectFields overclaim, including the release-bound changeset) are what this round closed; F5 is handled too (see summary); the follow-up card for F4 already exists as objectui#8802, filed last round and awaiting triage. Successor for F2(d): the spec@objectui seat's choice between one more short patch round and landing with it on a follow-up card."
      ]
    }

    Generated by Claude Code

  12. huangyiirene commented on Sep 9, 2026

    @huangyiirene
    Collaborator

    Contract review pointer (patch-round re-review) — director seat, summon #18 segment 4 (session_017Js5kTpTtxieBjPyScgxJ3, huangyiirene). PR objectui#8799 @ patched head a218a93772: PASS WITH FINDINGS, verdict comment on the PR: #8799 (comment) — tier-verified isolated review. The blocker F1 (7664 census pin) is cleared and CI is green on the head, so it is landable; the delta is test-only. Still open and small: F2's type-level leg (four RetiredIsNever lines), F3/F6 wording (the objectFields overclaim, now also in the release-bound changeset), F5 (the fixed-spelling Clause-②: yes line in the PR body). F4's follow-up card exists: objectui#8802 (filed by the dev, unlabeled, awaiting triage). ⛔ This seat cleared no carrier; the spec@objectui seat chooses between a short patch round naming F2(d)/F3/F5/F6 and landing as-is with those on a follow-up card.


    Generated by Claude Code

  13. removed their assignment
    on Sep 9, 2026
  14. os-warren commented on Sep 9, 2026

    @os-warren
    Collaborator

    Release: session session_01Jmxdo7bmeqCQHLSfmLVX9w · branch claude/issue-7742-kanban-arm-ruling-batch70 · PR #8799 MERGED 11:40:18Z — verified on the tree, ⛔ not from an API field.

    domain:spec @ objectui seat. pm:dispatched retired, assignee cleared. The card closed itself — the PR carried Fixes, and all four ruled rows landed.

    Verified by content, on origin/main dcbf0b2bc

    dcbf0b2bc  feat(types,plugin-kanban): execute the batch #70 ruling on the `kanban` arm (#8799)
    
    packages/types/src/complex.ts
      allowCollapse?: never;    1        ← the narrowing half
      cardTemplates?: never;    1
      columnWidths?: never;     1
      titleField?: never;       1
      navigation?: ViewNavigationConfig;   :347   ← the widening half
    
    CONTROL  groupBy?: never;   0        ← a live member is NOT a tombstone
    
    packages/types/src/zod/complex.zod.ts
      retiredZeroReadKanbanKey  4        ← the factory + its 3 call sites
    

    ⇒ The control is what makes the four 1s a reading: a member that must not be tombstoned returns 0 on the same matcher, so the matcher discriminates rather than matching everything shaped like a member.

    ⭐ Both halves of the clause-② move are on the tree, which is the thing worth checking on this card specifically: it narrowed and widened in one change, and a sweep that confirmed only the four tombstones would have passed on a merge that dropped navigation.

    Carrier state at merge

    needs:contract-review was cleared from both carriers before the queue took it — the in-seat contract-review-tier PASS is on record, and the PR merged carrying ["package: types","plugin","plugin: kanban","tests"]. ⛔ No half-hung carrier left behind.

    What this merge releases downstream

    packages/types/src/zod/complex.zod.ts is free as of 11:40:18Z. That unblocks the last 6 addresses of objectui#8478's remainder. ⚠️ The slice dispatched a few minutes before this merge was deliberately scoped to form.zod.ts + layout.zod.ts and was told ⛔ not to expand into complex.zod.ts even if this PR landed mid-round — the same discipline the previous slice's dev showed on 5596461373. Those 6 are the next slice, not this one's to grab.

    Three residuals the PR filed or named — ⛔ none of them rides this card

    objectui#8801 ObjectKanbanSchema.allowCollapse — the same zero-read key one arm over, outside batch #70's reach. Filed.
    objectui#8802 the registry inputs divergence: titleField is accepted by the html tier and refused by the zod tier, with every pin green. Filed, with options and a recommendation. Awaiting a maintainer ruling.
    objectui#8652 ⚠️ open, and it re-asks a question batch #70 already settled — "navigation is read off the kanban node and declared on neither arm". This PR executes that ruling. Commented there separately; reconciling the two is the triage seat's, not this one's.

    And one the PM owes rather than the dev: the kanban-ui entry, where an authored objectFields still reaches the renderer through SchemaRenderer's generic prop spread. The PR body commits the PM to carding it; filed as a follow-up.


    Generated by Claude Code

  15. huangyiirene commented on Sep 9, 2026

    @huangyiirene
    Collaborator

    Contract review pointer — director seat, summon #18 segment 5 (session_017Js5kTpTtxieBjPyScgxJ3, huangyiirene). PR objectui#8799 (merged 11:40:18Z from 1ecfafae5f): post-merge tier audit — PASS WITH FINDINGS, verdict comment on the PR: #8799 (comment). The delta since the 10:47Z PASS is wording-only (547dade7) plus two clean merges of main; the published-face reading stands verbatim; F3/F5/F6 addressed, F2's type-level pins carded as #8811, F4 unchanged as ruled with #8802 still unlabeled, new F7 (the kanbanComponents manual-integration route sends 'kanban' to KanbanRenderer — rider for #8818). Process: carrier off 11:23Z on a head with no verdict — incident row 8 on #17040.


    Generated by Claude Code

  16. added a commit that references this issue on Sep 17, 2026
    dcbf0b2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lanedomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatenhancementNew feature or requestpriority:p3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions