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
pm/fleet-write: advisory_read holds its sender to target-write, by the maintainer's ruling, since the collaborator gate refuses every live read #29644
advisory_read (the sealed advisory read, #29420, landed in #29536) holds the sender to senderGate: 'collaborator' in scripts/pm/fleet-write/ops.mjs. The maintainer has ruled it becomes 'target-write', the gate every other relay row keeps.
The ruling
The maintainer, in session session_01QSeKYn5CmmdShCJifm6WYj on 2026-11-02, answering the seat's question whether the read's sender gate should change from collaborator to write on the target repository, verbatim:
同意改成对仓库有写权限,立卡派发修复
This settles the open question the #29420 os-dev report left for the maintainer (comment 6584655262, open_questions[0], options A collaborator / B target-write). The ruling is B.
The measurement that prompted it (the first live reads, 2026-11-02)
advisory_collaborators_add for the sender landed, and its PATCH answer lists the sender among the collaborators (run 41545025429).
Three advisory_read strokes after it, on two advisories, were each refused at fence sender ("is not a collaborator on it"): runs 41545143476, 41545259848, 41546082963.
A re-sent advisory_collaborators_add on one of those advisories was a no-op: its pre-PATCH GET, under the write grant, already lists the sender (run 41546190167).
So the write-grant GET lists the sender in collaborating_users, and the read-grant GET the fence judges does not. Why the read-grant answer omits it is unverified (a hypothesis: the platform withholds collaborating_users from a read-only grant).
A sender with write on the target can already add itself to any advisory whose id it holds (ops.mjs, the sender-gate paragraph above advisory_read), so the collaborator gate excluded no one; it only blocked every live read.
Acceptance
advisory_read's senderGate is 'target-write'; the header prose and the row comment record the ruling verbatim, in place of "the card's recommendation" and "the maintainer rules which stands, on the pull request".
The relay self-tests that pin the default gate move with it; an unknown gate still fails closed.
After merge, one live advisory_read by a seat with write on the target opens (the seat runs it; recorded here as a run id, no advisory id).
Out of bounds
⛔ The row's grant stays read. If a read under the read grant is refused once the gate is switched, that is a fork for the maintainer, never a raise to write.
⛔ No advisory text, id or mechanism in the PR, the commits or the changeset.
Claim: maintainer-directed dispatch · 2026-11-02T23:42Z
Session: session_01QSeKYn5CmmdShCJifm6WYj
Account: os-justin (the seat's linked user as GET /user answers it; always the card's assignee)
Branch: claude/issue-29644-advisory-read-sender-gate
Worktree: objectstack-issue-29644
Domain: domain:skills
Seat: domain:skills#2
File surface: scripts/pm/fleet-write/ops.mjs, scripts/pm/fleet-write/execute.mjs, scripts/pm/fleet-write/validate.mjs, scripts/pm/fleet-write/dispatch.mjs (self-tests that pin the gate) (stop on breach; explain in the report)
Container & model: S, judgment in the prose, mode:subagent, model: opus (dispatch-gates --tier: no path-derived mandate; default tier), effort: xhigh (security channel)
Clause-②: no
Metadata-protocol: none
Responsibility: the relay row's senderGate value in ops.mjs | none: no other relay path reads an advisory | every fleet seat reaching an advisory read; every live read today is refused
Thread-read: none
Premise: holds (measured this session: runs 41545143476, 41545259848, 41546082963 refused at fence sender; run 41546190167 shows the sender persisted as a collaborator)
Serial constraints cleared: none found — the open skills-lane PRs #29577 and #29633 touch no scripts/pm/fleet-write/ file and #29620 (the workflow comment) is closed; the other open PRs were not enumerated file by file
Ruling carried: the maintainer's, verbatim, in the card body (session session_01QSeKYn5CmmdShCJifm6WYj). Triage: maintainer-directed, claimed before the triage audit, as on #29420.
{
"issue": 29644,
"status": "done",
"branch": "claude/issue-29644-advisory-read-sender-gate",
"pr": "https://github.com/objectstack-ai/objectstack/pull/29656",
"head_sha": "a8eed92854506c06d65249b2293b965aa705bd2f",
"session": "session_01QSeKYn5CmmdShCJifm6WYj (subagent: the dispatching seat's session)",
"premise_still_valid": true,
"summary": "advisory_read's senderGate is now 'target-write'. The maintainer's ruling 「同意改成对仓库有写权限,立卡派发修复」 is quoted verbatim (ASCII comma, as in the card body) in the ops.mjs header paragraph and in the row comment, replacing the 'card's recommendation' and 'the maintainer rules on the pull request' text. The row's grant stays read. Keep vs. remove: I REMOVED the collaborator arm. It measured as refusing every live read, it excluded no one, and nothing outside the three edited files names it, so the startup-stage rule applies and the removal stays inside the four-file surface. ADVISORY_READ_SENDER_GATES keeps the one value, and any other value, collaborator included, fails closed. The fence no longer reads the sender, so its context and advisoryReadAction drop `sender`; no export was renamed or removed. PM zone-2 readings re-taken at base 3482f3d8: senderGate at ops.mjs:1986, the table at :1315, the header paragraph at :560 and the sender fence at :1340-1350 all held. Execute pinned the default gate at :2676-2682 and validate at :1794 and :1872-1879. FALSIFIED: dispatch.mjs pins no gate; its end-to-end read's sender is on the fixture's collaborators, so it is unchanged. The PR body labels the read-grant GET omitting collaborating_users as an UNVERIFIED hypothesis, and this PR neither tests nor depends on it. The card's post-merge live read is left to the seat.",
"files_changed": [
"scripts/pm/fleet-write/ops.mjs (+31/-31)",
"scripts/pm/fleet-write/execute.mjs (+20/-17)",
"scripts/pm/fleet-write/validate.mjs (+10/-10)"
],
"tests": "Relay --self-test, before at base 3482f3d8 and after at HEAD a8eed928, each exit captured before any pipe. validate: 303 cases / 16 batteries both times. execute: 259 / 22 before, 260 / 22 after, with the advisory_read battery pin raised 17 to 18. dispatch: 315 / 27 both times. ops.mjs has no --self-test handler: it exits 0 with zero bytes because it is only an import, so it is NOT MEASURED as a self-test; validate pins its table. Executor battery: a write sender off the collaborators is now sealed for and opens byte for byte (this case was rewritten from a refusal pin). New: a triage sender is refused BEFORE the advisory GET even when listed as a collaborator (exit 4, the permission read alone). Rewritten: a made-up gate and the retired collaborator fail closed. The marker sweep now covers 20 runs instead of 19. Validator battery: the row pin is one setting with grant read; target-write reads no collaborator; any other gate is closed (retired, misspelt, a prototype key, empty, absent); a prose gate value is never echoed. One-shot ablation via scripts/ablation-replace.mjs in wrap mode, after committing the fix. Predicted directions were stated first. Leg A (senderGate back to 'collaborator'): anchor 1 to 0, blob 8bd15e59 to 46d1f81a. validate exit 1 (1/303 failed), execute exit 1 (8/260), dispatch exit 1 (4/315). Leg B (sender fence fails open): blob 8bd15e59 to 8e424259. validate exit 1 (3/303), execute exit 1 (1/260), dispatch exit 0 (315 pass, as predicted). Both legs restored with blob == HEAD 8bd15e59, git diff HEAD empty and git status clean. No *.test.* file names these scripts: git grep exit 1, against a control grep for any file naming ops.mjs that exits 0. Their suites are their own and their importers' --self-tests, all in the derived set.",
"gates": "At HEAD a8eed928, node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 39 commands (26 pnpm, 13 node) over 3 paths, 119 changed lines. All 39 were run and all exited 0, each exit captured before any pipe and each log's own verdict line read. pnpm check:pm-dispatch-gates ran under nohup and was waited on to its exit file (EXIT=0, fast tier 1945 cases, 403.2s). --ran with exit codes: '✓ dispatch-gates --ran: 39 derived famil(ies) accounted for — 39 run, 0 NOT-MEASURED (a DERIVED zero — all 39 recorded an exit code and none of them is 3)'. Commands: check-closing-keyword-parity (+self-test), check-comment-mask-corpus, check-declaration-mirrors (+self-test), check-self-test-wired (+self-test), check-self-test-workflow-commands (+self-test), check-whole-set-label-write (+self-test), ci/plan-test-core-shards self-test, pm/bare-root-worklist self-test, and pnpm check: agent-test-spelling, bash32-floor, ci-filter-parity, cli-command-ids, cross-package-test-inputs, driver-memory-census, entry-guard, gitlink-declared, nul-bytes, parse-guard, pm-close-cards, pm-dispatch-gates, pm-fleet-write-dispatch, pm-fleet-write-execute, pm-fleet-write-validate, pm-issue-create, pm-issue-transfer, pm-label-write, pm-post-stamped, pm-record-recognisers, pm-write-pace, pnpm-filter-targets, pnpm-flag-spellings, refd-timer-probe, scripts-symbol-anchors, watch-hint-literal. PR #29656 check-runs on a8eed928 at report time: 41 total, none failed. Success: Check Changeset, Check PR Size, Dogfood Regression Gate, Governed Surface Queue Guard, PR-body guards, Test UI, filter. in_progress: Lint (CI/release/engine, ESLint, PM dispatch-gates, docs & code guards, repo & tooling, three scoped lanes), Type Check (consumer, debt ledger, source, workspace), Plan Test Core shards, Auto Label. 20 skipped. Left to CI and not run locally: the 52 artifact-roster families, the 11 wide-population families and the type-check lanes. The diff touches no TypeScript package.",
"line_budget": "n/a — no skills/** file or line-ratcheted ledger touched. Diff +61/-58 over 3 files (119 changed lines, under the 3000 threshold).",
"deviations": [
"Kept/removed call (zone 3): removed the collaborator arm, with a one-line reason in the PR body. The removal reaches into the fence context (`sender` dropped from advisoryReadFenceFailures' ctx and from advisoryReadAction's parameters). That is inside the four-file surface, with no export renamed or removed, so check-platform-checklist --changed-from was not owed.",
"dispatch.mjs is in the file surface but unedited: measured, it pins no gate.",
"ops.mjs --self-test is a no-op (no handler), so the order's \"four relay self-tests\" are three real ones plus that no-op, reported as such.",
"No origin/main merge before pr_create (AGENTS.md multi-agent §10 asks for one). origin/main moved 2 commits past base 3482f3d8 and neither touches scripts/pm/fleet-write/ or its imports. The full suite is left to CI per the os-dev local-verification scope.",
"Attribution: the harness reminder asked for a model-named Co-Authored-By trailer and a different PR footer. Per AGENTS.md (which that reminder yields to), the commit carries the model-free Claude-Session / Co-authored-by pair and the PR body the session-URL footer.",
"Writes: two git pushes, the empty-branch route probe (rule 1) and the work commit, beyond the three-write budget's one push. The probe is mandated by rule 1."
],
"dogfood_battery": "n/a — no `!` in the PR title, and Clause-②: no without a (narrowing) arm",
"mcp_calls": "0 — no MCP GitHub calls of any kind",
"api_writes": "2 seat-side REST writes, both relay strokes, POST /repos/objectstack-ai/objectstack/dispatches. (1) pr_create, run 41550449857: the fleet executed POST /repos/objectstack-ai/objectstack/pulls (201, #29656, draft) and POST /repos/objectstack-ai/objectstack/issues/29656/labels (200, row 'labels skip-changeset'). The body read back 9760/9760 bytes identical. (2) this report comment via scripts/pm/post-stamped.mjs: POST /repos/objectstack-ai/objectstack/issues/29644/comments. Not REST: 2 git pushes.",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": []
}
Activity
objectstack-fleet commentedon Nov 2, 2026
domain:skills#2 · os-justin · session_01QSeKYn5CmmdShCJifm6WYj
Claim: maintainer-directed dispatch · 2026-11-02T23:42Z
Session:
session_01QSeKYn5CmmdShCJifm6WYjAccount:
os-justin(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-29644-advisory-read-sender-gateWorktree:
objectstack-issue-29644Domain:
domain:skillsSeat:
domain:skills#2File surface:
scripts/pm/fleet-write/ops.mjs,scripts/pm/fleet-write/execute.mjs,scripts/pm/fleet-write/validate.mjs,scripts/pm/fleet-write/dispatch.mjs(self-tests that pin the gate) (stop on breach; explain in the report)Container & model:
S, judgment in the prose,mode:subagent,model: opus (dispatch-gates --tier: no path-derived mandate; default tier),effort: xhigh (security channel)Clause-②: no
Metadata-protocol: none
Responsibility:
the relay row's senderGate value in ops.mjs | none: no other relay path reads an advisory | every fleet seat reaching an advisory read; every live read today is refusedThread-read: none
Premise: holds (measured this session: runs 41545143476, 41545259848, 41546082963 refused at fence sender; run 41546190167 shows the sender persisted as a collaborator)
Serial constraints cleared: none found — the open skills-lane PRs #29577 and #29633 touch no
scripts/pm/fleet-write/file and #29620 (the workflow comment) is closed; the other open PRs were not enumerated file by fileRuling carried: the maintainer's, verbatim, in the card body (session
session_01QSeKYn5CmmdShCJifm6WYj). Triage: maintainer-directed, claimed before the triage audit, as on #29420.objectstack-fleet commentedon Nov 3, 2026
domain:skills#2 · os-justin · session_01QSeKYn5CmmdShCJifm6WYj
os-dev-report
{ "issue": 29644, "status": "done", "branch": "claude/issue-29644-advisory-read-sender-gate", "pr": "https://github.com/objectstack-ai/objectstack/pull/29656", "head_sha": "a8eed92854506c06d65249b2293b965aa705bd2f", "session": "session_01QSeKYn5CmmdShCJifm6WYj (subagent: the dispatching seat's session)", "premise_still_valid": true, "summary": "advisory_read's senderGate is now 'target-write'. The maintainer's ruling 「同意改成对仓库有写权限,立卡派发修复」 is quoted verbatim (ASCII comma, as in the card body) in the ops.mjs header paragraph and in the row comment, replacing the 'card's recommendation' and 'the maintainer rules on the pull request' text. The row's grant stays read. Keep vs. remove: I REMOVED the collaborator arm. It measured as refusing every live read, it excluded no one, and nothing outside the three edited files names it, so the startup-stage rule applies and the removal stays inside the four-file surface. ADVISORY_READ_SENDER_GATES keeps the one value, and any other value, collaborator included, fails closed. The fence no longer reads the sender, so its context and advisoryReadAction drop `sender`; no export was renamed or removed. PM zone-2 readings re-taken at base 3482f3d8: senderGate at ops.mjs:1986, the table at :1315, the header paragraph at :560 and the sender fence at :1340-1350 all held. Execute pinned the default gate at :2676-2682 and validate at :1794 and :1872-1879. FALSIFIED: dispatch.mjs pins no gate; its end-to-end read's sender is on the fixture's collaborators, so it is unchanged. The PR body labels the read-grant GET omitting collaborating_users as an UNVERIFIED hypothesis, and this PR neither tests nor depends on it. The card's post-merge live read is left to the seat.", "files_changed": [ "scripts/pm/fleet-write/ops.mjs (+31/-31)", "scripts/pm/fleet-write/execute.mjs (+20/-17)", "scripts/pm/fleet-write/validate.mjs (+10/-10)" ], "tests": "Relay --self-test, before at base 3482f3d8 and after at HEAD a8eed928, each exit captured before any pipe. validate: 303 cases / 16 batteries both times. execute: 259 / 22 before, 260 / 22 after, with the advisory_read battery pin raised 17 to 18. dispatch: 315 / 27 both times. ops.mjs has no --self-test handler: it exits 0 with zero bytes because it is only an import, so it is NOT MEASURED as a self-test; validate pins its table. Executor battery: a write sender off the collaborators is now sealed for and opens byte for byte (this case was rewritten from a refusal pin). New: a triage sender is refused BEFORE the advisory GET even when listed as a collaborator (exit 4, the permission read alone). Rewritten: a made-up gate and the retired collaborator fail closed. The marker sweep now covers 20 runs instead of 19. Validator battery: the row pin is one setting with grant read; target-write reads no collaborator; any other gate is closed (retired, misspelt, a prototype key, empty, absent); a prose gate value is never echoed. One-shot ablation via scripts/ablation-replace.mjs in wrap mode, after committing the fix. Predicted directions were stated first. Leg A (senderGate back to 'collaborator'): anchor 1 to 0, blob 8bd15e59 to 46d1f81a. validate exit 1 (1/303 failed), execute exit 1 (8/260), dispatch exit 1 (4/315). Leg B (sender fence fails open): blob 8bd15e59 to 8e424259. validate exit 1 (3/303), execute exit 1 (1/260), dispatch exit 0 (315 pass, as predicted). Both legs restored with blob == HEAD 8bd15e59, git diff HEAD empty and git status clean. No *.test.* file names these scripts: git grep exit 1, against a control grep for any file naming ops.mjs that exits 0. Their suites are their own and their importers' --self-tests, all in the derived set.", "gates": "At HEAD a8eed928, node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 39 commands (26 pnpm, 13 node) over 3 paths, 119 changed lines. All 39 were run and all exited 0, each exit captured before any pipe and each log's own verdict line read. pnpm check:pm-dispatch-gates ran under nohup and was waited on to its exit file (EXIT=0, fast tier 1945 cases, 403.2s). --ran with exit codes: '✓ dispatch-gates --ran: 39 derived famil(ies) accounted for — 39 run, 0 NOT-MEASURED (a DERIVED zero — all 39 recorded an exit code and none of them is 3)'. Commands: check-closing-keyword-parity (+self-test), check-comment-mask-corpus, check-declaration-mirrors (+self-test), check-self-test-wired (+self-test), check-self-test-workflow-commands (+self-test), check-whole-set-label-write (+self-test), ci/plan-test-core-shards self-test, pm/bare-root-worklist self-test, and pnpm check: agent-test-spelling, bash32-floor, ci-filter-parity, cli-command-ids, cross-package-test-inputs, driver-memory-census, entry-guard, gitlink-declared, nul-bytes, parse-guard, pm-close-cards, pm-dispatch-gates, pm-fleet-write-dispatch, pm-fleet-write-execute, pm-fleet-write-validate, pm-issue-create, pm-issue-transfer, pm-label-write, pm-post-stamped, pm-record-recognisers, pm-write-pace, pnpm-filter-targets, pnpm-flag-spellings, refd-timer-probe, scripts-symbol-anchors, watch-hint-literal. PR #29656 check-runs on a8eed928 at report time: 41 total, none failed. Success: Check Changeset, Check PR Size, Dogfood Regression Gate, Governed Surface Queue Guard, PR-body guards, Test UI, filter. in_progress: Lint (CI/release/engine, ESLint, PM dispatch-gates, docs & code guards, repo & tooling, three scoped lanes), Type Check (consumer, debt ledger, source, workspace), Plan Test Core shards, Auto Label. 20 skipped. Left to CI and not run locally: the 52 artifact-roster families, the 11 wide-population families and the type-check lanes. The diff touches no TypeScript package.", "line_budget": "n/a — no skills/** file or line-ratcheted ledger touched. Diff +61/-58 over 3 files (119 changed lines, under the 3000 threshold).", "deviations": [ "Kept/removed call (zone 3): removed the collaborator arm, with a one-line reason in the PR body. The removal reaches into the fence context (`sender` dropped from advisoryReadFenceFailures' ctx and from advisoryReadAction's parameters). That is inside the four-file surface, with no export renamed or removed, so check-platform-checklist --changed-from was not owed.", "dispatch.mjs is in the file surface but unedited: measured, it pins no gate.", "ops.mjs --self-test is a no-op (no handler), so the order's \"four relay self-tests\" are three real ones plus that no-op, reported as such.", "No origin/main merge before pr_create (AGENTS.md multi-agent §10 asks for one). origin/main moved 2 commits past base 3482f3d8 and neither touches scripts/pm/fleet-write/ or its imports. The full suite is left to CI per the os-dev local-verification scope.", "Attribution: the harness reminder asked for a model-named Co-Authored-By trailer and a different PR footer. Per AGENTS.md (which that reminder yields to), the commit carries the model-free Claude-Session / Co-authored-by pair and the PR body the session-URL footer.", "Writes: two git pushes, the empty-branch route probe (rule 1) and the work commit, beyond the three-write budget's one push. The probe is mandated by rule 1." ], "dogfood_battery": "n/a — no `!` in the PR title, and Clause-②: no without a (narrowing) arm", "mcp_calls": "0 — no MCP GitHub calls of any kind", "api_writes": "2 seat-side REST writes, both relay strokes, POST /repos/objectstack-ai/objectstack/dispatches. (1) pr_create, run 41550449857: the fleet executed POST /repos/objectstack-ai/objectstack/pulls (201, #29656, draft) and POST /repos/objectstack-ai/objectstack/issues/29656/labels (200, row 'labels skip-changeset'). The body read back 9760/9760 bytes identical. (2) this report comment via scripts/pm/post-stamped.mjs: POST /repos/objectstack-ai/objectstack/issues/29644/comments. Not REST: 2 git pushes.", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [] }objectstack-fleet commentedon Nov 3, 2026
domain:skills#2 · os-justin · session_01QSeKYn5CmmdShCJifm6WYj
ACCEPT → PR #29656 comment 6592025585 · head
a8eed928· ready and auto-merge enabled (relay run 41552671164) · 2026-11-03T00:25Zobjectstack-fleet commentedon Nov 3, 2026
domain:skills#2 · os-justin · session_01QSeKYn5CmmdShCJifm6WYj
Landed · 2026-11-03T01:13Z
c3184908, through the merge queueadvisory_readafter merge (acceptance item 3)Closed as completed by the merge (
Fixes);pm:dispatchedremoved in the next stroke.