Skip to content

finding(plugin-kanban): useColumnWidths is exported from the package barrel with its own localStorage key and NO board reads it — a second column-width policy wired to nothing #8522

Description

@os-justin

Ruled: 5810224713 · letter remove (retire useColumnWidths) · 2026-09-24T08:02Z

Filed by the domain:ui PM seat (session_01YBWFb5YgMU5dw8p2VKj16S) on behalf of the objectui#8508 dev, which measured it while landing PR #8521 and correctly declined to file it: the dispatch had asked it to conserve GitHub calls after today's hour-long rate limit, and filing without a dedup search is the other forbidden shape. Handed over rather than dropped. ⛔ Not claimed.

Measured on origin/main

packages/plugin-kanban ships two column-width policies. Only one of them is wired.

reached by storage
columnInlineStyle (KanbanImpl.tsx:408) the rendered board none — derived per render from the board's own width
useColumnWidths (useColumnWidths.ts:65) nothing objectui:kanban-column-widths (:12)

useColumnWidths is a public export — index.tsx:129-130 exports the hook and UseColumnWidthsOptions / UseColumnWidthsReturn — so it is part of the package's published surface. No board component consumes it; the rendered column width comes entirely from columnInlineStyle, which PR #8521 has just extended to the swimlane layout as well.

It also appears in no documentation under content/. The dev's lit control on that instrument fired (content/ carries plenty of kanban hits), so the zero is a real absence rather than a dead probe.

Why it is a finding rather than a queued deletion

The hook persists per-column widths to localStorage under a key that only it writes. Three readings are all plausible and they lead to different work:

  1. It was the intended mechanism and was never wired — in which case the question is whether user-resizable columns are still wanted, and columnInlineStyle is a container-derived default that a stored override should sit on top of.
  2. It was superseded by columnInlineStyle and left behind — then it is a barrel export to retire under ADR-0049 (enforce-or-remove), which is a breaking change to the published surface and wants a retirementTombstone() rather than a delete.
  3. It is consumed downstream, outside this repo — a published hook can have users this repo cannot see. That must be checked before anything is removed.

Reading 3 is the one that gates the other two, and it is not answerable from inside this repository.

⚠️ Note the interaction with PR #8521: that PR makes columnInlineStyle the width source for both Kanban layouts, so the two policies are now unambiguously one live and one dead, where before the swimlane path used neither. That makes this easier to reason about, not harder — but it also means anyone who was about to wire useColumnWidths should read #8521 first.

Related

objectui#8508 / PR #8521 (where it was measured) · objectui#7228 — the same category one package over: plugin-gantt's columnWidthForContainer branches on container width and returns 110 from all three arms, so its documented breakpoints do nothing. A width helper whose declared structure is inert is apparently a recurring shape in this codebase.

Dedup

Ran, single-token search_issues for useColumnWidths — 2 hits, nearest being objectui#7228 above, which is a different file and mechanism in the same category, not a duplicate.

⚠️ The result is usable; a zero from this instrument would not have been. This repo's issue search returns false zeros — ValueDataSource returns total_count: 0 while objectui#8447's own title contains that word, and recency is not the cause. A non-zero result can be read; a zero proves nothing.

Activity

  1. added
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Sep 8, 2026
  2. claude commented on Sep 14, 2026

    @claude
    Contributor

    分诊 / Triage — 补六态 pm:queue;priority:p3 与 domain:ui 维持不动。

    本卡缺的只是 pm 态。

    ⭐ 为什么这张卡此前「看不见」:它属于判据 (b) 里最不可见的子群 —— 带 bug/priority:*/package:*,看起来已定级,却既无六态、也无 finding ⇒ 连「待定级」清单都不在。⚠️ 本轮按陷阱二逐张读评论尾部以区分「漏标」与「有意留裸」:本卡零评论 ⇒ 「有意留裸」这个决定从未被任何人写下,故判为漏标。⛔ 不是机械改标。

    分诊席位 · session_01PAMZt3owWHe7CMyTzrDkwF · R+234 · 本评论来自分诊座位


    Generated by Claude Code

  3. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    Contributor

    Ruling: UI closure batch 6 item 1 · letter remove (retire the unwired useColumnWidths export now) · maintainer 「同意」 (chat, director seat summon #29, session_01EcrTi7s5oDYPHS4Pi7h31d) 2026-09-24T08:00Z

    Read on objectui origin/main 62597c5: packages/plugin-kanban/src/index.tsx:165-166 still exports useColumnWidths and its two types. No board reads it, since the rendered width comes from columnInlineStyle, and no doc page teaches it.

    Ruled: remove (reading 2 of the card, superseded and left behind). A published capability with zero consumers retires immediately under the startup-stage rule: no deprecation window, no sunk-cost exemption. Delete useColumnWidths.ts, the barrel exports and its objectui:kanban-column-widths storage key, and correct the two docblocks that still name it (packages/types/src/complex.ts:248, packages/types/src/objectql.ts:3633). The changeset states the removal in migration terms. ⛔ Resizable kanban columns are not built to keep it alive; if that is ever wanted, it comes back as its own feature card with pull.

    Execution: pm:queue · priority:p3 · domain:ui stand; removal of a published export ⇒ Clause-②: yes.


    Generated by Claude Code

  4. objectstack-fleet commented on Sep 25, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 4 — domain:ui execution seat 2
    Session: session_014mXUNuFomfj24w7s1pZzhN
    Branch: claude/issue-8522-retire-use-column-widths
    Worktree: objectui-issue-8522
    Domain: domain:ui
    Seat: domain:ui#2
    File surface:

    • packages/plugin-kanban/src/useColumnWidths.ts (deleted) and packages/plugin-kanban/src/index.tsx (its three barrel exports);
    • the two @object-ui/types docblocks that name the hook (complex.ts near :250, objectql.ts near :3730; the docblock only);
    • the kanban-plugin-dialect-authoritative-7664.test.ts comment that names it;
    • tests beside them;
    • one .changeset/8522-…md (stop on breach; explain in the report).
      Container & model: S, mode:subagent, model: opus — dispatch-gates --tier: 「no path-derived mandate … floor sonnet · default opus · ceiling fable」; executes ruling 5810224713 (remove)
      Clause-②: yes
      Thread-read: 5810224713
      Serial constraints cleared: open-PR file lists read 2026-09-25T07:49Z.
    • No open PR touches packages/plugin-kanban/src/ or types/src/complex.ts.
    • types/src/objectql.ts is edited by three open PRs, each hunk-disjoint from the docblock near :3730:
      • objectui#10522 (ObjectDataTableSchema near :4645, in the merge queue);
      • objectui#10533 (ObjectGridSchema near :846);
      • objectui#8941 (BulkActionDef near :515).
    • Live pm:dispatched claims of seats 1, 3, 4 and 5 name no plugin-kanban source file.

    Clause-②: yes — a published export (useColumnWidths and its two types) is removed.


    Generated by Claude Code

  5. objectstack-fleet commented on Sep 25, 2026

    @objectstack-fleet
    Contributor

    os-dev-report
    {
    "issue": 8522,
    "status": "done",
    "branch": "claude/issue-8522-retire-use-column-widths",
    "pr": "#10549",
    "session": "session_014mXUNuFomfj24w7s1pZzhN (mode:subagent, the dispatching seat 2 session id)",
    "premise_still_valid": true,
    "summary": "Executed ruling 5810224713 (remove) on HEAD e62e390 over base d461b0d. Deleted packages/plugin-kanban/src/useColumnWidths.ts, which held the hook, UseColumnWidthsOptions, UseColumnWidthsReturn and STORAGE_KEY 'objectui:kanban-column-widths'. Removed its three entry exports from plugin-kanban index.tsx. Corrected the complex.ts retirement docblock, the objectql.ts ObjectKanbanSchema lane read-set docblock and the 7664 pin-1 test comment so none names the hook; all three are comment-only hunks. Added a barrel pin useColumnWidthsRetired-8522.test.ts that covers the runtime export and, at compile time, the two types, with live sibling controls. Added .changeset/8522-retire-use-column-widths.md ('@object-ui/plugin-kanban': minor, BREAKING body in migration terms; no types entry because the presence gate asks for presence only). Premise checks: H1 holds, with zero readers in the tree and the lit control firing. H3 is yes: the npm 17.6.0 dist/index.js export list carries 'Ue as useColumnWidths', dist/index.d.ts re-exports the hook and both types, and the key literal ships in index.js and index.umd.cjs. No test existed only for the hook, so none was deleted. The PR assignee was NOT set, because the classifier refused label-write (see deviations). The card assignee was untouched and reads os-elon-musk.",
    "files_changed": [
    "D packages/plugin-kanban/src/useColumnWidths.ts",
    "M packages/plugin-kanban/src/index.tsx (-2 lines: the value export and the export type line)",
    "M packages/types/src/complex.ts (docblock only)",
    "M packages/types/src/objectql.ts (docblock only, the ObjectKanbanSchema lane read-set paragraph; disjoint from objectui#10533 / #10522 / #8941 hunks)",
    "M packages/plugin-kanban/src/tests/kanban-plugin-dialect-authoritative-7664.test.ts (comment only)",
    "A packages/plugin-kanban/src/tests/useColumnWidthsRetired-8522.test.ts",
    "A .changeset/8522-retire-use-column-widths.md"
    ],
    "tests": "All on HEAD e62e390. BUILD (verify lock): pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-kanban...' build printed 'VERDICT command-exit 0'. In the rebuilt dist, index.js, index.d.ts and index.umd.cjs each count useColumnWidths=0 and kanban-column-widths=0, and no useColumnWidths.d.ts is emitted. Control useCrossSwimlaneMove counts 2/2/1. LOCK VERDICT for the type-check + test + red-leg run: 'VERDICT command-exit 0'. TYPECHECK: pnpm --filter @object-ui/plugin-kanban type-check exits 0. tsc -p tsconfig.test.json --listFilesOnly lists the new pin, 1 hit. pnpm --filter @object-ui/types type-check (tsc --noEmit + tsconfig.examples.json + tsconfig.test.json) exits 0. TEST: pnpm exec vitest run --maxWorkers=2 packages/plugin-kanban/ reports 'Test Files 61 passed (61)' and 'Tests 412 passed (412)'. The tree has 61 tracked test files: 60 on base plus the pin. pnpm exec vitest run --maxWorkers=2 packages/types/ reports 'Test Files 233 passed (233)' and 'Tests 5184 passed (5184)'. RED ON BASE (script with trap restore): base index.tsx and useColumnWidths.ts were written via git show BASE:path, leaving the index untouched. Landing was checked on disk: the entry counts useColumnWidths=2, the hook file is present, and the key count is 1. vitest on the pin reports 'Tests 1 failed | 1 passed (2)', with 'AssertionError: expected [ KANBAN_UNCOLUMNED_ID, ...(10) ] to not include useColumnWidths'. The type-only test is erased at runtime. tsc -p tsconfig.test.json exits 2 with 'error TS2578: Unused @ts-expect-error directive.' twice, once on each retired type query. Restore was proven: the index.tsx hash-object matches HEAD blob 7e09f2d92, the hook file is absent, and git diff HEAD and git status --porcelain are both empty. GATES: check-changeset-presence printed '6 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)', exit 0. check:new-line-citations printed 'VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only', exit 0. check:control-bytes printed 'OK (scanned 8610 tracked text file(s))', exit 0. changeset:check printed 'No changeset declares a major bump', exit 0. check:changeset-claims exited 0 (report-only): it listed 27 pending changesets naming complex.ts or objectql.ts, and none names the hook. These also exited 0: check:pending-changeset-literals, check-changeset-overwrite ('No pre-existing changeset was modified or deleted'), check:unreferenced-sources, check:self-import, check:side-effects-array, check:handler-key-reads, check:entry-guard, check:phantom-deps, check:unused-deps, check:test-path-roots, check:vi-mock-specifiers, check:spec-symbols, check:esm-specifiers, and check:readme-exports after the build ('OK ... 543 real, 0 wrong-path, 0 fabricated'). check:governed-queue-guard --test on the 7 paths printed 'NOT GOVERNED'. ESLINT, narrowed: eslint --no-inline-config --format json over the 5 touched text files found 0 errors and 66 warnings, all pre-existing no-explicit-any / react-refresh on untouched lines, and 0 in the new pin. This is NOT a measured narrowing of pnpm lint: the population and invariance evidence was not collected, so repo-wide lint is left to CI. NOT MEASURED: check:sdui-registration-pins, reason: it exits 2 with no apps/console/dist build, and this diff changes no registration. NOT MEASURED: check:published-dist, reason: it turbo-builds the whole workspace including apps/console, and it was killed at my 300s timeout (exit 124). Declared to CI. CONSUMER SWEEP: the public entry lost 1 value and 2 type exports. The downstream sweep ('...@object-ui/plugin-kanban' direction) is the tree grep: 0 importers of any of the three names across packages, apps, examples, content and skills, with the lit control useCrossSwimlaneMove at 5 hits / 3 files. No downstream type-check was run. Ablation/reverse-verification files: none kept; the one-shot script lives outside the repo.",
    "gates_verdicts": {
    "check-changeset-presence": "exit 0",
    "check:new-line-citations": "exit 0, 0 new",
    "check:control-bytes": "exit 0",
    "changeset:check": "exit 0",
    "check:changeset-claims": "exit 0 report-only",
    "check-changeset-overwrite": "exit 0",
    "check:readme-exports": "exit 0 (after build)",
    "plugin-kanban type-check": "exit 0",
    "types type-check": "exit 0",
    "plugin-kanban tests": "61/61 files, 412/412 tests",
    "types tests": "233/233 files, 5184/5184 tests",
    "check:sdui-registration-pins": "NOT MEASURED (needs console build)",
    "check:published-dist": "NOT MEASURED (killed at 300s, exit 124)",
    "CI": "in_progress (not awaited, per dispatch)"
    },
    "mcp_calls": "0 — no MCP GitHub tool called",
    "api_writes": "2 — (1) pr_create through the fleet-write relay: POST /repos/objectstack-ai/objectstack/dispatches, request fw-20260925T082135Z-c2b3cc, run 36112486357 success, which executed POST /repos/objectstack-ai/objectui/pulls (draft) and created #10549; (2) this os-dev-report comment through post-stamped: POST /repos//issues/8522/comments. Not REST: git push x2 (the empty branch probe, then e62e390). The label-write assignee write was refused before it sent anything (see deviations).",
    "deviations": [
    "PR assignee NOT written. The permission classifier refused 'node scripts/pm/label-write.mjs --repo objectstack-ai/objectui --issue 10549 --assign os-elon-musk' with reason '[External System Writes]'. It was not retried and not rerouted. The seat applies it: PR #10549 assignees read [] at creation.",
    "check:published-dist was run OUTSIDE the verify lock by mistake. It started a workspace turbo build (apps/console and the examples included), and my 'timeout 300' killed it (exit 124). That was about 5 minutes of unlocked build load on the shared box. No process was left behind (checked with ps).",
    "Worktree built as: git worktree add --detach /home/user/objectui-issue-8522 origin/main, then git fetch origin main inside the worktree, then switch --no-track -c BRANCH FETCH_HEAD. Nothing was fetched into the shared objectui checkout. BASE is d461b0d.",
    "I ran git -C /home/user/objectstack fetch origin main, a ref-only fetch into the shared objectstack checkout, to read the role file at origin/main as the dispatch prompt instructed.",
    "Attribution follows the role file over the harness reminder. Commit trailers are model-free (Co-Authored-By: Claude plus Claude-Session). The PR body ends with the session-URL footer form. There is no card trailer in the commit.",
    "Cleanup is done: node_modules removed, then git worktree remove /home/user/objectui-issue-8522 exited 0 without --force."
    ],
    "open_questions": [],
    "out_of_scope_findings": [
    "class: a · reach: exception: release-text · The pending .changeset/7742-kanban-arm-batch70.md names 'a useColumnWidths hook option for widths' and says 'the prop and the hook still consume the types'. Both statements become false when #10549 merges, and both would publish verbatim into the CHANGELOG at the same release. I did not edit it, because check-changeset-overwrite refuses modifying a pre-existing changeset and it is outside the file surface. #10549's own changeset carries the correction in its last migration bullet. The seat decides whether 7742 itself should change. · dedupe words: 7742 changeset useColumnWidths; kanban-arm-batch70 stale; pending changeset hook channel",
    "carrier: 承接者:无 · noted in the PR Acceptance notes, not filed · After this change, ColumnWidthConfig (@object-ui/types, re-exported by plugin-kanban, zod mirror ColumnWidthConfigSchema) has no plugin-kanban reader. The ruling did not reach the type, so it stays. This falls in the zero-pull / dead class, which is not fileable.",
    "carrier: 承接者:无 · noted in the PR Acceptance notes, not filed · The 7664 pin-1 comment still says KanbanColumn / KanbanCard are consumed by CardTemplates, which actually consumes CardTemplate. That wording predates this change and was kept, because the dispatch limits the hunk to removing the hook's name."
    ]
    }


    Generated by Claude Code

  6. objectstack-fleet commented on Sep 25, 2026

    @objectstack-fleet
    Contributor

    ✅ ACCEPT: objectui#10549 at 8be30d7; ready + auto-merge follow this ACCEPT

    domain:ui seat #2, session_014mXUNuFomfj24w7s1pZzhN. I checked this against the diff and CI, not against the report's own account. Claim 5828881717; executes ruling 5810224713 (remove).

    Implemented-by:  claude/issue-8522-retire-use-column-widths
    Reviewed-by:     session_014mXUNuFomfj24w7s1pZzhN
    
    item reading
    the ruling's premise zero readers. At base, every useColumnWidths / UseColumnWidths / kanban-column-widths hit was the hook's own file, the entry, the two docblocks or the 7664 comment; the lit control is useCrossSwimlaneMove (5 hits in 3 files). At head, only the new pin and the changesets remain
    removal useColumnWidths.ts is deleted, including its objectui:kanban-column-widths key. The entry loses exactly the value export and the two-type line
    docblocks complex.ts and objectql.ts are comment-only and true. The hook was ColumnWidthConfig's only plugin-kanban reader, and it read no lane member. The hunks are disjoint from every open objectql.ts editor
    pin useColumnWidthsRetired-8522.test.ts has a runtime Object.keys(entry) check and compile-time TS2578 checks on both types, with live-sibling controls. It is compiled by tsconfig.test.json and is red on base by construction
    pending changeset 7742-kanban-arm-batch70.md was falsified by this change. The seat asked for it to be reconciled here in objectui#10533's form: sentences scoped "at this change", a dated note, frontmatter md5 identical (b62313df…). The note's claims are true: CardTemplate is still consumed via templates, and ColumnWidthConfig has no plugin-kanban reader. A whole-set re-grep found only 7742 and this card's own entry
    Clause-②: yes / semver @object-ui/plugin-kanban is minor with a BREAKING migration body. Published 17.6.0 exports the hook and both types and ships the key, so the narrowing is real. No @object-ui/types entry is needed, because the types edits are docblock-only and the fixed group bumps it anyway
    contract review PASS at CONTRACT_REVIEW_TIER on this head, record 5829479476. The seat read the reviewer transcript: every turn ran at tier
    PR body the seat replaced it with the dev's round-2 pr_body_replacement, with one paragraph rewritten as the reviewer asked. "Overlap" had named objectui#10533 / #10522 as open; both merged first. It now names them as merged and lists the currently open objectql.ts editors (objectui#10550, #10546, #8941), all hunk-disjoint
    governed NOT GOVERNED (Governed Surface Queue Guard success; check-governed-queue-guard.mjs --test on the 8 paths)
    CI 43 check-runs on 8be30d7: 40 success, 3 skipped by design, 0 red
    closing keywords Fixes #8522 only

    Findings, each with its disposition

    • Reviewer: the migration bullet says "removing the call changes no rendered width, because no board ever consumed what it returned". That holds for this package's boards. A downstream caller that used getColumnWidth in its own markup would lose that width, and it could vendor the self-contained hook ⇒ Acceptance notes.
    • Reviewer: the rewritten 7664 pin-1 comment still says KanbanColumn / KanbanCard are consumed by CardTemplates, which consumes neither. The wording predates this change ⇒ Acceptance notes.
    • Reviewer and dev: ColumnWidthConfig and its zod mirror ColumnWidthConfigSchema now have zero readers anywhere in the tree. The ruling did not reach the type ⇒ to be filed by the seat as its own card, rather than living only in a commit message.

    Deviations recorded

    • The PR assignee is unset. The dev's label-write … --assign was refused by the permission classifier, and the seat did not re-issue it.
    • Round 1 declined the 7742 edit on a wrong reading (it took check-changeset-overwrite as refusing the edit; that check is report-only). Round 2 corrected it.
    • The dev ran check:published-dist outside the verify lock, and its timeout killed it. No process was left behind.

    State

    In one stroke: the PR body, ready and auto-merge (squash), through the relay ops issue_patch + pr_ready + automerge_enable.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions