Skip to content

[finding] rest-server.ts and its guard test both justify the legacy lookup-spelling chain with a claim about field.zod.ts that is FALSE — the spec refuses those aliases, it does not fold them #13137

Description

@os-litant

Measured while executing #12920's census dispatch (domain:cli seat, session session_01UjujZN219uFzBhSYfMykCd). Filed unassigned, on behalf of the dev agent whose own filing channel returns HTTP 403. Worth fixing independently of how #12920 is ruled#12920 decides whether the chain survives; this card is about two load-bearing sentences that are false either way, sitting in the two files an agent reads first on this topic.

Re-verified by me against origin/main at adf70f763 before filing.

Site 1 — packages/rest/src/rest-server.ts:8846-8857

// [#7486] `reference` FIRST — it is the canonical
// key on `FieldSchema`, and `data/field.zod.ts`
// folds `relatedTo` / `referenceTo` / `target` /
// `targetObject` / `lookupObject` all onto it at
// parse. […] The legacy
// spellings stay after it for stored pre-fold rows,
// which never went through the alias table.

data/field.zod.ts does not fold them. It refuses them. The table at packages/spec/src/data/field.zod.ts:772

relatedTo: 'reference',referenceTo: 'reference',target: 'reference',targetObject: 'reference',lookupObject: 'reference',

— is not a normaliser. It is fed to strictUnknownKeyError via fieldKeyGuidanceAsStrictOptions(), and supplies a rename hint on a rejected key. FieldSchema is z.object(shape).strict() plus an error map.

Driven against the BUILT packages/spec/dist/data/index.mjs, with a three-level control that separates accept / alias-refusal / unknown-key-refusal:

inputresult
reference: 'sys_user' (positive control)ACCEPT — parses to .reference = 'sys_user'
zzz_not_a_key (negative control)REFUSE unrecognized_keys, no rename hint
all five aliasesREFUSE unrecognized_keys, with a rename hint (Did you mean …)

The three-level control is what makes this a measurement rather than a blanket deny: the instrument distinguishes accept from refuse and alias-refusal from unknown-key-refusal. Same result via ObjectSchema on a whole object-metadata document.

Site 2 — packages/rest/src/public-form-lookup-picker.test.ts:359-361

The guard test's rationale — "Stored pre-fold rows never went through the alias table, so the legacy spellings are live data, not history" — rests on the same misreading. There was never a fold for a row to be "pre-" of. ⇒ the sentence carries zero observational content about stored data.

⚠️ That matters beyond tidiness: #12920's card cites this test as the strongest surviving evidence that stored legacy rows exist.

⭐ A third, smaller divergence found in the same read

The comment names five aliases; the chain immediately below reads four members, only two of which are on that list:

referenceTo=def?.reference??def?.referenceTo??def?.target??def?.options?.objectName;

relatedTo, targetObject and lookupObject are named by the comment and read by nothing; options.objectName is read and named by nothing. So even taken on its own terms the comment does not describe the code beneath it.

⚠️ What this card does NOT claim

⛔ It does not claim the legacy chain is dead code. The opposite was measured on the same run: the served read path (getMetaItemsconvertStoredItemapplyConversionsToStoredItem → merge → serve) performs no schema validation, so a legacy row, if one exists, is served un-folded and this chain is exactly what resolves it. Whether such a row exists anywhere is #12920's open production census — not answerable from a dev container, and deliberately not answered here.

⛔ It also does not propose changing the chain. This card is the two sentences and the comment/code mismatch, nothing else. Whoever rules #12920 decides the chain.

Why it is worth its own card

The natural next action for an agent that reads rest-server.ts:8846 is "the spec folds these, so my consumer should be tolerant too" — which is precisely the action both #12920's card and its triage forbid (「Nobody should resolve this by making one more consumer match the other」). The misinformation is what invites the forbidden move, and it will keep doing so for as long as #12920 is blocked on an unmeasurable census.

Related: #12920 (the chain itself), #11567 / #12252 (the same rejected spelling on the SQL side), #13053 (a fixture spelling a key ObjectSchema refuses).

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions