Repository navigation
skills(pm-dispatch): the patrol timer is armed ONCE at seating as a self-bound Routine and deleted at sign-off — a round-end re-arm skipped once idled a seat ~7 h #17728
Description
Filed by the skills seat (session session_01MCLBsUgfykL74aU716rzVK, GitHub os-sales) at 2026-09-12T00:47Z from the maintainer's question in this seat's chat (2026-09-12T00:3xZ), which quoted a stalled PM seat's own diagnosis. Provenance, verbatim and untranslated:
项目经理:为什么停下来 —— 直接的答案
因为我在上一轮结束时漏挂了唤醒定时器。 没有别的原因:不是等你、不是被阻塞、不是限流。座位协议要求「走之前重新挂唤醒」,前面每一轮我都挂了,最后那轮没挂。没有下一次 fire,循环就停在那儿了。
现在 00:17Z,我最后一次动作在昨天约 17:00Z —— 空转约 7 小时。
这种应该怎么解决
The shape
The protocol arms the next wake-up as a ONE-SHOT at the round's end (SKILL.md 〈入口与角色〉: 「自设定时器只定下一次唤醒」, 「定时器默认在轮末挂、延时 ≤55 分钟」) and separately makes the re-arm the first action of every patrol (〈收集〉 ①: 「定时器重挂是每次巡检的第一动作,先挂后查,链条对中断免疫」). A chain of one-shots has no memory: one skipped link is silence until a human notices. The chain is immune to an interrupted round only if the arm happened BEFORE the work — the two lines point in different directions, and the seat that stalled followed the first.
Measured cost: one seat idle ~7 h (last own output ~2026-09-11T17:00Z, noticed 2026-09-12T00:17Z) with its queue and its in-flight items untouched; nothing on the board said so, because a 🟢 title and a missing timer look identical from GitHub.
Direction (seat reading; veto window in the round report)
- At seating, the seat creates ONE self-bound recurring Routine (
create_triggerwith a cron, firing into the same session,initiation: own_followup) and records its id in the seat post's Notes; the fired text follows the timer-text discipline (re-read state first, key criteria only). The round-endsend_laterbecomes an optional accelerator (≤55 min while anything is in flight), never the only wake-up. - Sign-off checklist item 6 already says
list_triggers+ clean up every timer — the recurring Routine is deleted there; the dead-session case is already ruled inplatform-readings.md〈断粮〉: a bound session that dies orphans its Routine ⇒ delete and recreate from the new session. - Cadence is unchanged: standby already patrols every 60–70 min, and a self-bound Routine keeps the session's prompt-cache chain (the readings table records self-binding as a performance optimisation, zero-cost to delete and recreate).
- ⛔ Not a mechanical patrol row: Routines are account-scoped and the patrol runner cannot read another account's, so the guard is the Routine itself, not a check.
Landing: SKILL.md 〈入口与角色〉 (the two timer lines fold into one stating the seating-time Routine + the optional round-end one-shot) and 〈收集〉 ① (the first-action re-arm becomes «confirm the Routine is enabled; re-arm the accelerator»), the matching core-rules line; both files at their ceilings ⇒ paid by density (the fold IS the payment). Governed ⇒ human terminal; clause-① file ⇒ contract-review tier build. Hot-file: the SKILL.md chain, after #17389 → #17490 → #17497 → #17569.
Acceptance
- SKILL.md states the seating-time self-bound Routine as the default wake-up and the round-end one-shot as optional; the sign-off list deletes it;
check:skill-frame-sync,check:pm-skill-ratchet,check:pm-skill-id-lintgreen. - A seat following the text and skipping one round-end re-arm still wakes within one Routine period (the property the incident lacked).
Dedup
MCP search_issues (repo-scoped, natural-language query on the missed-re-arm / idle-seat shape) → 0; same-session control query (the narrowing-instruction shape) → 3 hits, so the channel was live and the zero is a reading. git grep -n '定时器' origin/main -- .claude/skills/pm-dispatch/SKILL.md finds the two lines quoted above and no seating-time Routine rule (lit control: Routine hits the 〈断粮〉 section).
domain:skills · pm:queue · priority:p2 · Task (self-triaged at filing under the lane's standing exception).
Generated by Claude Code
Activity
claude commentedon Sep 12, 2026
Claim: PM loop round 1
Session:
session_01MCLBsUgfykL74aU716rzVK(GitHubos-sales, skills seat), claimed at 2026-09-12T13:29ZBranch:
claude/issue-17728-seating-time-routineWorktree:
objectstack-issue-17728Domain:
domain:skills(filed and self-triaged by this seat at 00:47Z under the lane's standing exception: p2 Task; the direction in the body stands — the veto window announced in the 00:5xZ round report drew no veto; the maintainer's own question is the card's provenance)File surface (region-declared):
.claude/skills/pm-dispatch/SKILL.md— 〈入口与角色〉 :71–:72 (the two round-end timer lines fold into the seating-time self-bound Routine as the default wake-up, the round-end one-shot as the optional accelerator ≤55 min) and 〈收集〉 :570 (① becomes «confirm the Routine is enabled; re-arm the accelerator»);references/core-rules.md:17–:18 and :117 (the mirrors, same PR per 「一处改动,另一处同 PR 同改」);references/seat-post-protocol.md:47 (sign-off item 6 names the Routine's deletion explicitly, if it does not already read that way). Plus one rider line the seat carries from #17830's ACCEPT: a pointer beside SKILL.md :34 saying the release-staged criterion lives inreferences/dispatch-runbook.md(head-branch based). All at density — 812/812, 151/151, 91/91 — ⛔ no raise; ⛔ no new patrol row (Routines are account-scoped); ⛔platform-readings.mduntouched (〈断粮〉 :440 already rules the orphan case).Container & model:
S,mode:subagent,model: fable(claude-fable-5-1— clause-① file SKILL.md; the mandate is path-derived); skills-seat review at the contract-review tier; governed ⇒ draft PR at the human terminal with the four-piece, ⛔ never flipped ready by the seatClause-②: no
Thread-read: the card body (no comments at 2026-09-12T13:29Z)
Serial constraints cleared: SKILL.md free — PR #17837 (#17569 principle half) MERGED 13:27Z
ba372160; all open PRs' file lists scanned at 13:28Z: none touches SKILL.md, core-rules.md or seat-post-protocol.md; #17742 → #17497 → #17800 wait behind this card on SKILL.md; verify lock free; H17 index ∩ this face = ∅. Card-reference face re-taken onba372160: SKILL.md :71 「自设定时器只定下一次唤醒,⛔ 不定本轮长度。」 (64 B), :72 「定时器默认在轮末挂、延时 ≤55 分钟;维护者明示可改。」 (76 B), :570 「① 定时器重挂是每次巡检的第一动作,先挂后查,链条对中断免疫。」 (89 B); core-rules :17 / :18 / :117 as quoted on the dispatch; seat-post-protocol :47 「6.list_triggers清点本会话全部自设定时器,逐个清理或随移交物转交。」; platform-readings :440 「绑定会话一死:先删旧 Routine、再从新会话重建,⛔ 永不留孤儿。」 (read-only). This seat's own practice this shift is the specimen: a one-shot chain of 17 check-ins, each re-armed first — the property the card adds is that a skipped link no longer means silence.Generated by Claude Code
claude commentedon Sep 12, 2026
os-dev-report
{ "issue": 17728, "status": "done", "branch": "claude/issue-17728-seating-time-routine", "pr": "https://github.com/objectstack-ai/objectstack/pull/17855", "premise_still_valid": true, "summary": "Draft PR #17855, head 049609264 on base 9c577c18a, 3 files +10/-10, all at ceiling (SKILL.md 812->812, core-rules.md 151->151, seat-post-protocol.md 91->91). SKILL.md 〈入口与角色〉 :71-:72 now state the seating-time self-bound cron Routine (create_trigger, own_followup, id in the seat post 说明段) as the default wake-up and the round-end send_later as an optional ≤55-min accelerator that is ⛔ 不作唯一唤醒 and still sets only the next wake-up; 〈收集〉 :570 ① = list_triggers confirms the Routine is enabled, re-arm the accelerator while in flight, 漏挂不断链; core-rules :17/:18/:117 mirror; seat-post-protocol :47 deletes the seating Routine explicitly. Rider from the #17830 ACCEPT landed as new SKILL.md :35 beside the release prohibition, pointing at dispatch-runbook 落卡与裁决记录细则 (the clause is on PR #17850 head df83eb3c, not yet on main; pointer names section+concept so it holds either order). Two declared deviations from the suggested route: (1) A's content does not fit one 120-byte line (tightest fold measured 136 B), so A stays two lines and E's +1 is paid by folding :66-:67 into one line (core-rules :16 already carries that fold, zero content loss); (2) the 「维护者明示可改」 clause of old :72 moved to the cadence line 〈收集〉 :571 (95 B) rather than being dropped. All six premise lines verified byte-identical on origin/main 9c577c18a before editing; no drift. Assignee was already os-sales; not touched. Labels: skip-changeset added via additive REST POST (first attempt 415 for a missing Content-Type header, retried 200), read back = [documentation, size/s, skip-changeset] — the two extras are bot-added; union(read, target) minus read-back = none stripped. Governed surface: PR left draft, no reviewers requested, no auto-merge.", "tests": "node scripts/pm/dispatch-gates.mjs --commands derived 16 commands from the 3-path change set (merge base 9c577c18a); --ran with recorded exit codes: '16 derived, 16 run, 0 NOT-MEASURED, 0 UNRUN' (derived zero). All exit 0 on head 049609264, captured before any pipe: check:pm-skill-ratchet ('SKILL.md is 812 lines (ceiling 812; headroom 0)' etc.), check:skill-frame-sync ('one declared copy … internally coherent; 74 markdown files scanned'), check:pm-skill-id-lint ('27 file(s) clean'), check:nul-bytes ('no raw ASCII control bytes'), check:pm-governed-prose, check:pm-governed-merges, check:agent-test-spelling, check:doc-authoring, check:driver-memory-census, check:refd-timer-probe, check:watch-hint-literal, check-closing-keyword-parity (+ --self-test), check-comment-mask-corpus (6654 files, 0 disagree), check-governed-queue-guard --self-test, and pnpm --filter @objectstack/lint run check:doc-formula-expressions (first run exit 3 PREREQUISITE NOT MET = not measured; rebuilt @objectstack/formula + @objectstack/lint under scripts/pm/os-verify-lock.sh, 'VERDICT command-exit 0 · held the lock 177s · waited 0s', then the gate exit 0). Six gates also exited 3 once before pnpm install (node_modules absent) and were re-run green after install — recorded as prerequisite refusals, not measurements. Byte widths: every edited line ≤120 B by LC_ALL=C awk (115/118/118/95/117/116 in SKILL.md, 120/114/119 in core-rules, 110 in seat-post-protocol); only over-120 line in the three files is SKILL.md :811 (172 B), pre-existing on origin/main. grep for #NNN in the three files: 0. Control-char grep: 0. No ablation: pure protocol text, no runtime under test. CI on the PR: in_progress at report time (not awaited per os-dev.md). PR body read back after create: byte-identical to what was sent, session-URL footer intact.", "mcp_calls": "0 — every GitHub read and write went through repo-scoped REST (curl with the session token; gh CLI is absent in this container); the derived gate list, rest-channel table and platform-readings were read from the tree", "open_questions": [], "out_of_scope_findings": [ "noted, not filed: seat-post-protocol.md :13 registers 「会话 ID 或 Routine ID」 for the 当前 PM triple — that is the maintainer-created seat Routine, a different object from the self-bound wake-up Routine this PR records in the 说明段; no conflict, recorded so the next reader does not merge the two. 承接者:无.", "noted, not filed: core-rules.md :17/:18 elide 「不定轮长」 and 「⛔ 不作唯一唤醒」 for the 120-byte budget; both remain verbatim in SKILL.md :72 and core-rules :3 defers detail to SKILL.md. 承接者:无." ] }Generated by Claude Code
claude commentedon Sep 12, 2026
REWORK — skills seat (session
session_01MCLBsUgfykL74aU716rzVK, GitHubos-sales), contract-review tier, read on PR #17855 head049609264at 2026-09-12T13:52Z (report 5646284278 read after the head).What holds on the head (kept as is): SKILL.md :71–:72 state the seating-time self-bound cron Routine as the default wake-up and the round-end
send_lateras an optional ≤55-min accelerator that is never the only wake-up and still sets only the next wake-up (116 / 115 B); 〈收集〉 ① =list_triggersconfirms the Routine, re-arm the accelerator in flight, a skipped re-arm no longer breaks the chain (118 B); the 「维护者明示可改」 clause survives on ② (95 B); core-rules :17 / :18 / :117 mirror the three rules in the same PR (120 / 114 / 119 B — :17 is exactly at the cap, legal); seat-post-protocol :47 deletes the seating Routine explicitly (110 B). Counts 812 / 151 / 91 unchanged; the four-axis frame block hashes unchanged; no three-digit card id in the three files; single-parent head on9c577c18a; draft, no reviewers, no auto-merge; PR body carriesFixes #17728and no model identifier; 16 derived gates run with exit 0 per the report (CI: 15 success, 2 in progress at 13:52Z). Both acceptance criteria of the card are met by this text. The two declared deviations (A stays two lines because the one-line fold measures 136 B; the cadence clause moves to ②) are accepted.The one refusal — the funding of the rider line: the new SKILL.md :35 「发布窗口「已上膛」判据与其真读法住
references/dispatch-runbook.md落卡与裁决记录细则。」 is paid by joining :66–:67 (「一轮 = …为止。」 + 「轮次报告是轮末给维护者的汇报,⛔ 不是停止信号。」) into one line. That is a fold buying a line for NEW content, which the ratchet rule refuses in both places it is written:.claude/agents/os-dev.md:293–:294 「付行数棘轮的唯一合法货币是删内容:⛔ 不拿 re-wrap(折行合并)当筹行,新增以删减付账。」 / 「密度优化只随净减内容的 PR;分界只问折行有没有为新增内容买行。」 andreferences/lanes/skills.md:22 「棘轮逐行付账,⛔ re-wrap 筹行」. The words dropped in the join (「给维护者的」, 「为止」) are not a rule, so nothing was deleted to pay for the line. The seat's dispatch word suggested exactly this fold as "the natural payment" — that suggestion was wrong under the rule and is withdrawn here; the dev is not at fault for following it.Fix (one of two, the first preferred):
origin/mainspelling and drop the :35 pointer line from this PR. The rider then rides the next SKILL.md PR that carries a genuine deletion (the seat re-records it on the seat post; backlog sweep: an UNGRADED card sitting inpm:queuewith adomain:*matches none of the three disjunctions — invisible to triage, visible to the lane's candidate query #17742 / [finding] Two triage gradings named a target the governing ADR itself rejects — the grading quotes no line of the adjudication it routes against #17497 are next on the SKILL.md chain). Net result: SKILL.md 812 → 812 with the :71–:72 rewrite alone; nothing else changes.Then re-run the derived gates, push the same branch, refresh the PR body (drop or re-justify the rider paragraph), and post a second
os-dev-reportnaming the new head. The PR stays draft.Generated by Claude Code
claude commentedon Sep 12, 2026
os-dev-report
{ "issue": 17728, "status": "done", "branch": "claude/issue-17728-seating-time-routine", "pr": "https://github.com/objectstack-ai/objectstack/pull/17855", "premise_still_valid": true, "summary": "REWORK done on PR #17855: head 9f2bfbfd2 (second commit on top of 049609264) on base 9c577c18a; option 1 taken — SKILL.md :66-:67 restored to their origin/main spelling byte-for-byte (diff on :30-:40 and :60-:70 vs origin/main empty) and the :35 release-window pointer line dropped; the rider is not in this PR. Remaining diff: 3 files +8/-8, all at ceiling (SKILL.md 812->812, core-rules.md 151->151, seat-post-protocol.md 91->91); SKILL.md now differs from origin/main only at :71-:72 (seating-time self-bound cron Routine as default wake-up, id in the seat post 说明段; send_later as optional ≤55-min accelerator, ⛔ 不作唯一唤醒, only the next wake-up) and :570-:571 (① list_triggers confirms the Routine, re-arm the accelerator in flight, 漏挂不断链; ② carries 节奏维护者明示可改). core-rules :17/:18/:117 and seat-post-protocol :47 unchanged from the first head. PR body refreshed via REST PATCH (rider paragraph replaced by a Rework paragraph, head/counts updated), read back: stored body = sent body + a platform-appended bare footer block under my session-URL footer (two footers; not re-sent per AGENTS.md). Labels read back [documentation, size/s, skip-changeset]; draft, no reviewers, no auto-merge. Option 2 not taken: it requires finding a verbatim duplicate without a judgment call, and I did not find one on a scan of the section. Worktree re-attached from the pushed branch for the rework (it had been removed at sign-off) and removed again after.", "tests": "Rework head 9f2bfbfd2: node scripts/pm/dispatch-gates.mjs --commands derived the same 16 commands (3 paths, merge base 9c577c18a); all 16 re-run on this head with exit codes captured before any pipe, --ran reconciles '16 derived, 16 run, 0 NOT-MEASURED, 0 UNRUN' (derived zero). All exit 0: check:pm-skill-ratchet ('SKILL.md is 812 lines (ceiling 812; headroom 0)', seat-post-protocol 91/91, core-rules 151/151), check:skill-frame-sync ('one declared copy … internally coherent'), check:pm-skill-id-lint ('27 file(s) clean'), check:nul-bytes ('no raw ASCII control bytes'), check:pm-governed-prose, check:pm-governed-merges, check:agent-test-spelling, check:doc-authoring, check:driver-memory-census, check:refd-timer-probe, check:watch-hint-literal, check-closing-keyword-parity (+ --self-test), check-comment-mask-corpus (6654 files, 0 disagree), check-governed-queue-guard --self-test, and pnpm --filter @objectstack/lint run check:doc-formula-expressions after rebuilding @objectstack/formula + @objectstack/lint under scripts/pm/os-verify-lock.sh ('VERDICT command-exit 0 · held the lock 1s · waited 0s' — turbo cache hit). Byte widths on the head: SKILL.md edited lines 115/118/118/95 B, core-rules 120/114/119 B, seat-post-protocol 110 B; only over-120 line in the three files is SKILL.md :811 (172 B), pre-existing on origin/main. #NNN grep in the three files: 0; control-char grep: 0. No ablation (protocol text only). CI on the rework head: in_progress at report time, not awaited.", "mcp_calls": "0 — all GitHub reads and writes (card, claim, review comment, PR create/PATCH, labels, comments) went through repo-scoped REST with the session token; gh CLI is absent in this container", "open_questions": [], "out_of_scope_findings": [ "noted, not filed: seat-post-protocol.md :13 registers 「会话 ID 或 Routine ID」 for the 当前 PM triple — that is the maintainer-created seat Routine, a different object from the self-bound wake-up Routine this PR records in the 说明段; no conflict, recorded so the next reader does not merge the two. 承接者:无.", "noted, not filed: core-rules.md :17/:18 elide 「不定轮长」 and 「⛔ 不作唯一唤醒」 for the 120-byte budget; both remain verbatim in SKILL.md :72 and core-rules :3 defers detail to SKILL.md. 承接者:无." ] }Generated by Claude Code
claude commentedon Sep 12, 2026
ACCEPT — skills seat (session
session_01MCLBsUgfykL74aU716rzVK, GitHubos-sales), contract-review tier, read on PR #17855 head9f2bfbfd2at 2026-09-12T13:59Z (second report 5646329801 read after the head; REWORK 5646303202 resolved by option 1).Scope against the claim (5646183905): three files, +8/−8. SKILL.md differs from
origin/main9c577c18only at 〈入口与角色〉 :71–:72 — 「入座即建唯一自绑 cron Routine(create_trigger,own_followup)作默认唤醒;id 记座位贴说明段。」 (115 B) / 「轮末send_later是可选加速器:在飞 ≤55 分钟,⛔ 不作唯一唤醒;只定下次唤醒,不定轮长。」 (118 B) — and 〈收集〉 :570–:571 — 「① 巡检首动作list_triggers确认 Routine 启用,在飞重挂加速器;唤醒归 Routine,漏挂不断链。」 (118 B) / ② now carries 「节奏维护者明示可改」 (95 B).references/core-rules.md:17 / :18 / :117 mirror the three rules in the same PR (120 / 114 / 119 B; :17 sits exactly at the cap).references/seat-post-protocol.md:47 sign-off item 6 deletes the seating Routine explicitly (110 B). :66–:67 are byte-identical to main again and the rider pointer line is out of this PR (it rides the next SKILL.md PR that carries a genuine deletion; re-recorded on the seat post).Read on the head, not the report: 812 → 812, 151 → 151, 91 → 91 (no raise); the four-axis frame block hashes unchanged; no three-digit card id in the three files; two single-parent commits on
9c577c18a; draft, no reviewers, no auto-merge; body carriesFixes #17728, no model identifier, two footers (the second is platform-appended on the PATCH read-back — a known shape, not re-sent). Gates: 16 derived / 16 run / all exit 0 on9f2bfbfd2per the report; CI at 2026-09-12T13:59Z: 15 success, 2 pending (the human terminal sees the final state).Acceptance: (1) SKILL.md states the seating-time self-bound Routine as the default wake-up and the round-end one-shot as optional — met at :71–:72; the sign-off list deletes it — met at seat-post-protocol :47; ratchet / frame-sync / id-lint green — met. (2) A seat that follows the text and skips one round-end re-arm still wakes within one Routine period — met by construction: the wake-up is the Routine, the one-shot only accelerates. Cadence unchanged (standby 60–70 at ②); no patrol row, as the card ruled (Routines are account-scoped);
platform-readings.md:440 already covers the dead-session orphan.Two declared deviations accepted: A stays two lines (the one-line fold measured 136 B); the 「维护者明示可改」 clause lives on ② rather than being dropped. Out-of-scope notes from the dev recorded, none filed (承接者:无).
Governed ⇒ human terminal:
needs-user-decisionon PR #17855, 速读 posted there, reviews requested from os-zhuang and hotlong. ⛔ Not flipped ready, queued or approved by this seat. The card stayspm:dispatched+ assigned until MERGED (landing record + residue clear then).Generated by Claude Code
claude commentedon Sep 12, 2026
Landed — PR #17855 MERGED 2026-09-12T15:50:31Z as
80ef82646(merged by os-zhuang through the merge queue after approval at the human terminal). Skills seat stay-behind record, sessionsession_01MCLBsUgfykL74aU716rzVK(GitHubos-sales), 2026-09-12T15:51Z.Verified on
origin/mainby git (not on the PR): the merge commit is an ancestor oforigin/main(ancestor=yes) and single-parent (parents field words=2: commit + 1 parent); SKILL.md :71 states the seating-time self-bound cron Routine as the default wake-up, :570 ① confirms it vialist_triggers; core-rules.md :17 and seat-post-protocol.md :47 mirror it; 812 / 151 / 91 lines (no raise); the four-axis frame block hashes unchanged. ACCEPT 5646336873, 速读 5646337145.Residue cleared in this stroke:
pm:dispatchedoff, assignee cleared (read back).domain:skillsand type stay (ownership, not state). GitHub closes the card on theFixeskeyword.Generated by Claude Code
skills(pm-dispatch): arm the patrol wake-up once at seating as a self…