Found while measuring #13222 (driver-mongodb's lookup index gate). Filed unassigned, out of scope for that card's PR.
What is there
#11567 landed the ruling that reference is the only relationship spelling @objectstack/spec declares, and reference_to is a rejected alias — FieldSchema answers unrecognized_keys with "Did you mean reference_to → reference?". Its changeset put it as "One key, one answer, on both doors." It closed the authoring door and the SQL DDL door.
Three other live consumers still read the rejected alias as an accepted fallback:
| file |
line |
reader |
packages/lint/src/data-model-rules.ts |
167 |
return def?.reference || def?.reference_to; |
packages/plugins/plugin-security/src/security-plugin.ts |
5846 |
const ref = (f) =. f?.reference ?? f?.reference_to ?? f?.referenceTo; |
packages/verify/src/derive.ts |
103 |
const ref = f?.reference ?? f?.reference_to ?? f?.referenceTo; |
(The arrow in the middle row is written =. so the body survives GitHub's sanitizer; the source spells it as a normal arrow function.)
Why this is a defect and not harmless breadth
The repo already made the opposite call one door over, deliberately and in writing. packages/lint/src/validate-security-posture.ts:208 records it:
reference ?? reference_to ?? referenceTo; refOf here accepts only …
— i.e. one lint reader was narrowed on purpose to canonical-only, and the reason is in that file. The three above were not, so the same repo now answers one key two ways depending on which consumer sees it.
Concretely, data-model-rules.ts:167 is a lint rule: it exists to catch authoring mistakes, and it currently treats a field spelled reference_to as having a valid relationship target. So the one component whose job is to tell an author their metadata is wrong is the component that accepts the wrong spelling.
This is the shape the platform's own contract-first rule names: a tolerant consumer is where AI-authored metadata mistakes hide and spread. reference_to is exactly a key AI authors reach for — the published @objectstack/driver-mongodb README taught it until #13224 (in flight).
Measured
FieldSchema.safeParse({ name:'company_id', type:'lookup', reference_to:'company' })
success: false
code: unrecognized_keys
message: Unrecognized key(s) on this field: `reference_to`. Did you mean
`reference_to` → `reference`? Until this shape was closed these were
dropped silently — the field was still created, minus whatever the
key was meant to constrain, protect or compute.
FieldSchema.safeParse({ name:'company_id', type:'lookup', reference:'company' })
success: true
Run against @objectstack/spec@dist built from 9e0ba21a1.
Not proposed here
Whether to narrow all three, or to narrow some and keep a documented tolerance where stored legacy metadata is genuinely in play, is a triage call — each reader has a different population. verify/src/derive.ts and security-plugin.ts may be reading raw registered metadata (registerObject deliberately skips Zod, #3896), which is the one population where the alias can actually appear; data-model-rules.ts is a lint rule over authored source, where it cannot.
Related
#11567 (the ruling) · PR #12287 (where it landed) · #13222 (driver-mongodb's own copy of the same defect) · #13224 (removing the README that taught the key)
Generated by Claude Code
Found while measuring #13222 (driver-mongodb's lookup index gate). Filed unassigned, out of scope for that card's PR.
What is there
#11567 landed the ruling that
referenceis the only relationship spelling@objectstack/specdeclares, andreference_tois a rejected alias —FieldSchemaanswersunrecognized_keyswith "Did you meanreference_to→reference?". Its changeset put it as "One key, one answer, on both doors." It closed the authoring door and the SQL DDL door.Three other live consumers still read the rejected alias as an accepted fallback:
packages/lint/src/data-model-rules.tsreturn def?.reference || def?.reference_to;packages/plugins/plugin-security/src/security-plugin.tsconst ref = (f) =. f?.reference ?? f?.reference_to ?? f?.referenceTo;packages/verify/src/derive.tsconst ref = f?.reference ?? f?.reference_to ?? f?.referenceTo;(The arrow in the middle row is written
=.so the body survives GitHub's sanitizer; the source spells it as a normal arrow function.)Why this is a defect and not harmless breadth
The repo already made the opposite call one door over, deliberately and in writing.
packages/lint/src/validate-security-posture.ts:208records it:— i.e. one lint reader was narrowed on purpose to canonical-only, and the reason is in that file. The three above were not, so the same repo now answers one key two ways depending on which consumer sees it.
Concretely,
data-model-rules.ts:167is a lint rule: it exists to catch authoring mistakes, and it currently treats a field spelledreference_toas having a valid relationship target. So the one component whose job is to tell an author their metadata is wrong is the component that accepts the wrong spelling.This is the shape the platform's own contract-first rule names: a tolerant consumer is where AI-authored metadata mistakes hide and spread.
reference_tois exactly a key AI authors reach for — the published@objectstack/driver-mongodbREADME taught it until #13224 (in flight).Measured
Run against
@objectstack/spec@distbuilt from9e0ba21a1.Not proposed here
Whether to narrow all three, or to narrow some and keep a documented tolerance where stored legacy metadata is genuinely in play, is a triage call — each reader has a different population.
verify/src/derive.tsandsecurity-plugin.tsmay be reading raw registered metadata (registerObjectdeliberately skips Zod, #3896), which is the one population where the alias can actually appear;data-model-rules.tsis a lint rule over authored source, where it cannot.Related
#11567 (the ruling) · PR #12287 (where it landed) · #13222 (driver-mongodb's own copy of the same defect) · #13224 (removing the README that taught the key)
Generated by Claude Code