@seanyao/roll 3.618.3 → 3.619.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seanyao/roll",
3
- "version": "3.618.3",
3
+ "version": "3.619.1",
4
4
  "description": "Roll — Roll out features with AI agents",
5
5
  "packageManager": "pnpm@11.1.3",
6
6
  "scripts": {
package/skills/README.md CHANGED
@@ -27,8 +27,8 @@ roll 的**技能契约**仓——AI agent 在 roll 项目里工作时加载并
27
27
  - `roll-.review` / `roll-.qa` — TCR 内嵌自审与测试金字塔基准
28
28
 
29
29
  **Observation · 观察与汇报**
30
- - `roll-brief` — owner 简报;`roll-notes` — 项目日记
31
- - `roll-sentinel` — 生产抽查巡检;`roll-.dream` — 夜间架构/文档健康扫描
30
+ - `roll-notes` — 项目日记
31
+ - `roll-.dream` — 夜间架构/文档健康扫描
32
32
  - `roll-doctor` — 工具链体检;`roll-doc` — 存量文档自动化
33
33
 
34
34
  **Lifecycle & misc · 生命周期与杂项**
@@ -42,9 +42,10 @@ Every hub must include `## Gotchas` or `## Known Failure Modes`.
42
42
  - If a gotcha comes from a missed load, add a positive route case.
43
43
  - If a gotcha comes from an off-target load, add a negative route case.
44
44
  - Treat the section as append-mostly unless an entry is proven obsolete.
45
- - Never instruct agents to `source "$(command -v roll)"`: the TS-native `roll`
46
- is a bundled CLI, not a bash library, and sourcing it executes JS as shell
47
- (FIX-274). Skill steps call `roll <command>` directly.
45
+ - Never instruct agents to source the `roll` binary as if it were a shell
46
+ library: the TS-native `roll` is a bundled CLI, not a bash script, and
47
+ `source "$(command -v roll)"` executes JS as shell (FIX-274). Skill steps call
48
+ `roll <command>` directly.
48
49
  - Skills do NOT self-score (FIX-343). The working agent never scores its own
49
50
  story; the Review Score is a runner-side peer-review outcome, produced by a
50
51
  Reviewer in a FRESH, separate session (never a sub-agent of the builder's
@@ -86,30 +86,19 @@ reason: <one short line — which condition triggered, with numbers>
86
86
  When `verdict: ok` → continue to Step A2 normally.
87
87
  When `verdict: too_big` → go to **US-AGENT-008 self-downgrade path**, **but** first run the **US-AGENT-009 chain_depth cap check**:
88
88
 
89
- ```bash
90
- # 0a. Cap check: refuse the third consecutive auto-split.
91
- # exit 0 → split allowed; exit 1 → cap hit, take cap-hit path instead.
92
- if ! bash -c 'source "$(command -v roll)"; _loop_chain_depth_cap_check US-XXX-NNN'; then
93
- # Cap hit (chain_depth ≥ 2): hold + ALERT, exit cleanly.
94
- bash -c 'source "$(command -v roll)"; _loop_split_cap_hit US-XXX-NNN "depth >= 2, human triage required"'
95
- exit 0
96
- fi
97
-
98
- # 1. Invoke roll-design to re-split the story into smaller sub-stories.
99
- # Each sub-story carries chain_depth = (parent.chain_depth + 1).
100
- # Sub-stories land as 📋 Todo with depends-on:<parent> chained.
101
- Skill("roll-design", "--from-story US-XXX-NNN")
102
-
103
- # 2. After the sub-stories are written to BACKLOG, flip the parent
104
- # to 🚫 Hold and emit the downgrade event. The helper handles ALERT.
105
- bash -c 'source "$(command -v roll)"; _loop_self_downgrade US-XXX-NNN "too_big: <reason from verdict>" "US-XXX-NNNa,US-XXX-NNNb"'
89
+ > **v3 note (FIX-364)**: the retired bash helpers `_loop_chain_depth_cap_check`, `_loop_split_cap_hit`, and `_loop_self_downgrade` were removed with the v2 bash engine. v3 `roll` is a TS binary and cannot be sourced. The equivalent self-downgrade surface is being rebuilt in **US-AGENT-042** as `roll loop self-downgrade <story> <reason> <sub-ids>`; until that lands, the skill should **not** invoke the dead bash helpers above. If a story is genuinely too big for a single cycle, raise an ALERT and exit cleanly without TCR commits.
106
90
 
107
- # 3. Exit cleanly no TCR commits this cycle. The next loop cycle picks
108
- # up the first sub-story (which is smaller and should pass pre-flight).
109
- exit 0
110
- ```
91
+ 1. Invoke `roll-design` to re-split the story into smaller sub-stories.
92
+ Each sub-story carries `chain_depth = (parent.chain_depth + 1)`.
93
+ Sub-stories land as 📋 Todo with `depends-on:<parent>` chained.
94
+ 2. After the sub-stories are written to BACKLOG, flip the parent to 🚫 Hold
95
+ and emit the downgrade event.
96
+ 3. Exit cleanly — no TCR commits this cycle. The next loop cycle picks up
97
+ the first sub-story (which is smaller and should pass pre-flight).
111
98
 
112
- If `roll-design` cannot produce ≥2 sub-stories (story is already irreducible), fall through to **US-AGENT-009 cap-hit path** by invoking `_loop_split_cap_hit` directly. The cap is purely about stopping infinite split chains; even on the first re-split, if the design step gives up, the cap-hit handler raises ALERT for human triage.
99
+ If `roll-design` cannot produce ≥2 sub-stories (story is already irreducible),
100
+ treat it as a cap-hit: hold the parent, write an ALERT for human triage, and
101
+ exit cleanly. The cap exists purely to stop infinite split chains.
113
102
 
114
103
  > Pre-flight is honest, not paranoid: a small story (est_min ≤ 8 — the `easy` tier — with chain_depth=0) should almost always go `ok`. The check pays off on the long tail — stories with a large `est_min` that, on inspection, plainly compose far more files and behaviours than one cycle can land green.
115
104
 
@@ -389,12 +378,7 @@ When any signal appears, **do not stop — flag it**:
389
378
 
390
379
  Then continue implementing the current Story normally.
391
380
 
392
- **Event emission** — after all TCR micro-steps for a Story complete, emit a `build` event so the cycle event stream reflects the work done:
393
-
394
- ```bash
395
- # _tcr_count = number of "tcr:" prefix commits made during this Story
396
- _loop_event build "$US_ID" "${_tcr_count} commits" "" 2>/dev/null || true
397
- ```
381
+ **Event emission** — after all TCR micro-steps for a Story complete, emit a `build` event so the cycle event stream reflects the work done. The v3 runner writes events natively; do not call the retired bash helper `_loop_event`.
398
382
 
399
383
  ### Phase 4: E2E Deposit
400
384
 
@@ -129,18 +129,13 @@ Emit `verdict: ok` or `verdict: too_big` (with `reason:`) as the first cycle out
129
129
  - `ok` → continue with step 1 below normally
130
130
  - `too_big` → self-downgrade per US-AGENT-008, **gated by US-AGENT-009 cap check**:
131
131
 
132
- ```bash
133
- # Cap check first (chain_depth ≥ 2 → refuse third auto-split).
134
- if ! bash -c 'source "$(command -v roll)"; _loop_chain_depth_cap_check FIX-XXX-NNN'; then
135
- bash -c 'source "$(command -v roll)"; _loop_split_cap_hit FIX-XXX-NNN "depth >= 2"'
136
- exit 0
137
- fi
138
- Skill("roll-design", "--from-story FIX-XXX-NNN")
139
- bash -c 'source "$(command -v roll)"; _loop_self_downgrade FIX-XXX-NNN "too_big: <reason>" "FIX-XXX-NNNa,FIX-XXX-NNNb"'
140
- exit 0
141
- ```
132
+ > **v3 note (FIX-364)**: the retired bash helpers `_loop_chain_depth_cap_check`, `_loop_split_cap_hit`, and `_loop_self_downgrade` were removed with the v2 bash engine. v3 `roll` is a TS binary and cannot be sourced. The equivalent surface is being rebuilt in **US-AGENT-042** as `roll loop self-downgrade <story> <reason> <sub-ids>`; until that lands, if a fix is genuinely too big for one cycle, raise an ALERT and exit cleanly without TCR commits.
142
133
 
143
- Original FIX goes to 🚫 Hold with `→ split to ...` annotation; sub-stories carry `chain_depth + 1`. Cap-hit path raises ALERT for human triage. Do NOT TCR a half fix.
134
+ If split is possible, invoke `roll-design --from-story FIX-XXX-NNN` to mint
135
+ sub-stories, then flip the original FIX to 🚫 Hold with a `→ split to ...`
136
+ annotation; sub-stories carry `chain_depth + 1`. If the split cap is hit or
137
+ `roll-design` cannot produce ≥2 sub-stories, write an ALERT for human triage.
138
+ Do NOT TCR a half fix.
144
139
 
145
140
  Bug fixes are usually small (est_min ≤ 5), so pre-flight is mostly a sanity barrier for FIXes whose underlying issue turns out structural — e.g. a "simple null check" that requires touching 12 files. Catching that upfront is cheaper than burning a cycle.
146
141
 
@@ -89,7 +89,7 @@ loop:
89
89
  ### Step 1 — Orphan 🔨 Recovery
90
90
 
91
91
  Process-level crash recovery (LOCK, heartbeat, retry budget) is handled by
92
- the runner in `bin/roll:_write_loop_runner_script` — the per-project LOCK
92
+ the v3 runner (`packages/cli/src/runner/run-cycle.ts`) — the per-project LOCK
93
93
  guarantees only one cycle for this slug is alive when you start. So at
94
94
  this point, any `🔨 In Progress` row in `.roll/backlog.md` belongs to a
95
95
  previous cycle that crashed before flipping it back; reclaim it before
@@ -132,27 +132,27 @@ Before scanning BACKLOG, process open PRs first. PRs are also units of work:
132
132
  external contributors and human teammates expect their PRs to be reviewed and
133
133
  moved forward, not starved while loop opens new fronts.
134
134
 
135
- Call `_loop_pr_inbox` after the pre-run CI check passes. It walks
135
+ Call `roll loop pr-inbox` after the pre-run CI check passes. It walks
136
136
  `gh pr list --state open` and routes each PR by classification:
137
137
 
138
138
  | Classification | Action |
139
139
  |---|---|
140
- | `loop_self` (head ref starts with `loop/` **or** `claude/`, CI not red) | `_loop_pr_merge_self_eager` — squash-merge directly when CI green + clean; if the PR is BEHIND/CONFLICTING with main, `_loop_pr_rebase_stale` rebases it first (circuit-gated) so it merges on a later tick. Never AI-review your own commit. (Agent-authored `claude/*` PRs are loop-owned the same way; a CI-red `claude/*` PR is **not** auto-healed — it falls through for a human to decide.) |
141
- | `loop_self_ci_red` (loop/* PR whose CI went red) | **US-LOOP-062a**: `_loop_pr_heal_self` background-heal (per-PR lock + heal budget `ROLL_LOOP_HEAL_MAX`, default 2, via `_project_agent`); on `ROLL_LOOP_NO_HEAL=1` / budget exhausted → deduped `[TYPE:loop-pr-ci-red]` ALERT (never silently dropped) |
140
+ | `loop_self` (head ref starts with `loop/` **or** `claude/`, CI not red) | squash-merge directly when CI green + clean; if the PR is BEHIND/CONFLICTING with main, rebase it first (circuit-gated) so it merges on a later tick. Never AI-review your own commit. (Agent-authored `claude/*` PRs are loop-owned the same way; a CI-red `claude/*` PR is **not** auto-healed — it falls through for a human to decide.) |
141
+ | `loop_self_ci_red` (loop/* PR whose CI went red) | **US-LOOP-062a**: background-heal via `roll loop pr-heal-run` (per-PR lock + heal budget `ROLL_LOOP_HEAL_MAX`, default 2, via the configured agent); on `ROLL_LOOP_NO_HEAL=1` / budget exhausted → deduped `[TYPE:loop-pr-ci-red]` ALERT (never silently dropped) |
142
142
  | `blocked_human_request_changes` | Skip — last human review requested changes; wait for the author to push fixes |
143
- | `blocked_human_approved` | **US-LOOP-062b**: `_loop_pr_merge_approved` — merge directly (`gh pr merge --squash`) when CI green + mergeable, instead of relying on repo auto-merge (which may be off); merge failure is non-fatal (retried next tick) |
144
- | `stale` (CI failed or branch behind/conflicting) | Try `_loop_pr_rebase_stale` after the circuit breaker allows it |
145
- | `eligible` (clean external PR, no blocking review) | Invoke `_loop_pr_review_external` — the actual decision is provided by US-AUTO-035's GitHub Action |
143
+ | `blocked_human_approved` | **US-LOOP-062b**: merge directly (`gh pr merge --squash`) when CI green + mergeable, instead of relying on repo auto-merge (which may be off); merge failure is non-fatal (retried next tick) |
144
+ | `stale` (CI failed or branch behind/conflicting) | Rebase onto `origin/main` after the circuit breaker allows it |
145
+ | `eligible` (clean external PR, no blocking review) | Review via `roll review-pr` (or the equivalent project agent skill) — the actual decision is provided by US-AUTO-035's GitHub Action |
146
146
 
147
- **Rebase circuit breaker** — `_loop_pr_rebase_circuit <pr>` records each rebase
148
- attempt under `pr_state.<PR>.attempts_at` in the per-slug state file
147
+ **Rebase circuit breaker** — the runner records each rebase attempt under
148
+ `pr_state.<PR>.attempts_at` in the per-slug state file
149
149
  (`~/.shared/roll/loop/state-<slug>.yaml`, FIX-052), pruning entries older
150
150
  than 24 h. Once ≥3 attempts land within 24 h, further rebases are blocked and an
151
151
  ALERT is written (typical cause: a broken workflow file makes CI never run,
152
152
  which would otherwise drive infinite rebase loops).
153
153
 
154
154
  **Lenient on infrastructure** — `gh` missing, repo unparseable, or any
155
- `gh` API failure → `_loop_pr_inbox` returns 0 and the loop falls through to
155
+ `gh` API failure → `roll loop pr-inbox` returns 0 and the loop falls through to
156
156
  Step 2 (BACKLOG scan). Same posture as the pre-run CI check.
157
157
 
158
158
  ### Step 2 — Scan BACKLOG
@@ -172,27 +172,19 @@ claimed by an **open `loop/*` PR**. Each cycle's worktree is branched from
172
172
  locally until that cycle's PR merges. Without this gate, two cycles started
173
173
  back-to-back will both pick the same Todo row and produce duplicate PRs.
174
174
 
175
- ```bash
176
- bash -c 'source "$(command -v roll)"; _loop_pr_claimed_stories'
177
- # stdout: one story ID per line (deduped) these are claimed by open
178
- # loop/* PRs on the remote. SKIP any candidate whose ID appears.
179
- # exit 0 always (lenient: gh missing / API error → empty output).
180
- ```
175
+ Use `roll loop pr-inbox` to discover story IDs already claimed by open
176
+ `loop/*` PRs on the remote. Skip any candidate whose ID appears. The runner is
177
+ lenient: `gh` missing / API error empty claim list.
181
178
 
182
- **Dependency gate** (FIX-032). For each `📋 Todo` candidate, before picking:
183
-
184
- ```bash
185
- # Source bin/roll once per cycle, then call the helper per candidate.
186
- source "$(command -v roll)"
187
-
188
- bash -c 'source "$(command -v roll)"; _loop_check_depends_on "<story-id>" .roll/backlog.md'
189
- # exit 0 → all `depends-on:US-X,US-Y` are ✅ Done → eligible
190
- # exit 1 → stdout lists unsatisfied dep IDs; SKIP this story, log to
191
- # runs.jsonl `skipped` with reason "depends-on: <unsatisfied>"
192
- ```
179
+ **Dependency gate** (FIX-032). For each `📋 Todo` candidate, before picking,
180
+ check that every `depends-on:<ID>` referenced in the story's backlog row is
181
+ already ✅ Done. The v3 runner evaluates dependencies natively; do not call the
182
+ retired bash helper `_loop_check_depends_on`. If a dependency is unsatisfied,
183
+ skip the story and log to `runs.jsonl` `skipped` with reason
184
+ `"depends-on: <unsatisfied>"`.
193
185
 
194
186
  Move to the next candidate when skipping. The gate is a pure function
195
- over .roll/backlog.md text — no side effects, no LOCK interaction.
187
+ over `.roll/backlog.md` text — no side effects, no LOCK interaction.
196
188
 
197
189
  Cap at `max_items_per_run` to limit blast radius per cycle.
198
190
 
@@ -200,7 +192,7 @@ Cap at `max_items_per_run` to limit blast radius per cycle.
200
192
 
201
193
  Loop has two layers of concurrency protection:
202
194
 
203
- 1. **Per-project LOCK** (enforced by runner script, see `bin/roll:_write_loop_runner_script`):
195
+ 1. **Per-project LOCK** (enforced by the v3 runner, see `packages/cli/src/runner/run-cycle.ts`):
204
196
  - LOCK file path: `~/.shared/roll/loop/.LOCK-<project-slug>`
205
197
  - On launch: if LOCK exists and the PID inside is alive → exit 0 (previous loop still running)
206
198
  - On launch: if LOCK exists but PID is dead → clean up stale LOCK and continue
@@ -219,42 +211,30 @@ Together these mean: only one loop runs at a time per project (LOCK), and within
219
211
 
220
212
  > **US-AGENT-006 — Per-story agent routing (pre-cycle)**
221
213
  >
222
- > Before this skill even starts, the runner inner script has already:
223
- > 1. Picked the next eligible Todo via `_loop_pick_next_story` (priority FIX > US > REFACTOR, depends-on gate respected)
224
- > 2. Read its Agent profile (est_min / risk_zone) and routed an agent via `_loop_pick_agent_for_story` (hard rules from `.roll/agent-routes.yaml` + soft preference from `runs.jsonl`)
225
- > 3. Exported `ROLL_LOOP_ROUTED_STORY` / `ROLL_LOOP_ROUTED_AGENT` / `ROLL_LOOP_ROUTED_RULE` and printed `[loop] story <id> routed to <agent> via <rule_kind>` to cron.log
214
+ > Before this skill even starts, the v3 runner has already:
215
+ > 1. Picked the next eligible Todo (priority FIX > US > REFACTOR, depends-on gate respected).
216
+ > 2. Read its Agent profile (`est_min` / `risk_zone`) and routed an agent (hard rules from `.roll/agent-routes.yaml` + soft preference from `runs.jsonl`).
217
+ > 3. Exported `ROLL_LOOP_ROUTED_STORY` / `ROLL_LOOP_ROUTED_AGENT` / `ROLL_LOOP_ROUTED_RULE` and printed `[loop] story <id> routed to <agent> via <rule_kind>` to cron.log.
226
218
  >
227
- > When `ROLL_LOOP_ROUTED_STORY` is set, prefer it as `US_ID` for this cycle. The story has already been chosen by hard+soft routing rules — and, per FIX-146, the runner re-validates it against the authoritative backlog right before handing it to you (re-picking the next eligible Todo if it went ✅ Done / In Progress / ineligible between pick and handoff, emitting a `story_stale` event). So treat `ROLL_LOOP_ROUTED_STORY` as already-eligible and just work it. Only if you still find at cycle start that it is no longer 📋 Todo in BACKLOG (a residual concurrent flip), re-pick the next eligible Todo via `_loop_pick_next_story` rather than idling the whole cycle.
219
+ > When `ROLL_LOOP_ROUTED_STORY` is set, prefer it as `US_ID` for this cycle. The story has already been chosen by hard+soft routing rules — and, per FIX-146, the runner re-validates it against the authoritative backlog right before handing it to you (re-picking the next eligible Todo if it went ✅ Done / In Progress / ineligible between pick and handoff, emitting a `story_stale` event). So treat `ROLL_LOOP_ROUTED_STORY` as already-eligible and just work it. Only if you still find at cycle start that it is no longer 📋 Todo in BACKLOG (a residual concurrent flip), signal `story_stale` and let the runner pick the next eligible Todo rather than idling the whole cycle.
228
220
  >
229
221
  > Old single-agent fallback (`primary_agent` from `~/.roll/config.yaml`) still applies when:
230
222
  > - no story is pickable (empty Todo / all blocked by depends-on)
231
223
  > - the matching agent-routes.yaml has no agent that fits the story profile (then `cold_start_default` is used)
232
224
 
233
- For each item, **before invoking the executor skill**, mark the story 🔨 In Progress in the **main repo's** .roll/backlog.md so brief and peer agents can see it being worked on. The cycle worktree is gitignored at .roll/, so editing the worktree's own copy + committing carries no change back to main — write directly via the helper instead:
234
-
235
- ```bash
236
- bash -c 'source "$(command -v roll)"; _loop_mark_in_progress US-XXX'
237
- # Updates ${ROLL_MAIN_PROJECT}/.roll/backlog.md in place: flips the row
238
- # containing US-XXX from "📋 Todo" to "🔨 In Progress". Idempotent.
239
- ```
225
+ For each item, **before invoking the executor skill**, mark the story 🔨 In Progress in the **main repo's** `.roll/backlog.md` so brief and peer agents can see it being worked on. The cycle worktree is gitignored at `.roll/`, so editing the worktree's own copy + committing carries no change back to main — write directly via the backlog store instead. The v3 runner updates `${ROLL_MAIN_PROJECT}/.roll/backlog.md` in place; do not call the retired bash helpers `_loop_mark_in_progress` / `_loop_mark_todo`.
240
226
 
241
- If the executor fails (TCR aborts, CI red, etc.), revert the marker so the next cycle can re-pick the story:
227
+ If the executor fails (TCR aborts, CI red, etc.), revert the marker so the next cycle can re-pick the story.
242
228
 
243
- ```bash
244
- bash -c 'source "$(command -v roll)"; _loop_mark_todo US-XXX'
245
- ```
229
+ Status flips happen in main directly — no per-cycle commit needed. `roll-brief` reads main's backlog, so the 🔨 marker is visible the moment the update returns.
246
230
 
247
- Status flips happen in main directly no per-cycle commit needed. `roll-brief` reads main's backlog, so the 🔨 marker is visible the moment the helper returns.
231
+ 选定故事后,发出 `pick_todo` 事件,让 dashboard / monitor / attach 都能把"这个 cycle 选了哪个 story"正确归类。 The v3 runner emits events natively; do not call the retired bash helper `_loop_event`.
248
232
 
249
- 选定故事后,调用 `_loop_event` 发出 pick_todo 事件,让 dashboard / monitor / attach 都能把"这个 cycle 选了哪个 story"正确归类:
250
-
251
- ```bash
252
- # 选定故事后立即 emit(在调用 executor skill 之前)
253
- # label 必须是 cycle_id(来自 bin/roll 注入的 LOOP_CYCLE_ID 环境变量),
254
- # 不是 US_ID — dashboard 按 label 聚类,US_ID 当 label 会让事件分到错的桶
255
- # 里,cycle 看起来"有 token 没 ID"。
256
- _loop_event pick_todo "$LOOP_CYCLE_ID" "$US_ID" ""
257
- ```
233
+ - Emit immediately after picking and before invoking the executor skill.
234
+ - `label` must be the `cycle_id` (from the `LOOP_CYCLE_ID` environment variable),
235
+ not `US_ID` — the dashboard groups by label, and using `US_ID` as the label
236
+ would put events in the wrong bucket, making the cycle appear to have tokens
237
+ but no ID.
258
238
 
259
239
  Then invoke the executor:
260
240
 
@@ -287,8 +267,8 @@ After each item completes:
287
267
  - Count `tcr:` prefix commits since `started_at` via `git log --oneline --since=<started_at>`
288
268
  - Count == 0 → revert story status in .roll/backlog.md from ✅ Done → 📋 Todo; write ALERT to `~/.shared/roll/loop/ALERT-<slug>.md` with story ID, time, reason "zero tcr: commits since story start", and suggested actions (`roll loop now` / `$roll-build <id>` / `roll loop reset`)
289
269
  - Count > 0 → continue normally
290
- 2. **CI Gate** — **MUST** invoke `roll ci --wait` (the `_loop_enforce_ci`
291
- wrapper). **Do NOT call `gh` directly** (no `gh run list`, no `gh run watch`,
270
+ 2. **CI Gate** — **MUST** invoke `roll ci --wait`. **Do NOT call `gh` directly**
271
+ (no `gh run list`, no `gh run watch`,
292
272
  no ad-hoc shell checks): `roll ci --wait` is the only sanctioned entry —
293
273
  it derives `owner/repo` from the git remote and uses `gh -R <slug>`, which
294
274
  is required to work through `~/.ssh/config` host rewrites that break gh's
@@ -327,7 +307,7 @@ After each item completes:
327
307
  merges / rebases / closes it asynchronously. There is no false-Done risk:
328
308
  with worktree isolation the ✅ Done lives only in the unmerged PR, never on
329
309
  the loop's main checkout, and the story is not re-picked meanwhile via the
330
- open-PR eligibility gate (`_loop_story_is_eligible`, FIX-146). The story's
310
+ open-PR eligibility gate (FIX-146). The story's
331
311
  ✅ Done lands on main only when the PR Loop actually merges the PR.
332
312
  2. Write ALERT to `~/.shared/roll/loop/ALERT-<slug>.md` with:
333
313
  - story ID, time, commit SHA
@@ -346,10 +326,9 @@ After each item completes:
346
326
 
347
327
  ### Step 5 — Write Run Summary
348
328
 
349
- > **FIX-044**: The inner runner script (`_write_loop_runner_script` in `bin/roll`)
350
- > now appends this record deterministically at cycle end. The shell write is the
351
- > authoritative record; the agent should still emit a run summary in the cycle's
352
- > final report for `cron.log` visibility.
329
+ > **FIX-044**: The v3 runner (`packages/cli/src/runner/run-cycle.ts`) appends
330
+ > this record deterministically at cycle end. The agent should still emit a run
331
+ > summary in the cycle's final report for `cron.log` visibility.
353
332
 
354
333
  After all items in this cycle:
355
334
 
@@ -58,13 +58,7 @@ Allowed states only. No invented words.
58
58
  - **OBJECT**: The proposal is wrong. Provide an alternative. Proceed to next round.
59
59
  - **ESCALATE**: Round 3 reached without AGREE, or a round fails due to API/token error. Hand off to the human user.
60
60
 
61
- After each round decision, emit a `peer` event to the cycle event stream:
62
-
63
- ```bash
64
- # $round = current round number, $total = max rounds, $verdict = AGREE/REFINE/OBJECT/ESCALATE
65
- # $agents = e.g. "claude→deepseek"
66
- _loop_event peer "${round}/${total}" "$verdict" "$agents" 2>/dev/null || true
67
- ```
61
+ After each round decision, emit a `peer` event to the cycle event stream. The v3 runner writes events natively; do not call the retired bash helper `_loop_event`.
68
62
 
69
63
  If information is insufficient:
70
64
  ```
@@ -61,16 +61,6 @@
61
61
  "ask another agent for peer negotiation"
62
62
  ]
63
63
  },
64
- "roll-brief": {
65
- "positive": [
66
- "prepare an owner-facing digest of completed and in-progress Roll work",
67
- "summarize backlog queue, escalations, and release readiness"
68
- ],
69
- "negative": [
70
- "write public release notes for users",
71
- "capture a one-line idea into backlog"
72
- ]
73
- },
74
64
  "roll-build": {
75
65
  "positive": [
76
66
  "execute US-AUTH-001 through TCR and verification",
@@ -211,16 +201,6 @@
211
201
  "run attacker and defender agents for high-risk logic"
212
202
  ]
213
203
  },
214
- "roll-sentinel": {
215
- "positive": [
216
- "sample production behavior against backlog requirements",
217
- "run cost-controlled patrol checks on deployed flows"
218
- ],
219
- "negative": [
220
- "scan code architecture for refactor candidates",
221
- "debug a local browser page with console capture"
222
- ]
223
- },
224
204
  "roll-spar": {
225
205
  "positive": [
226
206
  "use adversarial TDD for auth or payment logic",
@@ -1,207 +0,0 @@
1
- ---
2
- name: roll-brief
3
- license: MIT
4
- allowed-tools: "Read, Glob, Grep, Write, Bash(git:*)"
5
- description: "Load when the owner asks for an internal Roll briefing summarizing completed work, in-progress items, backlog queue, escalations, and release readiness."
6
- ---
7
- # Roll Brief
8
-
9
- ## Gotchas
10
-
11
- - Brief is owner-facing internal context, not public changelog copy.
12
- - Call out escalations and release readiness explicitly; do not flatten them into a generic progress summary.
13
-
14
- > Follows the Architecture Constraints, Development Discipline, and Engineering
15
- > Common Sense defined in the project AGENTS.md.
16
-
17
- Owner-facing digest of autonomous agent activity. Gives the human everything
18
- needed to decide whether to cut a new release — without having to read every
19
- commit or diff.
20
-
21
- ## Distinct from roll-.changelog
22
-
23
- | | roll-brief | roll-.changelog |
24
- |--|-----------|----------------|
25
- | **Audience** | Product owner (internal) | End users (public) |
26
- | **Content** | All activity including REFACTOR, escalations, health signals | Only user-visible feature changes |
27
- | **Trigger** | Feature completion / daily / on-demand | Post-deploy |
28
- | **Tone** | Operational, candid | Product-facing, polished |
29
-
30
- ## Trigger Modes
31
-
32
- ### 1. Feature Completion (auto)
33
-
34
- Triggered by `roll-loop` when a set of related Stories under one Feature are
35
- all marked ✅ Done. The loop passes the Feature name as context.
36
-
37
- ### 2. Daily Morning (scheduled)
38
-
39
- Runs at a fixed time each morning (configurable in `~/.roll/config.yaml`).
40
- Covers all activity since the previous brief.
41
-
42
- ```yaml
43
- # ~/.roll/config.yaml
44
- brief:
45
- daily_time: "08:00" # local time
46
- timezone: "Asia/Shanghai"
47
- ```
48
-
49
- ### 3. On-Demand
50
-
51
- ```bash
52
- $roll-brief # since last brief
53
- $roll-brief --since 2026-05-09 # since specific date
54
- $roll-brief --feature auth # scoped to one feature
55
- ```
56
-
57
- ## Workflow
58
-
59
- ### Step 1 — Determine Scope
60
-
61
- ```bash
62
- # Find timestamp of last brief
63
- ls .roll/briefs/ | sort | tail -1
64
-
65
- # Read .roll/backlog.md — collect all status changes since last brief
66
- # Read git log — commits since last brief timestamp
67
- git log --since="{last_brief_timestamp}" --oneline
68
- ```
69
-
70
- ### Step 2 — Collect Activity
71
-
72
- From .roll/backlog.md and git log, classify all items since last brief:
73
-
74
- - **Completed**: US-XXX ✅, FIX-XXX ✅, REFACTOR-XXX ✅
75
- - **In progress**: items currently 🔨
76
- - **Queue**: items still 📋 Todo (ordered by priority)
77
- - **Dream findings**: any REFACTOR entries added by roll-.dream since last brief
78
- - **Escalations**: any ALERT files in `~/.shared/roll/loop/` or `~/.shared/roll/dream/`
79
- - **Doc coverage**: compute from `guide/en/` and `guide/zh/`:
80
- - EN coverage = number of files in `guide/en/`
81
- - ZH translation rate = files in `guide/zh/` ÷ files in `guide/en/` × 100%
82
-
83
- ### Step 3 — Assess Release Readiness
84
-
85
- A simple heuristic — not a gate, just a signal for the human:
86
-
87
- ```
88
- ✅ Release candidate if:
89
- - No 🔨 in-progress US items
90
- - No open ESCALATE alerts
91
- - CI is green (check latest workflow run)
92
- - No critical REFACTOR entries flagged in last 48h
93
-
94
- ⚠️ Hold if any of the above is false
95
- ```
96
-
97
- ### Step 4 — Write Brief
98
-
99
- 文件命名:`.roll/briefs/YYYY-MM-DD-{NN}.md`,NN 为当日序号(01 起,零填充两位)。
100
- 计算方式:`ls .roll/briefs/YYYY-MM-DD-*.md 2>/dev/null | wc -l`,+1 即为本次序号。
101
-
102
- 全部用中文输出。**省略空 section**(无内容时连标题一起不输出):
103
-
104
- ```markdown
105
- # 简报 {YYYY-MM-DD HH:mm}
106
-
107
- > 触发:{触发原因} | 覆盖:{起止时间范围}
108
-
109
- ## 已完成({N} 项)
110
- | 编号 | 描述 | 类型 |
111
- |----|-------------|------|
112
- | US-XXX | {标题} | 用户故事 |
113
- | FIX-XXX | {标题} | 缺陷修复 |
114
- | REFACTOR-XXX | {标题} | 重构 |
115
-
116
- <!-- 仅当有 🔨 条目时输出 -->
117
- ## 进行中
118
- | 编号 | 描述 |
119
- |----|-------------|
120
- | US-XXX | {标题} — 开始于 {date} |
121
-
122
- <!-- 仅当有 📋 条目时输出 -->
123
- ## 待处理队列({N} 项)
124
- | 编号 | 描述 | 优先级 |
125
- |----|-------------|----------|
126
- | US-XXX | {标题} | 高 |
127
-
128
- <!-- US-AGENT-010: per-agent hit-rate summary (one line). Read the last
129
- window_cycles records of runs.jsonl, group by `agent`, format as
130
- `agents: pi 8/22 (36%) · deepseek 5/8 (63%)`. Sample < 5 → `(n/a)`.
131
- Omit when no records have an agent field (legacy data). -->
132
- ## Agent 路由命中率
133
- {agents: <name> built/total (pct%) · …} ← from `runs.jsonl` last 50 cycles
134
-
135
- <!-- 仅当 roll-.dream 有新发现时输出 -->
136
- ## 悟见
137
- {来自 .roll/dream/ 的摘要}
138
-
139
- <!-- 仅当有 ESCALATE 告警时输出 -->
140
- ## 需人工介入
141
- {告警内容}
142
-
143
- <!-- 始终输出 doc coverage 数字;若无缺口写"覆盖完整" -->
144
- ## 文档覆盖度
145
- - guide/en: {N} 个文档
146
- - ZH 翻译率:{M}/{N}({%})
147
- - {缺口列表 或 "覆盖完整,无缺口。"}
148
-
149
- ## 发版就绪
150
- {✅ 可发版 / ⚠️ 暂缓 — 原因}
151
-
152
- **下一版本:** `v{YYYY}.{MMDD}.{序号}`
153
-
154
- - {本轮新增 1}
155
- - {本轮新增 2}
156
-
157
- ---
158
- *状态:进行中 {N} · 待处理 {N} · 告警 {N} | 下次简报:{datetime}*
159
- ```
160
-
161
- **首份简报或传入 `--full-history`**:在"已完成"表格后追加历史汇总区块:
162
-
163
- ```markdown
164
- ### 历史汇总
165
- **Epic: {Name}** — {done}/{total} ✅
166
- ```
167
-
168
- ### Step 4.5 — Commit Brief
169
-
170
- 写完文件后立即提交,让简报进入 git 历史,便于后续追溯与跨会话审计:
171
-
172
- ```bash
173
- git add .roll/briefs/YYYY-MM-DD-NN.md
174
- git commit -m "docs: roll-brief YYYY-MM-DD-NN — {触发原因}"
175
- git push origin main
176
- ```
177
-
178
- - 触发原因来自调用上下文(Feature 完成 / 每日 / 手动 / `--feature` / `--since`),用一句话填入
179
- - 写文件失败时不要执行 commit;保持工作区干净,由调用方处理重试
180
- - 仅 `.roll/briefs/` 下新文件入 commit,不要顺带带入其他无关变更
181
-
182
- ### Step 5 — Notify
183
-
184
- 写完文件后在终端或 CI 日志中打印简报路径:
185
-
186
- ```
187
- 📋 $(msg brief.generated ".roll/briefs/YYYY-MM-DD-NN.md")
188
- $(msg brief.release_readiness): ✅ $(msg brief.release_ready_status)
189
- ```
190
-
191
- 有升级事项时须显著打印,不得遗漏。
192
-
193
- ## Scheduler Configuration
194
-
195
- roll-brief runs **locally**, triggered either by roll-loop (on Feature
196
- completion) or by local cron (daily morning). The agent reads local
197
- BACKLOG state and git history directly.
198
-
199
- ### Local cron (daily morning)
200
-
201
- Installed automatically via `roll loop on` alongside roll-loop and roll-.dream.
202
- The cron entry is generated using the configured agent — no manual cron editing needed.
203
-
204
- ### Triggered by roll-loop
205
-
206
- When roll-loop detects a Feature is fully complete, it invokes roll-brief
207
- automatically — no separate cron entry needed for that trigger.
@@ -1,46 +0,0 @@
1
- ---
2
- name: roll-sentinel
3
- license: MIT
4
- allowed-tools: "Read, Edit, Write, Bash, WebFetch"
5
- description: "Load when production or deployed behavior needs cost-controlled randomized patrol checks based on backlog requirements and runtime sampling."
6
- ---
7
- # Roll Sentinel
8
-
9
- This hub keeps the routing boundary, hard gates, and execution skeleton in the initial context. Load the heavier runbook only when the task actually needs the detailed contract.
10
-
11
- ## Load
12
-
13
- Load when production or deployed behavior needs cost-controlled randomized patrol checks based on backlog requirements and runtime sampling.
14
-
15
- ## When Not to Use
16
-
17
- - Code health scans; load roll-.dream.
18
- - Interactive page debugging; load roll-debug.
19
-
20
- ## Read On Demand
21
-
22
- - Read [the full contract](references/full-contract.md) before executing the workflow end to end, recovering from failures, or checking exact output templates.
23
- - Keep this hub in context for trigger boundaries and hard gates.
24
-
25
- ## Workflow Skeleton
26
-
27
- 1. Select sampling targets from backlog requirements.
28
- 2. Run randomized cost-controlled checks.
29
- 3. Validate observed production behavior.
30
- 4. Record patrol evidence and escalate anomalies.
31
-
32
- ## Hard Gates
33
-
34
- - Sampling budget remains explicit.
35
- - Do not turn sentinel into exhaustive monitoring.
36
-
37
- ## Gotchas
38
-
39
- - Sentinel samples deployed behavior; it is not a code architecture scanner.
40
- - Keep cost controls and randomized sampling visible; do not turn patrols into exhaustive monitoring.
41
-
42
- ## Maintenance
43
-
44
- - Description changes require updates in `route-cases/skills.json`.
45
- - New observed failures should add a gotcha and the matching positive or negative route case.
46
- - Heavy examples, templates, recovery paths, and deterministic snippets belong in `references/`, `assets/`, or `scripts/`, not in this hub.