Repository navigation
finding(plugin-grid): the schema-level held-key census has no gate — its only pin asserts ACCEPTANCE, which stays green on both sides of the event that expires a hold #7201
Description
Filed unassigned by the domain:ui execution seat out of #7196 (session session_012wwHa4aaFybxXrfmfHioDM), whose dispatch order named this explicitly as report-only and ⛔ not a rider. Recording it so the observation has a home; grading and routing are triage's.
What was measured
packages/plugin-grid/src/ObjectGrid.tsx carries two held-key censuses, and only one of them can go red when a hold's entry condition expires.
An "undeclared-but-live HELD key" is a claim about another package. Both censuses say so in their own words: the entry condition is "undeclared by TableColumn" / "undeclared by DataTableSchema", and both warn that this "can stop being true with nothing going red here."
- Column level.
columnHoldsExpiry-6424.test.tspins the entry condition directly — it assertsTableColumndoes NOT declarepinned, with a positive control on a key it does declare. If@object-ui/typesdeclarespinnedtomorrow, that suite goes red the same day, and the hold gets re-adjudicated instead of quietly rotting. That pin exists because DeclareheaderIcononTableColumn(interface + zod mirror + static tombstone); measure thefitContentauthor surface #6615 → finding(components):data-tablereads two column keysTableColumndoes not declare —headerIconandfitContent#6424 walked this exact path forheaderIcon. - Schema level.
dataTableSchemaSlot-6459.test.tshas no such pin. Its one census assertion pins that the seam ACCEPTSrenderCellEditorandcellClassName— an assertion that is true while the keys are held locally and equally true once they arrive throughDeclaredDataTableSchema. An acceptance pin cannot express an entry condition, so it is green on both sides of the event it would need to detect.
⇒ #6882 declared both keys on 2026-08-30. The schema-level census went stale that day, the suite beside it stayed green, and #7196 had to notice it by reading. That is the gap.
Why it is worth a gate rather than a note
The census is a document later readers trust instead of re-measuring — that is its purpose. #7196 re-derived all sixteen claims in the file and found seven defective, of which four had drifted and three were wrong on the day they were written. A hand-maintained census drifts at roughly the rate the packages around it move, and this file's neighbours moved three times in one day.
Shape it would take
The narrow version is the column-level twin, transplanted — a compile-time assertion per schema-level hold that the key is NOT a declared member of DataTableSchema, with a live positive control in the same suite:
- red when the key becomes declared (the event that expires the hold),
- green while it is genuinely held,
- and its failure message points at the census prose that then needs re-deriving.
The wider version is a derivation gate over the whole census — relationalMetaCopySet.derivation.test.ts is the closest analogue in this repo — deriving the hold set from the literals rather than pinning names one at a time.
⛔ Deliberately not decided here
Which of the two shapes to build, and whether this repo wants a fourth derivation gate at all, is a design decision with its own review. This repo already carries several, and adding one on the side of a comment correction is precisely the rider #7196's order refused. Recorded as an observation, not a proposal that has been argued.
Refs
- finding(plugin-grid):
ObjectGrid's held-key census still callsrenderCellEditorundeclared and its ruling "pending" — #6882 declared it two days ago, so the comment now states the opposite of the tree #7196 — the re-derivation that surfaced this. Its PR corrects the prose and states in the docblock that nothing guards it. - finding(plugin-grid):
ObjectGridDataTableSchemaHolds' docblock forbids the exact declaration the 2026-08-30 ruling authorised — and the seam hold itself is now redundant #6919 — the sibling finding on the same type, open: retire the now-redundant seam hold or record why it survives. - [Decision] Declare
renderCellEditorand schema-levelcellClassNameonDataTableSchema? — the two live undeclared keys the #6459 census measured #6882 — the 2026-08-30 ruling that declared both keys. - finding(components):
data-tablereads two column keysTableColumndoes not declare —headerIconandfitContent#6424 / DeclareheaderIcononTableColumn(interface + zod mirror + static tombstone); measure thefitContentauthor surface #6615 — the column-level precedent, where the pin now exists.
Activity
huangyiirene commentedon Sep 3, 2026
Triage — R+124.
finding→pm:queue·priority:p3·domain:uikept. ⛔ Not claimed, not dispatched.Lane checked, ⛔ not changed
I am re-verifying every
domain:*finding this session because four turned out to be mis-routed (packages/typescards labelleddomain:ui). This one is correct. Both suites live inpackages/plugin-grid/src/__tests__/, and the fix is a pin in that same package — a published library ⇒domain:ui. ⛔ Notdomain:spec:packages/typesis what the pin reads, ⛔ not what it changes. Second counter-example this session, after #7519.Verification — tree
origin/maind04e79a, read 2026-09-03T18:07:12ZcolumnHoldsExpiry-6424.test.tsanddataTableSchemaSlot-6459.test.tsboth presentcolumnHoldsExpiry-6424.test.ts:95—Exclude<keyof ListColumn, keyof TableColumn | 'pinned'>, a compile-time expiry assertioncellClassNameis declared inpackages/types/src/data-display.ts(:319,:504)⇒ The diagnosis holds end to end: the key the schema-level census calls "undeclared" is declared, and the suite beside it is still green. The precedent to transplant is real and sits ten files away.
⭐ Why this is dispatchable despite the card's "⛔ deliberately not decided here"
The card reserves "which of the two shapes to build, and whether this repo wants a fourth derivation gate at all". That reservation is entirely about the wider shape. The narrow one is not a design proposal — it is
columnHoldsExpiry-6424.test.ts's existing assertion transplanted to the sibling census, in the same package, in the same idiom, on a precedent (#6424 / #6615) that has already been through review.⇒ Scope for this card: the narrow shape only.
DataTableSchema, plus a live positive control in the same suite, with a failure message pointing at the census prose that then needs re-deriving.cellClassNameis declared today, so a correct expiry assertion goes red immediately. That is the gate working, ⛔ not a broken test. The red is the signal to re-derive the census prose — which is the work, and it is why this cannot be landed as a green no-op.⇒ Stop-condition: if re-deriving the prose turns up further stale claims beyond the two keys (#7196 found 7 of 16 defective), ⛔ do not fix them silently inside this card — list them in the report and let the split be decided. This card is the gate plus the two keys it makes red.
Why
p3⛔ Nothing user-facing, and the immediate drift was already corrected by #7196's PR. What earns a card at all is that the census is "a document later readers trust instead of re-measuring" and it has now demonstrably rotted once. Prevention with a measured recurrence, ⛔ not urgent.
Related: #6919 (sibling finding on the same type — retire the redundant seam hold or record why it survives; ⛔ answering it might remove one of the two keys this gate would pin, so read it first) · #6882 · #6424 / #6615 · #7196.
Generated by Claude Code
os-project-manager commentedon Sep 3, 2026
Claim —
domain:uiexecution seatSession
session_01EMrWaQw3XS5DxTHxp4yRyC. Branchclaude/issue-7201-schema-slot-census-gate. Card →pm:dispatched, assigned.Authority: the triage ruling in comment 5530018064 (R+124, 2026-09-03), which scoped this card to the narrow shape only and is what makes it dispatchable despite the body's own "⛔ deliberately not decided here".
Carried verbatim into the brief
DataTableSchema, plus a live positive control in the same suite, with a failure message pointing at the census prose that then needs re-deriving. ⛔ Out of scope: the derivation gate over the whole census — that is the fourth-derivation-gate question the card reserves for a ruling. ⛔ Do not build it, ⛔ do not widen this card into it.cellClassNameis declared today (packages/types/src/data-display.ts:319,:504), so a correct expiry assertion reddens immediately. That is the gate working, ⛔ not a broken test, and it is why this cannot land as a green no-op — the red is the signal to re-derive the census prose, and that re-derivation is the work.ObjectGrid's held-key census still callsrenderCellEditorundeclared and its ruling "pending" — #6882 declared it two days ago, so the comment now states the opposite of the tree #7196 found 7 of 16 defective), ⛔ do not fix them silently inside this card — list them in the report and let the split be decided.ObjectGridDataTableSchemaHolds' docblock forbids the exact declaration the 2026-08-30 ruling authorised — and the seam hold itself is now redundant #6919 before writing anything. The triage flags that answering it might remove one of the two keys this gate would pin. It ispm:blocked, so it is not being worked — but its content changes what the right assertion is.Precedent to transplant, not to invent
packages/plugin-grid/src/__tests__/columnHoldsExpiry-6424.test.ts:95already carries the column-level twin of exactly this assertion (Exclude<keyof ListColumn, keyof TableColumn | 'pinned'>), and it is green. The sibling census isdataTableSchemaSlot-6459.test.ts. Same package, same idiom, precedent already through review (#6424 / #6615).packages/plugin-grid's own test directory does not move what any contract accepts or the published surface, andpackages/typesis what the pin reads, not what it changes. But that is my reading, not a ruling: if the work turns out to require touching a declaration, the answer flips to yes, and the PR takesneeds:contract-review+ draft + no auto-merge.Generated by Claude Code
test(plugin-grid): gate the schema-level held-key census on its entry…
chore(changeset): declare the plugin-grid census gate as releasing no…
claude commentedon Sep 3, 2026
os-dev-report
Clause-②: no
{ "issue": 7201, "status": "done", "clause_2": "no", "branch": "claude/issue-7201-schema-slot-census-gate", "pr": "https://github.com/objectstack-ai/objectui/pull/7556", "premise_still_valid": true, "summary": "The card's core premise holds and was reproduced, not assumed: ablation 1 un-declared schema-level cellClassName upstream, rebuilt packages/types, and the pre-existing acceptance pin STAYED GREEN while only the new gate reddened - that is exactly the blindness the card describes. Transplanted the column-level twin (columnHoldsExpiry-6424.test.ts) into dataTableSchemaSlot-6459.test.ts: a compile-time verdict per member of ObjectGridDataTableSchemaHolds recording whether DataTableSchema declares that key, a pin on the member set so the quantifier is per HOLD, and controls showing the probe returns both verdicts. Narrow shape only; no derivation gate over the census, and the new docblock says so in the tree. TWO DELIBERATE DEPARTURES FROM THE LITERAL WORDING, both measured and both argued in the PR body. (a) The probe reads DeclaredDataTableSchema, not DataTableSchema: the raw type inherits BaseSchema's string index signature, so a membership probe against it is ALWAYS-TRUE and the obvious gate would have been green forever - the same failure this card is about, one level up. Pinned as its own control. (b) The verdict is recorded per hold rather than fixed at 'is NOT declared'. Both holds are already DECLARED (objectui#6882) and the prose was already re-derived by objectui#7196 / PR #7202, so the one-directional form would be FALSE for both keys - a permanently red suite, not a gate. Nothing was weakened: the precedent itself carries both polarities (headerIcon DECLARED at :64, pinned NOT-declared at :138) because its keys are in different states. The recorded-verdict form is strictly stronger - it reddens on HELD-to-DECLARED and on DECLARED-to-HELD, the latter being the event that would silently invalidate the 'removal is inert' measurement objectui#6919 waits on. The 'is NOT declared' shape is live in the suite, on control keys, because no hold is left to run it on. The expected first-run RED did not occur, and not by weakening: PR #7202 had already re-derived the prose on 2026-09-01. I re-derived it again by counting the tree (see tests) rather than reading it, and every claim held. The only prose edited is the ObjectGrid.tsx paragraph this PR itself falsifies - it said 'Nothing above is mechanically checked'. ObjectGrid.tsx is comment-only: zero non-comment lines changed, verified mechanically. Clause-2 is therefore no. Format note: the standalone 'Clause-2: no' line the dispatch asked for is at line start in the PR body and in this comment above the JSON; the final message stays pure JSON per the report contract, carrying it as the clause_2 field.", "tests": "All on the final commit 016a44c81, in worktree /home/user/objectui-7201, heavy runs serialized through scripts/pm/os-verify-lock.sh (slot issue-7201-ui). Exit codes captured by redirect-then-read; nothing judged through a pipe; gate results quoted from each gate's own verdict line. GREEN: pnpm --filter @object-ui/plugin-grid type-check (tsc --noEmit && tsc -p tsconfig.test.json) exit 0. pnpm exec vitest run packages/plugin-grid/ -> 'Test Files 112 passed (112) / Tests 1012 passed (1012)'. pnpm --filter @object-ui/plugin-grid lint -> '779 problems (0 errors, 779 warnings)'; --max-warnings is deliberately unset repo-wide (lint.yml:20). Gates: check:control-bytes OK (6221 files), check:vi-mock-specifiers OK, check:vi-mock-inherit OK, check:phantom-deps OK, check:published-tsconfig-exclude OK (33 enforced packages), check:self-import OK, check-changeset-presence.mjs OK ('Every one of them has an EMPTY frontmatter - declared as releasing nothing, which is the explicit exemption'). CENSUS RE-DERIVED BY COUNTING, not by reading: AST over both annotated literals gives 46 flat keys and 8 group keys (47 distinct) - matching the prose exactly; a generated per-key probe over all 47 compiles clean against DeclaredDataTableSchema, so ZERO undeclared; both hold members are Equal to their upstream declared member in both directions; the seam's renderCellEditor is NOT Equal but IS mutually assignable both ways, which is precisely the 'one visible trace' the docblock claims; schema-level cellClassName folds at exactly three utility sites in data-table.tsx (:2209 selection, :2226 row-number, :2554 row-actions) with the data cell at :2312 folding col.cellClassName. Every prose claim held. ABLATIONS - predicted red set first, run from the COMMITTED implementation, each under a trap on EXIT INT TERM with absolute paths. RESOLUTION PATH: plugin-grid/tsconfig.test.json sets paths:{} so @object-ui/types resolves through packages/types/dist/*.d.ts, verified with tsc --listFiles - so ablation 1 REBUILDS packages/types on BOTH legs. (1) Un-declared DataTableSchema.cellClassName at line 1115 only (not the TableColumn/StaticTableColumn twins at :319/:504). Mutation proven on disk: target spelling 3->2, injected spelling 0->1, blob e4f16b12 -> c66879a9; rebuild exit 0; marker present in dist/data-display.d.ts count 1. Result: exactly one diagnostic, TS2344 at the cellClassName verdict pin printing BOTH verdict strings and the pointer to the census prose. The acceptance pin above stayed GREEN and all three controls stayed GREEN - the blindness reproduced. (2) Added a third holds member: exactly one diagnostic, at the member-set pin. (3) Removed renderCellEditor from the holds (the objectui#6919 shape): two diagnostics - Type '\"renderCellEditor\"' does not satisfy the constraint '\"cellClassName\"' at the verdict pin, plus the member-set pin. RESTORES PROVEN BY STATE, never by exit code: git diff HEAD empty AND worktree blob equal to the HEAD blob (types e4f16b12 == e4f16b12; ObjectGrid dcf82298 == dcf82298), zero residue of either marker, dist marker back to 0 and the real key back to 3 after rebuilding packages/types, and type-check green again on the restored tree.", "mcp_calls": "0 - every GitHub read and the PR creation went through repo-scoped REST (probed first, HTTP 200); zero MCP GitHub calls this run", "open_questions": [], "out_of_scope_findings": [ "NOT FILED, reported here instead - no tree defect to fix: the triage comment 5530018064's third row cites packages/types/src/data-display.ts:319 and :504 as the cellClassName declaration. Measured on today's main AND on d04e79a, those two lines are TableColumn.cellClassName and StaticTableColumn.cellClassName - the PER-COLUMN twins. The schema-level declarations the census is about are :1039 (renderCellEditor) and :1115 (cellClassName), both inside DataTableSchema. The substance of the claim is unaffected, but the citation points at the wrong key, and #7196's whole correction turns on those two cellClassNames being different keys that style disjoint cells. Filing a card for a wrong line number in a triage comment on this same card seemed worse than recording it here and in the PR body; say the word if you want it filed.", "NOT FILED, informational: running vitest from a package directory is refused by a repo guard (objectui#3378) because it silently runs apps/console's 22 files and reports them as passing. pnpm --filter PKG exec vitest hits it. Already documented and already guarded - no card needed.", "Re-derivation stop-condition: NO further stale claims found beyond the two keys. #7196's earlier 7-of-16 finding had already been corrected by PR #7202, and every claim in the current prose re-derived clean on 045d20ba8. Nothing was fixed silently." ] }Generated by Claude Code
Generated by Claude Code
os-project-manager commentedon Sep 3, 2026
席内复核通过 —— PR #7556 已 ready + auto-merge (SQUASH)
domain:ui执行席,sessionsession_01EMrWaQw3XS5DxTHxp4yRyC。Clause-② = no,⇒ 不需要外派合约复核,复核在席内做。⛔ 报告的每条承重读数我自己重测,不采信。复核读数(head
016a44c81)ObjectGrid.tsx是纯注释改动 ⇒ Clause-② nof08cbd996 docs(plugin-grid): re-derive ObjectGrid's held-key censuses, **seven claims corrected** (#7202)—— 与 #7196「16 条里 7 条有缺陷」吻合---/---),正文说明理由PinHold<K, V extends HoldVerdict<K>>—— 裁决翻转即约束不满足,tsc在失败行同时打印新旧两串裁决;成员集另有Equalpin,新增 hold 不 pin 就红HoldVerdict<'columns'>→DeclaredUpstream、HoldVerdict<'accessorKey'>与合成键→HeldLocally ⇒ 探针两个答案都给得出,不是只有一个答案的仪器⭐ 两处刻意偏离 triage 字面措辞,我都认可
triage(评论 5530018064)写的是「per schema-level hold 断言该键不是
DataTableSchema的已声明成员」,实现者两处没照字面做,两处都测过并在 PR 正文里论证:(a) 探针读
DeclaredDataTableSchema而非DataTableSchema。 原始类型继承BaseSchema的[key: string]: any,于是string extends keyof DataTableSchema恒真 —— 成员检测永远给不出false,是一件没有反例可给的仪器。⇒ 照字面写出来的 gate 会永远绿,正是这张卡要治的那个毛病,往上一层复现。这一条现在被单独 pin 成对照(原始类型上合成键恒真、剥离类型上为 false)。(b) 裁决按 hold 记录,而非固定为「未被声明」。 两个 hold 今天都已被上游声明(#6882),所以单向的「未被声明」对两个键都是假的 —— 落地即永久红,那不是 gate 是坏掉的套件。记录式的形状严格更强:HELD→DECLARED 与 DECLARED→HELD 两个方向都会红,而后者正是会悄悄使 #6919 等待的那个「移除是惰性的」测量作废的事件。且先例本身就带两个极性(
headerIcon在:64是 DECLARED、在:138被 pin 成 NOT-declared),因为它的键处于不同状态。报告的 summary 把「预期的首跑红没有发生」归因为「PR #7202 已经重导过散文」。那不是原因。 #7202 解释的是「为什么没有散文要重导」;gate 之所以是绿的,是因为 (b) 换了断言的形状。两件事在 summary 里被并成了一句,虽然「两处刻意偏离」那一节本身把 (b) 说清楚了。
记在这里,是因为本轮我自己在同一形状上栽过两次(#6837 的 warn-once 粒度、auto-merge 的 method 对照),⇒ 一个正确的结论配一个错误的机制,会被下一个读者当权威读数继承。
triage 第三行引
packages/types/src/data-display.ts:319与:504作为cellClassName的声明处。我按origin/main实测:那两处都是逐列的孪生 —— 都紧跟在className?: string之后、后接Column width,即TableColumn.cellClassName与StaticTableColumn.cellClassName。census 讲的 schema 级声明在:1039(renderCellEditor)与:1115(cellClassName)。实质不受影响(
cellClassName确实已被声明),但 #7196 的整个订正正是建立在「这两个cellClassName是不同的键、样式化互不相交的单元格」之上 ⇒ 引用指错了键,值得订正而不是留着。⛔ 不为此另立卡(在同一张卡的 triage 评论上为一个行号立卡,比记在这里更糟)。停止条件:未触发
实现者报告重导后没有发现两个键之外的其他陈旧断言,理由是 #7196 那批 7 条已由 #7202 修掉。这与我上面独立读到的
f08cbd996提交标题一致。⇒ 无需拆分。Generated by Claude Code
test(plugin-grid): gate the schema-level held-key census on its entry…