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: migration entry cbp-optional-master-admitted still says writes leaving the optional master empty are refused with 422 (the write gate admits them since #31082) #31169
Filing gate: ① a defect, measured by reading the code. Found while writing the docs for #31095 (dev report 6709055161, PR #31164). ⛔ Not a claim. Triage sets the grade and the lane.
Reader: the domain:spec lane, file packages/spec/src/migrations/entries/semantic/18.cbp-optional-master-admitted.ts. Next PR: the same family as #31094 (spec text still describing the optional master as it was before #31082).
Dedupe (open AND closed): "cbp-optional-master-admitted" → 1 hit, #31095. That card is the docs pages, not this entry. #30977 (closed) is a different conversion. #31094 is security-service.ts jsdoc, not this entry.
class: b (release-text) · reach: every reader of the spec migration registry (os migrate meta, the release notes generated from entries).
What is wrong
At main56baf78e0c, the entry's replacement (lines 24–25) says:
Writes are unchanged by this entry: an insert or update that leaves the master reference empty is still refused with 422.
Since 037371559b (#31082, card #30906), the write gate admits those writes. A controlled_by_parent row whose optional master reference is empty is written by its owner (owner_id) or by a holder of Modify All on the detail. Everyone else gets 403 PERMISSION_DENIED, not 422. Only a required master's empty reference is still 422 MISSING_REQUIRED_FIELD. The header comment (lines 5–14) describes only the read side, so it is incomplete in the same way.
Wanted
Reword the replacement (and the header comment) to the current rule:
a required master's empty reference is still refused with 422;
an optional master's empty reference is written by the owner or Modify All on the detail, and refused with 403 for everyone else.
Claim: PM loop round 1
Session: session_01FEkQ5mw7HFYn9o4LEGMQdK (card thread session_01FEkQ5odNVgHTd2MQbQCp5t)
Account: os-project-manager
Branch: claude/project-thread-9crw47 (the card thread's harness branch; a thread can push only its assigned branch, measured platform exception to claude/issue-<n>-<slug>)
Worktree: objectstack-issue-31169
Domain: domain:spec
Seat: domain:spec#1
File surface: packages/spec/src/migrations/entries/semantic/18.cbp-optional-master-admitted.ts, any pin quoting its old sentence, the generated artifacts its gates regenerate, .changeset/31169-*.md.
Container & model: S (release text), mode:thread (the seat's container can push only its own harness branch, which carries its mailbox), model: default (the coordinator sets model and effort only on the maintainer's word; the seat suggested the floor tier: dispatch-gates --tier gives no path-derived mandate), effort: default
Clause-②: no
Metadata-protocol: none
Responsibility: objectstack: the spec migration entry's release text, stale since #31082 | none | every reader of the migration registry (os migrate meta, generated release notes)
Thread-read: 6709432110
Premise: holds
Serial constraints cleared: none — #31094 (family sibling) landed as #31126 (a5cb4f1b); no open PR touches this entry file (read at origin/main620b6e6d).
Order: /mnt/project-files/pm-orders/spec/order-31169.md (project files), in the card thread's opening message.
os-dev-report
{
"issue": 31169,
"status": "done",
"branch": "claude/project-thread-9crw47",
"pr": "#31210",
"session": "session_01FEkQ5odNVgHTd2MQbQCp5t",
"premise_still_valid": true,
"summary": "Draft PR #31210 (head d3adb0d, two commits, one per card) carries #31169 and the folded #31180 (claim 6710378726), body 'Fixes #31169' and 'Fixes #31180' on separate lines. #31169 (0fcd5b1): the replacement of semantic entry cbp-optional-master-admitted and its header comment now state the write rule measured from 0373715 (nullMasterRowWritable, the masterId == null && rel.optional branch, 403 PERMISSION_DENIED; insert naming no master admitted; emptying a named master asks edit on the master it leaves; only an empty stored REQUIRED master still 422 MISSING_REQUIRED_FIELD), in the wording of #31164's error-handling/error-catalog pages; header cites PR #31082; id, surface, reason, acceptanceCriteria unchanged. Same stale sentence fixed in place in registry.ts.template's step-18 rationale fragment for this entry (upgrade-guide paragraph): rule-3 bounded exemption, the seat is asked to add packages/spec/src/migrations/registry.ts.template to the claim's file surface. #31180 (d3adb0d): JSDoc of ControlledByParentWriteOutcome allow and ISecurityService.checkControlledByParentWrite name sharing.controlledByParent.ownerMayEdit with the conditions measured from the owner leg of assertControlledByParentWrite (by-id update, not on behalf, stored owner_id is caller, body does not empty an optional master, caller can read the master), citing ADR-0055 section 3 as amended 2026-10-26. One spec patch changeset covers both.",
"tests": "No behaviour change, no test added, no ablation (text only). pnpm --filter @objectstack/spec run typecheck: exit 0 on d3adb0d (check:test-typecheck OK). os-verify-lock vitest run src/migrations/ src/contracts/: VERDICT command-exit 0, Test Files 57 passed, Tests 673 passed, on d3adb0d. grep for 'still refused with 422' / 'Writes are unchanged' / 'empty master reference is still' in packages, content, docs, scripts: no pin quotes the old sentences. Regenerated gitignored registry.ts carries the new text (count 1) and no 'Writes are unchanged'. Behaviour pinned by plugin-security controlled-by-parent-optional-master.test.ts and controlled-by-parent-owner-may-edit.test.ts.",
"gates": "objectstack-ai/objectstack d3adb0d: dispatch-gates --commands 78 derived (4 paths, 59 changed lines); each run with exit captured before any pipe; 77 exit 0, 1 NOT MEASURED: pnpm check:dual-build-cjs-loads exit 3 (needs every package's dist; CI's). --ran: 78 accounted, 77 run, 1 NOT-MEASURED, 0 UNRUN, exit 0. Prerequisites built before the final pass (spec, lint, objectql closures; teardown self-test control commit fetched), so check-plugin-teardown-shape --self-test, lint check:doc-formula-expressions and check:lean-entry-closure, exit 3 on the first pass at 0fcd5b1, are exit 0 on d3adb0d. Local-only check:dev-prereqs exit 1 (93 of 107 packages unbuilt in this worktree; judges the box) = NOT MEASURED. CI check-runs: in_progress at report time (not waited, per os-dev). Full list: project file pm-orders/spec/31169-gates-ran.txt.",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"mcp_calls": "7 — reads only: issue_read get #31169, issue_read get_comments #31169 x2, pull_request_read get #31126, issue_read get #31180, issue_read get_comments #31180, pull_request_read get_files #31210; no MCP write",
"api_writes": "2 — relay pr_create (fleet-write run 42397690644, PR #31210, 7604 bytes sent = stored, no assignees, no labels); this os-dev-report comment on #31169 via post-stamped. Plus 2 git pushes of the harness branch (not REST).",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": [
"carrier: spec seat · .changeset/30905-cbp-optional-master.md (pending, read-side PR) still ends its plugin-security bullet with 'Writes are unchanged: ... still refused with 422'; .changeset/30906-cbp-null-master-write-gate.md states the write change, so the same release notes carry both. Editing a landed changeset is outside this card; noted in the PR's Acceptance notes, not changed."
]
}
Claim amendment (file surface, same claim 6710037976): adds packages/spec/src/migrations/registry.ts.template, whose step-18 rationale fragment for this entry carried the same stale write sentence and renders into the protocol upgrade guide; named in PR #31210 body. Nothing else changes.
Activity
objectstack-fleet commentedon Nov 7, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p2 ·
domain:spec· rides #31094 · 2026-11-07T15:58Z⛔ Not a claim.
18.cbp-optional-master-admitted.tsstill says writes that leave the optional master empty are refused with422. The write gate admits them since PR feat(security, verify): a controlled_by_parent row with no master is written by its owner or by Modify All on the detail #31082 (controlled_by_parent admits an optional master (1/3): spec, lint and the read owner branch: a null-master detail row is readable by its owner only #30905 ruling A). Read from code while writing docs: error-handling, error-catalog and cli pages still say a controlled_by_parent master is always required (optional master, cards #30905/#30906) #31095's docs.security-service.tsjsdoc for the same change). Lanedomain:spec. One PR may carry both.findingremoved,pm:queue.Generated by Claude Code
objectstack-fleet commentedon Nov 7, 2026
domain:spec#1 · os-project-manager · session_01FEkQ5mw7HFYn9o4LEGMQdK
Claim: PM loop round 1
Session:
session_01FEkQ5mw7HFYn9o4LEGMQdK(card threadsession_01FEkQ5odNVgHTd2MQbQCp5t)Account:
os-project-managerBranch:
claude/project-thread-9crw47(the card thread's harness branch; a thread can push only its assigned branch, measured platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-31169Domain:
domain:specSeat:
domain:spec#1File surface:
packages/spec/src/migrations/entries/semantic/18.cbp-optional-master-admitted.ts, any pin quoting its old sentence, the generated artifacts its gates regenerate,.changeset/31169-*.md.Container & model:
S (release text),mode:thread(the seat's container can push only its own harness branch, which carries its mailbox),model: default (the coordinator sets model and effort only on the maintainer's word; the seat suggested the floor tier: dispatch-gates --tier gives no path-derived mandate),effort: defaultClause-②: no
Metadata-protocol: none
Responsibility:
objectstack: the spec migration entry's release text, stale since #31082 | none | every reader of the migration registry (os migrate meta, generated release notes)Thread-read: 6709432110
Premise: holds
Serial constraints cleared: none — #31094 (family sibling) landed as #31126 (
a5cb4f1b); no open PR touches this entry file (read atorigin/main620b6e6d).Order:
/mnt/project-files/pm-orders/spec/order-31169.md(project files), in the card thread's opening message.objectstack-fleet commentedon Nov 7, 2026
domain:spec#1 · os-project-manager · session_01FEkQ5odNVgHTd2MQbQCp5t
os-dev-report
{
"issue": 31169,
"status": "done",
"branch": "claude/project-thread-9crw47",
"pr": "#31210",
"session": "session_01FEkQ5odNVgHTd2MQbQCp5t",
"premise_still_valid": true,
"summary": "Draft PR #31210 (head d3adb0d, two commits, one per card) carries #31169 and the folded #31180 (claim 6710378726), body 'Fixes #31169' and 'Fixes #31180' on separate lines. #31169 (0fcd5b1): the replacement of semantic entry cbp-optional-master-admitted and its header comment now state the write rule measured from 0373715 (nullMasterRowWritable, the masterId == null && rel.optional branch, 403 PERMISSION_DENIED; insert naming no master admitted; emptying a named master asks edit on the master it leaves; only an empty stored REQUIRED master still 422 MISSING_REQUIRED_FIELD), in the wording of #31164's error-handling/error-catalog pages; header cites PR #31082; id, surface, reason, acceptanceCriteria unchanged. Same stale sentence fixed in place in registry.ts.template's step-18 rationale fragment for this entry (upgrade-guide paragraph): rule-3 bounded exemption, the seat is asked to add packages/spec/src/migrations/registry.ts.template to the claim's file surface. #31180 (d3adb0d): JSDoc of ControlledByParentWriteOutcome allow and ISecurityService.checkControlledByParentWrite name sharing.controlledByParent.ownerMayEdit with the conditions measured from the owner leg of assertControlledByParentWrite (by-id update, not on behalf, stored owner_id is caller, body does not empty an optional master, caller can read the master), citing ADR-0055 section 3 as amended 2026-10-26. One spec patch changeset covers both.",
"tests": "No behaviour change, no test added, no ablation (text only). pnpm --filter @objectstack/spec run typecheck: exit 0 on d3adb0d (check:test-typecheck OK). os-verify-lock vitest run src/migrations/ src/contracts/: VERDICT command-exit 0, Test Files 57 passed, Tests 673 passed, on d3adb0d. grep for 'still refused with 422' / 'Writes are unchanged' / 'empty master reference is still' in packages, content, docs, scripts: no pin quotes the old sentences. Regenerated gitignored registry.ts carries the new text (count 1) and no 'Writes are unchanged'. Behaviour pinned by plugin-security controlled-by-parent-optional-master.test.ts and controlled-by-parent-owner-may-edit.test.ts.",
"gates": "objectstack-ai/objectstack d3adb0d: dispatch-gates --commands 78 derived (4 paths, 59 changed lines); each run with exit captured before any pipe; 77 exit 0, 1 NOT MEASURED: pnpm check:dual-build-cjs-loads exit 3 (needs every package's dist; CI's). --ran: 78 accounted, 77 run, 1 NOT-MEASURED, 0 UNRUN, exit 0. Prerequisites built before the final pass (spec, lint, objectql closures; teardown self-test control commit fetched), so check-plugin-teardown-shape --self-test, lint check:doc-formula-expressions and check:lean-entry-closure, exit 3 on the first pass at 0fcd5b1, are exit 0 on d3adb0d. Local-only check:dev-prereqs exit 1 (93 of 107 packages unbuilt in this worktree; judges the box) = NOT MEASURED. CI check-runs: in_progress at report time (not waited, per os-dev). Full list: project file pm-orders/spec/31169-gates-ran.txt.",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"mcp_calls": "7 — reads only: issue_read get #31169, issue_read get_comments #31169 x2, pull_request_read get #31126, issue_read get #31180, issue_read get_comments #31180, pull_request_read get_files #31210; no MCP write",
"api_writes": "2 — relay pr_create (fleet-write run 42397690644, PR #31210, 7604 bytes sent = stored, no assignees, no labels); this os-dev-report comment on #31169 via post-stamped. Plus 2 git pushes of the harness branch (not REST).",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": [
"carrier: spec seat · .changeset/30905-cbp-optional-master.md (pending, read-side PR) still ends its plugin-security bullet with 'Writes are unchanged: ... still refused with 422'; .changeset/30906-cbp-null-master-write-gate.md states the write change, so the same release notes carry both. Editing a landed changeset is outside this card; noted in the PR's Acceptance notes, not changed."
]
}
Generated by Claude Code
objectstack-fleet commentedon Nov 7, 2026
domain:spec#1 · os-project-manager · session_01FEkQ5mw7HFYn9o4LEGMQdK
Claim amendment (file surface, same claim 6710037976): adds
packages/spec/src/migrations/registry.ts.template, whose step-18 rationale fragment for this entry carried the same stale write sentence and renders into the protocol upgrade guide; named in PR #31210 body. Nothing else changes.