Skip to content

feat(types,plugin-view,app-shell)!: retire NamedListView.densityMode; both relays read the density through the fold (objectui#7924) - #10793

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-7924-density-mode-through-fold
Sep 28, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-7924-density-mode-through-fold

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #7924
Clause-②: yes

Director ruling A′ on objectui#7924 (comment 5856690997, amending ruling A 5852199633). Claim 5856715104, seat domain:spec#1, session session_014fWVhLzhxR8qrFsJ5o8TYW. This PR is the card's last scope: bucket ① of ruling 5690906005 was split off as objectui#10758 and is not touched here.

What changes

  • NamedListView.densityMode becomes densityMode?: never (packages/types/src/objectql.ts, the NamedListView block). The tombstone docblock names top-level rowHeight, warns off userActions.rowHeight (the boolean toolbar toggle), and says stored views keep rendering through the fold.
  • Hop 1, the renderListView composition in @object-ui/plugin-view's ObjectView. The two rungs rowHeight: activeView?.rowHeight and densityMode: activeView?.densityMode become one rung that hands the active view to normalizeListViewSchema and relays the result's rowHeight.
  • Hop 2, the object-page relay in @object-ui/app-shell's ObjectView (the fullSchema literal). The two rungs rowHeight: viewDef.rowHeight ?? listSchema.rowHeight and densityMode: viewDef.densityMode ?? listSchema.densityMode become one rung: the view's rowHeight read through normalizeListViewSchema, falling back to listSchema.rowHeight. That is view over list, the same shape the relay's userActions rung already uses.
  • allowExport stays 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/react useDensityMode JSDoc @example now reads rowHeightToDensityMode(activeView?.rowHeight) and persists { rowHeight: DENSITY_MODE_TO_ROW_HEIGHT[m] } instead of { densityMode: m }. Docblock only, no behaviour change.
  • Changeset .changeset/7924-density-mode-through-fold.md: minor for @object-ui/types and @object-ui/plugin-view, with the BREAKING banner, the third-party renderListView host note, and the ADR-0087 D2 disposition line.

After this change, the fold is the only code in packages/*/src that reads densityMode by name (const legacyDensity = s.densityMode; and delete next.densityMode; in normalizeListViewSchema). The zod ListViewSchema legacy-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:

class hits
app-shell relay (the code line and 1 comment) 2
plugin-view composition (the code line and 1 comment) 2
the fold (const legacyDensity = s.densityMode;, delete next.densityMode;, 4 docblock lines) 6
label namespace (10 locale toolbar.densityMode entries, plugin-list's grid.toolbar.densityMode default, 3 t() calls) 14
plugin-list comment 1
useDensityMode JSDoc example 2
types (the member, 2 objectql.ts docblocks, the zod README, 1 objectql.zod.ts docblock, the zod ListViewSchema line) 6
the co-located app-shell relay census test, which the __tests__ exclusion does not cover 1

The 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 -- apps and git 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:
    • densityMode moves from BUCKET_LOCAL_ONLY_RETAINED into NAMED_LIST_VIEW_TOMBSTONES (16 → 17), and the AST-derived tombstone assertion follows.
    • The type pin _DensityModeRetained is re-pointed, not deleted. It is renamed _DensityModeTombstoned and now asserts that the member's type is undefined, with a comment recording what it used to assert.
    • A new @ts-expect-error refusal, _refusedDensityMode, is added, together with _acceptedDensityCanonical (rowHeight: 'compact' accepted on a named view). _acceptedRetained drops densityMode.
    • The densityMode is RETAINED case becomes densityMode 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.
    • The bucket-③ intent case now also asserts that the tombstone text names top-level rowHeight and warns off userActions.rowHeight.
    • The named-view counter-control used to assert the literal text rowHeight: activeView?.rowHeight,. It now asserts the fold-through spelling off activeView. The claim it carries (rowHeight is read off activeView, not off a named view) is unchanged.
  • packages/app-shell/src/views/ObjectView.relayRungCensus-7559.test.ts: a new densityMode row, { kind: 'legacy-alias', canonical: 'rowHeight', mentions: 'normalizeListViewSchema' }. Its evidence check requires the rowHeight rung to read the view AND to call normalizeListViewSchema. The showDensity row's reason no longer mentions a densityMode rung.
  • New: packages/app-shell/src/views/ObjectView.densityModeThroughFold-7924.test.tsx, the retirement pin for H1. It mounts the real plugin-view ObjectView under the real object page, stubs only ListView to capture its schema, and pins plugin-view on its own through a spy renderListView. The effective density is normalizeListViewSchema(schema).rowHeight, which is what ListView renders. 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=2 built the dependency closure of all six consumer packages: Tasks: 28 successful, 28 total, lock VERDICT command-exit 0.

package (direction: the edited @object-ui/types / core and its downstream consumers) type-check pnpm exec vitest run packages/PKG/
@object-ui/types exit 0 exit 0 · Test Files 247 passed · Tests 5345 passed
@object-ui/core (the fold) exit 0 exit 0 · Test Files 175 passed · Tests 3534 passed
@object-ui/react exit 0 exit 0 · Test Files 99 passed · Tests 1333 passed
@object-ui/plugin-list exit 0 exit 0 · Test Files 102 passed · Tests 1169 passed
@object-ui/plugin-view exit 0 exit 0 · Test Files 51 passed · Tests 485 passed
@object-ui/app-shell exit 0 exit 0 · Test Files 830 passed, 1 skipped · Tests 8408 passed, 9 skipped

tsc -p tsconfig.test.json --listFiles confirms 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-error refusal is compiled, not skipped.

ESLint --no-inline-config --format json on the 7 touched TS/TSX files: 7 file results, 0 errors, 274 warnings (no-explicit-any and the other pre-existing warning rules; this repo's lint workflow sets no --max-warnings). This narrowing is a proof, not a skip:

  • The population is the 7 touched files, all linted: none was reported as ignored.
  • eslint.config.js enables no type-aware linting (no parserOptions.project or projectService), and no local rule under eslint-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.mjs
  • pnpm check:new-line-citations (VERDICT 0 new citations)
  • pnpm check:control-bytes
  • pnpm check:spec-symbols
  • pnpm check:test-path-roots
  • node scripts/check-governed-queue-guard.mjs --test on 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 through ablation-replace.mjs with its EXIT/INT/TERM restore, and every restore proven by blob hash equal to HEAD with an empty git 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 -c of each restored line read 1. Predicted before the run: exactly the two THE CHANGE cases red, the census declares nothing that IS relayed and legacy-alias checks red, and the 7779 densityMode is RETIRED case and counter-control red, so 6 red in total. Every SAME DENSITY and CONTROL case stays green, because the fold inside ListView gives 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 6 SAME DENSITY / CONTROL cases in the new file stayed green, and that is the H1 pin: a stored densityMode: 'compact' view yields the same effective rowHeight at both hosts as it did on BASE. Both restores were proven.

2. The type face.

  • (a) Consumer probe. A new file in @object-ui/app-shell held a NamedListView literal carrying densityMode: 'compact', and app-shell's tsc --noEmit ran against the rebuilt @object-ui/types. Result: error TS2322: Type 'string' is not assignable to type 'undefined'. The probe was removed by a trap, and git status was clean afterwards.
  • (b) Tombstone widened back to the old three-value union. Predicted: 3 errors. Measured: _EveryTombstoneAdmitsOnlyAbsence TS2344, _DensityModeTombstoned TS2344, and _refusedDensityMode TS2578 (unused @ts-expect-error). The restore was proven.

Acceptance notes

  • H2 (not this ruling). The zod ListViewSchema in packages/types/src/zod/objectql.zod.ts still declares densityMode as its legacy-alias line, and list-view-spec-parity.test.ts still ledgers it as input-only. NamedListView has no zod mirror, so the tombstone is on the TypeScript face only. This PR leaves the zod line as ruled.
  • H3 held false, as the first report found. viewDef (app-shell) and the plugin-view views element are any-indexed, so the tombstone forced neither hop at compile time. Both hops were moved by hand, and the text pins above hold them.
  • One precedence delta, confined to third-party renderListView hosts (read from source, not run). On BASE, a host whose list schema carried its own rowHeight beat a view that spelled its density densityMode: 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 its rowHeight comes from the same active view. The effective-density pins above were measured on that path. The changeset also says that a third-party host reading schema.densityMode now receives schema.rowHeight.
  • The changeset from the earlier landing (.changeset/7924-named-list-view-retire.md, from PR objectui#10285, still pending release) says densityMode stays 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.ts needed no docblock change. Its fold behaviour is unchanged.
  • Observation, not filed (承接者:无). The fold tests legacyDensity in DENSITY_MODE_TO_ROW_HEIGHT, and in walks the prototype chain. Measured on the built @object-ui/core: normalizeListViewSchema({ densityMode: 'toString' }) returns a rowHeight of type function and drops the key, while the control 'cozy' stays unfolded. rowHeightToDensityMode fixed the same shape in the other direction with hasOwnProperty. No producer writes such a value, so no public door gives a wrong answer, and it is noted here rather than filed.
  • Concurrency. objectui#10770 edits the ObjectChartSchema block of objectql.ts, a disjoint region. objectui#10758 will edit plugin-view's delegation, a different region of the same file. Whichever lands later merges main.
  • Spec Main Shape Gate: NOT MEASURED locally. The reason: the touched member is objectui-own (densityMode is not spec-derived), and the gate needs a spec tarball built from objectstack main. CI runs it.
  • Commit trailers are model-free. The local commit was amended once, before its first push, to drop a model name from Co-Authored-By. No pushed history was rewritten.

Generated by Claude Code

… 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
@github-actions

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 24 pending changeset(s) describe a file this change touches

Their bodies publish verbatim into the CHANGELOG at the next release, so this is a request to re-read them against your diff — addressed here because you are the one seat that can answer it without re-deriving anything.

⛔ Nothing here blocks, and nothing here is a verdict on your change. This gate exits 0, is not a required context, and judges name resolution, never meaning: it asked whether a pending body names a file you touched. "Is this sentence still true?" is the one question it will not answer, and the one you are being asked to answer.

.changeset/5903-objectgantt-declared-keys.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    Both halves move together. The TS declaration (packages/types/src/objectql.ts) and its zod mirror (src/zod/objectql.zod.ts) gain the same ten keys at the same requiredness — all optional — and no KnownDrift entry is added. navigation is taken from @objectstack/spec's NavigationConfigSchema by reference rather than restated, matching ObjectGridSchema.navigation.

.changeset/6726-find-envelope-records-arms.md

  • names plugin-view/src/ObjectView.tsx → packages/plugin-view/src/ObjectView.tsx — edited by this change

    | module | what it does | | --- | --- | | components/src/hooks/related-count-store.ts | related-list tab badge count | | components/src/renderers/basic/data-list.tsx | element:repeater rows | | components/src/renderers/basic/elements.tsx | element:number client-side aggregate | | components/src/renderers/basic/record-picker.tsx | element:record_picker options | | plugin-detail/src/renderers/record-activity.tsx | record:activity self-fetch | | plugin-detail/src/renderers/record-history.tsx | record:history self-fetch | | plugin-view/src/ObjectView.tsx | non-grid (kanban / calendar / gallery / timeline) fetch |

.changeset/7070-no-invented-gantt-date-fields.md

  • names app-shell/src/views/ObjectView.tsx → packages/app-shell/src/views/ObjectView.tsx — edited by this change

    • app-shell/src/views/ObjectView.tsx — the console object page. The inline branch becomes ganttViewOptions, the sibling of calendarViewOptions and timelineViewOptions: the declared block spread whole, title floored at 'name', no date field invented. - plugin-list/src/ListView.tsx — the render branch AND the capability gate. - plugin-view/src/ObjectView.tsx — generateViewSchema, the authored object-view element route, which bypasses ListView entirely.
  • names plugin-view/src/ObjectView.tsx → packages/plugin-view/src/ObjectView.tsx — edited by this change

    • app-shell/src/views/ObjectView.tsx — the console object page. The inline branch becomes ganttViewOptions, the sibling of calendarViewOptions and timelineViewOptions: the declared block spread whole, title floored at 'name', no date field invented. - plugin-list/src/ListView.tsx — the render branch AND the capability gate. - plugin-view/src/ObjectView.tsx — generateViewSchema, the authored object-view element route, which bypasses ListView entirely.

.changeset/7322-object-kanban-group-by-limit.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    Breaking for authored metadata: ObjectKanbanSchema.groupField is RETIRED (objectui#7322, ADR-0049 enforce-or-remove), and the two keys the object-kanban renderer actually reads — groupBy and limit — are now DECLARED and validated on both published faces: the TypeScript interface in objectql.ts and the Zod mirror in zod/objectql.zod.ts.

.changeset/7363-objectql-union-arms.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectGallerySchema and ObjectDataTableSchema are members of ObjectQLComponentSchema on both faces — the TS union in objectql.ts and the zod union in zod/objectql.zod.ts — so AnyComponentSchema, and with it validateSchema / safeValidateSchema / objectui validate, has an arm for object-gallery and object-data-table nodes (objectui#7363).

.changeset/7499-gantt-non-axis-floors-omitted.md

  • names plugin-view/src/ObjectView.tsx → packages/plugin-view/src/ObjectView.tsx — edited by this change

    • plugin-list/src/ListView.tsx — the object-gantt render branch. - plugin-view/src/ObjectView.tsx — generateViewSchema, the authored object-view element route, which bypasses ListView entirely.

.changeset/7632-shared-record-source-config.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    That ladder is published contract on both faces — packages/types/src/objectql.ts and its zod mirror both ship .describe() strings naming getDataConfig's order (objectui#6939, maintainer ruling 2026-09-02), pinned by objectql-record-source-refinement-6939.test.ts — and it was hand-copied into five plugin components with no gate holding them together. A change to the ruled order had five edit sites and nothing that noticed a missed one; that is the AGENTS.md #0.1 drift class.

.changeset/7804-objectql-handler-key-arms.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    The four plain objectql.ts node faces declare the nine handler keys their registered renderers read (objectui#7804, the objectql.ts slice): ObjectFormSchema.onCancel / .onError / .onOpenChange / .onStepChange / .onSuccess, ObjectGallerySchema.onCardClick / .onRowClick, ObjectGridSchema.onNavigate and ObjectViewSchema.onNavigate.

.changeset/7804-tree-view-handler-slot.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    'runtime-slot' and not 'retired', measured at this key's own channel. 'retired' publishes "no renderer reads this key, so nothing could ever run it" — true of the two siblings already tombstoned on this arm (onSelectChange, onExpandChange) and flatly false here, since the read is live and INVOKED. ⚠️ No in-repo host builds a tree-view node carrying the key: the channel is wired end to end and only the supplier is absent, which is the same shape as ObjectFormSchema.onStepChange in this card's objectql.ts slice and is not evidence of a dead read. The TypeScript declaration is unchanged and still callable, so a programmatic host supplies it exactly as before.

.changeset/7963-alert-dialog-footer-keys-retired.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    Nothing else moves. These spellings are overloaded across the tree and every other owner is a live key on a different declaration — FormSchema.cancelLabel, objectql.ts's confirmLabel, plugin-designer's ConfirmDialog React props, plugin-grid's def.confirmLabel, and plugin-form's ModalForm / DrawerForm, which build a local cancelLabel from schema.cancelText. None is an AlertDialogSchema; none is touched, and a pin asserts it. No fixture, catalog schema, example app or doc fence authored any of the three on an alert-dialog node, so no shipped document is stranded.

.changeset/8653-listview-title-retired-rowactiondefs-pinned.md

  • names packages/plugin-view/src/ObjectView.tsx → packages/plugin-view/src/ObjectView.tsx — edited by this change

    title — retired. ListView resolved its export filename through schema.label || (schema as any).title. @objectstack/spec/ui's ListViewSchema refuses title by name (unrecognized_keys: ['title']) while ObjectGridPropsSchema accepts it; packages/types mirrors the platform contract rather than ruling over it, so declaring title on ListViewSchema would have made this repo accept what the platform save gate rejects. That asymmetry is also why objectui#6639 could take the declare branch for ObjectGridSchema.title one package over and this site could not. A parse-based census of apps/ examples/ content/ and packages/ found zero list-view nodes authoring title, so the retirement costs no author a filename. Over that same corpus the instrument reports three object-grid nodes carrying the key: two authored ones, both in content/docs/api/schema-reference.md, plus one that is not authored at all — packages/plugin-view/src/ObjectView.tsx composes title: schema.table?.title onto a grid node it builds, so it is a producer writing the key rather than an author declaring it. ObjectGrid's own title reads are untouched — they remain declared, ruled and read.

.changeset/8767-object-grid-refuses-string-sort.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    Migration. Write the array: sort: [{ field: 'name', order: 'desc' }]. Both keys are required. SortConfig.order carries no ? in @object-ui/types (packages/types/src/objectql.ts) and no .optional() in its zod mirror, and the protocol's own reusable SortItemSchema requires order as well — measured: that schema refuses [{ field: 'name' }] with invalid_value at 0.order. Do not omit it: this block's array arm interpolates whatever is present, so an omitted order lowers to $orderby: 'name undefined' today. That is pre-existing behaviour on the arm this change does not touch, and it is filed as a successor card rather than widened into here.

.changeset/8801-object-kanban-allow-collapse-retired.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    • the declarations retired here — packages/types/src/objectql.ts and its mirror packages/types/src/zod/objectql.zod.ts; - the pins that assert the retirement — object-kanban-allow-collapse-retired-8801.test.ts and bare-kanban-node-key-retired-8802.test.ts; - a comment in packages/types/src/zod/complex.zod.ts, recording that the deleted retiredZeroReadKanbanKey helper once carried this spelling on the SIBLING arm; - one row of content/docs/api/schema-reference.md; - the .changeset/ release notes that discuss it — this one, the two historical entries covering the sibling arm's own spelling, and objectui#9629's note recording the correction to this paragraph.

.changeset/8885-object-chart-drilldown-title-compareto.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectChart.tsx reads all three off schema, and until now neither published copy declared any of them: not the TS interface (packages/types/src/objectql.ts) and not the zod mirror (packages/types/src/zod/objectql.zod.ts). They rode BaseSchema's index signature / .passthrough() and arrived unvalidated. drillDown was the sharpest case — this component's registry inputs advertise it to the designer palette, and @objectstack/spec publishes ChartDrillDownSchema for exactly this carrier, so an author was offered a key that neither published shape mentioned.

.changeset/8913-object-kanban-columns-declared.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    What moved. ObjectKanbanSchema gains columns on both halves that move together — the TypeScript interface (objectql.ts) and its Zod mirror (zod/objectql.zod.ts). Retiring the bare kanban node type key (objectui#8802) removed the only face that judged a lane, and object-kanban had never declared the key, so it rode BaseSchema's [key: string]: any / .passthrough(): read by the renderer at three sites, named by no published face.

.changeset/8990-object-kanban-groupby-optional.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    @objectstack/spec declares the key optional — groupBy: z.string().optional() on ObjectKanbanPropsSchema — while this package required it on the TypeScript declaration (packages/types/src/objectql.ts) and on the Zod mirror (packages/types/src/zod/objectql.zod.ts). objectui was therefore narrower than the protocol on a published key: ObjectKanbanSchema.safeParse and safeValidateSchema refused an object-kanban node the protocol accepts, and such a node could not be annotated with its own type.

.changeset/9092-inline-locale-declared-face.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    • AppComponentSchema.label (app.ts) - ObjectGridSchema.label and .description (objectql.ts) - PageNodeSchema.aria.ariaLabel (layout.ts)

.changeset/9309-object-gallery-filter-destination-typed.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectGallerySchema.filter is typed as the destination its own docblock names — QueryParams['$filter'] — on both faces, the TS interface in objectql.ts and the zod mirror in zod/objectql.zod.ts (objectui#9309).

.changeset/9511-record-id-is-a-string.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    The three authorable keys, each on BOTH faces. ObjectFormSchema.recordId (objectql.ts + zod/objectql.zod.ts), DetailViewSchema.resourceId (views.ts + zod/views.zod.ts) and DetailSchema.resourceId (crud.ts + zod/crud.zod.ts). ⚠️ The crud pair is DetailSchema, not DetailViewSchema, and it reaches the same renderer — not by symbol but by data flow: plugin-detail registers the 'detail' node type onto DetailView. A read that follows TypeScript symbols alone finds two keys and is incomplete.

.changeset/9549-tree-filter-declared.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectTreeSchema.filter is declared on both faces, in the shape objectui#9309 settled for ObjectGallerySchema.filter: QueryParams['$filter'] by indexed access on the TS interface in objectql.ts, and the same two-arm union (array first) on the zod mirror in zod/objectql.zod.ts (objectui#9549).

.changeset/9550-object-tree-root-barrel.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectQLComponentSchema declares the node types an ObjectQL block may be. Every one of its arms was a named export of this package's root barrel except ObjectTreeSchema, which was declared in objectql.ts, applied by the union, and re-exported by the ./zod barrel (objectui#7917) — while no TypeScript consumer could name it. There is no ./objectql subpath to reach around the barrel: the package's exports map is pinned by packages/types/src/__tests__/package-exports-manifest.test.ts, and the root barrel was the only route to this type.

.changeset/9606-object-kanban-card-title.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    Both published faces of the object-kanban arm now name the key: the zod mirror ObjectKanbanSchema in zod/objectql.zod.ts and its TypeScript twin, the ObjectKanbanSchema interface in objectql.ts. Both declare it OPTIONAL, at the same requiredness the other face uses, so the two faces accept and refuse the same documents. (Located and cited by SYMBOL: line addresses in zod/objectql.zod.ts have drifted before, and this change is itself about a drifted mirror.)

.changeset/9628-kanban-column-collapsed-honoured.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    The key was declared on both published faces of the object-kanban arm — the lane element of ObjectKanbanSchema (objectql.ts and its Zod mirror) and the runtime lane KanbanColumn (complex.ts and its mirror) — and read by KanbanEnhanced alone, a module no production source imports. An authored { "id": "todo", "title": "To Do", "collapsed": true } therefore parsed green on both faces and reached a board that did nothing with it: KanbanImpl's only collapse is the SWIMLANE row's, held in viewer state under objectui:kanban-collapsed:ANGLE-BRACKETS(swimlaneField) and never keyed to a lane's declared value. That is the ADR-0049 declared-but-unhonoured shape.

.changeset/object-view-unmirrored-keys-7779.md

  • names packages/plugin-view/src/ObjectView.tsx → packages/plugin-view/src/ObjectView.tsx — edited by this change

    What was measured. Every reading was taken on the object-view node renderer (packages/plugin-view/src/ObjectView.tsx, registered by plugin-view/src/index.tsx) with schema.objectName / schema.layout as the positive controls of the same schema.KEY query, so each zero is a reading; the repo-wide census of viewTabBar finds the key in no source file outside @object-ui/types (two doc tables listed it as authorable and are corrected here). The spec side was read through the installed pin (@objectstack/spec@17.2.0, ui entry, 117 exported object schemas walked; control keys objectName / columns / navigation / listViews hit): the three spec-modelled keys are optional slots on ListViewSchema and ObjectListViewSchema; the six local keys have no spec slot anywhere.

Read the paragraph, not the line: both false halves of the objectui#8617 claim sat in one paragraph, and correcting either alone would have left it asserting the same wrong thing.

If a claim did go false, correct the body. That is precedented and prose-only, frontmatter untouched; check-changeset-overwrite.mjs will report the correction as its own case 2 ("correcting a declaration on purpose … legitimate"), which is the intended shape — one gate asks for the read, the other records the write.

Not covered, stated so nobody reads this as more: a born-false claim that spells no line address at all (objectui#9495 coordinated one by ORDINAL — "a grep finds that member first" — and deciding that means reading what the sentence means), a claim spelled as a symbol or a package rather than a backticked file name, and a file named ambiguously.

Angle-bracketed names in the quoted prose above are rewritten as ANGLE-BRACKETS(name): GitHub deletes tag-shaped fragments from a stored body, and a quote that silently loses the identifier it is about is worse than a visible repair.

Compared the checked-out tree with dac022c4e (merge-base with origin/main): 7 file(s) changed outside .changeset/, read against 1591 pending declaration(s) that publish a body (2179 pending in total). · run

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3068.8 KB 3104.5 KB
Main entry chunk (gzip) 148.3 KB 350 KB
Entry file index-DZg4pI6d.js —
Status PASS —

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

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.57KB 6.15KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.17KB 10.58KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.52KB 3.45KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.13KB 7.95KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 554.95KB 132.67KB
core (index.js) 9.57KB 3.81KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 224.98KB 62.48KB
fields (index.js) 259.68KB 65.89KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.28KB 11.09KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.93KB
plugin-calendar (index.js) 51.65KB 14.69KB
plugin-charts (index.js) 83.58KB 22.75KB
plugin-chatbot (index.js) 198.40KB 47.22KB
plugin-dashboard (index.js) 134.11KB 35.62KB
plugin-designer (index.js) 216.25KB 44.39KB
plugin-detail (index.js) 233.23KB 61.74KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 158.35KB 40.47KB
plugin-gantt (index.js) 169.75KB 41.96KB
plugin-grid (index.js) 218.12KB 59.72KB
plugin-kanban (index.js) 48.43KB 15.11KB
plugin-list (index.js) 114.70KB 28.42KB
plugin-map (index.js) 22.90KB 7.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.55KB 11.99KB
plugin-timeline (index.js) 30.91KB 9.05KB
plugin-tree (index.js) 10.58KB 3.72KB
plugin-view (index.js) 87.81KB 22.00KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 116.21KB 38.14KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.03KB 1.86KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 7.50KB 3.05KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.16KB 2.71KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 18.27KB 6.20KB
types (ai.js) 4.11KB 2.06KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 17.15KB 6.32KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review ABSENT at head dd43c757c, so this PR stays draft and out of the queue. domain:spec#1 @ objectui · session_014fWVhLzhxR8qrFsJ5o8TYW · 2026-09-27T15:24Z.

  • Where the PR stands. It executes director ruling A′ (5856690997) in 8 files, all inside claim 5856715104, and it is Clause-②: yes. The dev's report is on the card. The premise grep found no third code read. The reverse verification reddens exactly the 6 named cases. The type face gives TS2322 on a consumer literal and TS2344 ×2 / TS2578 on a widened tombstone.
  • Why no record. The isolated at-tier reviewer could not start: its model returned HTTP 429, 「reached your Fable limit」. Under the contract-review rule, a reviewer that cannot start means the review is absent. The PR carries needs:contract-review and stays draft. The only bypass is the maintainer reviewing it personally.
  • Seat decision on the dev's open question (the earlier .changeset/7924-named-list-view-retire.md says densityMode stays declared): B, leave it as written. This PR's changeset states in its body that it 「supersedes the earlier objectui#7924 entry in this release」. Editing another PR's pending changeset trips the check-changeset-overwrite report and would cost a patch round for a sentence the new entry already corrects.

Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: dd43c757c8cae27fd56e3863dd337259d697963c

① Derived judgments

Diff read three-dot against objectui origin/main a7fd877c3c (merge-base bf14b64608): 8 files, +402 / −55. The PR implements director ruling A′ on objectui#7924 (5856690997, amending 5852199633); the reviewer is the session that ruled, the implementer is the domain:spec#1 seat's dev on the branch below.

  1. Public surface: one declaration narrows, exactly as ruled. NamedListView.densityMode becomes densityMode?: never (packages/types/src/objectql.ts:2369); its docblock names top-level rowHeight and warns off userActions.rowHeight (the boolean toolbar toggle). allowExport stays declared, its docblock now naming both relays. Emitted .d.ts: a TS author writing densityMode fails at the key (pins: _DensityModeTombstoned = Expect<Equal<NamedListView['densityMode'], undefined>>, the @ts-expect-error _refusedDensityMode, the accepted _acceptedDensityCanonical with rowHeight). No zod face changes: NamedListView has no mirror, and the list-view node's own ListViewSchema legacy alias (objectql.zod.ts:1456) is outside the card and left as ruled.
  2. Both relay hops read through the fold. plugin-view ObjectView.tsx:2402: rowHeight: (normalizeListViewSchema(activeView ?? {}) …).rowHeight, the densityMode: rung deleted; app-shell ObjectView.tsx:2719-2721: normalizeListViewSchema(viewDef ?? {}).rowHeight ?? listSchema.rowHeight, view over list, the same shape as the userActions rung. At head, git grep densityMode over packages/*/src non-test code lights only the fold (normalize-list-view.ts:449, :517), the tombstone, the list-view zod alias, i18n label keys and prose — the ruling's own premise, re-run first-hand.
  3. Stored views render the same density. The fold is unchanged (DENSITY_MODE_TO_ROW_HEIGHT). The new pin ObjectView.densityModeThroughFold-7924.test.tsx mounts the real plugin-view ObjectView under the real object page, stubs only ListView, and holds 8 cases: a stored densityMode: 'compact' renders compact on both hosts; 'spacious' arrives at ListView as rowHeight: 'tall' with no densityMode key; an authored rowHeight still wins over a legacy densityMode on the same view; a view with no density hands down none, and an off-vocabulary 'cozy' is not coerced. The THE CHANGE cases go red if either hop's by-name rung is restored; the SAME DENSITY cases go red if the fold is bypassed.
  4. Census pins re-pointed, none deleted. relayRungCensus-7559: a densityMode row legacy-alias → rowHeight, evidence requiring the rowHeight rung to read the view and call normalizeListViewSchema; object-view-unmirrored-keys-7779: tombstones 16 → 17, BUCKET_LOCAL_ONLY_RETAINED = ['allowExport'], the text assertions on both relays inverted to the fold-through spelling, the bucket-③ intent case asserting the tombstone text.
  5. The one behaviour delta is confined and written down. A third-party renderListView host that read schema.densityMode off its argument now receives the same density as schema.rowHeight and no densityMode key; and hop 2 now folds the view before applying view-over-list, where before a host list schema's own rowHeight could beat a view's legacy densityMode. Unreachable in the Console (the host's rowHeight comes from the same active view); stated in the changeset and the PR. Accepted: it is the ruled shape.
  6. useDensityMode JSDoc reads rowHeightToDensityMode(activeView?.rowHeight) and persists { rowHeight: DENSITY_MODE_TO_ROW_HEIGHT[m] }; both are exported by @object-ui/core (normalize-list-view.ts:36, :83). Docblock only.
  7. Mergeability and CI. git merge-tree --write-tree origin/main refs/pull/10793/head at a7fd877c3c exits 0; pairwise with PR feat(types): ObjectChartSchema accepts the react tier's object-chart node — the spec's { name } series arm, family as specType (objectui#10770) #10802 also clean; with PR feat(types,plugin-view,app-shell)!: ObjectViewSchema.listViews mirrors the spec's ObjectListViewSchema by reference; ViewPreview folds a stored options bag (objectui#7928) #10821 it conflicts in object-view-unmirrored-keys-7779.test.ts (③). Check runs on dd43c757c8: 40 success, 3 skipped (dependabot, the two coverage rows), 0 red.

② Semver level

minor for @object-ui/types and @object-ui/plugin-view with a **BREAKING** banner, the before/after literal, the third-party host note and an ADR-0087 D2 disposition line (the fold is the load-time conversion) — right for a TS-face retirement under the version-alignment rule; Clause-②: yes is the objectui retirement convention. Every sentence checks out against items 1-6. @object-ui/app-shell's ObjectView.tsx also changed and the entry does not name it: the presence gate is satisfied by one declaration and the fixed group versions all 40 packages together, so nothing ships wrong, but app-shell's CHANGELOG will not carry this relay change. Non-blocking; ③.

③ Boundary flags

Implemented-by: claude/issue-7924-density-mode-through-fold
Reviewed-by: session_01AsCNgFBs8HCjwhyHQsFbx3

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 main), so needs:contract-review comes off and ready + auto-merge follow through the relay.


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 27, 2026 23:48
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 27, 2026
Merged via the queue into main with commit 66e8b2a Sep 28, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-7924-density-mode-through-fold branch September 28, 2026 00:02
os-tesla pushed a commit that referenced this pull request Sep 28, 2026
…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
akarma-synetal pushed a commit to akarma-synetal/objectui that referenced this pull request Sep 28, 2026
…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>
akarma-synetal pushed a commit to akarma-synetal/objectui that referenced this pull request Sep 28, 2026
…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>
akarma-synetal pushed a commit to akarma-synetal/objectui that referenced this pull request Sep 28, 2026
…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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants