tumwater 0.1.3 → 0.3.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 (482) hide show
  1. package/README.md +77 -28
  2. package/dist/build-info.json +2 -2
  3. package/dist/src/agent/agent-args.js +23 -0
  4. package/dist/src/agent/agent-backend.js +9 -7
  5. package/dist/src/agent/backend-traits.js +77 -0
  6. package/dist/src/agent/claude/claude-account.js +81 -161
  7. package/dist/src/agent/claude/claude-args.js +19 -19
  8. package/dist/src/agent/claude/claude-backend.js +58 -48
  9. package/dist/src/agent/claude/claude-env.js +7 -3
  10. package/dist/src/agent/claude/claude-stream.js +11 -19
  11. package/dist/src/agent/claude/claude-write-guard.js +49 -0
  12. package/dist/src/agent/claude/write-guard-hook.js +13 -0
  13. package/dist/src/agent/codex/codex-account.js +119 -0
  14. package/dist/src/agent/codex/codex-args.js +181 -0
  15. package/dist/src/agent/codex/codex-backend.js +279 -0
  16. package/dist/src/agent/codex/codex-catalog.js +97 -0
  17. package/dist/src/agent/codex/codex-env.js +18 -0
  18. package/dist/src/agent/codex/codex-hook-trust.js +246 -0
  19. package/dist/src/agent/codex/codex-patch-paths.js +36 -0
  20. package/dist/src/agent/codex/codex-rollout.js +179 -0
  21. package/dist/src/agent/codex/codex-stream.js +402 -0
  22. package/dist/src/agent/codex/codex-write-guard.js +86 -0
  23. package/dist/src/agent/codex/write-guard-hook.js +12 -0
  24. package/dist/src/agent/image-input.js +112 -0
  25. package/dist/src/agent/notes-shim.js +40 -0
  26. package/dist/src/agent/opencode/opencode-args.js +60 -0
  27. package/dist/src/agent/opencode/opencode-backend.js +258 -0
  28. package/dist/src/agent/opencode/opencode-catalog.js +210 -0
  29. package/dist/src/agent/opencode/opencode-config.js +193 -0
  30. package/dist/src/agent/opencode/opencode-env.js +35 -0
  31. package/dist/src/agent/opencode/opencode-session-id.js +36 -0
  32. package/dist/src/agent/opencode/opencode-stream.js +278 -0
  33. package/dist/src/agent/opencode/write-guard-plugin/index.js +48 -0
  34. package/dist/src/agent/role-notes-write.js +16 -33
  35. package/dist/src/agent/run-agent.js +475 -381
  36. package/dist/src/agent/run-settle.js +214 -0
  37. package/dist/src/agent/session-ledger.js +142 -16
  38. package/dist/src/agent/subscription-account.js +220 -0
  39. package/dist/src/agent/write-guard.js +148 -0
  40. package/dist/src/backlog/backlog-archive.js +487 -0
  41. package/dist/src/backlog/backlog-cli-view.js +280 -0
  42. package/dist/src/backlog/backlog-cli.js +384 -0
  43. package/dist/src/backlog/backlog-commit.js +4 -5
  44. package/dist/src/backlog/backlog-eligibility.js +354 -132
  45. package/dist/src/backlog/backlog-index.js +149 -0
  46. package/dist/src/backlog/backlog-md.js +132 -22
  47. package/dist/src/backlog/backlog-parts.js +254 -0
  48. package/dist/src/backlog/backlog-release.js +117 -0
  49. package/dist/src/backlog/backlog-render.js +89 -11
  50. package/dist/src/backlog/backlog-structure.js +271 -125
  51. package/dist/src/backlog/backlog-write.js +121 -471
  52. package/dist/src/backlog/backlog.js +129 -17
  53. package/dist/src/backlog/question-answer.js +345 -0
  54. package/dist/src/baseline/main-baseline.js +157 -101
  55. package/dist/src/baseline/main-culprit.js +94 -0
  56. package/dist/src/baseline/main-guardrails.js +209 -0
  57. package/dist/src/baseline/main-red.js +164 -55
  58. package/dist/src/baseline/main-revert.js +133 -0
  59. package/dist/src/baseline/main-watch.js +184 -0
  60. package/dist/src/brief/brief-edit.js +41 -0
  61. package/dist/src/{brief.js → brief/brief.js} +38 -33
  62. package/dist/src/budget/budget.js +55 -28
  63. package/dist/src/budget/fallback-breaker.js +31 -31
  64. package/dist/src/build/build-check-detect.js +25 -16
  65. package/dist/src/build/build-check-events.js +87 -22
  66. package/dist/src/build/build-check-report.js +66 -27
  67. package/dist/src/build/build-check-scoped.js +64 -68
  68. package/dist/src/build/build-check.js +17 -15
  69. package/dist/src/build/build-info.js +3 -3
  70. package/dist/src/build/build-stage.js +31 -35
  71. package/dist/src/build/dep-install.js +21 -21
  72. package/dist/src/build/host-sleep.js +1 -1
  73. package/dist/src/change/change-data.js +131 -37
  74. package/dist/src/change/change-render.js +56 -14
  75. package/dist/src/cli/brief-command.js +9 -8
  76. package/dist/src/cli/cli-args.js +133 -28
  77. package/dist/src/cli/cli-command-args.js +82 -21
  78. package/dist/src/cli/cli-editor.js +15 -2
  79. package/dist/src/cli/cli-flag-specs.js +180 -50
  80. package/dist/src/cli/cli-init.js +51 -0
  81. package/dist/src/cli/cli-marker-commands.js +14 -11
  82. package/dist/src/cli/cli-query-commands.js +325 -224
  83. package/dist/src/cli/cli-repo-gate.js +12 -2
  84. package/dist/src/cli/cli-role-command.js +420 -0
  85. package/dist/src/cli/cli-start-summary.js +160 -0
  86. package/dist/src/cli/cli-start.js +453 -0
  87. package/dist/src/cli/completion.js +202 -17
  88. package/dist/src/cli/config-commands.js +51 -25
  89. package/dist/src/cli/follow-view.js +75 -0
  90. package/dist/src/cli/help.js +413 -157
  91. package/dist/src/cli/log-commands.js +234 -62
  92. package/dist/src/cli/notify-command.js +33 -18
  93. package/dist/src/cli/question-commands.js +215 -231
  94. package/dist/src/cli.js +154 -49
  95. package/dist/src/collections.js +84 -18
  96. package/dist/src/concurrency/check-permit.js +35 -19
  97. package/dist/src/concurrency/lock.js +22 -17
  98. package/dist/src/concurrency/provider-lease.js +105 -0
  99. package/dist/src/concurrency/semaphore.js +344 -46
  100. package/dist/src/config/config-aliases.js +105 -0
  101. package/dist/src/config/config-editable-keys.js +16 -4
  102. package/dist/src/config/config-fallbacks.js +416 -0
  103. package/dist/src/config/config-field-checks.js +58 -19
  104. package/dist/src/config/config-keys.js +182 -0
  105. package/dist/src/config/config-live.js +113 -22
  106. package/dist/src/config/config-request.js +137 -0
  107. package/dist/src/config/config-schema.js +58 -39
  108. package/dist/src/config/config-selector-checks.js +123 -0
  109. package/dist/src/config/config-validation-agents.js +80 -0
  110. package/dist/src/config/config-validation-model.js +116 -0
  111. package/dist/src/config/config-validation.js +201 -175
  112. package/dist/src/config/config-views.js +202 -346
  113. package/dist/src/config/config-write-core.js +135 -0
  114. package/dist/src/config/config-write.js +219 -391
  115. package/dist/src/config/config.js +102 -81
  116. package/dist/src/config/model-selector.js +44 -18
  117. package/dist/src/doctor/doctor-backlog-bugs.js +287 -0
  118. package/dist/src/doctor/doctor-backlog-plans.js +263 -0
  119. package/dist/src/doctor/doctor-backlog.js +191 -161
  120. package/dist/src/doctor/doctor-check-names.js +81 -0
  121. package/dist/src/doctor/doctor-checks.js +229 -305
  122. package/dist/src/doctor/doctor-claude-checks.js +145 -0
  123. package/dist/src/doctor/doctor-codex-checks.js +279 -0
  124. package/dist/src/doctor/doctor-contention-checks.js +380 -0
  125. package/dist/src/doctor/doctor-holds.js +181 -104
  126. package/dist/src/doctor/doctor-install.js +31 -0
  127. package/dist/src/doctor/doctor-launch-services.js +2 -2
  128. package/dist/src/doctor/doctor-model-checks.js +496 -270
  129. package/dist/src/doctor/doctor-notify.js +5 -7
  130. package/dist/src/doctor/doctor-opencode-checks.js +162 -0
  131. package/dist/src/doctor/doctor-orphans.js +189 -69
  132. package/dist/src/doctor/doctor-project-checks.js +303 -0
  133. package/dist/src/doctor/doctor-render.js +36 -9
  134. package/dist/src/doctor/doctor.js +145 -50
  135. package/dist/src/doctor/image-probe.js +257 -0
  136. package/dist/src/doctor/outcome.js +3 -2
  137. package/dist/src/doctor/probe.js +60 -0
  138. package/dist/src/events/event-format.js +363 -155
  139. package/dist/src/events/event-labels.js +123 -0
  140. package/dist/src/events/event-legacy.js +164 -0
  141. package/dist/src/events/event-read.js +74 -38
  142. package/dist/src/events/event-tally.js +16 -0
  143. package/dist/src/events/event-window.js +83 -27
  144. package/dist/src/events/events.js +47 -26
  145. package/dist/src/events/notify.js +85 -35
  146. package/dist/src/failure/failure-cluster.js +23 -20
  147. package/dist/src/failure/failure-data.js +140 -92
  148. package/dist/src/failure/failure-render.js +97 -78
  149. package/dist/src/failure/failure-state-change.js +45 -33
  150. package/dist/src/failure/time-spend.js +166 -82
  151. package/dist/src/files/file-queue.js +16 -4
  152. package/dist/src/files/files.js +129 -41
  153. package/dist/src/files/json-files.js +3 -3
  154. package/dist/src/files/json-object.js +45 -9
  155. package/dist/src/files/stat-cache.js +2 -2
  156. package/dist/src/files/tail.js +2 -2
  157. package/dist/src/gates/bootstrap-gates.js +8 -8
  158. package/dist/src/gates/budget-gates.js +361 -52
  159. package/dist/src/gates/disk-gate.js +18 -18
  160. package/dist/src/gates/gate-polls.js +201 -103
  161. package/dist/src/gates/maintenance-quota.js +34 -37
  162. package/dist/src/gates/pause-gates.js +33 -15
  163. package/dist/src/gates/readiness.js +8 -3
  164. package/dist/src/gates/role-cap-gates.js +23 -28
  165. package/dist/src/gates/startup-gate.js +154 -48
  166. package/dist/src/gates/streak-gate.js +67 -41
  167. package/dist/src/git/commit-message.js +80 -48
  168. package/dist/src/git/git-diff.js +29 -23
  169. package/dist/src/git/git-run.js +87 -46
  170. package/dist/src/git/git.js +114 -92
  171. package/dist/src/git/slot-salvage.js +253 -0
  172. package/dist/src/git/slots-state.js +18 -9
  173. package/dist/src/git/worktree-pool.js +150 -49
  174. package/dist/src/git/worktree-use.js +14 -20
  175. package/dist/src/git/worktree.js +108 -51
  176. package/dist/src/gui/gui-admin-endpoints.js +96 -0
  177. package/dist/src/gui/gui-args.js +88 -21
  178. package/dist/src/gui/gui-backlog-commands.js +297 -0
  179. package/dist/src/gui/gui-backlog-endpoints.js +155 -0
  180. package/dist/src/gui/gui-command.js +9 -14
  181. package/dist/src/gui/gui-config-commands.js +462 -0
  182. package/dist/src/gui/gui-endpoint-commands.js +17 -716
  183. package/dist/src/gui/gui-endpoint-common.js +49 -0
  184. package/dist/src/gui/gui-endpoints.js +13 -331
  185. package/dist/src/gui/gui-history-endpoints.js +301 -0
  186. package/dist/src/gui/gui-operator-commands.js +240 -0
  187. package/dist/src/gui/gui-prompt-commands.js +231 -0
  188. package/dist/src/gui/gui-report-endpoints.js +90 -0
  189. package/dist/src/gui/gui-server.js +33 -9
  190. package/dist/src/gui/gui-team-commands.js +164 -0
  191. package/dist/src/gui/http-body.js +17 -1
  192. package/dist/src/history/history-data.js +166 -203
  193. package/dist/src/history/history-queued.js +147 -0
  194. package/dist/src/history/history-render.js +96 -0
  195. package/dist/src/history/history.js +206 -103
  196. package/dist/src/inbox/inbox-attachments.js +94 -39
  197. package/dist/src/inbox/inbox-cancel.js +16 -15
  198. package/dist/src/inbox/inbox-edit.js +10 -10
  199. package/dist/src/inbox/inbox-submit.js +54 -14
  200. package/dist/src/inbox/inbox-top.js +99 -0
  201. package/dist/src/inbox/inbox.js +49 -44
  202. package/dist/src/inbox/pending-prompt.js +27 -27
  203. package/dist/src/inbox/prompt-commands.js +154 -100
  204. package/dist/src/inbox/prompt-not-before.js +2 -2
  205. package/dist/src/init/init-templates.js +15 -14
  206. package/dist/src/init/init.js +35 -29
  207. package/dist/src/merge/backlog-conflicts.js +335 -0
  208. package/dist/src/{landing/landing-batch.js → merge/merge-batch.js} +100 -93
  209. package/dist/src/merge/merge-cancel.js +53 -0
  210. package/dist/src/merge/merge-check-failures.js +209 -0
  211. package/dist/src/{landing/landing-core.js → merge/merge-core.js} +183 -110
  212. package/dist/src/{landing/landing-diff.js → merge/merge-diff.js} +6 -5
  213. package/dist/src/merge/merge-drain.js +351 -0
  214. package/dist/src/merge/merge-git.js +403 -0
  215. package/dist/src/merge/merge-pipeline.js +111 -0
  216. package/dist/src/merge/merge-post-review.js +90 -0
  217. package/dist/src/{landing/landing-questions.js → merge/merge-questions.js} +9 -6
  218. package/dist/src/merge/merge-queue-render.js +113 -0
  219. package/dist/src/merge/merge-queue.js +224 -0
  220. package/dist/src/merge/merge-requeue.js +102 -0
  221. package/dist/src/merge/merge-slot.js +385 -0
  222. package/dist/src/{landing/landing-stack.js → merge/merge-stack.js} +97 -71
  223. package/dist/src/{landing/landing-merge.js → merge/merge-to-main.js} +151 -82
  224. package/dist/src/merge/merge-top.js +69 -0
  225. package/dist/src/merge/merge-verify.js +214 -0
  226. package/dist/src/notes-cli.js +112 -0
  227. package/dist/src/operator/operator-commands.js +268 -89
  228. package/dist/src/operator/operator-intent.js +130 -82
  229. package/dist/src/operator/operator-requests.js +82 -87
  230. package/dist/src/operator/retire.js +49 -31
  231. package/dist/src/operator/revert.js +179 -0
  232. package/dist/src/orchestrator/orchestrator-launch.js +116 -48
  233. package/dist/src/orchestrator/orchestrator-poll.js +320 -0
  234. package/dist/src/orchestrator/orchestrator-scheduling.js +78 -348
  235. package/dist/src/orchestrator/orchestrator.js +173 -361
  236. package/dist/src/orchestrator/retention.js +66 -15
  237. package/dist/src/orchestrator/scheduling-admit.js +116 -0
  238. package/dist/src/orchestrator/scheduling-scope.js +201 -0
  239. package/dist/src/orchestrator/scheduling-skip.js +185 -0
  240. package/dist/src/orchestrator/startup-migration-steps.js +52 -0
  241. package/dist/src/orchestrator/startup-migrations.js +44 -0
  242. package/dist/src/paths.js +228 -75
  243. package/dist/src/pi/command-shape.js +12 -1
  244. package/dist/src/pi/pi-args.js +30 -5
  245. package/dist/src/pi/pi-backend.js +19 -27
  246. package/dist/src/pi/pi-bin.js +64 -67
  247. package/dist/src/pi/pi-event-line.js +17 -1
  248. package/dist/src/pi/pi-failure.js +87 -0
  249. package/dist/src/pi/pi-listed-models.js +53 -0
  250. package/dist/src/pi/pi-models.js +163 -42
  251. package/dist/src/pi/pi-run-result.js +1 -1
  252. package/dist/src/pi/pi-settings.js +86 -0
  253. package/dist/src/pi/pi-stream.js +137 -113
  254. package/dist/src/pi/pi-watchdogs.js +20 -20
  255. package/dist/src/pi-extension/bounded-output.js +25 -8
  256. package/dist/src/pi-extension/context-budget.js +5 -3
  257. package/dist/src/pi-extension/context-shake.js +54 -21
  258. package/dist/src/pi-extension/context-window.js +36 -0
  259. package/dist/src/pi-extension/full-output.js +5 -12
  260. package/dist/src/pi-extension/strip-thinking.js +79 -0
  261. package/dist/src/pi-extension/trim-system-prompt.js +37 -0
  262. package/dist/src/pi-extension/write-guard.js +37 -0
  263. package/dist/src/process/launch-services.js +11 -11
  264. package/dist/src/process/node-bin.js +16 -0
  265. package/dist/src/process/process-group.js +8 -18
  266. package/dist/src/process/process-table.js +1 -1
  267. package/dist/src/process/process.js +48 -9
  268. package/dist/src/process/run-marker.js +42 -7
  269. package/dist/src/process/supervisor.js +47 -35
  270. package/dist/src/prompt/dialect.js +46 -11
  271. package/dist/src/prompt/gate-notes.js +203 -0
  272. package/dist/src/prompt/gate-prompts.js +201 -188
  273. package/dist/src/prompt/notes-backlog.js +181 -0
  274. package/dist/src/prompt/principles.js +1 -1
  275. package/dist/src/prompt/prompt-followup.js +43 -29
  276. package/dist/src/prompt/prompt.js +255 -172
  277. package/dist/src/redeploy/redeploy-policy.js +29 -24
  278. package/dist/src/redeploy/redeploy-probes.js +1 -1
  279. package/dist/src/redeploy/redeploy.js +7 -6
  280. package/dist/src/redeploy/redeployer.js +78 -70
  281. package/dist/src/redeploy/self-reload.js +3 -2
  282. package/dist/src/report/report-data.js +374 -285
  283. package/dist/src/report/report-fold.js +430 -0
  284. package/dist/src/report/report-main-red.js +55 -0
  285. package/dist/src/report/report-render.js +321 -61
  286. package/dist/src/report/report-types.js +1 -0
  287. package/dist/src/report/report.js +26 -9
  288. package/dist/src/request-timeouts.js +2 -2
  289. package/dist/src/review/known-flakes.js +133 -14
  290. package/dist/src/review/post-merge-review.js +106 -0
  291. package/dist/src/review/protected-edits.js +7 -7
  292. package/dist/src/review/review-followup.js +21 -9
  293. package/dist/src/review/review-precheck.js +77 -33
  294. package/dist/src/review/review-run.js +395 -0
  295. package/dist/src/review/review-verdict.js +16 -2
  296. package/dist/src/review/review.js +172 -356
  297. package/dist/src/review/secret-leaks.js +147 -0
  298. package/dist/src/review/suite-rerun.js +3 -3
  299. package/dist/src/roles/legacy-role-ids.js +21 -0
  300. package/dist/src/roles/legacy-role-migration.js +135 -0
  301. package/dist/src/roles/role-catalog.js +172 -137
  302. package/dist/src/roles/role-guidance.js +112 -44
  303. package/dist/src/roles/role-labels.js +9 -0
  304. package/dist/src/roles/role-render.js +221 -28
  305. package/dist/src/roles/role-view.js +244 -33
  306. package/dist/src/roles/roles.js +37 -35
  307. package/dist/src/roles/runner-ids.js +97 -0
  308. package/dist/src/run/acceptance-greps.js +119 -0
  309. package/dist/src/run/feedback-filings.js +51 -0
  310. package/dist/src/{tick → run}/qa-coverage.js +10 -27
  311. package/dist/src/{tick/tick-apply.js → run/run-apply.js} +166 -136
  312. package/dist/src/run/run-detail-data.js +179 -0
  313. package/dist/src/run/run-detail-render.js +98 -0
  314. package/dist/src/run/run-detail.js +168 -0
  315. package/dist/src/run/run-finalize.js +154 -0
  316. package/dist/src/{tick/tick-outcome.js → run/run-outcome.js} +6 -6
  317. package/dist/src/run/run-prompt.js +304 -0
  318. package/dist/src/{tick/tick-resume.js → run/run-resume.js} +80 -35
  319. package/dist/src/run/run-stage.js +295 -0
  320. package/dist/src/run/run-timing.js +198 -0
  321. package/dist/src/run/run-usage.js +180 -0
  322. package/dist/src/run/run-verdict.js +301 -0
  323. package/dist/src/run/selfcheck-digest.js +40 -0
  324. package/dist/src/run/stage-backlog-checks.js +249 -0
  325. package/dist/src/run/stage-check.js +172 -0
  326. package/dist/src/run/stage-path-checks.js +730 -0
  327. package/dist/src/runner/leftover.js +185 -0
  328. package/dist/src/{loop → runner}/model-fallback.js +13 -12
  329. package/dist/src/runner/revision.js +202 -0
  330. package/dist/src/{loop/loop-fallback.js → runner/runner-fallback.js} +10 -10
  331. package/dist/src/runner/runner-outcome.js +107 -0
  332. package/dist/src/runner/runner-pi.js +433 -0
  333. package/dist/src/{loop/loop-recovery.js → runner/runner-recovery.js} +34 -28
  334. package/dist/src/runner/runner-run.js +625 -0
  335. package/dist/src/runner/runner-state-load.js +268 -0
  336. package/dist/src/runner/runner-state.js +102 -0
  337. package/dist/src/runner/runner.js +350 -0
  338. package/dist/src/scheduling/backoff.js +64 -54
  339. package/dist/src/scheduling/claims.js +46 -26
  340. package/dist/src/scheduling/once-round.js +30 -30
  341. package/dist/src/scheduling/quiet-hours.js +26 -34
  342. package/dist/src/scheduling/scheduling.js +87 -74
  343. package/dist/src/scheduling/{work-landed-cache.js → work-merged-cache.js} +14 -14
  344. package/dist/src/status/status-budget.js +123 -0
  345. package/dist/src/status/status-data.js +106 -191
  346. package/dist/src/status/status-inbox.js +47 -0
  347. package/dist/src/status/status-install.js +26 -0
  348. package/dist/src/status/status-polls.js +70 -59
  349. package/dist/src/status/status-roles.js +131 -0
  350. package/dist/src/{fleet → team}/error-storm.js +16 -16
  351. package/dist/src/{fleet → team}/failure-spread.js +10 -10
  352. package/dist/src/{fleet → team}/orchestrator-info.js +97 -25
  353. package/dist/src/{fleet → team}/reclaim.js +9 -9
  354. package/dist/src/{fleet/fleet-hold.js → team/team-hold.js} +60 -26
  355. package/dist/src/team/team-polls.js +299 -0
  356. package/dist/src/{fleet/fleet-state.js → team/team-state.js} +47 -40
  357. package/dist/src/text/datetime.js +102 -16
  358. package/dist/src/text/format.js +49 -3
  359. package/dist/src/text/markdown.js +8 -5
  360. package/dist/src/text/phrases.js +89 -54
  361. package/dist/src/text/suggest.js +3 -2
  362. package/dist/src/text/text.js +68 -14
  363. package/dist/src/ui/badges.js +165 -93
  364. package/dist/src/ui/gui/gui-client-backlog.js +292 -0
  365. package/dist/src/ui/gui/gui-client-boot.js +221 -42
  366. package/dist/src/ui/gui/gui-client-composer.js +105 -27
  367. package/dist/src/ui/gui/gui-client-drawer-config.js +212 -0
  368. package/dist/src/ui/gui/gui-client-drawer.js +226 -130
  369. package/dist/src/ui/gui/gui-client-feed.js +271 -0
  370. package/dist/src/ui/gui/gui-client-history.js +492 -68
  371. package/dist/src/ui/gui/gui-client-labels.js +23 -0
  372. package/dist/src/ui/gui/gui-client-markdown.js +1 -1
  373. package/dist/src/ui/gui/gui-client-model.js +84 -76
  374. package/dist/src/ui/gui/gui-client-operator.js +112 -78
  375. package/dist/src/ui/gui/gui-client-pending.js +248 -41
  376. package/dist/src/ui/gui/gui-client-report-chart.js +464 -0
  377. package/dist/src/ui/gui/gui-client-report.js +122 -179
  378. package/dist/src/ui/gui/{gui-client-loops.js → gui-client-roles.js} +118 -76
  379. package/dist/src/ui/gui/gui-client-settings.js +180 -20
  380. package/dist/src/ui/gui/gui-client-team.js +252 -0
  381. package/dist/src/ui/gui/gui-client.js +48 -40
  382. package/dist/src/ui/gui/gui-icons.js +0 -2
  383. package/dist/src/ui/gui/gui-page.js +25 -24
  384. package/dist/src/ui/gui/gui-styles.js +46 -38
  385. package/dist/src/ui/progress-data.js +11 -11
  386. package/dist/src/ui/{tick-progress-model.js → run-progress-model.js} +40 -40
  387. package/dist/src/ui/status-model.js +276 -194
  388. package/dist/src/ui/status-payload.js +227 -62
  389. package/dist/src/ui/status-render.js +196 -108
  390. package/dist/src/ui/team-alerts.js +532 -0
  391. package/dist/src/ui/tone.js +11 -11
  392. package/dist/src/ui/transcript-run.js +58 -0
  393. package/dist/src/ui/transcript-tail.js +28 -19
  394. package/dist/src/ui/transcript.js +85 -38
  395. package/dist/src/ui/tui/tui-backlog.js +132 -21
  396. package/dist/src/ui/tui/tui-editor-answer.js +93 -0
  397. package/dist/src/ui/tui/tui-editor-attach.js +105 -0
  398. package/dist/src/ui/tui/tui-editor-backends.js +132 -0
  399. package/dist/src/ui/tui/tui-editor-brief.js +105 -0
  400. package/dist/src/ui/tui/tui-editor-budget.js +159 -0
  401. package/dist/src/ui/tui/tui-editor-claude-reserve.js +24 -0
  402. package/dist/src/ui/tui/tui-editor-concurrency.js +24 -0
  403. package/dist/src/ui/tui/tui-editor-config.js +86 -0
  404. package/dist/src/ui/tui/tui-editor-ctx.js +1 -0
  405. package/dist/src/ui/tui/tui-editor-entry.js +219 -0
  406. package/dist/src/ui/tui/tui-editor-fallback.js +31 -0
  407. package/dist/src/ui/tui/tui-editor-instances.js +37 -0
  408. package/dist/src/ui/tui/tui-editor-instructions.js +136 -0
  409. package/dist/src/ui/tui/tui-editor-interval.js +124 -0
  410. package/dist/src/ui/tui/tui-editor-model.js +29 -0
  411. package/dist/src/ui/tui/tui-editor-notes.js +112 -0
  412. package/dist/src/ui/tui/tui-editor-notify.js +25 -0
  413. package/dist/src/ui/tui/tui-editor-pause.js +255 -0
  414. package/dist/src/ui/tui/tui-editor-prompt.js +90 -0
  415. package/dist/src/ui/tui/tui-editor-provider-caps.js +27 -0
  416. package/dist/src/ui/tui/tui-editor-queued.js +94 -0
  417. package/dist/src/ui/tui/tui-editor-quiet.js +170 -0
  418. package/dist/src/ui/tui/tui-editor-retire.js +81 -0
  419. package/dist/src/ui/tui/tui-editor-role-key.js +76 -0
  420. package/dist/src/ui/tui/tui-editor-role-model.js +28 -0
  421. package/dist/src/ui/tui/tui-editor-search.js +85 -0
  422. package/dist/src/ui/tui/tui-editor-session.js +123 -0
  423. package/dist/src/ui/tui/tui-editor-slots.js +23 -0
  424. package/dist/src/ui/tui/tui-editors.js +185 -0
  425. package/dist/src/ui/tui/tui-frame.js +107 -58
  426. package/dist/src/ui/tui/tui-history.js +16 -12
  427. package/dist/src/ui/tui/tui-input.js +56 -60
  428. package/dist/src/ui/tui/tui-keys.js +106 -1825
  429. package/dist/src/ui/tui/tui-pane-activity.js +102 -0
  430. package/dist/src/ui/tui/tui-pane-backlog.js +269 -0
  431. package/dist/src/ui/tui/tui-pane-brief.js +29 -0
  432. package/dist/src/ui/tui/tui-pane-ctx.js +11 -0
  433. package/dist/src/ui/tui/tui-pane-health.js +174 -0
  434. package/dist/src/ui/tui/tui-pane-history.js +636 -0
  435. package/dist/src/ui/tui/tui-pane-pending.js +369 -0
  436. package/dist/src/ui/tui/tui-pane-queued.js +159 -0
  437. package/dist/src/ui/tui/tui-pane-report.js +154 -0
  438. package/dist/src/ui/tui/tui-pane-session.js +120 -0
  439. package/dist/src/ui/tui/tui-pane-transcript.js +224 -0
  440. package/dist/src/ui/tui/tui-pane.js +125 -44
  441. package/dist/src/ui/tui/tui-panes.js +364 -0
  442. package/dist/src/ui/tui/tui.js +52 -34
  443. package/dist/src/verdict/fix-claim.js +135 -62
  444. package/dist/src/verdict/no-change.js +19 -0
  445. package/dist/src/verdict/refusal.js +80 -24
  446. package/dist/src/verdict/reply-contract.js +51 -28
  447. package/dist/src/version.js +2 -2
  448. package/package.json +5 -2
  449. package/dist/src/agent/mcp/role-notes-server.js +0 -160
  450. package/dist/src/brief-edit.js +0 -42
  451. package/dist/src/cli/cli-run.js +0 -469
  452. package/dist/src/fleet/fleet-polls.js +0 -207
  453. package/dist/src/landing/backlog-conflicts.js +0 -116
  454. package/dist/src/landing/landing-check-failures.js +0 -141
  455. package/dist/src/landing/landing-drain.js +0 -204
  456. package/dist/src/landing/landing-git.js +0 -190
  457. package/dist/src/landing/landing-pipeline.js +0 -96
  458. package/dist/src/landing/landing-queue-render.js +0 -56
  459. package/dist/src/landing/landing-queue.js +0 -149
  460. package/dist/src/landing/landing-slot.js +0 -256
  461. package/dist/src/landing/landing-vetting.js +0 -196
  462. package/dist/src/loop/leftover.js +0 -129
  463. package/dist/src/loop/loop-pi.js +0 -370
  464. package/dist/src/loop/loop-state.js +0 -204
  465. package/dist/src/loop/loop-tick.js +0 -545
  466. package/dist/src/loop/loop.js +0 -315
  467. package/dist/src/loop/revision.js +0 -61
  468. package/dist/src/pi-extension/role-notes.js +0 -40
  469. package/dist/src/roles/loop-ids.js +0 -60
  470. package/dist/src/tick/stage-check.js +0 -302
  471. package/dist/src/tick/telemetry-digest.js +0 -24
  472. package/dist/src/tick/tick-detail-data.js +0 -107
  473. package/dist/src/tick/tick-detail.js +0 -150
  474. package/dist/src/tick/tick-finalize.js +0 -135
  475. package/dist/src/tick/tick-prompt.js +0 -201
  476. package/dist/src/tick/tick-stage.js +0 -223
  477. package/dist/src/tick/tick-timing.js +0 -195
  478. package/dist/src/tick/tick-usage.js +0 -142
  479. package/dist/src/tick/tick-verdict.js +0 -201
  480. package/dist/src/ui/fleet-alerts.js +0 -174
  481. package/dist/src/ui/gui/gui-client-fleet.js +0 -576
  482. package/dist/src/ui/gui/gui-client-sound.js +0 -52
@@ -1,15 +1,22 @@
1
- /** The role catalog: one built-in loop's identity and its role-specific "find something to do"
1
+ /** The role catalog: one built-in role's identity and its role-specific "find something to do"
2
2
  * instruction text. Split out of roles.ts (2026-10-01, organize) so the catalog's embedded
3
3
  * prompt prose lives apart from the derived registries and classification helpers, which stayed
4
4
  * in roles.ts. Pure catalog data — the shared instruction fragments role prompts embed live in
5
5
  * role-guidance.ts (import-only downward, so prompt assembly depends on both without a cycle).
6
6
  * 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";
7
+ import { backlogMoveGuidance, DECOMPOSITION_GUIDANCE, HELD_TAG_PREFIX, NEEDS_REPLAN_NOTE, NEEDS_REVIEW_NOTE, PLAN_QUEUE_GUIDANCE, PLAN_SIZING, PRIOR_HELD_PREFIX, searchGuidance, VALIDATION_GAP_GUIDANCE, VALIDATION_GAP_QUERY, VALIDATION_GAP_TALLY, WAITING_FOR_FAILURE_NOTE, WAITING_FOR_FAILURE_PREFIX, } from "./role-guidance.js";
8
+ import { roleCommitGrep } from "./legacy-role-ids.js";
8
9
  import { NOTHING_TO_DO } from "../verdict/reply-contract.js";
9
- /** The opinionated role catalog. Every loop runs one role; a role's `find` text is
10
- * the role-specific "find something to do" half of the tick prompt.
10
+ /** The trailer the readme role's commits carry and its `git log --grep` reads back; git parses
11
+ * it, so it keeps this spelling. Interpolated because a comment inside the template would
12
+ * become prompt text. */
13
+ const README_TRAILER = "Run: readme #";
14
+ const README_TRAILER_GREP = "^(Run|Tick): readme #"; // vocabulary-ok: legacy name read from old refs or commits
15
+ const README_TRAILER_LEGACY = "Tick: readme #"; // vocabulary-ok: legacy name read from old refs or commits
16
+ /** The opinionated role catalog. Every role has one job; a role's `find` text is
17
+ * the role-specific "find something to do" half of the run prompt.
11
18
  *
12
- * Order matters: it is the scheduling priority when loops are otherwise tied
19
+ * Order matters: it is the scheduling priority when roles are otherwise tied
13
20
  * (e.g. the startup burst), so shipping work (feature, bugfix) outranks hygiene. */
