Repository navigation
finding(types): zod-mirror-parity's header says KnownDrift holds 62 keys; two instruments measure 63 — wrong since objectui#7664, and the sibling half of #7733 #8222
Description
Filed by the dev seat implementing #7733 (branch claude/pin-zod-mirror-parity-ledger-counts-7733), unassigned and unlabelled — grading and domain:* are triage's. Out of #7733's scope by that card's own boundary, so it is reported rather than repaired.
The number
packages/types/src/__tests__/zod-mirror-parity.test.ts, population section, the KnownDrift bullet:
- **41 entries** in KnownDrift, **62 keys** across them — 42 / 63 until objectui#7542 REPAIRED …
| quantity | prose | measured on ecf8e726e |
|---|---|---|
KnownDrift entries |
41 | 41 ✅ |
KnownDrift keys |
62 | 63 ❌ |
The entry count is right; the key total beside it is one low. The file is fully green with it, exactly the way #7733's restatement site was.
Two instruments, and the positive control that says they are not blind
- A TypeScript AST walk: for each
PropertySignaturein theKnownDriftinterface, count the arms of its string-literal union. - A line-oriented parse of the same interface body, comments stripped, entries split on
;.
Both read 41 entries / 63 keys.
⭐ Control — the same two instruments read UnmirroredDeclared as 14 / 87 and RuntimeOnlyDeclared as 7 / 24, and both agree with the prose beside them. The UnmirroredDeclared figure is stronger than agreement: the file's OWN pin (the split figures and the totals the header writes down equal the ledger, objectui#7279) derives that key total with the same union-arm semantics through ledgerEntryMembers() and is green. ⇒ the semantics being used here are the semantics the file already treats as authoritative, and the reading of 63 is a reading, not a different definition of "key".
When it rotted (bisected, not assumed)
Running the line-oriented instrument over the file at each commit that touched it since objectui#7542:
| commit | measured KnownDrift |
prose |
|---|---|---|
2fcefb955 (objectui#7542) |
41 entries / 62 keys | 62 ✅ |
2af1fa7c0 (objectui#7664) |
41 entries / 63 keys | 62 ❌ |
6bca0e4e8 · 5b5a5c3a3 · 15789d565 · ecf8e726e |
41 / 63 | 62 ❌ |
⇒ objectui#7664 (the kanban dialect card) moved the key total and not the sentence. The entry count did not move across that commit, which is why the figure that did move had nothing looking at it.
Why the #7733 PR does not fix it
#7733's card body and its triage comment 5557456510 both draw the same boundary in the same words — "a number nobody measured gets no verdict from it", and (triage) "⛔ 不要顺手钉键总数(62 / 87 / 24)…若要做,先测,再单独立案". This is that separate filing: measured first, then filed, and neither the digit nor a pin for it was touched in the PR for #7733.
Suggested remedy (one change, both halves)
⛔ Not route 1. Correcting 62 to 63 alone is the move this file's whole history is a record of, and #7733's pin exists because it kept recurring.
Both instruments are already in the file and neither is new work:
ledgerEntryMembers()already sizes a ledger in keys. Its parameter type is'UnmirroredDeclared' | 'RuntimeOnlyDeclared'today; widening it to include'KnownDrift'is the whole mechanical change.headerFigures()already reads one figure off the header's own spelling, so a rewording that drops the digit is red rather than quietly unpinned.
⇒ correct the digit and add the key total to a pin in the same PR, and prove the pin fires by mutating the ledger.
The rest of the unpinned figures in that header, for whoever picks this up
Measured on ecf8e726e by the same instruments, stated as readings and nothing more:
RuntimeOnlyDeclared24 keys — correct today, pinned by nothing.- "the union of the two unmirrored ledgers is 15 pairs and not 14" — correct today (union measures 15;
TreeViewSchemais the one member ofRuntimeOnlyDeclaredoutsideUnmirroredDeclared), pinned by nothing. The census derives that union at runtime already, so pinning it is one line. UnmirroredDeclaredentries and keys — already pinned (objectui#7279), no action.- The three
KnownDrift/UnmirroredDeclared/RuntimeOnlyDeclaredentry counts and the ratchet restatement — pinned by the PR for finding(types): zod-mirror-parity's three LEDGER entry counts are still hand-written prose — the half of #6141 that #7433's scope deliberately left behind #7733.
Duplicate check
GET /search/issues returns 403 for this session, so this ran as one targeted MCP search_issues (channel switch declared): 11 results, incomplete_results: false. The control fired: #7733 itself came back on-topic, so a session-level search failure is excluded. The near ones and why none is this card: #6141 (closed — pairs and ledger ENTRIES, not key totals), #7433 (closed — the population count), #7733 (this seat's card — entry counts, key totals explicitly excluded), #6152 / #6058 / #5927 / #7759 / #6033 (the drift populations themselves, not the header's arithmetic about them), #5684 / #5853 / #7069 (guard coverage). None is a live card for a key total in this header.
Refs: #7733 (the entry-count half, in flight) · #7433 · #6141 · objectui#7664 (the commit that moved the figure) · objectui#7279 (the pin whose instrument the remedy reuses).
Generated by Claude Code
Activity
claude commentedon Sep 7, 2026
os-dev-report
{ "issue": 8222, "status": "done", "branch": "claude/pin-zod-mirror-parity-key-totals-8222", "pr": "https://github.com/objectstack-ai/objectui/pull/8242", "premise_still_valid": true, "summary": "The card's premise holds and was re-derived, not inherited: two independent instruments (a TypeScript AST walk over each ledger interface and a line-oriented parse of the same block) read KnownDrift 41 / 63 where the header said 62, and the bisection was reproduced by running the walk at each commit — 2fcefb955 reads 62 (prose 62 correct), 2af1fa7c0 reads 63 (prose 62 wrong). The digit is corrected AND pinned in the same PR, and the whole header is closed rather than just that digit. I enumerated every numeral in the header (38 lines carry one) and separated LIVE figures — those describing the file as it is now — from historical readings at a named past revision, which cannot rot. Thirteen live figures: 5 were already pinned (#7733 x4, #7279 x1, one of them by both), 1 was wrong, 6 more were unpinned, and 1 cannot be pinned. All six unpinned ones are now pinned; the last is explicitly excluded in writing with its reason. FOUR LIVE FIGURES #8222's OWN TABLE MISSED, reported as the card asked: (a) 'Six of the seven are a subset of the 14 pairs above' carries three of them — the 6 (a quantity of its own), a second site for the RuntimeOnlyDeclared entry count and a third for the UnmirroredDeclared one; the first two were spelled as ENGLISH WORDS, which is the mechanical reason no instrument had ever read them. (b) 'and not 14' is a fourth site for the UnmirroredDeclared entry count. (c) The seed decomposition '95 + 1 mirrored + 2 retired + 23 reclassified' was STALE and is the one figure nothing here can pin: every term but the last needs each key's provenance, which no ledger in this file records. It is excluded rather than refreshed — a fresh digit would rot again — and the header defers to the ledger paragraph that owns the statement, which it already did in its last sentence. Implementation is the mechanical change the card named: ledgerEntryMembers() gains one union arm ('KnownDrift'), no new instrument, and NO new constant — an EXPECTED_KNOWN_DRIFT_KEYS would be a third site for the number. The KnownDrift history chain also gains the #7664 step it was missing; without it the chain's arithmetic ('42 / 63 until #7542 repaired one entry, one key') no longer reaches the current figure. UnmirroredDeclared's 87 keys stay pinned by #7279 alone, noted in a comment so it is not 'cleaned up' as missing, and #7733's trailing caveat saying the key totals were unpinned is updated.", "tests": "DIST LEG: none, and established before any result was claimed. Every new assertion's subject is this test file's OWN SOURCE — ledgerEntryKeys, ledgerEntryMembers and headerFigures are defined in the file and all three read SELF (fileURLToPath(import.meta.url)) with readFileSync; nothing they assert travels through a package exports map or a built barrel, so the mutation target IS the file under test. This is the #8224 case, not the #8226 one. No rebuild leg exists to prove, and none is claimed. ABLATION, 6 legs, implementation COMMITTED FIRST so the restore leg had a real reference; harness carried trap on EXIT INT TERM with absolute paths from git rev-parse --show-toplevel. Each leg: mutate -> prove the mutation landed on disk (injected-text grep count >= 1 AND removed-text grep count = 0 AND git hash-object differing from the HEAD blob; a leg that failed any of the three would abort as VOID) -> run -> restore with 'git checkout HEAD -- PATH' (never bare --, which reads the polluted index) -> prove the restore BY STATE (git hash-object == HEAD blob 616af4a46 AND git diff HEAD zero lines). All six restores verified by state; none by an exit code. Leg 0 baseline: 23/23 green, both new tests named in the verbose reporter. Leg 1 (THE DECISIVE ONE, the #7664 shape — a KnownDrift entry's union gains one arm, so a KEY moves and the ENTRY count does not): #8222 row knownDriftKeys RED (expected 64 derived vs 63 spelled), #7733 entry-count row GREEN. That is the leg proving the new pin covers what actually broke rather than a correlated figure. Leg 2 (a whole KnownDrift entry removed): BOTH blocks RED — they are independent in the other direction too. Leg 3 (a RuntimeOnlyDeclared entry's union gains one arm): #8222 runtimeOnlyKeys RED, #7733 GREEN. Leg 4 (a RuntimeOnlyDeclared entry re-keyed onto a pair already in UnmirroredDeclared — the UNION moves while no entry count and no key total moves): #8222 RED on unionOfUnmirroredLedgers 14 vs 15 and runtimeOnlyAlsoUnmirrored 7 vs 6, AND the new nesting non-vacuity control fired; #7733 GREEN; the #7433 census stayed green because both its derivations moved together, which is the isolation working. Leg 5 (the header digit alone, **63 keys** -> **64 keys**): #8222 RED, #7733 GREEN — the pin reads the prose, not a constant. GATES, union run AFTER the final commit at 37f72d274: 'pnpm exec vitest run --project unit packages/types/src/__tests__' -> 'Test Files 136 passed (136) / Tests 2560 passed (2560)' (main was 2558; this adds 2). 'pnpm --filter @object-ui/types run type-check' -> lock VERDICT command-exit 0; the script echoed '> tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json', so not a zero-match silent pass. --listFiles FOUND THE TRAP and it is reported rather than glossed: 'tsc --noEmit' alone has ZERO hits for zod-mirror-parity.test.ts (120 files, tests excluded) — that leg says nothing about this change; 'tsc -p tsconfig.test.json' has the file in its program (441 files) and exits 0, and that is the leg that covers it. 'pnpm --filter @object-ui/types run lint' (eslint .) -> 0 errors, 272 pre-existing warnings, ZERO in the edited file. 'node scripts/check-control-bytes.mjs' -> exit 0 (6558 tracked text files), plus a direct grep -naP control-byte scan over the edited file and the changeset. 'node scripts/check-changeset-presence.mjs' -> exit 0, empty-frontmatter changeset (the explicit exemption for a test-only change; the objectui skip-changeset label was NOT applied — wrong repo for it). Every exit code was captured by redirecting first (cmd > file 2>&1; EXIT=$?), never through a pipe, and every locked run is quoted from the os-verify-lock VERDICT line rather than a bare $?. All heavy runs went through scripts/pm/os-verify-lock.sh with a stable slot (waits: 246s, 0s, 0s, 0s). DECLARED NARROWING: the repo-wide 'pnpm lint' / 'pnpm test' farms were not run locally — CI runs them exactly once anyway. The narrowing is bounded by evidence, not assumed: eslint.config.js configures NO type-aware linting (no parserOptions.project / projectService), so this diff cannot move the verdict on any untouched file; and git grep over scripts/ and .github/ finds NO check:* script naming this file or any of its ledgers. GOVERNED_SURFACES (AGENTS.md, CLAUDE.md, .claude/**, skills/**, docs/adr/**) is untouched.", "mcp_calls": "0 — the session's repo-scoped REST gate probed OPEN (GET /repos/objectstack-ai/objectui/issues/8222 -> 200), so every read and write (issue + comments, PR 8224 as a template, the dedup listing, opening the draft PR, filing #8243, this comment) went through container curl on the REST channel. No MCP GitHub call was made.", "open_questions": [], "out_of_scope_findings": [ "filed as #8243: zod-mirror-parity.test.ts's two LEDGER DOCSTRINGS (above interface UnmirroredDeclared and above interface RuntimeOnlyDeclared) both say that ledger 'records 94' keys where two instruments measure 87 — unmoved since objectui#7779 took it 96 -> 87, and outside every pin in the file including #7279's and this PR's. Out of #8222's scope by its own boundary (the header), and the decomposition beside the 94 is not mechanical, so it is filed rather than repaired under the bounded-in-place exemption. I measured the harder half for whoever picks it up: at beccf1c6b (oldest revision of the file in this shallow checkout) the ledger holds 98 keys — exactly the docstring's own '121 became 98' figure, which is the positive control — of which 85 survive into today's 87 and 13 have left, so the true shape is 87 - 2 seeded + 10 mirrored + 3 retired + 23 reclassified = 121. The 13 is MEASURED; the 10/3 split is prose-derived and reported as unmeasured." ] }Generated by Claude Code
test(types): re-derive and pin the WIDER ledger's #7760 pairs figure,…
test(types): re-derive and pin the WIDER ledger's #7760 pairs figure,…
test(types): re-derive and pin the WIDER ledger's objectstack-ai#7760 …
fix(types): settle FilterField.operators, Container.maxWidth and Head…
feat(types): ObjectGridSchema's zod mirror declares ten members its T…
feat(types)!: retire object-grid's resizableColumns on both faces and…