@seanyao/roll 4.630.2 → 4.702.2

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.
Files changed (108) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/README.md +65 -56
  3. package/conventions/global/AGENTS.md +8 -7
  4. package/dist/roll.mjs +12909 -8532
  5. package/docs/INDEX.md +32 -0
  6. package/docs/architecture.md +444 -0
  7. package/docs/difftest-freeze-paradigm.md +113 -0
  8. package/docs/live-console.md +203 -0
  9. package/docs/manifesto.md +65 -0
  10. package/docs/migration/role-taxonomy-v4.md +60 -0
  11. package/docs/verification.md +83 -0
  12. package/guide/INDEX.md +86 -0
  13. package/guide/assets/layouts/cards-2.png +0 -0
  14. package/guide/assets/layouts/cards-3.png +0 -0
  15. package/guide/assets/layouts/cards-4.png +0 -0
  16. package/guide/assets/layouts/compare.png +0 -0
  17. package/guide/assets/layouts/highlight.png +0 -0
  18. package/guide/assets/layouts/pipeline.png +0 -0
  19. package/guide/assets/layouts/plain.png +0 -0
  20. package/guide/assets/layouts/quote.png +0 -0
  21. package/guide/assets/layouts/timeline.png +0 -0
  22. package/guide/en/acceptance-evidence.md +231 -0
  23. package/guide/en/ai-agents.md +185 -0
  24. package/guide/en/backlog-github-sync.md +108 -0
  25. package/guide/en/changelog.md +66 -0
  26. package/guide/en/configuration.md +112 -0
  27. package/guide/en/consistency.md +58 -0
  28. package/guide/en/conventions.md +113 -0
  29. package/guide/en/dream.md +121 -0
  30. package/guide/en/faq.md +855 -0
  31. package/guide/en/feedback.md +31 -0
  32. package/guide/en/getting-started.md +103 -0
  33. package/guide/en/installation.md +86 -0
  34. package/guide/en/legacy-onboarding.md +195 -0
  35. package/guide/en/loop-data-layout.md +256 -0
  36. package/guide/en/loop-driven-architecture.md +186 -0
  37. package/guide/en/loop.md +1324 -0
  38. package/guide/en/methodology.md +715 -0
  39. package/guide/en/migration-2.0.md +154 -0
  40. package/guide/en/overview.md +190 -0
  41. package/guide/en/pairing.md +151 -0
  42. package/guide/en/patterns/README.md +76 -0
  43. package/guide/en/patterns/graft-pattern.md +110 -0
  44. package/guide/en/patterns/replant-pattern.md +114 -0
  45. package/guide/en/patterns/seed-pattern.md +132 -0
  46. package/guide/en/peer.md +71 -0
  47. package/guide/en/pr-review.md +62 -0
  48. package/guide/en/practices/engineering-common-sense.md +395 -0
  49. package/guide/en/pricing.md +116 -0
  50. package/guide/en/project-setup.md +126 -0
  51. package/guide/en/roll-doc-audit.md +98 -0
  52. package/guide/en/skills.md +206 -0
  53. package/guide/en/test-isolation.md +51 -0
  54. package/guide/en/testing/quality-rubric.md +340 -0
  55. package/guide/en/testing.md +123 -0
  56. package/guide/en/tools.md +173 -0
  57. package/guide/skills.md +30 -0
  58. package/guide/zh/acceptance-evidence.md +194 -0
  59. package/guide/zh/ai-agents.md +170 -0
  60. package/guide/zh/backlog-github-sync.md +105 -0
  61. package/guide/zh/changelog.md +57 -0
  62. package/guide/zh/configuration.md +99 -0
  63. package/guide/zh/consistency.md +48 -0
  64. package/guide/zh/conventions.md +96 -0
  65. package/guide/zh/dream.md +97 -0
  66. package/guide/zh/faq.md +773 -0
  67. package/guide/zh/feedback.md +30 -0
  68. package/guide/zh/getting-started.md +96 -0
  69. package/guide/zh/installation.md +83 -0
  70. package/guide/zh/legacy-onboarding.md +192 -0
  71. package/guide/zh/loop-data-layout.md +236 -0
  72. package/guide/zh/loop-driven-architecture.md +186 -0
  73. package/guide/zh/loop.md +1124 -0
  74. package/guide/zh/methodology.md +702 -0
  75. package/guide/zh/migration-2.0.md +154 -0
  76. package/guide/zh/overview.md +186 -0
  77. package/guide/zh/pairing.md +117 -0
  78. package/guide/zh/patterns/README.md +74 -0
  79. package/guide/zh/patterns/graft-pattern.md +108 -0
  80. package/guide/zh/patterns/replant-pattern.md +112 -0
  81. package/guide/zh/patterns/seed-pattern.md +130 -0
  82. package/guide/zh/peer.md +63 -0
  83. package/guide/zh/pr-review.md +54 -0
  84. package/guide/zh/practices/engineering-common-sense.md +393 -0
  85. package/guide/zh/pricing.md +97 -0
  86. package/guide/zh/project-setup.md +114 -0
  87. package/guide/zh/roll-doc-audit.md +90 -0
  88. package/guide/zh/skills.md +191 -0
  89. package/guide/zh/test-isolation.md +46 -0
  90. package/guide/zh/testing/quality-rubric.md +284 -0
  91. package/guide/zh/testing.md +116 -0
  92. package/guide/zh/tools.md +173 -0
  93. package/package.json +4 -1
  94. package/skills/README.md +1 -0
  95. package/skills/roll-.qa/SKILL.md +1 -1
  96. package/skills/roll-.review/SKILL.md +1 -1
  97. package/skills/roll-build/SKILL.md +1 -1
  98. package/skills/roll-build/references/full-contract.md +16 -13
  99. package/skills/roll-design/SKILL.md +3 -3
  100. package/skills/roll-design/references/full-contract.md +17 -13
  101. package/skills/roll-fix/SKILL.md +1 -1
  102. package/skills/roll-fix/references/full-contract.md +13 -10
  103. package/skills/roll-peer/SKILL.md +1 -1
  104. package/skills/roll-prime/SKILL.md +77 -0
  105. package/skills/roll-prime/references/explorer-annex.md +39 -0
  106. package/skills/roll-prime/references/supervisor-prompt.md +165 -0
  107. package/skills/route-cases/skills.json +10 -0
  108. package/template/AGENTS.md +3 -1
