Skip to content

spec builder: force required: true on a master_detail reference under controlled_by_parent (ruled Direction 2 of #8772) #9138

Description

@os-zhuang

Provenance

Slice B (Direction 2) of the #8772 maintainer ruling (2026-08-16, comment 5306089973): the authoring builder forces required: true on a master_detail reference under a controlled_by_parent object, 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 session session_01NYgmGheCzM6NrHZN436Cxf. Intended lane: domain:spec (lands in packages/spec's authoring builder) — domain:* left for triage per the single-producer rule.

Dispatch note: model: claude-fable-5 mandatory — authorable-shape narrowing (standing tiering rule).

The work

  • The builder path that emits a controlled_by_parent object's master master_detail reference sets/forces required: true (and refuses/corrects an explicit required: false there, loudly).
  • ⛔ Runtime untouched: resolveCbpRelation's fallbacks stay (tolerance for existing installs); lint stays warning until the v18 sibling card lands. This slice is the bridge that makes new metadata safe while old metadata stays tolerated.
  • The 2026-08-15 survey stands: the shipped surface (examples/**, packages/platform-objects/**) holds exactly 3 controlled_by_parent objects, all already required: true — migration cost measured at zero for first-party.
  • Consumer-package fixture triage per standing rule (spec-touching change ⇒ run consumer packages' tests).
  • Note for implementer: validate-security-posture.test.ts lives in packages/lint/ (the A controlled_by_parent object may declare its master reference without required, 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

Refs: #8772 (ruling + measurement) · siblings: guard freeze note (identity, lands first), lint warning→error at v18 (devx).

Activity

  1. os-project-manager commented on Aug 16, 2026

    @os-project-manager
    Collaborator

    Triage: domain:spec added (lands in packages/spec's authoring builder; single-producer rule), pm:queue kept, type Task — maintainer-ruled implementation (Direction 2 of #8772, ruling comment linked in the card).

    This narrows the authorable accept face (an explicit required: false on that shape becomes a loud refusal), so the card's own model: claude-fable-5 mandatory 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

  2. os-project-manager commented on Aug 17, 2026

    @os-project-manager
    Collaborator

    Claiming for implementation.

    • Session: session_01Y26DJEHSBhhAQ6wwfsHNza
    • Branch: claude/issue-9138-cbp-master-detail-required

    Scope per the #8772 ruling, Direction 2: builder-only — force required: true on the master master_detail reference under a controlled_by_parent object, loud refusal on explicit required: false. Runtime (resolveCbpRelation) and lint severity untouched.


    Generated by Claude Code


    Generated by Claude Code

  3. os-project-manager commented on Aug 17, 2026

    @os-project-manager
    Collaborator
    {
      "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

  4. added a commit that references this issue on Sep 1, 2026
  5. added a commit that references this issue on Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions