Repository navigation
Commit edba9d2
pm-dispatch: a project seat creates its own hourly patrol routine, bound to its session (#26067)
Fixes #25991
Clause-②: no
Metadata-protocol: none
## What this changes
The pm-dispatch skill said a project seat's patrol routine runs every
2–4 hours and is created by the maintainer in the claude.ai Routines UI.
The maintainer's word on the ui-lane project (2026-10-26, verbatim and
untranslated):
> 你应该自己创建定时啊
> 为什么不是每小时
> 那需要立卡改 skills吗
> 立卡
Two points, the project-seat form only (Routine seats are untouched):
1. **Interval.** The project seat's patrol runs **hourly by default**; a
lane may relax it with a reason, stated on its seat post.
2. **Who creates it.** The project seat creates its own patrol routine
from inside its session, bound to that session (`create_trigger` in its
default same-session mode — no `create_new_session_on_fire`, no
`persistent_session_id`). The "maintainer creates it in the Routines UI"
step is removed for project seats.
Kept, as the triage audit on the card fixes the boundary: the
zero-output warning (now scoped to the new-session `create_trigger`
form) and the `send_later`-chain ban.
## The four files, line by line
All four sit at their `check-skill-line-ratchet` ceiling with headroom
0. The change is **line-neutral in every file** — rewrite in place, no
ceiling moved, no re-wrap, no joined lines — and every rewritten line is
within the ratchet's 120-byte line cap.
| File | Lines before → after | Edited line(s) | Bytes |
|:--|:--|:--|:--|
| `.claude/skills/pm-dispatch/SKILL.md` | 319 → 319 | 71: the 项目席唤醒 rule
— one self-created, self-bound (自绑, the term `platform-readings.md`
already uses) patrol routine per project, hourly by default; the old `⛔
无自绑 cron` clause is replaced by that scoped rule; the `send_later`-chain
ban stays | 120 |
| `references/seat-post-protocol.md` | 91 → 91 | 58: Routine seat =
maintainer in the Routines UI; project seat = self-created, self-bound.
60: zero-output warning scoped to the new-session `create_trigger` form.
65: tier and cron as UI tunables scoped to Routine seats. 66:
project-seat patrol hourly by default, relaxing needs a reason and goes
on the seat post — folded into the existing "the protocol does not copy
the current value; the seat post is the current state" rule | 119 / 119
/ 110 / 118 |
| `references/seat-lifecycle.md` | 96 → 96 | 96: 每 2–4 小时 → 默认每小时 | 118
|
| `references/project-forms.md` | 54 → 54 | 31: the seating step builds
its own routine (自建), patrol hourly by default | 117 |
Wording choices worth a reviewer's eye:
- `SKILL.md:71` drops the word 事件 from `PR 订阅事件` to land at exactly 120
bytes while keeping `每项目一个` — the one-per-project guard matters more now
that seats create the routine themselves.
- The mechanism is spelled by contrast, not by parameter name: the
project seat's routine is 自绑 (bound to its own session, the tool's
default mode), and the warned-against form is the one that 开新会话 (opens a
new session per fire). `platform-readings.md` already records both facts
(an agent-created new-session Routine carries no GitHub tools; a
self-bound trigger wakes an existing session with its tools loaded, at
the cost of an orphan if that session dies — delete and recreate from
the new session).
- The seat-post-protocol section keeps its smoke-test and rollback lines
for both forms.
## Verification
- `pnpm check:pm-skill-ratchet`, `pnpm check:pm-skill-id-lint`, `pnpm
check:skill-frame-sync` green on the working tree before the commit, and
the full derived union on the final head below.
- Control-character scan of the four files: none.
- Not run locally: the `Type Check` lanes and the workflow-event-only
families `dispatch-gates` marks CI-measured; the PR's check-runs are the
reading for those.
### Local gate union on the final head `c4503e6c`
Derived with `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` (no paths; change set taken from git off the
merge base): 20 commands, each run with its exit code captured before
any pipe, reconciled with `--ran`: **20 derived, 20 run, 0 NOT-MEASURED,
0 UNRUN** — every one exit 0.
`check-closing-keyword-parity` (+ `--self-test`) ·
`check-comment-mask-corpus` · `pm/check-governed-queue-guard
--self-test` · `pm/check-harness-current --self-test` ·
`@objectstack/lint check:doc-formula-expressions` ·
`check:agent-test-spelling` · `check:cross-package-test-inputs` ·
`check:doc-authoring` · `check:driver-memory-census` ·
`check:gitlink-declared` · `check:nul-bytes` · `check:pm-expected-skips`
· `check:pm-governed-merges` · `check:pm-governed-prose` ·
`check:pm-skill-id-lint` · `check:pm-skill-ratchet` ·
`check:refd-timer-probe` · `check:skill-frame-sync` ·
`check:watch-hint-literal`
Readings worth quoting: `check:pm-skill-ratchet` holds each of the four
files at its ceiling with headroom 0 (319, 91, 96, 54) and every line
within the 120-byte budget; `check:pm-skill-id-lint`: 88 files clean;
`check:skill-frame-sync`: the one declared copy of the decision frame is
internally coherent (the frame lines were not touched).
`check:doc-formula-expressions` first refused with exit 3 (unbuilt
`@objectstack/formula` and `@objectstack/lint`); after building the two
packages under the verify lock (VERDICT command-exit 0) it ran clean.
Local-only reading, not a CI family: `check:skill-frame-freshness` — the
decision frame in this tree is current with `origin/main`.
## 维护者速读(草稿)
**改了什么**:项目席的巡查 routine 改为席位自己在会话内创建、绑定本会话(`create_trigger`
默认模式),默认每小时;车道有理由可放宽,间隔写在座位贴。「由维护者在 Routines UI 创建」只保留给 Routine 席;「开新会话的
`create_trigger` 拿不到 GitHub 工具、零产出」的警告保留并收窄到那一种形态;`send_later`
链禁令保留。四个文件各改一到四行,行数一行不增。
**为什么改**:你 2026-10-26 在 ui
车道项目的原话:「你应该自己创建定时啊」「为什么不是每小时」「立卡」。效果:新坐席的项目车道从第一分钟就有巡查,不用等你在 Routines
UI 建一次;改判答复、半态巡查、补位这些非事件驱动的待命项最多晚一小时,不再是最多四小时。
**风险与代价(含回滚)**:自绑触发器随会话生死——所绑会话一死,触发器成孤儿(平台读数已记:先删旧的、再从新会话重建,不留孤儿)。每小时唤醒比
2–4 小时多耗用量,车道可按理由放宽。回滚 = revert 本 PR 的一个 commit;各席已建的触发器由各席自己
`delete_trigger`。
**席位意见**:
**你要做的**:读完 diff 给一个字——批准则由你亲手落地(受管面 `.claude/**`,本 PR 保持 draft
等你),否决则关闭。
## Acceptance notes
Observed while measuring, outside the four named lines — noted here, not
filed, for the seat to route:
- `references/project-forms.md:32` says the director and triage seats in
one project may share one routine. A session-bound patrol trigger wakes
only the session that created it, so a shared routine now wakes one seat
thread; the other needs its own trigger or a poke. Not changed here
(outside the card's four lines).
- `references/seat-post-protocol.md:61` (model pinned in the UI; a
Routine inherits the environment default model) reads as Routine-seat
text after line 58's split and is left as is; a self-bound trigger keeps
the bound session's tier (`platform-readings.md`, the 自绑 facts). Not a
contradiction of either point.
- `references/execution-duties.md:158` and
`references/dispatch-runbook.md:122`, named in the dispatch as
unverified candidates, were measured and contradict neither point: 158
says the project seat is woken by events and the patrol routine
(consistent); 122 is the poke-trigger spelling (`create_trigger` with
`persistent_session_id` plus `fire_trigger`) for message delivery, a
different mechanism. `references/lanes/director.md:7` (direct-connect
director seat: no Routine or cron) is about the director seat and out of
scope.
- The card's evidence that a session-bound trigger runs with the seat
session's own tools (the ui seat's hourly trigger) is a fleet
colleague's statement. The wording here rests on `platform-readings.md`
(self-bound triggers wake an existing session with its tools loaded) and
the `create_trigger` tool contract (the default mode fires into the
calling session), not on that trigger id.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01LqKsGyMNFwwnbF5FTAqyPn)_
Co-authored-by: os-warren <noreply@anthropic.com>1 parent 48e84a9 commit edba9d2
4 files changed
Lines changed: 7 additions & 7 deletions
File tree
- .claude/skills/pm-dispatch
- references
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
68 | 68 | | |
69 | 69 | | |
70 | 70 | | |
71 | | - | |
| 71 | + | |
72 | 72 | | |
73 | 73 | | |
74 | 74 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
31 | | - | |
| 31 | + | |
32 | 32 | | |
33 | 33 | | |
34 | 34 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
93 | 93 | | |
94 | 94 | | |
95 | 95 | | |
96 | | - | |
| 96 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
55 | 55 | | |
56 | 56 | | |
57 | 57 | | |
58 | | - | |
| 58 | + | |
59 | 59 | | |
60 | | - | |
| 60 | + | |
61 | 61 | | |
62 | 62 | | |
63 | 63 | | |
64 | 64 | | |
65 | | - | |
66 | | - | |
| 65 | + | |
| 66 | + | |
67 | 67 | | |
68 | 68 | | |
69 | 69 | | |
| |||
0 commit comments