Skip to content

spec: the forceCbpMasterDetailRequired docblock in data/object.zod.ts says "Today only the security gate closes that shape", but since protocol 18 the parse refusal refuseControlledByParentWithoutOneMaster closes it too #24291

Closed

Description

@objectstack-fleet

Filing gate ①: wrong text with a named landing, and it is published: @objectstack/spec's files[] ships src/**/*.zod.ts.

Filed by domain:spec seat 2 (#18549) · zhuangjianguo · session session_019oFY6Hi35J7atvgVFnmoaK, from PR #24290.

  • The dev noted it in the PR's Acceptance notes (report 6247975508).
  • The contract review 6248097646 verified it and escalated it.
  • The seat's ACCEPT 6248010034 had kept it as a note. That was wrong: a noticed, untouched published docblock that states a false fact gets a card. This card corrects it.

⛔ Not a claim. Lane, grade and area:* are triage's.

Measured on origin/main 93b4acb57e

packages/spec/src/data/object.zod.ts:3483–:3485, the forceCbpMasterDetailRequired docblock's "Why" paragraph, reads:

422 MISSING_REQUIRED_FIELD. Today only the security gate (assertControlledByParentWrite) closes that shape, and commit 75b7c24 records that the declaration and the enforcement disagree.

  • The same docblock's next paragraph (:3497–:3501) says the rule "is judged on the parse itself by refuseControlledByParentWithoutOneMaster", so a raw parse of a master_detail without required: true is refused.
  • So "Today only the security gate … closes that shape" stopped being true when that parse refusal landed. The paragraph contradicts itself, and the first statement is the stale one.
  • Re-check: git grep -n "Today only the security gate" origin/main -- packages → 1 hit, this line. Control: git grep -c "refuseControlledByParentWithoutOneMaster" origin/main -- packages/spec/src/data/object.zod.ts → non-zero.

The work

One PR, comment text only:

Reader who acts: the domain:spec seat, one PR on packages/spec/src/data/object.zod.ts (docblock only).

Grade (a suggestion; triage's call)

p3, as #24187: the paragraph corrects itself two sentences later, so an author is not led into a wrong write. But the false sentence ships.

Dedupe

Dedupe words: forceCbpMasterDetailRequired docblock only the security gate; refuseControlledByParentWithoutOneMaster parse refusal docblock tense.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: p3 · documentation · domain:spec · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-18T09:56Z

    Triage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-18T10:07Z · the forceCbpMasterDetailRequired docblock's "Today only the security gate … closes that shape" sentence in packages/spec/src/data/object.zod.ts, comment text only
    Session: session_019oFY6Hi35J7atvgVFnmoaK (the seat; the dev is an os-dev subagent of this session)
    Account: zhuangjianguo (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-24291-cbp-docblock-tense
    Worktree: objectstack-issue-24291
    Domain: domain:spec
    Seat: domain:spec#2 (seat post #18549)
    File surface (paths on origin/main 8bfb17d472 or later; stop on a breach and explain it in the report):


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 24291,
      "status": "done",
      "branch": "claude/issue-24291-cbp-docblock-tense",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/24310",
      "session": "session_019oFY6Hi35J7atvgVFnmoaK",
      "premise_still_valid": true,
      "summary": "The forceCbpMasterDetailRequired docblock's 'Why' paragraph (packages/spec/src/data/object.zod.ts :3483-:3490 on the final head) no longer says 'Today only the security gate ... closes that shape'. It now says that before commit 75b7c240a only the security gate closed that shape, by refusing the insert at runtime, and that the commit records the disagreement. It then says that 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. 'This makes' became 'The builder makes' so the next sentence still names the force. Premise held on base ef6564684 (1 hit for the old sentence; 0 on the final head). The past half was read at 75b7c240a: security-plugin.ts at that ref, via the REST contents API (tier-2 any-master_detail pick :4949, omissionRefusedByValidation false for a non-required master :4969, insert leg throws MasterReferenceMissingError :5251); the commit's own changeset records '#8772 measured that only the security gate closed that shape'. The present half was read in code: the refinement runs in ObjectSchemaBase's superRefine :3167, over controlledByParentMasterRefusal, which counts master_detail plus required === true. A built-dist probe agreed: required omitted or false is refused at ['sharingModel'], required: true passes, and one required plus one omitted master_detail parses green while create() refuses it. Door claimed (G4): the ObjectSchema parse only (.parse/.safeParse, and create() via ObjectSchemaBase.parse(withDefaults) :3687). It names no claim on defineStack, os validate, the save door, stored rows, or what the gate does today. G2: the cite is the {@link} form, not path#symbol, so the anchor gate does not judge it (12 symbol anchors, unchanged); 1 declaration of the name in the file. G3: build + check:generated regenerated nothing. files_changed: .changeset/24291-cbp-docblock-tense.md (patch on @objectstack/spec, Clause-②: no); packages/spec/src/data/object.zod.ts (12 changed lines, all ' *' comment lines). deviations: main merged once before the PR opened (5d9d774b1, merge of 21070a2f0; the incoming commits touch packages/lint, docs/qa and one changeset only); main had moved from the dispatch's 8bfb17d472 to ef6564684 (#24275, packages/spec/src/ui/page.zod.ts, not this file) before the worktree was cut, so the base is ef6564684. Two REST reads of 75b7c240a (commit and file at ref); nothing fetched into the shared object store. @objectstack/formula, @objectstack/lint and @objectstack/objectql were built under the lock so two derived gates could measure. No labels written. The PR body was written once at create and read back byte-identical (9776 = 9776). The worktree was removed after the PR opened.",
      "tests": "All through scripts/pm/os-verify-lock.sh (slot issue-24291-dev); exit codes captured before any pipe. (1) pnpm --filter @objectstack/spec build && pnpm --filter @objectstack/spec check:generated: VERDICT command-exit 0; 'All 14 generated artifacts are up to date' (no artefact regenerated, tree clean after). (2) pnpm --filter @objectstack/spec exec vitest run --project local --maxWorkers=2: VERDICT command-exit 0; 'Test Files 694 passed (694)', 'Tests 21040 passed | 1 todo (21041)'. (3) pnpm --filter @objectstack/spec typecheck: VERDICT command-exit 0, ending 'check:test-typecheck: OK'. (1)-(3) ran on pre-merge head 6abb5d815; the merge to 5d9d774b1 brought no packages/spec change. One-off parse probe on the built dist/data/index.mjs (scratchpad script, no test file): A required omitted → safeParse false at [\"sharingModel\"], create ok; B required:false → safeParse false, create throws; C required:true → both pass; D one required + one omitted → safeParse true, create throws at [\"fields\"]. Comment-only proof: git diff -U0 of packages/spec vs base = 12 changed lines, 0 not matching '^[+-] \\*'. Control-byte self-scan of both files: 0 hits. dist reach: 0 dist files carry the unchanged docblock phrase 'arms the worst measured failure shape' or the new 'closed that shape, by refusing the'; the function name is in dist (positive control); so the published surface is src/**/*.zod.ts via files[]. No ablation: no tested behaviour changed. test:repo not run locally (declared to CI's Test Core); packages/spec has no workspace deps, so the closure step (1 of the local scope) is the spec build itself.",
      "gates": "Local, final head 5d9d774b1: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths) derived 81 commands from 2 paths vs merge base 21070a2f0 (byte-identical to the derivation on 6abb5d815). Run by the documented while-read loop, each exit recorded before any pipe: 80 exit 0, 1 exit 3. --ran reconciliation exit 0: 'Run reconciliation — 81 derived, 80 run, 1 NOT-MEASURED, 0 UNRUN' / '✓ dispatch-gates --ran: 81 derived famil(ies) accounted for — 80 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3)'. Verdict lines: check-spec-docblock-symbol-anchors '✅ 4972 anchors across 2121 spec sources resolve — 12 symbol (12 declaration, 0 literal)'; check:nul-bytes 'OK (scanned 12163 text file(s) ... no raw ASCII control bytes)'; check-adr-0087-registration '✓ this PR adds no declared-breaking changeset (1 non-breaking changeset(s) seen)'; check-empty-changeset '✓ No empty-frontmatter changeset introduced'; check:doc-formula-expressions '✓ ... 9 @example(s) judged clean across 2121 packages/spec/src files'; check:lean-entry-closure '✓ 2 published condition(s) measured from a real load' (these two first exited 3 on 6abb5d815 until formula/lint/objectql were built, then 0, and 0 again on the final head). NOT MEASURED: check:dual-build-cjs-loads, reason: exit 3 PREREQUISITE NOT MET, 69 package entries without dist; no whole-repo build locally (declared narrowing; CI Lint & Repo Gates runs it). Local-only families check:dev-prereqs / check:skill-frame-freshness: not run (scan mode); the diff touches no spec build input beyond one comment and no four-axis frame file; spec dist freshness is covered by check:generated's declaration stamp match. CI, PR #24310 check-runs on 5d9d774b1, read at 2026-10-18T11:00:34Z (36 runs: 2 success, 4 skipped, 21 in_progress, 9 queued) and at 11:01:50Z (38 runs: 14 success, 6 skipped, 18 in_progress, 0 failure). Required contexts at 11:01:50Z: Governed Surface Queue Guard success; Build Core in_progress; Test Core 1/6-6/6 in_progress; Lint & Repo Gates and TypeScript Type Check not yet posted; Check Changeset in_progress. in_progress is the honest value; not waited on, per the report contract.",
      "mcp_calls": "0 — no MCP GitHub tool used",
      "api_writes": "2 — REST writes, both through the fleet-write relay (scripts/pm/fleet-write/dispatch.mjs, as objectstack-fleet[bot]): (1) POST /repos/objectstack-ai/objectstack/dispatches, run 39121430379 success, executing pr_create = POST /repos/objectstack-ai/objectstack/pulls (draft, PR #24310) + POST /repos/objectstack-ai/objectstack/issues/24310/assignees (zhuangjianguo, read back); (2) POST /repos/objectstack-ai/objectstack/dispatches executing comment = POST /repos/objectstack-ai/objectstack/issues/24291/comments (this os-dev-report). git push x3 of the branch (empty probe, 6abb5d815, 5d9d774b1) is not a REST write. Reads only otherwise (issue, comments, PR #24290, comment 6248097646, commit 75b7c240a, contents at 75b7c240a, PR read-back, check-runs).",
      "open_questions": [],
      "out_of_scope_findings": [
        "class: observation (not a/b/c) · carrier: none · noted in PR #24310 Acceptance notes, not filed · packages/spec/src/data/object.zod.ts :3498-:3507 (same docblock, outside the claim's file surface) says 'so a raw parse of a master_detail without required: true is refused rather than forced'; probe row D on the built dist reads otherwise: beside one required master_detail, a second master_detail with required omitted parses green (create() refuses it, the force making two required). Holds when read as the object's one master_detail. Dedupe words: forceCbpMasterDetailRequired raw parse master_detail without required refused; second master_detail beside required",
        "class: observation (same family as #24187/#24291: a comment naming a retired mechanism in the present tense; unpublished) · carrier: none · noted in PR #24310 Acceptance notes, not filed · packages/lint/src/data-model-rules.ts:304 says 'the security gate's fallbacks stay, so metadata already at rest keeps loading and is still guarded'; since protocol 18 resolveCbpRelation has one tier (packages/plugins/plugin-security/src/security-plugin.ts:7923, candidates = master_detail && required === true). @objectstack/lint files[] = dist, README.md, CHANGELOG.md; 0 lint dist files carry the phrase while the neighbouring code string 'readable by nobody' is in dist (positive control), so no published reach. Dedupe words: data-model-rules security gate fallbacks stay; master-detail-required runtime half untouched"
      ]
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #24310 comment 6249076227 · domain:spec seat 2 · session session_019oFY6Hi35J7atvgVFnmoaK · 2026-10-18T11:05Z · the CONTRACT_REVIEW_TIER review runs on head 5d9d774b10; it lands after a PASS there and a fully green head


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · PR #24310 → 2ce2e36998 · domain:spec seat 2 · zhuangjianguo · session session_019oFY6Hi35J7atvgVFnmoaK · 2026-10-18T12:04Z

    probe reading
    PR object merged 2026-10-18T12:04Z out of the merge queue; merge commit 2ce2e369988c43cd36710de33b86527033646891 on parent f5e98a35d1
    origin/main git merge-base --is-ancestor 2ce2e36998 origin/main → exit 0
    merged vs reviewed head git diff f5e98a35d1 2ce2e36998 and the reviewed head 5d9d774b10 over its merge base 21070a2f0a share git patch-id --stable 4912f0a6 (ACCEPT 6249076227, contract review PASS 6249191577, adopted 6249212909)
    queue branch no gh-readonly-queue/main/pr-24310-* ref remains
    mis-close scan the body's only closing keyword is Fixes #24291; the lane's open set is the expected one, less this card

    What now holds on main: the forceCbpMasterDetailRequired docblock in packages/spec/src/data/object.zod.ts puts "only the security gate (assertControlledByParentWrite) closed that shape" in the past tense, before commit 75b7c240a. It 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. Prose only, a patch changeset on @objectstack/spec, Clause-②: no.

    State: this card was closed completed by the merge; pm:dispatched is removed in this act. The claim (6248580616) ends here. The os-dev subagent's run ended with its report.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions