tumwater 0.1.3 → 0.2.0

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 (359) hide show
  1. package/README.md +63 -28
  2. package/dist/build-info.json +2 -2
  3. package/dist/src/agent/agent-args.js +24 -0
  4. package/dist/src/agent/agent-backend.js +2 -2
  5. package/dist/src/agent/backend-traits.js +60 -0
  6. package/dist/src/agent/claude/claude-account.js +61 -8
  7. package/dist/src/agent/claude/claude-args.js +12 -15
  8. package/dist/src/agent/claude/claude-backend.js +51 -41
  9. package/dist/src/agent/claude/claude-env.js +7 -3
  10. package/dist/src/agent/claude/claude-stream.js +7 -16
  11. package/dist/src/agent/image-input.js +107 -0
  12. package/dist/src/agent/notes-shim.js +41 -0
  13. package/dist/src/agent/opencode/opencode-args.js +61 -0
  14. package/dist/src/agent/opencode/opencode-backend.js +255 -0
  15. package/dist/src/agent/opencode/opencode-catalog.js +184 -0
  16. package/dist/src/agent/opencode/opencode-config.js +188 -0
  17. package/dist/src/agent/opencode/opencode-env.js +36 -0
  18. package/dist/src/agent/opencode/opencode-session-id.js +37 -0
  19. package/dist/src/agent/opencode/opencode-stream.js +278 -0
  20. package/dist/src/agent/role-notes-write.js +16 -32
  21. package/dist/src/agent/run-agent.js +95 -18
  22. package/dist/src/agent/session-ledger.js +57 -1
  23. package/dist/src/backlog/backlog-archive.js +296 -0
  24. package/dist/src/backlog/backlog-cli.js +573 -0
  25. package/dist/src/backlog/backlog-eligibility.js +332 -43
  26. package/dist/src/backlog/backlog-md.js +79 -17
  27. package/dist/src/backlog/backlog-render.js +62 -11
  28. package/dist/src/backlog/backlog-structure.js +261 -58
  29. package/dist/src/backlog/backlog-write.js +178 -441
  30. package/dist/src/backlog/backlog.js +113 -16
  31. package/dist/src/backlog/question-answer.js +339 -0
  32. package/dist/src/baseline/main-baseline.js +75 -88
  33. package/dist/src/baseline/main-red.js +32 -30
  34. package/dist/src/{brief-edit.js → brief/brief-edit.js} +12 -11
  35. package/dist/src/{brief.js → brief/brief.js} +33 -8
  36. package/dist/src/budget/budget.js +32 -15
  37. package/dist/src/budget/fallback-breaker.js +8 -7
  38. package/dist/src/build/build-check-detect.js +8 -7
  39. package/dist/src/build/build-check-events.js +68 -22
  40. package/dist/src/build/build-check-report.js +22 -23
  41. package/dist/src/build/build-check-scoped.js +51 -62
  42. package/dist/src/build/build-check.js +15 -14
  43. package/dist/src/build/build-info.js +2 -1
  44. package/dist/src/build/build-stage.js +23 -22
  45. package/dist/src/build/dep-install.js +22 -21
  46. package/dist/src/build/host-sleep.js +1 -1
  47. package/dist/src/change/change-data.js +13 -11
  48. package/dist/src/change/change-render.js +11 -10
  49. package/dist/src/cli/brief-command.js +9 -7
  50. package/dist/src/cli/cli-args.js +25 -5
  51. package/dist/src/cli/cli-command-args.js +43 -10
  52. package/dist/src/cli/cli-editor.js +13 -1
  53. package/dist/src/cli/cli-flag-specs.js +31 -6
  54. package/dist/src/cli/cli-marker-commands.js +13 -10
  55. package/dist/src/cli/cli-query-commands.js +439 -56
  56. package/dist/src/cli/cli-repo-gate.js +1 -1
  57. package/dist/src/cli/cli-run.js +124 -68
  58. package/dist/src/cli/completion.js +70 -12
  59. package/dist/src/cli/config-commands.js +14 -11
  60. package/dist/src/cli/help.js +264 -124
  61. package/dist/src/cli/log-commands.js +127 -21
  62. package/dist/src/cli/notify-command.js +33 -18
  63. package/dist/src/cli/question-commands.js +13 -224
  64. package/dist/src/cli.js +78 -36
  65. package/dist/src/collections.js +66 -16
  66. package/dist/src/concurrency/check-permit.js +16 -17
  67. package/dist/src/concurrency/lock.js +6 -5
  68. package/dist/src/concurrency/provider-lease.js +69 -0
  69. package/dist/src/concurrency/semaphore.js +258 -36
  70. package/dist/src/config/config-aliases.js +106 -0
  71. package/dist/src/config/config-editable-keys.js +3 -3
  72. package/dist/src/config/config-fallbacks.js +379 -0
  73. package/dist/src/config/config-field-checks.js +19 -10
  74. package/dist/src/config/config-keys.js +160 -0
  75. package/dist/src/config/config-live.js +64 -12
  76. package/dist/src/config/config-schema.js +34 -22
  77. package/dist/src/config/config-validation.js +132 -48
  78. package/dist/src/config/config-views.js +107 -325
  79. package/dist/src/config/config-write.js +138 -177
  80. package/dist/src/config/config.js +60 -49
  81. package/dist/src/config/model-selector.js +28 -2
  82. package/dist/src/doctor/doctor-backlog.js +494 -68
  83. package/dist/src/doctor/doctor-checks.js +509 -58
  84. package/dist/src/doctor/doctor-holds.js +139 -78
  85. package/dist/src/doctor/doctor-install.js +30 -0
  86. package/dist/src/doctor/doctor-launch-services.js +2 -2
  87. package/dist/src/doctor/doctor-model-checks.js +549 -157
  88. package/dist/src/doctor/doctor-notify.js +2 -3
  89. package/dist/src/doctor/doctor-orphans.js +10 -9
  90. package/dist/src/doctor/doctor-render.js +36 -9
  91. package/dist/src/doctor/doctor.js +76 -25
  92. package/dist/src/doctor/image-probe.js +244 -0
  93. package/dist/src/doctor/probe.js +64 -0
  94. package/dist/src/events/event-format.js +219 -106
  95. package/dist/src/events/event-labels.js +116 -0
  96. package/dist/src/events/event-legacy.js +140 -0
  97. package/dist/src/events/event-read.js +58 -22
  98. package/dist/src/events/event-window.js +27 -7
  99. package/dist/src/events/events.js +18 -14
  100. package/dist/src/events/notify.js +80 -30
  101. package/dist/src/failure/failure-cluster.js +12 -9
  102. package/dist/src/failure/failure-data.js +96 -48
  103. package/dist/src/failure/failure-render.js +69 -58
  104. package/dist/src/failure/failure-state-change.js +33 -26
  105. package/dist/src/failure/time-spend.js +79 -59
  106. package/dist/src/files/file-queue.js +16 -4
  107. package/dist/src/files/files.js +18 -6
  108. package/dist/src/files/json-object.js +18 -3
  109. package/dist/src/files/tail.js +1 -1
  110. package/dist/src/gates/bootstrap-gates.js +5 -4
  111. package/dist/src/gates/budget-gates.js +250 -34
  112. package/dist/src/gates/disk-gate.js +18 -18
  113. package/dist/src/gates/gate-polls.js +117 -69
  114. package/dist/src/gates/maintenance-quota.js +29 -29
  115. package/dist/src/gates/pause-gates.js +11 -11
  116. package/dist/src/gates/readiness.js +2 -1
  117. package/dist/src/gates/role-cap-gates.js +16 -21
  118. package/dist/src/gates/startup-gate.js +75 -31
  119. package/dist/src/gates/streak-gate.js +18 -16
  120. package/dist/src/git/commit-message.js +6 -5
  121. package/dist/src/git/git-diff.js +16 -16
  122. package/dist/src/git/git-run.js +8 -8
  123. package/dist/src/git/git.js +79 -59
  124. package/dist/src/git/slots-state.js +14 -5
  125. package/dist/src/git/worktree-pool.js +25 -18
  126. package/dist/src/git/worktree-use.js +15 -14
  127. package/dist/src/git/worktree.js +18 -18
  128. package/dist/src/gui/gui-args.js +10 -14
  129. package/dist/src/gui/gui-backlog-commands.js +273 -0
  130. package/dist/src/gui/gui-command.js +1 -1
  131. package/dist/src/gui/gui-config-commands.js +440 -0
  132. package/dist/src/gui/gui-endpoint-commands.js +16 -716
  133. package/dist/src/gui/gui-endpoint-common.js +49 -0
  134. package/dist/src/gui/gui-endpoints.js +105 -54
  135. package/dist/src/gui/gui-operator-commands.js +145 -0
  136. package/dist/src/gui/gui-prompt-commands.js +234 -0
  137. package/dist/src/gui/gui-server.js +25 -8
  138. package/dist/src/gui/gui-team-commands.js +164 -0
  139. package/dist/src/gui/http-body.js +17 -1
  140. package/dist/src/history/history-data.js +179 -104
  141. package/dist/src/history/history-render.js +76 -0
  142. package/dist/src/history/history.js +29 -70
  143. package/dist/src/inbox/inbox-attachments.js +66 -10
  144. package/dist/src/inbox/inbox-cancel.js +7 -5
  145. package/dist/src/inbox/inbox-edit.js +1 -1
  146. package/dist/src/inbox/inbox-submit.js +44 -4
  147. package/dist/src/inbox/inbox-top.js +83 -0
  148. package/dist/src/inbox/inbox.js +8 -2
  149. package/dist/src/inbox/pending-prompt.js +1 -1
  150. package/dist/src/inbox/prompt-commands.js +114 -73
  151. package/dist/src/init/init-templates.js +16 -14
  152. package/dist/src/init/init.js +12 -11
  153. package/dist/src/loop/leftover.js +28 -27
  154. package/dist/src/loop/loop-fallback.js +2 -2
  155. package/dist/src/loop/loop-pi.js +104 -50
  156. package/dist/src/loop/loop-recovery.js +15 -15
  157. package/dist/src/loop/loop-state.js +130 -13
  158. package/dist/src/loop/loop-tick.js +190 -88
  159. package/dist/src/loop/loop.js +68 -36
  160. package/dist/src/loop/model-fallback.js +3 -2
  161. package/dist/src/loop/revision.js +16 -7
  162. package/dist/src/merge/backlog-conflicts.js +155 -0
  163. package/dist/src/{landing/landing-batch.js → merge/merge-batch.js} +90 -89
  164. package/dist/src/{landing/landing-check-failures.js → merge/merge-check-failures.js} +87 -41
  165. package/dist/src/{landing/landing-core.js → merge/merge-core.js} +119 -95
  166. package/dist/src/{landing/landing-diff.js → merge/merge-diff.js} +1 -1
  167. package/dist/src/merge/merge-drain.js +212 -0
  168. package/dist/src/{landing/landing-git.js → merge/merge-git.js} +94 -20
  169. package/dist/src/merge/merge-pipeline.js +99 -0
  170. package/dist/src/{landing/landing-questions.js → merge/merge-questions.js} +9 -6
  171. package/dist/src/merge/merge-queue-render.js +75 -0
  172. package/dist/src/{landing/landing-queue.js → merge/merge-queue.js} +95 -36
  173. package/dist/src/merge/merge-slot.js +340 -0
  174. package/dist/src/{landing/landing-stack.js → merge/merge-stack.js} +66 -62
  175. package/dist/src/{landing/landing-merge.js → merge/merge-to-main.js} +72 -62
  176. package/dist/src/merge/merge-verify.js +212 -0
  177. package/dist/src/notes-cli.js +97 -0
  178. package/dist/src/operator/operator-commands.js +113 -45
  179. package/dist/src/operator/operator-intent.js +74 -53
  180. package/dist/src/operator/operator-requests.js +52 -52
  181. package/dist/src/operator/retire.js +47 -28
  182. package/dist/src/operator/revert.js +71 -0
  183. package/dist/src/orchestrator/orchestrator-launch.js +74 -14
  184. package/dist/src/orchestrator/orchestrator-scheduling.js +74 -43
  185. package/dist/src/orchestrator/orchestrator.js +149 -96
  186. package/dist/src/orchestrator/retention.js +29 -12
  187. package/dist/src/orchestrator/startup-migration-steps.js +51 -0
  188. package/dist/src/orchestrator/startup-migrations.js +40 -0
  189. package/dist/src/paths.js +124 -38
  190. package/dist/src/pi/pi-args.js +26 -3
  191. package/dist/src/pi/pi-backend.js +15 -23
  192. package/dist/src/pi/pi-bin.js +18 -12
  193. package/dist/src/pi/pi-event-line.js +17 -1
  194. package/dist/src/pi/pi-failure.js +87 -0
  195. package/dist/src/pi/pi-models.js +126 -38
  196. package/dist/src/pi/pi-run-result.js +1 -1
  197. package/dist/src/pi/pi-settings.js +86 -0
  198. package/dist/src/pi/pi-stream.js +131 -107
  199. package/dist/src/pi/pi-watchdogs.js +4 -3
  200. package/dist/src/pi-extension/bounded-output.js +20 -5
  201. package/dist/src/pi-extension/context-budget.js +3 -1
  202. package/dist/src/pi-extension/context-shake.js +54 -21
  203. package/dist/src/pi-extension/context-window.js +37 -0
  204. package/dist/src/pi-extension/full-output.js +2 -2
  205. package/dist/src/pi-extension/strip-thinking.js +80 -0
  206. package/dist/src/pi-extension/trim-system-prompt.js +38 -0
  207. package/dist/src/process/launch-services.js +11 -10
  208. package/dist/src/process/process-table.js +1 -1
  209. package/dist/src/process/process.js +7 -7
  210. package/dist/src/process/run-marker.js +29 -6
  211. package/dist/src/process/supervisor.js +36 -25
  212. package/dist/src/prompt/dialect.js +30 -10
  213. package/dist/src/prompt/gate-prompts.js +170 -67
  214. package/dist/src/prompt/principles.js +1 -0
  215. package/dist/src/prompt/prompt-followup.js +29 -20
  216. package/dist/src/prompt/prompt.js +249 -91
  217. package/dist/src/redeploy/redeploy-policy.js +10 -10
  218. package/dist/src/redeploy/redeploy.js +6 -4
  219. package/dist/src/redeploy/redeployer.js +63 -55
  220. package/dist/src/redeploy/self-reload.js +1 -1
  221. package/dist/src/report/report-data.js +259 -254
  222. package/dist/src/report/report-fold.js +353 -0
  223. package/dist/src/report/report-render.js +235 -44
  224. package/dist/src/request-timeouts.js +1 -1
  225. package/dist/src/review/known-flakes.js +34 -14
  226. package/dist/src/review/protected-edits.js +4 -3
  227. package/dist/src/review/review-followup.js +16 -4
  228. package/dist/src/review/review-precheck.js +14 -13
  229. package/dist/src/review/review-verdict.js +14 -0
  230. package/dist/src/review/review.js +55 -34
  231. package/dist/src/review/secret-leaks.js +127 -0
  232. package/dist/src/review/suite-rerun.js +4 -3
  233. package/dist/src/roles/legacy-role-ids.js +21 -0
  234. package/dist/src/roles/legacy-role-migration.js +62 -0
  235. package/dist/src/roles/loop-ids.js +19 -2
  236. package/dist/src/roles/role-catalog.js +109 -131
  237. package/dist/src/roles/role-guidance.js +64 -31
  238. package/dist/src/roles/role-labels.js +10 -0
  239. package/dist/src/roles/role-render.js +194 -18
  240. package/dist/src/roles/role-view.js +216 -17
  241. package/dist/src/roles/roles.js +16 -14
  242. package/dist/src/scheduling/backoff.js +29 -19
  243. package/dist/src/scheduling/claims.js +15 -8
  244. package/dist/src/scheduling/once-round.js +11 -11
  245. package/dist/src/scheduling/quiet-hours.js +25 -32
  246. package/dist/src/scheduling/scheduling.js +28 -25
  247. package/dist/src/scheduling/{work-landed-cache.js → work-merged-cache.js} +14 -14
  248. package/dist/src/status/status-budget.js +115 -0
  249. package/dist/src/status/status-data.js +72 -184
  250. package/dist/src/status/status-inbox.js +47 -0
  251. package/dist/src/status/status-install.js +27 -0
  252. package/dist/src/status/status-polls.js +50 -39
  253. package/dist/src/status/status-roles.js +105 -0
  254. package/dist/src/{fleet → team}/error-storm.js +10 -10
  255. package/dist/src/{fleet → team}/failure-spread.js +8 -8
  256. package/dist/src/{fleet → team}/orchestrator-info.js +84 -18
  257. package/dist/src/{fleet → team}/reclaim.js +5 -4
  258. package/dist/src/{fleet/fleet-hold.js → team/team-hold.js} +55 -21
  259. package/dist/src/{fleet/fleet-polls.js → team/team-polls.js} +116 -65
  260. package/dist/src/{fleet/fleet-state.js → team/team-state.js} +39 -38
  261. package/dist/src/text/datetime.js +42 -2
  262. package/dist/src/text/format.js +10 -1
  263. package/dist/src/text/markdown.js +1 -1
  264. package/dist/src/text/phrases.js +35 -34
  265. package/dist/src/text/suggest.js +3 -2
  266. package/dist/src/text/text.js +2 -2
  267. package/dist/src/tick/qa-coverage.js +2 -1
  268. package/dist/src/tick/stage-check.js +142 -25
  269. package/dist/src/tick/telemetry-digest.js +10 -9
  270. package/dist/src/tick/tick-apply.js +101 -72
  271. package/dist/src/tick/tick-detail-data.js +23 -22
  272. package/dist/src/tick/tick-detail.js +37 -24
  273. package/dist/src/tick/tick-finalize.js +29 -22
  274. package/dist/src/tick/tick-outcome.js +2 -1
  275. package/dist/src/tick/tick-prompt.js +94 -26
  276. package/dist/src/tick/tick-resume.js +29 -13
  277. package/dist/src/tick/tick-stage.js +67 -53
  278. package/dist/src/tick/tick-timing.js +60 -59
  279. package/dist/src/tick/tick-usage.js +53 -23
  280. package/dist/src/tick/tick-verdict.js +75 -10
  281. package/dist/src/ui/badges.js +113 -69
  282. package/dist/src/ui/gui/gui-client-boot.js +202 -29
  283. package/dist/src/ui/gui/gui-client-composer.js +102 -23
  284. package/dist/src/ui/gui/gui-client-drawer.js +330 -75
  285. package/dist/src/ui/gui/gui-client-history.js +94 -37
  286. package/dist/src/ui/gui/gui-client-labels.js +24 -0
  287. package/dist/src/ui/gui/gui-client-loops.js +90 -47
  288. package/dist/src/ui/gui/gui-client-markdown.js +1 -0
  289. package/dist/src/ui/gui/gui-client-model.js +60 -43
  290. package/dist/src/ui/gui/gui-client-operator.js +73 -43
  291. package/dist/src/ui/gui/gui-client-pending.js +34 -31
  292. package/dist/src/ui/gui/gui-client-report.js +330 -47
  293. package/dist/src/ui/gui/gui-client-settings.js +126 -18
  294. package/dist/src/ui/gui/gui-client-sound.js +2 -1
  295. package/dist/src/ui/gui/{gui-client-fleet.js → gui-client-team.js} +190 -74
  296. package/dist/src/ui/gui/gui-client.js +26 -20
  297. package/dist/src/ui/gui/gui-page.js +18 -19
  298. package/dist/src/ui/gui/gui-styles.js +12 -4
  299. package/dist/src/ui/progress-data.js +5 -3
  300. package/dist/src/ui/status-model.js +176 -102
  301. package/dist/src/ui/status-payload.js +114 -36
  302. package/dist/src/ui/status-render.js +121 -52
  303. package/dist/src/ui/team-alerts.js +341 -0
  304. package/dist/src/ui/tick-progress-model.js +14 -14
  305. package/dist/src/ui/tone.js +9 -8
  306. package/dist/src/ui/transcript-tail.js +1 -0
  307. package/dist/src/ui/transcript.js +23 -16
  308. package/dist/src/ui/tui/tui-app.js +1 -0
  309. package/dist/src/ui/tui/tui-backlog.js +85 -11
  310. package/dist/src/ui/tui/tui-editor-answer.js +97 -0
  311. package/dist/src/ui/tui/tui-editor-attach.js +107 -0
  312. package/dist/src/ui/tui/tui-editor-brief.js +107 -0
  313. package/dist/src/ui/tui/tui-editor-budget.js +155 -0
  314. package/dist/src/ui/tui/tui-editor-ctx.js +1 -0
  315. package/dist/src/ui/tui/tui-editor-entry.js +230 -0
  316. package/dist/src/ui/tui/tui-editor-interval.js +122 -0
  317. package/dist/src/ui/tui/tui-editor-notes.js +114 -0
  318. package/dist/src/ui/tui/tui-editor-pause.js +266 -0
  319. package/dist/src/ui/tui/tui-editor-prompt.js +95 -0
  320. package/dist/src/ui/tui/tui-editor-queued.js +98 -0
  321. package/dist/src/ui/tui/tui-editor-quiet.js +106 -0
  322. package/dist/src/ui/tui/tui-editor-retire.js +83 -0
  323. package/dist/src/ui/tui/tui-editor-search.js +73 -0
  324. package/dist/src/ui/tui/tui-editor-session.js +97 -0
  325. package/dist/src/ui/tui/tui-editors.js +152 -0
  326. package/dist/src/ui/tui/tui-frame.js +61 -57
  327. package/dist/src/ui/tui/tui-history.js +12 -7
  328. package/dist/src/ui/tui/tui-input.js +44 -50
  329. package/dist/src/ui/tui/tui-keymap.js +1 -0
  330. package/dist/src/ui/tui/tui-keys.js +87 -1821
  331. package/dist/src/ui/tui/tui-pane-activity.js +99 -0
  332. package/dist/src/ui/tui/tui-pane-backlog.js +224 -0
  333. package/dist/src/ui/tui/tui-pane-brief.js +30 -0
  334. package/dist/src/ui/tui/tui-pane-ctx.js +11 -0
  335. package/dist/src/ui/tui/tui-pane-health.js +124 -0
  336. package/dist/src/ui/tui/tui-pane-history.js +316 -0
  337. package/dist/src/ui/tui/tui-pane-pending.js +74 -0
  338. package/dist/src/ui/tui/tui-pane-queued.js +143 -0
  339. package/dist/src/ui/tui/tui-pane-report.js +122 -0
  340. package/dist/src/ui/tui/tui-pane-session.js +101 -0
  341. package/dist/src/ui/tui/tui-pane-transcript.js +150 -0
  342. package/dist/src/ui/tui/tui-pane.js +52 -28
  343. package/dist/src/ui/tui/tui-panes.js +294 -0
  344. package/dist/src/ui/tui/tui.js +44 -26
  345. package/dist/src/verdict/fix-claim.js +56 -33
  346. package/dist/src/verdict/no-change.js +19 -0
  347. package/dist/src/verdict/refusal.js +43 -11
  348. package/dist/src/verdict/reply-contract.js +17 -5
  349. package/dist/src/version.js +3 -2
  350. package/package.json +4 -2
  351. package/dist/src/agent/mcp/role-notes-server.js +0 -160
  352. package/dist/src/landing/backlog-conflicts.js +0 -116
  353. package/dist/src/landing/landing-drain.js +0 -204
  354. package/dist/src/landing/landing-pipeline.js +0 -96
  355. package/dist/src/landing/landing-queue-render.js +0 -56
  356. package/dist/src/landing/landing-slot.js +0 -256
  357. package/dist/src/landing/landing-vetting.js +0 -196
  358. package/dist/src/pi-extension/role-notes.js +0 -40
  359. package/dist/src/ui/fleet-alerts.js +0 -174
