@seanyao/roll 4.630.2 → 4.702.3

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