@@ -6481,23 +6481,46 @@ export class SecurityPlugin implements Plugin {
64816481 // every later by-id write through the stored-row leg below. The residual
64826482 // envelope asymmetry is confined to exactly those shapes.
64836483 //
6484- // [#8959, re-measured 2026-08-16] "Confined" is still NOT a publish-time
6485- // bound today, though the reason has moved on from #8959's finding. #8772
6486- // has since been RULED (2026-08-16, comment 5306089973) — it is no longer
6487- // "open and unruled" — but the ramp it ordered has two code legs and
6488- // neither has landed yet: Direction 2 (the authoring builder forces
6489- // `required: true` under `controlled_by_parent`, #9138) is dispatchable
6490- // now but not yet merged; Direction 1 (`relationship/master-detail-required`
6491- // promoted `warning` → `error`, scoped to `controlled_by_parent`, #9139) is
6492- // deliberately held for the **v18** boundary (`main` is still 17.x as of
6493- // this note). So the lint measured by #8959 is unchanged: `master_detail`
6494- // with no `required` still draws only `severity: 'warning'`, and
6495- // `required` + `readonly` / `required` + `system` still draw nothing at
6496- // all (`packages/lint/src/data-model-rules.ts`). A freshly authored detail
6497- // therefore still reaches this branch and its `422` — the residue is a
6498- // live, newly-authorable surface, not a shrinking legacy tail, until BOTH
6499- // #9138 and #9139 land. Re-check this paragraph before trusting it; once
6500- // both have landed it is the one that goes stale next.
6484+ // [#8959, re-measured 2026-09-01] "Confined" is now a PARTIAL publish-time
6485+ // bound: of the three shapes above, ONE is fenced at authoring time and
6486+ // two are not. #8772 was RULED (2026-08-16, comment 5306089973) and the
6487+ // ramp it ordered has two code legs, of which exactly one has landed.
6488+ // Direction 2 (#9138) IS merged: `ObjectSchema.create()` now runs
6489+ // `forceCbpMasterDetailRequired` (`packages/spec/src/data/object.zod.ts`)
6490+ // — under `controlled_by_parent`, a `master_detail` reference with
6491+ // `required` omitted is forced to `required: true`, and an explicit
6492+ // `required: false` is refused with a located error. Direction 1
6493+ // (`relationship/master-detail-required` promoted `warning` → `error`,
6494+ // scoped to `controlled_by_parent`, #9139) has NOT landed — that card is
6495+ // open and `pm:on-hold`, deliberately held for the **v18** boundary
6496+ // (`main` is still 17.x as of this note).
6497+ //
6498+ // ⛔ #9138 landing is NOT "the residue is gone". It narrows the FIRST
6499+ // shape only, and only on the builder path:
6500+ // • no `required` — no longer newly authorable through
6501+ // `ObjectSchema.create()`, but it survives on the raw
6502+ // `.parse()`/`.safeParse()` path, which #9138 left untouched ON
6503+ // PURPOSE so metadata already at rest keeps loading (its docblock
6504+ // says so). Measured: `safeParse` of a `controlled_by_parent` object
6505+ // takes both an omitted `required` and an explicit `required: false`.
6506+ // • `required` + `readonly` and `required` + `system` — STILL newly
6507+ // authorable through `ObjectSchema.create()` itself: the force
6508+ // returns early on `required === true` and never inspects
6509+ // `readonly`/`system`. It in fact MINTS them — a `readonly`/`system`
6510+ // master reference authored with no `required` comes out of
6511+ // `create()` as `required: true` plus the flag, which is exactly a
6512+ // shape `validateRecord` skips.
6513+ //
6514+ // And nothing warns on the way past: the lint measured by #8959 is
6515+ // unchanged — the predicate is still `def.required !== true` at
6516+ // `severity: 'warning'` (`packages/lint/src/data-model-rules.ts`), so the
6517+ // two flagged shapes draw NO finding at ANY severity and only the
6518+ // un-flagged one draws a warning. A freshly authored detail therefore
6519+ // still reaches this branch and its `422`: for the two flagged shapes
6520+ // straight through the builder, for the third through raw parse. It is a
6521+ // live surface, not a shrinking legacy tail. Re-check this paragraph
6522+ // before trusting it — it goes stale when #9139 lands, or when the
6523+ // builder force grows to cover the two flagged shapes.
65016524 //
65026525 // ⛔ [#9137] FREEZE NOTE — maintainer ruling on #8772, Direction 4,
65036526 // "immediately": until the two legs above both land, this `if` is the
0 commit comments