Found while doing the ADR-0117 D1 declaration sync (#5767 / PR #6364). Not fixed there — different fact, different defect class, and it predates #5677. Filed unassigned for triage.
The defect
packages/spec/src/data/object.zod.ts, in the systemFields strictObject's guidance block — the message an author gets when they write the non-existent systemFields: { owner: ... } key:
`owner` is not a `systemFields` key — `owner_id` injection is governed by the
object-level `ownership` property (`ownership: 'none'` skips it;
`'user'`/`'org'` choose the principal). `systemFields` controls only `tenant`
(organization_id) and `audit` (created_at/created_by/updated_at/updated_by).
'user'/'org' choose the principal is false. ownership: 'org' does not choose a different principal — it injects no owner_id at all. From packages/spec/src/data/injected-system-columns.ts (the authority applySystemFields consumes):
const owner = ownershipEligible && (ownership === undefined || ownership === 'user');
Only undefined and 'user' produce the column. The same file's own ownership JSDoc, ~90 lines above the guidance, already states it correctly:
- `org` / `none` — no per-record owner (Dataverse-style catalog / junction
tables); `owner_id` is NOT injected.
So the guidance contradicts the JSDoc two stanzas away, and it is the guidance that is wrong.
Why it matters — the message is on a real authoring path
This is not dormant prose: it is the error text an author (or an AI writing metadata) is handed at the moment they are already confused about where owner injection is configured. It sends them to ownership: 'org' expecting an owner column keyed to the organization. They get no owner column, and every owner-keyed feature quietly does nothing — owner-scoped RLS, "My" views, owner reports, the first-admin bootstrap handoff. Silent, not loud: nothing rejects ownership: 'org', so the mistake ships.
The failure mode is exactly the one the surrounding guidance machinery exists to prevent, inverted — a wrong-key rescue that hands out a second wrong answer.
Second, smaller item in the same block (fix together)
The sibling guidance.ownership message is now incomplete rather than wrong:
`ownership` is a TOP-LEVEL object key, not a `systemFields` key — write it beside
`systemFields`. It, not this block, decides whether `owner_id` is injected.
Since #5677, ownership governs both ownership anchors — owner_id and owning_business_unit_id. PR #6364 deliberately left this alone (it is an error-message surface, not the injection-list description that issue named), but whoever fixes the 'org' claim should widen this sentence in the same pass, since both messages describe the same property.
Suggested fix
Text only, no schema change. Something like: ownership: 'user' (or omitted) injects the ownership anchors; 'org' and 'none' both skip them, 'org' meaning "org-wide catalog, no per-record owner". Keep 'none' and 'org' visibly distinct in intent so the message still explains why both exist.
Not in scope of this finding
The ownership enum's own error text and describe() (they enumerate the legal values verbatim and are #5678's surface), and adding the business_unit tier anywhere.
Provenance
Found while doing the ADR-0117 D1 declaration sync (#5767 / PR #6364). Not fixed there — different fact, different defect class, and it predates #5677. Filed unassigned for triage.
The defect
packages/spec/src/data/object.zod.ts, in thesystemFieldsstrictObject'sguidanceblock — the message an author gets when they write the non-existentsystemFields: { owner: ... }key:'user'/'org'choose the principal is false.ownership: 'org'does not choose a different principal — it injects noowner_idat all. Frompackages/spec/src/data/injected-system-columns.ts(the authorityapplySystemFieldsconsumes):Only
undefinedand'user'produce the column. The same file's ownownershipJSDoc, ~90 lines above the guidance, already states it correctly:So the guidance contradicts the JSDoc two stanzas away, and it is the guidance that is wrong.
Why it matters — the message is on a real authoring path
This is not dormant prose: it is the error text an author (or an AI writing metadata) is handed at the moment they are already confused about where owner injection is configured. It sends them to
ownership: 'org'expecting an owner column keyed to the organization. They get no owner column, and every owner-keyed feature quietly does nothing — owner-scoped RLS, "My" views, owner reports, the first-admin bootstrap handoff. Silent, not loud: nothing rejectsownership: 'org', so the mistake ships.The failure mode is exactly the one the surrounding
guidancemachinery exists to prevent, inverted — a wrong-key rescue that hands out a second wrong answer.Second, smaller item in the same block (fix together)
The sibling
guidance.ownershipmessage is now incomplete rather than wrong:Since #5677,
ownershipgoverns both ownership anchors —owner_idandowning_business_unit_id. PR #6364 deliberately left this alone (it is an error-message surface, not the injection-list description that issue named), but whoever fixes the'org'claim should widen this sentence in the same pass, since both messages describe the same property.Suggested fix
Text only, no schema change. Something like:
ownership: 'user'(or omitted) injects the ownership anchors;'org'and'none'both skip them,'org'meaning "org-wide catalog, no per-record owner". Keep'none'and'org'visibly distinct in intent so the message still explains why both exist.Not in scope of this finding
The
ownershipenum's ownerrortext anddescribe()(they enumerate the legal values verbatim and are #5678's surface), and adding thebusiness_unittier anywhere.Provenance
git log -S, most recently rebased in b5bdf48 (check:docs的第一步是gen:schema—— 修好 #4711 之后,「检查改工作区」仍从这里漏进来 #4723 / PR fix(spec): check:docs 不再以 gen:schema 开头,生成交给调用方 (#4723) #6000).origin/mainatdb59e9c5f.systemFields guidance owner ownership,"choose the principal") — no existing card.