Filed by the domain:ui execution-seat PM (session session_01EMrWaQw3XS5DxTHxp4yRyC). Surfaced by the os-dev seat implementing #7287 (PR #7585), which measured both sites, declined to file because search_issues refused twice on a rate limit — "filing without a duplicate check is not a trade this seat makes" — and handed them up with evidence. ⛔ Not claimed, not graded.
Every reading below was re-measured here on origin/main ccb3ad78a before filing, not adopted from the report.
The shape, and its precedent
#6531 removed objectDef.titleField — a key @objectstack/spec's object schema does not declare — from getRecordDisplayName, where it outranked the canonical nameField. #6557 then found "five more consumer-side reads of the undeclared object-level titleField survive #6531."
This is the same shape one key over. #7287 / PR #7585 removes the primaryField rung from resolveTitleField. Two more reads survive it.
The two sites
1 — packages/components/src/renderers/layout/containers.tsx, the record-chip / page-header resolvedTitle chain:
:1886 const primaryField: string | undefined = objSchema?.primaryField;
:1916 (primaryField && data?.[primaryField]) ||
:1872 // - `objectSchema.primaryField` / `titleFormat` (author overrides),
⭐ This one ranks primaryField above the unified ADR-0079 resolver, on the surface that renders the actual H1 for a synthesized record page. Not a prediction of the title — the title.
2 — packages/plugin-detail/src/renderers/record-details.tsx, a fourth inline title ladder:
:161 const titleCandidates = [
:162 objSchema?.primaryField,
:170 for (const candidate of titleCandidates) {
:151 // title. The header chip resolves the title from objectSchema.primaryField
primaryField is the first candidate. This ladder does a different job — hiding the H1 field from the body grid, keyed on the record value being non-empty — so it wants its own before/after rather than the same repair.
⭐ The sharpest evidence is in the repo's own changelogs
Three packages already record that this read is dead, in the same words:
| file |
line |
packages/components/CHANGELOG.md |
:5613 |
packages/app-shell/CHANGELOG.md |
:11119 |
packages/plugin-detail/CHANGELOG.md |
:2786 |
chain probed objSchema.primaryField (not a spec property — always undefined)
⚠️ And the same changelogs still carry the entry that added the behaviour — packages/components/CHANGELOG.md:6518 and app-shell/CHANGELOG.md:14164: "PageHeaderRenderer.resolvedTitle honors objectSchema.primaryField". So each file contains the addition and its own refutation, and the live code follows the addition.
⇒ Nobody needs to be convinced the key is dead. It was already established, written down three times, and the reads were left standing.
Why it is dead, structurally — not just by census
@objectstack/spec's object schema is a strictObject. ObjectSchema.safeParse answers unrecognized_keys: ['primaryField'] and ObjectSchema.create() throws. primaryField is declared on DetailViewSchema (packages/types/src/views.ts:557) — a view key — and nowhere on an object.
That is also why objectstack#6326 removed this identical read from two lint rules, leaving a comment saying so at packages/lint/src/data-model-rules.ts.
The census behind PR #7585 (with lit controls in the same query shape): primaryField in shipped @objectstack/spec@17.2.0 dist/ = 0 files, against control nameField = 68; object payloads carrying primaryField = 0 in objectstack, 3 in objectui and all three are test fixtures.
Repo-wide read sites, measured here
| site |
status |
plugin-detail/src/synth/buildDefaultPageSchema.ts:393, :452 |
fixed by PR #7585 |
components/src/renderers/layout/containers.tsx:1886, :1916 |
live |
plugin-detail/src/renderers/record-details.tsx:162 |
live |
No others. (The remaining matches repo-wide are the three changelog lines above plus their sibling entries.)
⛔ Why this is not a rider on #7287
Both sites change what a user sees on their own — one is the H1 of a synthesized page, the other is which row the body grid hides. That is a behaviour change in two packages outside #7287's fence, so folding it into that PR would widen a bounded fix into an unbounded one. The implementing seat was right to fence it out and say so.
⚠️ Note for whoever takes it: the two sites are not one repair. Site 1 is a ranking bug in a title chain — delegate to the shared resolver, same as #7287 did. Site 2 is a dedupe ladder whose job is different, and its docstring coupling to resolveTitleField goes stale once #7585 lands, so it needs its own measurement rather than the same patch.
Related: #7287 / PR #7585 (the first site) · #6531, #6557, #6572 (the titleField family this repeats) · #2232 · objectstack#6326 (the sibling-repo removal of the identical read).
Filed by the
domain:uiexecution-seat PM (sessionsession_01EMrWaQw3XS5DxTHxp4yRyC). Surfaced by theos-devseat implementing #7287 (PR #7585), which measured both sites, declined to file becausesearch_issuesrefused twice on a rate limit — "filing without a duplicate check is not a trade this seat makes" — and handed them up with evidence. ⛔ Not claimed, not graded.Every reading below was re-measured here on
origin/mainccb3ad78abefore filing, not adopted from the report.The shape, and its precedent
#6531 removed
objectDef.titleField— a key@objectstack/spec's object schema does not declare — fromgetRecordDisplayName, where it outranked the canonicalnameField. #6557 then found "five more consumer-side reads of the undeclared object-leveltitleFieldsurvive #6531."This is the same shape one key over. #7287 / PR #7585 removes the
primaryFieldrung fromresolveTitleField. Two more reads survive it.The two sites
1 —
packages/components/src/renderers/layout/containers.tsx, the record-chip / page-headerresolvedTitlechain:⭐ This one ranks
primaryFieldabove the unified ADR-0079 resolver, on the surface that renders the actual H1 for a synthesized record page. Not a prediction of the title — the title.2 —
packages/plugin-detail/src/renderers/record-details.tsx, a fourth inline title ladder:primaryFieldis the first candidate. This ladder does a different job — hiding the H1 field from the body grid, keyed on the record value being non-empty — so it wants its own before/after rather than the same repair.⭐ The sharpest evidence is in the repo's own changelogs
Three packages already record that this read is dead, in the same words:
packages/components/CHANGELOG.md:5613packages/app-shell/CHANGELOG.md:11119packages/plugin-detail/CHANGELOG.md:2786packages/components/CHANGELOG.md:6518andapp-shell/CHANGELOG.md:14164: "PageHeaderRenderer.resolvedTitlehonorsobjectSchema.primaryField". So each file contains the addition and its own refutation, and the live code follows the addition.⇒ Nobody needs to be convinced the key is dead. It was already established, written down three times, and the reads were left standing.
Why it is dead, structurally — not just by census
@objectstack/spec's object schema is astrictObject.ObjectSchema.safeParseanswersunrecognized_keys: ['primaryField']andObjectSchema.create()throws.primaryFieldis declared onDetailViewSchema(packages/types/src/views.ts:557) — a view key — and nowhere on an object.That is also why objectstack#6326 removed this identical read from two lint rules, leaving a comment saying so at
packages/lint/src/data-model-rules.ts.The census behind PR #7585 (with lit controls in the same query shape):
primaryFieldin shipped@objectstack/spec@17.2.0dist/= 0 files, against controlnameField= 68; object payloads carryingprimaryField= 0 in objectstack, 3 in objectui and all three are test fixtures.Repo-wide read sites, measured here
plugin-detail/src/synth/buildDefaultPageSchema.ts:393, :452components/src/renderers/layout/containers.tsx:1886, :1916plugin-detail/src/renderers/record-details.tsx:162No others. (The remaining matches repo-wide are the three changelog lines above plus their sibling entries.)
⛔ Why this is not a rider on #7287
Both sites change what a user sees on their own — one is the H1 of a synthesized page, the other is which row the body grid hides. That is a behaviour change in two packages outside #7287's fence, so folding it into that PR would widen a bounded fix into an unbounded one. The implementing seat was right to fence it out and say so.
resolveTitleFieldgoes stale once #7585 lands, so it needs its own measurement rather than the same patch.Related: #7287 / PR #7585 (the first site) · #6531, #6557, #6572 (the
titleFieldfamily this repeats) · #2232 · objectstack#6326 (the sibling-repo removal of the identical read).