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
fix(spec): require a non-empty reference on lookup/master_detail fields (#13927)
* fix(spec): FieldSchema requires a non-empty reference on lookup/master_detail
superRefine on the relationship types (ADR-0049 declared = enforced): a
lookup / master_detail whose reference is missing or '' is refused at
parse with a prescriptive message on the reference path. TSDoc aligned;
pins for missing/empty/legal on both types; the three key-absence sample
fixtures that used a bare lookup move to legal shape.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PBjwYLS6BciTQW3c9xQiD2
* docs(spec): adr-0087 disposition marker; re-anchor system-context census line
The changeset gains the not-required (no-migration-prescription) marker
mirroring the #11519/#11842/#13733 narrowing precedents; the superRefine
insertion shifted field.zod.ts line numbers, so the system-context page
anchor is re-anchored by the census --fix.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PBjwYLS6BciTQW3c9xQiD2
---------
Co-authored-by: Claude <noreply@anthropic.com>
narrowings) and #13733 (`FormViewSchema` wizard tightening), all `minor` with the
11
+
**BREAKING** header.
12
+
13
+
The key's own TSDoc has always called `reference`**required** on the two
14
+
relationship types, but the schema accepted a `lookup` / `master_detail` with the
15
+
key missing or set to `''` — a relationship that points nowhere. Nothing
16
+
downstream can act on that shape: the record picker has no object to query,
17
+
`$expand` has nothing to resolve, `deleteBehavior` has no parent to apply to, and
18
+
driver-mongodb silently skips the relationship index it would otherwise build.
19
+
Lint's `relationship/missing-reference` already grades the same hole an
20
+
error-severity finding; the publish seam was the one door left open — exactly
21
+
where AI-authored metadata that omits the key would otherwise parse cleanly and
22
+
fail far from the cause (ADR-0049 declared = enforced).
23
+
24
+
What newly gets rejected: `type: 'lookup'` or `type: 'master_detail'` with
25
+
`reference` absent or `''`. The rejection is prescriptive on the `reference`
26
+
path — it names the type, the key, the expected shape (a snake_case target
27
+
object name), and the fix. Everything else is untouched: a non-empty `reference`
28
+
round-trips byte-identically, non-relationship types never carried the
29
+
requirement, `referenceVia` stays text-only and mutually exclusive with
30
+
`reference`, and the `Field.lookup()` / `Field.masterDetail()` helpers already
31
+
take the target as their first positional argument, so helper-authored fields
32
+
cannot miss it.
33
+
34
+
The measured population of affected authored sources is zero in every in-tree
35
+
corpus (examples, reference apps, packaged metadata, seeds, structured metadata
36
+
and docs samples all declare targets; the census and its positive controls are
37
+
recorded on the PR). No key is removed or renamed, so there is no ADR-0087
38
+
registry entry — the key stays authorable with the same meaning; only the
39
+
missing/empty hole closes.
40
+
41
+
<!-- adr-0087: not-required (no-migration-prescription) A validity narrowing over an existing key: `reference` is not removed, renamed or re-shaped, so there is no tombstone and nothing mechanical for `objectstack migrate meta` to rewrite. The parse refusal is the channel that reaches an affected author, at the parse site, carrying the remedy; which target object a targetless `lookup` / `master_detail` was meant to point at is authoring intent no migration entry can decide on an upgrader's behalf — and the measured population of affected sources is zero in every in-tree corpus (census on the PR). Mirrors the disposition of the #11519 / #11842 ActionSchema narrowings and the #13733 wizard tightening. -->
Copy file name to clipboardExpand all lines: content/docs/permissions/system-context.mdx
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -196,7 +196,7 @@ assuming `isSystem` covers it is a documented source of bugs.
196
196
| "It suppresses triggers / record-change automation" |**No.** Only `skipTriggers` does. A bare `{ isSystem: true }` on a seed write re-fired automation on freshly seeded rows and wedged first boot |`metadata-protocol/src/seed-loader.ts:1909` (rationale at `:1819`–`1821`, #3760), `flow.zod.ts:685`|
197
197
| "It skips the state machine" |**No.** That is `skipStateMachine`, carried by seed replay and by `treatAsHistorical` imports |`objectql/src/engine.ts` FSM gate; see [State Machine](/docs/protocol/objectql/state-machine)|
198
198
| "It skips validation rules" |**No.** Field shape, `format`, `script` and the rest still run. The `readonly` strip runs *before* validation precisely so a discarded value is not judged |`objectql/src/engine.ts:9588`–`9605`|
199
-
| "It preserves a supplied `updated_at` / `updated_by`" |**No.** That is `preserveAudit`, a separate opt-in — and an UPDATE-path exemption only |`field.zod.ts:1514` (#3493 / #6640) |
199
+
| "It preserves a supplied `updated_at` / `updated_by`" |**No.** That is `preserveAudit`, a separate opt-in — and an UPDATE-path exemption only |`field.zod.ts:1516` (#3493 / #6640) |
200
200
| "It stamps `created_by`" |**No.** Audit stamping reads `userId` from the context. A user-less system write stamps nothing — that is today's behaviour, not an error |`runtime-identity.ts:280`–`281`|
201
201
| "It bypasses every guard" |**No.** The last-admin guard applies to **every** context, `isSystem` included — the deprovision path that actually locks an org out is the system one |`last-admin-guard.ts:286`|
202
202
| "A client can request it" |**No.** Never settable from inbound HTTP or from an action body |`rest-server.ts:1302`, `:1331`; `domains/actions.ts:404`|
0 commit comments