…#7924)
Re-derive both halves of the `listViews` measurement on today's head and pin
them per member, replacing the regex instruments with the TypeScript parser.
- declared set: walked with `ts.createSourceFile` over the interface's own
`PropertySignature` members, not a regex and not a brace-depth count. The two
regexes are kept and asserted against the parser, so the instrument swap is
itself a reading: strict regex 47 = parser 47, loose regex 59.
- read set: derived through every route from `schema.listViews` to a named
view, with every occurrence of that record classified. A new route fails as
UNCLASSIFIED instead of silently shrinking the reading. This found a
named-view read the old `currentNamedViewConfig?.KEY` regex cannot see —
`{view.label || key}` on the tab strip.
- each of the 47 members is pinned by name on its side of the partition
(6 read, 41 unread), so a member moving between the sets fails in either
direction; `data` stays read-but-undeclared, reached via an `as any` cast.
A member reached through `activeView?.KEY` — the host's `views` prop — is not
read off the named view; `rowHeight: activeView?.rowHeight` is the pinned
counter-control.
Measurement only: no declaration face moved and no renderer read set moved.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jmxdo7bmeqCQHLSfmLVX9w
Refs #7924 — this PR lands the census only and decides nothing. The two dispositions the card names for the unread members (
?: nevertombstones per the objectui#7129 route, or making the delegation read them from the named view) are maintainer rulings and stay with objectui#7928. ⛔ No declaration face moved:packages/types/src/objectql.ts, every*.zod.tsand every renderer read set are byte-identical tomainin this diff, which touches one test file and one changeset.Why none of the card's figures are quoted
The card body says "about 52 members" / "exactly seven read" / "~45", measured on
6a9ee323. Every figure below is re-derived on this branch's head (3b5053d45). The reading is 47 declared, 6 declared-and-read, 41 unread, plus one read-but-undeclared key. "About 52" reproduces only as a hand figure sitting between two instruments and is neither of them — the instrument table below pins that gap as an assertion rather than a sentence.The census
NamedListView(packages/types/src/objectql.ts:2025–:2202today — re-located by AST, not by the card's stale line numbers) declares 47 top-level members. Theobject-viewnode renderer reads 7 names off a named view; 6 of them are declared members.activeView?.KEY— the host'sviewsprop — is not read off the named view. It is included because it is what the ruling needs: it separates "unread here" from "unread anywhere".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?.dataTotals: 47 declared = 6 read + 41 unread. Read set off the named view = 7 names (the 6 above plus the undeclared
data)."fold only" means the member has no⚠️ Worth stating because a named-property probe alone reports those four as having no reader at all, which is false — and that mistake would have gone straight into the ruling.
activeView?.KEYaccess, but IS consumed when it appears onactiveView, throughnormalizeListViewSchema(activeView)(packages/core/src/utils/normalize-list-view.ts, itsSHOW_FLAG_TO_USER_ACTIONmap).Three readings the ruling request should carry
datais still read-but-undeclared. It reaches the renderer asdata: (currentNamedViewConfig as any)?.data ?? …. objectui#7928 requires it to be declared or its cast removed and names this card as its home; it is still neither. It is why the arithmetic subtracts six, not seven, from 47.activeView; 4 more are folded fromactiveView; 3 have no reader on any path —description,exportOptions,bulkActionDefs. Of those,exportOptionsandbulkActionDefsdo not appear in the renderer at all (pinned), anddescriptionappears only offschema/schema.table/schema.form, never off a view.labelis the only required member, and it is read — so a tombstone route would leave the sole required member intact.Instruments, and the control that makes each zero a reading
namedListViewMembers()(new)ts.createSourceFile, the interface's ownPropertySignaturemembersnamedListViewMemberCount()(kept)namedListViewLooseMemberCount()(new)⛔ Not a brace-depth count: a brace parser on this repo has already failed to terminate at the end of an object literal (objectui#8071). The three are now pinned against each other, so the instrument swap is itself a measurement and "52 is between two instruments and is neither" stops being prose.
The read set is derived by walking every route from
schema.listViewsto a named view — a binding annotatedNamedListView; the value binding ofObject.entries(record).map(...)(through an intermediateconst entries = …too); and element access straight off the record — stripping( ),!andas anyat each access, which is the only reasondatais visible at all.⭐ That walk found a named-view read the old
currentNamedViewConfig?.KEYregex cannot see:{view.label || key}on the named-view tab strip.labelis read at two sites, and the count is asserted.Completeness, not just coverage: every occurrence of the record binding is classified into a role (
DECLARATION,ELEMENT_ACCESS,OBJECT_KEYS,OBJECT_ENTRIES,COMPARISON,CONDITION,HOOK_DEPENDENCY). A new syntactic route lands asUNCLASSIFIEDand fails before the census can silently under-count — the test says in its own message not to add the role to make it green.Firing controls (a silent probe is a parser that found nothing, not a reading of zero):
columns— asserted present in both the declared set and the read set;rowHeightis asserted declared and not read off the named view, withrowHeight: activeView?.rowHeight,pinned as the text that makes it so;stickyHeader, in neither set, is non-vacuity for both probes at once;grepthat finds nothing for them is asserted to findrowHeight.Ablation — the pin is non-vacuous in both directions
Each leg: mutation proven on disk before any result was read (anchor counts on both the removed and the injected text, plus a
git hash-objectdiffering from the HEAD blob), restore from atrap … EXIT INT TERMusinggit checkout HEAD -- ABSOLUTE_PATH, restoration proven by blob hash, never by an exit code. HEAD blob ofObjectView.tsx=c1a807af683a0147796780c801ac34ffa97e8c70.Leg A — unread becomes read.
navigation: activeView?.navigation ?? …rewritten to read the named view first. Removed-text count 1 to 0, injected 0 to 1, blobc1a807aftofdfe41ac. Result: 4 failed / 143 passed, and the only per-member row that moved is the expected one:UNREAD — navigation is declared and NOT read off a named view⇒ red6 read + 41 unread = 47partition ⇒ redLeg B — read becomes unread. The
currentNamedViewConfig?.typeread deleted. Blobc1a807aftoc9e79701. Result: 4 failed / 143 passed:READ — type is declared AND read off a named view⇒ redif (activeView?.type) return activeView.type;) already existed on the next line, so the on-disk proof read injected-count 2, expected 1, and the script aborted withexit 94before running anything and restored the file. The reading was void, not green. Re-anchored on a unique marker and re-run; both blob hashes above are from the run that actually happened.Restoration verified after every leg:
git hash-objectback toc1a807af683a0147796780c801ac34ffa97e8c70andgit diff HEADempty for that path.Readings — commands and exit codes
Exit codes captured into a file before any pipe (
cmd > out 2>&1; RC=$?), never off the end of a pipeline.pnpm exec vitest run packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.tsTest Files 1 passed (1)·Tests 147 passed (147)pnpm --filter @object-ui/types type-checktsc --noEmit,tsconfig.examples.json,tsconfig.test.jsonechoed and green — the test file is typecheckedpnpm exec eslint packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.tsnode scripts/check-changeset-presence.mjsnode scripts/check-changeset-no-major.mjsmajorpnpm check:control-bytespnpm check:phantom-depstypescriptis already a declared devDependency of@object-ui/typesnode scripts/check-governed-queue-guard.mjs --test(both changed paths)NOT GOVERNED— 2 paths, no governed surface matchedAll test runs went through the container's shared heavy-verify lock; each printed
VERDICT command-exit 0.Declared narrowing. Repo-wide
pnpm lintandpnpm testare CI's runs, not this seat's. The lint reading above is narrowed to the one changed file;eslint.config.jsconfigures no type-aware linting (noproject/projectService), so this diff cannot move the verdict on any file it does not touch. Test scope is the single pin file because the diff changes exactly that file plus a changeset, and no published byte moves.Scope
⛔ The three live branches' files were not touched:
packages/types/src/complex.ts/plugin-kanban/plugin-gantt(PR #8865),packages/types/src/layout.ts/page-breadcrumbs-refusal-8871.test.ts(PR #8930),registry-inputs-spec-parity.test.ts/plugin-calendar(PR #8872).The census extends the existing pin rather than adding a file. That file already owned both halves of this measurement (the 47 count and the seven-name read set) and is where the regex instrument being improved on lives; a second file would create a second instrument for the same number, which is the staleness shape objectui#7947 was filed about. The header's prose figures are now backed by the assertions underneath them.
⛔ This PR stays draft — the PM lands it. The card is not closed by it: the disposition is still unruled.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Jmxdo7bmeqCQHLSfmLVX9w
Generated by Claude Code
Generated by Claude Code