Repository navigation
feat(types,plugin-view,app-shell)!: retire NamedListView.densityMode; both relays read the density through the fold (objectui#7924) - #10793
Conversation
… both relays read density through the fold (objectui#7924) Ruling A-prime on objectui#7924: `NamedListView.densityMode` becomes a `?: never` tombstone naming top-level `rowHeight`. The plugin-view `renderListView` composition and the app-shell object-page relay both hand the active view to `normalizeListViewSchema` and relay its `rowHeight`, so the fold is the only code left that reads the retired key by name. Stored views that still carry `densityMode` render the same density. `allowExport` stays declared; its docblock names both relays. The `useDensityMode` JSDoc example reads and persists `rowHeight`. Pins: the objectui#7779/#7924 census re-points `_DensityModeRetained` to the tombstone and adds the refusal; the app-shell relay census files `densityMode` as `legacy-alias` of `rowHeight`; a new end-to-end pin mounts the real plugin-view under the object page. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014fWVhLzhxR8qrFsJ5o8TYW
|
changeset-claim-re-read
|
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
|
Contract review ABSENT at head
Generated by Claude Code |
Contract reviewServed-tier: ① Derived judgmentsDiff read three-dot against objectui
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Rendered at tier by the director seat (summon #30 续 2) on the fetched head. Not a governed path; the landing pre-checks are met (fresh PASS, CI green, no conflict with Generated by Claude Code |
…hart-series claims PRs #10793, #10802 and #10821 made false Each false sentence gets a dated supersession note beside it, in the objectui#10533 / objectui#10801 form, naming the superseding entry by file and pull request. Frontmatter is byte-identical and no line is deleted; the still-true sentences, and all of the objectui#8086 entry, are untouched. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014fWVhLzhxR8qrFsJ5o8TYW
…ts name fourteen objectui issues that answer 404 (objectui#10803) (objectstack-ai#10854) Part of objectstack-ai#10803 Clause-②: no Dispatched implementation of the `domain:ui` seat objectstack-ai#1 claim (comment `5859894652`) on objectui#10803, session `https://claude.ai/code/session_01DuWo5bdP9SdVebamn99GGk`. Citations only: no sentence's claim moves and every edited pending changeset's frontmatter is byte-identical. The only code tokens that move are eleven zod `.describe()` strings in `@object-ui/types`, each losing its dead pointer (patch round, under the seat's claim amendment `5860244997`). ## Why `Part of`, not a closing line The enumeration pin for the fourteen now reads 0. The card stays open because the seat's amendment `5860244997` (Q2) keeps the 115-number remainder of the family on it, to be carried by later PRs after this one lands (see **Acceptance notes**). ## Premise, re-measured - REST `GET /repos/objectstack-ai/objectui/issues/N` and `/pulls/N`: all fourteen (objectstack-ai#5489, objectstack-ai#5498, objectstack-ai#5853, objectstack-ai#6938, objectstack-ai#6939, objectstack-ai#6950, objectstack-ai#7070, objectstack-ai#7071, objectstack-ai#7628, objectstack-ai#7632, objectstack-ai#7635, objectstack-ai#7688, objectstack-ai#9318, objectstack-ai#9473) answer 404 on both. Lit controls: objectui#10533 and objectui#7714 answer 200. - The same fourteen in objectstack all answer 200. Thirteen are unrelated subjects. objectstack#6938 IS the `bodyShape` forwarding subject, and the seven in-scope lines that name it already spell `objectstack#6938`: live citations, which the card's instrument counted because its bare `#` branch matches inside `objectstack#6938`. They are untouched. No objectui site here is a mis-attributed objectstack number, so no site is re-qualified. - Pending means pending: no `CHANGELOG.md` names any of the fourteen (42 changelogs; control: `packages/core/CHANGELOG.md` carries 140 `objectui#` mentions), so all 47 changesets edited here are pending. - Base: `195052fff` (origin/main at dispatch; it carries the four PRs the deferral waited on). The census there reads the card's own numbers, below. ## Census (the enumeration pin) The pin is this re-count, as PR objectui#10797 recorded its own. The instrument, reproducible as printed (REF = a commit): ``` git grep -nE '(objectui#|#|issues/)(5489|5498|5853|6938|6939|6950|7070|7071|7628|7632|7635|7688|9318|9473)([^0-9]|$)' REF -- '.changeset/*.md' 'packages/*/src/**' ':!**/__tests__/**' ':!**/*.test.*' ':!**/*.spec.*' ':!**/test/**' ':!**/tests/**' | grep -v 'objectstack#' | wc -l ``` - REF = `195052fff`: **224** lines, 66 changeset lines in 47 files and 158 src-nontest lines in 48 files. - REF = `4906c4408` (this head): **0** lines. Round 1's head `6c3ad7c80` read 11, every one a `.describe(` line; patch round 1 (`19da7f8c0`) took them, and it read 0. - This head merged with `main` at `4aebea00a` (`git merge-tree`, clean): 0. - Lit control, the same printed instrument over live objectui#7714 at this head: 17 lines (20 without the `grep -v 'objectstack#'` filter, because three of those lines also name an `objectstack#` number). Hex-colour false positives (the pattern followed by a hex letter): 0. - The card's own instrument (no `objectstack#` filter) reads 67 changeset lines in 48 files and 164 src-nontest lines in 54 files at the base, the card's figures exactly; the extra 1 and 6 are the `objectstack#6938` lines. At this head it reads 1 and 6: those 7, all live. - Out of scope, as it stands (card's instrument, unchanged by this PR): 223 test lines in 80 files, 6 scripts lines in 2 files, 1 `.github` line, 0 governed, 6 other lines in 6 files. ## Citation form - The 9-character backticked sha of the commit on `main` that landed the change the sentence rests on (the objectui#10707 / objectstack-ai#10766 / objectstack-ai#10797 form). Commits, not PRs: PR 7628, PR 7660 (the objectstack-ai#7632 landing) and PR 5530 (the objectstack-ai#5498 landing) answer 404 themselves. All 20 shas are ancestors of the base (`git merge-base --is-ancestor`, exit 0 each; control leg: the head of PR objectui#10851 answers exit 1) and `git rev-parse --short=9` returns the same 9 characters for each. - A changeset's pointer to its OWN card is dropped, not replaced: `@changesets/changelog-git` prefixes each released entry with the hash of the commit that added the file, which is that landing. - Where the sentence cites a RULING recorded on a dead card and no single commit is the ruling, the ruling is cited by its date, the form the same sentences already use: "the 2026-09-02 ruling" for the eight-group ruling on objectstack-ai#6939, "the 2026-09-01 ruling (总监批 objectstack-ai#28)" for the one on objectstack-ai#7070. - Inside a zod `.describe()` string the dead pointer is dropped, not replaced, in the PR objectui#10707 shape: a reader of a runtime description has no repository to resolve a sha against. - Where the sentence says something was reported to a dead card, the live successor card that carried it is named (objectui#7561, objectui#7562). ## Number to resolution | dead number | resolution | evidence | |:--|:--|:--| | objectstack-ai#5489 | `78cbdb530` | "retire ThemeComponentSchema, the `type: 'theme'` component kind no renderer implements (objectstack-ai#5489)"; it added `retire-theme-component-schema-5489.md`. | | objectstack-ai#5498 | `4bb940b6e` | "Readonly markdown/html/richtext form fields render formatted, not their markup source (objectstack-ai#5498)"; it added `readonly-richtext-raw-markup-5498.md` and moved the renderers into `widgets/richTextDisplay.tsx`. PR 5530 answers 404. | | objectstack-ai#5853 | `fc62bb490` | "make the 8-literal union the one canonical TableColumn.type" (PR 6370); it added `5853-tablecolumn-type-canonical-union.md`, `TABLE_COLUMN_TYPES` and `normalizeTableColumnType`, citing the 2026-08-25 Option B ruling. | | objectstack-ai#6938 | `b74a8598d` | "declare `wrapperClass` on `CheckboxSchema`, on both faces" (PR 7723); it added `6938-checkbox-wrapper-class.md` and `checkbox-wrapper-class-6938.test.ts`. The `objectstack#6938` sites are live and untouched. | | objectstack-ai#6939, tooltip / context-menu group | `bfaa1589c` | "declare what the tooltip / context-menu renderers read" (PR 7456), "Part of objectstack-ai#6939 ... one of eight groups"; added `6939-overlay-trigger-mirror.md`. | | objectstack-ai#6939, tree-view group | `777e5c6f4` | "tree-view mirror stops requiring the limb it reads third (group 2 of objectui#6939)" (PR 7533). | | objectstack-ai#6939, kanban group | `240b80f31` | "rename KanbanColumn.items to cards on both published halves" (PR 7541); its message carries the 12 / 8 read-site measurement the `complex.ts` docblock quotes. | | objectstack-ai#6939, filter-builder group | `d4493fdbc` | "the filter-builder mirror names the keys and the vocabulary its renderer reads" (PR 7560); added `6939-filter-builder-mirror.md`. | | objectstack-ai#6939, object-map / object-gantt group (the record-source ladder and `requireRecordSource`) | `77cb489b4` | "object-map / object-gantt — objectName optional behind a record-source refinement (objectui#6939, group 6 of 8)" (PR 7471); added `objectql-record-source-refinement-6939.test.ts`, which `ce2aaefe1`'s message names as the pin of the published ladder. | | objectstack-ai#6939, chart row | `5f789538d` | "ChartSchema declares the data model it renders" (PR 7545); added `7113-chart-data-model.md` and the series binding refinement. | | objectstack-ai#6939, the ruling itself and its grading language | "the 2026-09-02 ruling" | Recorded 2026-09-02 (director seat, summon objectstack-ai#8, decision batch objectstack-ai#8) per `77cb489b4`; landed per group, the last row by `fd5b09aaf` (PR 9558). | | objectstack-ai#6950 | `9e37d9b39` | "type the framework-injected `binding` input instead of casting it in" (PR 8297); added `6950-binding-framework-injected-input.md`. | | objectstack-ai#7070, gantt dates | `5f4514f7b` | "no invented gantt date field names, so the refusal screen becomes reachable" (PR 7110); added `7070-no-invented-gantt-date-fields.md`, wrote the "only ever restate a binding the view actually DECLARED" lines, the app-shell sibling-branch note, and "re-expressed rather than deleted" for the control its change retired. | | objectstack-ai#7070, timeline step ③ | `04a67b9dc` | "retire the 'created_at' timeline date-axis floors" (PR 7500), "objectui#7070 step ③ of the maintainer ruling of 2026-09-01 (总监批 objectstack-ai#28)"; added `7070-timeline-date-axis-floors-retired.md`. | | objectstack-ai#7070, the ruling | "the 2026-09-01 ruling (总监批 objectstack-ai#28)" | The sentences already name it by date and batch. | | objectstack-ai#7071 | `bc5870c9f` | "a record with no date leaves the grid for an 'unscheduled' area" (PR 7453); "Ruled on objectui#7071 by the maintainer (2026-09-01 ... re-confirmed 2026-09-02)". | | objectstack-ai#7628 (a PR, not a card) | `00d2fa682` | The squash of PR 7628, which answers 404: "fold ListView's `object` data provider onto `objectName`", "released by the maintainer's ruling B". | | objectstack-ai#7632 | `ce2aaefe1` | "one shared record-source ladder, five plugins delegate (objectui#7632)"; PR 7660 answers 404. | | objectstack-ai#7635 | `544ecba84` | "docblocks stop asserting a refusal the spec no longer performs" (PR 9588); its body names objectstack-ai#7635 as the card it settles. Already mapped by the triage. | | objectstack-ai#7688 | nothing answers | A finding card that recorded the `[floor-too-low]` finding the opposite way round. No commit lands it and no successor carries it. See **Special cases**. | | objectstack-ai#9318 | `e3cb47624` | "the field-rule wrong-layer verdict comes from @objectstack/lint, not a second copy of it" (PR 9366); added `9318-field-rule-verdict-from-lint.md` and `celAuthoring.fieldRuleVerdict-9318.test.ts`. | | objectstack-ai#9473 | `ab856ed30` | "type `resolveRecordSourceConfig`'s `data` by the arm it is already told" (PR 9967); its body names objectstack-ai#9473 as the card it settles, and it removed the calendar cast. | ## Special cases (the judgement calls) 1. **objectstack-ai#7688.** "and objectui#7688 records the opposite" becomes "and the card that filed the `[floor-too-low]` finding recorded the opposite", and "The correction is recorded on objectui#7688." becomes "The correction is recorded in `639114c4d`, the commit that landed this entry." That commit's message carries the measured correction verbatim. 2. **`6939-filter-builder-mirror.md`.** "it is reported on objectui#6939 rather than decided here" and "it is reported on the same card" become the two live successors that carried them: objectui#7561 (the operator vocabulary fork and the blank trigger) and objectui#7562 (the seven refused field types). Both answer 200 and their titles match. 3. **"A control is restated, never deleted into a vacuum (objectui#7070)"** (two changesets, `plugin-chatbot/renderer.tsx`, `types/complex.ts`) cites `5f4514f7b`, whose message states that discipline for the control it retired ("re-expressed rather than deleted"). 4. **`plugin-gantt/ObjectGantt.tsx`.** "the fabrication objectui#7070 spent this file's other branches removing" becomes "the fabrication the invented-binding work (`5f4514f7b`) spent this file's other branches removing". The claim is the original author's and is not re-judged here: `5f4514f7b` itself adds a test in that package, not a change to that file. 5. **`6150-undeclared-but-consumed-keys.md`.** Its sentence describes the `nodes` describe text ("records that a `nodes`-only document became legal ..."). The pointer becomes "(at `777e5c6f4`)", so the sentence stays true now that the patch round has taken the pointer out of that string too. 6. **`7070-no-invented-gantt-date-fields.md`.** "which objectui#7070 routes to a ruling rather than settling per-face" becomes "which is routed to a ruling rather than settled per-face": the changeset's own card, so the pointer is dropped and the sentence becomes passive. 7. **`8913-object-kanban-columns-declared.md`** and the `ObjectKanbanLaneSchema` docblock: "restores objectui#6939's finding / judging" becomes "restores what the kanban repair `240b80f31` established" / "the judging `240b80f31` established". 8. **`ObjectGanttSchema.data`'s description** (patch round) was "read FIRST by resolveRecordSourceConfig; undeclared on either face until objectui#6939". Dropping only the pointer would leave a dangling "until", and dropping "until" too would make the string say the key is undeclared, which is false. The clause goes with its pointer, leaving "Data source configuration — read FIRST by resolveRecordSourceConfig": the same shape as its `ObjectMapSchema.data` twin, which reads "Data source configuration — read FIRST by getDataConfig". It is the only one of the eleven where more than the pointer and its connective (" at", " (", ", ") left the string. ## Per file Each row: the dead numbers the file carried, the lines changed, and what they cite now. The diff is the site-by-site record. | file | dead number(s) | lines | now cites | |:--|:--|--:|:--| | `.changeset/5853-tablecolumn-type-canonical-union.md` | objectstack-ai#5853 | 1 | own pointer dropped | | `.changeset/6004-grid-column-emit-boundary.md` | objectstack-ai#5853 | 1 | `fc62bb490` | | `.changeset/6150-undeclared-but-consumed-keys.md` | objectstack-ai#6939 | 2 | `777e5c6f4` | | `.changeset/6373-datatable-emit-boundary.md` | objectstack-ai#5853 | 1 | `fc62bb490` | | `.changeset/6594-headercolor-mirror-enum.md` | objectstack-ai#5853 | 2 | `fc62bb490` | | `.changeset/6938-checkbox-wrapper-class.md` | objectstack-ai#6938, objectstack-ai#6939 | 2 | own pointer dropped; `bfaa1589c` | | `.changeset/6939-filter-builder-catalog-operator-spellings.md` | objectstack-ai#6939 | 1 | own pointer dropped | | `.changeset/6939-filter-builder-mirror.md` | objectstack-ai#6939 | 5 | own pointer dropped; the 2026-09-02 ruling; live successors objectui#7561, objectui#7562 | | `.changeset/6939-kanban-column-cards.md` | objectstack-ai#6939 | 1 | own pointer dropped | | `.changeset/6939-objectql-record-source-refinement.md` | objectstack-ai#6939 | 2 | own pointer dropped | | `.changeset/6939-overlay-trigger-mirror.md` | objectstack-ai#6939 | 2 | own pointer dropped | | `.changeset/6939-tree-view-nodes-mirror.md` | objectstack-ai#6939 | 2 | own pointer dropped | | `.changeset/6950-binding-framework-injected-input.md` | objectstack-ai#6950 | 1 | own pointer dropped | | `.changeset/6951-tree-view-data-retired.md` | objectstack-ai#6939 | 1 | `777e5c6f4` | | `.changeset/7014-select-option-spec-claim-correction.md` | objectstack-ai#7635 | 1 | `544ecba84` | | `.changeset/7070-no-invented-gantt-date-fields.md` | objectstack-ai#7070 | 2 | own pointer dropped | | `.changeset/7070-timeline-date-axis-floors-retired.md` | objectstack-ai#7070 | 1 | own pointer dropped; the 2026-09-01 ruling | | `.changeset/7083-richtext-field-metadata.md` | objectstack-ai#5498 | 1 | `4bb940b6e` | | `.changeset/7113-chart-data-model.md` | objectstack-ai#6939 | 4 | the 2026-09-02 ruling (its `chart` row landed in this entry's own commit) | | `.changeset/7122-spec-17-3-0-parity-reconciliation.md` | objectstack-ai#7688 | 2 | `639114c4d` (nothing answers objectstack-ai#7688; see below) | | `.changeset/7295-chat-message-avatar-keys.md` | objectstack-ai#6938 | 1 | `b74a8598d` | | `.changeset/7313-object-calendar-record-source.md` | objectstack-ai#6939 | 1 | `77cb489b4` | | `.changeset/7459-timeline-absent-date-axis-refusal.md` | objectstack-ai#7070 | 4 | `04a67b9dc`, `5f4514f7b` | | `.changeset/7470-designer-objectname-not-required.md` | objectstack-ai#6939 | 1 | `77cb489b4` | | `.changeset/7499-gantt-non-axis-floors-omitted.md` | objectstack-ai#7070 | 1 | `5f4514f7b` | | `.changeset/7546-chart-series-keys-declared.md` | objectstack-ai#6939 | 2 | `5f789538d` | | `.changeset/7547-forced-path-invented-bindings.md` | objectstack-ai#7070 | 1 | `5f4514f7b` | | `.changeset/7562-filter-field-type-fourteen-members.md` | objectstack-ai#6939 | 1 | `d4493fdbc` | | `.changeset/7627-shared-record-source-reader.md` | objectstack-ai#6939, objectstack-ai#7628 | 2 | `00d2fa682`, `77cb489b4` | | `.changeset/7632-shared-record-source-config.md` | objectstack-ai#6939, objectstack-ai#7632 | 2 | own pointer dropped; `77cb489b4` | | `.changeset/7638-navigation-url-follows-record-source.md` | objectstack-ai#6939 | 2 | `77cb489b4` | | `.changeset/7654-chatbot-display-mode-tombstone.md` | objectstack-ai#7070 | 1 | `5f4514f7b` | | `.changeset/7694-chart-series-chart-type-alias-refusal.md` | objectstack-ai#6939 | 1 | `5f789538d` | | `.changeset/7703-chatbot-dark-keys-retired.md` | objectstack-ai#7070 | 1 | `5f4514f7b` | | `.changeset/7722-wrapper-class-five-more.md` | objectstack-ai#6938 | 3 | `b74a8598d` | | `.changeset/7780-object-kanban-record-source.md` | objectstack-ai#6939 | 1 | `77cb489b4` | | `.changeset/8072-input-wrapper-class-mirrored.md` | objectstack-ai#6938 | 2 | `b74a8598d` | | `.changeset/8169-map-refuses-unbound.md` | objectstack-ai#7070 | 1 | the 2026-09-01 ruling | | `.changeset/8284-content-channel-per-component.md` | objectstack-ai#6939 | 1 | `bfaa1589c`; "Seven earlier cards" now reads "Seven earlier changes", since the list carries a commit (patch round 2) | | `.changeset/8315-sdui-parser-manifest-binding-field-retired.md` | objectstack-ai#6950 | 1 | `9e37d9b39` | | `.changeset/8802-8257-8008-kanban-gantt-family-retirement.md` | objectstack-ai#6939 | 1 | `240b80f31` | | `.changeset/8913-object-kanban-columns-declared.md` | objectstack-ai#6939 | 1 | `240b80f31` | | `.changeset/9318-field-rule-verdict-from-lint.md` | objectstack-ai#9318 | 1 | own pointer dropped | | `.changeset/9618-record-source-ladder-attribution.md` | objectstack-ai#7632 | 1 | `ce2aaefe1` | | `.changeset/readonly-richtext-raw-markup-5498.md` | objectstack-ai#5498 | 1 | own pointer dropped | | `.changeset/retire-theme-component-schema-5489.md` | objectstack-ai#5489 | 1 | own pointer dropped | | `.changeset/retire-theme-switcher-preview-5647.md` | objectstack-ai#5489 | 1 | `78cbdb530` | | `app-shell/…/views/ObjectView.tsx` | objectstack-ai#7070 | 8 | `5f4514f7b` | | `app-shell/…/views/metadata-admin/CelPredicateField.tsx` | objectstack-ai#9318 | 1 | `e3cb47624` | | `app-shell/…/views/metadata-admin/celAuthoring.ts` | objectstack-ai#9318 | 7 | `e3cb47624` | | `app-shell/…/views/metadata-admin/clientValidation.ts` | objectstack-ai#9318 | 1 | `e3cb47624` | | `app-shell/…/views/metadata-admin/inspectors/ObjectFieldInspector.tsx` | objectstack-ai#9318 | 3 | `e3cb47624` | | `components/…/renderers/complex/data-table.tsx` | objectstack-ai#5853 | 2 | `fc62bb490` | | `core/…/data-scope/element-data-source.ts` | objectstack-ai#6950 | 1 | `9e37d9b39` | | `core/…/index.ts` | objectstack-ai#6939, objectstack-ai#7632 | 2 | `77cb489b4`, `ce2aaefe1` | | `core/…/registry/Registry.ts` | objectstack-ai#6950 | 2 | `9e37d9b39` | | `core/…/utils/record-source.ts` | objectstack-ai#6939, objectstack-ai#7628, objectstack-ai#7632, objectstack-ai#9473 | 5 | `00d2fa682`, `77cb489b4`, `ab856ed30`, `ce2aaefe1` | | `fields/…/coerceToSafeValue.ts` | objectstack-ai#5498 | 1 | `4bb940b6e` | | `fields/…/index.tsx` | objectstack-ai#5498 | 3 | `4bb940b6e` | | `fields/…/widgets/RichTextField.tsx` | objectstack-ai#5498 | 3 | `4bb940b6e` | | `fields/…/widgets/richTextDisplay.tsx` | objectstack-ai#5498 | 1 | `4bb940b6e` | | `plugin-calendar/…/ObjectCalendar.tsx` | objectstack-ai#6939, objectstack-ai#7071, objectstack-ai#9473 | 8 | `77cb489b4`, `ab856ed30`, `bc5870c9f` | | `plugin-chatbot/…/renderer.tsx` | objectstack-ai#7070 | 1 | `5f4514f7b` | | `plugin-dashboard/…/ObjectDataTable.tsx` | objectstack-ai#5853 | 3 | `fc62bb490` | | `plugin-gantt/…/ObjectGantt.tsx` | objectstack-ai#7070 | 1 | `5f4514f7b` | | `plugin-gantt/…/index.tsx` | objectstack-ai#6939 | 1 | `77cb489b4` | | `plugin-grid/…/ObjectGrid.tsx` | objectstack-ai#5853, objectstack-ai#6939, objectstack-ai#7632 | 6 | `77cb489b4`, `ce2aaefe1`, `fc62bb490` | | `plugin-list/…/ListView.tsx` | objectstack-ai#7070 | 7 | `04a67b9dc`, `5f4514f7b` | | `plugin-map/…/ObjectMap.tsx` | objectstack-ai#6939, objectstack-ai#7070, objectstack-ai#7632 | 4 | `77cb489b4`, `ce2aaefe1` | | `plugin-map/…/index.tsx` | objectstack-ai#6939 | 1 | `77cb489b4` | | `plugin-timeline/…/ObjectTimeline.tsx` | objectstack-ai#7070 | 2 | the 2026-09-01 ruling (总监批 objectstack-ai#28), already named beside it | | `plugin-timeline/…/useTimelineTranslation.ts` | objectstack-ai#7070 | 1 | the 2026-09-01 ruling (总监批 objectstack-ai#28) | | `plugin-tree/…/ObjectTree.tsx` | objectstack-ai#6939 | 1 | `77cb489b4` | | `plugin-view/…/ObjectView.tsx` | objectstack-ai#7070 | 3 | `04a67b9dc`, `5f4514f7b` | | `react/…/hooks/useNavigationOverlay.ts` | objectstack-ai#6939 | 1 | `77cb489b4` | | `sdui-parser/…/index.ts` | objectstack-ai#6950 | 1 | `9e37d9b39` | | `sdui-parser/…/types.ts` | objectstack-ai#6950 | 1 | `9e37d9b39` | | `types/…/base.ts` | objectstack-ai#6950 | 6 | `9e37d9b39` | | `types/…/complex.ts` | objectstack-ai#6939, objectstack-ai#7070 | 6 | `240b80f31`, `5f4514f7b`, `d4493fdbc` | | `types/…/data-display.ts` | objectstack-ai#5853, objectstack-ai#6938, objectstack-ai#6939 | 7 | `5f789538d`, `777e5c6f4`, `b74a8598d`, `fc62bb490` | | `types/…/field-types.ts` | objectstack-ai#5498, objectstack-ai#7635 | 6 | `4bb940b6e`, `544ecba84` | | `types/…/form.ts` | objectstack-ai#6938 | 5 | `b74a8598d` | | `types/…/index.ts` | objectstack-ai#5489, objectstack-ai#5853, objectstack-ai#6950 | 3 | `78cbdb530`, `9e37d9b39`, `fc62bb490` | | `types/…/objectql.ts` | objectstack-ai#6939 | 4 | `77cb489b4` | | `types/…/overlay.ts` | objectstack-ai#6939 | 7 | `bfaa1589c` | | `types/…/select-option.ts` | objectstack-ai#7635 | 1 | `544ecba84` | | `types/…/theme.ts` | objectstack-ai#5489 | 3 | `78cbdb530` | | `types/…/zod/blocks.zod.ts` | objectstack-ai#5489 | 1 | `78cbdb530` | | `types/…/zod/complex.zod.ts` | objectstack-ai#6939 | 5 | `d4493fdbc` | | `types/…/zod/data-display.zod.ts` | objectstack-ai#5853, objectstack-ai#6939 | 3 | `5f789538d`, `fc62bb490`; one `.describe()` pointer dropped | | `types/…/zod/form.zod.ts` | objectstack-ai#6938 | 1 | one `.describe()` pointer dropped | | `types/…/zod/index.zod.ts` | objectstack-ai#5489 | 1 | `78cbdb530` | | `types/…/zod/objectql.zod.ts` | objectstack-ai#6939 | 9 | `240b80f31`, `77cb489b4`; three `.describe()` pointers dropped | | `types/…/zod/overlay.zod.ts` | objectstack-ai#6939 | 9 | `bfaa1589c`; six `.describe()` pointers dropped | | `types/…/zod/theme.zod.ts` | objectstack-ai#5489 | 2 | `78cbdb530` | ## Patch round: the eleven `.describe()` strings (commit `19da7f8c0`) Under the seat's amendment `5860244997` (Q1 = A), each dead pointer is dropped from its string; nothing else in any string moves, and no key, path, accept set or refusal changes. | file | member | before | after | |:--|:--|:--|:--| | `types/src/zod/data-display.zod.ts` | `TreeViewSchema.nodes` | "a `nodes`-only document became LEGAL at objectui#6939; the `data` fallback" | "a `nodes`-only document became LEGAL; the `data` fallback" | | `types/src/zod/form.zod.ts` | `CheckboxSchema.wrapperClass` | "... around the box and its label (objectui#6938)" | "... around the box and its label" | | `types/src/zod/objectql.zod.ts` | `ObjectMapSchema.objectName` | "... one of the three must be present (objectui#6939)" | "... one of the three must be present" | | `types/src/zod/objectql.zod.ts` | `ObjectGanttSchema.objectName` | "... one of the three must be present (objectui#6939)" | "... one of the three must be present" | | `types/src/zod/objectql.zod.ts` | `ObjectGanttSchema.data` | "... read FIRST by resolveRecordSourceConfig; undeclared on either face until objectui#6939" | "Data source configuration — read FIRST by resolveRecordSourceConfig" (special case 8; the `ObjectMapSchema.data` twin names `getDataConfig` instead) | | `types/src/zod/overlay.zod.ts` | `TooltipSchema.trigger` | "Element the tooltip attaches to (objectui#6939)" | "Element the tooltip attaches to" | | `types/src/zod/overlay.zod.ts` | `TooltipSchema.content` | "... the fallback for the same slot (objectui#6939). Text only: ..." | "... the fallback for the same slot. Text only: ..." | | `types/src/zod/overlay.zod.ts` | `TooltipSchema.children` | `... the "Rich Content" slot (objectui#6939, objectui#6771)` | `... the "Rich Content" slot (objectui#6771)` | | `types/src/zod/overlay.zod.ts` | `ContextMenuSchema.triggerClassName` | "... when none are set (objectui#6939)" | "... when none are set" | | `types/src/zod/overlay.zod.ts` | `ContextMenuSchema.contentClassName` | "... the underlying `ContextMenuContent` (objectui#6939)" | "... the underlying `ContextMenuContent`" | | `types/src/zod/overlay.zod.ts` | `ContextMenuSchema.modal` | "... root as `modal` (objectui#6939)" | "... root as `modal`" | - **Only those substrings moved, measured.** Each of the four files printed by TypeScript's `createPrinter({ removeComments: true })` at `6c3ad7c80`, with exactly these 11 substring deletions applied to the print, equals the print at `19da7f8c0` (4 of 4 equal, 11 substitutions counted). objectui#6771 and objectui#10295, which stay in two strings, both answer 200. - **Pins.** No test quotes any of the eleven strings: searching the whole tree (not only `packages/types` tests and `scripts/__tests__`) for a distinctive fragment of each string finds them only in the four zod files, in two test COMMENTS (`recordSourceInput-7470` in `plugin-gantt` and `plugin-map`, unchanged wording, no pointer), and in `overlay.ts` docblocks and two `content/docs` pages that say the same words without the pointer. No snapshot carries them. - **`dist`.** After `@object-ui/types` is rebuilt, its `dist` carries 0 of the fourteen (round 1 left 22 hits, all inside `describe(` calls); objectui#6771 is still in 21 files, the control. - **Serial, re-checked for these four files.** The open-PR list was re-read (10 open; objectui#10852 is new and touches none of the four). objectui#10821 and objectstack-ai#10802 touch `objectql.zod.ts` and objectstack-ai#10714 touches `data-display.zod.ts`; their `/files` hunks mapped onto this branch cover lines 39-1246 and 2524-2716, and 167-206, and none contains a describe line (1874, 1925, 1926; 575). Nothing was held. ## Serial The open-PR list was re-read at the start (9 open). Six touch census files: objectui#10851, objectstack-ai#10821, objectstack-ai#10802, objectstack-ai#10793, objectstack-ai#10714 and objectstack-ai#10278 (objectstack-ai#5400 is the release PR and regenerates). Each one's REST `/files` patch was read and its hunk ranges were mapped onto the base with a line alignment of the PR's merge-base file against the base file. **No census site lies inside any hunk range**, so nothing was held for the serial rule. Trial merges with `git merge-tree` at each PR's head, base against head of this branch: | PR (head) | at the base | at this head | |:--|:--|:--| | objectui#10851 (`8b146b0da`) | clean | clean | | objectui#10821 (`24bcb0035`) | clean | clean | | objectui#10802 (`77646f415`) | clean | clean | | objectui#10793 (`dd43c757c`) | clean | clean | | objectui#10714 (`d2afdb6bf`) | clean | clean | | objectui#10278 (`eab4c8e52`) | 1 conflict region in `ObjectGrid.tsx`, already there at the base | the same single region; this branch's five `ObjectGrid.tsx` citations merge cleanly | No file that exists only on another PR's branch was edited. ## Changesets - `.changeset/10803-dead-citation-sweep-second-batch.md`, EMPTY frontmatter: the comment-only edits in 17 released packages, no published behaviour changes through them. Its prose now says so of the comment edits alone and points at the second file. - `.changeset/10803-describe-string-citations.md`, `'@object-ui/types': patch`: the eleven runtime `.describe()` strings lose their dead pointer, and nothing else in them, no key, path, accept set or refusal, moves. It names the `ObjectGanttSchema.data` clause and quotes the resulting string; patch round 2 (`4906c4408`) corrected its sentence, which had called that string the same text as the `ObjectMapSchema.data` twin (the twin names `getDataConfig`). - Round 1: before the first changeset was added, `check-changeset-presence` exited 1 on the comment-only `src` edits. ## Gates, patch round 2, on the head `4906c4408` (changeset prose only) - `node scripts/check-changeset-presence.mjs`, exit 0: "48 source file(s) of 17 released package(s) changed, and this change declares 2 changeset(s): .changeset/10803-dead-citation-sweep-second-batch.md, .changeset/10803-describe-string-citations.md." - `pnpm changeset:check`, exit 0: "No changeset declares a `major` bump." - `node scripts/check-changeset-overwrite.mjs` (report-only), exit 0: "2 changeset(s) added, 47 modified, 0 deleted"; `declared at base` equals `declares now` for all 47 (the `8284` wording change moves no frontmatter). - `pnpm check:changeset-claims` (report-only), exit 0: 111 pending changesets name a file this change touches, unchanged from patch round 1. - `pnpm check:control-bytes`, exit 0: "check-control-bytes: OK (scanned 9087 tracked text file(s); skipped 85 binary)." - Pin at this head: 0; this head merged with `main` at `4aebea00a`: 0. ## Gates, patch round 1, on the head `19da7f8c0` - `node scripts/check-changeset-presence.mjs`, exit 0: "48 source file(s) of 17 released package(s) changed, and this change declares 2 changeset(s): .changeset/10803-dead-citation-sweep-second-batch.md, .changeset/10803-describe-string-citations.md." - `pnpm changeset:check`, exit 0: "No changeset declares a `major` bump." `node scripts/check-changeset-overwrite.mjs` (report-only), exit 0: "2 changeset(s) added, 47 modified, 0 deleted". - `pnpm check:changeset-claims` (report-only), exit 0: 111 pending changesets name a file this change touches; none quotes any of the eleven strings, and the ones that describe them (`6150-undeclared-but-consumed-keys.md` on the `nodes` text, `7632-shared-record-source-config.md` and `9618-record-source-ladder-attribution.md` on the ladder order) stay true. - `pnpm check:pending-changeset-literals`, exit 0. `pnpm check:new-line-citations`, exit 0: "VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0". `pnpm check:control-bytes`, exit 0: "check-control-bytes: OK (scanned 9087 tracked text file(s); skipped 85 binary)." - `node scripts/check-spec-symbol-derivation.mjs`, exit 0: "spec member citations: 1412 sources + 184 documentation pages; nothing cites a key its spec symbol does not declare." `node scripts/check-hand-rolled-comment-mask.mjs`, exit 0. - eslint, narrowed: the four zod files, `--no-inline-config --format json`: 4 files, 0 errors, 1 warning; the same four at the base: 0 errors, 1 warning. No type-aware linting in `eslint.config.js`. ## Gates, round 1, on the head `6c3ad7c80` Each line is the gate's own verdict and its exit code, captured by redirect-then-`$?`. - `node scripts/check-changeset-presence.mjs`, exit 0: "47 source file(s) of 17 released package(s) changed, and this change declares 1 changeset(s): .changeset/10803-dead-citation-sweep-second-batch.md." - `pnpm changeset:check`, exit 0: "No changeset declares a `major` bump." - `node scripts/check-changeset-overwrite.mjs` (report-only), exit 0: "1 changeset(s) added, 47 modified, 0 deleted"; for all 47, `declared at base` equals `declares now`. Separately, the sha256 of every edited changeset's frontmatter block is equal before and after (47 of 47). - `pnpm check:changeset-claims` (report-only), exit 0: "108 pending changeset(s) describe a file this change touches." Read against the diff: of 122 distinct 28-to-40-character segments of the removed comment text, 9 occur in a pending changeset, and every one is a phrase this diff keeps verbatim (for example "maintainer ruling 2026-08-25, Option B"); none quotes a replaced pointer. - `pnpm check:pending-changeset-literals`, exit 0: "No test source names a pending changeset." - `pnpm check:new-line-citations`, exit 0: "VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0". - `pnpm check:control-bytes`, exit 0: "check-control-bytes: OK (scanned 9086 tracked text file(s); skipped 85 binary)." Self-scan of the 95 changed files for C0 / DEL bytes: 0. - `node scripts/check-hand-rolled-comment-mask.mjs`, exit 0: "OK every carrier is a DEBT entry, and every DEBT entry still carries one." - `pnpm check:comment-mask-corpus`, exit 0: the standing report only (1 file, `apps/console/src/pages/DocsIndex.tsx`, not touched here). - `pnpm check:spec-symbols`, exit 0: "spec member citations: 1412 sources + 184 documentation pages; nothing cites a key its spec symbol does not declare." - `pnpm check:installed-pin-claims`, exit 0: "OK". `pnpm check:metadata-write-doors`, exit 0: "OK 17 metadata write door(s) derived". `pnpm check:element-data-source-declaration`, exit 0: "OK — 13 gate-consuming file(s) checked". `pnpm check:handler-key-reads`, exit 0. `pnpm check:designer-field-key-parity`, exit 0. `pnpm check:action-forward-parity`, exit 0. `pnpm check:doc-example-ids`, exit 0: "414 real reference(s) all resolve in the catalog registry." `pnpm check:doc-example-readers`, exit 0: "no @example hand-spells one." `node scripts/check-doc-expression-carriage.mjs`, exit 0. - `pnpm check:doc-examples` (`check-doc-example-types`): **NOT MEASURED**, exit 2 "THE GATE COULD NOT RUN — the packages these examples import are not built" (it needs every package's `dist`). Its input cannot move here: 0 of the 150 changed source lines sits inside an `@example` block (walked per line to the enclosing tag), and the comment-stripped tree of every touched file is identical. - **Comment-only, measured.** Each of the 47 touched source files parsed with TypeScript 6.0.3's `createSourceFile` and re-printed by `createPrinter({ removeComments: true })`: the sha256 is identical before and after for 47 of 47, with 0 parse diagnostics. Lit control on the same instrument: dropping "(objectui#6938)" from the `form.zod.ts` describe string moves the hash; re-spacing a comment does not. - Built `dist`: 0 hits of the fourteen outside the held describe strings in any built package; the new shas reach `dist` in `types`, `core`, `fields`, `react`, `sdui-parser`, `plugin-dashboard` and `plugin-grid`. ## Tests and type-check, through the shared verify lock Each run reports `VERDICT command-exit 0`. Patch round 1, on `19da7f8c0` (patch round 2 changed changeset prose only, so these stand): - `pnpm exec vitest run packages/types/ --maxWorkers=2`: `Test Files 252 passed (252)`, `Tests 5429 passed (5429)`. - The 55 `scripts/__tests__` suites that read `packages/types/src/zod`, any zod source, or `.changeset/` (every test there naming either, plus the suite of every script that reads either): `Test Files 55 passed (55)`, `Tests 2685 passed (2685)`. - `turbo run build --filter=@object-ui/types...` (1 task), then `pnpm --filter @object-ui/types run type-check` (`tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json`), exit 0. Round 1, on `6c3ad7c80`: - `pnpm exec vitest run packages/types/ --maxWorkers=2`: `Test Files 252 passed (252)`, `Tests 5429 passed (5429)`. - A second run of 128 files: every test file outside `packages/types` that reads the file system and names a touched source file by path, the `.changeset/**` readers `node scripts/markdown-test-inputs.mjs --list` names, and the suites of the changeset, comment-mask, citation and control-byte gates. `Test Files 128 passed (128)`, `Tests 3949 passed (3949)`. - Build of the 28-package dependency closure of the 17 touched packages (`turbo run build --concurrency=2`), then `pnpm --workspace-concurrency=2 run type-check` over all 17 touched packages: every one printed its `type-check$ tsc ...` line and `Done`, exit 0. - eslint, narrowed and declared. Population: the 47 touched source files, each linted through the repo's `eslint.config.js` (47 results, none ignored). Counts from `--no-inline-config --format json`: 47 files, 4 errors, 1167 warnings. The same 47 files at the base, through the ESLint API with inline config off: 4 errors, 1167 warnings, the 4 errors on the same lines and rules (`react-hooks/static-components` twice, `@typescript-eslint/no-empty-object-type`, `no-restricted-imports`). Invariance: `eslint.config.js` enables no type-aware linting (no `projectService`, no `project` parser option, no type-checked preset), so a comment diff cannot move another file's verdict. **Declared narrowing.** NOT MEASURED locally: the full test suites of the other 16 touched packages (their edits are comment-only and unchanged since round 1). Reason: the comment-stripped syntax tree of every touched file is identical, so only a test that reads source TEXT can move, and those ran above. CI runs the full farm. ## Acceptance notes 1. **The family is larger than fourteen: the remainder rides this card (seat amendment `5860244997`, Q2 = A), not this PR.** Census method: every distinct `objectui#N` and objectui issue or pull URL cited in the two in-scope classes (pending `.changeset/*.md`, non-test `packages/*/src`) was read by REST `GET /repos/objectstack-ai/objectui/issues/N`, and every 404 was read a second time. At `6c3ad7c80`: 2791 numbers, 2663 answer 200 and 128 answer 404 (128 of 128 again). Thirteen of the 128 are this card's (the fourteenth, objectstack-ai#7628, is only ever cited as "PR objectstack-ai#7628"). The other **115**, cited on 652 lines (197 changeset lines in 153 files and 455 src-nontest lines in 162 files), are: objectstack-ai#3499 objectstack-ai#3559 objectstack-ai#4784 objectstack-ai#5197 objectstack-ai#5221 objectstack-ai#5286 objectstack-ai#5309 objectstack-ai#5399 objectstack-ai#5401 objectstack-ai#5413 objectstack-ai#5414 objectstack-ai#5416 objectstack-ai#5417 objectstack-ai#5418 objectstack-ai#5425 objectstack-ai#5518 objectstack-ai#5533 objectstack-ai#5709 objectstack-ai#5738 objectstack-ai#5741 objectstack-ai#5852 objectstack-ai#5859 objectstack-ai#6296 objectstack-ai#6464 objectstack-ai#6661 objectstack-ai#6740 objectstack-ai#6757 objectstack-ai#6854 objectstack-ai#6859 objectstack-ai#6864 objectstack-ai#6872 objectstack-ai#6879 objectstack-ai#6882 objectstack-ai#6887 objectstack-ai#6888 objectstack-ai#6889 objectstack-ai#6892 objectstack-ai#6896 objectstack-ai#6905 objectstack-ai#6907 objectstack-ai#6921 objectstack-ai#6923 objectstack-ai#6924 objectstack-ai#6931 objectstack-ai#6940 objectstack-ai#6942 objectstack-ai#6951 objectstack-ai#6958 objectstack-ai#6959 objectstack-ai#6962 objectstack-ai#6965 objectstack-ai#7004 objectstack-ai#7008 objectstack-ai#7023 objectstack-ai#7025 objectstack-ai#7036 objectstack-ai#7068 objectstack-ai#7069 objectstack-ai#7077 objectstack-ai#7079 objectstack-ai#7087 objectstack-ai#7088 objectstack-ai#7091 objectstack-ai#7097 objectstack-ai#7108 objectstack-ai#7177 objectstack-ai#7612 objectstack-ai#7620 objectstack-ai#7623 objectstack-ai#7658 objectstack-ai#7666 objectstack-ai#7667 objectstack-ai#7669 objectstack-ai#7678 objectstack-ai#7681 objectstack-ai#7682 objectstack-ai#7703 objectstack-ai#7704 objectstack-ai#7708 objectstack-ai#7804 objectstack-ai#7844 objectstack-ai#7853 objectstack-ai#7869 objectstack-ai#7874 objectstack-ai#7877 objectstack-ai#7926 objectstack-ai#7959 objectstack-ai#7967 objectstack-ai#7979 objectstack-ai#7980 objectstack-ai#8058 objectstack-ai#8060 objectstack-ai#8072 objectstack-ai#8127 objectstack-ai#8137 objectstack-ai#8204 objectstack-ai#8229 objectstack-ai#8248 objectstack-ai#8307 objectstack-ai#8408 objectstack-ai#9231 objectstack-ai#9241 objectstack-ai#9244 objectstack-ai#9365 objectstack-ai#9373 objectstack-ai#9375 objectstack-ai#9542 objectstack-ai#9553 objectstack-ai#9585 objectstack-ai#10117 objectstack-ai#10119 objectstack-ai#10120 objectstack-ai#10129 objectstack-ai#10132 #14026. They are carried by later PRs on this card after this one lands, in batches, each under the same serial rule. Two of them sit in sentences this PR edits (objectui#6896 in the chart changesets, objectui#6951 beside the tree-view history and in the `nodes` description), and they are left as they are. 2. **Filenames are not citations.** Pending changeset FILENAMES carry several of the fourteen (six carry `6939`); they stay, as PRs objectui#10707 and objectstack-ai#10797 left theirs. 3. **The census instrument's one false positive class** is `objectstack#N`: its bare `#` branch matches inside a repo-qualified sister-repo citation. The printed pin above filters it; the card's figures did not. --- _Generated by [Claude Code](https://claude.ai/code/session_01DuWo5bdP9SdVebamn99GGk)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
…s the spec's ObjectListViewSchema by reference; ViewPreview folds a stored options bag (objectui#7928) (objectstack-ai#10821) Fixes objectstack-ai#7928 Clause-②: yes Ruling `5856694523` (director seat, Q1 A · Q2 (i)), under ruling `5565628927` (option A, staged, maintainer 「同意」). Claim `5857418366`, seat `domain:spec#1`, session `session_014fWVhLzhxR8qrFsJ5o8TYW`. ## What changed - **`@object-ui/types`: the mirror flips by reference.** - The zod face: `ObjectViewSchema.listViews` is `stripImportedDefaults(SpecViewSchema).shape.listViews`. That is the spec container's own record of the strict `ObjectListViewSchema`, crossed through the import boundary so no protocol default is written into a parsed document. - The TS face: a record of string to `z.input` of `typeof ObjectListViewSchema`, imported type-only from `@objectstack/spec/ui`. - A named view authoring `options` is refused `unrecognized_keys`, naming `options`. - The `UnmirroredDeclared` ledger row is deleted. The header figures moved to 12 entries / 84 keys (2 / 16 spec-derived), each with its history sentence. - The two ledger comments triage `5853448361` names are rewritten. - **`@object-ui/app-shell` `ViewPreview`: the fold.** The new `foldStoredListOptions` lifts each `options.KIND` of a stored body onto the top-level `KIND` block before the node is built. The top-level value wins per key, and `options` is not relayed. A body without `options` comes back as the same object. - **`@object-ui/plugin-view` `ObjectView`: both named-view `options` reads are removed.** They are the `legacyViewOptions` rung and the `options:` relay into the `list-view` node. The host `activeView` rung stays on both, so objectui#10758 / objectstack-ai#10380's path is untouched. The JSDoc example now teaches the canonical `kanban` / `calendar` blocks. `currentNamedViewConfig` is typed off `ObjectViewSchema['listViews']`. - **`NamedListView` is untouched** (Q2 (i)). - **`examples/byo-backend-console`**: the named view gains per-object `columns`. - **Changeset** `7928-listviews-by-reference-fold.md`: `minor` for types / plugin-view / app-shell, with the breaking semantics spelled out. ## Beyond the claimed file surface, and why each was forced Every item below is a measured consequence of the flip. None is a new capability. 1. **The two named-view door checks now run under `superRefine(…, { when })`, and they read the protocol's refusal.** - The checks are objectui#8355's calendar aliases and objectui#10321's stray `kanban.groupBy`, which landed on `main` mid-card and was merged in. - The strict record refuses the alias itself. That aborts a default refinement, and the parse output DROPS the key. Measured: without the change, the checks never ran on the documents they exist for. - The author would then see only the protocol's near-miss hint, which for `dateField` says `endDateField`: the hazard objectui#8355's docblock names. - A shared helper, `namedViewKindRefusals`, reads the `unrecognized_keys` issue at `listViews.KEY.KIND` and adds the pointer at the key. It adds messages only. It refuses and accepts nothing on its own. - The `options.KIND` nesting is not judged any more. The bag is refused whole. 2. **plugin-view tab strip: a named view's `label` is resolved as the protocol's `I18nLabel`.** It uses `resolveI18nLabel` with `useDisplayLocale`, as `ListView` already does. - Measured on the flipped tree before the fix: a locale-map label threw "Objects are not valid as a React child". - The contract now declares that shape, so it has to render. 3. **plugin-view sort reads.** The protocol's named-view `sort` (17.4.0) still admits the bare string clause objectui retired (objectui#8221). - The two sink reads cast to the sink's declared input and hand the value on unchanged. The sinks refuse a string out loud (`normalizeSortEntries`, `ObjectGrid`). Nothing is narrowed, dropped or lowered. - A pin (`ObjectView.namedViewSpecRecord-7928.test.tsx`) reads that answer: no `$orderby`, and the refusal is reported. 4. **Pins that asserted the unmirrored state are inverted. ⛔ None is deleted.** - objectstack-ai#8980's three legacy-nesting cases. - objectstack-ai#8355's legacy-nesting arm, scope controls and TIMELINE control, on both the plugin-view and the types side. - objectstack-ai#10321's legacy nesting and scope controls. - The objectui#7924 census in `object-view-unmirrored-keys-7779.test.ts`: `options` moves from read to unread (20 / 44), and bucket ③ is 11. `options` is HELD, not tombstoned, per Q2 (i). The value-binding instrument now also recognises `NamedViewConfig`, the mirrored member's entry type. - `object-view-spec-parity` (the TS-only backlog is empty; 22 / 24 keys). - `imported-defaults-8317`: `ViewSchema` is registered, and a fourth `lazy` node sits under `formViews`. The walker docblock count moved with it. 5. **Three plugin-view fixture files** typed as `ObjectViewSchema`: named views gain `columns`, and a tuple filter is respelled as a rule object. The assertions are unchanged. 6. **Three reference rows** (`schema-reference.md`, `plugin-view.mdx`, plugin-view README) said a `listViews` entry is a `NamedListView`. ## Verification, first taken at `24bcb00353` (after an earlier merge of `main`) The readings in this section are of `24bcb00353`. The base-merge round re-took them at the final head `395371dad2`; see Patch round 1 below. Every heavy run went through `os-verify-lock.sh`. Each exit code was captured redirect-first. - vitest `packages/types/ packages/plugin-view/`: 301 files, 5854 tests passed, VERDICT command-exit 0. - vitest `packages/plugin-list/` plus 71 app-shell files: 173 files, 1816 tests passed, exit 0. - The app-shell files are those reaching `ViewPreview` or the preview registry, `ObjectView*` and `InterfaceListPage*`. - The full app-shell suite (831 files) is declared to CI. app-shell's only source change is `ViewPreview.tsx`. - type-check (`tsc --noEmit` plus `tsconfig.test.json`), exit 0 each: `@object-ui/types` (plus examples), plugin-view, app-shell, plugin-list, and `examples/byo-backend-console`. - Reverse verification of the cross-package type: before the fixtures were respelled, plugin-view's `tsconfig.test.json` went red with TS2741 "Property 'columns' is missing" against the rebuilt `.d.ts`. - ESLint `--no-inline-config` on the 20 touched TS/TSX files: 0 errors, 200 warnings. - The only new warning is `react-refresh/only-export-components` for the exported fold in `ViewPreview.tsx`. - Not type-aware: `eslint.config.js` has no `projectService` / `parserOptions` (count 0, control `languageOptions` 1), so no untouched file's verdict can move. - Gates, exit 0 each: - `check-changeset-presence` (19 source files of 3 released packages, 1 changeset) and `check-changeset-no-major`. - `check:new-line-citations` (0 new), `check:control-bytes`, `check:spec-symbols`, `check:test-path-roots`. - The three `check:vi-mock-*` gates and `check-changeset-claims`. - `check:doc-types`, `check:doc-snippets` (676 of 676 judged, 0 failed), `check:doc-examples`, `check:readme-exports`, `check:doc-fences`. - `check-governed-queue-guard --test` (NOT GOVERNED). - **Spec Main Shape Gate: NOT MEASURED locally.** It is a repo-wide forced type-check against a spec built from objectstack `main`, which CI runs on this PR. Source reading of objectstack `main` (`e4621867`): `ViewSchema.listViews` is the same record, and the list-view `sort` is array-only there, so the sort casts narrow nothing. **Ablations.** Each used `ablation-replace.mjs`, on the committed tree, with the restore proven (`git diff HEAD` empty, blob equals HEAD): 1. The fold call replaced by the raw body: 3 of 12 red (the legacy lane, the per-key survival, the contract parse). "Canonical wins" stays green, because the renderer no longer reads the bag. 2. The named-view `options` read restored: 4 red (two inverted objectstack-ai#8980 cases, the fold file's CONTROL, objectstack-ai#8355's half-1 legacy control). 3. `when` dropped from the door checks: 4 red (the canonical `calendar.dateField` / `endField` pointer pins, types and plugin-view). 4. The tab-strip label resolution reverted: the locale-map case and the empty-map fall-through went red, and the plain-string CONTROL stayed green. 5. The kanban sibling unwired (merged head): the two objectstack-ai#10321 pointer pins went red, and every control stayed green. ## Patch round 1: base merge (final head `395371dad2`) After objectstack-ai#10793 (`66e8b2ab38`) and objectstack-ai#10802 (`b956e693d0`) landed, `origin/main` `b956e693d0` was merged into this branch as merge commit `9c2a692186`. Both landed commits were confirmed as its ancestors first. There was no rebase and no force-push. - **`imported-defaults-8317.test.ts`**: the `IMPORTED` list keeps both crossings. `ChartSeriesSchema` (objectui#10770) comes first, then `ViewSchema` (this PR). The walker's `lazy` count stays 4, since `ChartSeriesSchema` owns no `z.lazy`. - **`object-view-unmirrored-keys-7779.test.ts`**: the describe takes `main`'s "seventeen `?: never` tombstones". The first `it()` checks 8 + (11 − 1 − 1) = 17 tombstones derived off the AST, which is `main`'s `NAMED_LIST_VIEW_TOMBSTONES` with `densityMode`. objectstack-ai#10793's assertions (`_DensityModeTombstoned`, `_refusedDensityMode`, `_acceptedDensityCanonical`, and the relay fold-through lines) and this PR's (`listViews` by reference, `BUCKET_LOCAL_ONLY_HELD`, and "`options` is HELD") all survive, and no assertion was re-pointed. Four comment passages were re-pointed to the merged state: bucket ③ is eleven, `options` is the held eleventh member, and the retained read quotes Q2 (i). - **`plugin-view/src/ObjectView.tsx`** merged cleanly, and the two edits have no semantic collision. objectstack-ai#10793's `rowHeight` rung reads `normalizeListViewSchema(activeView ?? {})`, while this PR dropped the `currentNamedViewConfig?.options` reads: there are 0 on the merged file, with `currentNamedViewConfig?.kanban` at 1 as the control. - **Changeset.** `395371dad2` re-points one paragraph that the merge made false: the entry leaves `NamedListView` unchanged, objectstack-ai#7924's own entry retires its `densityMode`, and any further retirement follows ruling A′ and the `allowExport` ruling (`5856694523` Q2 (i)). **Readings at the merged tree.** Every heavy run went through the lock, and each exit code was read before any pipe. - `type-check` exited 0 for `@object-ui/types`, `core`, `plugin-view`, `app-shell` and `plugin-charts`, and also for `plugin-list` and `examples/byo-backend-console`. - vitest: | package | files | tests | | --- | --- | --- | | `types` | 257 | 5482 | | `core` | 182 | 3635 | | `plugin-view` | 52 | 490 | | `plugin-charts` | 84 | 1015 | | `plugin-list` | 104 | 1173 | All passed with exit 0. - **`app-shell` exited 1: 838 files passed, 1 failed and 1 skipped (8551 tests passed, 1 failed, 9 skipped).** - The failure is `AppContent.inaccessibleAppStrand.test.tsx`, "bounces to the DECLARED landing…". Its network-escape guard fired on a real socket to `localhost:3000/api/v1/meta`. - The same file passed alone 3 of 3. It is outside this diff, which touches nothing under `app-shell/src/console`. - This is recorded, not waived. CI's sharded run on this head decides it. - The named pins passed together: 7 files, 411 tests (the 7779, 8317 and 7928 pins, `ViewPreview.optionsFold-7928`, `ObjectView.densityModeThroughFold-7924` and `ObjectView.relayRungCensus-7559`). - ESLint `--no-inline-config` on the 20 TS/TSX files: 0 errors and 200 warnings, the same as at `24bcb00353`. - Gates at `395371dad2` exited 0 each: - `check-changeset-presence` and `check-changeset-no-major`; - `check:new-line-citations` (0 new), `check:control-bytes`, `check:spec-symbols` and `check:test-path-roots`; - the three `check:vi-mock-*` gates, `check:doc-types`, `check:doc-fences` and `check-changeset-claims`; - `check-governed-queue-guard --test`: 24 paths, NOT GOVERNED. - **Reverse check.** Writing `24bcb00353`'s 7779 pin over the merge turned vitest red on objectstack-ai#10793's tombstone: 3 failed, exit 1. `tsconfig.test.json` also went red, with TS2344 and TS2322. The restore was proven: the blob equals HEAD, and `git diff HEAD` is empty. - **NOT MEASURED:** - `check:readme-exports`: its prerequisite is not met (unbuilt dists). - `check:doc-snippets` / `check:doc-examples`: not re-run, because this PR's doc lines are byte-identical to `24bcb00353`, where both passed. - The Spec Main Shape Gate: CI runs it. ## Acceptance notes - **The named view now has one dialect, and it is wider in two ways and stricter in more.** - Keys the protocol's strict kind blocks do not declare are refused on a named view. Measured on 17.4.0: `kanban.titleField` / `groupField` / `swimlaneField` / `conditionalFormatting`, `gallery.imageField`, `timeline.dateField` / `endField`, `calendar.allDayField` / `defaultView` and `map.style`. - `generateViewSchema` still reads them off a named view that reaches it unvalidated, so a stored body keeps rendering. - This is ruling A's "by reference". It is not the stop condition (a third top-level `options` read), but it is a larger population than the thread measured (top-level members only). - `kanban.titleField`, `calendar.defaultView` and `map.style` have no protocol spelling on this surface. Whether any deserves one is an upstream question for the seat. - **Release text.** Pending changesets for objectui#7779, objectstack-ai#8355, objectstack-ai#10321, objectstack-ai#8365 and objectstack-ai#9242 say `listViews` stays unmirrored, or that the doors judge the `options` nesting. This PR's changeset states that it supersedes both, rather than editing five other cards' bodies. - **Left as found, deliberately:** - `NamedListView`'s own docblock still says "Used in ObjectViewSchema.listViews". Under Q2 (i) the interface is untouched. objectui#7924 closed via objectstack-ai#10793, which retired only `densityMode` and left this docblock as it was. The director seat carries it as a hygiene card (record `5860951313` ③). - The dev-mode warning in `generateViewSchema` still tells authors to "Move them under options.KIND"; it now reads the host `views` entry only. - `normalizeSortEntries`' refusal text says the array is "the only one `@objectstack/spec` accepts". That is false for 17.4.0's `ObjectListViewSchema` and true on objectstack `main`. - **Overlap, resolved.** objectstack-ai#10793 (objectui#7924) and objectstack-ai#10802 (objectui#10770) each conflicted textually with this PR: objectstack-ai#10793 in the describe and first `it()` names of the 7779 census, and objectstack-ai#10802 in the 8317 `IMPORTED` list. Both landed first. Merge commit `9c2a692186` resolved both conflicts and kept every assertion from both sides (Patch round 1). --- _Generated by [Claude Code](https://claude.ai/code/session_014fWVhLzhxR8qrFsJ5o8TYW)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
…i#10793, objectstack-ai#10802 and objectstack-ai#10821 made false (objectui#10877) (objectstack-ai#10891) Fixes objectstack-ai#10877 Clause-②: no. It is release-text hygiene, and no published type or behaviour moves. ## What this does Eight pending changesets each state a contract fact that a later PR in this same unreleased batch made false: PR objectstack-ai#10793 (objectui#7924, `densityMode` retired), PR objectstack-ai#10821 (objectui#7928, `ObjectViewSchema.listViews` mirrored by reference, a named view's `options` bag refused whole) and PR objectstack-ai#10802 (objectui#10770, `ObjectChartSchema.series` became two arms). A pending changeset publishes verbatim into the CHANGELOG at the next release, and the release PR objectui#5400 is still open. So each false sentence now has a dated supersession note beside it. The note form is copied from the landed precedents, PR objectstack-ai#10533 (the `6235-mergedsort-wrap.md` note) and PR objectstack-ai#10828 (objectui#10801): a bold headline naming the date and the card whose change supersedes the sentence, then what holds now, then the superseding entry by file and PR, then "the text above is kept as the reading of this change". - Zero lines deleted: `git diff --numstat` against the merge-base `9f0c84a448` is 168 insertions, 0 deletions, over 8 files. The first round added 10 notes in 6 files. Patch round 1 added 4 notes in 2 files (below). Patch round 2 edited the 7779 note and added none, so there are 14 notes. - The frontmatter is byte-identical in all nine entries the claim and its addendum `5862987983` name. The md5 of the frontmatter block is equal at the merge-base `9f0c84a448` and the head `50deccd71a` for each: 7924-retire `ecedb10c`, 8355 `8f322642`, 10321 `564c93d5`, 10584 `84f96a9a`, 8365 `379475b3`, 9242 `acef2a2c`, 8086 `e927372d`, 7779 `ecedb10c`, 7946 `2ffd8635`. - The seventh entry, `8086-chart-series-type-arm.md`, is untouched (whole-file md5 `7ea6b544` at base and head). Every sentence in it measured STILL-TRUE (see the lit control below). - No new changeset: the diff is `.changeset/` only, and `check-changeset-presence` says none is owed. | Entry | FALSE-NOW sentences, quoted | Superseding entry (PR) | Notes | | --- | --- | --- | --- | | `7924-named-list-view-retire.md` | "`NamedListView` (one entry of `ObjectViewSchema.listViews`)"; "Two bucket-③ members are NOT retired" and "They stay declared as they were." | `7928-listviews-by-reference-fold.md` (objectstack-ai#10821); `7924-density-mode-through-fold.md` (objectstack-ai#10793) | 2 | | `8355-retire-calendar-date-aliases.md` | "it now names the key and the remedy on all five authoring surfaces", for "a named view's two nestings under `listViews`"; "plus a `.check()` on `ObjectViewSchema` for a named view's two nestings"; "`ObjectViewSchema.listViews` stays UNMIRRORED" and the rest of that paragraph; "`timeline.dateField` stays a live, accepted alias", on a named view; "the structural guard that `listViews` stays out of the object's `shape`" | `7928-listviews-by-reference-fold.md` (objectstack-ai#10821) | 3 | | `10321-named-view-kanban-groupby-refused.md` | "`ObjectViewSchema.listViews` is unmirrored"; "and in its legacy `options.kanban` bag" with the issue path under `options.kanban`; "reports one issue per written key, naming the key and the replacement"; "Not changed, deliberately: `listViews` stays unmirrored" and the rest of that paragraph | `7928-listviews-by-reference-fold.md` (objectstack-ai#10821) | 2 | | `10584-object-chart-series-describe.md` | "It now says the copy is that `{ dataKey }` arm minus its per-series `type`, and that the per-series family override on an `object-chart` node is `chartType`"; "taking `type` up would widen a published accept set" | `10770-object-chart-react-tier-node.md` (objectstack-ai#10802) | 1 | | `8365-stray-kanban-groupby-refused.md` | "objectui#10321 gives that route its own door, which refuses the key in either nesting with the same message" | `7928-listviews-by-reference-fold.md` (objectstack-ai#10821) | 1 | | `9242-stray-kanban-groupby-lane-second-route.md` | "which refuses the key in either nesting with the same message"; "(a named view's `kanban` is typed as the `list-view`'s), but not the key inside the untyped `options.kanban` bag on either" | `7928-listviews-by-reference-fold.md` (objectstack-ai#10821) | 1 | | `object-view-unmirrored-keys-7779.md` (patch round 1) | the table's "still unmirrored"; "`listViews` stays unmirrored, on the ruling's own fallback clause."; "The declaration's value is the local `NamedListView`"; the 21-read / 43-unread figures; "The key therefore stays in the parity ledger … until the maintainer decides its value type" | `7928-listviews-by-reference-fold.md` (objectstack-ai#10821) | 1 | | `objectchart-schema-anchor-7946.md` (patch round 1) | the `series` half of "value types taken from their READ sites (`ChartRendererProps` for `xAxisKey` / `series`)" and of "two are INTERNAL, relay-composed (`xAxisKey`, `series` …)"; "`series` entries must be `dataKey`-shaped."; "`aggregate` is the exception, and only because the spec's own object is strict." | `10770-object-chart-react-tier-node.md` (objectstack-ai#10802) | 3 | **Placement.** Each note sits directly after the paragraph that holds the false sentence. Where two false paragraphs are adjacent, one note covers both: the first 10321 note, the 10584 note and the last 8355 note. The 8355 note after the UNMIRRORED paragraph also covers the matching clause in the `@object-ui/types` bullet above it, because both describe the same named-view check. No note cites a line address; source facts are cited by symbol and test name, and `check:new-line-citations` reads 0 new citations. ## Measured, not inherited (one-time probes, not committed) The probes ran the worktree sources at base `b2683a2c0e`, with `@objectstack/spec` 17.4.0 resolved from `packages/types`. The zod face ran through `tsx`, and the TS face through `tsc --noEmit` against `packages/types/src/index.ts`. Each probe sits beside a control that differs only by the key. A named view is `listViews.v` with `columns` set. Zod face (`ObjectViewSchema.safeParse`; `safeValidateSchema` gives the same issues on the two `kanban` rows): | Probe | Result | | --- | --- | | control `kanban: { groupByField, columns }` | parses | | `kanban.groupBy` | two issues: `unrecognized_keys` at `listViews.v.kanban` naming `groupBy`, and `custom` at `listViews.v.kanban.groupBy` | | `options: { kanban: { groupBy } }` | one issue: `unrecognized_keys` at `listViews.v` naming `options`; nothing at the `options.kanban.groupBy` path | | `calendar.dateField` | `unrecognized_keys` at `listViews.v.calendar`, and `custom` at `listViews.v.calendar.dateField` | | `options: { calendar: { dateField } }` | one issue: `options` refused | | `timeline.dateField` | `unrecognized_keys` at `listViews.v.timeline`; control `timeline: { startDateField, titleField }` parses | | each of the 16 retired `NamedListView` spellings, and `densityMode` | `unrecognized_keys` at `listViews.v` naming the key (17 of 17); control `userActions: { search: false }` parses | | `listViews` in `ObjectViewSchema.shape` | present | | list-view route: `kanban.groupBy`, `options.kanban.groupBy`, `calendar.dateField`, `options.calendar.dateField`, `timeline.dateField` | `invalid_type`, `custom`, `invalid_type`, `custom`, parses: unchanged | TS face (`tsc`): | Probe | Result | | --- | --- | | named view `kanban.groupBy` in an `ObjectViewSchema` literal | TS2353, excess property on the spec's kanban block | | named view `options` | TS2353, `options` does not exist | | named view canonical control | compiles | | `list-view` `kanban.groupBy` | TS2322 (`never`): unchanged | | `list-view` `options.kanban.groupBy` | compiles: unchanged | | a `NamedListView` value as a `listViews` entry | TS2322, not assignable | | `NamedListView` with `densityMode`; with `allowExport` | TS2322; compiles | Chart series (`ObjectChartSchema.safeParse`): `{ name, type: 'line' }` parses with `type` kept; `{ dataKey, type: 'line' }` parses with `type` stripped; `{ name, chartType }` is refused (`invalid_union`). The series `.describe()` string now names both arms. The runtime fold was read, not probed: `normalizeListViewSchema` still folds `densityMode` and the eight `show*` flags, and `ListView` still merges `options.kanban` under `kanban`. ## Lit control: STILL-TRUE, left byte-identical - `8086-chart-series-type-arm.md`, the whole entry. PR objectstack-ai#10802 changed no `plugin-charts` source (its one file there is a test). `ChartRendererProps.schema.series` still declares `type?: string` on both arms. The `ObjectChartSchema.series` docblock still says the copy of the internal arm omits `type`, and that internal arm's type is the same literal as before PR objectstack-ai#10802. - 8365, "takes the identical message through a check on that untyped bag", and the distinguishing `options.kanban` fixture. Both are the `list-view` route, measured unchanged. - 9242, "a `list-view` document carrying the key, under `kanban` or under the legacy `options.kanban` bag, is refused by `safeValidateSchema`". Measured unchanged. - 8355, the `@object-ui/types` bullet's "on the legacy `options.calendar` nesting (a check, since an open record declares no member". This is the list-view surface, measured unchanged. - 7924-retire, "`densityMode` is folded onto `rowHeight` by `normalizeListViewSchema`" and "Only the authoring face changes". The fold still does both. - 10584, "Wording only. The accepted shape does not move on either face". This is a statement about that change's own delta, and it is still true of that change. - 7779 (patch round 1): `viewTabBar` retired; the eight keys enforced; "64 declared top-level members"; the spec record requires `columns` and refuses `options`, tuple filters and `default`; "not papered over with `z.any()`"; "absent stays valid on all nine"; the ledger move 14/96 → 14/87 (that change's own delta). Each measured true at `0ea55c3701`. - 7946 (patch round 1): the `xAxisKey` half of the INTERNAL sentence (its `.describe()` still says all five producers compute it); `type: 'object-chart'` required; `chartType` must be the declared union; `normalizeChartSchema` translates the `{ name }` arm; `aggregate` `function` / `groupBy` required with unknown members refused; a misspelled key on the node itself is not refused; `filter` keeps both arms. Each measured true at `0ea55c3701`. ## Gates (re-taken at head `50deccd71a`; hand-derived from `package.json` and `.github/workflows/`; each exit captured by redirect-then-status) | Command | Verdict line | Exit | | --- | --- | --- | | `pnpm check:pending-changeset-literals` | ✅ No test source names a pending changeset. | 0 | | `node scripts/check-changeset-claims.mjs` | ✅ No pending changeset names a file this change touches. (Self-contradiction reading: every declared package across the 8 bodies is not negated.) | 0 | | `node scripts/check-changeset-presence.mjs` | ✅ No source or published contract of a released package changed in this range, so no changeset is owed. | 0 | | `node scripts/check-changeset-no-major.mjs` | ✅ No changeset declares a `major` bump. | 0 | | `node scripts/check-changeset-overwrite.mjs` | report-only: this change touches 8 changesets it did not add. The declared packages are identical at base and head for all 8, which is the prose-correction case. | 0 | | `node scripts/check-changeset-fixed.mjs` | ✅ All workspace packages are in the changeset fixed group. | 0 | | `pnpm check:new-line-citations` | VERDICT new-cross-file-line-citations: 0 new citation(s) | 0 | | `pnpm check:control-bytes` | ✅ check-control-bytes: OK | 0 | | `pnpm check:spec-symbols` | ✅ spec member citations: nothing cites a key its spec symbol does not declare. | 0 | | `pnpm check:test-path-roots` | ✅ check-test-path-roots: OK | 0 | | `node scripts/check-installed-spec-pin-claims.mjs` | OK (it excludes `.changeset/`, so it was run for completeness only) | 0 | | `node scripts/check-governed-queue-guard.mjs --test` (the 8 paths) | ✅ NOT GOVERNED | 0 | Tests, from the repo root under the shared verify lock: every `scripts/__tests__` file that names `.changeset` (derived with `git grep -l`: 24 test files, plus one fixture that is not a test), and the five `@object-ui/types` pins that re-derive what the notes state (`calendar-date-alias-refusal-8355`, `named-view-kanban-stray-group-by-10321`, `object-view-listviews-by-reference-7928`, `object-chart-react-tier-node-10770`, `object-view-unmirrored-keys-7779`). Result at `f5e0123f4b`: **Test Files 29 passed (29), Tests 1193 passed (1193)**, lock `VERDICT command-exit 0`. Re-taken at `0ea55c3701` with the 24 `scripts/__tests__` files and the four pins the new notes rest on (`object-view-unmirrored-keys-7779`, `object-chart-react-tier-node-10770`, `object-view-listviews-by-reference-7928`, `zod-mirror-parity`): **Test Files 28 passed (28), Tests 1200 passed (1200)**, lock `VERDICT command-exit 0`. Re-taken at `50deccd71a` (patch round 2): the 24 `scripts/__tests__` files plus `object-view-unmirrored-keys-7779` gave **25 files / 1146 tests**, and the four other pins (`calendar-date-alias-refusal-8355`, `named-view-kanban-stray-group-by-10321`, `object-view-listviews-by-reference-7928`, `object-chart-react-tier-node-10770`) gave **4 files / 48 tests**. Both runs gave lock `VERDICT command-exit 0`. Not applicable, with the reason: - `@object-ui/types` type-check, package vitest runs and consumer sweeps: the diff touches no package source, only `.changeset/`. - The Spec Main Shape Gate: no touched type. - ESLint `--no-inline-config` on the touched files: `eslint.config.js` has no configuration that matches `.md`. All 8 files report "File ignored because no matching configuration was supplied", so it judged nothing (NOT MEASURED). ## Acceptance notes - **Residue in the same family: closed by patch round 1.** The first round stopped on two files outside the claimed surface, `object-view-unmirrored-keys-7779.md` and `objectchart-schema-anchor-7946.md`. Each is named by a superseding PR itself. The seat extended the file surface (addendum `5862987983`, option A), and patch round 1 (`80ee15eecb`) added one note to 7779 and three to 7946, in the same form and measured the same way. `Fixes objectstack-ai#10877` stays. - **For the at-tier review.** The last 7946 note also names two changes outside the three PRs: `drillDown` (objectui#8885, PR objectstack-ai#8895) and `xAxis` / `yAxis` (objectui#10518, PR objectstack-ai#10601). Both landed after the 7946 entry, and both also make its "`aggregate` is the exception" sentence false. That sentence of the note can be dropped if the review holds it out of scope; the rest of the note stands without it. - Not measured: the wider pending population that names `listViews` / `NamedListView` or `ObjectChartSchema`. Only the entries the superseding PRs name were read. - **Source prose. These are observations and were not filed; carrier: none.** - The `ObjectChartSchema.series` TS docblock (`packages/types/src/objectql.ts`) says "A `type` written on this arm anyway is an excess property on a literal typed by this interface." Since PR objectstack-ai#10802 that is false. `{ dataKey: 'amount', type: 'line' }` compiles in an `ObjectChartSchema` literal, because the union's `{ name }` arm declares `type` (tsc probe above). The zod mirror still strips it. - The zod docblock headed "WHERE THIS ARM IS INSTALLED — TWO ROUTES, TWO NESTINGS EACH, ONE STRING" (`packages/types/src/zod/objectql.zod.ts`) still says a named view's `listViews` "is unmirrored", and it still names a `custom` issue under `options.kanban` on that route. The docblocks of `checkNamedViewKanbanStrayGroupBy` and `namedViewKindRefusals` are current. - **A dispatch premise, corrected.** "Each one already states in its own body that it supersedes the older entry" holds for `7924-density-mode-through-fold.md` and `7928-listviews-by-reference-fold.md`. `10770-object-chart-react-tier-node.md` names no superseded entry. The supersession is stated in PR objectstack-ai#10802's body ("Superseded pending changesets"), which names the objectui#10584, objectui#7946-anchor and objectui#8086 entries. - **`main` merged, twice.** `origin/main` `4f38f39286` was merged as `0ea55c3701`: the two merged commits touch none of the probed sources, and the probes re-ran byte-identical. `origin/main` `9f0c84a448` was merged as `bade176fff` (patch round 2), which carries `35d68c4c` (PR objectstack-ai#10884, objectui#10758). That merge moved probed sources (`objectql.zod.ts`, `objectql.ts`, `ChartRenderer.tsx`); the probes re-ran at `50deccd71a`, byte-identical to round 1's head outputs. Neither merge used a rebase or a force-push. - **Patch round 2 (at-tier record `5864532186`, FAIL on one note).** The 7779 note said the renderer reads 20 members and leaves 44 unread. That was true at `4f38f39286`, but PR objectstack-ai#10884 re-took the census to 43 / 21 on `main`. Per the seat's decision (REWORK `5864543090`), the note now states no figure. It says the split is no longer the 21 / 43 the entry counted, names both changes that moved it (objectui#7928 and objectui#10758), and cites the census pin in `object-view-unmirrored-keys-7779.test.ts`, which re-derives the figures on every run (`43 read + 21 unread = 64` at the head). No other note moved. - **The headline card.** Each note's headline names the card whose change supersedes the sentence, as the PR objectstack-ai#10533 notes did. PR objectstack-ai#10828's notes named their own card instead, because the cause there was a spec release that has no pending entry. - **Commit trailers are model-free** (`Co-Authored-By: Claude`), per the dispatch. The harness offered a trailer that carries a model name, and it was not used. Implemented by a `domain:spec#1` dispatch (dev subagent). Session: `https://claude.ai/code/session_014fWVhLzhxR8qrFsJ5o8TYW`. --- _Generated by [Claude Code](https://claude.ai/code/session_014fWVhLzhxR8qrFsJ5o8TYW)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
Fixes #7924
Clause-②: yes
Director ruling A′ on objectui#7924 (comment
5856690997, amending ruling A5852199633). Claim5856715104, seatdomain:spec#1, sessionsession_014fWVhLzhxR8qrFsJ5o8TYW. This PR is the card's last scope: bucket ① of ruling5690906005was split off as objectui#10758 and is not touched here.What changes
NamedListView.densityModebecomesdensityMode?: never(packages/types/src/objectql.ts, theNamedListViewblock). The tombstone docblock names top-levelrowHeight, warns offuserActions.rowHeight(the boolean toolbar toggle), and says stored views keep rendering through the fold.renderListViewcomposition in@object-ui/plugin-view'sObjectView. The two rungsrowHeight: activeView?.rowHeightanddensityMode: activeView?.densityModebecome one rung that hands the active view tonormalizeListViewSchemaand relays the result'srowHeight.@object-ui/app-shell'sObjectView(thefullSchemaliteral). The two rungsrowHeight: viewDef.rowHeight ?? listSchema.rowHeightanddensityMode: viewDef.densityMode ?? listSchema.densityModebecome one rung: the view'srowHeightread throughnormalizeListViewSchema, falling back tolistSchema.rowHeight. That is view over list, the same shape the relay'suserActionsrung already uses.allowExportstays declared. Its docblock now names both relays that carry it (plugin-view's composition and app-shell's relay), which was the omission the first dev report found.@object-ui/reactuseDensityModeJSDoc@examplenow readsrowHeightToDensityMode(activeView?.rowHeight)and persists{ rowHeight: DENSITY_MODE_TO_ROW_HEIGHT[m] }instead of{ densityMode: m }. Docblock only, no behaviour change..changeset/7924-density-mode-through-fold.md:minorfor@object-ui/typesand@object-ui/plugin-view, with the BREAKING banner, the third-partyrenderListViewhost note, and the ADR-0087 D2 disposition line.After this change, the fold is the only code in
packages/*/srcthat readsdensityModeby name (const legacyDensity = s.densityMode;anddelete next.densityMode;innormalizeListViewSchema). The zodListViewSchemalegacy-alias declaration also still names it; this ruling leaves that alone (see Acceptance notes).Premise re-verified before the first edit
The ruling's own grep, run at BASE
bf14b6460:git grep -n densityMode bf14b6460 -- 'packages/*/src/**' ':!**/__tests__/**'exits 0 with 34 hits. By class:const legacyDensity = s.densityMode;,delete next.densityMode;, 4 docblock lines)toolbar.densityModeentries, plugin-list'sgrid.toolbar.densityModedefault, 3t()calls)useDensityModeJSDoc exampleobjectql.tsdocblocks, the zod README, 1objectql.zod.tsdocblock, the zodListViewSchemaline)__tests__exclusion does not coverThe only code reads are the two hops and the fold, so the stop condition did not fire. Outside
packages/*/src,git grep densityMode -- apps examples e2e content docs skills(CHANGELOG excluded) exits 1 with no hits. The firing control on the same trees,git grep -l listViews -- appsandgit grep -l rowHeight -- content docs skills examples, does return hits.Pins
packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.ts, re-pointed with no assertion deleted:densityModemoves fromBUCKET_LOCAL_ONLY_RETAINEDintoNAMED_LIST_VIEW_TOMBSTONES(16 → 17), and the AST-derived tombstone assertion follows._DensityModeRetainedis re-pointed, not deleted. It is renamed_DensityModeTombstonedand now asserts that the member's type isundefined, with a comment recording what it used to assert.@ts-expect-errorrefusal,_refusedDensityMode, is added, together with_acceptedDensityCanonical(rowHeight: 'compact'accepted on a named view)._acceptedRetaineddropsdensityMode.densityMode is RETAINEDcase becomesdensityMode is RETIRED by ruling A′. It asserts that the by-name line is absent at both relays, that the fold-through line is present at both (the firing control on the same files), and that the fold still names the key.rowHeightand warns offuserActions.rowHeight.rowHeight: activeView?.rowHeight,. It now asserts the fold-through spelling offactiveView. The claim it carries (rowHeightis read offactiveView, not off a named view) is unchanged.packages/app-shell/src/views/ObjectView.relayRungCensus-7559.test.ts: a newdensityModerow,{ kind: 'legacy-alias', canonical: 'rowHeight', mentions: 'normalizeListViewSchema' }. Its evidence check requires therowHeightrung to read the view AND to callnormalizeListViewSchema. TheshowDensityrow's reason no longer mentions adensityModerung.packages/app-shell/src/views/ObjectView.densityModeThroughFold-7924.test.tsx, the retirement pin for H1. It mounts the real plugin-viewObjectViewunder the real object page, stubs onlyListViewto capture its schema, and pins plugin-view on its own through a spyrenderListView. The effective density isnormalizeListViewSchema(schema).rowHeight, which is whatListViewrenders. The file has 8 cases: 4 per host (SAME DENSITY×2,THE CHANGE,CONTROL).Tests
All at HEAD
dd43c757c(git rev-parse --short HEAD), run after the final commit. Every exit code was captured before any pipe.Build first.
pnpm exec turbo run build --filter="@object-ui/app-shell^..." --concurrency=2built the dependency closure of all six consumer packages:Tasks: 28 successful, 28 total, lock VERDICTcommand-exit 0.@object-ui/types/coreand its downstream consumers)type-checkpnpm exec vitest run packages/PKG/@object-ui/types@object-ui/core(the fold)@object-ui/react@object-ui/plugin-list@object-ui/plugin-view@object-ui/app-shelltsc -p tsconfig.test.json --listFilesconfirms that the test projects type-check the edited pins: the types project includes the 7779 test, and the app-shell project includes both the census and the new file. So the@ts-expect-errorrefusal is compiled, not skipped.ESLint
--no-inline-config --format jsonon the 7 touched TS/TSX files: 7 file results, 0 errors, 274 warnings (no-explicit-anyand the other pre-existing warning rules; this repo's lint workflow sets no--max-warnings). This narrowing is a proof, not a skip:eslint.config.jsenables no type-aware linting (noparserOptions.projectorprojectService), and no local rule undereslint-rules/reads the disk. So this diff cannot move the verdict on any untouched file.Gates: each exited 0.
node scripts/check-changeset-presence.mjs(7 source files of 4 released packages changed, 1 changeset declared)node scripts/check-changeset-no-major.mjspnpm check:new-line-citations(VERDICT 0 new citations)pnpm check:control-bytespnpm check:spec-symbolspnpm check:test-path-rootsnode scripts/check-governed-queue-guard.mjs --teston the 8 changed paths (NOT GOVERNED)A control-byte self-scan of the changed files and this body found nothing.
Reverse verification (both from the committed HEAD
dd43c757c, every mutation throughablation-replace.mjswith its EXIT/INT/TERM restore, and every restore proven by blob hash equal to HEAD with an emptygit diff HEAD)1. The relays. Both by-name hop lines were restored on top of HEAD, which is the BASE shape of the two hops. The anchors hit x1 → x0, and on-disk
grep -cof each restored line read 1. Predicted before the run: exactly the twoTHE CHANGEcases red, the censusdeclares nothing that IS relayedandlegacy-aliaschecks red, and the 7779densityMode is RETIREDcase and counter-control red, so 6 red in total. EverySAME DENSITYandCONTROLcase stays green, because the fold insideListViewgives the same density on either shape.Measured:
Tests 6 failed | 256 passed (262). The 6 failures were exactly the 6 predicted cases, by name. All 6SAME DENSITY/CONTROLcases in the new file stayed green, and that is the H1 pin: a storeddensityMode: 'compact'view yields the same effectiverowHeightat both hosts as it did on BASE. Both restores were proven.2. The type face.
@object-ui/app-shellheld aNamedListViewliteral carryingdensityMode: 'compact', and app-shell'stsc --noEmitran against the rebuilt@object-ui/types. Result:error TS2322: Type 'string' is not assignable to type 'undefined'. The probe was removed by a trap, andgit statuswas clean afterwards._EveryTombstoneAdmitsOnlyAbsenceTS2344,_DensityModeTombstonedTS2344, and_refusedDensityModeTS2578 (unused@ts-expect-error). The restore was proven.Acceptance notes
ListViewSchemainpackages/types/src/zod/objectql.zod.tsstill declaresdensityModeas its legacy-alias line, andlist-view-spec-parity.test.tsstill ledgers it as input-only.NamedListViewhas no zod mirror, so the tombstone is on the TypeScript face only. This PR leaves the zod line as ruled.viewDef(app-shell) and the plugin-viewviewselement areany-indexed, so the tombstone forced neither hop at compile time. Both hops were moved by hand, and the text pins above hold them.renderListViewhosts (read from source, not run). On BASE, a host whose list schema carried its ownrowHeightbeat a view that spelled its densitydensityMode: the relay merged the two into one schema, and the fold's rule "canonical wins" picked the host's value. Hop 2 now folds the view first and then applies view over list, so the view's density wins. In the Console this cannot arise, because the host is plugin-view's composition and itsrowHeightcomes from the same active view. The effective-density pins above were measured on that path. The changeset also says that a third-party host readingschema.densityModenow receivesschema.rowHeight..changeset/7924-named-list-view-retire.md, from PR objectui#10285, still pending release) saysdensityModestays declared. This PR's changeset says in its body that it supersedes that line. The older file is outside this claim's file surface and is left untouched; the seat may prefer to amend it before release.normalize-list-view.tsneeded no docblock change. Its fold behaviour is unchanged.legacyDensity in DENSITY_MODE_TO_ROW_HEIGHT, andinwalks the prototype chain. Measured on the built@object-ui/core:normalizeListViewSchema({ densityMode: 'toString' })returns arowHeightof typefunctionand drops the key, while the control'cozy'stays unfolded.rowHeightToDensityModefixed the same shape in the other direction withhasOwnProperty. No producer writes such a value, so no public door gives a wrong answer, and it is noted here rather than filed.ObjectChartSchemablock ofobjectql.ts, a disjoint region. objectui#10758 will edit plugin-view's delegation, a different region of the same file. Whichever lands later mergesmain.densityModeis not spec-derived), and the gate needs a spec tarball built from objectstackmain. CI runs it.Co-Authored-By. No pushed history was rewritten.Generated by Claude Code