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-dispatch: a project seat can sit with no hourly patrol routine and nothing notices — make the patrol a step of seat-online, record it in the seat post, and flag an on-duty lane's unclaimed pm:queue card #28642
Filing gate: ① the maintainer asked about this incident: 「28560 等了4 个小时,是你的技能有什么问题吗」 and 「为什么会停了定时巡查,skills 是否需要优化」 (2026-11-01 10:23Z / 10:29Z, project thread). Filed by domain:spec seat 4 (marchtian), the seat that missed it. ⛔ Not a claim. No grade: triage sets it.
Reader: domain:skills, .claude/skills/pm-dispatch/SKILL.md 〈唤醒〉 and references/seat-lifecycle.md 〈坐席〉 / 〈停止条件与待命〉, references/seat-post-protocol.md L66, scripts/pm/check-half-states.mjs.
Dedupe (open AND closed): "patrol seat hourly", "巡查", "seat patrol trigger" → only seat posts and #9857 (the half-state patrol view). No card about a missing seat patrol.
reach: any project seat. Measured on spec seat 4 (#18917), 2026-11-01. #28560 (p1, domain:spec) entered pm:queue at 05:56Z and was not claimed until 10:29Z, 4.5 h later, while the seat was on duty with 0 cards in hand.
What happened (measured from the seat's own session)
The seat never created the hourly patrol routine at any point in its tenure (since 2026-10-29 15:26Z). It woke only on PR subscriptions, coordinator relays and its own one-shot send_later reminders. That is the "send_later 链" the skill forbids.
When its last PR merged (2026-10-31 23:30Z), the queue was empty. The seat scheduled two one-shot checks (00:33Z, 02:35Z), found nothing, and stopped checking. It wrote "不再定时查" on its checklist.
The skill already says the right thing in three places, and the seat broke all three:
Creating the routine is not a step of seat-online (seat-lifecycle L41), so taking the seat never asks for it.
The seat post carries no patrol line, so neither the maintainer nor triage can see that a seat has none.
Nothing measures an on-duty lane whose pm:queue card sits unclaimed.
The agent's generic habit ("after a few checks with no change, stop polling") overrode the seat rule. The skill does not say that it outranks that habit.
Wanted
seat-online includes the patrol. Taking a project seat creates one self-bound hourly patrol routine (create_trigger, cron, bound to the seat session) in the same act. The seat-online record and the seat post carry Patrol: <trigger_id> · <cron>. seat-offline deletes it in the same act as the clock-out brief.
Empty queue is standby, not a stop. One explicit line in 〈停止条件与待命〉: the patrol runs until seat-offline, empty queue included. "Back off and stop after N quiet checks" never applies to a seat's patrol. Only the maintainer's order or clock-out stops it.
A report-only measurement in check-half-states.mjs, or the triage daily sweep:
(a) a seat post 🟢 with no Patrol: line;
(b) a pm:queue card of a lane with an on-duty seat that has spare concurrency, unclaimed for over 2 h.
Both are printed as readings, not gates (instrument-discipline).
The patrol prompt names the work: queue claim up to the seat's concurrency, in-flight PR follow-up, and Restart-when: / pm:blocked unlock re-checks.
Not here
The seat-4 patrol itself was created at 2026-11-01 10:31Z: hourly at :48, routine Spec seat 4 hourly patrol. #28560 is claimed (6556731523).
Lane:domain:skills for .claude/skills/pm-dispatch/**, which is Tier H. The check-half-states.mjs report row rides the same PR, and the claim names the exact files.
The maintainer's floor applies. Making the patrol a step of seat-online, and recording it in the seat post, is a rule change. The PR's Tier H approval is that ruling.
The unclaimed-pm:queue flag must stay a report row (a half-state the patrols read). ⛔ It is not a new merge gate (「新增门禁默认否」).
Claim: PM loop round 1
Session: session_017ihL2g7RyXa8ErM6GAkHyc
Account: marchtian
Branch: claude/issue-28642-seat-patrol
Worktree: objectstack-issue-28642
Domain: domain:skills
Seat: domain:skills#2
File surface: .claude/skills/pm-dispatch/references/seat-lifecycle.md, .claude/skills/pm-dispatch/references/project-forms.md, .claude/skills/pm-dispatch/references/seat-post-protocol.md, .claude/skills/pm-dispatch/references/dispatch-runbook.md (〈巡查常设项〉 only), scripts/pm/check-half-states.mjs (+ its self-test). SKILL.md only if a line is unavoidable (then the tier mandate below changes and the dev stops to report).
Container & model: M, mode:subagent, model: opus (dispatch-gates --tier on the surface above: "no path-derived mandate", PM per-card judgment; SKILL.md stays out of the surface), effort: high
Clause-②: no
Metadata-protocol: none
Responsibility: n/a — not a defect card (triage 6556985958 graded it a rule change)
Thread-read: 6556985958
Premise: holds — on origin/maine4ec4f22c5 no seat-online step, seat-post line or check-half-states row mentions a patrol (grep of .claude/skills/pm-dispatch/** and scripts/pm/check-half-states.mjs); SKILL.md:72 and seat-post-protocol.md:66 still state the rule without enforcement.
Serial constraints cleared: no open PR touches .claude/skills/pm-dispatch/** or scripts/pm/check-half-states.mjs (read 2026-11-01 over every open non-mailbox PR); no open domain:skills card carries pm:dispatched. Fold-or-serial with #28675 (same seat-online files): serial, this card first. Fold gate ① fails (#28642 is patrol enforcement, #28675 is the doorbell scene table and new keys: different change shape). #28675 is told on its card when this lands.
finding removed in this write: triage graded the card at 6556985958 and the label stayed behind.
Tier H (.claude/**): the PR waits for the maintainer's approval. A contract-review-tier review of the rules text is owed before the ACCEPT.
{
"issue": 28642,
"status": "done",
"branch": "claude/issue-28642-seat-patrol",
"pr": "https://github.com/objectstack-ai/objectstack/pull/28687",
"head": "58de368f04d9392425076b29eb2dc4eb5fb064f3",
"session": "session_017ihL2g7RyXa8ErM6GAkHyc",
"premise_still_valid": true,
"summary": "Seating now creates the self-bound patrol routine, records `Patrol:` on the stub and deletes it at sign-off (seat-lifecycle.md 座位贴协议 is the one home; project-forms.md and seat-post-protocol.md point there and carry the spelling `Patrol: TRIGGER_ID · CRON`). Stop/standby says an empty queue is standby, the patrol runs until sign-off and the N-quiet-checks habit does not apply; the patrol prompt claims up to `batch` first, then runs the standby items. check-half-states.mjs gains H70 (held seat post without a Patrol line, state band) and H71 (unassigned pm:queue card quiet over 2h on a lane with a green seat post, stall band), both report-only and free.",
"tests": "node scripts/pm/check-half-states.mjs --self-test: exit 0, 5158 cases pass, battery 'H70/H71 seat patrol' 27/26. Live read-only sweep at f4027cfe: H70 = 16 seat posts, H71 = 3 cards (25918, 25921, 27890). No ablation: script/config diff (os-dev rule).",
"gates": {
"head": "58de368f",
"derived": "dispatch-gates --commands --repo objectstack-ai/objectstack: 55 commands, all exit 0 (check:doc-formula-expressions exit 3 PREREQUISITE NOT MET first, exit 0 after building formula+lint)",
"ran_reconciliation": "55 derived, 55 run, 0 NOT-MEASURED (a DERIVED zero; every entry recorded an exit code)",
"ratchets": {"check:pm-skill-ratchet": 0, "check:pm-skill-id-lint": 0, "check:skill-frame-sync": 0, "check:pm-governed-prose": 0, "check:pm-half-states": 0, "check:pm-dispatch-gates": 0},
"roster_readings": {"check-published-list-mirrors": 0, "check:dts-closure": 0, "check:engine-double-contract": 0, "check:i18n-stale-fill": 0, "check:pm-label-desc-cap": 0, "check:pm-settings-deny-roster": 0, "check:published-readme-exports": "NOT MEASURED (exit 3, 63 packages unbuilt; CI runs it)"},
"ci": "in_progress at report time; not awaited"
},
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"line_budget": {
".claude/skills/pm-dispatch/references/seat-lifecycle.md": "96 -> 96 (net 0; +1 standby line paid by deleting the 断粮 patrol line)",
".claude/skills/pm-dispatch/references/seat-post-protocol.md": "88 -> 88 (net 0, in place)",
".claude/skills/pm-dispatch/references/project-forms.md": "54 -> 54 (net 0, in place)",
".claude/skills/pm-dispatch/references/dispatch-runbook.md": "245 -> 245 (untouched)",
".claude/skills/pm-dispatch/SKILL.md": "untouched"
},
"files_changed": [
".claude/skills/pm-dispatch/references/project-forms.md",
".claude/skills/pm-dispatch/references/seat-lifecycle.md",
".claude/skills/pm-dispatch/references/seat-post-protocol.md",
"scripts/pm/check-half-states.mjs"
],
"deviations": [
"Notify: seat-online key not extended with a patrol field: its template is parsed by record-recognisers.mjs (outside the claimed surface, and mailbox keys are the serial card behind this one); the Patrol line lives on the stub only.",
"H71 drops the spare-concurrency condition: no seat post states its cap machine-readably and a cap can span several seats of one account; the row says so.",
"dispatch-runbook.md not edited: item 4 lives in seat-lifecycle.md 停止条件与待命 next to the standby list it points at.",
"The deleted 断粮 line's clause 含前提过时 is not re-homed (no standby item carried it).",
"The seating line carries no director exemption (120-byte budget); project-forms.md, seat-post-protocol.md and SKILL.md 唤醒 carry it.",
"H70 reuses seatIsHeld, so 🟢 titles whose first token is not a login (held, session_ ids) read as held, as in H32.",
"Commit trailers use Co-Authored-By casing as the order spelled it."
],
"mcp_calls": "0 — no MCP GitHub tool called",
"api_writes": "2 — POST /repos/objectstack-ai/objectstack/dispatches (relay pr_create, run 41313247854, which performed POST /pulls + POST /issues/28687/labels as objectstack-fleet[bot]); this comment via post-stamped.mjs. Plus 3 git pushes (not REST writes).",
"open_questions": [
{"question": "Tier: the governed register puts .claude/** at Tier S, while triage 6556985958 and the order call this Tier H with the maintainer's approval as the ruling. Which landing path applies?", "options": ["A: wait for the maintainer's approval (triage's ruling) and a contract-tier review", "B: Tier S contract-review record only"], "recommendation": "A, because triage made the approval the rule-change ruling, whatever the register's tier"},
{"question": "instrument-discipline.md says report-only instruments get no dev work except deletion, and also that a new patrol row needs the maintainer's words quoted on the card. The card quotes a question, not an order to add a row. Is the PR's approval enough to cover H70/H71?", "options": ["A: the PR's approval covers it (stated in the 速读 需要你做的 line)", "B: ask the maintainer for an explicit word on the card first"], "recommendation": "A, because the 速读 line asks for exactly that approval"}
],
"out_of_scope_findings": [
"carrier: domain:skills#2 seat · noted, not filed — live H71 reading: #27890 (domain:skills) unassigned in pm:queue, quiet ~58h",
"carrier: the seats named · noted, not filed — 16 held seat posts carry no Patrol line yet (H70 live reading); expected under a rule that is new"
]
}
Activity
objectstack-fleet commentedon Nov 1, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: p2 ·
domain:skills·area:devpath·pm:queue· rule change · 2026-11-01T10:54Z⛔ Not a claim.
pm:queuebecause a seated lane never created its hourly patrol routine, and nothing noticed. The skill already forbids this in three places, so the gap is enforcement, not wording. p2.domain:skillsfor.claude/skills/pm-dispatch/**, which is Tier H. Thecheck-half-states.mjsreport row rides the same PR, and the claim names the exact files.seat-online, and recording it in the seat post, is a rule change. The PR's Tier H approval is that ruling.pm:queueflag must stay a report row (a half-state the patrols read). ⛔ It is not a new merge gate (「新增门禁默认否」).Generated by Claude Code
objectstack-fleet commentedon Nov 1, 2026
domain:skills#2 · marchtian · session_017ihL2g7RyXa8ErM6GAkHyc
Claim: PM loop round 1
Session:
session_017ihL2g7RyXa8ErM6GAkHycAccount:
marchtianBranch:
claude/issue-28642-seat-patrolWorktree:
objectstack-issue-28642Domain:
domain:skillsSeat:
domain:skills#2File surface:
.claude/skills/pm-dispatch/references/seat-lifecycle.md,.claude/skills/pm-dispatch/references/project-forms.md,.claude/skills/pm-dispatch/references/seat-post-protocol.md,.claude/skills/pm-dispatch/references/dispatch-runbook.md(〈巡查常设项〉 only),scripts/pm/check-half-states.mjs(+ its self-test).SKILL.mdonly if a line is unavoidable (then the tier mandate below changes and the dev stops to report).Container & model:
M,mode:subagent,model: opus(dispatch-gates --tieron the surface above: "no path-derived mandate", PM per-card judgment; SKILL.md stays out of the surface),effort: highClause-②: no
Metadata-protocol: none
Responsibility:
n/a — not a defect card(triage 6556985958 graded it a rule change)Thread-read: 6556985958
Premise: holds — on
origin/maine4ec4f22c5no seat-online step, seat-post line orcheck-half-statesrow mentions a patrol (grep of.claude/skills/pm-dispatch/**andscripts/pm/check-half-states.mjs); SKILL.md:72 andseat-post-protocol.md:66still state the rule without enforcement.Serial constraints cleared: no open PR touches
.claude/skills/pm-dispatch/**orscripts/pm/check-half-states.mjs(read 2026-11-01 over every open non-mailbox PR); no opendomain:skillscard carriespm:dispatched. Fold-or-serial with #28675 (same seat-online files): serial, this card first. Fold gate ① fails (#28642 is patrol enforcement, #28675 is the doorbell scene table and new keys: different change shape). #28675 is told on its card when this lands.findingremoved in this write: triage graded the card at 6556985958 and the label stayed behind..claude/**): the PR waits for the maintainer's approval. A contract-review-tier review of the rules text is owed before the ACCEPT.objectstack-fleet commentedon Nov 1, 2026
domain:skills#2 · marchtian · session_017ihL2g7RyXa8ErM6GAkHyc
os-dev-report
{ "issue": 28642, "status": "done", "branch": "claude/issue-28642-seat-patrol", "pr": "https://github.com/objectstack-ai/objectstack/pull/28687", "head": "58de368f04d9392425076b29eb2dc4eb5fb064f3", "session": "session_017ihL2g7RyXa8ErM6GAkHyc", "premise_still_valid": true, "summary": "Seating now creates the self-bound patrol routine, records `Patrol:` on the stub and deletes it at sign-off (seat-lifecycle.md 座位贴协议 is the one home; project-forms.md and seat-post-protocol.md point there and carry the spelling `Patrol: TRIGGER_ID · CRON`). Stop/standby says an empty queue is standby, the patrol runs until sign-off and the N-quiet-checks habit does not apply; the patrol prompt claims up to `batch` first, then runs the standby items. check-half-states.mjs gains H70 (held seat post without a Patrol line, state band) and H71 (unassigned pm:queue card quiet over 2h on a lane with a green seat post, stall band), both report-only and free.", "tests": "node scripts/pm/check-half-states.mjs --self-test: exit 0, 5158 cases pass, battery 'H70/H71 seat patrol' 27/26. Live read-only sweep at f4027cfe: H70 = 16 seat posts, H71 = 3 cards (25918, 25921, 27890). No ablation: script/config diff (os-dev rule).", "gates": { "head": "58de368f", "derived": "dispatch-gates --commands --repo objectstack-ai/objectstack: 55 commands, all exit 0 (check:doc-formula-expressions exit 3 PREREQUISITE NOT MET first, exit 0 after building formula+lint)", "ran_reconciliation": "55 derived, 55 run, 0 NOT-MEASURED (a DERIVED zero; every entry recorded an exit code)", "ratchets": {"check:pm-skill-ratchet": 0, "check:pm-skill-id-lint": 0, "check:skill-frame-sync": 0, "check:pm-governed-prose": 0, "check:pm-half-states": 0, "check:pm-dispatch-gates": 0}, "roster_readings": {"check-published-list-mirrors": 0, "check:dts-closure": 0, "check:engine-double-contract": 0, "check:i18n-stale-fill": 0, "check:pm-label-desc-cap": 0, "check:pm-settings-deny-roster": 0, "check:published-readme-exports": "NOT MEASURED (exit 3, 63 packages unbuilt; CI runs it)"}, "ci": "in_progress at report time; not awaited" }, "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm", "line_budget": { ".claude/skills/pm-dispatch/references/seat-lifecycle.md": "96 -> 96 (net 0; +1 standby line paid by deleting the 断粮 patrol line)", ".claude/skills/pm-dispatch/references/seat-post-protocol.md": "88 -> 88 (net 0, in place)", ".claude/skills/pm-dispatch/references/project-forms.md": "54 -> 54 (net 0, in place)", ".claude/skills/pm-dispatch/references/dispatch-runbook.md": "245 -> 245 (untouched)", ".claude/skills/pm-dispatch/SKILL.md": "untouched" }, "files_changed": [ ".claude/skills/pm-dispatch/references/project-forms.md", ".claude/skills/pm-dispatch/references/seat-lifecycle.md", ".claude/skills/pm-dispatch/references/seat-post-protocol.md", "scripts/pm/check-half-states.mjs" ], "deviations": [ "Notify: seat-online key not extended with a patrol field: its template is parsed by record-recognisers.mjs (outside the claimed surface, and mailbox keys are the serial card behind this one); the Patrol line lives on the stub only.", "H71 drops the spare-concurrency condition: no seat post states its cap machine-readably and a cap can span several seats of one account; the row says so.", "dispatch-runbook.md not edited: item 4 lives in seat-lifecycle.md 停止条件与待命 next to the standby list it points at.", "The deleted 断粮 line's clause 含前提过时 is not re-homed (no standby item carried it).", "The seating line carries no director exemption (120-byte budget); project-forms.md, seat-post-protocol.md and SKILL.md 唤醒 carry it.", "H70 reuses seatIsHeld, so 🟢 titles whose first token is not a login (held, session_ ids) read as held, as in H32.", "Commit trailers use Co-Authored-By casing as the order spelled it." ], "mcp_calls": "0 — no MCP GitHub tool called", "api_writes": "2 — POST /repos/objectstack-ai/objectstack/dispatches (relay pr_create, run 41313247854, which performed POST /pulls + POST /issues/28687/labels as objectstack-fleet[bot]); this comment via post-stamped.mjs. Plus 3 git pushes (not REST writes).", "open_questions": [ {"question": "Tier: the governed register puts .claude/** at Tier S, while triage 6556985958 and the order call this Tier H with the maintainer's approval as the ruling. Which landing path applies?", "options": ["A: wait for the maintainer's approval (triage's ruling) and a contract-tier review", "B: Tier S contract-review record only"], "recommendation": "A, because triage made the approval the rule-change ruling, whatever the register's tier"}, {"question": "instrument-discipline.md says report-only instruments get no dev work except deletion, and also that a new patrol row needs the maintainer's words quoted on the card. The card quotes a question, not an order to add a row. Is the PR's approval enough to cover H70/H71?", "options": ["A: the PR's approval covers it (stated in the 速读 需要你做的 line)", "B: ask the maintainer for an explicit word on the card first"], "recommendation": "A, because the 速读 line asks for exactly that approval"} ], "out_of_scope_findings": [ "carrier: domain:skills#2 seat · noted, not filed — live H71 reading: #27890 (domain:skills) unassigned in pm:queue, quiet ~58h", "carrier: the seats named · noted, not filed — 16 held seat posts carry no Patrol line yet (H70 live reading); expected under a rule that is new" ] }objectstack-fleet commentedon Nov 1, 2026
domain:skills#2 · marchtian · session_017ihL2g7RyXa8ErM6GAkHyc
ACCEPT → PR #28687 comment 6559181882 (head
8eb102fffe4c9231ba98d19964b6b215161f2070; contract review PASS 6559169512). Waiting on an authorised approver; the PR stays draft withneeds-user-decisionuntil then. Follow-up filed: #28699.objectstack-fleet commentedon Nov 1, 2026
domain:skills#2 · marchtian · session_017ihL2g7RyXa8ErM6GAkHyc
Landed 2026-11-01T15:56Z: PR #28687 merged as
fa494d0538(merge queue, enqueued by os-zhuang). Contract review PASS 6559169512, seat ACCEPT 6559181882. Follow-ups: #28699 (SKILL.md unit), #28675 (mailbox keys, PR #28716, carries theseat-onlinepatrol field).