From 6abb5d815b60f99925d93cc7f320725f376f2350 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 18 Oct 2026 10:14:34 +0000 Subject: [PATCH] docs(spec): put the forceCbpMasterDetailRequired "only the security gate" sentence in the past tense The docblock said that today only the security gate closes the null-master-FK shape. That held before the builder's force landed; since protocol 18 the parse refuses the declaration itself (refuseControlledByParentWithoutOneMaster). Comment text and a patch changeset only. Claude-Session: https://claude.ai/code/session_019oFY6Hi35J7atvgVFnmoaK Co-authored-by: Claude --- .changeset/24291-cbp-docblock-tense.md | 13 +++++++++++++ packages/spec/src/data/object.zod.ts | 12 ++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 .changeset/24291-cbp-docblock-tense.md diff --git a/.changeset/24291-cbp-docblock-tense.md b/.changeset/24291-cbp-docblock-tense.md new file mode 100644 index 00000000000..3b3d818d68f --- /dev/null +++ b/.changeset/24291-cbp-docblock-tense.md @@ -0,0 +1,13 @@ +--- +'@objectstack/spec': patch +--- + +Clause-②: no + +The `forceCbpMasterDetailRequired` docblock in `src/data/object.zod.ts` no longer says that today only +the security gate (`assertControlledByParentWrite`) closes the null-master-FK shape of a +`controlled_by_parent` object. That was true before the builder's force landed, and the sentence is now +in the past tense. It also names what has refused the declaration at parse since protocol 18: +`refuseControlledByParentWithoutOneMaster` refuses a `controlled_by_parent` object none of whose +`master_detail` fields declares `required: true`. No key, schema, export, accepted value or message text +changes. diff --git a/packages/spec/src/data/object.zod.ts b/packages/spec/src/data/object.zod.ts index 60d11818410..5ee9ab17df9 100644 --- a/packages/spec/src/data/object.zod.ts +++ b/packages/spec/src/data/object.zod.ts @@ -3480,10 +3480,14 @@ function assertReferenceViaSiblingDeclared(objectName: unknown, fields: unknown) * master FK, the row lands with a null FK, the derived read filter * `masterFK IN (accessible master ids)` can never match null — the row is * invisible to everyone — and every later by-id write answers - * `422 MISSING_REQUIRED_FIELD`. Today only the security gate - * (`assertControlledByParentWrite`) closes that shape, and commit 75b7c240a records that - * the declaration and the enforcement disagree. This makes the unsafe shape - * impossible to NEWLY declare: + * `422 MISSING_REQUIRED_FIELD`. Before commit 75b7c240a only the security + * gate (`assertControlledByParentWrite`) closed that shape, by refusing the + * insert at runtime, and that commit records that the declaration and the + * enforcement disagreed. Since protocol 18 the parse refuses the declaration + * itself: {@link refuseControlledByParentWithoutOneMaster} refuses a + * `controlled_by_parent` object none of whose `master_detail` fields declares + * `required: true`. The builder makes the unsafe shape impossible to NEWLY + * declare: * * - omitted `required` → forced to `true` (the lint rule * `relationship/master-detail-required` already computes exactly this fix);