tumwater 0.2.0 → 0.4.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.
- package/README.md +27 -13
- package/dist/build-info.json +2 -2
- package/dist/src/agent/agent-args.js +8 -9
- package/dist/src/agent/agent-backend.js +8 -6
- package/dist/src/agent/backend-traits.js +55 -25
- package/dist/src/agent/claude/claude-account.js +71 -204
- package/dist/src/agent/claude/claude-args.js +9 -6
- package/dist/src/agent/claude/claude-backend.js +10 -10
- package/dist/src/agent/claude/claude-env.js +1 -1
- package/dist/src/agent/claude/claude-stream.js +6 -4
- package/dist/src/agent/claude/claude-write-guard.js +49 -0
- package/dist/src/agent/claude/write-guard-hook.js +13 -0
- package/dist/src/agent/codex/codex-account.js +119 -0
- package/dist/src/agent/codex/codex-args.js +181 -0
- package/dist/src/agent/codex/codex-backend.js +279 -0
- package/dist/src/agent/codex/codex-catalog.js +97 -0
- package/dist/src/agent/codex/codex-env.js +18 -0
- package/dist/src/agent/codex/codex-hook-trust.js +246 -0
- package/dist/src/agent/codex/codex-patch-paths.js +36 -0
- package/dist/src/agent/codex/codex-rollout.js +179 -0
- package/dist/src/agent/codex/codex-stream.js +404 -0
- package/dist/src/agent/codex/codex-write-guard.js +86 -0
- package/dist/src/agent/codex/write-guard-hook.js +12 -0
- package/dist/src/agent/image-input.js +29 -24
- package/dist/src/agent/notes-shim.js +11 -12
- package/dist/src/agent/opencode/opencode-args.js +0 -1
- package/dist/src/agent/opencode/opencode-backend.js +12 -9
- package/dist/src/agent/opencode/opencode-catalog.js +55 -29
- package/dist/src/agent/opencode/opencode-config.js +19 -14
- package/dist/src/agent/opencode/opencode-env.js +0 -1
- package/dist/src/agent/opencode/opencode-session-id.js +1 -2
- package/dist/src/agent/opencode/opencode-stream.js +1 -1
- package/dist/src/agent/opencode/write-guard-plugin/index.js +48 -0
- package/dist/src/agent/role-notes-write.js +5 -6
- package/dist/src/agent/run-agent.js +465 -448
- package/dist/src/agent/run-settle.js +214 -0
- package/dist/src/agent/session-ledger.js +86 -16
- package/dist/src/agent/subscription-account.js +220 -0
- package/dist/src/agent/write-guard.js +148 -0
- package/dist/src/backlog/backlog-archive.js +281 -55
- package/dist/src/backlog/backlog-cli-view.js +255 -0
- package/dist/src/backlog/backlog-cli.js +91 -335
- package/dist/src/backlog/backlog-commit.js +20 -13
- package/dist/src/backlog/backlog-eligibility.js +193 -242
- package/dist/src/backlog/backlog-index.js +149 -0
- package/dist/src/backlog/backlog-md.js +54 -6
- package/dist/src/backlog/backlog-parts.js +264 -0
- package/dist/src/backlog/backlog-release.js +134 -0
- package/dist/src/backlog/backlog-render.js +27 -0
- package/dist/src/backlog/backlog-structure.js +99 -156
- package/dist/src/backlog/backlog-write.js +40 -127
- package/dist/src/backlog/backlog.js +21 -6
- package/dist/src/backlog/question-answer.js +21 -15
- package/dist/src/baseline/main-baseline.js +89 -20
- package/dist/src/baseline/main-guardrails.js +136 -0
- package/dist/src/baseline/main-red.js +153 -36
- package/dist/src/baseline/main-watch.js +232 -0
- package/dist/src/brief/brief-edit.js +12 -12
- package/dist/src/brief/brief.js +31 -51
- package/dist/src/budget/budget-fallback-view.js +288 -0
- package/dist/src/budget/budget-wiring.js +158 -0
- package/dist/src/budget/budget.js +31 -20
- package/dist/src/budget/fallback-breaker.js +26 -27
- package/dist/src/build/build-check-detect.js +23 -15
- package/dist/src/build/build-check-events.js +25 -6
- package/dist/src/build/build-check-report.js +49 -9
- package/dist/src/build/build-check-scoped.js +18 -11
- package/dist/src/build/build-check.js +2 -1
- package/dist/src/build/build-info.js +2 -3
- package/dist/src/build/build-stage.js +9 -14
- package/dist/src/build/dep-install.js +65 -3
- package/dist/src/change/change-data.js +123 -31
- package/dist/src/change/change-render.js +46 -5
- package/dist/src/cli/brief-command.js +3 -4
- package/dist/src/cli/cli-args.js +181 -33
- package/dist/src/cli/cli-command-args.js +46 -18
- package/dist/src/cli/cli-editor.js +2 -1
- package/dist/src/cli/cli-flag-specs.js +183 -45
- package/dist/src/cli/cli-init.js +51 -0
- package/dist/src/cli/cli-marker-commands.js +4 -4
- package/dist/src/cli/cli-query-commands.js +291 -598
- package/dist/src/cli/cli-repo-gate.js +11 -1
- package/dist/src/cli/cli-review-commands.js +113 -0
- package/dist/src/cli/cli-role-command.js +525 -0
- package/dist/src/cli/cli-start-summary.js +167 -0
- package/dist/src/cli/{cli-run.js → cli-start.js} +193 -237
- package/dist/src/cli/completion.js +169 -22
- package/dist/src/cli/config-commands.js +58 -26
- package/dist/src/cli/follow-view.js +75 -0
- package/dist/src/cli/help.js +258 -82
- package/dist/src/cli/log-commands.js +164 -85
- package/dist/src/cli/question-commands.js +211 -10
- package/dist/src/cli.js +173 -45
- package/dist/src/collections.js +56 -13
- package/dist/src/concurrency/check-permit.js +20 -3
- package/dist/src/concurrency/lock.js +17 -13
- package/dist/src/concurrency/provider-lease.js +44 -8
- package/dist/src/concurrency/semaphore.js +102 -26
- package/dist/src/config/config-aliases.js +0 -1
- package/dist/src/config/config-editable-keys.js +16 -1
- package/dist/src/config/config-fallbacks.js +94 -56
- package/dist/src/config/config-field-checks.js +40 -10
- package/dist/src/config/config-keys.js +30 -8
- package/dist/src/config/config-live.js +63 -24
- package/dist/src/config/config-request.js +137 -0
- package/dist/src/config/config-schema.js +31 -24
- package/dist/src/config/config-selector-checks.js +123 -0
- package/dist/src/config/config-validation-agents.js +80 -0
- package/dist/src/config/config-validation-model.js +116 -0
- package/dist/src/config/config-validation.js +169 -222
- package/dist/src/config/config-views.js +136 -54
- package/dist/src/config/config-write-core.js +135 -0
- package/dist/src/config/config-write.js +164 -265
- package/dist/src/config/config.js +53 -38
- package/dist/src/config/model-selector.js +34 -34
- package/dist/src/doctor/doctor-backlog-bugs.js +330 -0
- package/dist/src/doctor/doctor-backlog-plans.js +398 -0
- package/dist/src/doctor/doctor-backlog.js +249 -512
- package/dist/src/doctor/doctor-check-names.js +85 -0
- package/dist/src/doctor/doctor-checks.js +61 -593
- package/dist/src/doctor/doctor-claude-checks.js +142 -0
- package/dist/src/doctor/doctor-codex-checks.js +276 -0
- package/dist/src/doctor/doctor-contention-checks.js +506 -0
- package/dist/src/doctor/doctor-fallback-checks.js +130 -0
- package/dist/src/doctor/doctor-holds.js +80 -66
- package/dist/src/doctor/doctor-install.js +2 -1
- package/dist/src/doctor/doctor-model-checks.js +216 -537
- package/dist/src/doctor/doctor-notify.js +9 -5
- package/dist/src/doctor/doctor-opencode-checks.js +164 -0
- package/dist/src/doctor/doctor-orphans.js +182 -63
- package/dist/src/doctor/doctor-pi-checks.js +62 -0
- package/dist/src/doctor/doctor-project-checks.js +397 -0
- package/dist/src/doctor/doctor.js +126 -77
- package/dist/src/doctor/image-probe.js +21 -8
- package/dist/src/doctor/outcome.js +3 -2
- package/dist/src/doctor/probe.js +21 -12
- package/dist/src/events/event-format.js +185 -89
- package/dist/src/events/event-labels.js +11 -5
- package/dist/src/events/event-legacy.js +39 -15
- package/dist/src/events/event-read.js +52 -39
- package/dist/src/events/event-tally.js +16 -0
- package/dist/src/events/event-window.js +80 -26
- package/dist/src/events/events.js +30 -13
- package/dist/src/events/notify.js +7 -7
- package/dist/src/failure/failure-cluster.js +12 -12
- package/dist/src/failure/failure-data.js +65 -60
- package/dist/src/failure/failure-render.js +29 -21
- package/dist/src/failure/failure-state-change.js +17 -12
- package/dist/src/failure/time-spend.js +35 -35
- package/dist/src/files/file-queue.js +17 -0
- package/dist/src/files/files.js +111 -35
- package/dist/src/files/json-files.js +3 -3
- package/dist/src/files/json-object.js +28 -7
- package/dist/src/files/stat-cache.js +2 -2
- package/dist/src/files/tail.js +1 -1
- package/dist/src/gates/bootstrap-gates.js +4 -5
- package/dist/src/gates/budget-gates.js +88 -225
- package/dist/src/gates/disk-gate.js +1 -1
- package/dist/src/gates/gate-polls.js +101 -143
- package/dist/src/gates/maintenance-quota.js +37 -30
- package/dist/src/gates/pause-gates.js +28 -10
- package/dist/src/gates/readiness.js +7 -3
- package/dist/src/gates/role-cap-gates.js +8 -8
- package/dist/src/gates/startup-gate.js +94 -32
- package/dist/src/gates/streak-gate.js +54 -30
- package/dist/src/git/commit-message.js +89 -46
- package/dist/src/git/git-diff.js +16 -10
- package/dist/src/git/git-run.js +79 -38
- package/dist/src/git/git.js +54 -34
- package/dist/src/git/slot-salvage.js +253 -0
- package/dist/src/git/slots-state.js +6 -6
- package/dist/src/git/worktree-pool.js +132 -38
- package/dist/src/git/worktree-use.js +4 -11
- package/dist/src/git/worktree.js +94 -37
- package/dist/src/gui/gui-admin-endpoints.js +96 -0
- package/dist/src/gui/gui-args.js +79 -8
- package/dist/src/gui/gui-backlog-commands.js +43 -19
- package/dist/src/gui/gui-backlog-endpoints.js +156 -0
- package/dist/src/gui/gui-command.js +26 -13
- package/dist/src/gui/gui-config-commands.js +168 -80
- package/dist/src/gui/gui-endpoint-commands.js +5 -4
- package/dist/src/gui/gui-endpoint-common.js +4 -4
- package/dist/src/gui/gui-endpoints.js +11 -380
- package/dist/src/gui/gui-history-endpoints.js +301 -0
- package/dist/src/gui/gui-operator-commands.js +235 -13
- package/dist/src/gui/gui-prompt-commands.js +26 -20
- package/dist/src/gui/gui-report-endpoints.js +97 -0
- package/dist/src/gui/gui-server.js +26 -5
- package/dist/src/gui/gui-team-commands.js +7 -7
- package/dist/src/gui/http-body.js +1 -1
- package/dist/src/history/history-data.js +122 -234
- package/dist/src/history/history-queued.js +155 -0
- package/dist/src/history/history-render.js +42 -22
- package/dist/src/history/history.js +190 -49
- package/dist/src/inbox/inbox-attachments.js +29 -30
- package/dist/src/inbox/inbox-cancel.js +10 -11
- package/dist/src/inbox/inbox-edit.js +9 -9
- package/dist/src/inbox/inbox-submit.js +18 -18
- package/dist/src/inbox/inbox-top.js +28 -17
- package/dist/src/inbox/inbox.js +42 -43
- package/dist/src/inbox/pending-prompt.js +26 -26
- package/dist/src/inbox/prompt-commands.js +62 -49
- package/dist/src/inbox/prompt-not-before.js +2 -2
- package/dist/src/init/init-templates.js +1 -2
- package/dist/src/init/init.js +28 -23
- package/dist/src/merge/backlog-conflicts.js +215 -35
- package/dist/src/merge/merge-batch.js +14 -8
- package/dist/src/merge/merge-cancel.js +53 -0
- package/dist/src/merge/merge-check-failures.js +44 -22
- package/dist/src/merge/merge-core.js +58 -32
- package/dist/src/merge/merge-diff.js +5 -4
- package/dist/src/merge/merge-drain.js +45 -19
- package/dist/src/merge/merge-git.js +177 -38
- package/dist/src/merge/merge-pipeline.js +15 -3
- package/dist/src/merge/merge-post-review.js +214 -0
- package/dist/src/merge/merge-queue-render.js +48 -11
- package/dist/src/merge/merge-queue.js +52 -15
- package/dist/src/merge/merge-requeue.js +103 -0
- package/dist/src/merge/merge-slot.js +61 -16
- package/dist/src/merge/merge-stack.js +27 -11
- package/dist/src/merge/merge-to-main.js +77 -26
- package/dist/src/merge/merge-top.js +83 -0
- package/dist/src/merge/merge-verify.js +75 -18
- package/dist/src/notes-cli.js +35 -15
- package/dist/src/operator/operator-commands.js +192 -81
- package/dist/src/operator/operator-intent.js +69 -42
- package/dist/src/operator/operator-requests.js +35 -40
- package/dist/src/operator/retire.js +5 -6
- package/dist/src/operator/revert.js +142 -34
- package/dist/src/orchestrator/orchestrator-launch.js +60 -52
- package/dist/src/orchestrator/orchestrator-poll.js +352 -0
- package/dist/src/orchestrator/orchestrator-scheduling.js +71 -370
- package/dist/src/orchestrator/orchestrator.js +129 -369
- package/dist/src/orchestrator/retention.js +42 -8
- package/dist/src/orchestrator/scheduling-admit.js +116 -0
- package/dist/src/orchestrator/scheduling-scope.js +245 -0
- package/dist/src/orchestrator/scheduling-skip.js +195 -0
- package/dist/src/orchestrator/startup-migration-steps.js +8 -7
- package/dist/src/orchestrator/startup-migrations.js +11 -7
- package/dist/src/paths.js +126 -49
- package/dist/src/pi/command-shape.js +12 -1
- package/dist/src/pi/pi-args.js +6 -4
- package/dist/src/pi/pi-backend.js +6 -6
- package/dist/src/pi/pi-bin.js +54 -63
- package/dist/src/pi/pi-listed-models.js +53 -0
- package/dist/src/pi/pi-models.js +63 -30
- package/dist/src/pi/pi-run-result.js +1 -1
- package/dist/src/pi/pi-settings.js +1 -1
- package/dist/src/pi/pi-stream.js +6 -6
- package/dist/src/pi/pi-watchdogs.js +18 -19
- package/dist/src/pi-extension/bounded-output.js +5 -3
- package/dist/src/pi-extension/context-budget.js +2 -2
- package/dist/src/pi-extension/context-shake.js +1 -1
- package/dist/src/pi-extension/context-window.js +0 -1
- package/dist/src/pi-extension/full-output.js +3 -10
- package/dist/src/pi-extension/strip-thinking.js +0 -1
- package/dist/src/pi-extension/trim-system-prompt.js +3 -4
- package/dist/src/pi-extension/write-guard.js +37 -0
- package/dist/src/process/launch-services.js +1 -2
- package/dist/src/process/node-bin.js +16 -0
- package/dist/src/process/process-group.js +8 -18
- package/dist/src/process/process.js +41 -2
- package/dist/src/process/run-marker.js +26 -6
- package/dist/src/process/supervisor.js +22 -21
- package/dist/src/prompt/dialect.js +17 -2
- package/dist/src/prompt/gate-notes.js +203 -0
- package/dist/src/prompt/gate-prompts.js +150 -217
- package/dist/src/prompt/notes-backlog.js +184 -0
- package/dist/src/prompt/principles.js +1 -2
- package/dist/src/prompt/prompt-followup.js +19 -14
- package/dist/src/prompt/prompt.js +131 -204
- package/dist/src/redeploy/redeploy-policy.js +24 -19
- package/dist/src/redeploy/redeploy-probes.js +1 -1
- package/dist/src/redeploy/redeploy.js +2 -3
- package/dist/src/redeploy/redeployer.js +20 -20
- package/dist/src/redeploy/self-reload.js +2 -1
- package/dist/src/report/report-data.js +188 -124
- package/dist/src/report/report-fold.js +130 -54
- package/dist/src/report/report-main-red.js +55 -0
- package/dist/src/report/report-render.js +136 -65
- package/dist/src/report/report-types.js +1 -0
- package/dist/src/report/report.js +23 -9
- package/dist/src/request-timeouts.js +2 -2
- package/dist/src/review/diff-rules.js +53 -0
- package/dist/src/review/known-flakes.js +112 -1
- package/dist/src/review/post-merge-review-accept.js +51 -0
- package/dist/src/review/post-merge-review-render.js +112 -0
- package/dist/src/review/post-merge-review.js +239 -0
- package/dist/src/review/protected-edits.js +24 -10
- package/dist/src/review/quarantine-render.js +65 -0
- package/dist/src/review/review-followup.js +8 -8
- package/dist/src/review/review-precheck.js +66 -23
- package/dist/src/review/review-run.js +395 -0
- package/dist/src/review/review-verdict.js +2 -2
- package/dist/src/review/review.js +180 -401
- package/dist/src/review/secret-leaks.js +36 -16
- package/dist/src/review/suite-rerun.js +0 -1
- package/dist/src/roles/legacy-role-migration.js +80 -7
- package/dist/src/roles/role-catalog.js +127 -12
- package/dist/src/roles/role-guidance.js +65 -20
- package/dist/src/roles/role-labels.js +7 -5
- package/dist/src/roles/role-render.js +108 -56
- package/dist/src/roles/role-view.js +95 -56
- package/dist/src/roles/roles.js +33 -33
- package/dist/src/roles/runner-ids.js +97 -0
- package/dist/src/run/acceptance-greps.js +119 -0
- package/dist/src/run/ci-parity.js +121 -0
- package/dist/src/run/feedback-filings.js +51 -0
- package/dist/src/run/qa-coverage.js +125 -0
- package/dist/src/{tick/tick-apply.js → run/run-apply.js} +95 -94
- package/dist/src/run/run-detail-data.js +175 -0
- package/dist/src/run/run-detail-render.js +91 -0
- package/dist/src/run/run-detail.js +168 -0
- package/dist/src/{tick/tick-finalize.js → run/run-finalize.js} +73 -60
- package/dist/src/{tick/tick-outcome.js → run/run-outcome.js} +6 -7
- package/dist/src/{tick/tick-prompt.js → run/run-prompt.js} +122 -73
- package/dist/src/{tick/tick-resume.js → run/run-resume.js} +55 -26
- package/dist/src/{tick/tick-stage.js → run/run-stage.js} +170 -83
- package/dist/src/{tick/tick-timing.js → run/run-timing.js} +43 -41
- package/dist/src/{tick/tick-usage.js → run/run-usage.js} +45 -37
- package/dist/src/{tick/tick-verdict.js → run/run-verdict.js} +105 -57
- package/dist/src/run/selfcheck-digest.js +40 -0
- package/dist/src/run/stage-backlog-checks.js +249 -0
- package/dist/src/run/stage-check.js +178 -0
- package/dist/src/run/stage-checks-shared.js +65 -0
- package/dist/src/run/stage-name-checks.js +204 -0
- package/dist/src/run/stage-path-checks.js +231 -0
- package/dist/src/run/stage-prose-checks.js +261 -0
- package/dist/src/runner/leftover.js +216 -0
- package/dist/src/{loop → runner}/model-fallback.js +12 -12
- package/dist/src/runner/revision.js +191 -0
- package/dist/src/{loop/loop-fallback.js → runner/runner-fallback.js} +8 -8
- package/dist/src/runner/runner-outcome.js +109 -0
- package/dist/src/{loop/loop-pi.js → runner/runner-pi.js} +140 -131
- package/dist/src/{loop/loop-recovery.js → runner/runner-recovery.js} +39 -18
- package/dist/src/{loop/loop-tick.js → runner/runner-run.js} +236 -245
- package/dist/src/{loop/loop-state.js → runner/runner-state-load.js} +61 -114
- package/dist/src/runner/runner-state.js +103 -0
- package/dist/src/{loop/loop.js → runner/runner.js} +123 -120
- package/dist/src/scheduling/backoff.js +38 -38
- package/dist/src/scheduling/claim-entries.js +49 -0
- package/dist/src/scheduling/claims.js +35 -22
- package/dist/src/scheduling/once-round.js +22 -22
- package/dist/src/scheduling/quiet-hours.js +5 -6
- package/dist/src/scheduling/scheduling.js +74 -64
- package/dist/src/scheduling/work-merged-cache.js +2 -2
- package/dist/src/status/status-budget.js +55 -47
- package/dist/src/status/status-data.js +49 -17
- package/dist/src/status/status-inbox.js +2 -2
- package/dist/src/status/status-install.js +0 -1
- package/dist/src/status/status-polls.js +43 -28
- package/dist/src/status/status-roles.js +50 -13
- package/dist/src/team/error-storm.js +8 -8
- package/dist/src/team/failure-spread.js +2 -2
- package/dist/src/team/orchestrator-info.js +15 -9
- package/dist/src/team/reclaim.js +7 -8
- package/dist/src/team/team-hold.js +7 -7
- package/dist/src/team/team-polls.js +91 -50
- package/dist/src/team/team-state.js +8 -2
- package/dist/src/text/datetime.js +65 -18
- package/dist/src/text/format.js +48 -11
- package/dist/src/text/markdown.js +8 -5
- package/dist/src/text/phrases.js +60 -23
- package/dist/src/text/suggest.js +1 -1
- package/dist/src/text/text.js +78 -13
- package/dist/src/ui/badges.js +99 -38
- package/dist/src/ui/gui/gui-client-backlog.js +314 -0
- package/dist/src/ui/gui/gui-client-boot.js +89 -61
- package/dist/src/ui/gui/gui-client-composer.js +8 -9
- package/dist/src/ui/gui/gui-client-drawer-config.js +254 -0
- package/dist/src/ui/gui/gui-client-drawer.js +155 -289
- package/dist/src/ui/gui/gui-client-feed.js +271 -0
- package/dist/src/ui/gui/gui-client-history.js +437 -68
- package/dist/src/ui/gui/gui-client-labels.js +6 -3
- package/dist/src/ui/gui/gui-client-markdown.js +1 -2
- package/dist/src/ui/gui/gui-client-model.js +27 -36
- package/dist/src/ui/gui/gui-client-operator.js +60 -52
- package/dist/src/ui/gui/gui-client-pending.js +405 -24
- package/dist/src/ui/gui/gui-client-report-chart.js +492 -0
- package/dist/src/ui/gui/gui-client-report.js +105 -430
- package/dist/src/ui/gui/{gui-client-loops.js → gui-client-roles.js} +43 -44
- package/dist/src/ui/gui/gui-client-settings.js +163 -5
- package/dist/src/ui/gui/gui-client-team.js +36 -465
- package/dist/src/ui/gui/gui-client.js +38 -26
- package/dist/src/ui/gui/gui-icons.js +0 -2
- package/dist/src/ui/gui/gui-page.js +10 -7
- package/dist/src/ui/gui/gui-styles.js +38 -34
- package/dist/src/ui/progress-data.js +9 -11
- package/dist/src/ui/{tick-progress-model.js → run-progress-model.js} +33 -32
- package/dist/src/ui/status-model.js +133 -125
- package/dist/src/ui/status-payload.js +364 -49
- package/dist/src/ui/status-render.js +109 -82
- package/dist/src/ui/team-alerts.js +728 -62
- package/dist/src/ui/tone.js +12 -6
- package/dist/src/ui/transcript-run.js +58 -0
- package/dist/src/ui/transcript-tail.js +28 -20
- package/dist/src/ui/transcript.js +63 -23
- package/dist/src/ui/tui/tui-app.js +0 -1
- package/dist/src/ui/tui/tui-backlog.js +53 -14
- package/dist/src/ui/tui/tui-editor-answer.js +27 -31
- package/dist/src/ui/tui/tui-editor-attach.js +4 -12
- package/dist/src/ui/tui/tui-editor-backends.js +127 -0
- package/dist/src/ui/tui/tui-editor-brief.js +14 -36
- package/dist/src/ui/tui/tui-editor-budget.js +36 -39
- package/dist/src/ui/tui/tui-editor-check.js +29 -0
- package/dist/src/ui/tui/tui-editor-checks.js +28 -0
- package/dist/src/ui/tui/tui-editor-claude-reserve.js +24 -0
- package/dist/src/ui/tui/tui-editor-concurrency.js +25 -0
- package/dist/src/ui/tui/tui-editor-config.js +99 -0
- package/dist/src/ui/tui/tui-editor-entry.js +39 -64
- package/dist/src/ui/tui/tui-editor-fallback.js +31 -0
- package/dist/src/ui/tui/tui-editor-instances.js +46 -0
- package/dist/src/ui/tui/tui-editor-instructions.js +117 -0
- package/dist/src/ui/tui/tui-editor-interval.js +29 -16
- package/dist/src/ui/tui/tui-editor-model.js +29 -0
- package/dist/src/ui/tui/tui-editor-notes.js +9 -29
- package/dist/src/ui/tui/tui-editor-notify.js +25 -0
- package/dist/src/ui/tui/tui-editor-pause.js +48 -59
- package/dist/src/ui/tui/tui-editor-prompt.js +11 -16
- package/dist/src/ui/tui/tui-editor-provider-caps.js +27 -0
- package/dist/src/ui/tui/tui-editor-queued.js +5 -9
- package/dist/src/ui/tui/tui-editor-quiet.js +95 -41
- package/dist/src/ui/tui/tui-editor-retire.js +5 -13
- package/dist/src/ui/tui/tui-editor-role-enabled.js +126 -0
- package/dist/src/ui/tui/tui-editor-role-key.js +71 -0
- package/dist/src/ui/tui/tui-editor-role-model.js +28 -0
- package/dist/src/ui/tui/tui-editor-search.js +45 -33
- package/dist/src/ui/tui/tui-editor-session.js +101 -34
- package/dist/src/ui/tui/tui-editor-slots.js +24 -0
- package/dist/src/ui/tui/tui-editors.js +44 -2
- package/dist/src/ui/tui/tui-frame.js +68 -11
- package/dist/src/ui/tui/tui-history.js +8 -9
- package/dist/src/ui/tui/tui-input.js +13 -11
- package/dist/src/ui/tui/tui-keymap.js +0 -1
- package/dist/src/ui/tui/tui-keys.js +33 -9
- package/dist/src/ui/tui/tui-pane-activity.js +35 -19
- package/dist/src/ui/tui/tui-pane-backlog.js +198 -126
- package/dist/src/ui/tui/tui-pane-brief.js +0 -1
- package/dist/src/ui/tui/tui-pane-ctx.js +2 -2
- package/dist/src/ui/tui/tui-pane-health.js +168 -8
- package/dist/src/ui/tui/tui-pane-history.js +446 -82
- package/dist/src/ui/tui/tui-pane-pending.js +539 -15
- package/dist/src/ui/tui/tui-pane-queued.js +78 -57
- package/dist/src/ui/tui/tui-pane-report.js +54 -16
- package/dist/src/ui/tui/tui-pane-session.js +34 -6
- package/dist/src/ui/tui/tui-pane-transcript.js +111 -37
- package/dist/src/ui/tui/tui-pane.js +91 -28
- package/dist/src/ui/tui/tui-panes.js +153 -34
- package/dist/src/ui/tui/tui.js +18 -15
- package/dist/src/verdict/fix-claim.js +129 -33
- package/dist/src/verdict/no-change.js +4 -4
- package/dist/src/verdict/refusal.js +40 -16
- package/dist/src/verdict/reply-contract.js +77 -31
- package/dist/src/version.js +0 -1
- package/package.json +2 -1
- package/dist/src/loop/leftover.js +0 -130
- package/dist/src/loop/revision.js +0 -70
- package/dist/src/roles/loop-ids.js +0 -77
- package/dist/src/tick/qa-coverage.js +0 -108
- package/dist/src/tick/stage-check.js +0 -419
- package/dist/src/tick/telemetry-digest.js +0 -25
- package/dist/src/tick/tick-detail-data.js +0 -108
- package/dist/src/tick/tick-detail.js +0 -163
- package/dist/src/ui/gui/gui-client-sound.js +0 -53
|
@@ -1,47 +1,53 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
import path from "node:path";
|
|
3
2
|
import { describeCheck } from "../build/build-check-report.js";
|
|
4
|
-
import { DECOMPOSITION_GUIDANCE, NEEDS_REPLAN_NOTE, NEEDS_REVIEW_NOTE, PLAN_SIZING } from "../roles/role-guidance.js";
|
|
5
|
-
import { CLAIMS_RULE,
|
|
3
|
+
import { DECOMPOSITION_GUIDANCE, NEEDS_REPLAN_NOTE, NEEDS_REVIEW_NOTE, PLAN_QUEUE_GUIDANCE, PLAN_SIZING } from "../roles/role-guidance.js";
|
|
4
|
+
import { CLAIMS_RULE, REPLY_ENDINGS } from "../verdict/reply-contract.js";
|
|
6
5
|
import { todayStamp } from "../budget/budget.js";
|
|
7
6
|
import { daysBetween } from "../text/datetime.js";
|
|
8
7
|
import { plural } from "../text/phrases.js";
|
|
9
8
|
import { worktreePath } from "../paths.js";
|
|
10
9
|
import { PI_DIALECT, dialectFor } from "./dialect.js";
|
|
11
|
-
/**
|
|
10
|
+
/** Prompt construction for the roles' pi runs (run and director). The reply contract those
|
|
11
|
+
* runs must follow — the TUMWATER_NOTHING_TO_DO sentinel, the TUMWATER_REFUSED line, the
|
|
12
|
+
* SUMMARY/WHY/RISK/VERIFIED block format, the three endings, and the claims rules — lives in
|
|
13
|
+
* reply-contract.ts; this module weaves it into each prompt. The follow-up prompts that pick a
|
|
14
|
+
* session back up — the resume bridge, the missing-summary recovery, and the fresh-run cut-off
|
|
15
|
+
* note — live in prompt-followup.ts. The merge gate's pi runs (conflict resolution, build fix,
|
|
16
|
+
* review) build their prompts in gate-prompts.ts; assembling a reply into the run's commit message
|
|
17
|
+
* lives in git/commit-message.ts.
|
|
18
|
+
*
|
|
19
|
+
* The prose is tuned for the team's models (2026-10-01): the primary GLM-5.3-Flash (an 18B-active
|
|
20
|
+
* MoE behind a ~1M window) and the budget fallback's local Qwen3.8-27B (~127k window). Both follow
|
|
21
|
+
* short grouped rules with concrete numbers and literal commands far better than long dense
|
|
22
|
+
* paragraphs, over-read when told merely to "work economically", make unchecked claims the reviewer
|
|
23
|
+
* then rejects (the primary's leading rejection cause), and need to be told how a reply must end
|
|
24
|
+
* — so the rules are grouped with one rule per bullet, budgets are numeric, role tasks are
|
|
25
|
+
* numbered steps, claims carry the check that proves them, the three possible endings are a
|
|
26
|
+
* mutually exclusive list, and that closing contract comes last, where a model attends to it most.
|
|
27
|
+
* The prompt is compact: its first request is re-sent on every turn, so the rules keep their
|
|
28
|
+
* directives without the reasons, the principles block keeps only its bullets, the brief file is
|
|
29
|
+
* read rather than inlined, and an assigned run goes without the material its assignment makes
|
|
30
|
+
* redundant. It was written for models with a window of at most 128k (2026-10-17) and became
|
|
31
|
+
* every model's prompt on 2026-10-18 to cut the tokens each turn re-sends; the longer full
|
|
32
|
+
* variant was deleted after a day of the team's runs on it (2026-10-19). The PRINCIPLES.md reader
|
|
33
|
+
* the principles block is fed from lives in principles.ts (readPrinciples, with its injection
|
|
34
|
+
* cap). */
|
|
35
|
+
/** The context-budget rule every run carries. Under the old 87k window half of all runs ended
|
|
12
36
|
* at the ceiling merging nothing (308 of 733 in the autonomous fortnight; 216 of 245 no-change
|
|
13
|
-
*
|
|
37
|
+
* runs in the first week of September), almost all of it whole-file reads: the model, told only
|
|
14
38
|
* to "work economically", read the codebase file by file (277 whole-file reads against 6 ranged
|
|
15
39
|
* ones in the bugfix/improve/clean logs). Every token read is prefill and dilutes the model's
|
|
16
40
|
* attention, so the rule states the cost in numbers and the one habit that prevents it: check
|
|
17
|
-
* size, then read in ranges.
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* the
|
|
24
|
-
*
|
|
41
|
+
* size, then read in ranges. The range-read threshold is ~150 lines, what a 64k window's read cap
|
|
42
|
+
* holds (bounded-output.ts outputLimits), and the first bullet names the cost rather than the
|
|
43
|
+
* window's size, since every model gets it. One rule per bullet (2026-10-01), so a small model can
|
|
44
|
+
* follow each on its own. (Reasoning length is not addressed here: a "think briefly" bullet
|
|
45
|
+
* measured no drop in the fallback model's thinking — the oMLX thinking-budget cap is the lever.)
|
|
46
|
+
* The bundled context-budget extension (src/pi-extension/context-budget.ts) complements this rule
|
|
47
|
+
* with the live fill level. Stated once so the run rules and prompt-followup.ts's resume bridge
|
|
48
|
+
* cannot drift. Must not contain the phrase "ran out of context" — the loop tests use it to tell
|
|
49
|
+
* a fresh run from a cut-off resume. */
|
|
25
50
|
export function contextBudgetRule(dialect = PI_DIALECT) {
|
|
26
|
-
return `- Your context window is finite: everything you read stays in it until the run ends, and a
|
|
27
|
-
run that fills the window lands nothing. A whole-file read of a 500-line module costs ~5k tokens.
|
|
28
|
-
- Check size before reading (\`wc -l\`) and read files over ~300 lines in ranges: find the lines
|
|
29
|
-
with \`grep -n\`, then read them with ${dialect.readRange}.
|
|
30
|
-
- Cap command output with \`head\`/\`tail\`. Never dump a file, a log, or a test run wholesale.
|
|
31
|
-
- Do not re-read what you already saw — re-read only a region you edited.
|
|
32
|
-
- Each turn re-sends everything read so far, so issue lookups that do not depend on each other
|
|
33
|
-
(a \`wc -l\` over several files, the ranges a \`grep -n\` found, a typecheck and a targeted
|
|
34
|
-
test) as separate tool calls in the same turn. Keep anything that depends on a prior result
|
|
35
|
-
sequential — do not batch an edit with the test that checks it.
|
|
36
|
-
- ${dialect.oversizedOutput}`;
|
|
37
|
-
}
|
|
38
|
-
/** The pi-dialect reading-budget rule, byte-identical to the rule before the dialect split, for
|
|
39
|
-
* the callers and tests that want the default text. */
|
|
40
|
-
export const CONTEXT_BUDGET_RULE = contextBudgetRule(PI_DIALECT);
|
|
41
|
-
/** contextBudgetRule for the compact prompt: the same habits, with the range-read threshold at
|
|
42
|
-
* ~150 lines, which is what a 64k window's read cap holds (bounded-output.ts outputLimits). Its
|
|
43
|
-
* first bullet names the cost rather than the window's size, since every model gets it. */
|
|
44
|
-
export function compactContextBudgetRule(dialect = PI_DIALECT) {
|
|
45
51
|
return `- Everything you read stays in your context until the run ends and is re-sent on every turn;
|
|
46
52
|
a run that fills the window merges nothing. A whole read of a 500-line file costs ~5k tokens.
|
|
47
53
|
- Check size first (\`wc -l\`) and read files over ~150 lines in ranges: find the lines with
|
|
@@ -52,7 +58,7 @@ export function compactContextBudgetRule(dialect = PI_DIALECT) {
|
|
|
52
58
|
dependent steps sequential.
|
|
53
59
|
- ${dialect.oversizedOutput}`;
|
|
54
60
|
}
|
|
55
|
-
/** The process-kill rule every run that may run commands carries, word for word: the
|
|
61
|
+
/** The process-kill rule every run that may run commands carries, word for word: the run and
|
|
56
62
|
* director rules (full and compact, each adding its own reason), the conflict resolver, and the
|
|
57
63
|
* reviewer. The team's runs and tumwater's own checks share one host, so a kill by pattern
|
|
58
64
|
* reaches them all. On 2026-10-18 a feature run's `pkill -f "dist/test/test-runner.js"; pkill -f
|
|
@@ -62,7 +68,7 @@ export function compactContextBudgetRule(dialect = PI_DIALECT) {
|
|
|
62
68
|
export const KILL_BY_PID_RULE = `Never kill processes by name or pattern (\`pkill\`, \`killall\`,
|
|
63
69
|
\`pgrep … | xargs kill\`): stop only a process you started, by its PID (\`kill $!\` right after
|
|
64
70
|
backgrounding it).`;
|
|
65
|
-
/** The test-runner rule every run that may run tests carries: the
|
|
71
|
+
/** The test-runner rule every run that may run tests carries: the run and director rules, the
|
|
66
72
|
* conflict resolver, and the reviewer. Project-neutral on purpose — a team works on any codebase
|
|
67
73
|
* (npm, cargo, pytest, a configured check.command), so the rule names no ecosystem's runner as THE
|
|
68
74
|
* right one: it points at the declared check or the framework already in use, and its one example
|
|
@@ -78,14 +84,13 @@ export const TEST_RUNNER_RULE = `- Run tests only through the project's declared
|
|
|
78
84
|
runner finds no tests at best, and can kill them mid-run, leaking processes and temp files.`;
|
|
79
85
|
/** Render a dialect's `backendRules` as one bullet each, or nothing when the dialect has none
|
|
80
86
|
* (pi and claude) — so a backend's extra shell/reasoning guidance rides the reading-budget
|
|
81
|
-
* section right after the oversized-output rule
|
|
82
|
-
* prompts. */
|
|
87
|
+
* section right after the oversized-output rule. */
|
|
83
88
|
function backendRuleLines(rules) {
|
|
84
89
|
if (!rules || rules.length === 0)
|
|
85
90
|
return "";
|
|
86
91
|
return "\n" + rules.map((rule) => `- ${rule}`).join("\n");
|
|
87
92
|
}
|
|
88
|
-
/** The date line every pi prompt carries —
|
|
93
|
+
/** The date line every pi prompt carries — run and director (via sharedPreamble) and the gate's
|
|
89
94
|
* conflict and review runs — naming the local calendar day as YYYY-MM-DD. No prompt
|
|
90
95
|
* used to say what day it is, so a run that had to write one (a BUGS.md heading's "(found by …
|
|
91
96
|
* YYYY-MM-DD)", a Fixed or Refused date, NEEDS_REVIEW_NOTE's and NEEDS_REPLAN_NOTE's
|
|
@@ -98,7 +103,7 @@ function backendRuleLines(rules) {
|
|
|
98
103
|
export function dateLine(today = todayStamp()) {
|
|
99
104
|
return `Today's date is ${today} (local time).`;
|
|
100
105
|
}
|
|
101
|
-
/** The repo root as a
|
|
106
|
+
/** The repo root as a role's worktree reaches it (`../../..`, out of .tumwater/worktrees/<role>),
|
|
102
107
|
* derived from worktreePath so the prompt cannot drift from the layout: the hand-written "two
|
|
103
108
|
* levels up (`../../node_modules`)" it replaced pointed at .tumwater/ itself, and on 2026-09-29
|
|
104
109
|
* a bugfix run that followed it (`cd ../..`, git output empty there) fell back to the primary
|
|
@@ -111,118 +116,25 @@ export const DEFAULT_SCOPE = `- Do exactly ONE focused task, then stop. Small, c
|
|
|
111
116
|
- Choose the task within your first ~15 tool calls, in a handful of turns. A task that would
|
|
112
117
|
need more than roughly 60 tool calls, or most of the codebase in view, is too big for one
|
|
113
118
|
run — take a smaller one.`;
|
|
114
|
-
/** The rules every
|
|
119
|
+
/** The rules every role prompt carries — run and director alike, so the two cannot drift.
|
|
115
120
|
* `check` — the project's resolved check (plans/portability.md §6/7) — names the actual
|
|
116
121
|
* verification command in the Leave-the-project-working rule instead of asserting npm, and
|
|
117
122
|
* only an npm check keeps the node_modules borrowing sentence: false and actively misleading
|
|
118
123
|
* in a repo with no node_modules anywhere (a Python, Rust, or Go repo, or one with no check
|
|
119
124
|
* at all). Undefined keeps the generic wording, exactly as prompts read before a check could
|
|
120
|
-
* be configured. `scope` is the Scope section's rules: DEFAULT_SCOPE unless the
|
|
121
|
-
* states its own (Role.scope).
|
|
122
|
-
*
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
125
|
+
* be configured. `scope` is the Scope section's rules: DEFAULT_SCOPE unless the run's role
|
|
126
|
+
* states its own (Role.scope). Orientation differs for an `assigned` run, which reads its entry
|
|
127
|
+
* first and the brief only when the entry needs it — reading the brief in full cost a median
|
|
128
|
+
* ~2.5k tokens of every run before its first edit (2026-10-17 audit). */
|
|
129
|
+
function commonRules(check, briefFile = "README.md", scope = DEFAULT_SCOPE, dialect = PI_DIALECT, assigned = false, gateCommand) {
|
|
130
|
+
const verify = check && gateCommand
|
|
131
|
+
? `verify with \`${gateCommand}\` (lint, compile and the tests your change affects) — run it
|
|
132
|
+
after your change and fix what you broke. Tumwater runs the full check (${describeCheck(check)})
|
|
133
|
+
itself; do not run it.`
|
|
134
|
+
: check
|
|
135
|
+
? `verify with ${describeCheck(check)} (the project's declared check) — run it after your
|
|
128
136
|
change and fix what you broke.`
|
|
129
|
-
|
|
130
|
-
const modules = check?.kind === "npm"
|
|
131
|
-
? `
|
|
132
|
-
- Your worktree has no node_modules of its own; it borrows the install at the repo root
|
|
133
|
-
(\`${ROOT_FROM_WORKTREE}/node_modules\`). To inspect a dependency's types or source, read that
|
|
134
|
-
directory directly instead of widening the search outward.`
|
|
135
|
-
: "";
|
|
136
|
-
return `
|
|
137
|
-
Rules for this run:
|
|
138
|
-
|
|
139
|
-
Orientation — read this much before choosing your task, and no more:
|
|
140
|
-
- First read the project brief (${briefFile}) in full, plus QUESTIONS.md when present.
|
|
141
|
-
- PLANS.md and BUGS.md hold open work: the prompt's <backlog-index> block lists their actionable
|
|
142
|
-
entries (PLANS.md ## Planned, BUGS.md ## Open, QUESTIONS.md ## Open), each with its 1-based line
|
|
143
|
-
range, so read only the entries you need by those ranges. Finished entries live in
|
|
144
|
-
PLANS-DONE.md and BUGS-FIXED.md, newest first; the index lists the newest few with their
|
|
145
|
-
ranges. Those archive files only grow — never read them whole: search them with grep, or read
|
|
146
|
-
one entry by its range, and only when a specific finished entry matters to your task.
|
|
147
|
-
- Your worktree starts clean at main, and tumwater checks main's build before code roles
|
|
148
|
-
start: do not run the build or test suite just to establish a baseline. Run it after your
|
|
149
|
-
change, or when the task itself needs its output (reproducing a failure, counting the suite).
|
|
150
|
-
|
|
151
|
-
Scope:
|
|
152
|
-
${scope}
|
|
153
|
-
|
|
154
|
-
Reading budget:
|
|
155
|
-
${contextBudgetRule(dialect)}${backendRuleLines(dialect.backendRules)}
|
|
156
|
-
|
|
157
|
-
Where you work:
|
|
158
|
-
- Stay inside your worktree: run commands from it — the directory you start in, where
|
|
159
|
-
\`git log\` and \`git show\` work just the same — or from a scratch directory under the system
|
|
160
|
-
temp.
|
|
161
|
-
- Other agents run concurrently on this machine: put scratch files under \`$TMPDIR\` (made with
|
|
162
|
-
\`mktemp\`), never at a fixed \`/tmp\` path such as \`/tmp/check.log\`, so no other run overwrites
|
|
163
|
-
or reads yours.
|
|
164
|
-
- Never cd to the repo root (\`${ROOT_FROM_WORKTREE}\`): it is the primary checkout, which tumwater
|
|
165
|
-
merges main into while you work, and when this project is tumwater itself its dist/ is the
|
|
166
|
-
code the running team executes — never build, test, or edit files in that checkout.${modules}
|
|
167
|
-
- Never run an unbounded scan (\`find /\`, \`grep -r /\`, any recursive search rooted outside the
|
|
168
|
-
repo): it runs for tens of minutes with no output until tumwater kills your run as hung.
|
|
169
|
-
- Never run a command that can wait forever — interactive programs (TUIs, REPLs, editors,
|
|
170
|
-
anything reading stdin), servers, or watch modes. To test such a program, background it with
|
|
171
|
-
a hard time limit (kill it after at most 30 minutes) and never give it a real TTY.
|
|
172
|
-
- ${KILL_BY_PID_RULE} A pattern naming your check or test runner also matches other
|
|
173
|
-
agents' runs and tumwater's own checks on this machine, and kills them too.
|
|
174
|
-
- Leave the project working: ${verify} One run answers every question about the check: write
|
|
175
|
-
its full output to a file in a scratch dir once (\`<check> > <scratch-dir>/check.log 2>&1\`),
|
|
176
|
-
then pipe that file through \`tail\` — only the failures matter. To see any other part of the
|
|
177
|
-
output, grep or read the same file; re-run the check only after an edit changes the tree.
|
|
178
|
-
${TEST_RUNNER_RULE}
|
|
179
|
-
|
|
180
|
-
Boundaries:
|
|
181
|
-
- Never create, amend, or revert git commits, branches, or merges — tumwater handles all git
|
|
182
|
-
operations. Reading git history is fine.
|
|
183
|
-
- Never touch the .tumwater directory or tumwater.json.
|
|
184
|
-
- Never edit the brief block in ${briefFile} (between the tumwater:prompt markers).
|
|
185
|
-
- PRINCIPLES.md holds this project's design principles; only the director and steward roles may
|
|
186
|
-
edit it. Treat it as read-only — to object to a principle, record the objection in PLANS.md.
|
|
187
|
-
- docs/invariants.md states each subsystem's guarantees, pinned to the test that enforces them.
|
|
188
|
-
Read the matching section before you reconstruct what the code you are changing is supposed
|
|
189
|
-
to guarantee; when a merge adds or changes a guarantee, update the register in the same
|
|
190
|
-
commit.
|
|
191
|
-
|
|
192
|
-
When to ask, when to refuse:
|
|
193
|
-
- When a fork in the road is genuinely the user's call (product direction, an irreversible
|
|
194
|
-
choice, taste), do not guess: append a question to QUESTIONS.md under ## Open with context,
|
|
195
|
-
the options, and your own recommendation. Then continue with the parts that don't depend on
|
|
196
|
-
it, or end the run. Never block on an unanswered question; check QUESTIONS.md for answers at
|
|
197
|
-
the start of each run and act on one that unblocks your work. Do not re-ask an open question.
|
|
198
|
-
- If partway in you conclude the task would harm the project — it violates PRINCIPLES.md, grows
|
|
199
|
-
complexity without justification, or keeps fighting back — refuse it. Revert nothing; append
|
|
200
|
-
this note directly under the entry's heading in PLANS.md (a planned feature) or BUGS.md:
|
|
201
|
-
**Refused <YYYY-MM-DD> by <role>: <one-line reason>**
|
|
202
|
-
That note is the only change a refusing run leaves.
|
|
203
|
-
- When choosing work, skip entries carrying a Refused note — do not pick them and do not
|
|
204
|
-
re-refuse them. The objection stands until a human or the director edits the entry, so a
|
|
205
|
-
fully blocked backlog is a legitimate nothing-to-do state.
|
|
206
|
-
|
|
207
|
-
${CLAIMS_RULE}
|
|
208
|
-
|
|
209
|
-
How to end your reply — tumwater parses it, so the form matters:
|
|
210
|
-
- Your last message is plain text: never a tool call, and never an announcement of what you would
|
|
211
|
-
do next ("Let me check…") — either make the call or finish. If a tool result only repeats what
|
|
212
|
-
you already have, do not call it again.
|
|
213
|
-
${REPLY_ENDINGS}`;
|
|
214
|
-
}
|
|
215
|
-
/** commonRules for the compact prompt (CompactPrompt): every directive of the full rules, in
|
|
216
|
-
* fewer words. Orientation differs for an assigned run, which reads its entry first and the
|
|
217
|
-
* brief only when the entry needs it — reading the brief in full cost a median ~2.5k tokens of
|
|
218
|
-
* every run before its first edit (2026-10-17 audit). Scope, Boundaries' first three bullets,
|
|
219
|
-
* TEST_RUNNER_RULE and the reply contract are the full prompt's own text. Keep it in step with
|
|
220
|
-
* commonRules: test/compact-prompt.test.ts checks every directive both must state. */
|
|
221
|
-
function compactRules(check, briefFile, scope, dialect, assigned) {
|
|
222
|
-
const verify = check
|
|
223
|
-
? `verify with ${describeCheck(check)} (the project's declared check) — run it after your
|
|
224
|
-
change and fix what you broke.`
|
|
225
|
-
: `if it has a build or test command, run it after your change and fix what you broke.`;
|
|
137
|
+
: `if it has a build or test command, run it after your change and fix what you broke.`;
|
|
226
138
|
const modules = check?.kind === "npm"
|
|
227
139
|
? `
|
|
228
140
|
- Your worktree has no node_modules; it borrows \`${ROOT_FROM_WORKTREE}/node_modules\`. Read a
|
|
@@ -233,14 +145,15 @@ function compactRules(check, briefFile, scope, dialect, assigned) {
|
|
|
233
145
|
- Read your assigned entry (at the end of this prompt) by its line range first. It replaces your
|
|
234
146
|
task's choosing steps, so this prompt carries no backlog index. Read the project brief
|
|
235
147
|
(${briefFile}) or QUESTIONS.md only when the entry needs them.
|
|
236
|
-
- PLANS.md
|
|
237
|
-
by a range this prompt gives, or find it with \`grep -n\` first.`
|
|
148
|
+
- Never read PLANS.md, BUGS.md or their archives (PLANS-DONE.md, BUGS-FIXED.md) whole. Read
|
|
149
|
+
another entry only by a range this prompt gives, or find it with \`grep -n\` first.`
|
|
238
150
|
: `Orientation — read this much before choosing your task, and no more:
|
|
239
151
|
- First read the project brief (${briefFile}) in full, plus QUESTIONS.md when present.
|
|
240
|
-
- PLANS.md and BUGS.md
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
152
|
+
- PLANS.md and BUGS.md hold open work: the <backlog-index> block gives each actionable entry
|
|
153
|
+
with its 1-based line range, so read only the entries you need, by range. Finished entries live
|
|
154
|
+
in PLANS-DONE.md and BUGS-FIXED.md, newest first (the index lists the newest few). Never read
|
|
155
|
+
those archives whole: grep them, or read one entry by its range, only when a finished entry
|
|
156
|
+
matters to your task.`;
|
|
244
157
|
return `
|
|
245
158
|
Rules for this run:
|
|
246
159
|
|
|
@@ -252,7 +165,7 @@ Scope:
|
|
|
252
165
|
${scope}
|
|
253
166
|
|
|
254
167
|
Reading budget:
|
|
255
|
-
${
|
|
168
|
+
${contextBudgetRule(dialect)}${backendRuleLines(dialect.backendRules)}
|
|
256
169
|
|
|
257
170
|
Where you work:
|
|
258
171
|
- Run commands from your worktree (where you start; \`git log\` and \`git show\` work there) or a
|
|
@@ -266,7 +179,7 @@ Where you work:
|
|
|
266
179
|
30 minutes) and never give it a real TTY.
|
|
267
180
|
- ${KILL_BY_PID_RULE} A pattern also kills other agents' runs and checks.
|
|
268
181
|
- Leave the project working: ${verify} Write the check's full output to a scratch file once
|
|
269
|
-
(
|
|
182
|
+
(\`${gateCommand ? "<gate>" : "<check>"} > <scratch-dir>/check.log 2>&1\`) and \`tail\` it; grep that file for anything else, and
|
|
270
183
|
re-run the check only after an edit changes the tree.
|
|
271
184
|
${TEST_RUNNER_RULE}
|
|
272
185
|
|
|
@@ -289,11 +202,13 @@ When to ask, when to refuse:
|
|
|
289
202
|
justification, or keeps fighting back): refuse it. Revert nothing; append this note directly
|
|
290
203
|
under the entry's heading in PLANS.md (a planned feature) or BUGS.md:
|
|
291
204
|
**Refused <YYYY-MM-DD> by <role>: <one-line reason>**
|
|
292
|
-
|
|
205
|
+
The one-line reason must name what in this entry makes it harmful; another entry's hold, or
|
|
206
|
+
your own notes, is never a reason — skip that entry instead. That note is the only change a
|
|
207
|
+
refusing run leaves.
|
|
293
208
|
- Skip entries carrying a Refused note: never pick or re-refuse them. A fully blocked backlog is
|
|
294
209
|
a legitimate nothing-to-do state.
|
|
295
210
|
|
|
296
|
-
${
|
|
211
|
+
${CLAIMS_RULE}
|
|
297
212
|
|
|
298
213
|
How to end your reply — tumwater parses it, so the form matters:
|
|
299
214
|
- Your last message is plain text: never a tool call, and never an announcement of what you would
|
|
@@ -301,21 +216,21 @@ How to end your reply — tumwater parses it, so the form matters:
|
|
|
301
216
|
you already have, do not call it again.
|
|
302
217
|
${REPLY_ENDINGS}`;
|
|
303
218
|
}
|
|
304
|
-
/**
|
|
305
|
-
*
|
|
306
|
-
* kept whole. */
|
|
219
|
+
/** What the principles block carries of PRINCIPLES.md: the file from its first list item on,
|
|
220
|
+
* dropping its own introduction (which restates the block's heading). A file with no list item
|
|
221
|
+
* is kept whole. */
|
|
307
222
|
export function principleBullets(principles) {
|
|
308
223
|
const lines = principles.split("\n");
|
|
309
224
|
const first = lines.findIndex((line) => /^[-*] /.test(line));
|
|
310
225
|
return first <= 0 ? principles : lines.slice(first).join("\n");
|
|
311
226
|
}
|
|
312
|
-
/** The <principles> block injected into every
|
|
313
|
-
* taste, phrased positively so
|
|
314
|
-
* itself is read by principles.ts's readPrinciples. */
|
|
227
|
+
/** The <principles> block injected into every run and director prompt: the project's codified
|
|
228
|
+
* taste, phrased positively so roles follow it rather than merely avoid violations — its bullets
|
|
229
|
+
* only (principleBullets). The file itself is read by principles.ts's readPrinciples. */
|
|
315
230
|
function principlesBlock(principles) {
|
|
316
|
-
return `Design principles this project holds — uphold them in everything you produce:\n<principles>\n${principles}\n</principles>`;
|
|
231
|
+
return `Design principles this project holds — uphold them in everything you produce:\n<principles>\n${principleBullets(principles)}\n</principles>`;
|
|
317
232
|
}
|
|
318
|
-
/** The <failure-digest> block injected into the
|
|
233
|
+
/** The <failure-digest> block injected into the selfcheck role's prompt (plans/telemetry-role.md):
|
|
319
234
|
* the harness renders the digest from its own event log at the project root and hands it over, so
|
|
320
235
|
* the role spends no tool calls acquiring evidence and cannot read a stale or foreign log. */
|
|
321
236
|
function digestBlock(digest) {
|
|
@@ -333,19 +248,29 @@ function savedClause(savedDay, today) {
|
|
|
333
248
|
return "last saved today; ";
|
|
334
249
|
return `last saved ${savedDay}, ${plural(age, "day")} ago; `;
|
|
335
250
|
}
|
|
336
|
-
/** The role's
|
|
251
|
+
/** The role's notes as shown to it: its own earlier runs' note, labeled as unverified.
|
|
337
252
|
* Rides only when there is a non-empty note; the standing instruction to write one is always
|
|
338
|
-
* present (roleNotesInstruction), so a role's FIRST
|
|
339
|
-
* command exists and can seed the
|
|
340
|
-
function roleNotesBlock(notes, savedDay, today) {
|
|
253
|
+
* present (roleNotesInstruction), so a role's FIRST run — with no note yet — still learns the
|
|
254
|
+
* command exists and can seed the notes. */
|
|
255
|
+
function roleNotesBlock(notes, hasBacklogIndex, savedDay, today) {
|
|
256
|
+
const liveSource = hasBacklogIndex
|
|
257
|
+
? `the <backlog-index> block above is the live
|
|
258
|
+
source of what is currently true of each entry and series, so check it (and the entry itself) before acting on a
|
|
259
|
+
note's say-so.`
|
|
260
|
+
: `the backlog is the live
|
|
261
|
+
source of what is currently true of each entry and series, so check the entry itself (and, when this run carries
|
|
262
|
+
one, its line in the backlog) before acting on a note's say-so.`;
|
|
341
263
|
return `Notes your role wrote in earlier runs (${savedClause(savedDay, today)}yours, unverified — check against the code before
|
|
342
|
-
relying on them)
|
|
264
|
+
relying on them). A claim they make about an entry's backlog state — refused, blocked, abandoned, needs-replan,
|
|
265
|
+
done, behind another entry — is a snapshot of the past, not the present: ${liveSource}
|
|
266
|
+
A note that tells you to skip or never re-author an entry is always overridden by the backlog.
|
|
267
|
+
<role-notes>\n${notes.trim()}\n</role-notes>`;
|
|
343
268
|
}
|
|
344
|
-
/** The standing instruction that makes the
|
|
345
|
-
* write one, so the first
|
|
269
|
+
/** The standing instruction that makes the notes seedable: every role run is told it may
|
|
270
|
+
* write one, so the first run (when no note exists yet) can create it. The note content block
|
|
346
271
|
* (roleNotesBlock) is what is omitted when there is nothing to show. Every backend speaks the
|
|
347
272
|
* same shell command (plans/notes-command.md §3), and the director never reaches
|
|
348
|
-
*
|
|
273
|
+
* buildRunPrompt, so it never carries one. */
|
|
349
274
|
export function roleNotesInstruction() {
|
|
350
275
|
return `Before you end, if you learned something the next run of your role should know (where
|
|
351
276
|
things live, what you ruled out and why, what you would look at next), save the full replacement
|
|
@@ -363,42 +288,45 @@ const OLDER_NAMES_MAP = "loop = role, tick = run, fleet = team, landing/landed =
|
|
|
363
288
|
/** The sentence every assembled prompt carries once: the older names and where all of them are
|
|
364
289
|
* listed. Interpolated into the shared preamble and the reviewer and resolver openers. */
|
|
365
290
|
export const OLDER_NAMES_SENTENCE = `Older tumwater names still appear in code, git history and logs: ${OLDER_NAMES_MAP}; docs/glossary.md in tumwater's repository lists them all.`;
|
|
366
|
-
/** Shared opening of every
|
|
367
|
-
*
|
|
368
|
-
*
|
|
369
|
-
*
|
|
370
|
-
|
|
371
|
-
|
|
291
|
+
/** Shared opening of every role prompt: where the run happens and what day it is. The brief is
|
|
292
|
+
* not inlined: the rules send each run to the brief file, which holds the same text. Defined
|
|
293
|
+
* once so the run and director prompts cannot drift — and so the one sentence telling every
|
|
294
|
+
* role to date its records from dateLine, not from the repo, reaches each of them without
|
|
295
|
+
* editing any role text. */
|
|
296
|
+
function sharedPreamble(today) {
|
|
297
|
+
return [
|
|
372
298
|
`You work in a dedicated git worktree of this project; your changes will be committed and merged to main by tumwater after you finish.`,
|
|
373
299
|
`${dateLine(today)} Stamp it on anything you record now — a new BUGS.md heading ends
|
|
374
|
-
"(found by the <role> role YYYY-MM-DD)", a
|
|
375
|
-
a
|
|
300
|
+
"(found by the <role> role YYYY-MM-DD)", a BUGS.md record closes with "— fixed YYYY-MM-DD by the <role> role",
|
|
301
|
+
a finished plan's Done stamp reads "— done YYYY-MM-DD by the <role> role" appended after its
|
|
302
|
+
"(planned YYYY-MM-DD by the <role> role …)" parenthetical, and a Refused or
|
|
376
303
|
Needs-review note carries the date too — and count plan deadlines from it; never infer the date
|
|
377
304
|
from the repo.`,
|
|
378
305
|
OLDER_NAMES_SENTENCE,
|
|
379
306
|
];
|
|
380
|
-
if (initialPrompt) {
|
|
381
|
-
parts.push(`The project's brief — its reason to exist — is:\n<project-prompt>\n${initialPrompt}\n</project-prompt>`);
|
|
382
|
-
}
|
|
383
|
-
return parts;
|
|
384
307
|
}
|
|
385
|
-
/** The
|
|
386
|
-
export function
|
|
387
|
-
const { role,
|
|
308
|
+
/** The prompt for one role run. */
|
|
309
|
+
export function buildRunPrompt(input) {
|
|
310
|
+
const { role, rejectedReview, principles, digest, coverage, ciParity, filings, backlogStructure, backlogIndex, notes, notesSavedDay, notesBacklog, extraInstructions, planTargetNote, flakyChecks, check, gateCommand, briefFile, today, userRequest, agent, assigned } = input;
|
|
388
311
|
const dialect = dialectFor(agent);
|
|
389
312
|
const day = today ?? todayStamp();
|
|
390
313
|
const parts = [
|
|
314
|
+
...(rejectedReview ? [rejectedReview.trim()] : []),
|
|
391
315
|
`You are the "${role.id}" role (${role.title}) on this project's tumwater team — tumwater runs a team of AI roles that develop the project.`,
|
|
392
|
-
...sharedPreamble(
|
|
316
|
+
...sharedPreamble(day),
|
|
393
317
|
];
|
|
394
318
|
if (principles)
|
|
395
|
-
parts.push(principlesBlock(
|
|
319
|
+
parts.push(principlesBlock(principles));
|
|
396
320
|
if (userRequest)
|
|
397
321
|
parts.push(`An explicit request from the user, aimed at this role. Treat it as this run's steering;
|
|
398
322
|
your role's rules and the merge gate still apply unchanged. If the request is out of this
|
|
399
323
|
role's scope, say so in your reply instead of doing it anyway.\n<user-request>\n${userRequest.trim()}\n</user-request>`);
|
|
400
324
|
if (coverage)
|
|
401
325
|
parts.push(coverage);
|
|
326
|
+
if (ciParity)
|
|
327
|
+
parts.push(ciParity);
|
|
328
|
+
if (filings)
|
|
329
|
+
parts.push(filings);
|
|
402
330
|
if (digest)
|
|
403
331
|
parts.push(digestBlock(digest));
|
|
404
332
|
if (backlogStructure)
|
|
@@ -406,7 +334,9 @@ role's scope, say so in your reply instead of doing it anyway.\n<user-request>\n
|
|
|
406
334
|
if (backlogIndex)
|
|
407
335
|
parts.push(backlogIndex);
|
|
408
336
|
if (notes && notes.trim() !== "")
|
|
409
|
-
parts.push(roleNotesBlock(notes, notesSavedDay, day));
|
|
337
|
+
parts.push(roleNotesBlock(notes, Boolean(backlogIndex), notesSavedDay, day));
|
|
338
|
+
if (notesBacklog)
|
|
339
|
+
parts.push(notesBacklog);
|
|
410
340
|
parts.push(`Your task this run:\n${role.find.trim()}`);
|
|
411
341
|
if (planTargetNote)
|
|
412
342
|
parts.push(planTargetNote.trim());
|
|
@@ -415,39 +345,35 @@ role's scope, say so in your reply instead of doing it anyway.\n<user-request>\n
|
|
|
415
345
|
if (extraInstructions)
|
|
416
346
|
parts.push(`Additional standing instructions from the user:\n${extraInstructions.trim()}`);
|
|
417
347
|
parts.push(roleNotesInstruction());
|
|
418
|
-
parts.push(commonRules(check, briefFile, role.scope, dialect,
|
|
348
|
+
parts.push(commonRules(check, briefFile, role.scope, dialect, assigned, gateCommand).trim());
|
|
419
349
|
return parts.join("\n\n");
|
|
420
350
|
}
|
|
421
|
-
/** The prompt for a director
|
|
422
|
-
export function buildDirectorPrompt(userPrompt,
|
|
423
|
-
/** The project's resolved check (plans/portability.md §6/7) — same threading as the
|
|
351
|
+
/** The prompt for a director run, which routes a user request into the project. */
|
|
352
|
+
export function buildDirectorPrompt(userPrompt, principles,
|
|
353
|
+
/** The project's resolved check (plans/portability.md §6/7) — same threading as the run
|
|
424
354
|
* prompt, since commonRules is shared by both builders. */
|
|
425
355
|
check,
|
|
426
356
|
/** The resolved brief file's name (plans/portability.md §7a/7) — same threading again. */
|
|
427
357
|
briefFile,
|
|
428
358
|
/** Today's local date (see dateLine). Omitted: todayStamp() — tests pin it. */
|
|
429
359
|
today,
|
|
430
|
-
/** Rendered actionable backlog index (see backlog-
|
|
360
|
+
/** Rendered actionable backlog index (see backlog-index.ts); the run prompt carries it
|
|
431
361
|
* too, so the director can route against the same bounded view of the backlog. */
|
|
432
362
|
backlogIndex,
|
|
433
|
-
/** The
|
|
363
|
+
/** The backend the director resolves to, selecting the prompt dialect (./dialect.ts).
|
|
434
364
|
* Omitted: pi's dialect. */
|
|
435
|
-
|
|
436
|
-
/** The compact variant every run gets; a director run is never assigned an entry. Omitted:
|
|
437
|
-
* the full prompt. */
|
|
438
|
-
compact,
|
|
365
|
+
backend,
|
|
439
366
|
/** The director's `roles.director.instructions` override — its run prompt is otherwise the
|
|
440
367
|
* user's request. Omitted: no `Additional standing instructions` block, exactly as today. */
|
|
441
368
|
extraInstructions) {
|
|
442
|
-
const variant = compact ? { assigned: false } : undefined;
|
|
443
369
|
const parts = [
|
|
444
370
|
`You are the "director" role on this project's tumwater team — tumwater runs a team of AI roles that develop the project. The user steers
|
|
445
371
|
the project by sending it requests; one has just arrived. Other specialist roles continuously
|
|
446
372
|
implement planned features from PLANS.md and fix bugs from BUGS.md.`,
|
|
447
|
-
...sharedPreamble(
|
|
373
|
+
...sharedPreamble(today),
|
|
448
374
|
];
|
|
449
375
|
if (principles)
|
|
450
|
-
parts.push(principlesBlock(
|
|
376
|
+
parts.push(principlesBlock(principles));
|
|
451
377
|
if (backlogIndex)
|
|
452
378
|
parts.push(backlogIndex);
|
|
453
379
|
parts.push(`The user's request:\n<user-request>\n${userPrompt.trim()}\n</user-request>`);
|
|
@@ -455,7 +381,7 @@ implement planned features from PLANS.md and fix bugs from BUGS.md.`,
|
|
|
455
381
|
work yourself:
|
|
456
382
|
- A feature request or substantial change: write a concrete plan for it in PLANS.md (goal,
|
|
457
383
|
approach, files touched, acceptance criteria) so the feature role implements it. Do not build
|
|
458
|
-
it now. ${PLAN_SIZING}
|
|
384
|
+
it now. ${PLAN_SIZING} ${PLAN_QUEUE_GUIDANCE}
|
|
459
385
|
- A bug report: record it in BUGS.md (symptom, how to reproduce, suspected cause — investigate
|
|
460
386
|
briefly to sharpen the report) so the bugfix role fixes it. Do not fix it now.
|
|
461
387
|
- Guidance, a decision, or a constraint (e.g. "prefer X", "drop feature Y"): record it durably
|
|
@@ -494,7 +420,7 @@ work yourself:
|
|
|
494
420
|
if (extraInstructions)
|
|
495
421
|
parts.push(`Additional standing instructions from the user:\n${extraInstructions.trim()}`);
|
|
496
422
|
// Before the shared rules, not after them: the closing reply contract stays the last thing
|
|
497
|
-
// in the prompt, where a model attends to it most (the
|
|
423
|
+
// in the prompt, where a model attends to it most (the run prompt's invariant too).
|
|
498
424
|
parts.push(`Note on one boundary in the rules below, director only: user-defined-role requests are
|
|
499
425
|
executed by writing .tumwater-config-request.json in your worktree (shape and worked example
|
|
500
426
|
above) — never by editing tumwater.json, which stays off-limits to you as to every role. Tumwater
|
|
@@ -502,6 +428,7 @@ validates the request and applies only its customRoles array; a request that als
|
|
|
502
428
|
any other setting (timeouts, budgets, role enablement, review settings) has that key discarded
|
|
503
429
|
with a warning, so such a request is guidance to record per the routing rules, not an edit you
|
|
504
430
|
can make.`);
|
|
505
|
-
|
|
431
|
+
// A director run is never assigned an entry.
|
|
432
|
+
parts.push(commonRules(check, briefFile, undefined, dialectFor(backend)).trim());
|
|
506
433
|
return parts.join("\n\n");
|
|
507
434
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { HOUR_MS, DAY_MS } from "../text/datetime.js";
|
|
1
2
|
/** Self-redeploy for a self-hosting team (see build/build-info.ts for why): when main's build
|
|
2
3
|
* inputs have moved past the running build, verify that main is green, compile it into a staging
|
|
3
|
-
* dir, drain the team (no new
|
|
4
|
+
* dir, drain the team (no new runs; in-flight ones finish or are aborted resumably after
|
|
4
5
|
* RESTART_DRAIN_MAX_MS), swap the compiled tree into dist/, and ask the supervisor
|
|
5
6
|
* (src/process/supervisor.ts) to respawn the harness onto it by exiting RESTART_EXIT_CODE. Every
|
|
6
7
|
* step is non-blocking from the orchestrator's poll: the green check and the compile run in the
|
|
@@ -24,38 +25,42 @@
|
|
|
24
25
|
* BuildStatus.restartBlocked, which the dashboards and doctor render — because a stale build that
|
|
25
26
|
* is about to be replaced and one that never will be look identical otherwise (BUGS.md
|
|
26
27
|
* 2026-09-08). A green, compiled build can still be unable to START here — the environment, not
|
|
27
|
-
* the code, fails `tumwater
|
|
28
|
+
* the code, fails `tumwater start`'s startup gate — so that gate is asked before the team is held
|
|
28
29
|
* and again right before the swap, and a failure refuses the restart with a `restart_refused`
|
|
29
30
|
* event instead of trading a running team for a child that exits on its first line (BUGS.md
|
|
30
|
-
* 2026-09-23). Every
|
|
31
|
+
* 2026-09-23). Every run a restart interrupts resumes on the new build through the same resume
|
|
31
32
|
* machinery a Ctrl+C uses, so a restart loses no work. */
|
|
32
|
-
/** The exit code a supervised `tumwater
|
|
33
|
+
/** The exit code a supervised `tumwater start` child uses to say "rebuilt; respawn me" —
|
|
33
34
|
* EX_TEMPFAIL, distinct from success (0), fail() (1) and a forced Ctrl+C (130). */
|
|
34
35
|
export const RESTART_EXIT_CODE = 75;
|
|
35
|
-
/** The COLD-START drain window: how long a pending restart waits for in-flight ROLE
|
|
36
|
-
* aborting them (they resume on the new build) when the orchestrator has too few completed-
|
|
36
|
+
/** The COLD-START drain window: how long a pending restart waits for in-flight ROLE runs before
|
|
37
|
+
* aborting them (they resume on the new build) when the orchestrator has too few completed-run
|
|
37
38
|
* samples to derive one. Measured across the whole unbroken hold, not per head — see
|
|
38
|
-
* Redeployer.drainSince. Director
|
|
39
|
+
* Redeployer.drainSince. Director runs are exempt: an in-flight human prompt extends the hold
|
|
39
40
|
* without any cap (see poll).
|
|
40
41
|
*
|
|
41
|
-
* The live window tracks the team's real
|
|
42
|
-
* completed work-bearing role
|
|
42
|
+
* The live window tracks the team's real run duration: the orchestrator passes the p75 of recent
|
|
43
|
+
* completed work-bearing role runs (InFlightCounts.roleRunP75Ms) and poll uses it in place of
|
|
43
44
|
* this constant once it has enough samples (BUGS.md 2026-09-18). The hand-set 30 minutes had not
|
|
44
45
|
* been re-derived since an earlier backend; measured p50 was 46 min and p75 82 min, so the drain
|
|
45
|
-
* timed out on 60% of
|
|
46
|
+
* timed out on 60% of runs — paying the full idle cost of waiting plus the interruption cost of
|
|
46
47
|
* not waiting. */
|
|
47
48
|
export const RESTART_DRAIN_MAX_MS = 30 * 60_000;
|
|
48
49
|
/** How often a COMPLETED auto-restart may land — at most once per this window (BUGS.md
|
|
49
50
|
* 2026-09-11): under sustained main churn every stale head would otherwise drive a full
|
|
50
51
|
* hold+drain+swap episode back to back, halting the team for a drain over and over. Bounds
|
|
51
|
-
* frequency across episodes; RESTART_DRAIN_MAX_MS bounds the drain within one.
|
|
52
|
-
|
|
52
|
+
* frequency across episodes; RESTART_DRAIN_MAX_MS bounds the drain within one. Cut from twelve
|
|
53
|
+
* hours to four on 2026-10-20: the last eight drains took a median of about 7 min (2 s to
|
|
54
|
+
* 26 min) and only one aborted runs, so the longer wait cost more than the drains it prevented. */
|
|
55
|
+
export const RESTART_COOLDOWN_MS = 4 * HOUR_MS;
|
|
56
|
+
/** The cooldown in whole hours — the one home of that ms→h division, for the warning text. */
|
|
57
|
+
export const RESTART_COOLDOWN_HOURS = RESTART_COOLDOWN_MS / HOUR_MS;
|
|
53
58
|
/** The cooldown's urgency carve-out (BUGS.md 2026-09-30): when the RUNNING build's own commit
|
|
54
|
-
* carries a red baseline verdict, the deferral is cut to this window instead of the
|
|
55
|
-
* a red running build is not churn but the exact predicament the self-redeploy exists
|
|
56
|
-
* and the rate limit protects against storms, not against a team knowingly executing
|
|
57
|
-
* own tree fails. Still a real delay, so consecutive reds cannot storm: one episode
|
|
58
|
-
* window at most, each swap giving the team a chance to merge on green. */
|
|
59
|
+
* carries a red baseline verdict, the deferral is cut to this window instead of the ordinary
|
|
60
|
+
* cooldown — a red running build is not churn but the exact predicament the self-redeploy exists
|
|
61
|
+
* to end, and the rate limit protects against storms, not against a team knowingly executing
|
|
62
|
+
* code its own tree fails. Still a real delay, so consecutive reds cannot storm: one episode
|
|
63
|
+
* per this window at most, each swap giving the team a chance to merge on green. */
|
|
59
64
|
export const RESTART_URGENT_COOLDOWN_MS = 15 * 60_000;
|
|
60
65
|
/** The urgent carve-out in whole minutes — the one home of that ms→min division, beside the
|
|
61
66
|
* constant it derives from, so the three redeployer.ts warnings that restate the length in
|
|
@@ -66,6 +71,6 @@ export const RESTART_URGENT_COOLDOWN_MIN = RESTART_URGENT_COOLDOWN_MS / 60_000;
|
|
|
66
71
|
* different commit, so the aggregate — hours pinned on a stale build while every rebuild dies —
|
|
67
72
|
* raised no alarm anywhere the operator reads. One warning at this age, then at most one per
|
|
68
73
|
* STALE_ESCALATE_EVERY_MS for as long as the episode lasts. */
|
|
69
|
-
export const STALE_ESCALATE_AFTER_MS = 6 *
|
|
74
|
+
export const STALE_ESCALATE_AFTER_MS = 6 * HOUR_MS;
|
|
70
75
|
/** The sustained-pin warning's repeat cadence: daily, not per poll and not per head. */
|
|
71
|
-
export const STALE_ESCALATE_EVERY_MS =
|
|
76
|
+
export const STALE_ESCALATE_EVERY_MS = DAY_MS;
|