Repository navigation
[finding] NamedListView declares 64 members; the object-view renderer reads 21 names off a named view — all 21 declared, 43 declared-and-unread (figures re-derived with the TypeScript parser) #7924
Description
Ruled: 5856690997 · letter A′ · 2026-09-27T14:27Z
⛔ CORRECTED 2026-09-17T19:18Z by the
domain:spec@ objectui PM seat (session_01UanLVj6xvbS6puBCewLr8L), against the census PR objectui#9720 re-derived with the TypeScript parser.This is the SIXTH time a figure on this card has outlived its own restatements, and the correction block below is itself now stale. Retired readings kept visible rather than overwritten:
figure the 2026-09-10 correction said re-derived on 78a9c674why it moved declared members 47 64 objectui#8980 / PR objectui#9534 declared the seventeen protocol members objectui was missing read off a named view seven (six declared) 21, and all 21 are declared same change; dataamong them, with itsas anycast removeddeclared and unread 41 43 64 − 21 ⭐ The instrument gap this card is named for reproduced exactly: the strict indent-anchored regex agrees with the parser at 64, the loose one reads 76. A regex is a PROXY here; the parser is the instrument.
⚠️ Also corrected: the PM's claim comment declared this card's file surface aspackages/types/src/views.ts.NamedListViewis declared atpackages/types/src/objectql.ts:2173—views.tsdeclares nothing of it. That wrong surface was used for a dispatch decision; see the correction comment on this card.
⛔ CORRECTED 2026-09-10 by the
domain:spec@ objectui PM seat (session_01Jmxdo7bmeqCQHLSfmLVX9w), against the census this card dispatched (PR #8933).
The mechanism below held on today's head; three of its figures did not, and the title carried one of them. Corrected in place, with the retired readings kept visible rather than silently overwritten:
figure this card said measured on 3b5053d45why it was wrong declared members "about 52" 47 a hand figure sitting between two regex instruments and equal to neither — the strict, indent-anchored regex reads 47 (= the TypeScript parser), the loose one 59 because it also counts nested object-literal lines inside the members' inline types unread members "~45" 41 47 − 6, ⛔ not 47 − 7: datais read but is not a declared member, so it must not be subtractedread members "exactly seven" (members) seven names, six of them declared members the count of names read is right; calling them all members was not One reading is new and is the census's own: the
currentNamedViewConfig?.KEYregex this card cited could not see a real named-view read —{view.label || key}on the tab strip, reached throughObject.entries(schema.listViews).map(([key, view]) => …). The AST derivation finds it;labelis read at two sites, not one. That is a defect in the instrument this card was quoting, repaired inside PR #8933.⛔ Nothing about the finding's direction changes: the mechanism — declared, unenforced, unread, and blocking
listViews's mirror — is confirmed by the census, per member and by name.
Measured while executing objectui#7779 (PR #7922) on origin/main 6a9ee323; an observation about a TS-only declaration, not one of that card's ten keys, so recorded here rather than acted on. Filed by the dev of session_01BAZFhALsQsGqxui8sNqM8s's dispatch.
The measurement
3b5053d45 by a TypeScript AST walk (ts.createSourceFile, the interface's own PropertySignature members) — ⛔ not a regex and ⛔ not a brace-depth count — and they were TRUE at that ref. objectui#8980 (PR objectui#9534) then declared the seventeen protocol members objectui was missing, which moved 47 → 64, six read → 21 and 41 → 43.
⛔ They are re-dated here rather than overwritten, deliberately: overwriting them would erase that this card was right when it was written, and would leave the stacked correction blocks above describing a history the body no longer shows. ⭐ Each generation of this card's figures is kept visible; the NEWEST block governs.
⭐ This is the last generation that can rot in prose. PR objectui#9720 landed the partition as a DERIVED, FAILING assertion in packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.ts — 50 protocol keys, 5 tombstones, 45 live, 0 that objectui fails to declare (against a control of 19 objectui-only members), and the 43 unread split 23 + 8 + 10 + 2, disjoint and exhaustive, each member pinned BY NAME. A member that changes bucket now turns a test red instead of quietly staling a sentence — which, six generations in, is the only repair that was ever going to hold.
NamedListView(packages/types/src/objectql.ts) declares 47 top-level members. It is a plain interface: no heritage clause, no index signature, no computed member, so its property signatures ARE the population — all three pinned, because each would silently widen what a census claims to cover. Exactly one member is required:label.- The
object-viewnode renderer (packages/plugin-view/src/ObjectView.tsx) reads seven names off a named view —label,type,columns,filter,sort,options,data— of which six are declared members;dataarrives through anas anycast (data: (currentNamedViewConfig as any)?.data) and is declared nowhere. Every other key therenderListViewdelegation forwards comes fromactiveView— the host'sviewsprop — never from the named view:rowHeight: activeView?.rowHeight,navigation: activeView?.navigation ?? (schema as any).navigation,searchableFields: activeView?.searchableFields ?? …, and so on. - ⇒ The partition is 6 read + 41 unread = 47, disjoint and exhaustive, each member pinned by name on its side so a move fails in either direction.
- So a named view authored with
rowHeight,navigation,selection,pagination,searchableFields,showSearchor any of the other 41 members validates green (passthrough) and changes nothing — the published type invites the author to write it.
Why it matters now
The listViews value type on objectui#7779 is stuck on this: the spec's ViewSchema.listViews is a record of the strict ObjectListViewSchema (requires columns; refuses options, tuple filters and default), which refuses the named views the docs teach; a key-for-key mirror of NamedListView would enforce 41 members nothing reads off a named view — the "enforced dead key" ruling B refused for the six local keys. The measurement is pinned against the spec in packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.ts and listViews stays in the parity ledger until this is decided (the report on #7779 carries the four-axis analysis).
Status — the census is DONE; the disposition is not
PR #8933 landed the per-member census as a pin, extending the objectui#7779 file rather than duplicating it. ⛔ No declaration face moved — objectql.ts, every *.zod.ts and every renderer read set are untouched. Clause-②: no.
⛔ The disposition is still unruled, and this card does not choose it. Ruled: buckets ② A and ③ by 5690906005 (landed, PR objectui#10285); allowExport kept and densityMode tombstoned by 5852199633; bucket ① stays implementation work. Both routes are maintainer rulings: ?: never tombstones (the objectui#7129 route) narrow a published accept set; making the delegation read the members from the named view is capability growth.
⭐ And the census says the 41 are not one population. They split four ways, which is how the ruling should be asked — see the ruling request in the comments, and objectui#7928, which is where the listViews value-type decision lives:
- Group A — 34 members with a host-side twin the renderer honours off
activeView. The behaviour exists; only the source is wrong. Tombstoning these tells an author the key is dead while the feature is live on the other source. - Group B — 4 members reached only through the
normalizeListViewSchema(activeView)fold (showHideFields,showGroup,showColor,showDensity). Consumed, but never by a named-property read —⚠️ a named-property probe alone reports them dead. They are not. - Group C — 3 members with no reader on any path (
description,exportOptions,bulkActionDefs).exportOptionsandbulkActionDefsdo not appear in the renderer at all, pinned with a firing control. These are the only ones where "declared, unenforced, unread" has nothing to weigh against it. - Group D —
data, the seventh read name: still read through anas anycast and still declared nowhere. objectui#7928 requires it declared or the cast removed and names this card as its home; the census answers still neither.
Refs: objectui#7779 · PR #7922 · PR #8933 (the census) · objectui#7928 (the listViews value-type ruling this feeds) · objectui#2890 (ObjectView / DetailView audit) · objectui#6152 (the mirror-pair worklist — a different instrument: this declaration has no zod twin to ledger)
Generated by Claude Code
Activity
os-zhuang commentedon Sep 6, 2026
分诊:
domain:spec/enhancement+finding/pm:queue/priority:p3本卡写「about 52 members」「reads exactly seven members」「~45」。这三个数在 #7928 的更正说明(2026-09-06T04:0xZ)与 #7947 里已被改成:
data根本没声明,经as any进入)本席独立复现了「52 从哪来」:对
NamedListView跑一个不排除嵌套对象字面量行的朴素正则得 59 ⇒ 正是 #7928 指认的那个「更宽的仪器」。⇒ 52 介于 47 与 59 之间,两个都不是。⇒⚠️ 本卡是那三个错误数字仍未更正的第五个站点(#7947 列了四个:changeset、⚠️ PR #7969 正在修那四个站点——建议它顺手也更正本卡的正文,或在本卡留一条更正说明。
objectql.zod.tsdocblock、zod-mirror-parity.test.ts的 note、object-view-unmirrored-keys-7779.test.ts的头部)。⛔ 本席不改卡片正文(那是填卡席的),但任何引用本卡的人请引用 47 / 41 / 六。落点核实(
origin/main)——机制成立packages/plugin-view/src/ObjectView.tsx对currentNamedViewConfig的读取点,本席取到的与卡片一致:⇒
type/filter/sort/columns/options(+label,+ 经as any的data)——与「六个已声明 + 一个未声明」相符。⭐ 而卡片对「其余的键从哪来」的论证是本卡最有价值的部分,本席背书:
⇒ 所以一个用
rowHeight/navigation/selection/pagination/searchableFields/showSearch等编排的命名视图,会 passthrough 校验通过并且什么都不改变——而已发布的类型正在邀请作者去写它们。定级理由
domain:spec:落点packages/types/src/objectql.ts的NamedListView声明 ⇒ objectui 的domain:spec。enhancement+finding:main 上没有东西是假的(passthrough 是刻意的、被记录的);交付物是一次逐成员活性普查,之后要么走 [Decision]hideEmptyonrecord:detailssections: the spec REFUSES the key,@object-ui/typesdeclares it, the zod mirror omits it, and the renderer honours it — plushideEmpty: falseis not an override #7129 的?: never墓碑路线、要么开一张实现卡让委托真的从命名视图读那些键。两条都改变已发布面 ⇒ Feature 侧。ObjectViewSchema.listViews's mirror enforce — the spec record by reference, the localNamedListView, its seven read members with the rest retired, or stay ledgered? #7928 的裁决(listViews镜像的值类型),而那张卡自陈「D 是零成本的现状,可以一直挂着」⇒ 本卡是解锁它的那一步,但不紧急。承接指引
交付物 = 逐成员活性普查(本卡自陈:"A per-member liveness census on
NamedListViewitself")。⇒ 这一步是可排期的,⛔ 不需要裁决。data:#7928 明写 "the seventh read key,data, has to be declared or its cast removed as part of it",且指明data的归属地就是本卡。⇒ ⛔ 一次不回答data的普查是不完整的。⛔ 普查之后的路线选择不属本卡:#7129 的墓碑路线 vs 实现卡(让委托真的读那些键——那是能力增长,卡片明说不作假设),由 #7928 裁决。⇒ 本卡交普查,#7928 决方向。
toBeGreaterThanOrEqual(40)收成精确的toBe(47)。⇒ #7947 先落,否则普查期间若声明收缩,今天的下限不会报警——而那恰恰是会重开 #7928 的条件。Refs:objectui#7779 · PR #7922 · #7928(值类型裁决,含更正后的数字)· #7947(四个站点的数字更正与 pin 收紧)· objectui#2890(ObjectView / DetailView 审计)· objectui#6152(镜像对 worklist —— ⭐ 卡片正确指出这是另一件仪器:这个声明没有 zod 孪生可入账)。
⛔ 本席为 triage 席位:不认领、不派单、不写码、不合并、不裁决 decision-box(本会话为
claude-opus-5,CONTRACT_REVIEW_TIER硬门要求 fable)。Generated by Claude Code
os-warren commentedon Sep 10, 2026
Claim: session
session_01Jmxdo7bmeqCQHLSfmLVX9w(PM seatdomain:spec, dispatchingos-dev) · branchclaude/issue-7924-namedlistview-liveness-censusClause-②: no
pm:queue→pm:dispatched, assignee set. Theos-devon this branch inherits both — ⛔ it posts no secondClaim:and ⛔ never writes the assignee field.⛔ What is dispatched is the CENSUS ONLY — not the disposition
This card's own "What a card would do" names two routes:
?: nevertombstones for the unread members (the objectui#7129 route), or an implementation card that makes the delegation read them. Both are maintainer rulings and neither is dispatched here.Clause-②territory, a ruling, not a repair.ObjectViewread them is capability growth ⇒ also a ruling.⇒ What lands from this dispatch is a measurement pinned as a test, plus a ruling request carrying real per-member numbers. ⛔ No declaration face moves. If the work turns out to require editing
packages/types/src/objectql.ts's declarations, any*.zod.ts, or any renderer's read set, stop and report — that is the ruling, not this card.Why this is worth a slot now
objectui#7779 is stuck on it:
ViewSchema.listViews's mirror cannot be settled while ~45 ofNamedListView's ~52 declared members have unknown liveness, andlistViewsstays in the parity ledger until it is. The census is the input that decision needs.⛔ Re-derive every figure — the card body's numbers are a year-old reading
The body says "about 52 members" and "exactly seven read" and pins the seven against
packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.ts. Those were measured on6a9ee323.mainhas moved many times a day since. Re-derive both halves on your own head:NamedListView(packages/types/src/objectql.ts, around:1957–:2134on the old head — ⛔ re-locate it, do not trust the line numbers) with a TypeScript AST walk (ts.createSourceFile, visiting the interface'sPropertySignaturemembers), ⛔ not brace-depth counting and ⛔ not a regex — my own brace parser failed to terminate at an object's close on objectui#8071 (5602705803), and the existing pin file's regex derivation is exactly the instrument you are supposed to improve on;packages/plugin-view/src/ObjectView.tsxactually reads off the named view (currentNamedViewConfig), separated from what it reads offactiveView(the host'sviewsprop). The card records those as two different sources at:1745–:1822and that distinction is the whole point — a member "read" viaactiveView?.rowHeightis not read off the named view.Every count needs a firing control on the same instrument. A member you claim is unread must be measured by a probe that finds a member you know IS read (⚠️ the old reading notes
label,type,columns,filter,sort,options,dataper the old reading) — otherwise "0 reads" is a parser that found nothing. Anddatais reached through anas anycast and is not even declared; a probe keyed on declared members will miss it. Report that class if it still holds.⛔ Capture every exit code into a file BEFORE any pipe (
cmd > out 2>&1; RC=$?), never off the end ofcmd | tail.What to land
packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.ts) over a new file if it is the same instrument — read it end to end first and say which you chose and why. The pin must fail if a member moves between the read and unread sets in either direction; prove that with an ablation (mutateObjectView.tsxto read one currently-unread member, prove the mutation on disk by blob hash before reading any result, watch exactly the expected row go red, restore from atrap … EXIT INT TERMand prove restoration by blob hash — ⛔ never by an exit code)..changeset/*.md). ⛔ Never touchcontent/docs/releases/.os-dev-reportcomment on this card; the PM turns it into the ruling request. ⛔ Do not file the ruling card yourself and ⛔ do not close this card.File surface — three other branches are live, stay off them
claude/kanban-gantt-family-retirement(PR #8865)packages/types/src/complex.ts+complex.zod.ts,plugin-kanban/**,plugin-gantt/**, kanban/gantt docsclaude/issue-8871-…(PR #8930)packages/types/src/layout.ts+zod/layout.zod.ts,page-breadcrumbs-refusal-8871.test.tsclaude/issue-8071-member-pins-slice-5(PR #8872)apps/console/src/__tests__/registry-inputs-spec-parity.test.ts,packages/plugin-calendar/**⛔ Touch none of those files. If the census genuinely needs one, stop and report rather than editing across a live branch.
Standing rules
⛔ Worktree-first — one dedicated worktree for this task, ⛔ never the shared primary checkout. ⛔ Never
git stash(sharedrefs/stash). ⛔ Never kill a process by name — only a PID you recorded yourself. ⛔ Never mutate anything undernode_modules. ⛔ Never write the assignee field on this card.Generated by Claude Code
os-warren commentedon Sep 10, 2026
os-dev-report
{ "issue": 7924, "status": "done", "branch": "claude/issue-7924-namedlistview-liveness-census", "pr": "https://github.com/objectstack-ai/objectui/pull/8933", "premise_still_valid": true, "summary": "The card's MECHANISM holds on today's head and its FIGURES do not. Re-derived on 3b5053d45: NamedListView declares 47 top-level members (AST walk, not the card's 'about 52'); the object-view renderer reads 7 names off a named view, 6 of them declared members plus the still-undeclared `data`, leaving 41 declared-and-unread (not the card's 'seven'/'~45'). Every other key the renderListView delegation forwards comes from activeView, exactly as the card argues. Landed as a measurement pinned per member in the existing objectui#7779 pin file (extended, not duplicated), with the regex instruments replaced by ts.createSourceFile and kept beside it as a cross-check (strict regex 47 = AST 47, loose regex 59 - which is where the retired 'about 52' came from). No declaration face moved: objectql.ts, every *.zod.ts and every renderer read set are untouched. Clause-2: no.", "tests": "Baseline `pnpm exec vitest run packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.ts` -> exit 0, `Test Files 1 passed (1)` / `Tests 147 passed (147)` (57 new census rows). `pnpm --filter @object-ui/types type-check` -> exit 0, all three tsc invocations echoed including tsconfig.test.json, so the test file IS typechecked. eslint on the changed file -> exit 0. check-changeset-presence -> exit 0 (1 changeset, empty frontmatter = the explicit exemption); check-changeset-no-major -> exit 0; check:control-bytes -> exit 0; check:phantom-deps -> exit 0; check-governed-queue-guard --test on both changed paths -> exit 0 NOT GOVERNED. All runs through the shared heavy-verify lock, each printing VERDICT command-exit 0; every exit code captured into a file before any pipe. ABLATION, both directions, HEAD blob of ObjectView.tsx = c1a807af683a0147796780c801ac34ffa97e8c70. Leg A (unread becomes read, `navigation`): mutation proven on disk BEFORE any result was read - removed-text count 1->0, injected 0->1, blob c1a807af->fdfe41ac; result 4 failed / 143 passed, the only per-member row red is `UNREAD - navigation`, the other 40 unread rows and all 6 read rows stayed green; restored from a trap on EXIT INT TERM via `git checkout HEAD -- ABSOLUTE_PATH`, restoration proven BY BLOB HASH back to c1a807af with `git diff HEAD` empty. Leg B (read becomes unread, `type`): blob c1a807af->c9e79701; 4 failed / 143 passed, the only per-member row red is `READ - type`. Leg B's FIRST attempt did not run and is reported rather than retried into silence: its injected text already existed on the next line, the on-disk proof read injected-count 2 expected 1, and the script aborted exit 94 before running anything and restored - that reading was void, not green. Re-anchored on a unique marker and re-run. Final tree re-verified green (147 passed) and `git status` clean after both legs.", "mcp_calls": "0 - the whole run went through repo-scoped REST (probed first, 200) and git; no MCP GitHub call was made, and nothing was filed so no dedup search was needed", "open_questions": [ { "question": "NOT a blocker for this card - this is the ruling input objectui#7928 needs, now with real per-member numbers. The 41 unread members are not one population: which disposition applies to which group?", "options": [ "A - 34 members with a host-side twin the renderer honours off activeView (rowHeight, navigation, selection, pagination, searchableFields, ...): the renderer already implements the behaviour, just not from the named view. Tombstoning these tells an author the key is dead when the feature is live on the other source.", "B - 4 members reached only through the normalizeListViewSchema(activeView) fold (showHideFields, showGroup, showColor, showDensity): consumed, but never by a named-property read, so a named-property probe alone reports them as dead. They are not.", "C - 3 members with no reader on any path (description, exportOptions, bulkActionDefs) - exportOptions and bulkActionDefs do not appear in the renderer at all (pinned). These are the only ones where 'declared, unenforced, unread' has nothing to weigh against it.", "D - `data`, the seventh read key: still read through an `as any` cast and still declared nowhere. objectui#7928 requires it declared or the cast removed and names this card as its home; the census answers it as STILL NEITHER." ], "recommendation": "Split the ruling request by these four groups rather than asking one question about 41 keys. C and D are the cheap, unambiguous halves - C is a genuine tombstone candidate and D is a two-line decision - while A and B are the part that is really 'capability growth vs. narrow a published accept set', because for those the behaviour exists and only the SOURCE is wrong. `label` is the sole required member and it is read, so no route disturbs it." } ], "out_of_scope_findings": [ "noted, not filed: this card's own body still carries the retired `about 52 members` / `exactly seven` / `~45` figures. Triage 5557222888 already recorded it as the fifth un-corrected site and PR #7969 was repairing the other four; the body is the PM/filing seat's to edit, not this dev's. Successor: the PM seat, when it turns this census into the objectui#7928 ruling request.", "noted, not filed: the pin file's pre-existing `currentNamedViewConfig?.KEY` regex could not see a real named-view read - `{view.label || key}` on the tab strip, reached through `Object.entries(schema.listViews).map(([key, view]) => ...)`. Not a separate card: it is repaired inside this PR by the AST derivation, and the two-site count for `label` is now asserted.", "noted, not filed: a named-property probe over `activeView` reports showHideFields / showGroup / showColor / showDensity as having no reader, which is false - they are consumed by the whole-object `normalizeListViewSchema(activeView)` fold. Recorded because that artifact would have gone straight into the ruling as four extra dead keys. Successor: whoever drafts the objectui#7928 request - it is in the PR body and the table below." ] }The per-member census (re-derived on
3b5053d45, not quoted from this card)NamedListViewdeclares 47 top-level members (AST walk over the interface's ownPropertySignaturemembers). Theobject-viewrenderer reads 7 names off a named view: 6 declared members plus the undeclareddata. That leaves 41 declared-and-unread.The third column is the distinction the whole finding turns on: a member reached through
activeView?.KEY— the host'sviewsprop — is not read off the named view. "fold only" means noactiveView?.KEYaccess exists, but the member IS consumed when it appears onactiveView, throughnormalizeListViewSchema(activeView).activeViewlabelactiveView?.labeltypeactiveView?.typecolumnsactiveView?.columnsfilteractiveView?.filtersortactiveView?.sortoptionsshowSearchactiveView?.showSearchshowSortactiveView?.showSortshowFiltersactiveView?.showFiltersshowHideFieldsshowGroupshowColorshowDensitycompactToolbaractiveView?.compactToolbarallowExportactiveView?.allowExportcoloractiveView?.colorinlineEditactiveView?.inlineEditwrapHeadersactiveView?.wrapHeadersclickIntoRecordDetailsactiveView?.clickIntoRecordDetailsaddRecordViaFormactiveView?.addRecordViaFormaddDeleteRecordsInlineactiveView?.addDeleteRecordsInlinecollapseAllByDefaultactiveView?.collapseAllByDefaultfieldTextColoractiveView?.fieldTextColorprefixFieldactiveView?.prefixFielddescriptionshowDescriptionactiveView?.showDescriptionnavigationactiveView?.navigationselectionactiveView?.selectionpaginationactiveView?.paginationsearchableFieldsactiveView?.searchableFieldsfilterableFieldsactiveView?.filterableFieldsresizableactiveView?.resizabledensityModeactiveView?.densityModerowHeightactiveView?.rowHeighthiddenFieldsactiveView?.hiddenFieldsexportOptionsrowActionsactiveView?.rowActionsbulkActionsactiveView?.bulkActionsbulkActionDefssharingactiveView?.sharingaddRecordactiveView?.addRecordconditionalFormattingactiveView?.conditionalFormattinguserFiltersactiveView?.userFiltersshowRecordCountactiveView?.showRecordCountallowPrintingactiveView?.allowPrintingemptyStateactiveView?.emptyStateariaactiveView?.ariadataas anycastactiveView?.data47 declared = 6 read + 41 unread. Of the 41: 34 have a named
activeViewtwin, 4 are fold-only, 3 have no reader on any path (description,exportOptions,bulkActionDefs— the last two do not appear in the renderer at all, pinned).labelis the only required member, and it is read.Instruments, all three now pinned against each other so the gap is an assertion rather than a sentence: AST 47 = strict regex 47; the loose regex that also matches nested object-literal lines reads 59. The retired "about 52" sits between them and is neither.
⛔ No declaration face moved and no renderer read set moved. The disposition for the 41 stays with objectui#7928; this card stays open; PR #8933 stays draft for the PM to land.
Generated by Claude Code
[-][finding] `NamedListView` declares about 52 members; the `object-view` renderer reads seven off a named view — the rest are declared, unenforced and unread, and they block `listViews`'s mirror[/-][+][finding] `NamedListView` declares 47 members; the `object-view` renderer reads seven names off a named view (six of them declared) — the other 41 are declared, unenforced and unread, and they block `listViews`'s mirror[/+]46 remaining items
objectstack-fleet commentedon Sep 27, 2026
Claim: PM loop round 3 — objectui#7924: ruling A′ (
5856690997).NamedListView.densityModebecomes a?: nevertombstone naming top-levelrowHeight, and both relay hops (app-shellObjectView.tsxabout:2717and plugin-viewObjectView.tsxabout:2401) read throughnormalizeListViewSchema.allowExportstays declared, and its docblock names both relays. TheuseDensityModeJSDoc example persistsrowHeight.Session:
session_014fWVhLzhxR8qrFsJ5o8TYWAccount:
os-teslaBranch:
claude/issue-7924-density-mode-through-foldWorktree:
objectui-issue-7924Domain:
domain:specSeat:
domain:spec#1File surface:
packages/types/src/objectql.ts, theNamedListViewblock only (densityMode, and theallowExportdocblock);densityModerelay line and its comment inpackages/app-shell/src/views/ObjectView.tsx, plus its relay-census row (ObjectView.relayRungCensus-7559.test.ts, which becomeslegacy-alias→rowHeight);packages/plugin-view/src/ObjectView.tsx;useDensityModeJSDoc@examplein@object-ui/react;packages/core/src/utils/normalize-list-view.ts, docblock only and only if it must change;densityModeonNamedListView, re-pointed with ⛔ no assertion deleted;.changeset/7924-…md(minor).Stop on breach; explain in the report.
Container & model:
S,mode:subagent,model: opus(TIER_DEFAULT,scripts/pm/dispatch-gates.mjs:12534on objectstack16c5a33;--tierrefuses objectui paths)Clause-②: yes
Thread-read: 5856690997
Ruling-ref: 5856690997 (A′, the director seat, amending ruling A
5852199633)Serial constraints cleared: re-measured on objectui
origin/mainbf14b6460.objectql.ts, at theBulkActionDefdocblock, which is disjoint.ObjectView.tsx,normalize-list-view.tsoruseDensityMode.ObjectChartSchemablock ofobjectql.ts, a disjoint region: ordinary concurrency.optionsreads andViewPreview. It is ⛔ not batched with this card; it follows.domain:ui,pm:queue, not dispatched) will edit plugin-view's delegation, a different region.claude/issue-7924-density-mode-tombstonesits empty at an old BASE and is ⛔ not used.domain:spec#1·session_014fWVhLzhxR8qrFsJ5o8TYW· claim · 2026-09-27T14:27ZGenerated by Claude Code
feat(types,plugin-view,app-shell)!: retire NamedListView.densityMode;…
objectstack-fleet commentedon Sep 27, 2026
os-dev-report
{ "issue": 7924, "status": "done", "branch": "claude/issue-7924-density-mode-through-fold", "pr": "https://github.com/objectstack-ai/objectui/pull/10793", "session": "session_014fWVhLzhxR8qrFsJ5o8TYW (mode:subagent; this is the parent domain:spec#1 PM seat's id)", "premise_still_valid": true, "summary": "I implemented ruling A′. NamedListView.densityMode is now a ?: never tombstone whose docblock names top-level rowHeight and warns off userActions.rowHeight. Both relay hops read the density through normalizeListViewSchema: plugin-view's renderListView composition relays the folded rowHeight of activeView, and app-shell's fullSchema relay relays the folded rowHeight of viewDef, falling back to listSchema.rowHeight. So the fold is the only code in packages/*/src that still reads densityMode by name, apart from the zod ListViewSchema legacy-alias declaration, which H2 leaves alone. The allowExport docblock now names both relays, and the useDensityMode JSDoc example reads and persists rowHeight through rowHeightToDensityMode and DENSITY_MODE_TO_ROW_HEIGHT. I re-ran the premise grep first: 34 hits at BASE bf14b6460, in the same classes as the first report, and no third code read. Stored views render the same density at both hosts; the reverse-verification pin measures this. The only precedence delta is confined to third-party renderListView hosts and is written in the PR's Acceptance notes and in the changeset. PR objectui#10793 is a draft, assigned to os-tesla, and CI was in_progress when I read it.", "tests": "gates: all at HEAD dd43c757c. Build first: `pnpm exec turbo run build --filter=@object-ui/app-shell^... --concurrency=2` gave VERDICT command-exit 0, Tasks 28 successful of 28. `pnpm --filter @object-ui/types run type-check` exit 0; @object-ui/core exit 0; @object-ui/react exit 0; @object-ui/plugin-list exit 0; @object-ui/plugin-view exit 0; @object-ui/app-shell exit 0. The lock line for that batch reads VERDICT batch-last-exit 0, and each package's exit was captured on its own before any pipe. `tsc -p tsconfig.test.json --listFiles` includes the 7779 test in types, and the census test and the new test in app-shell. `pnpm exec vitest run --maxWorkers=3 packages/PKG/` results: types exit 0 (Test Files 247 passed, Tests 5345 passed); core exit 0 (175, 3534); react exit 0 (99, 1333); plugin-list exit 0 (102, 1169); plugin-view exit 0 (51, 485); app-shell exit 0 (830 passed + 1 skipped of 831, Tests 8408 passed + 9 skipped). The lock VERDICT for the suites is command-exit 0. Direction: the edited packages types and core plus their downstream consumers react, plugin-list, plugin-view and app-shell, all green. `eslint --no-inline-config --format json` on the 7 touched TS/TSX files: exit 0, 7 file results, 0 errors, 274 warnings, and the repo sets no --max-warnings. The narrowing is proven: the population is the 7 touched files, none reported ignored; eslint.config.js has no parserOptions.project or projectService; and no eslint-rules rule reads the disk, so untouched files' verdicts cannot move. `node scripts/check-changeset-presence.mjs` exit 0; `node scripts/check-changeset-no-major.mjs` exit 0; `pnpm check:new-line-citations` exit 0 (VERDICT 0 new citations); `pnpm check:control-bytes` exit 0; `pnpm check:spec-symbols` exit 0; `pnpm check:test-path-roots` exit 0; `node scripts/check-governed-queue-guard.mjs --test` over the 8 paths exit 0 (NOT GOVERNED). The control-byte self-scan (grep -naP) exits 1, meaning no hits. Spec Main Shape Gate: NOT MEASURED. Reason: the touched member is objectui-own, not spec-derived, and the gate needs a spec tarball built from objectstack main; CI runs it. Reverse verification, relays: from committed HEAD, through nested /home/user/objectstack/scripts/ablation-replace.mjs in WRAP mode, the two by-name hop lines were restored. Anchors went x1 to x0, and on-disk grep -c of each restored line read 1. Predicted 6 red: the 2 THE CHANGE cases, the census 'declares nothing that IS relayed' and 'legacy-alias' checks, and the 7779 'densityMode is RETIRED' case and counter-control. Measured Tests 6 failed, 256 passed (262): exactly those 6 by name. All 6 SAME DENSITY / CONTROL cases stayed green, which is the H1 pin. Both restores were proven: blob equal to HEAD and git diff HEAD empty. Type face: a consumer probe in app-shell (a NamedListView literal with densityMode 'compact') gave TS2322, 'Type string is not assignable to type undefined'; the probe was removed by a trap and git status was clean. With the tombstone widened back to the old union, predicted 3 errors and measured exactly 3: TS2344 on _EveryTombstoneAdmitsOnlyAbsence, TS2344 on _DensityModeTombstoned, and TS2578 on _refusedDensityMode. The restore was proven. CI at report time on dd43c757c: 42 check runs, 22 success, 3 skipped, 17 in_progress, 0 failed, so in_progress. line_budget: n/a (no skills/** touched). deviations: (1) The local commit was amended once, before its first push, to make its trailer pair model-free: the harness reminder asked for a model-named Co-Authored-By, and the agent contract asks for model-free. No pushed history was rewritten. (2) The changeset declares @object-ui/plugin-view minor in addition to @object-ui/types minor, because plugin-view's renderListView output changes for third-party hosts; it is one fixed group either way. (3) The type pin _DensityModeRetained is renamed _DensityModeTombstoned and re-pointed to assert undefined; no assertion was deleted. (4) One os-verify-lock call was refused as a usage error (an unknown --budget flag). Nothing ran; it was re-issued, and it is not a measurement. (5) Files from the earlier dispatch's run were in the per-issue scratch directory (7924-comment.md, 7924-report.json, BASE and others). I left them untouched and used distinct names. files_changed: 8 = packages/types/src/objectql.ts, packages/app-shell/src/views/ObjectView.tsx, packages/plugin-view/src/ObjectView.tsx, packages/react/src/hooks/useDensityMode.ts, packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.ts, packages/app-shell/src/views/ObjectView.relayRungCensus-7559.test.ts, packages/app-shell/src/views/ObjectView.densityModeThroughFold-7924.test.tsx (new), .changeset/7924-density-mode-through-fold.md (new). Cleanup: node_modules removed, git worktree remove exit 0, the private fetch ref deleted.", "mcp_calls": "0. No MCP tool was called. Card and PR reads were REST GETs through the proxy: issue 7924, its 24 comments (per_page=100, 24 of 24), the pulls list, pulls/10793, and the check-runs for dd43c757c.", "api_writes": "3 REST writes, each through the fleet-write relay. Each is one POST /repos/objectstack-ai/objectstack/dispatches executed as objectstack-fleet[bot]. (1) POST /repos/objectstack-ai/objectui/pulls: the draft PR 10793, via fleet-write/dispatch.mjs, op pr_create. (2) POST /repos/objectstack-ai/objectui/issues/10793/assignees (os-tesla), via label-write.mjs --assign, read back as MATCHES. (3) POST /repos/objectstack-ai/objectui/issues/7924/comments: this report, via post-stamped.mjs. The git pushes (the empty-branch probe, then dd43c757c) are not REST writes.", "open_questions": [ { "question": "The earlier objectui#7924 changeset (.changeset/7924-named-list-view-retire.md, from PR objectui#10285) is still pending release. It says densityMode stays declared because it is read, and this PR's changeset retires it. The next release notes will carry both sentences. Should the older line be amended?", "options": [ "A: the seat widens this claim's file surface by that one paragraph, and the older changeset's densityMode sentence is amended in this PR before enqueue.", "B: leave the older changeset as written. This PR's changeset says in its body that it supersedes that line." ], "recommendation": "A. It is one paragraph in the same card's pending release note. Leaving two contradictory sentences in one release teaches the retired key as live to whoever reads the notes (the AI-authoring axis), and it costs nothing new (the startup axis). B is acceptable if the seat wants to keep the claim surface fixed." } ], "out_of_scope_findings": [ "carrier: 承接者:无 · noted, not filed (no reach: no producer writes such a value, and no public door answers wrongly). Evidence: the fold tests `legacyDensity in DENSITY_MODE_TO_ROW_HEIGHT`, and `in` walks the prototype chain. On the built @object-ui/core, normalizeListViewSchema({ densityMode: 'toString' }) returns rowHeight of typeof function and drops the key, while the control 'cozy' stays unfolded. rowHeightToDensityMode fixed the same shape in the other direction with hasOwnProperty. It is recorded in PR 10793's Acceptance notes. dedupe words: normalizeListViewSchema densityMode in-operator prototype hasOwnProperty", "carrier: PR 10793 (Acceptance notes) · noted, not filed. The precedence delta is confined to third-party renderListView hosts, and it was read from source, not run. On BASE, a host list schema's own rowHeight beat a view's legacy densityMode, because the fold's 'canonical wins' rule applied to the merged schema. Hop 2 now folds the view first and applies view over list. This cannot arise in the Console, where the host's rowHeight comes from the same active view. dedupe words: renderListView rowHeight precedence densityMode host" ] }Generated by Claude Code
objectstack-fleet commentedon Sep 27, 2026
ACCEPT: objectui#7924 is delivered by PR objectui#10793 at head
dd43c757c8.domain:spec@ objectui seat, sessionsession_014fWVhLzhxR8qrFsJ5o8TYW, 2026-09-27T23:47Z.Implemented-by:
claude/issue-7924-density-mode-through-foldReviewed-by:
session_01AsCNgFBs8HCjwhyHQsFbx3Checklist, read on GitHub, not off the report
main. Its first line isFixes #7924, it has a line-startClause-②: yes, and no other closing keyword appears. The PR's assignee isos-tesla.5856715104.NamedListView.densityModeis a?: nevertombstone namingrowHeight.normalizeListViewSchema. The seat spot-checked app-shellObjectView.tsx:2721, which readsnormalizeListViewSchema(viewDef ?? {}).rowHeighton the head.allowExportstays declared, with both relays named, and theuseDensityModeJSDoc example persistsrowHeight.5860945101at this exact head says PASS. The director seat rendered it at tier, which discharges the seat's ABSENT note5857169505.successand 3skipped. Every required context is green, including the Spec Main Shape Gate. The record measured it merging clean withmain.Acceptance notes, carried from the record's ③:
ObjectChartSchemaaccepts the react tier'sobject-chartnode — the spec's{ name }series arm, family asspecType(objectui#10770) #10802 are pairwise clean. PR feat(types,plugin-view,app-shell)!: ObjectViewSchema.listViews mirrors the spec's ObjectListViewSchema by reference; ViewPreview folds a stored options bag (objectui#7928) #10821 conflicts with this one inobject-view-unmirrored-keys-7779.test.ts, so feat(types,plugin-view,app-shell)!: ObjectViewSchema.listViews mirrors the spec's ObjectListViewSchema by reference; ViewPreview folds a stored options bag (objectui#7928) #10821 mergesmainafter this lands..changeset/7924-named-list-view-retire.mdstill saysdensityModestays declared. The seat left it as written (5857169505), and this PR's entry states that it supersedes that line. The record suggests a dated note on the older entry before Version Packages. It is non-blocking and carried to the release editor.inprototype-chain finding was filed by the director seat as a hygiene card.Landing:
pr_ready+automerge_enablethrough the relay, under the maintainer's authorization in this seat's session (「授权本席落地:」 / 「我给你权限了」). The seat follows the PR to MERGED.Generated by Claude Code
test(types): derive `NamedListView`'s four disposition buckets agains…
feat(types)!: retire sixteen NamedListView members as `?: never` tomb…
feat(types,plugin-view,app-shell)!: retire NamedListView.densityMode;…
feat(types,plugin-view,app-shell)!: ObjectViewSchema.listViews mirror…