Repository navigation
spec builder: force required: true on a master_detail reference under controlled_by_parent (ruled Direction 2 of #8772) #9138
Description
Activity
os-project-manager commented
on Aug 16, 2026 CollaboratorMore actionsTriage:
domain:specadded (lands inpackages/spec's authoring builder; single-producer rule),pm:queuekept, typeTask— maintainer-ruled implementation (Direction 2 of #8772, ruling comment linked in the card).This narrows the authorable accept face (an explicit
required: falseon that shape becomes a loud refusal), so the card's ownmodel: claude-fable-5mandatory note is correct under the standing tiering rule — dispatching seat, carry it. Serial: the ruling says the freeze-note slice #9137 (identity) lands before or with this one; honor that ordering. Consumer-package fixture triage applies (spec-touching change).
Generated by Claude Code
os-project-manager commented
on Aug 17, 2026 CollaboratorMore actionsClaiming for implementation.
- Session:
session_01Y26DJEHSBhhAQ6wwfsHNza - Branch:
claude/issue-9138-cbp-master-detail-required
Scope per the #8772 ruling, Direction 2: builder-only — force
required: trueon the mastermaster_detailreference under acontrolled_by_parentobject, loud refusal on explicitrequired: false. Runtime (resolveCbpRelation) and lint severity untouched.
Generated by Claude Code
Generated by Claude Code
- Session:
- added 3 commits that reference this issue
on Aug 17, 2026 os-project-manager commented
on Aug 17, 2026 CollaboratorMore actions{ "issue": 9138, "status": "done", "branch": "claude/issue-9138-cbp-master-detail-required", "pr": "https://github.com/objectstack-ai/objectstack/pull/9206", "premise_still_valid": true, "summary": "Implemented #8772 ruling Direction 2, builder-only: ObjectSchema.create() forces required: true on every master_detail reference under sharingModel controlled_by_parent when omitted, and refuses an explicit required: false with a located, prescriptive error. Raw parse/safeParse tolerance for metadata at rest is pinned by a new test; runtime (resolveCbpRelation), lint severity, and plugin-security are untouched (zero file overlap with #9137 — the ruling's lands-before-or-with ordering is the PM's merge sequencing). Premise re-verified on origin/main @ 7a537ce90 before building (both unsafe shapes parsed green), and the survey re-verified: 3 shipped cbp objects, all already required: true. Changeset: @objectstack/spec minor with BREAKING marker + ADR-0087 'registered' via semantic entry cbp-master-detail-required-forced under protocol 18 (spec-changes.json/upgrade guide are byte-identical by design — they project released majors only; #9186's entry is absent from them too). Contract note: the dispatch prompt asked assign-per-CLAUDE.md; the standing dev contract says the PM holds the claim and the assignee is not mine to touch — I followed the contract (claim comment with session id + branch only).", "tests": "All at final commit 17f5340 (git rev-parse --short HEAD; porcelain clean). spec: 407 files / 10834 tests passed, typecheck green, eslint green on changed files. Reverse verification from committed state, direction pre-declared as red: with object.zod.ts restored to origin/main, exactly the 4 enforcement tests failed (4 failed | 164 passed) while the 3 unchanged-behavior pins stayed green; restored byte-identically, 168/168 green. Consumer sweep — DOWNSTREAM consumers of @objectstack/spec, scoped to the rule's consumption radius (not the full prefix-filter farm): lint 2065, plugin-security 1279, objectql 3755, metadata-protocol 1588, example-crm 42, example-showcase 221, all passed; card-named pin validate-security-posture(.runtime-surface).test.ts re-run explicitly, 106/106 green. Built-dist receipt: spec dist rebuilt after the final source edit (check-dev-prereqs content-hash confirms), dogfood cbp proofs 2 files / 8 tests green against dist, plus a direct dist import probe showing forced true + refusal. Gates: dispatch-gates.mjs derived against actual changed paths; ran matched + convention set — check:generated (13/13 current), check:migration-registry, check:adr-0087-registration, check-changeset-no-major, check-empty-changeset, check:cross-package-test-inputs, check:merge-driver, check:objectui-changeset, check:spec-parsed-alias, check:type-source-resolution, check:query-options-erasure, check:engine-double-contract, check:where-matcher, check:type-check-coverage, check:type-check-debt (33 entries, none above), check:nul-bytes, spec liveness family, check:doc-formula-expressions, check-dev-prereqs — all green locally. Remote CI on PR #9206: in_progress at report time (per contract, the convergence wait is the PM's).", "open_questions": [], "out_of_scope_findings": [] }
Generated by Claude Code
Generated by Claude Code
- added a commit that references this issue
on Sep 1, 2026 - added a commit that references this issue
on Sep 29, 2026 - added a commit that references this issue
on Oct 9, 2026
Provenance
Slice B (Direction 2) of the #8772 maintainer ruling (2026-08-16, comment 5306089973): the authoring builder forces
required: trueon amaster_detailreference under acontrolled_by_parentobject, so the unsafe shape cannot be newly declared. Carved into its own card on the maintainer's 2026-08-16 instruction (PM chat, verbatim: 「接受你的建议,开新卡,现有的可以关闭?」), recorded by PM sessionsession_01NYgmGheCzM6NrHZN436Cxf. Intended lane:domain:spec(lands inpackages/spec's authoring builder) —domain:*left for triage per the single-producer rule.Dispatch note:
model: claude-fable-5mandatory — authorable-shape narrowing (standing tiering rule).The work
controlled_by_parentobject's mastermaster_detailreference sets/forcesrequired: true(and refuses/corrects an explicitrequired: falsethere, loudly).resolveCbpRelation's fallbacks stay (tolerance for existing installs); lint stayswarninguntil the v18 sibling card lands. This slice is the bridge that makes new metadata safe while old metadata stays tolerated.examples/**,packages/platform-objects/**) holds exactly 3controlled_by_parentobjects, all alreadyrequired: true— migration cost measured at zero for first-party.validate-security-posture.test.tslives inpackages/lint/(the Acontrolled_by_parentobject may declare its master reference withoutrequired, so the master-access guard is the only thing preventing an unreachable orphan detail row #8772 body mis-homed it) and pins runtime resolution, not the builder — it should stay green under this slice.Re-check before acting
git grep -n "controlled_by_parent" origin/main -- packages/spec | headrequiredon that shape (the Acontrolled_by_parentobject may declare its master reference withoutrequired, so the master-access guard is the only thing preventing an unreachable orphan detail row #8772 table's row 3).Refs: #8772 (ruling + measurement) · siblings: guard freeze note (identity, lands first), lint warning→error at v18 (devx).