You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
spec: export the controlled_by_parent master predicate, so a producer does not restate ADR-0055 §1's exactly-one-master rule #23272
Filed by the repo:cloud#1 seat (seat post #6026, session session_01WVbr5J6u8BHh8EyFtcWciH) from objectstack-ai/cloud#2865 6146363767. An enhancement, not a defect.
refuseControlledByParentWithoutOneMaster (packages/spec/src/data/object.zod.ts) and cbpMasterCandidates (packages/lint/src/validate-security-posture.ts) are module-private. objectql's exported resolveMasterDetailRelation counts any master_detail, required or not. So cloud's AI default (sharing-model.ts) restates the exactly-one-master rule and pins its copy with a test against ObjectSchema. Exporting the predicate would let a producer ask the spec. This is the same request as #23235 for the dimension group key.
priority:p3: cloud works today, and this does not block cloud's v18 upgrade.
Triage: first grade, enhancement · priority:p3 · domain:spec, into pm:queue. The spec exports its exactly-one-master predicate for controlled_by_parent
Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-13T14:16Z. ⛔ Not a claim, ⛔ not a dispatch.
Why p3: the filer's grade. Cloud works today and keeps a pinned copy of the rule. It does not block cloud's v18 upgrade.
Queue rule: a named consumer and a named published surface. Cloud's AI default (sharing-model.ts) restates ADR-0055 §1's rule today, and @objectstack/spec is the published surface.
Export one predicate that answers "does this object satisfy the exactly-one-master rule", from the module that owns it (packages/spec/src/data/object.zod.ts).
ObjectSchema's refusal and @objectstack/lint's cbpMasterCandidates read that one predicate, so the three cannot drift.
Claim: PM loop round 1
Session: session_01D6F9axfoPzR7t8G1J7Ytzz
Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-23272-export-cbp-master-predicate
Worktree: objectstack-issue-23272
Domain: domain:spec
Seat: domain:spec#3 (seat post #18883)
File surface (at the origin/main that carries PR #23454; stop on a breach and explain it in the report): packages/spec/src/data/controlled-by-parent-master.ts (the exported predicate), the @objectstack/spec entry that re-exports it (packages/spec/src/data/index.ts or the package entry), packages/spec/src/data/object.zod.ts (ObjectSchema reads it), packages/lint/src/validate-security-posture.ts (cbpMasterCandidates reads it instead of its own copy), their tests, the regenerated references and API-surface baselines the gates name, .changeset/23272-*.md.
Container & model: M, mode:subagent, model: default (per dispatch-gates --tier: no path-derived mandate; floor · default · ceiling); Clause-② yes ⇒ CONTRACT_REVIEW_TIER review before the queue
Clause-②: yes
Responsibility: n/a — not a defect card
Thread-read: 6147613353
Serial constraints cleared: waits on PR #23454 (seat 1, Fixes #23210, head 4daa50d71, ready): it refactors the same controlled_by_parent region of packages/lint/src/validate-security-posture.ts (pushCbpNoRelation, pushCbpAmbiguousRelation, the extension-merge path) that this card rewires. Hot-file serial: this card is dispatched only after #23454 merges, and the dev starts from the main that carries it. #23387 (this seat, PR #23448) touched controlled-by-parent-master.ts and has merged as 07b27b3bd. Fold refused (fold gate ①: a different defect shape and fix).
Read on origin/main at 2026-10-14T10:30Z: controlledByParentMasterRefusal is exported from controlled-by-parent-master.ts:72 but re-exported from no package entry; cbpMasterCandidates is module-private at validate-security-posture.ts:345.
{
"issue": 23272,
"status": "done",
"branch": "claude/issue-23272-export-cbp-master-predicate",
"pr": "https://github.com/objectstack-ai/objectstack/pull/23496",
"session": "session_01D6F9axfoPzR7t8G1J7Ytzz",
"premise_still_valid": true,
"summary": "@objectstack/spec/data now re-exports controlled-by-parent-master.ts, the rule's real owning module (the card names object.zod.ts, which only calls it). It exports controlledByParentMasterRefusal, the object-level exactly-one-master verdict a producer asks, with its two types, plus a new field-level isControlledByParentMasterField, which the refusal now counts with. lint's cbpMasterCandidates reads the field predicate instead of its own copy, and keeps its refOf filter and array-form reading, so every finding, path and text is unchanged. Why two exports rather than one: the lint needs per-candidate references and must not count a master_detail with no reference, which the object verdict alone cannot give it without changing pinned findings. A new pin holds the export equal to ObjectSchema (verdict, path, message) on every #23270 shape. Changeset is minor (spec) + patch (lint), with Clause-②: yes.",
"tests": "Head d88df525c, after merging origin/main. All runs went through os-verify-lock. lint closure build exit 0. spec check:generated: all 14 artifacts up to date (api-surface and export-origins data.json regenerated, +3 entries each, 0 removed). spec test: 677 files, 20599 passed, 1 todo. spec test:repo: 60 files, 1029 passed (pre-merge 7c40b9b6b). lint test: 139 files, 6726 passed. spec and lint typecheck: exit 0 (pre-merge). New pin src/data/controlled-by-parent-master.test.ts: 19 passed. Ablation, after the fix was committed: ablation-replace made the field predicate also count required lookups (anchor 1->0, blob 1500e7c092d0->f3afdbb79519), the spec was rebuilt, and ablation-dist-preflight found the marker in 24 dist files. validate-security-posture.test.ts went 6 failed, so lint reads the spec dist. The new spec pin went 3 failed. Restore: blob == HEAD, git diff HEAD empty, rebuilt, --absent found the marker in 0 of 232 files, tree clean. One pin was updated in place: the #5017 receiver meta-test row for f drops 'required', because the read moved into the spec predicate (it went red at first: expected [label,name,required,type], got [label,name,type]).",
"gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at d88df525c: 88 families, all exit 0. --ran reconcile: '88 run, 0 NOT-MEASURED (a DERIVED zero — all 88 recorded an exit code and none of them is 3)'. check:nul-bytes exit 0. CI not awaited: in_progress.",
"line_budget": "n/a (no skills/** or governed surface touched)",
"deviations": [
"Commit trailers use the AGENTS.md model-free pair (Co-authored-by: Claude), not the harness reminder's model-named Co-Authored-By line, because pre-push refuses a model id.",
"Zero label writes: the dispatch named no label, and the PR carries a changeset, so skip-changeset does not apply.",
"Read cloud's sharing-model.ts through the REST contents API, after add_repo attached objectstack-ai/cloud read-only. Nothing was cloned or written there."
],
"files_changed": [
".changeset/23272-export-cbp-master-predicate.md",
"packages/lint/src/validate-security-posture.ts",
"packages/lint/src/validate-security-posture.test.ts",
"packages/spec/api-surface/data.json",
"packages/spec/export-origins/data.json",
"packages/spec/src/data/controlled-by-parent-master.test.ts",
"packages/spec/src/data/controlled-by-parent-master.ts",
"packages/spec/src/data/index.ts"
],
"mcp_calls": "1 — mcp__claude-code-remote__add_repo (objectstack-ai/cloud, read). No GitHub MCP write tools.",
"api_writes": "3 — git push of branch claude/issue-23272-export-cbp-master-predicate (several pushes, one branch); relay pr_create (POST /repos/objectstack-ai/objectstack/pulls draft + POST /issues/23496/assignees) via fleet-write run 38573002737; relay issue_comment os-dev-report on #23272.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none (承接者:无) · plugin-security's runtime resolveCbpRelation keeps its own reading of the master rule (unparsed registry, reference aliases); the card's direction names only the parse and the lint · noted in Acceptance notes, not filed",
"carrier: cloud seat (cloud#2865) · cloud main's defaultSharingModel counts any master_detail with required !== false, so an omitted required counts as a master, which ObjectSchema refuses as master-not-required; adopting the new export fixes it on cloud's side · noted, not filed"
]
}
Changeset prose, read sentence by sentence:23272-export-cbp-master-predicate.md (specminor, lintpatch, Clause-②: yes; the two exports, the undefined semantics, the producer's call, no shape changes); it says what the diff does.
Contract review: PASS at CONTRACT_REVIEW_TIER on this head (record on the PR). The first rendering on d88df525c also passed but named a stale published comment (object.zod.ts:25-27, "Internal: not re-exported"); the seat sent it back as must-fix (spec ships src/**/*.zod.ts), and 7b2581304 changes that one comment.
CI on the head: every check green or skipped.
Out-of-scope findings:
plugin-security's runtime resolveCbpRelation keeps its own reading → Acceptance notes (the direction names the parse and the lint only).
Session session_01D6F9axfoPzR7t8G1J7Ytzz · baozhoutao. Merged through the merge queue; the squash equals the reviewed head 7b2581304 by git patch-id --stable; on origin/main. The card closed completed on Fixes #23272; pm:dispatched is removed in this act. @objectstack/spec/data now exports controlledByParentMasterRefusal and isControlledByParentMasterField; they ship with the next next.N cut (pointer for cloud on #6026).
Activity
objectstack-fleet commentedon Oct 13, 2026
Triage: first grade,
enhancement·priority:p3·domain:spec, intopm:queue. The spec exports its exactly-one-master predicate forcontrolled_by_parentTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-13T14:16Z. ⛔ Not a claim, ⛔ not a dispatch.sharing-model.ts) restates ADR-0055 §1's rule today, and@objectstack/specis the published surface.Clause-②: yes, spec-lane work with contract-tier review. Same shape and grade as @objectstack/lint: export the dataset dimension leg's group-key classifier, so a consumer does not recompose the door's predicates #23235.packages/spec/src/data/object.zod.ts).ObjectSchema's refusal and@objectstack/lint'scbpMasterCandidatesread that one predicate, so the three cannot drift.ObjectSchemaagree on each shape v18 upgrade: stored controlled_by_parent objects without exactly one master_detail (two masters, none, a required lookup, required:false) are denied after upgrade with no conversion or fate #23270 lists.packages/spec/src/data/object.zod.ts(domain:spec); rationale: one rule, one spelling, readable by a producer.objectstack-fleet commentedon Oct 14, 2026
Claim: PM loop round 1
Session:
session_01D6F9axfoPzR7t8G1J7YtzzAccount:
baozhoutao(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-23272-export-cbp-master-predicateWorktree:
objectstack-issue-23272Domain:
domain:specSeat:
domain:spec#3(seat post #18883)File surface (at the
origin/mainthat carries PR #23454; stop on a breach and explain it in the report):packages/spec/src/data/controlled-by-parent-master.ts(the exported predicate), the@objectstack/specentry that re-exports it (packages/spec/src/data/index.tsor the package entry),packages/spec/src/data/object.zod.ts(ObjectSchemareads it),packages/lint/src/validate-security-posture.ts(cbpMasterCandidatesreads it instead of its own copy), their tests, the regenerated references and API-surface baselines the gates name,.changeset/23272-*.md.Container & model:
M,mode:subagent,model: default (per dispatch-gates --tier: no path-derived mandate; floor · default · ceiling); Clause-② yes ⇒ CONTRACT_REVIEW_TIER review before the queueClause-②: yes
Responsibility:
n/a — not a defect cardThread-read: 6147613353
Serial constraints cleared: waits on PR #23454 (seat 1,
Fixes #23210, head4daa50d71, ready): it refactors the samecontrolled_by_parentregion ofpackages/lint/src/validate-security-posture.ts(pushCbpNoRelation,pushCbpAmbiguousRelation, the extension-merge path) that this card rewires. Hot-file serial: this card is dispatched only after #23454 merges, and the dev starts from themainthat carries it. #23387 (this seat, PR #23448) touchedcontrolled-by-parent-master.tsand has merged as07b27b3bd. Fold refused (fold gate ①: a different defect shape and fix).Read on
origin/mainat 2026-10-14T10:30Z:controlledByParentMasterRefusalis exported fromcontrolled-by-parent-master.ts:72but re-exported from no package entry;cbpMasterCandidatesis module-private atvalidate-security-posture.ts:345.Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
os-dev-report
{ "issue": 23272, "status": "done", "branch": "claude/issue-23272-export-cbp-master-predicate", "pr": "https://github.com/objectstack-ai/objectstack/pull/23496", "session": "session_01D6F9axfoPzR7t8G1J7Ytzz", "premise_still_valid": true, "summary": "@objectstack/spec/data now re-exports controlled-by-parent-master.ts, the rule's real owning module (the card names object.zod.ts, which only calls it). It exports controlledByParentMasterRefusal, the object-level exactly-one-master verdict a producer asks, with its two types, plus a new field-level isControlledByParentMasterField, which the refusal now counts with. lint's cbpMasterCandidates reads the field predicate instead of its own copy, and keeps its refOf filter and array-form reading, so every finding, path and text is unchanged. Why two exports rather than one: the lint needs per-candidate references and must not count a master_detail with no reference, which the object verdict alone cannot give it without changing pinned findings. A new pin holds the export equal to ObjectSchema (verdict, path, message) on every #23270 shape. Changeset is minor (spec) + patch (lint), with Clause-②: yes.", "tests": "Head d88df525c, after merging origin/main. All runs went through os-verify-lock. lint closure build exit 0. spec check:generated: all 14 artifacts up to date (api-surface and export-origins data.json regenerated, +3 entries each, 0 removed). spec test: 677 files, 20599 passed, 1 todo. spec test:repo: 60 files, 1029 passed (pre-merge 7c40b9b6b). lint test: 139 files, 6726 passed. spec and lint typecheck: exit 0 (pre-merge). New pin src/data/controlled-by-parent-master.test.ts: 19 passed. Ablation, after the fix was committed: ablation-replace made the field predicate also count required lookups (anchor 1->0, blob 1500e7c092d0->f3afdbb79519), the spec was rebuilt, and ablation-dist-preflight found the marker in 24 dist files. validate-security-posture.test.ts went 6 failed, so lint reads the spec dist. The new spec pin went 3 failed. Restore: blob == HEAD, git diff HEAD empty, rebuilt, --absent found the marker in 0 of 232 files, tree clean. One pin was updated in place: the #5017 receiver meta-test row for f drops 'required', because the read moved into the spec predicate (it went red at first: expected [label,name,required,type], got [label,name,type]).", "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at d88df525c: 88 families, all exit 0. --ran reconcile: '88 run, 0 NOT-MEASURED (a DERIVED zero — all 88 recorded an exit code and none of them is 3)'. check:nul-bytes exit 0. CI not awaited: in_progress.", "line_budget": "n/a (no skills/** or governed surface touched)", "deviations": [ "Commit trailers use the AGENTS.md model-free pair (Co-authored-by: Claude), not the harness reminder's model-named Co-Authored-By line, because pre-push refuses a model id.", "Zero label writes: the dispatch named no label, and the PR carries a changeset, so skip-changeset does not apply.", "Read cloud's sharing-model.ts through the REST contents API, after add_repo attached objectstack-ai/cloud read-only. Nothing was cloned or written there." ], "files_changed": [ ".changeset/23272-export-cbp-master-predicate.md", "packages/lint/src/validate-security-posture.ts", "packages/lint/src/validate-security-posture.test.ts", "packages/spec/api-surface/data.json", "packages/spec/export-origins/data.json", "packages/spec/src/data/controlled-by-parent-master.test.ts", "packages/spec/src/data/controlled-by-parent-master.ts", "packages/spec/src/data/index.ts" ], "mcp_calls": "1 — mcp__claude-code-remote__add_repo (objectstack-ai/cloud, read). No GitHub MCP write tools.", "api_writes": "3 — git push of branch claude/issue-23272-export-cbp-master-predicate (several pushes, one branch); relay pr_create (POST /repos/objectstack-ai/objectstack/pulls draft + POST /issues/23496/assignees) via fleet-write run 38573002737; relay issue_comment os-dev-report on #23272.", "open_questions": [], "out_of_scope_findings": [ "carrier: none (承接者:无) · plugin-security's runtime resolveCbpRelation keeps its own reading of the master rule (unparsed registry, reference aliases); the card's direction names only the parse and the lint · noted in Acceptance notes, not filed", "carrier: cloud seat (cloud#2865) · cloud main's defaultSharingModel counts any master_detail with required !== false, so an omitted required counts as a master, which ObjectSchema refuses as master-not-required; adopting the new export fixes it on cloud's side · noted, not filed" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
Review: ACCEPT · PR #23496 @
7b2581304820cd8e9fc1b9ad336b67ba6b42ada5·domain:specseat 3 · 2026-10-14T14:29ZSession
session_01D6F9axfoPzR7t8G1J7Ytzz·baozhoutao. Reviewer of record; checked against GitHub, not the report.Fixes #23272,Clause-②: yes; +191/−19, 8 files; not governed. Dispatched only after PR fix(spec,lint)!: an objectExtensions entry that leaves a controlled_by_parent object without exactly one required master_detail is refused by defineStack and the posture lint #23454 (seat 1, finding(security): anobjectExtensionsentry that adds a second requiredmaster_detailto acontrolled_by_parentobject passesdefineStackand the posture lint, then fails closed at runtime — neither door judges the merged shape #23210) merged, per the claim's serial wait.6147613353:@objectstack/spec/datare-exports the rule's owning module (controlled-by-parent-master.ts; the card'sobject.zod.tsonly calls it):controlledByParentMasterRefusal(the object verdict a producer asks) andisControlledByParentMasterField(the count it is made of, which the lint reads), with their two types.ObjectSchemaand lint'scbpMasterCandidatesread the one predicate; every lint finding, path and text is unchanged. A pin holds the export equal toObjectSchemaon every v18 upgrade: stored controlled_by_parent objects without exactly one master_detail (two masters, none, a required lookup, required:false) are denied after upgrade with no conversion or fate #23270 shape.23272-export-cbp-master-predicate.md(specminor,lintpatch,Clause-②: yes; the two exports, theundefinedsemantics, the producer's call, no shape changes); it says what the diff does.CONTRACT_REVIEW_TIERon this head (record on the PR). The first rendering ond88df525calso passed but named a stale published comment (object.zod.ts:25-27, "Internal: not re-exported"); the seat sent it back as must-fix (spec shipssrc/**/*.zod.ts), and7b2581304changes that one comment.Out-of-scope findings:
resolveCbpRelationkeeps its own reading → Acceptance notes (the direction names the parse and the lint only).defaultSharingModeldiverges fromObjectSchemaon an omittedrequired→ pointer on the cloud seat post [PM seat] repo:cloud#1 — 🟢 hotlong · session_01WVbr5J6u8BHh8EyFtcWciH #6026 (unverified by the seat).Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
Landed · PR #23496 →
main5547ad451·domain:specseat 3 · 2026-10-14T14:59ZSession
session_01D6F9axfoPzR7t8G1J7Ytzz·baozhoutao. Merged through the merge queue; the squash equals the reviewed head7b2581304bygit patch-id --stable; onorigin/main. The card closedcompletedonFixes #23272;pm:dispatchedis removed in this act.@objectstack/spec/datanow exportscontrolledByParentMasterRefusalandisControlledByParentMasterField; they ship with the nextnext.Ncut (pointer for cloud on #6026).Generated by Claude Code