@@ -1,11 +1,19 @@
1
+ // vocabulary: plain
1
2
  /** The role catalog: one built-in loop's identity and its role-specific "find something to do"
2
3
  * instruction text. Split out of roles.ts (2026-10-01, organize) so the catalog's embedded
3
4
  * prompt prose lives apart from the derived registries and classification helpers, which stayed
4
5
  * in roles.ts. Pure catalog data — the shared instruction fragments role prompts embed live in
5
6
  * role-guidance.ts (import-only downward, so prompt assembly depends on both without a cycle).
6
7
  * roles.ts re-exports ROLES and Role, so every existing importer keeps its import path. */
7
- import { backlogMoveGuidance, DECOMPOSITION_GUIDANCE, NEEDS_REPLAN_NOTE, NEEDS_REVIEW_NOTE, PLAN_SIZING, searchGuidance, VALIDATION_GAP_GUIDANCE, VALIDATION_GAP_TALLY, } from "./role-guidance.js";
8
+ import { backlogMoveGuidance, DECOMPOSITION_GUIDANCE, NEEDS_REPLAN_NOTE, NEEDS_REVIEW_NOTE, PLAN_SIZING, searchGuidance, VALIDATION_GAP_GUIDANCE, VALIDATION_GAP_QUERY, VALIDATION_GAP_TALLY, WAITING_FOR_FAILURE_NOTE, WAITING_FOR_FAILURE_PREFIX, } from "./role-guidance.js";
9
+ import { roleCommitGrep } from "./legacy-role-ids.js";
8
10
  import { NOTHING_TO_DO } from "../verdict/reply-contract.js";