14
21
  export const ROLES = [
15
22
  {
@@ -20,20 +27,27 @@ export const ROLES = [
20
27
  1. The prompt's <backlog-index> block lists PLANS.md's \`## Planned\` entries with each
21
28
  entry's line range; read the one you pick by that range.
22
29
  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
30
+ Skip entries the index block marks \`[blocked: …]\` — \`[blocked: requires …]\` (a
31
+ prerequisite has not merged), \`[blocked: refused]\`, \`[blocked: needs review]\` or
32
+ \`[blocked: needs replan]\`. Skip plans whose entry carries a Refused note, and skip
25
33
  entries already carrying a **Needs review …** note or a ${NEEDS_REPLAN_NOTE}. If PLANS.md
26
34
  is empty or everything is done, there is nothing to do.
27
35
  3. Read only the chosen entry's line range and the code it names.
28
36
  4. A plan too large to finish in this run is not split by you: append the note
29
37
  ${NEEDS_REVIEW_NOTE}
30
38
  under its heading, skip it, and implement the next available plan that fits. You may mark
31
- several oversized entries while scanning, but land exactly one plan.
39
+ several oversized entries while scanning, but land exactly one plan. The held tag you write
40
+ — \`${HELD_TAG_PREFIX}<N>)\` on a Needs-review note, \`${HELD_TAG_PREFIX}<H>)\` on a
41
+ Needs-replan note — is ONE past the count already on the entry: read your own or an earlier
42
+ mark's \`${HELD_TAG_PREFIX}N)\` tag, else the \`${PRIOR_HELD_PREFIX}<N>**\` line a lift left
43
+ behind, else start at 1 — never reset it while the same plan ping-pongs, so three holds
44
+ without a merge reach \`${HELD_TAG_PREFIX}3)\`. A plan that merged and left \`## Planned\`
45
+ carries no marker — the convergence backstop starts fresh there.
32
46
  5. Implement it completely: code, tests, and any docs. The reviewer checks your diff against
33
47
  the entry's files-touched list and acceptance criteria, so land everything the entry
34
48
  promises, or update the entry to say what changed and why. When a plan's anchors no longer
35
49
  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")}
50
+ 6. Mark the plan done in PLANS.md — ${backlogMoveGuidance("PLANS.md", "## Planned", "## Done", "PLANS-DONE.md", "done")}
37
51
  7. Verify last, after the PLANS.md edit, so one run of the project's check covers everything
38
52
  you changed (see "Leave the project working" below).
39
53
  A plan that resists implementation is a finding: refuse it with the objection recorded rather
@@ -45,13 +59,16 @@ than forcing it.`,
45
59
  title: "bug fixer",
46
60
  find: `Fix the SINGLE most important open bug in BUGS.md.
47
61
  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
62
+ line range; read the one you pick by that range. Skip BUGS.md entries the index block marks
63
+ \`[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
64
  latent-bug hunt at the end instead.
51
- 2. Reproduce it if possible: a failing test or a scratch script.
65
+ 2. Reproduce it if possible: a failing test or a scratch script. When it cannot be reproduced
66
+ and this run made its failure message name the cause next time (or found it already does),
67
+ record a Progress note, write ${WAITING_FOR_FAILURE_NOTE} as its own line under the
68
+ heading, and end the run. Do not keep investigating without new evidence.
52
69
  3. Fix it, and add a regression test that fails without the fix — run that test to watch it
53
70
  fail before the fix and pass after.
54
- 4. Mark it fixed in BUGS.md — ${backlogMoveGuidance("BUGS.md", "## Open", "## Fixed")}
71
+ 4. Mark it fixed in BUGS.md — ${backlogMoveGuidance("BUGS.md", "## Open", "## Fixed", "BUGS-FIXED.md", "fixed")}
55
72
  5. In the moved entry, write the required validation-gap trace line (format below).
56
73
  6. Verify last, after the BUGS.md edits, so one run of the project's check covers everything
57
74
  you changed (see "Leave the project working" below).
@@ -76,54 +93,64 @@ within that budget, there is nothing to do.`,
76
93
  1. Check what is already waiting: the prompt's <backlog-index> block lists PLANS.md's
77
94
  \`## Planned\` entries with each entry's line range.
78
95
  - 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,
96
+ independently mergeable sub-plans that cross-reference each other (per PLAN_SIZING below,
80
97
  each with its own acceptance criteria), then remove the note. That split is this run's task.
81
98
  - A plan carrying a ${NEEDS_REPLAN_NOTE} note also outranks adding another plan: read the
82
99
  quoted objections and the code they name, then rewrite the plan so an implementation
83
100
  following it would answer them — correcting the approach or the anchors, tightening the
84
101
  acceptance criteria, splitting it per PLAN_SIZING, or refusing it with the objection
85
102
  recorded when it should not be done — and remove both the note and the quoted objections.
103
+ - When you lift a Needs-review or Needs-replan note (a split or a rewrite) and the change
104
+ has NOT merged, keep the held count instead of letting it reset: remove any existing
105
+ \`**Previously held N**\` line on the surviving parent and every child part the split
106
+ produces, then write \`${PRIOR_HELD_PREFIX}<N>**\` at the lifted note's count on the
107
+ parent and copy it to each child, so exactly one marker survives and heldCount reads the
108
+ lifted count everywhere — a merged parent (one whose plan left \`## Planned\`) leaves no
109
+ marker.
86
110
  - 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),
111
+ are feature instances (one waiting per instance, plus one for the next planner run),
88
112
  end with ${NOTHING_TO_DO} — feature has work, and a waiting plan is refined by the
89
113
  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
114
+ entries — those the index block does not mark \`[blocked: …]\`. When it does not
91
115
  stop, prefer a plan independent of the waiting series, so feature can run it alongside
92
116
  the blocked ones; with more than one feature instance, an independent plan keeps every
93
117
  runner fed.
94
- 2. Choose ONE unplanned feature or improvement worth doing, guided by the initial prompt in the
118
+ 2. Choose ONE unplanned feature or improvement worth doing, guided by the
95
119
  project brief (TUMWATER.md when it exists with the tumwater:prompt markers, else README.md)
96
120
  and by what already exists.
97
121
  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).
122
+ Planned entry, nor any finished plan in PLANS-DONE.md, already covers it — grep the archive
123
+ rather than reading it, and read only the entries whose headings look related.
99
124
  4. Ground the plan in the code: name the actual files and functions it touches, having looked
100
125
  at them in ranges.
101
126
  5. Write it as a short markdown section under \`## Planned\` in PLANS.md: goal, approach, files
102
127
  touched, acceptance criteria.
128
+ ${PLAN_QUEUE_GUIDANCE}
103
129
  ${PLAN_SIZING}
104
130
  ${DECOMPOSITION_GUIDANCE}`,
105
131
  },
106
132
  {
107
133
  id: "readme",
108
134
  tier: "small",
109
- title: "README maintainer",
135
+ title: "brief and README keeper",
110
136
  find: `Keep the project brief — TUMWATER.md when it exists with the tumwater:prompt markers, else
111
137
  README.md — accurate against the actual state of the project.
112
138
  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
139
+ everything that merged since your last sync — your new commits carry a \`${README_TRAILER}N\`
140
+ trailer and older ones \`${README_TRAILER_LEGACY}N\`; \`git log -E --grep='${README_TRAILER_GREP}' -1 --format=%H\`
141
+ names the last one. Read only
115
142
  what those commits touched.
116
- 2. If the brief is already accurate, there is nothing to do: a landing that touched no
143
+ 2. If the brief is already accurate, there is nothing to do: a merge that touched no
117
144
  user-facing surface (commands, flags, config keys, docs) needs no sync.
118
145
  3. The status section (between the tumwater:status markers) describes CURRENT STATE ONLY, and
119
146
  you rewrite it wholesale on each sync — never append to it. It carries exactly two things:
120
147
  (a) a one-line version/capability summary — no command or flag lists, which belong in the
121
148
  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.
149
+ never a copy of their entries, which every run already reads there.
123
150
  4. Keep these out of the status section:
124
151
  - 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
152
+ never stamped into the section, so a merge needs no README commit to refresh it.
153
+ - Per-run merge narrative: merges are recorded by their owning roles in
127
154
  PLANS.md/BUGS.md and git log; stale narrative found in the section is deleted as part of
128
155
  updating it (that is an update, not a loss).
129
156
  If the section exceeds ~1KB it has drifted back into narrative — prune it to the state-only
@@ -132,7 +159,7 @@ README.md — accurate against the actual state of the project.
132
159
  only the director and steward edit.
133
160
  Keep the brief short: a summary, the status, and brief usage; mechanics and reference detail
134
161
  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.`,
162
+ edit the brief between the tumwater:prompt markers.`,
136
163
  },
137
164
  {
138
165
  id: "organize",
@@ -140,8 +167,8 @@ edit the initial prompt between the tumwater:prompt markers.`,
140
167
  title: "code organizer",
141
168
  // Written against the 2026-10-05/06 churn: with minor fixes exhausted and the shared
142
169
  // 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.
170
+ // directory per run (45 of 86 merges in four hours) with no target structure ever
171
+ // stated. Major refactors stay welcome; they must be considered whole and merge whole.
145
172
  find: `Find ONE way the code could be better organized, and restructure it.
146
173
  1. First rank the production source files (not the tests) by \`wc -l\`. A production module
147
174
  several times the project's median file size almost always holds more than one
@@ -149,7 +176,8 @@ edit the initial prompt between the tumwater:prompt markers.`,
149
176
  file of similar size: a test file's shape follows the module it covers. An outlier that is
150
177
  mostly one large function or closure cannot be split in one run: do not start the split,
151
178
  write it as a plan in PLANS.md under ## Planned that states the target structure (which
152
- state and handlers move into which module). Then look for other minor improvements to
179
+ state and handlers move into which module).
180
+ ${PLAN_QUEUE_GUIDANCE} Then look for other minor improvements to
153
181
  the existing structure: a module in the wrong directory, a missing separation between
154
182
  layers, or inconsistent file naming.
155
183
  2. When the minor improvements are exhausted, a major refactor — new directories, a
@@ -176,10 +204,10 @@ organize changes where code lives and how it is divided, not what it does. Updat
176
204
  imports/references so the project still builds and tests still pass. A change is complete only
177
205
  when a grep for every old path and every moved or renamed name — over the source, the tests,
178
206
  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
207
+ scope: `- Do exactly ONE task, then stop — but unlike the other roles' tasks, yours need not be
180
208
  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
209
+ files, and one coherent change merged whole beats the same change spread over many runs.
210
+ Where PRINCIPLES.md asks for one focused change per run, for this role that means one
183
211
  coherent restructure. Complete and correct still beats big and half-done.
184
212
  - Choose the task within your first ~15 tool calls, in a handful of turns. A restructure that
185
213
  would need more than roughly 150 tool calls, or that you could not finish with the project
@@ -191,10 +219,14 @@ and the markdown docs (doc comments, PLANS.md, BUGS.md) — finds no stale refer
191
219
  title: "test coverage improver",
192
220
  find: `Find ONE meaningful gap in unit test coverage — an untested module, branch, or edge case
193
221
  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
222
+ 1. The team's own record of what made past bugs hard to confirm is the first evidence: run
223
+ \`${VALIDATION_GAP_QUERY}\` and read the entry above each hit and its free-text sentence;
224
+ when it names a module, branch or behavior (or the entry's fix touched one), that is the
225
+ first candidate — a \`no-fake\` or \`no-repro\` trace names test infrastructure to build.
226
+ Only when no recent trace names a candidate: Locate it from evidence rather than by reading
227
+ every module — compare the source module list against the test files (a module with no test
228
+ is the first candidate), or run the project's coverage command — for an npm project that is
229
+ \`npm run test:coverage\`, piped through \`tail\` — and pick the file with the most uncovered
198
230
  lines from the deterministic-coverage table at the end of its output — node's own table above
199
231
  it can flip between runs on the same tree, so quote the deterministic numbers.
200
232
  2. Then read only that file and its existing tests — every test that imports it, not just the
@@ -212,17 +244,19 @@ scratch analysis scripts — that is a different, much larger task.`,
212
244
  tier: "default",
213
245
  title: "code cleaner",
214
246
  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.
247
+ this run's ONE task: move each listed entry to the section its heading's dates say it belongs in
248
+ (cut and paste, under the existing \`## \` heading — never add, remove, or rename a \`## \`
249
+ heading), leave its text verbatim, and change nothing else. An entry listed under PLANS-DONE.md's
250
+ \`## Done\` with no done date is already finished and archived there: keep it in place and only add the
251
+ missing \`done YYYY-MM-DD\` to its \`### \` heading — never move it back under PLANS.md's \`## Planned\`.
218
252
 
219
253
  Otherwise, pick ONE kind of uncleanliness — dead code, misleading names, commented-out blocks,
220
254
  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
255
+ style, or deeply nested branching (a function whose if/for/switch nesting runs four or more
222
256
  levels deep, or an else-if chain a reader cannot hold; flatten it with early returns, guard
223
257
  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.
258
+ tests, and the markdown docs, and fix them all in this run. One theme applied everywhere it
259
+ holds is one focused change, not one site per run. Do not change behavior.
226
260
  ${searchGuidance("clean")}
227
261
  Grep is your detector:
228
262
  - an exported name with a single hit across the tree is dead;
@@ -232,23 +266,23 @@ Grep is your detector:
232
266
  file's indent width (for 2-space code \`^ {10,}(if|for|while|switch) \\(\`, for 4-space
233
267
  Python \`^ {16,}(if|for|while) \`). Hits are candidates, not proof: an object literal or class
234
268
  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.
269
+ Examples of a kind: comments that still name a removed mechanism; comments citing a PLANS.md
270
+ entry title that no longer exists; doc comments citing a renamed helper.
237
271
  Keep the diff under about 300 changed lines. When the kind has more instances than that, sweep
238
272
  one directory or subsystem completely instead — still one kind of fix throughout — and say in
239
273
  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
274
+ Internal-only exports are caught by test/exports.test.ts in the suite, so do not spend a run
241
275
  on them. A rename or deletion is complete only when a grep for the old name over the source, the
242
276
  tests, and the markdown docs finds nothing stale; a doc comment you write or fix is a claim about
243
277
  the code — check it against the code before you end.`,
244
278
  },
245
279
  {
246
- id: "dry",
280
+ id: "dedupe",
247
281
  tier: "default",
248
- title: "repetition remover",
282
+ title: "duplication remover",
249
283
  find: `Find ONE instance of meaningful repetition — duplicated logic, copy-pasted blocks, or
250
284
  parallel structures that should share a helper — and factor it out.
251
- ${searchGuidance("dry")}
285
+ ${searchGuidance("dedupe")}
252
286
  Repetition shows up in grep before it shows up in reading: search for a distinctive expression,
253
287
  error message, or sequence of calls and see where else it recurs. Factor it out into a single
254
288
  well-named place and update all call sites. Do not abstract things that are merely superficially
@@ -267,9 +301,9 @@ serializes what could overlap, unnecessary subprocess spawns, or unbounded growt
267
301
  over time.
268
302
  ${searchGuidance("perf")}
269
303
  Then:
270
- - Hot paths are where the process actually spends time — pollers, per-tick loops, anything
304
+ - Hot paths are where the process actually spends time — pollers, repeating per-run work, anything
271
305
  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.
306
+ the poll/interval/for-while sites), not from a file listing.
273
307
  - Pick the ONE with the best ratio of measured benefit to risk.
274
308
  - Before changing anything, convince yourself the cost is real (measure or reason from actual
275
309
  data sizes — a quick timing in a scratch script is ideal).
@@ -285,48 +319,92 @@ exists, there is nothing to do.`,
285
319
  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
320
 
287
321
  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.
322
+ 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.
323
+ 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
324
  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.
325
+ 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
326
 
293
327
  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.
328
+ - Every process gets a hard time limit and an explicit kill; no listening process may outlive your run.
295
329
  - 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
330
  - 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").
331
+ - 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.
332
+ - 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
333
 
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>:
334
+ 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
335
  FLOW: <name> — passed
302
336
  ${NOTHING_TO_DO}`,
303
337
  },
304
338
  {
305
- id: "telemetry",
339
+ id: "selfcheck",
306
340
  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
341
+ title: "self-check: files tumwater bugs from its own failure log",
342
+ find: `File ONE bug in BUGS.md's ## Open section per run, or declare nothing-to-do, from the
343
+ <failure-digest> block in your prompt: a deterministic digest of this project's own event log over
310
344
  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
345
+ warning clusters, review rejections, and what merged). It is your entire evidence base — do not go
346
+ looking for the event log or per-role transcripts yourself; tumwater injects the digest because
313
347
  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)
348
+ The digest ends with a ## Fast merge guardrails section when the post-merge machinery is failing
349
+ quietly (main red over 30 minutes, quarantine aged or oversized). Each line there is tumwater's
350
+ own response failing, so it is fileable as it stands under rule 1.
351
+ 1. A cluster is a bug ONLY when tumwater's RESPONSE to it is wrong — a failure that raised no
352
+ alarm, drove the wrong state or sleep ladder, latched a stale verdict, or hid itself from
353
+ the user. A mere infrastructure failure (the model server was slow, pi exited non-zero)
317
354
  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
355
+ 2. Read the digest for that wrong response — 44 identical errors that raised no warning, a run
319
356
  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
357
+ specific commit merged.
358
+ 3. Rank what you would file by LOSS, not by run count: the digest's time-and-spend table and
322
359
  top loss causes price each cause in agent-hours and dollars, and a cluster that burned hours
323
360
  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.
361
+ 4. Before filing, check BUGS.md's ## Open section and \`git log ${roleCommitGrep("selfcheck")}\`
362
+ for an entry that already names this cluster — no duplicate filings. When that Open entry
363
+ carries a ${WAITING_FOR_FAILURE_PREFIX}…** note and the cluster failed again after the
364
+ note's date, add the new occurrence under the entry (time, merged commit, failure message)
365
+ and delete the note line, instead of filing a duplicate.
326
366
  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.
367
+ entry, so the bugfix role can reproduce it.
328
368
  BUGS.md is your only write; never edit source, tests, or docs. If every cluster is ordinary
329
369
  infrastructure weather or already filed, there is nothing to do.`,
370
+ },
371
+ {
372
+ id: "feedback",
373
+ tier: "default",
374
+ title: "feedback: files tumwater bugs upstream on GitHub",
375
+ find: `File ONE bug per run as a GitHub issue on github.com/znation/tumwater, or declare
376
+ nothing-to-do, from the <failure-digest> block in your prompt: a deterministic digest of this
377
+ project's own event log over the last day (per-role outcome counts, each role's time and spend by
378
+ outcome, normalized error and warning clusters, review rejections, and what merged). It is your
379
+ entire evidence base — do not go looking for the event log or per-role transcripts yourself; tumwater
380
+ injects the digest because the live log lives outside your worktree.
381
+ The digest ends with a ## Fast merge guardrails section when the post-merge machinery is failing
382
+ quietly (main red over 30 minutes, quarantine aged or oversized). Each line there is tumwater's
383
+ own response failing, so it is fileable as it stands under rule 1.
384
+ 1. A cluster is a bug ONLY when tumwater's RESPONSE to it is wrong — a failure that raised no
385
+ alarm, drove the wrong state or sleep ladder, latched a stale verdict, or hid itself from
386
+ the user. A mere infrastructure failure (the model server was slow, pi exited non-zero)
387
+ is weather, not a bug: filing it produces an issue no maintainer can act on.
388
+ 2. Read the digest for that wrong response — 44 identical errors that raised no warning, a run
389
+ that failed in 200 ms then climbed the idle ladder, a cluster that begins on the date a
390
+ specific commit merged.
391
+ 3. Rank what you would file by LOSS, not by run count: the digest's time-and-spend table and
392
+ top loss causes price each cause in agent-hours and dollars, and a cluster that burned hours
393
+ outranks one that burned seconds — cite its cost when it is the reason you file.
394
+ 4. Before filing, dedupe: check the "Previously filed from this install" block in your prompt
395
+ and run \`gh issue list --repo znation/tumwater --search <cluster terms>\` — never file a
396
+ duplicate. When the same cluster is already filed, there is nothing to do.
397
+ 5. File it with \`gh issue create --repo znation/tumwater --title … --body …\` from the shell
398
+ and verify the issue URL in the command's output before you report it. The body cites the
399
+ cluster's normalized key, its count and roles, the correlated \`merged\` commit, and the
400
+ output of \`tumwater version\`; redact absolute paths and secrets — file only what the digest
401
+ itself already shows.
402
+ You never edit files in this repo — \`gh\` is your only write. End every run with the
403
+ ${NOTHING_TO_DO} sentinel; when you filed, one \`FILED: #<n> — <title>\` line rides just above it
404
+ (named as qa's FLOW line is). A run that cannot file because \`gh\` is missing, unauthenticated,
405
+ or failed ends WITHOUT the sentinel, naming the failure in your final prose so tumwater's
406
+ finished-without-changes warning surfaces it. If every cluster is ordinary infrastructure weather
407
+ or already filed, there is nothing to do.`,
330
408
  },
331
409
  {
332
410
  id: "security",
@@ -355,7 +433,7 @@ Then:
355
433
  - Grep for those sinks in this project's own language and pick ONE hit. Trace it back to its
356
434
  source: it is real only when you can name the input an attacker controls, the path it
357
435
  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
436
+ closes it — and a sink fed only by constants or the user's own trusted config is not a
359
437
  finding.
360
438
  - Prove it with a test that feeds the hostile input (a \`../\` path, a shell metacharacter, an
361
439
  oversized body, a foreign Origin) and fails before your fix. Then fix it at the boundary —
@@ -389,14 +467,14 @@ concurrent processes or tasks — for these failure modes:
389
467
  rejection handler) where the caller needs to know;
390
468
  - cleanup skipped on the error path: a leaked lock file, child process, file handle, listener,
391
469
  or temp directory;
392
- - a retry with no bound or backoff, or a queue, cache, log, or map that only ever grows;
470
+ - a retry with no bound or sleep, or a queue, cache, log, or map that only ever grows;
393
471
  - a read-modify-write that two processes or tasks can interleave, losing one update.
394
472
  ${searchGuidance("robustness")}
395
473
  Then:
396
474
  - Grep for those patterns in this project's own language and pick ONE hit on a path that
397
475
  actually runs. Read its callers: it is real only when you can name the concrete fault (the
398
476
  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
477
+ exits) and the wrong outcome it causes (lost state, a stuck role, a crash, a silently wrong
400
478
  answer).
401
479
  - Prove it with a test that injects that fault — a truncated file, a fake that throws or
402
480
  hangs, a timer that never fires — and fails before your fix; then make the code handle it
@@ -423,75 +501,32 @@ arguments, config files, environment), and rough edges you meet while running th
423
501
  {
424
502
  id: "steward",
425
503
  tier: "default",
426
- title: "project steward",
504
+ title: "backlog curator",
427
505
  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
506
+ 1. Re-read the brief, PRINCIPLES.md, PLANS.md, BUGS.md — and QUESTIONS.md if it
429
507
  exists — and skim the codebase's shape (sizes, module list, test count).
430
508
  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;
509
+ - delete or merge stale/duplicative/superseded PLANS.md entries: move each one under
510
+ PLANS.md's ## Done with a one-line epitaph as its body (tumwater archives it to
511
+ PLANS-DONE.md when your change commits), keeping the entry's title, because
512
+ \`plans-citations.test.ts\` fails when a \`PLANS.md "<title>"\` citation in a \`src/\` or
513
+ \`test/\` comment matches no heading;
514
+ - flag drift between what is being built and the brief as a PLANS.md note;
434
515
  - tighten or update a principle or complexity budget in PRINCIPLES.md;
435
516
  - 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).
517
+ - promote a recurring non-\`none\` \`gap:\` tag — three or more Fixed entries carrying it —
518
+ into a PLANS.md entry for the infrastructure that would retire it, citing those entries.
519
+ ${VALIDATION_GAP_TALLY}
520
+ ${PLAN_QUEUE_GUIDANCE}
440
521
  You edit only markdown — never source.
441
522
 
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.
450
-
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}
523
+ Reading the backlog files: PLANS.md and BUGS.md hold open work, so read them whole when your move
524
+ needs it. Finished entries live in PLANS-DONE.md and BUGS-FIXED.md, newest first, and those files
525
+ only grow: never read them whole. Search them with \`grep -n\`, and read an entry by its line range
526
+ only where your move needs its body. The prompt's <backlog-index> block lists the newest ones.
527
+ Finished history is not curated: nothing reads the archive files whole, so they are never
528
+ compressed or trimmed.
487
529
 
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.`,
530
+ ${VALIDATION_GAP_GUIDANCE}`,
496
531
  },
497
532
  ];