@@ -0,0 +1,1324 @@
1
+ # roll loop — Autonomous BACKLOG Executor
2
+
3
+ `roll loop` schedules and manages the autonomous execution of BACKLOG stories.
4
+ When enabled, it wakes up on a configurable schedule (within your active
5
+ window), picks the top pending story, and executes it — committing changes in
6
+ TCR micro-steps.
7
+
8
+ `roll loop on` is the explicit switch into **autonomous** mode. `roll loop off`
9
+ or `roll loop pause` returns the project to **guided** operation, where the
10
+ owner asks `roll supervisor next/why` and starts any long-running Story work
11
+ explicitly. `roll loop resume` switches back to autonomous without changing
12
+ agent bindings.
13
+
14
+ ## How It Works
15
+
16
+ 1. Reads `BACKLOG.md`, picks the highest-priority `📋 Todo` item.
17
+ 2. Marks it `🔨 In Progress` and commits.
18
+ 3. Invokes `$roll-build <story-id>` or `$roll-fix <bug-id>`.
19
+ 4. On success: marks `✅ Done`, commits, appends to `runs.jsonl`.
20
+ 5. On failure: reverts to `📋 Todo`, writes an `ALERT.md` entry.
21
+
22
+ Loop runs inside a **tmux session** named `roll-loop-<project-slug>`.
23
+ When not muted, a terminal window pops up automatically so you can watch in real time.
24
+
25
+ ## Scheduling
26
+
27
+ Loop is scheduled via **launchd** (macOS). By default, every hour at a
28
+ project-derived minute (different projects get different offsets to avoid
29
+ collisions).
30
+
31
+ ```
32
+ Active window: 0–24 (always on — the shipped default)
33
+ ```
34
+
35
+ By default the active window is the full day (`loop_active_start=0`,
36
+ `loop_active_end=24`), so loop fires on every scheduled tick. Narrow it to a
37
+ working window with `roll config loop-window` — e.g. `roll config loop-window
38
+ 10-18` for 10am – 6pm. Outside the configured window, loop silently exits
39
+ without doing anything.
40
+
41
+ ## Configuring the schedule
42
+
43
+ Instead of hand-editing `~/.roll/config.yaml` and `.roll/local.yaml` and then
44
+ hoping the launchd plist picks up your change, use the `roll config` command
45
+ family. Each write lands in the right yaml file **and** automatically
46
+ regenerates the runner, re-bootstraps the launchd plist, and is reflected
47
+ immediately by `roll loop status` — no manual reload step.
48
+
49
+ | Command | What it sets |
50
+ |---------|--------------|
51
+ | `roll config loop-window <start>-<end>` | loop active window hours (`loop_active_start` + `loop_active_end`) |
52
+ | `roll config loop-schedule <period>[/<offset>]` | fire interval (`loop_schedule.period_minutes` + `offset_minute`) |
53
+ | `roll config dream-time <HH:MM>` | dream daily fire time (`loop_dream_hour` + `loop_dream_minute`) |
54
+
55
+ ```bash
56
+ roll config loop-window 9-18 # active 9am – 6pm; start < end, both in [0,24]
57
+ roll config loop-schedule 30 # fire every 30 minutes (period in [1,1440])
58
+ roll config loop-schedule 30/7 # every 30 minutes, offset :07 (offset in [0, period-1])
59
+ roll config dream-time 03:20 # dream fires at exactly 03:20; HH in [0,23], MM in [0,59]
60
+ ```
61
+
62
+ **Reading the current value.** Run any facade with no value to print the
63
+ effective combination and where it comes from:
64
+
65
+ ```bash
66
+ roll config loop-window # loop-window: 0-24 (from default)
67
+ roll config dream-time # dream-time: 03:20 (from ~/.roll/config.yaml)
68
+ ```
69
+
70
+ **Range validation.** Out-of-range or non-numeric input is rejected with a
71
+ locale-selected error and exit code 2. For example, with `ROLL_LANG=en`,
72
+ `roll config loop-window 9-25` prints `loop-window end must be <= 24`.
73
+
74
+ **`--global` vs `--project`.** Writes default to `--project` (`.roll/local.yaml`,
75
+ this project only). Pass `--global` to write `~/.roll/config.yaml` as the
76
+ default for every project that has no project-level override.
77
+
78
+ ```bash
79
+ roll config dream-time 03:20 # this project (.roll/local.yaml)
80
+ roll config dream-time 03:20 --global # all projects (~/.roll/config.yaml)
81
+ ```
82
+
83
+ **Auto-reload.** After writing a schedule key, `roll config` re-installs the
84
+ launchd plists for loop / pr / dream so the change fires on the next
85
+ window. If reload fails (e.g. in a sandbox), the yaml is still the source of
86
+ truth — run `roll loop on` to apply it by hand. See `roll config --help` for
87
+ the full key list and ranges.
88
+
89
+ ### Per-project frequency
90
+
91
+ Set the fire interval with one command:
92
+
93
+ ```bash
94
+ roll config loop-schedule 30 # every 30 minutes (period 1–1440, any interval)
95
+ roll config loop-schedule 45 # every 45 minutes (no longer restricted to divisors of 60)
96
+ ```
97
+
98
+ This writes a `loop_schedule` block to `.roll/local.yaml`:
99
+
100
+ ```yaml
101
+ loop_schedule:
102
+ period_minutes: 30 # 1-1440 (any minute interval)
103
+ offset_minute: 7 # 0–(period-1) (deprecated; for backward compat only)
104
+ ```
105
+
106
+ - `period_minutes` — how often loop fires. Any value 1–1440.
107
+ - `offset_minute` — (deprecated since US-LOOP-032) no longer affects timing.
108
+ Kept for backward compat.
109
+
110
+ If no `.roll/local.yaml` or no `loop_schedule` block is present, Roll falls
111
+ back to the global value (set with `roll config loop-schedule … --global`), or
112
+ derives a per-project default from the project path hash.
113
+
114
+ `roll loop status` and `roll loop on` display the actual schedule frequency
115
+ so you can verify it at a glance. An invalid value (e.g. `period_minutes: 0` or
116
+ `1441`) is rejected at write time with exit code 2.
117
+
118
+ ### Global defaults (backward-compatible)
119
+
120
+ For a single global default across all projects, write with `--global`:
121
+
122
+ ```bash
123
+ roll config loop-window 10-18 --global # active window for every project
124
+ roll config loop-schedule 60 --global # default interval for every project
125
+ ```
126
+
127
+ (Agent selection is no longer a global config key. It is resolved from Machine
128
+ Scope and Project Scope agent files. See [Autonomous Role Resolution](#autonomous-role-resolution).)
129
+
130
+ Project-level `.roll/local.yaml` always takes priority over the global default.
131
+
132
+ ## Subcommands
133
+
134
+ ```bash
135
+ roll loop on # Install launchd scheduler (loop + pr + dream)
136
+ roll loop off # Remove launchd scheduler
137
+
138
+ roll loop now # Run one cycle immediately (same as launchd fires)
139
+ roll loop test # Quick smoke test: verify tmux/popup/stream chain works
140
+
141
+ roll loop status # Show scheduler state and current loop state
142
+ roll loop watch # Default owner view: phase, quiet time, TCR count, last signal, plus live activity
143
+ roll loop watch -n 50 # Look back 50 lines before following (default 200; 'all' = whole log)
144
+ roll loop watch --events # Compact developer event stream from .roll/loop/events.ndjson
145
+ roll loop watch --raw-events # Raw JSON event stream for audit/debug only
146
+ roll loop watch --verbose # Also show the raw agent transcript (default folds it away)
147
+ roll loop watch --attach # Read-only attach to the loop's tmux observe window (tmux attach -r)
148
+ roll loop go # Run goal mode manually for all backlog until complete/pause/guardrail
149
+ roll loop go --epic <name> # Limit the goal to one epic
150
+ roll loop go --cards US-1,FIX-2 # Limit the goal to selected cards
151
+ roll loop go --budget 10 # Stop conservatively when goal cost reaches $10
152
+ roll loop go --usage-threshold 0.85 # Pause when five-hour or weekly usage reaches this ratio
153
+ roll loop go --no-wait # On usage limit, pause and return instead of waiting for reset
154
+ roll loop go --for 5h # Stop after the current cycle once the timebox is reached
155
+ roll loop go --max-cycles 3 # Stop after this many cycles
156
+ roll loop go --review <auto|hetero|self|off> # Set the final review policy
157
+ roll loop goal # Show persisted goal status, scope, review mode, usage, limits, and safety gate
158
+
159
+ roll loop runs # Show last 10 run summaries (story IDs, TCR count, duration, slowest phase)
160
+ roll loop runs 20 # Show last 20 runs
161
+ roll loop runs --all # Show all projects' run history
162
+ roll loop runs --detail <cycle_id> # Phase Breakdown panel for a single cycle
163
+
164
+ roll loop story <ID> # Per-story rollup: cycles, span, duration, tokens, cost, PRs
165
+ roll loop story <ID> --json # Machine-readable form for scripting
166
+
167
+ roll loop eval # Objective result-eval trend over the last 14 scored cycles
168
+ roll loop eval 30 # Widen the window to the last 30 scored cycles
169
+ roll loop signals # Surface repeated low-score patterns as improvement signals
170
+ roll loop signals --streak 4 # Require 4 consecutive low cycles before firing
171
+
172
+ roll loop watch # Recommended daily live view
173
+ tmux attach -t roll-loop-<project-slug> # Read-only tmux observe window; use when you want the pane
174
+ roll loop mute # Suppress auto-attach popup (loop still runs in tmux)
175
+ roll loop unmute # Re-enable auto-attach popup
176
+
177
+ roll loop pause # Pause scheduling (keep plist, skip execution)
178
+ roll loop resume # Resume scheduling after pause
179
+
180
+ roll loop reset # Clear loop state (start fresh on next fire)
181
+
182
+ roll loop gc # GC orphan slugs, tmp debris, expired backups (default: keep 30 days)
183
+ roll loop gc --dry-run # Preview what would be removed without deleting
184
+ roll loop gc --keep-days 14 # Override retention (also: loop_gc.retention_days in .roll/local.yaml)
185
+ # See guide/en/loop-data-layout.md for the full gc manual
186
+
187
+ # loop-related branches: `git ls-remote --heads origin 'loop/*'` (the `branches` subcommand is retired)
188
+
189
+ roll loop events # Show last 20 cycle events
190
+ roll loop events 50 # Show last 50 events
191
+
192
+ roll agent # Show scopes, roles, agent pool, and legacy inputs
193
+ roll agent list # Show agents installed on this machine
194
+ ```
195
+
196
+ ### Goal Mode vs Scheduled Mode
197
+
198
+ `roll loop go` is a manual goal session, not a launchd scheduler tick. While it
199
+ runs, Roll holds `.roll/loop/go.lock`; scheduled ticks yield when they see that
200
+ lock, record `goal:tick_skipped`, and do not start another `roll loop run-once`.
201
+
202
+ Goal mode can run when the scheduler is off because it starts its own session
203
+ and does not depend on launchd. For paused projects, run `roll loop resume`
204
+ first: the `PAUSE-<slug>` marker is still respected at cycle boundaries.
205
+
206
+ ### Goal Mode Safety Gates
207
+
208
+ Budget and run limits are explicit per `roll loop go`. `--budget`,
209
+ `--max-cycles`, and `--for` apply to THIS invocation only; omitting one means no
210
+ limit for this run — Roll never silently inherits a budget or cap from a prior
211
+ session's persisted goal, so a flagless `roll loop go` can neither be capped nor
212
+ bricked by a limit you set days ago. Scope (`--epic`/`--cards`) and `--review`
213
+ still persist when unspecified, because they are the goal's identity, not a
214
+ per-run safety knob.
215
+
216
+ `roll loop go` enforces safety only at cycle boundaries. `--budget <usd>` uses
217
+ the effective run cost ledger and moves the goal to `budget_limited` when the
218
+ budget is reached. An idle or aborted cycle that ran no agent counts as a known
219
+ $0, not as an unknown-cost row. Only a row where an agent actually executed but
220
+ left no parseable usage is recorded as unknown; those still stop conservatively
221
+ rather than being counted as zero. Usage headroom is checked against five-hour
222
+ and weekly windows; by default Roll pauses at 85% and waits for the reset
223
+ window, while `--no-wait` leaves the goal paused for the owner. The recovery
224
+ wait is bounded — a hung usage API cannot stall the session forever; on timeout
225
+ Roll records a `usage_wait_timeout` audit event and leaves the goal paused.
226
+ `--for <duration>` is a wall-clock box: the in-flight cycle finishes, then the
227
+ goal pauses with reason `timebox`.
228
+
229
+ Each safety trip records `goal:gate_tripped`, and `roll loop goal` shows the
230
+ last safety gate reading.
231
+
232
+ ### `roll loop goal` Fields
233
+
234
+ `roll loop goal` is the read face for `.roll/loop/goal.yaml` plus the latest
235
+ goal events. The key fields are:
236
+
237
+ | Field | Meaning |
238
+ |-------|---------|
239
+ | `Status` | `active`, `paused`, `budget_limited`, or `complete`. |
240
+ | `Scope` | All backlog, one epic, or an explicit card list. |
241
+ | `Review` | Completion review policy: `auto`, `hetero`, `self`, or `off`. |
242
+ | `Usage` | Goal cycle count, effective cost, and unknown-cost-row count. |
243
+ | `Limits` | Explicit `--budget`, `--max-cycles`, and `--for` settings. |
244
+ | `Safety gate` | The latest budget, usage, or timebox trip and its reading. |
245
+ | `Last decision` | Why the goal continued, paused, became budget-limited, or completed. |
246
+
247
+ When `auto` final review degrades to same-provider review, the status view
248
+ shows the recorded degradation reason from `goal:review_degraded`. When a goal
249
+ cannot complete, `Last decision` carries the unmet truth or review reason.
250
+
251
+ ### Goal Mode Final Review
252
+
253
+ `roll loop go` persists its goal state in `.roll/loop/goal.yaml` and runs a
254
+ final review gate before a goal can become `complete`. The default policy is
255
+ `--review auto`: Roll tries heterogeneous reviewers in ranked order, and records
256
+ `goal:review_degraded` when it must fall back to self review because every
257
+ heterogeneous candidate failed or because only one provider is installed.
258
+
259
+ Final review uses the same structured adapter as `-peer` skill. The
260
+ `goal:final_review` event records reviewer agent, provider, command family,
261
+ verdict, findings, timeout/error state, duration, and transcript/evidence
262
+ paths when available. A transient review crash rotates to the next ranked
263
+ candidate; if every candidate fails Roll records the real error reason on the
264
+ `ERROR` verdict and raises an ALERT, instead of collapsing into a reasonless
265
+ generic error.
266
+
267
+ Use `--review hetero` when completion must fail closed unless a heterogeneous
268
+ reviewer is installed. Use `--review self` to allow same-provider review. Use
269
+ `--review off` only as an explicit operator waiver; Roll skips the gate but
270
+ still records a `goal:final_review` event with `verdict: SKIPPED`.
271
+
272
+ ## Autonomous Role Resolution
273
+
274
+ Loop resolves agents through the scoped Agent model:
275
+
276
+ ```text
277
+ Scope -> Role -> Binding -> Agent -> optional Model
278
+ ```
279
+
280
+ Machine Scope lives in `~/.roll/agents.yaml`; Project Scope lives in
281
+ `.roll/agents.yaml`. A loop cycle resolves `story.execute` for the Builder and
282
+ `story.evaluate` for review/score, using inherited machine declarations when the
283
+ project says `inherits: machine`.
284
+
285
+ ```yaml
286
+ schema: roll-agents/v1
287
+ scope: project
288
+ inherits: machine
289
+ defaults:
290
+ story:
291
+ roles:
292
+ execute:
293
+ kind: select
294
+ from: [kimi, codex, pi]
295
+ require: [execute]
296
+ strategy: first-available
297
+ evaluate:
298
+ kind: select
299
+ from: [claude, codex, kimi, pi, agy, reasonix]
300
+ require: [evaluate]
301
+ strategy: health-aware
302
+ ```
303
+
304
+ `roll agent` shows the effective Machine Scope, Project Scope, resolved roles,
305
+ candidate pool, runtime health notes, and any legacy compatibility inputs. Use
306
+ `roll agent migrate --dry-run` to preview conversion from old agent files.
307
+
308
+ Runtime health is not static policy. Auth, network, VPN, account, or missing
309
+ binary failures skip a candidate for the current resolution and are recorded as
310
+ runtime facts. If no candidate remains, loop pauses and writes an ALERT instead
311
+ of silently rewriting the pool.
312
+
313
+ For open casting, `health-aware` ranks the same visible pool across Builder,
314
+ Designer, Evaluator, and Peer Reviewer roles. `roll supervisor route --role
315
+ builder --story <id> [--json]` exposes the trace: candidates, ranked scores,
316
+ warnings, skipped runtime facts, selected agent, source binding, recent-use
317
+ input, and capability/health ranking.
318
+
319
+ ### Agent toolchain health check (US-V4-022)
320
+
321
+ Before scheduling, Supervisor also classifies agent toolchain health signals
322
+ from the durable event stream. It distinguishes auth blocks, network blocks,
323
+ setup/skill-root pollution, and worktree permission failures. Pollution signals
324
+ are routed to the delta team as a FIX rather than misclassified as auth failures.
325
+ Use `roll supervisor health` for the dedicated board, or read the summary from
326
+ `roll supervisor next` / `roll supervisor why`.
327
+
328
+ ### Agent self-downgrade (too_big verdict)
329
+
330
+ The picked agent runs a **pre-flight self-check** (in `roll-build` / `roll-fix`
331
+ SKILL.md). When it decides the story is over capacity it emits:
332
+
333
+ ```yaml
334
+ verdict: too_big
335
+ reason: est_min=20 > pi.max=8
336
+ ```
337
+
338
+ 并触发 self-downgrade 流程:调 `roll-design --from-story <id>` 把故事拆成
339
+ chain_depth + 1 的子故事写回 BACKLOG,原故事翻 🚫 Hold,cycle 干净退出。
340
+ 下一轮 loop 接力第一个更小的子故事。
341
+
342
+ The chain is capped at **2 auto re-splits**. The third would be refused and a
343
+ `StorySplitCapHit` ALERT is written, forcing human triage instead of letting
344
+ the chain grow indefinitely.
345
+
346
+ ## Execution profiles (standard / verified / designed)
347
+
348
+ Role resolution above chooses the concrete Agent and optional Model for the
349
+ `execute` and `evaluate` roles. Separately, Roll chooses an **execution profile** per
350
+ Story — the cheapest *sufficient* role pipeline for that Story's risk and ROI.
351
+ You do not declare it; it is selected once at cycle start from the story's risk
352
+ signals and recorded in an `execution:profile` event. These are **not
353
+ user-facing "team shapes"** — they are risk/ROI tiers:
354
+
355
+ - **`standard` = execute only** — low-risk, local scope, clear acceptance, low
356
+ evidence risk (a copy fix, a small parser bug, an internal rename).
357
+ - **`verified` = execute → evaluate** — user-visible behavior, screenshot/visual
358
+ evidence required, or a history of weak/missing evidence. An independent
359
+ `evaluate` role (fresh session) judges the delivery; blocking review, score, and
360
+ attest stay three separate dimensions.
361
+ - **`designed` = Designer -> Builder -> Evaluator** — the risk is doing the *wrong*
362
+ work: unclear requirements, cross-module change, or truth/release/routing/state
363
+ semantics. A design artifact is written before `execute`; `evaluate` maps
364
+ design-contract-vs-delivered. evaluate → execute repair rounds are strictly bounded
365
+ (max rounds, repeated-finding signature, budget, timeout) and escalate on a
366
+ bound trip.
367
+
368
+ Roles hand off through artifacts only (design contract, builder evidence,
369
+ eval-report) — never a shared raw session. Project-level coordination across
370
+ Stories (ordering, conflicts, budget, release readiness) belongs to the
371
+ **Supervisor** (`roll supervisor`), not to any single Story's execution.
372
+
373
+ When the owner asks to clear the backlog, Supervisor uses a backlog-clearing
374
+ standard rather than a fix-only queue. The default scope is every live non-Hold
375
+ `FIX-*`, `US-*`, and `REFACTOR-*` row. Before starting another card it reconciles
376
+ backlog truth, open PRs, CI/evaluator gates, recent cycle endings, manual-merge
377
+ PRs, and `.roll` meta state. Each card gets a fresh Builder and, when its
378
+ execution profile requires it, an independent Evaluator/Scorer from the current
379
+ Agent roster. Repeated failure, zero TCR, missing evidence, parser failure,
380
+ auth/permission blocks, or `[roll:manual-merge]` PRs stop scheduling until the
381
+ owner action shown by `roll supervisor status/next/why` is resolved.
382
+
383
+ ## Cycle Role Visibility
384
+
385
+ A v4 cycle is a multi-agent collaboration: a Builder writes the code, one or
386
+ more Peer Reviewers re-check the risky diff, an Evaluator/Scorer judges the
387
+ delivery, and the Attest Gate decides whether the result is admissible. The
388
+ underlying truth lives in `events.ndjson` and the peer/evidence artifacts, but
389
+ you should never have to grep those by hand to answer the first-run question:
390
+ **who was Builder and who was Evaluator?**
391
+
392
+ Three surfaces answer that question.
393
+
394
+ ### `roll loop cycle <id> --roles`
395
+
396
+ ```bash
397
+ roll loop cycle <id> --roles # human-readable execution cast for one cycle
398
+ roll loop cycle <id> --roles --json # the same facts as cycle-role-summary.v1 JSON
399
+ ```
400
+
401
+ The roles view renders the full role chain — Builder, Peer Review,
402
+ Evaluator / Score, and Gates — for a single cycle:
403
+
404
+ ```text
405
+ # Cycle Role Summary — 20260629-112437-39253
406
+
407
+ Story: US-TASK-001
408
+ Execution profile: standard
409
+
410
+ ## Builder
411
+ - pi / deepseek-v4-pro
412
+ - log: .roll/loop/cycle-logs/20260629-112437-39253.agent.log
413
+
414
+ ## Peer Review
415
+ - reasonix: accepted verdict=refine findings=0
416
+ - kimi: returned reviewed, no structured verdict accepted
417
+ - codex: returned reviewed, no structured verdict accepted
418
+
419
+ ## Evaluator / Score
420
+ - reasonix: accepted score=10 verdict=good
421
+ - agy: failed unparseable (control characters before SCORE)
422
+ - kimi: selected, no accepted score
423
+
424
+ ## Gates
425
+ - peer: consulted
426
+ - attest: produced
427
+ ```
428
+
429
+ The command reads the cached summary artifact first and rebuilds from
430
+ `events.ndjson` when it is missing or corrupt, so it works for both fresh and
431
+ archived cycles.
432
+
433
+ ### The `summary.md` / `summary.json` artifacts
434
+
435
+ Every cycle writes the same role cast to disk so a delivery report or a teammate
436
+ can read it without re-running the CLI:
437
+
438
+ ```text
439
+ .roll/loop/cycle-logs/<cycle-id>/summary.md # the markdown shown above
440
+ .roll/loop/cycle-logs/<cycle-id>/summary.json # cycle-role-summary.v1, machine-readable
441
+ ```
442
+
443
+ `summary.json` carries one `CycleRoleAttempt` per agent participation, each with
444
+ its role, agent, model, session id, stage, state, and (when relevant) verdict,
445
+ score, findings, parse-failure cause, and artifact path.
446
+
447
+ ### The Execution Cast report block
448
+
449
+ The story attest report embeds an **Execution Cast** block (🎭) that projects
450
+ the same summary into the delivery view, so the role chain travels with the
451
+ evidence. When no role summary exists the block degrades gracefully to "Role
452
+ summary unavailable". Accepted artifacts are linked directly — e.g. the
453
+ `accepted evaluator artifact` link points at the scorer output the gate actually
454
+ used.
455
+
456
+ ### Selected vs returned vs accepted
457
+
458
+ The per-agent `state` is the key to reading the cast correctly. The states form
459
+ a ladder, and **being selected or returning output is not the same as being
460
+ accepted by the gate**:
461
+
462
+ | State | Meaning |
463
+ |-------|---------|
464
+ | `selected` | The agent was chosen for the stage but produced no accepted result. |
465
+ | `started` | The agent began the stage. |
466
+ | `returned` | The reviewer returned output, but no structured verdict was accepted. |
467
+ | `parsed` | Structured output was parsed. |
468
+ | `accepted` | The gate accepted this attempt — the verdict/score that counts. |
469
+ | `rejected` / `failed` | Rejected, errored, or produced unparseable output. |
470
+ | `not_required` / `not_available` | The role was not needed (e.g. `standard` profile) or had no candidate. |
471
+
472
+ **Only one evaluator/scorer is gate-accepted, even when several agents were
473
+ consulted.** A cycle may select reasonix, kimi, and codex for review and ask
474
+ reasonix and agy to score, but exactly one score is `accepted` and stamped into
475
+ the Attest Gate. The others show as `returned`, `selected`, or `failed` — they
476
+ are recorded for transparency, not because they all gate the delivery. When you
477
+ need the verdict that actually decided the cycle, read the `accepted` row (and
478
+ the `accepted evaluator` artifact link), not whichever agent happens to be
479
+ listed first.
480
+
481
+ When a reviewer or scorer produced unparseable output, its row is `failed` with
482
+ a `cause` (e.g. `unparseable`) and a `raw artifact:` pointer to the captured
483
+ attempt under `.roll/loop/peer/` — see
484
+ [Troubleshooting unparseable score/review](../../docs/live-console.md#故障排查).
485
+
486
+ ## Collaboration View
487
+
488
+ US-OBS-032 writes the role cast (`summary.md` / `summary.json`), US-OBS-033
489
+ exposes that cast with `roll loop cycle <id> --roles`, and the collaboration view is
490
+ the upper layer over CycleRoleSummary. It turns the same facts into a protocol
491
+ relay: who designed, who built, who reviewed, who evaluated, and where the
492
+ baton ended.
493
+
494
+ Use these entry points:
495
+
496
+ ```bash
497
+ roll loop cycle <id> --collab # one cycle as a protocol relay
498
+ roll loop cycle <id> --collab --json # collab-view.v1 JSON
499
+ roll supervisor live --collab # live multi-cycle collaboration stream
500
+ roll supervisor live --collab --once
501
+ roll loop cycle --legend # Layer A protocol legend
502
+ ```
503
+
504
+ Read the protocol as:
505
+
506
+ ```text
507
+ Supervisor/Designer -> Builder -> independent Peer Reviewer/Evaluator -> Gate
508
+ ```
509
+
510
+ The Supervisor can intervene at three levels. `observe/advise` means the
511
+ Supervisor is watching, asking for evidence, or routing owner attention without
512
+ changing the Builder's work. `design/split` means the Supervisor turns unclear
513
+ scope into a design artifact or smaller follow-up actions. `Builder override`
514
+ is explicit and exceptional: the Supervisor chooses or replaces the Builder
515
+ binding, and that decision must remain visible in the cast.
516
+
517
+ Role independence is session-based, not brand-based: separate fresh sessions
518
+ and artifact handoff are the rule. The same agent brand can serve more than
519
+ one role only when each role runs in its own session and hands off through
520
+ artifacts: a design contract, diff, review, score, AC map, or report.
521
+ A shared transcript is not an independent review. Agent diversity is useful
522
+ evidence and a ranking signal, especially when capability or shortcoming
523
+ profiles are visible in role summaries, but it is not a default hard exclusion
524
+ rule; capability, availability, and the required role contract still decide.
525
+
526
+ `handoff`, `escalation`, and `terminus` are separate reading keys. A handoff is
527
+ the normal baton pass between roles, such as Builder -> Peer Reviewer with a diff and evidence.
528
+ Escalation is a visible break in the normal path: the Supervisor, Gate, or owner
529
+ needs attention because the ordinary relay could not finish cleanly. The
530
+ `terminus` says where the baton ended, not whether the Story passed or failed:
531
+ `walked_full`, `escalated`, `split`, and `supervisor_fix` describe the relay's
532
+ ending point. Use the Gate and attest result for pass/fail.
533
+
534
+ ## Status Dashboard
535
+
536
+ `roll loop status` prints a compact dashboard with per-cycle rows and daily rollup totals.
537
+
538
+ ### Token column
539
+
540
+ Each cycle row shows token usage in a 4-component format:
541
+
542
+ ```
543
+ · 19:18 13m 164/498.2K↑ 12.7M↓/63.3K opus-4-7 $11.07 US-VIEW-012
544
+ ↑ in cw↑ cr↓ out
545
+ ```
546
+
547
+ | Segment | Meaning |
548
+ |---------|---------|
549
+ | `164` (before first `/`) | Base input tokens |
550
+ | `498.2K↑` | Cache write tokens (billed at write rate) |
551
+ | `12.7M↓` | Cache read tokens (billed at read rate, much cheaper) |
552
+ | `63.3K` (after last `/`) | Output tokens |
553
+
554
+ When a cycle has no cache data (older cycles or non-Opus models), the column
555
+ falls back to the two-part `in/out` format.
556
+
557
+ **Per-agent coverage.** Token/cost capture depends on a per-agent usage plugin.
558
+
559
+ | Agent | Token/cost in dashboard |
560
+ |-------|-------------------------|
561
+ | Claude | ✅ supported |
562
+ | pi (DeepSeek) | ✅ supported |
563
+ | OpenAI (codex) | ✅ supported |
564
+ | Gemini | ✅ supported |
565
+ | Kimi | ✅ supported |
566
+
567
+ Agents without a plugin fall back to a `—/—` placeholder. Adding a new agent is
568
+ a small per-agent plugin (`lib/agent_usage/<agent>.py`) — it does not happen
569
+ automatically. See `lib/agent_usage/README.md` for the five-step howto.
570
+
571
+ ### Rollup rows
572
+
573
+ Below the cycle list, daily totals break out all four components:
574
+
575
+ ```
576
+ input tokens 164
577
+ cache writes 498.2K
578
+ cache reads 12.7M
579
+ output tokens 63.3K
580
+ ```
581
+
582
+ This lets you verify that the displayed per-cycle cost (e.g. `$11.07`) matches
583
+ your Anthropic invoice — 86 % of the cost in that example comes from cache.
584
+
585
+ ## Per-Story Rollup
586
+
587
+ `roll loop status` shows the rolling window (default 3 days). When you want the
588
+ **full lifetime** of a single story — every cycle that ever ran on it, including
589
+ cycles that have aged out of the dashboard window — use `roll loop story`.
590
+
591
+ ```bash
592
+ roll loop story US-LOOP-004 # Compact panel for one story
593
+ roll loop story us-loop-004 # Case-insensitive
594
+ roll loop story US-LOOP-004 --days 90 # Widen the event-stream lookback
595
+ roll loop story US-LOOP-004 --json # Emit JSON for scripting / dashboards
596
+ ```
597
+
598
+ The panel reports the totals you'd otherwise have to hand-add across multiple
599
+ `status` runs:
600
+
601
+ ```
602
+ ── US-LOOP-004 · 把每轮 cycle 成本/token/耗时写进事件流 ──
603
+ cycles 3 (✓ 2 ✗ 1 ⏵ 0)
604
+ span 2026-05-18 14:22 → 2026-05-19 09:11
605
+ duration 1h 47m tokens in 412k out 18.3k cache w 1.2M r 7.8M
606
+ cost $4.92 model claude-opus-4-7
607
+ PRs #128 ✓ #131 ✓ #134 ✗
608
+ recent 20260518-142233-91 ✓ $2.10
609
+ 20260518-203045-12 ✗ $1.71
610
+ 20260519-091112-44 ✓ $1.11
611
+ ```
612
+
613
+ **How history is preserved:** the loop runner rotates `events-<slug>.ndjson` at 10 MB,
614
+ keeping `.1` … `.4` archives. `roll loop status` and `roll loop story` both read
615
+ the head plus all rotated files, so cycles never disappear once they're on disk.
616
+
617
+ **Exit codes:** `0` when at least one cycle is found, `2` when no cycles match
618
+ the story id in the lookback window. The `--json` form follows the same exit
619
+ code contract so scripts can detect missing data.
620
+
621
+ ## Cycle Result Eval
622
+
623
+ Every cycle is scored *objectively* at finish against a fixed multi-dimensional
624
+ rubric, with **zero extra tokens** — the score is computed from facts the loop
625
+ already has (merge state, CI verdict, TCR count, duration, alerts, orphans). The
626
+ result is written into that cycle's `runs.jsonl` record under a `result_eval`
627
+ block:
628
+
629
+ ```json
630
+ { "version": 1, "score": 8, "dims": { "outcome": 1.0, "correctness": 1.0,
631
+ "scope_fidelity": 1.0, "quality": 1.0, "efficiency": 0.6, "cleanliness": 1.0 } }
632
+ ```
633
+
634
+ > **Result-eval is NOT skill self-scoring.** Skill self-scoring (the agent's
635
+ > *subjective* review of one skill run, written into `.roll/notes/*.md`) and
636
+ > result-eval (this *objective* per-cycle result score, computed from facts) are
637
+ > two different signals. They are reported on separate dashboard lines and never
638
+ > merged.
639
+
640
+ ### The rubric (six dimensions)
641
+
642
+ Each dimension is scored on `0.0`–`1.0`, or `unknown` when its facts are absent.
643
+ Unknown dimensions are excluded from the roll-up and the remaining weights are
644
+ renormalised, so a missing fact never silently scores `0`.
645
+
646
+ | Dimension | Weight | Meaning | 1.0 when… |
647
+ |-----------|--------|---------|-----------|
648
+ | `outcome` | 3 | Did the cycle merge into `main`? | merged · `0.0` not merged |
649
+ | `correctness` | 2 | Is the produced PR's CI green? | green · `0.0` red |
650
+ | `scope_fidelity` | 2 | Did it complete the story it was routed to? | completed · `0.0` idle / off-scope |
651
+ | `quality` | 1 | Tests added, no immediate rework? | TCR ≥ 1, no rework FIX · `0.5` rework landed · `0.0` no tests |
652
+ | `efficiency` | 1 | Duration vs the story's `est_min` budget | within budget · grades down past it |
653
+ | `cleanliness` | 1 | No orphan worktrees/branches and no ALERTs | clean · `0.0` orphans / alerts |
654
+
655
+ The dimensions roll up into a single **1–10 cycle score**:
656
+
657
+ ```
658
+ weighted = Σ(score_i × weight_i for known dims) / Σ(weight_i for known dims)
659
+ cycle_score = round(1 + weighted × 9) # 0.0 → 1, 1.0 → 10
660
+ ```
661
+
662
+ Weights are a centralised constant in `lib/loop_result_eval.py` — tunable there,
663
+ but deliberately not a high-frequency user knob.
664
+
665
+ ### Reading the trend — `roll loop eval [N]`
666
+
667
+ `roll loop eval` aggregates the `result_eval` of the last `N` scored cycles
668
+ (default 14) and prints mean / minimum cycle score, each dimension's hit-rate,
669
+ and a trend arrow. Older records without a `result_eval` block are skipped; with
670
+ fewer than 3 scored cycles it prints an `(n/a) need 3` notice.
671
+
672
+ ```
673
+ $ roll loop eval
674
+ Loop result-eval — last 14 cycles
675
+ 循环结果评分 — 最近 14 轮
676
+
677
+ mean 6.8 / 10 ↓
678
+ min 4 / 10
679
+ n 4
680
+
681
+ dimension hit-rate / 各维度命中率
682
+ outcome 75%
683
+ correctness 67%
684
+ scope_fidelity 75%
685
+ quality 75%
686
+ efficiency 50%
687
+ cleanliness 100%
688
+ ```
689
+
690
+ The `roll loop status` dashboard also carries a one-line result-eval summary,
691
+ shown **separately** from the Review Score line so the two are never
692
+ confused:
693
+
694
+ ```
695
+ result-eval: mean 6.8↓ / min 4 / out 75% ci 67% scope 75% qual 75% eff 50% clean 100% (last 14)
696
+ ```
697
+
698
+ ### Self-evolution signals — `roll loop signals`
699
+
700
+ When a dimension stays low (`0.0`) for `N` cycles in a row (default 3,
701
+ `--streak` to change), the loop surfaces it as an **improvement signal**: it
702
+ appends a *candidate* backlog draft — an `IDEA` or `FIX`, marked `📋 待人确认`
703
+ — to `.roll/signals/candidates.md`, and `roll loop signals` (and the
704
+ `roll loop status` dashboard) reports it. Signals are deduped per pattern, so a
705
+ standing issue is raised once, not every cycle.
706
+
707
+ A signal is advisory only. It never edits the real backlog, never activates a
708
+ story, and never changes code — it only exposes what keeps going wrong so a
709
+ human can decide. The cycle-finish hook runs the detector once per cycle;
710
+ `roll loop signals` runs it on demand.
711
+
712
+ | Dimension stuck low | Surfaced as | Reading |
713
+ |---------------------|-------------|---------|
714
+ | `outcome` | FIX | cycles keep failing to merge into main |
715
+ | `correctness` | FIX | produced PRs keep failing CI |
716
+ | `scope_fidelity` | IDEA | cycles keep going idle or off-scope |
717
+ | `quality` | FIX | cycles keep landing without test activity |
718
+ | `efficiency` | IDEA | cycles keep blowing past their `est_min` budget |
719
+ | `cleanliness` | FIX | cycles keep leaving orphans / raising ALERTs |
720
+
721
+ ## TerminalOutcome vocabulary
722
+
723
+ User-facing cycle projections use TerminalOutcome values, not legacy summary
724
+ text. The stable vocabulary is:
725
+
726
+ `delivered`, `published_pending_merge`, `failed`, `blocked`,
727
+ `aborted_no_delivery`, `aborted_with_delivery`, `orphan_timeout`,
728
+ `idle_no_work`, `unknown`.
729
+
730
+ Older `runs.jsonl` records may contain free-form result strings. Readers
731
+ convert them through the truth adapter before rendering dashboards, archives,
732
+ or summaries.
733
+
734
+ ## Visibility (tmux + popup)
735
+
736
+ Every loop run lives in a detached tmux session.
737
+ When you're not muted, a terminal window opens automatically.
738
+
739
+ Use `roll loop watch` first for daily observation. It combines the live agent
740
+ feed with the structured event stream into a concise status layer. Use
741
+ `roll loop watch --events` when debugging event ordering or phase/TCR facts.
742
+ Use `roll loop watch --raw-events` only when you need the unchanged audit JSON.
743
+ All watch modes are read-only; Ctrl-C stops only the view.
744
+
745
+ ```bash
746
+ roll loop watch # default status layer
747
+ roll loop watch --events # compact events
748
+ roll loop watch --raw-events # raw audit stream
749
+ tmux attach -t roll-loop-<project-slug> # join the running observe pane at any time
750
+ # Ctrl-B D # detach (loop continues)
751
+
752
+ roll loop mute # 🔇 stop popup (mute file: ~/.shared/roll/mute)
753
+ roll loop unmute # 🔔 re-enable popup
754
+ ```
755
+
756
+ The `mute` file is shared across all projects and all autonomous activity
757
+ (loop + peer review). One switch controls everything.
758
+
759
+ ### Environment drift & session lifecycle
760
+
761
+ The tmux session is long-lived, but a cycle's **network environment always
762
+ follows the invoker**, not the session: the proxy family
763
+ (`HTTP_PROXY`/`HTTPS_PROXY`/`ALL_PROXY`/`NO_PROXY` + lowercase) is re-injected
764
+ from the caller every time a cycle window opens. Agent secret env names declared
765
+ by runner profiles, such as Reasonix's `DEEPSEEK_API_KEY`, are also forwarded by
766
+ name; file-backed profile credentials such as `~/.reasonix/.env` are loaded by
767
+ the spawn layer. So turning a local proxy on or off between cycles just works —
768
+ a session created under a proxy that has since died can no longer starve every
769
+ agent into `Connection error` (FIX-230), and env-only agent credentials do not
770
+ depend on the stale tmux session. Each cycle also logs its effective proxy env as
771
+ an `env:` line in `.roll/loop/cron.log`, so an environment-shaped failure is
772
+ readable straight from the log. Other variables still come from the session
773
+ created at `roll loop on` time; if you rotate something exotic, `roll loop off &&
774
+ roll loop on` rebuilds the session fresh.
775
+
776
+ ### Edit fold
777
+
778
+ When the live tmux stream shows the agent editing the same file several times
779
+ in a row, Roll no longer repeats the identical long path on N separate lines
780
+ (which used to look like a hang). Instead it folds consecutive same-file edits
781
+ into a single line and refreshes it in place:
782
+
783
+ ```text
784
+ ✏ <basename> | <hint> ×N
785
+ ```
786
+
787
+ - **Trigger** — two or more *adjacent* `Edit` / `Write` calls targeting the
788
+ same `file_path`. The path is shown as `os.path.basename(file_path)`, never
789
+ the full path. A single edit shows no `×N` counter.
790
+ - **`<hint>`** — a ≤20-char feature derived from the edit input so you can tell
791
+ *what* is changing, not just count:
792
+ - `replace_all=true` → the literal `replace-all`.
793
+ - otherwise the first non-blank token of `new_string`'s first line, with
794
+ leading whitespace and comment markers (`#`, `//`, `/*`, `*`, `--`, `;`)
795
+ stripped.
796
+ - tokens longer than 20 characters are truncated to `token[:20] + "…"`
797
+ (counted by unicode char, so 中文 / emoji are not byte-split).
798
+ - an empty / all-whitespace `new_string` yields no hint, and the ` | <hint>`
799
+ segment is omitted entirely.
800
+ - **Cross-file flush** — switching to a different file (or any other event:
801
+ `Bash`, `Skill`, an error, or cycle end) first flushes the previous file's
802
+ final streak line so it stays in the scrollback, then starts a fresh line for
803
+ the new file. Edits never fold across a non-edit line.
804
+
805
+ Three examples (ANSI-stripped):
806
+
807
+ ```text
808
+ # single edit
809
+ ✏ auth.ts | export
810
+
811
+ # folded ×N (7 edits of the same file)
812
+ ✏ auth.ts | export ×7
813
+
814
+ # cross-file switch — two lines, the first flushed before the second starts
815
+ ✏ auth.ts | export ×3
816
+ ✏ router.ts | replace-all
817
+ ```
818
+
819
+ ## Cycle exit summary
820
+
821
+ When a cycle ends and the tmux session detaches, the macOS `.command` window
822
+ no longer leaves you staring at a bare `press enter to close` line. Just before
823
+ that prompt, the window renders a compact recap block so you can see what the
824
+ cycle did without scrolling back through tmux scrollback or opening the cron
825
+ log:
826
+
827
+ ```text
828
+ ─── Cycle 20260530-2301-94839 Summary ───
829
+ outcome: delivered · story: US-LOOP-040 · tcr commits: 4
830
+ ci: green
831
+ todo remaining: 7
832
+ phases (top 5 by time):
833
+ build 612s
834
+ ci 94s
835
+ pr 31s
836
+ press enter to close.
837
+ ```
838
+
839
+ The summary covers five signals:
840
+
841
+ 1. **Result** — the cycle outcome from `runs.jsonl`, rendered as
842
+ TerminalOutcome in the summary:
843
+ `delivered`, `published_pending_merge`, `failed`, `blocked`,
844
+ `aborted_no_delivery`, `aborted_with_delivery`, `orphan_timeout`,
845
+ `idle_no_work`, or `unknown`.
846
+ 2. **CI / build status** — the latest `ci` event outcome: `green`, `red`,
847
+ `heal-attempting`, or `ci: n/a` when the cycle never ran CI.
848
+ 3. **Todo remaining** — count of `📋 Todo` lines still in `.roll/backlog.md`.
849
+ 4. **Phase breakdown** — the top 5 cycle phases by elapsed time.
850
+ 5. **Failure / alert highlights** — failed/aborted runs, red CI, active alerts,
851
+ and suspected zero-diff cycles are flagged with a `✗` (failure) or `⚠`
852
+ (warning) prefix and, on a colour terminal, red / yellow highlighting. A
853
+ fully green cycle prints in the default colour with no prefix.
854
+
855
+ The `press enter to close` prompt is preserved — the summary is printed *above*
856
+ it, nothing about the close interaction changes.
857
+
858
+ ### Turning off colour
859
+
860
+ ANSI colour is only emitted when the output is a real terminal. Pipes,
861
+ redirects and captured output stay plain text. To force colour off on a TTY,
862
+ set `NO_COLOR=1` (per [no-color.org](https://no-color.org)):
863
+
864
+ ```bash
865
+ NO_COLOR=1 roll loop now
866
+ ```
867
+
868
+ ### Troubleshooting: no summary appears
869
+
870
+ If the cycle exited early (aborted/idle) or `runs.jsonl` had not yet flushed,
871
+ the window prints a single placeholder line instead, and the `press enter`
872
+ prompt still works:
873
+
874
+ ```text
875
+ (summary unavailable — see log: ~/.shared/roll/loop/cron-<slug>.log)
876
+ ```
877
+
878
+ Summary rendering is always a silent best-effort step: if `python3` is missing
879
+ or the data is corrupt, the cycle skips the recap and falls straight through to
880
+ `press enter to close` — it never changes the `.command` exit code or blocks
881
+ the window from closing.
882
+
883
+ ## Concurrency Safety
884
+
885
+ Loop has two layers:
886
+
887
+ - **LOCK file** (`<project>/.roll/loop/.LOCK-<slug>`): only one loop per project runs at a time.
888
+ If loop is already running, a new fire exits immediately.
889
+ - **🔨 In Progress status**: stories being worked by humans or other agents are skipped.
890
+
891
+ You can always run `$roll-build US-XXX` to take over a story manually.
892
+ Loop sees the `🔨 In Progress` marker and skips it.
893
+
894
+ ## Failure Handling
895
+
896
+ | Condition | What happens |
897
+ |-----------|-------------|
898
+ | API error | Retry up to 3×, 30s backoff |
899
+ | Role candidate unavailable | Skip for current resolution, record runtime health |
900
+ | No role candidate available | Pause loop, write ALERT.md |
901
+ | TCR: 0 commits | Revert story to 📋 Todo, write ALERT.md |
902
+ | HEAD CI red | Hot-fix attempt (see below), or ALERT if exhausted |
903
+
904
+ ALERT entries surface in `roll loop status`, `roll loop alert`, and cycle/story evidence views.
905
+
906
+ ## CI Self-Healing (US-LOOP-046..050)
907
+
908
+ When loop detects that HEAD CI is red before picking a story, it no longer
909
+ immediately writes an ALERT and stops. Instead it tries to fix CI autonomously.
910
+
911
+ **How it works:**
912
+
913
+ 1. `roll loop precheck-ci` runs before each BACKLOG scan.
914
+ 2. If CI is green → cycle proceeds normally.
915
+ 3. If CI is red AND heal is allowed:
916
+ - Loop captures the failing CI log + commit diff via `roll loop hotfix-head-context`.
917
+ - Invokes `roll-fix` with that context as a brief.
918
+ - Waits for CI to go green.
919
+ - If still red after `ROLL_LOOP_HEAL_MAX` attempts (default 2): writes ALERT and stops.
920
+ 4. If CI is red AND heal is exhausted or `ROLL_LOOP_NO_HEAL=1`: writes ALERT (existing behavior).
921
+
922
+ **Loop's own PRs (`loop/*`) that turn red after a cycle exits** are detected
923
+ (US-LOOP-049) and **background-healed** (US-LOOP-062a): classified as
924
+ `loop_self_ci_red`, the PR Loop routes them to `roll loop pr-heal-run`, which checks
925
+ out the PR branch and hands the failing-CI context to the project's agent
926
+ (`_project_agent`) — bounded by a per-PR heal budget (`ROLL_LOOP_HEAL_MAX`,
927
+ default 2) and a per-PR lock that prevents duplicate concurrent heals. The heal
928
+ runs in the background so the PR tick continues. When heal is disabled
929
+ (`ROLL_LOOP_NO_HEAL=1`) or the budget is exhausted, it writes a deduped
930
+ `[TYPE:loop-pr-ci-red]` ALERT instead of silently skipping.
931
+
932
+ **Environment variables:**
933
+
934
+ | Variable | Default | Effect |
935
+ |----------|---------|--------|
936
+ | `ROLL_LOOP_NO_HEAL=1` | unset | Disables all CI hot-fix attempts; reverts to fail-fast |
937
+ | `ROLL_LOOP_HEAL_MAX` | `2` | Maximum consecutive hot-fix attempts before ALERT |
938
+
939
+ ## PR Inbox & Review
940
+
941
+ Each loop cycle processes open PRs before picking new stories.
942
+
943
+ **Review skill:**
944
+
945
+ PR review is dispatched through the `roll-review-pr` skill. It fetches the PR
946
+ title, body, and diff via `gh`, renders a review prompt, and routes it to the
947
+ project's configured agent (Claude, Kimi, DeepSeek, etc.). The agent outputs a
948
+ structured verdict:
949
+
950
+ | Verdict | Action |
951
+ |---------|--------|
952
+ | `APPROVE` | `gh pr review --approve` |
953
+ | `REQUEST_CHANGES` | `gh pr review --request-changes` with reason |
954
+ | `UNCERTAIN` | Writes an ALERT — human decides |
955
+
956
+ **Escape hatch:** Add `[skip-ai-review]` anywhere in the PR body to
957
+ auto-approve without invoking the agent.
958
+
959
+ **How the loop uses it:** `roll loop pr-inbox` classifies each open PR and routes
960
+ `eligible` PRs to the `roll-review-pr` skill. Loop's own PRs (`loop/*` branches)
961
+ are skipped to avoid same-source bias.
962
+
963
+ **Stale PR rebase:** PRs classified as `stale` (CI failed or branch behind/conflicting)
964
+ are automatically rebased onto `origin/main` by the runner's stale-PR rebase. A circuit
965
+ breaker limits rebase attempts to 3 within 24 hours — after that, an ALERT is raised.
966
+ Fork PRs are skipped (no write access) with an ALERT.
967
+
968
+ **Bot review detection:** If a GitHub Actions bot has already reviewed the PR
969
+ (e.g. via the optional GHA workflow), `roll loop pr-inbox` defers:
970
+ - Bot `APPROVED` → skip, let auto-merge proceed
971
+ - Bot `CHANGES_REQUESTED` → write ALERT (loop PR rejected by GHA reviewer)
972
+
973
+ **Active merge of approved PRs (US-LOOP-062b):** when a PR is human-approved,
974
+ CI-green, and mergeable, the PR Loop merges it directly (`gh pr merge --squash`)
975
+ through the runner's approved-PR merge rather than waiting for repo-level auto-merge
976
+ (which may be disabled). Merge failure is non-fatal — the PR is left open and
977
+ retried on the next tick.
978
+
979
+ ### Optional: Event-driven PR review (GHA)
980
+
981
+ Without extra setup, `roll loop pr-inbox` reviews eligible PRs each loop cycle
982
+ (up to ~1 hour delay). For seconds-fast feedback on GitHub-hosted repos,
983
+ install the event-driven workflow:
984
+
985
+ ```bash
986
+ cp templates/workflows/pr-review-event.yml .github/workflows/
987
+ ```
988
+
989
+ This triggers the `roll-review-pr` skill on every PR open/update. Fork PRs and PRs
990
+ with `[skip-ai-review]` in the body are automatically skipped. The template
991
+ requires only one API key secret — the one matching your configured agent.
992
+
993
+ The two modes coexist: the GHA workflow provides instant feedback, and
994
+ `roll loop pr-inbox` acts as a safety net if the workflow is not installed.
995
+
996
+ ## Session Cleanup
997
+
998
+ At the end of every cycle, loop automatically prunes stale local worktrees:
999
+
1000
+ - Any directory under `.claude/worktrees/` whose branch has been fully merged
1001
+ into `main` is removed (`git worktree remove --force` + `git branch -D`).
1002
+ - `git worktree prune` runs afterward to clear stale metadata.
1003
+
1004
+ This keeps `git worktree list` clean and prevents `.claude/worktrees/` from
1005
+ accumulating old entries over time. Active worktrees (branches ahead of `main`)
1006
+ are left untouched.
1007
+
1008
+ ## Cycle phases
1009
+
1010
+ Every cycle is sliced into seven named phases. Each phase emits a `phase_start`
1011
+ event when entered and a `phase_end` event with duration + outcome when it
1012
+ exits. Long-silent phases (claude, PR-merge wait) emit a `phase_tick` heartbeat
1013
+ so the tmux viewer never looks frozen.
1014
+
1015
+ | # | Phase | When it runs | Typical duration |
1016
+ |---|-------|--------------|------------------|
1017
+ | 1 | `startup` | env / lock / heartbeat setup | < 1 s |
1018
+ | 2 | `preflight` | meta sync + stale-branch GC + orphan-worktree recovery | 0 s — 30 s |
1019
+ | 3 | `worktree_setup` | fetch origin + worktree create + meta sync | 2 – 10 s |
1020
+ | 4 | `agent_invoke` | Agent executes with up to 3 retries | 5 – 45 min |
1021
+ | 5 | `publish_push` | push branch + open PR (or doc-only merge) | 5 – 30 s |
1022
+ | 6 | `cleanup` | emit PR final state + worktree teardown | < 1 s |
1023
+
1024
+ > **US-AUTO-044**: the main loop exits after opening the PR and **no longer waits for merge**. Merge / rebase / close is handled asynchronously by the dedicated PR Loop (`com.roll.pr.<slug>`, every 5 min); a story with an open PR is skipped by the eligibility gate, so it is neither re-opened nor falsely marked Done.
1025
+
1026
+ Idle / failed / aborted cycles only emit the phases they actually entered.
1027
+ At cycle exit, the inner runner prints a phase breakdown panel sorted by
1028
+ duration descending, e.g.:
1029
+
1030
+ ```
1031
+ ─── Cycle 20260523-114502-12345 Phase Breakdown ───
1032
+ agent_invoke 723s ( 96.2%) ████████████████████
1033
+ publish_wait_merge 19s ( 2.5%) █
1034
+ worktree_setup 4s ( 0.5%)
1035
+ publish_push 2s ( 0.3%)
1036
+ preflight 2s ( 0.3%)
1037
+ cleanup 1s ( 0.1%)
1038
+ startup 1s ( 0.1%)
1039
+ ──────────────────────────────────────
1040
+ Total 752s
1041
+ ```
1042
+
1043
+ Each phase duration is also persisted to `runs.jsonl` in a new top-level
1044
+ `phases` object (see [State Files](#state-files) below). `roll loop runs`
1045
+ appends `slowest=<phase> <pct>%` to each built row so you can see which step
1046
+ dominated without opening the cycle. For the full breakdown, use:
1047
+
1048
+ ```bash
1049
+ roll loop runs --detail 20260523-114502-12345
1050
+ ```
1051
+
1052
+ ## Cycle Log Archive
1053
+
1054
+ Every cycle's full agent output is archived to `.roll/cycle-logs/<cycle-id>.log`
1055
+ as an ANSI-stripped plain-text file — readable with `less`, `cat`, or any editor.
1056
+
1057
+ - **Per-cycle archive**: one `.log` file per cycle, saved to `.roll/cycle-logs/`
1058
+ - **ANSI-stripped**: color codes and control characters removed, clean plain text
1059
+ - **Retention**: keeps the 50 most recent cycles, older ones are auto-rotated
1060
+ - **Works muted or not**: logs are saved even when `roll loop mute` is on
1061
+
1062
+ ```bash
1063
+ roll loop log # View the most recent cycle's full log
1064
+ roll loop log <cycle-id> # View a specific cycle (e.g. 20260525-231803-39799)
1065
+ roll loop log <prefix> # Prefix match (e.g. 20260525 matches all May 25 cycles)
1066
+ ```
1067
+
1068
+ Cycle logs are stored inside `.roll/` (the project's meta directory) and are
1069
+ gitignored — they won't pollute your repo.
1070
+
1071
+ ## Cross-Machine Sync
1072
+
1073
+ When you run loop on multiple machines for the same project, Roll can sync cycle
1074
+ records to a shared git repo. Every machine writes its own events file, and the
1075
+ dashboard reads all of them — you get a unified view of every cycle across every
1076
+ machine.
1077
+
1078
+ ### Setup
1079
+
1080
+ Add a `roll_records_remote` field to `~/.roll/config.yaml`:
1081
+
1082
+ ```yaml
1083
+ roll_records_remote: "git@github.com:you/roll-loop-records.git"
1084
+ ```
1085
+
1086
+ **Private repo strongly recommended.** Cycle records contain prompt text, file
1087
+ paths, and other potentially sensitive information. Treat the records repo the
1088
+ same way you treat application logs — private, access-controlled, never public.
1089
+
1090
+ If `roll_records_remote` is not configured, cross-machine sync is entirely
1091
+ skipped — no records leave your machine.
1092
+
1093
+ ### How it works
1094
+
1095
+ - Each machine generates a unique machine-id (UUID v4) on first run, cached at
1096
+ `~/.shared/roll/machine-id`.
1097
+ - Every cycle completion pushes an append-only `.ndjson` file to
1098
+ `<slug>/events/<machine-id>.ndjson` in the records repo. Each machine only
1099
+ writes to its own file — no merge conflicts.
1100
+ - Before rendering the dashboard, Roll runs `git pull --ff-only` on a local
1101
+ clone at `~/.shared/roll/sync/`, reads every `*.ndjson` file, and merges
1102
+ them sorted by timestamp with `run_id` deduplication.
1103
+ - Push and pull are best-effort background operations — if the remote is
1104
+ unreachable, the cycle continues normally and the dashboard shows only
1105
+ local data.
1106
+
1107
+ ### Dashboard sync indicator
1108
+
1109
+ The dashboard footer shows one of three states:
1110
+
1111
+ | Indicator | Meaning |
1112
+ |-----------|---------|
1113
+ | `sync: ok (2m ago)` | Remote reachable, records merged successfully |
1114
+ | `sync: offline` | Remote unreachable (network issue, auth expired) — showing local data only |
1115
+ | `sync: not configured` | `roll_records_remote` not set — sync is off, this is expected |
1116
+
1117
+ ### Fork caveat
1118
+
1119
+ Roll derives the project slug from `git remote get-url origin`. If you change
1120
+ `origin` to point to a fork, the slug changes — records from the original repo
1121
+ and the fork will land in different directories in the records repo. This is
1122
+ intentional (different repos, different identities), but if you're temporarily
1123
+ working from a fork, be aware that the dashboard won't show the upstream's
1124
+ cycle history.
1125
+
1126
+ ## Loop Meta Sync
1127
+
1128
+ At the start of every cycle, roll automatically pulls the latest project metadata
1129
+ (`.roll/` directory — backlog, conventions, skills) from its git remote before
1130
+ scanning for stories.
1131
+
1132
+ **How it works**
1133
+
1134
+ 1. Detects whether `.roll/` has a configured `origin` remote.
1135
+ If not, the step is silently skipped (no side-effects for standard roll installs).
1136
+ 2. Runs `git fetch && git reset --hard origin/main` with a 15-second timeout.
1137
+ 3. On success: emits a `meta_sync ok` event; cycle proceeds with fresh backlog.
1138
+ 4. On failure: emits a `meta_sync stale` event; cycle continues with the existing
1139
+ `.roll/` contents (stale is better than no-op).
1140
+
1141
+ **After 3 consecutive failures** the loop writes an ALERT prompting you to check
1142
+ your SSH key or network connectivity.
1143
+
1144
+ **Manual sync**
1145
+
1146
+ ```bash
1147
+ git -C .roll fetch && git -C .roll reset --hard origin/main
1148
+ ```
1149
+
1150
+ **FAQ: the loop runs but the dashboard shows an empty backlog**
1151
+
1152
+ This usually means `.roll/` is out of date:
1153
+ - On a new machine: clone roll-meta manually into `.roll/` and configure the origin remote.
1154
+ - After reinstalling the OS: same as above — SSH key may also need re-authorization.
1155
+ - To confirm: `git -C .roll remote get-url origin` — if empty, no sync is attempted.
1156
+
1157
+ ## Remote Monitoring
1158
+
1159
+ When you're away from your machine you can still watch the loop — backlog
1160
+ progress, Dream health, CI state — from a phone or any browser, without a local
1161
+ `roll` command. It works in two layers: a **data layer** (your machine pushes a
1162
+ status snapshot to the roll-meta repo) and a **prompt layer** (you paste a watch
1163
+ prompt into Claude Code, which reads roll-meta + the GitHub API).
1164
+
1165
+ ### Configure `roll_meta_dir`
1166
+
1167
+ Tell roll where your roll-meta checkout lives, in `~/.roll/config.yaml`:
1168
+
1169
+ ```yaml
1170
+ # ~/.roll/config.yaml
1171
+ roll_meta_dir: ~/projects/roll-meta
1172
+ ```
1173
+
1174
+ `~` is expanded. The key is optional — if it's unset, nothing changes and no
1175
+ snapshot is pushed. If the path doesn't exist, roll prints one WARNING to the
1176
+ cron log and skips the push (the cycle is never affected).
1177
+
1178
+ ### How the automatic push works
1179
+
1180
+ Once `roll_meta_dir` is configured, the loop pushes a fresh snapshot after
1181
+ **every** cycle — including idle cycles where no story ran, so the snapshot
1182
+ doubles as a heartbeat. The cycle runner calls
1183
+ `${roll_meta_dir}/ops/push-loop-status.sh` in the background right after the
1184
+ `cycle_end` event. The script writes `status/loop.md` and commits + pushes it to
1185
+ roll-meta. Output goes to `~/.shared/roll/push-status.log` (rotated at 1MB, 2
1186
+ copies kept).
1187
+
1188
+ Because the loop runs on its normal schedule, `status/loop.md` stays **≤35min
1189
+ fresh** — the watch prompt always sees recent data. The push is best-effort: a
1190
+ network error, git conflict, or a >60s timeout is logged to push-status.log, the
1191
+ process is killed if it hangs, and the cycle continues. No ALERT, no retry.
1192
+
1193
+ ### Manual push
1194
+
1195
+ You can push a snapshot by hand at any time:
1196
+
1197
+ ```bash
1198
+ bash .roll/ops/push-loop-status.sh .roll
1199
+ ```
1200
+
1201
+ (`.roll` is your project's roll-meta checkout.) This is also how you confirm the
1202
+ push pipeline works before relying on the automatic hook.
1203
+
1204
+ ### Watching from a phone or browser
1205
+
1206
+ Open `.roll/prompts/remote-watch.md`, copy its contents, and paste them into
1207
+ Claude Code (web, mobile, or a remote IDE). The prompt does a full health check
1208
+ on first run, then polls every 15 minutes and raises an ALERT immediately on
1209
+ conditions like CI failing twice in a row or `status/loop.md` going >60min
1210
+ stale. It only reads — it never modifies `seanyao/roll`.
1211
+
1212
+ ### Troubleshooting: `status/loop.md` is stale
1213
+
1214
+ If the snapshot's timestamp is far older than 35 minutes:
1215
+
1216
+ 1. Check `~/.shared/roll/push-status.log` — it records every push attempt and
1217
+ any timeout or git error.
1218
+ 2. Confirm `roll_meta_dir` is set and the path exists
1219
+ (`roll config get roll_meta_dir`).
1220
+ 3. Confirm `${roll_meta_dir}/ops/push-loop-status.sh` exists and is executable.
1221
+ 4. Run the manual push above and watch for errors.
1222
+
1223
+ ---
1224
+
1225
+ 远程不在本机时,依然可以从手机或任意浏览器查看 loop —— backlog 进度、Dream 健康、
1226
+ CI 状态 —— 无需本地 `roll` 命令。它分两层:**数据层**(本机把状态快照 push 到
1227
+ roll-meta 仓库)和 **prompt 层**(把巡检 prompt 粘贴进 Claude Code,读 roll-meta +
1228
+ GitHub API)。
1229
+
1230
+ ### 配置 `roll_meta_dir`
1231
+
1232
+ 在 `~/.roll/config.yaml` 里告诉 roll 你的 roll-meta 检出在哪:
1233
+
1234
+ ```yaml
1235
+ # ~/.roll/config.yaml
1236
+ roll_meta_dir: ~/projects/roll-meta
1237
+ ```
1238
+
1239
+ `~` 会被展开。这个键是可选的——不配就什么都不变,也不会推快照。路径不存在时,roll 向
1240
+ cron 日志打一条 WARNING 并跳过推送(绝不影响 cycle)。
1241
+
1242
+ ### 自动 push 的工作原理
1243
+
1244
+ 配好 `roll_meta_dir` 后,loop 在**每一次** cycle 结束后推一份新快照——包括没跑故事
1245
+ 的 idle cycle,所以快照同时充当心跳。cycle runner 在 `cycle_end` 事件之后,于后台调
1246
+ 用 `${roll_meta_dir}/ops/push-loop-status.sh`。脚本写出 `status/loop.md` 并提交 +
1247
+ push 到 roll-meta。输出写到 `~/.shared/roll/push-status.log`(1MB 轮转,保留 2 份)。
1248
+
1249
+ 因为 loop 按固定节奏运行,`status/loop.md` 始终保持 **≤35min 新鲜**——巡检 prompt 总
1250
+ 能看到近期数据。推送是 best-effort:网络错误、git 冲突或 >60s 超时都记进
1251
+ push-status.log,进程卡住会被 kill,cycle 继续。不设 ALERT,不重试。
1252
+
1253
+ ### 手动 push
1254
+
1255
+ 随时可以手动推一份快照:
1256
+
1257
+ ```bash
1258
+ bash .roll/ops/push-loop-status.sh .roll
1259
+ ```
1260
+
1261
+ (`.roll` 是你项目的 roll-meta 检出。)这也是在依赖自动 hook 前确认推送链路是否正常
1262
+ 的方法。
1263
+
1264
+ ### 在手机或浏览器上巡检
1265
+
1266
+ 打开 `.roll/prompts/remote-watch.md`,复制全文,粘贴进 Claude Code(网页、手机或远端
1267
+ IDE)。该 prompt 首次执行做一次全量体检,之后每 15min 轮询一次,遇到「CI 连续两次失
1268
+ 败」或「`status/loop.md` 超过 60min 未更新」等条件立即告警。它只读——绝不修改
1269
+ `seanyao/roll`。
1270
+
1271
+ ### 排障:`status/loop.md` 不更新
1272
+
1273
+ 若快照时间戳远早于 35 分钟:
1274
+
1275
+ 1. 看 `~/.shared/roll/push-status.log`——它记录每次推送尝试以及任何超时或 git 错误。
1276
+ 2. 确认 `roll_meta_dir` 已配置且路径存在(`roll config get roll_meta_dir`)。
1277
+ 3. 确认 `${roll_meta_dir}/ops/push-loop-status.sh` 存在且可执行。
1278
+ 4. 跑一次上面的手动 push,观察是否报错。
1279
+
1280
+ ## State Files
1281
+
1282
+ Since Phase 2.0, a project's loop state lives **inside the project** at
1283
+ `<project>/.roll/loop/`. Only machine-level binding files (launchd runners,
1284
+ attach scripts) and the global mute switch stay in `~/.shared/roll/`. See
1285
+ [Loop Data Layout](loop-data-layout.md) for the full layout, migration, and
1286
+ `roll loop gc`.
1287
+
1288
+ 自 Phase 2.0 起,项目的 loop 状态搬进了**项目目录** `<project>/.roll/loop/`。只有机
1289
+ 器级绑定文件(launchd runner、attach 脚本)和全局静音开关留在 `~/.shared/roll/`。完
1290
+ 整布局、迁移与 `roll loop gc` 见 [Loop 数据布局](loop-data-layout.md)。
1291
+
1292
+ | File | Content |
1293
+ |------|---------|
1294
+ | `<project>/.roll/loop/state-<slug>.yaml` | Current/last run: status, story, agent, run_id |
1295
+ | `<project>/.roll/loop/runs.jsonl` | Append-only run history (one JSON line per cycle); each record carries a `result_eval` block (see [Cycle Result Eval](#cycle-result-eval)) |
1296
+ | `<project>/.roll/loop/events.ndjson` | Per-cycle event stream (phase_start/phase_end, …) |
1297
+ | `.roll/signals/candidates.md` | Candidate backlog drafts from self-evolution signals (`📋 待人确认`, never auto-activated) |
1298
+ | `<project>/.roll/loop/ALERT-<slug>.md` | Accumulated alerts (failures, TCR violations) |
1299
+ | `<project>/.roll/loop/PAUSE-<slug>` | Pause marker (created by `roll loop pause`) |
1300
+ | `~/.shared/roll/mute` | Global auto-attach mute marker (shared across projects) |
1301
+
1302
+ ## Degraded modes & observation
1303
+
1304
+ - **Offline**: when a cycle fails while the network is unreachable, the loop
1305
+ degrades to **local-only delivery** — TCR commits and green tests stay on the
1306
+ branch, a locale-selected notice is printed, the consecutive-failure counter
1307
+ is NOT ticked (offline never accumulates into an auto-PAUSE), and the
1308
+ scheduler keeps breathing. The next online cycle's push/PR catches up
1309
+ naturally.
1310
+ - **Live window for every agent**: non-claude agents (pi, kimi, codex, …) run
1311
+ under a pseudo-terminal on macOS so their output streams line-by-line into
1312
+ the observation window instead of buffering until exit; claude streams over
1313
+ its own protocol unchanged.
1314
+
1315
+ ## Launchd lanes
1316
+
1317
+ Roll owns exactly three launchd jobs per project slug: `com.roll.loop.<slug>`
1318
+ (the cycle scheduler), `com.roll.dream.<slug>` (nightly scan) and
1319
+ `com.roll.pr.<slug>` (PR inbox). `roll loop on` installs them; `roll loop off`
1320
+ uninstalls them AND sweeps any other `com.roll.*.<slug>` plist it finds —
1321
+ retired shapes from older versions (ci/alert/brief) once survived for weeks as
1322
+ zombies pointing at deleted engines. `roll doctor` lists every `com.roll.*`
1323
+ job on the machine with its target directory and load state; a lane whose
1324
+ WorkingDirectory no longer exists is marked STALE in red.