11
+ /** The trailer the readme role's commits carry and its `git log --grep` reads back; git parses
12
+ * it, so it keeps this spelling. Interpolated because a comment inside the template would
13
+ * become prompt text. */
14
+ const README_TRAILER = "Run: readme #";
15
+ const README_TRAILER_GREP = "^(Run|Tick): readme #"; // vocabulary-ok: legacy name read from old refs or commits
16
+ const README_TRAILER_LEGACY = "Tick: readme #"; // vocabulary-ok: legacy name read from old refs or commits
9
17
  /** The opinionated role catalog. Every loop runs one role; a role's `find` text is
10
18
  * the role-specific "find something to do" half of the tick prompt.
11
19
  *
@@ -20,8 +28,9 @@ export const ROLES = [
20
28
  1. The prompt's <backlog-index> block lists PLANS.md's \`## Planned\` entries with each
21
29
  entry's line range; read the one you pick by that range.
22
30
  2. Pick one entry under \`## Planned\`, preferring ones marked ready or with a written plan.
23
- Skip entries the index block marks \`[blocked: …]\` (their prerequisite has not landed),
24
- \`[refused]\` or \`[needs review]\`. Skip plans whose entry carries a Refused note, and skip
31
+ Skip entries the index block marks \`[blocked: …]\` — \`[blocked: requires …]\` (a
32
+ prerequisite has not merged), \`[blocked: refused]\`, \`[blocked: needs review]\` or
33
+ \`[blocked: needs replan]\`. Skip plans whose entry carries a Refused note, and skip
25
34
  entries already carrying a **Needs review …** note or a ${NEEDS_REPLAN_NOTE}. If PLANS.md
26
35
  is empty or everything is done, there is nothing to do.
27
36
  3. Read only the chosen entry's line range and the code it names.
@@ -33,7 +42,7 @@ export const ROLES = [
33
42
  the entry's files-touched list and acceptance criteria, so land everything the entry
34
43
  promises, or update the entry to say what changed and why. When a plan's anchors no longer
35
44
  match the code, correct the entry in the same change instead of refusing.
36
- 6. Mark the plan done in PLANS.md — ${backlogMoveGuidance("PLANS.md", "## Planned", "## Done")}
45
+ 6. Mark the plan done in PLANS.md — ${backlogMoveGuidance("PLANS.md", "## Planned", "## Done", "PLANS-DONE.md")}
37
46
  7. Verify last, after the PLANS.md edit, so one run of the project's check covers everything
38
47
  you changed (see "Leave the project working" below).
39
48
  A plan that resists implementation is a finding: refuse it with the objection recorded rather
@@ -45,13 +54,16 @@ than forcing it.`,
45
54
  title: "bug fixer",
46
55
  find: `Fix the SINGLE most important open bug in BUGS.md.
47
56
  1. The prompt's <backlog-index> block lists BUGS.md's \`## Open\` entries with each entry's
48
- line range; read the one you pick by that range. Skip BUGS.md entries carrying a Refused
49
- note: when every open entry carries one, there is nothing to do. When \`## Open\` holds no entries at all, skip to the
57
+ line range; read the one you pick by that range. Skip BUGS.md entries the index block marks
58
+ \`[blocked: …]\` (such as \`[blocked: refused]\`, for a Refused note): when every open entry is marked, there is nothing to do. When \`## Open\` holds no entries at all, skip to the
50
59
  latent-bug hunt at the end instead.
51
- 2. Reproduce it if possible: a failing test or a scratch script.
60
+ 2. Reproduce it if possible: a failing test or a scratch script. When it cannot be reproduced
61
+ and this run made its failure message name the cause next time (or found it already does),
62
+ record a Progress note, write ${WAITING_FOR_FAILURE_NOTE} as its own line under the
63
+ heading, and end the run. Do not keep investigating without new evidence.
52
64
  3. Fix it, and add a regression test that fails without the fix — run that test to watch it
53
65
  fail before the fix and pass after.
54
- 4. Mark it fixed in BUGS.md — ${backlogMoveGuidance("BUGS.md", "## Open", "## Fixed")}
66
+ 4. Mark it fixed in BUGS.md — ${backlogMoveGuidance("BUGS.md", "## Open", "## Fixed", "BUGS-FIXED.md")}
55
67
  5. In the moved entry, write the required validation-gap trace line (format below).
56
68
  6. Verify last, after the BUGS.md edits, so one run of the project's check covers everything
57
69
  you changed (see "Leave the project working" below).
@@ -76,7 +88,7 @@ within that budget, there is nothing to do.`,
76
88
  1. Check what is already waiting: the prompt's <backlog-index> block lists PLANS.md's
77
89
  \`## Planned\` entries with each entry's line range.
78
90
  - A plan carrying a ${NEEDS_REVIEW_NOTE} note outranks adding another plan: split it into
79
- independently landable sub-plans that cross-reference each other (per PLAN_SIZING below,
91
+ independently mergeable sub-plans that cross-reference each other (per PLAN_SIZING below,
80
92
  each with its own acceptance criteria), then remove the note. That split is this run's task.
81
93
  - A plan carrying a ${NEEDS_REPLAN_NOTE} note also outranks adding another plan: read the
82
94
  quoted objections and the code they name, then rewrite the plan so an implementation
@@ -84,18 +96,19 @@ within that budget, there is nothing to do.`,
84
96
  acceptance criteria, splitting it per PLAN_SIZING, or refusing it with the objection
85
97
  recorded when it should not be done — and remove both the note and the quoted objections.
86
98
  - Otherwise, when PLANS.md \`## Planned\` already holds one more eligible plan than there
87
- are feature instances (one waiting per instance, plus one for the next planner tick),
99
+ are feature instances (one waiting per instance, plus one for the next planner run),
88
100
  end with ${NOTHING_TO_DO} — feature has work, and a waiting plan is refined by the
89
101
  feature run that picks it up, against the code as it stands then. Count only eligible
90
- entries — those not blocked, refused, needs-review or needs-replan. When it does not
102
+ entries — those the index block does not mark \`[blocked: …]\`. When it does not
91
103
  stop, prefer a plan independent of the waiting series, so feature can run it alongside
92
104
  the blocked ones; with more than one feature instance, an independent plan keeps every
93
105
  runner fed.
94
- 2. Choose ONE unplanned feature or improvement worth doing, guided by the initial prompt in the
106
+ 2. Choose ONE unplanned feature or improvement worth doing, guided by the
95
107
  project brief (TUMWATER.md when it exists with the tumwater:prompt markers, else README.md)
96
108
  and by what already exists.
97
109
  3. Before planning, confirm with grep that the capability does not already exist and that no
98
- Planned or Done entry already covers it (read only the entries whose headings look related).
110
+ Planned entry, nor any finished plan in PLANS-DONE.md, already covers it — grep the archive
111
+ rather than reading it, and read only the entries whose headings look related.
99
112
  4. Ground the plan in the code: name the actual files and functions it touches, having looked
100
113
  at them in ranges.
101
114
  5. Write it as a short markdown section under \`## Planned\` in PLANS.md: goal, approach, files
@@ -106,24 +119,25 @@ ${DECOMPOSITION_GUIDANCE}`,
106
119
  {
107
120
  id: "readme",
108
121
  tier: "small",
109
- title: "README maintainer",
122
+ title: "brief and README keeper",
110
123
  find: `Keep the project brief — TUMWATER.md when it exists with the tumwater:prompt markers, else
111
124
  README.md — accurate against the actual state of the project.
112
125
  1. Work from the delta, not from scratch: \`git log --oneline <last readme commit>..main\` names
113
- everything that landed since your last sync — your commits carry a \`Tick: readme #N\`
114
- trailer, and \`git log --grep='^Tick: readme #' -1 --format=%H\` names the last one. Read only
126
+ everything that merged since your last sync — your new commits carry a \`${README_TRAILER}N\`
127
+ trailer and older ones \`${README_TRAILER_LEGACY}N\`; \`git log -E --grep='${README_TRAILER_GREP}' -1 --format=%H\`
128
+ names the last one. Read only
115
129
  what those commits touched.
116
- 2. If the brief is already accurate, there is nothing to do: a landing that touched no
130
+ 2. If the brief is already accurate, there is nothing to do: a merge that touched no
117
131
  user-facing surface (commands, flags, config keys, docs) needs no sync.
118
132
  3. The status section (between the tumwater:status markers) describes CURRENT STATE ONLY, and
119
133
  you rewrite it wholesale on each sync — never append to it. It carries exactly two things:
120
134
  (a) a one-line version/capability summary — no command or flag lists, which belong in the
121
135
  usage docs, and (b) one line pointing at PLANS.md, BUGS.md, and QUESTIONS.md for open work —
122
- never a copy of their entries, which every tick already reads there.
136
+ never a copy of their entries, which every run already reads there.
123
137
  4. Keep these out of the status section:
124
138
  - Main's build and suite state: it is reported live by \`tumwater status\` (its mainCheck) —
125
- never stamped into the section, so a landing needs no README commit to refresh it.
126
- - Per-tick landing narrative: landings are recorded by their owning loops in
139
+ never stamped into the section, so a merge needs no README commit to refresh it.
140
+ - Per-run merge narrative: merges are recorded by their owning roles in
127
141
  PLANS.md/BUGS.md and git log; stale narrative found in the section is deleted as part of
128
142
  updating it (that is an update, not a loss).
129
143
  If the section exceeds ~1KB it has drifted back into narrative — prune it to the state-only
@@ -132,7 +146,7 @@ README.md — accurate against the actual state of the project.
132
146
  only the director and steward edit.
133
147
  Keep the brief short: a summary, the status, and brief usage; mechanics and reference detail
134
148
  belong in separate docs it links to, so move detail there instead of growing the brief. Never
135
- edit the initial prompt between the tumwater:prompt markers.`,
149
+ edit the brief between the tumwater:prompt markers.`,
136
150
  },
137
151
  {
138
152
  id: "organize",
@@ -140,8 +154,8 @@ edit the initial prompt between the tumwater:prompt markers.`,
140
154
  title: "code organizer",
141
155
  // Written against the 2026-10-05/06 churn: with minor fixes exhausted and the shared
142
156
  // small-and-self-contained scope rule in force, organize reorganized the whole tree one
143
- // directory per tick (45 of 86 landings in four hours) with no target structure ever
144
- // stated. Major refactors stay welcome; they must be considered whole and land whole.
157
+ // directory per tick (45 of 86 merges in four hours) with no target structure ever
158
+ // stated. Major refactors stay welcome; they must be considered whole and merge whole.
145
159
  find: `Find ONE way the code could be better organized, and restructure it.
146
160
  1. First rank the production source files (not the tests) by \`wc -l\`. A production module
147
161
  several times the project's median file size almost always holds more than one
@@ -176,10 +190,10 @@ organize changes where code lives and how it is divided, not what it does. Updat
176
190
  imports/references so the project still builds and tests still pass. A change is complete only
177
191
  when a grep for every old path and every moved or renamed name — over the source, the tests,
178
192
  and the markdown docs (doc comments, PLANS.md, BUGS.md) — finds no stale reference.`,
179
- scope: `- Do exactly ONE task, then stop — but unlike the other loops' tasks, yours need not be
193
+ scope: `- Do exactly ONE task, then stop — but unlike the other roles' tasks, yours need not be
180
194
  small or self-contained: a restructure worth doing often takes real refactoring across many
181
- files, and one coherent change landed whole beats the same change spread over many runs.
182
- Where PRINCIPLES.md asks for one focused change per tick, for this loop that means one
195
+ files, and one coherent change merged whole beats the same change spread over many runs.
196
+ Where PRINCIPLES.md asks for one focused change per run, for this role that means one
183
197
  coherent restructure. Complete and correct still beats big and half-done.
184
198
  - Choose the task within your first ~15 tool calls, in a handful of turns. A restructure that
185
199
  would need more than roughly 150 tool calls, or that you could not finish with the project
@@ -191,10 +205,14 @@ and the markdown docs (doc comments, PLANS.md, BUGS.md) — finds no stale refer
191
205
  title: "test coverage improver",
192
206
  find: `Find ONE meaningful gap in unit test coverage — an untested module, branch, or edge case
193
207
  that could plausibly break — and close it with focused tests.
194
- 1. Locate it from evidence rather than by reading every module: compare the source module list
195
- against the test files (a module with no test is the first candidate), or run the
196
- project's coverage command — for an npm project that is \`npm run test:coverage\`, piped
197
- through \`tail\` — and pick the file with the most uncovered
208
+ 1. The team's own record of what made past bugs hard to confirm is the first evidence: run
209
+ \`${VALIDATION_GAP_QUERY}\` and read the entry above each hit and its free-text sentence;
210
+ when it names a module, branch or behavior (or the entry's fix touched one), that is the
211
+ first candidate — a \`no-fake\` or \`no-repro\` trace names test infrastructure to build.
212
+ Only when no recent trace names a candidate: Locate it from evidence rather than by reading
213
+ every module — compare the source module list against the test files (a module with no test
214
+ is the first candidate), or run the project's coverage command — for an npm project that is
215
+ \`npm run test:coverage\`, piped through \`tail\` — and pick the file with the most uncovered
198
216
  lines from the deterministic-coverage table at the end of its output — node's own table above
199
217
  it can flip between runs on the same tree, so quote the deterministic numbers.
200
218
  2. Then read only that file and its existing tests — every test that imports it, not just the
@@ -212,17 +230,18 @@ scratch analysis scripts — that is a different, much larger task.`,
212
230
  tier: "default",
213
231
  title: "code cleaner",
214
232
  find: `When a \`<backlog-structure>\` block is present in your prompt, that repair is instead
215
- this tick's ONE task: move each listed PLANS.md entry to the section its heading's dates say it
216
- belongs in (cut and paste, under the existing \`## \` heading — never add, remove, or rename a
217
- \`## \` heading), leave its text verbatim, and change nothing else.
233
+ this run's ONE task: move each listed entry to the section its heading's dates say it belongs in
234
+ (cut and paste, under the existing \`## \` heading — never add, remove, or rename a \`## \`
235
+ heading), leave its text verbatim, and change nothing else. An entry listed under PLANS-DONE.md's
236
+ \`## Done\` with no done date goes back under PLANS.md's \`## Planned\`.
218
237
 
219
238
  Otherwise, pick ONE kind of uncleanliness — dead code, misleading names, commented-out blocks,
220
239
  overly clever constructs, missing or wrong doc comments on public surfaces, inconsistent
221
- style, or deeply nested branching (a function whose if/loop/switch nesting runs four or more
240
+ style, or deeply nested branching (a function whose if/for/switch nesting runs four or more
222
241
  levels deep, or an else-if chain a reader cannot hold; flatten it with early returns, guard
223
242
  clauses, or extracted named helpers) — and sweep every instance of that kind across the tree: grep for it over the source, the
224
- tests, and the markdown docs, and fix them all in this tick. One theme applied everywhere it
225
- holds is one focused change, not one site per tick. Do not change behavior.
243
+ tests, and the markdown docs, and fix them all in this run. One theme applied everywhere it
244
+ holds is one focused change, not one site per run. Do not change behavior.
226
245
  ${searchGuidance("clean")}
227
246
  Grep is your detector:
228
247
  - an exported name with a single hit across the tree is dead;
@@ -232,23 +251,23 @@ Grep is your detector:
232
251
  file's indent width (for 2-space code \`^ {10,}(if|for|while|switch) \\(\`, for 4-space
233
252
  Python \`^ {16,}(if|for|while) \`). Hits are candidates, not proof: an object literal or class
234
253
  body also adds indentation, so read the function and confirm the nesting before you count it.
235
- Examples of a kind: comments that still name a removed mechanism; doc lines over 100 columns in
236
- one directory; doc comments citing a renamed helper.
254
+ Examples of a kind: comments that still name a removed mechanism; comments citing a PLANS.md
255
+ entry title that no longer exists; doc comments citing a renamed helper.
237
256
  Keep the diff under about 300 changed lines. When the kind has more instances than that, sweep
238
257
  one directory or subsystem completely instead — still one kind of fix throughout — and say in
239
258
  your WHY which instances remain.
240
- Internal-only exports are caught by test/exports.test.ts in the suite, so do not spend a tick
259
+ Internal-only exports are caught by test/exports.test.ts in the suite, so do not spend a run
241
260
  on them. A rename or deletion is complete only when a grep for the old name over the source, the
242
261
  tests, and the markdown docs finds nothing stale; a doc comment you write or fix is a claim about
243
262
  the code — check it against the code before you end.`,
244
263
  },
245
264
  {
246
- id: "dry",
265
+ id: "dedupe",
247
266
  tier: "default",
248
- title: "repetition remover",
267
+ title: "duplication remover",
249
268
  find: `Find ONE instance of meaningful repetition — duplicated logic, copy-pasted blocks, or
250
269
  parallel structures that should share a helper — and factor it out.
251
- ${searchGuidance("dry")}
270
+ ${searchGuidance("dedupe")}
252
271
  Repetition shows up in grep before it shows up in reading: search for a distinctive expression,
253
272
  error message, or sequence of calls and see where else it recurs. Factor it out into a single
254
273
  well-named place and update all call sites. Do not abstract things that are merely superficially
@@ -267,9 +286,9 @@ serializes what could overlap, unnecessary subprocess spawns, or unbounded growt
267
286
  over time.
268
287
  ${searchGuidance("perf")}
269
288
  Then:
270
- - Hot paths are where the process actually spends time — pollers, per-tick loops, anything
289
+ - Hot paths are where the process actually spends time — pollers, repeating per-run work, anything
271
290
  called per request or per line of a growing file — so start from those entry points (grep for
272
- the poll/interval/loop sites), not from a file listing.
291
+ the poll/interval/for-while sites), not from a file listing.
273
292
  - Pick the ONE with the best ratio of measured benefit to risk.
274
293
  - Before changing anything, convince yourself the cost is real (measure or reason from actual
275
294
  data sizes — a quick timing in a scratch script is ideal).
@@ -285,46 +304,49 @@ exists, there is nothing to do.`,
285
304
  find: `Act as a first-time user of this product: follow the README's usage instructions literally and check outputs against what the docs promise. You never edit source, tests, or docs — BUGS.md is your only write.
286
305
 
287
306
  Steps:
288
- 1. Pick ONE flow. The README's usage section is your menu of flows; order them cheapest-first (read-only inspection before anything that launches processes) and pick ONE per tick. Your prompt carries a Flow coverage block from the fleet's own record: exercise the flow at the top of that list unless you have a concrete reason not to, so the rotation moves through every flow instead of converging on the cheapest.
289
- 2. Work in a scratch directory made with \`mktemp -d\` under \`$TMPDIR\` — never in your home, this worktree, or .tumwater/. Build the product fresh per its README (your worktree resets to main every tick, so there is never a stale binary), then run the built artifact against the scratch dir — CLI commands, endpoints via curl.
307
+ 1. Pick ONE flow. The README's usage section is your menu of flows; order them cheapest-first (read-only inspection before anything that launches processes) and pick ONE per run. Your prompt carries a Flow coverage block from the team's own record: exercise the flow at the top of that list unless you have a concrete reason not to, so the rotation moves through every flow instead of converging on the cheapest.
308
+ 2. Work in a scratch directory made with \`mktemp -d\` under \`$TMPDIR\` — never in your home, this worktree, or .tumwater/. Build the product fresh per its README (your worktree resets to main every run, so there is never a stale binary), then run the built artifact against the scratch dir — CLI commands, endpoints via curl.
290
309
  3. Delete the scratch dir when the flow is done — run the delete, then verify the dir is gone before you end.
291
- 4. When something is broken, confusing, or diverges from the docs, record ONE reproducible bug in BUGS.md: exact commands, expected vs actual. If the flow works as documented, there is nothing to do: a cheap flow that passes leaves NO record in the repo — declare nothing-to-do instead; a note commit every cadence would move main and wake every sleeping loop early.
310
+ 4. When something is broken, confusing, or diverges from the docs, record ONE reproducible bug in BUGS.md: exact commands, expected vs actual. If the flow works as documented, there is nothing to do: a cheap flow that passes leaves NO record in the repo — declare nothing-to-do instead; a note commit every cadence would move main and wake every sleeping role early.
292
311
 
293
312
  Safety rails for anything you launch:
294
- - Every process gets a hard time limit and an explicit kill; no listening process may outlive your tick.
313
+ - Every process gets a hard time limit and an explicit kill; no listening process may outlive your run.
295
314
  - Servers bind ephemeral high ports, never the product's documented default port, on loopback only — check a flag that widens the bind (e.g. \`--all-interfaces\`) from its startup banner and stop it at once.
296
315
  - Track each background process by its own pid (in \`cd dir && server & echo $!\`, \`$!\` names the subshell, not the server — \`cd\` first).
297
- - When a flow starts long-running or model-backed processes, prefer a deterministic offline mode (a fake/shim) if the project documents one; otherwise do ONE real bounded run — constrain it to minimal scope (an agent harness: exactly one enabled role and maxConcurrent 1), wall-cap it (~10 min including prefill), background it, and kill its whole process tree when done.
298
- - Use that expensive real mode only when the newest Verified note for the flow is older than a day; after a successful real run append one line under a ## Verified section at the end of BUGS.md (e.g. "- 2026-08-28 run (real): init + one tick landed; status/logs confirm").
316
+ - When a flow starts long-running or model-backed processes, prefer a deterministic offline mode (a fake/shim) if the project documents one; otherwise do ONE real bounded run — constrain it to minimal scope (a minimal setup: exactly one enabled role and maxConcurrent 1), wall-cap it (~10 min including prefill), background it, and kill its whole process tree when done.
317
+ - Use that expensive real mode only when the newest Verified note for the flow is older than a day; after a successful real run append one line under a ## Verified section at the end of BUGS.md (e.g. "- 2026-08-28 run (real): init + one run merged; status/logs confirm").
299
318
 
300
- The FLOW line — required on every tick: your final reply carries one result-carrying line — \`FLOW: <name> — <passed|bug>\` — naming the flow you exercised and whether it passed or filed a bug (spell the name as the coverage block does, e.g. \`FLOW: run (real) — passed\`), placed just before your ending (the nothing-to-do line, or the SUMMARY block when you filed a bug). The verdict is required: a bare \`FLOW: <name>\` with no \`passed|bug\` suffix is not a result and is not recorded, so the rotation never advances. The harness records it for the next tick's coverage block. A passing flow's reply ends with two lines in this form, with the name of the flow you actually exercised in place of <name>:
319
+ The FLOW line — required on every run: your final reply carries one result-carrying line — \`FLOW: <name> — <passed|bug>\` — naming the flow you exercised and whether it passed or filed a bug (spell the name as the coverage block does, e.g. \`FLOW: run (real) — passed\`), placed just before your ending (the nothing-to-do line, or the SUMMARY block when you filed a bug). The verdict is required: a bare \`FLOW: <name>\` with no \`passed|bug\` suffix is not a result and is not recorded, so the rotation never advances. tumwater records it for the next run's coverage block. A passing flow's reply ends with two lines in this form, with the name of the flow you actually exercised in place of <name>:
301
320
  FLOW: <name> — passed
302
321
  ${NOTHING_TO_DO}`,
303
322
  },
304
323
  {
305
- id: "telemetry",
324
+ id: "selfcheck",
306
325
  tier: "default",
307
- title: "runtime telemetry reader",
308
- find: `File ONE bug in BUGS.md's ## Open section per tick, or declare nothing-to-do, from the
309
- <failure-digest> block in your prompt: a deterministic digest of this harness's own event log over
326
+ title: "self-check: files tumwater bugs from its own failure log",
327
+ find: `File ONE bug in BUGS.md's ## Open section per run, or declare nothing-to-do, from the
328
+ <failure-digest> block in your prompt: a deterministic digest of this project's own event log over
310
329
  the last day (per-role outcome counts, each role's time and spend by outcome, normalized error and
311
- warning clusters, review rejections, and what landed). It is your entire evidence base — do not go
312
- looking for the event log or per-role transcripts yourself; the harness injects the digest because
330
+ warning clusters, review rejections, and what merged). It is your entire evidence base — do not go
331
+ looking for the event log or per-role transcripts yourself; tumwater injects the digest because
313
332
  the live log lives outside your worktree.
314
- 1. A cluster is a bug ONLY when the harness's RESPONSE to it is wrong — a failure that raised no
315
- alarm, drove the wrong state or backoff ladder, latched a stale verdict, or hid itself from
316
- the operator. A mere infrastructure failure (the model server was slow, pi exited non-zero)
333
+ 1. A cluster is a bug ONLY when tumwater's RESPONSE to it is wrong — a failure that raised no
334
+ alarm, drove the wrong state or sleep ladder, latched a stale verdict, or hid itself from
335
+ the user. A mere infrastructure failure (the model server was slow, pi exited non-zero)
317
336
  is weather, not a bug: filing it produces an entry no bugfix run can act on.
318
- 2. Read the digest for that wrong response — 44 identical errors that raised no warning, a tick
337
+ 2. Read the digest for that wrong response — 44 identical errors that raised no warning, a run
319
338
  that failed in 200 ms then climbed the idle ladder, a cluster that begins on the date a
320
- specific commit landed.
321
- 3. Rank what you would file by LOSS, not by tick count: the digest's time-and-spend table and
339
+ specific commit merged.
340
+ 3. Rank what you would file by LOSS, not by run count: the digest's time-and-spend table and
322
341
  top loss causes price each cause in agent-hours and dollars, and a cluster that burned hours
323
342
  outranks one that burned seconds — cite its cost when it is the reason you file.
324
- 4. Before filing, check BUGS.md's ## Open section and \`git log --grep="tumwater(telemetry)"\`
325
- for an entry that already names this cluster — no duplicate filings.
343
+ 4. Before filing, check BUGS.md's ## Open section and \`git log ${roleCommitGrep("selfcheck")}\`
344
+ for an entry that already names this cluster — no duplicate filings. When that Open entry
345
+ carries a ${WAITING_FOR_FAILURE_PREFIX}…** note and the cluster failed again after the
346
+ note's date, add the new occurrence under the entry (time, merged commit, failure message)
347
+ and delete the note line, instead of filing a duplicate.
326
348
  5. File it: cite the cluster's normalized key plus the correlated \`merged\` commit in the
327
- entry, so the bugfix loop can reproduce it.
349
+ entry, so the bugfix role can reproduce it.
328
350
  BUGS.md is your only write; never edit source, tests, or docs. If every cluster is ordinary
329
351
  infrastructure weather or already filed, there is nothing to do.`,
330
352
  },
@@ -355,7 +377,7 @@ Then:
355
377
  - Grep for those sinks in this project's own language and pick ONE hit. Trace it back to its
356
378
  source: it is real only when you can name the input an attacker controls, the path it
357
379
  travels, and the missing check. Read every caller on that path — a guard upstream already
358
- closes it — and a sink fed only by constants or the operator's own trusted config is not a
380
+ closes it — and a sink fed only by constants or the user's own trusted config is not a
359
381
  finding.
360
382
  - Prove it with a test that feeds the hostile input (a \`../\` path, a shell metacharacter, an
361
383
  oversized body, a foreign Origin) and fails before your fix. Then fix it at the boundary —
@@ -389,14 +411,14 @@ concurrent processes or tasks — for these failure modes:
389
411
  rejection handler) where the caller needs to know;
390
412
  - cleanup skipped on the error path: a leaked lock file, child process, file handle, listener,
391
413
  or temp directory;
392
- - a retry with no bound or backoff, or a queue, cache, log, or map that only ever grows;
414
+ - a retry with no bound or sleep, or a queue, cache, log, or map that only ever grows;
393
415
  - a read-modify-write that two processes or tasks can interleave, losing one update.
394
416
  ${searchGuidance("robustness")}
395
417
  Then:
396
418
  - Grep for those patterns in this project's own language and pick ONE hit on a path that
397
419
  actually runs. Read its callers: it is real only when you can name the concrete fault (the
398
420
  process is killed during this write, this file is empty after a crash, this child never
399
- exits) and the wrong outcome it causes (lost state, a stuck loop, a crash, a silently wrong
421
+ exits) and the wrong outcome it causes (lost state, a stuck role, a crash, a silently wrong
400
422
  answer).
401
423
  - Prove it with a test that injects that fault — a truncated file, a fake that throws or
402
424
  hangs, a timer that never fires — and fails before your fix; then make the code handle it
@@ -423,75 +445,31 @@ arguments, config files, environment), and rough edges you meet while running th
423
445
  {
424
446
  id: "steward",
425
447
  tier: "default",
426
- title: "project steward",
448
+ title: "backlog curator",
427
449
  find: `Make ONE curation move on this project's records — the most valuable one.
428
- 1. Re-read the initial prompt, PRINCIPLES.md, PLANS.md, BUGS.md — and QUESTIONS.md if it
450
+ 1. Re-read the brief, PRINCIPLES.md, PLANS.md, BUGS.md — and QUESTIONS.md if it
429
451
  exists — and skim the codebase's shape (sizes, module list, test count).
430
452
  2. Then make ONE curation move, the most valuable one:
431
- - delete or merge stale/duplicative/superseded PLANS.md entries (with a one-line epitaph in
432
- the entry's place or in Done);
433
- - flag drift between what is being built and the initial prompt as a PLANS.md note;
453
+ - delete or merge stale/duplicative/superseded PLANS.md entries: move each one under
454
+ PLANS.md's ## Done with a one-line epitaph as its body (tumwater archives it to
455
+ PLANS-DONE.md when your change commits), keeping the entry's title, because
456
+ \`plans-citations.test.ts\` fails when a \`PLANS.md "<title>"\` citation in a \`src/\` or
457
+ \`test/\` comment matches no heading;
458
+ - flag drift between what is being built and the brief as a PLANS.md note;
434
459
  - tighten or update a principle or complexity budget in PRINCIPLES.md;
435
460
  - record a structural risk in BUGS.md;
436
- - promote a recurring non-\`none\` \`gap:\` tag — three or more retained Fixed entries
437
- carrying it — into a PLANS.md entry for the infrastructure that would retire it, citing
438
- those entries. ${VALIDATION_GAP_TALLY}
439
- - compress an overflowing ## Done or ## Fixed section (rules below).
461
+ - promote a recurring non-\`none\` \`gap:\` tag — three or more Fixed entries carrying it —
462
+ into a PLANS.md entry for the infrastructure that would retire it, citing those entries.
463
+ ${VALIDATION_GAP_TALLY}
440
464
  You edit only markdown — never source.
441
465
 
442
- Reading the backlog files: you may see PLANS.md and BUGS.md whole, but do it cheaply — they run to
443
- hundreds of KB. The prompt's <backlog-index> block lists every Planned and Open entry with its
444
- line range; read those from it, and read Done/Fixed entries by line range only where your move
445
- needs their bodies. For the compression moves below, an entry's
446
- heading line plus a \`grep -n\` for its landing citation (the "tick N (\`<sha>\`)" form) supply
447
- everything the one-line record needs — except a Fixed entry's \`gap:\` suffix, which comes from the
448
- \`**Validation gap:**\` line in its body: read that one line (\`grep -n 'Validation gap' FILE\`), not
449
- the whole body.
466
+ Reading the backlog files: PLANS.md and BUGS.md hold open work, so read them whole when your move
467
+ needs it. Finished entries live in PLANS-DONE.md and BUGS-FIXED.md, newest first, and those files
468
+ only grow: never read them whole. Search them with \`grep -n\`, and read an entry by its line range
469
+ only where your move needs its body. The prompt's <backlog-index> block lists the newest ones.
470
+ Finished history is not curated: nothing reads the archive files whole, so they are never
471
+ compressed or trimmed.
450
472
 
451
- Compressing PLANS.md ## Done — PLANS.md's ## Done section is curated to stay bounded:
452
- - Keep the ten most recent entries verbatim (newest first, by position in file) and compress
453
- older ones to one line each:
454
- \`- <title> (planned YYYY-MM-DD, done YYYY-MM-DD; commit(s) <sha>[, <sha>])\` — title and
455
- dates from the entry's heading.
456
- - The hashes are the LANDING commit(s): an explicit landing citation in the entry body (the
457
- "tick N (\`<sha>\`)" form naming the commit that landed it), else git log on main, whose
458
- self-explaining subjects name the role and describe the change.
459
- - Never use a verification or base reference ("Verified … against main \`<sha>\`", "at HEAD
460
- \`<sha>\`") as the record's hash — bodies citing several shas need the one cited as having
461
- landed the work — and when no landing commit exists (a plan closed without code change says
462
- so in its Done note) omit the commit(s) field rather than guess.
463
- - The one-line form keeps every existing cross-reference resolvable: references cite titles or
464
- commit hashes, both preserved.
465
-
466
- Compressing BUGS.md ## Fixed — BUGS.md's ## Fixed section is curated to stay bounded by the same
467
- policy:
468
- - Keep the ten most recent entries verbatim (newest first) and compress older ones to one line
469
- each: \`- <symptom headline> (<the heading's own date clause>; commit <sha>; gap: <tag>)\` —
470
- carrying the entry's validation-gap tag as a suffix, and omitting the \`gap: <tag>\` suffix
471
- entirely when the tag is \`none\` (so the common case costs nothing).
472
- - The headline comes from the entry's heading, and the date clause is copied from that heading
473
- as-is: BUGS.md headings vary across found/reported/re-recorded × fixed/closed/resolved and
474
- may carry extra notes inside their parentheses, so do not normalize or fabricate dates; when
475
- a heading carries no dates at all, omit that part of the line.
476
- - The commit is the entry's LANDING commit — the one that merged the fix to main: an explicit
477
- landing citation in the entry body (the "tick N (\`<sha>\`)" form naming the fix commit
478
- itself), else git log on main, whose self-explaining subjects name the role and describe the
479
- change; never use a verification reference ("Verified … on main \`<sha>\`", "at HEAD
480
- \`<sha>\`") as the record's hash — bodies citing several shas need the one cited as having
481
- landed the fix.
482
- - When no landing commit exists (an entry closed without code change says so in its
483
- **Resolution:** note) omit the \`commit\` field rather than guess, keeping the \`gap: <tag>\`
484
- suffix (the no-commit variant reads \`- <symptom headline> (<date clause>; gap: <tag>)\`, and
485
- plain \`(<date clause>)\` when the tag is \`none\`).
486
- ${VALIDATION_GAP_GUIDANCE}
487
-
488
- Rules for both compressions:
489
- - Never compress an entry carrying a standing **Refused …** note — the objection stands until
490
- a human or director edits it, and compression would bury it; such entries stay full (they are
491
- rare).
492
- - Compression is lossy on purpose: pre-compression text stays in git history — no archive file.
493
- - One curation move per tick still holds: one steward tick compresses one section's overflow
494
- (or makes any other planned move) — a large backlog takes several ticks to reach the window,
495
- each shrinking the file by tens of KB; once at the window it stays bounded.`,
473
+ ${VALIDATION_GAP_GUIDANCE}`,
496
474
  },
497
475
  ];