Reading taken 2026-09-18T16:52Z on origin/main@221dabb72; every line is git grep -n … origin/main, ⛔ not the shared working tree.
Defect
FieldSchema.reference is declared an optional string. Where a reader cannot read the carrier, the design's answer is undefined — absence. These four call sites do something worse: they propagate the unreadable value onward, one of them after inventing a name for it.
| site |
code, verbatim |
what the unreadable carrier becomes |
packages/plugins/plugin-approvals/src/approval-service.ts:5773 |
out.push({ key, reference: String(f.reference) }); |
the literal target name '[object Object]' |
packages/services/service-analytics/src/plugin.ts:735-736 |
if (field && (… 'lookup' …) && field.reference) { → return field.reference; |
a dataset relationship target of a non-string type |
packages/cli/src/commands/doctor.ts:708-709 |
if (field?.type === 'lookup' && field?.reference) { → deps.push(field.reference); |
a non-string entry in a dependency graph |
packages/cli/src/commands/doctor.ts:894-895 |
same gate → referencedObjects.add(field.reference); |
a non-string member of a referenced-object set |
Each gate is a truthiness test, which a non-string object passes. The approvals site is the sharpest: String() on an object yields '[object Object]', so resolveLookupFields hands the approval path a target name that can never resolve, and nothing reports it. ⇒ this class does not merely lose information, it manufactures a wrong answer.
⭐ The same file already knows the right shape. doctor.ts:792 reads if (typeof field?.reference === 'string') refs.push(field.reference); — a narrowing gate, twenty lines from two that have none. ⇒ the fix at these sites is local and cheap, and the inconsistency is inside one file rather than across a boundary.
Measurement
| reading |
value |
instrument |
| the four propagating sites above |
present as quoted |
git grep -n per path |
lit control: files in packages/objectql, plugin-approvals, service-analytics, packages/cli that route through the arbiter referenceCarrierOf |
1, and it is a test (packages/cli/test/data-model-rules.test.ts) |
git grep -c referenceCarrierOf origin/main -- <those four packages> |
⇒ none of these production paths routes through the arbiter today, and the zero is a reading rather than a dead grep: the token does resolve in that corpus, in a test.
Provenance and why it is filed rather than fixed
Reported by the os-dev round on #18550 (PR #19080) as an out-of-scope finding; the four code facts were re-measured by the domain:spec#3 execution seat against origin/main before filing, and the doctor.ts:792 contrast is the seat's addition.
These sites belong to the class PR #18503 labelled C2 and deliberately left unchanged, so this card is a request to act on that class, ⛔ not a claim that #18503 or #19080 was wrong to leave it. #19080's declared surface is the ten residue sites; touching these would have widened it.
Adjacent — read, and not the same subject
Evidence limit
Static reading on one ref. What is NOT established: whether any of the four is reachable from an authored document today. The engine's own write path refuses this shape (per #19080's probe: insert → assertReferencesResolve → the same arbiter), so a row carrying it had to be written straight through the driver — which makes the population plausibly empty in practice and the fix cheap insurance rather than an incident. ⛔ Do not grade this as a live outage without that reachability reading.
Dedup words
String(f.reference) approval lookup, [object Object] reference target, C2 truthiness reference read, analytics relationship target unnarrowed, doctor dependency graph carrier
Generated by Claude Code
Reading taken 2026-09-18T16:52Z on
origin/main@221dabb72; every line isgit grep -n … origin/main, ⛔ not the shared working tree.Defect
FieldSchema.referenceis declared an optional string. Where a reader cannot read the carrier, the design's answer isundefined— absence. These four call sites do something worse: they propagate the unreadable value onward, one of them after inventing a name for it.packages/plugins/plugin-approvals/src/approval-service.ts:5773out.push({ key, reference: String(f.reference) });'[object Object]'packages/services/service-analytics/src/plugin.ts:735-736if (field && (… 'lookup' …) && field.reference) {→return field.reference;packages/cli/src/commands/doctor.ts:708-709if (field?.type === 'lookup' && field?.reference) {→deps.push(field.reference);packages/cli/src/commands/doctor.ts:894-895referencedObjects.add(field.reference);Each gate is a truthiness test, which a non-string object passes. The approvals site is the sharpest:
String()on an object yields'[object Object]', soresolveLookupFieldshands the approval path a target name that can never resolve, and nothing reports it. ⇒ this class does not merely lose information, it manufactures a wrong answer.⭐ The same file already knows the right shape.
doctor.ts:792readsif (typeof field?.reference === 'string') refs.push(field.reference);— a narrowing gate, twenty lines from two that have none. ⇒ the fix at these sites is local and cheap, and the inconsistency is inside one file rather than across a boundary.Measurement
git grep -nper pathpackages/objectql,plugin-approvals,service-analytics,packages/clithat route through the arbiterreferenceCarrierOfpackages/cli/test/data-model-rules.test.ts)git grep -c referenceCarrierOf origin/main -- <those four packages>⇒ none of these production paths routes through the arbiter today, and the zero is a reading rather than a dead grep: the token does resolve in that corpus, in a test.
Provenance and why it is filed rather than fixed
Reported by the
os-devround on #18550 (PR #19080) as an out-of-scope finding; the four code facts were re-measured by thedomain:spec#3execution seat againstorigin/mainbefore filing, and thedoctor.ts:792contrast is the seat's addition.These sites belong to the class PR #18503 labelled C2 and deliberately left unchanged, so this card is a request to act on that class, ⛔ not a claim that #18503 or #19080 was wrong to leave it. #19080's declared surface is the ten residue sites; touching these would have widened it.
Adjacent — read, and not the same subject
.referencereads still answerundefinedsilently after #18503 routed the carrier through one arbiter — the measured residue of ruling E item 2 #18550 / PR Refuse an unreadablereferencecarrier at the ten residual readers (ruling E item 2 residue) #19080 — the residue that WAS routed (the C3 class). These four are the ones that answer worse thanundefined.reference: { object: ... }, a carrierObjectSchemarefuses and the rule's own reader ignores #13053 (closedcompleted) — the same non-string carrier shape measured in a lint fixture, where 「a carrierObjectSchemarefuses and the rule's own reader ignores」. Shape provenance; different reader.referencenames an object that exists nowhere — the dangling target is found only at runtime #16611, [spec]FieldSchemaaccepts alookup/master_detailwith noreferencetarget, though its own TSDoc calls the key required #13632 (both closed) — the dangling and missing target questions. A carrier naming a non-existent object is not this: these sites' carrier is not a name at all.Evidence limit
Static reading on one ref. What is NOT established: whether any of the four is reachable from an authored document today. The engine's own write path refuses this shape (per #19080's probe:
insert→assertReferencesResolve→ the same arbiter), so a row carrying it had to be written straight through the driver — which makes the population plausibly empty in practice and the fix cheap insurance rather than an incident. ⛔ Do not grade this as a live outage without that reachability reading.Dedup words
String(f.reference) approval lookup,[object Object] reference target,C2 truthiness reference read,analytics relationship target unnarrowed,doctor dependency graph carrierGenerated by Claude Code