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,7 +1,7 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
import fs from "node:fs";
|
|
3
2
|
import path from "node:path";
|
|
4
|
-
import {
|
|
3
|
+
import { errCode } from "../errno.js";
|
|
4
|
+
import { isJsonObject } from "../files/json-object.js";
|
|
5
5
|
import { readJsonFile } from "../files/json-files.js";
|
|
6
6
|
import { changeBaseRev, fileContentAt } from "../git/git.js";
|
|
7
7
|
import { piModelsPath } from "../pi/pi-models.js";
|
|
@@ -32,9 +32,6 @@ export function secretEnvValues(env) {
|
|
|
32
32
|
}
|
|
33
33
|
return out;
|
|
34
34
|
}
|
|
35
|
-
function isRecord(v) {
|
|
36
|
-
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
37
|
-
}
|
|
38
35
|
/** The credentials pi stores: literal `apiKey`s and header values in `models.json`, and the
|
|
39
36
|
* `key`/`access`/`refresh` fields (plus secret-named `env` values) of the sibling `auth.json`.
|
|
40
37
|
* `$NAME` interpolations (secretEnvValues covers those) and `!command` values are skipped. A
|
|
@@ -48,12 +45,12 @@ export function piCredentialValues(modelsPath = piModelsPath()) {
|
|
|
48
45
|
out.push({ name, value });
|
|
49
46
|
};
|
|
50
47
|
const models = readJsonFile(modelsPath);
|
|
51
|
-
if (models &&
|
|
48
|
+
if (models && isJsonObject(models.providers)) {
|
|
52
49
|
for (const [p, cfg] of Object.entries(models.providers)) {
|
|
53
|
-
if (!
|
|
50
|
+
if (!isJsonObject(cfg))
|
|
54
51
|
continue;
|
|
55
52
|
add(`models.json ${p}.apiKey`, cfg.apiKey);
|
|
56
|
-
if (
|
|
53
|
+
if (isJsonObject(cfg.headers)) {
|
|
57
54
|
for (const [h, v] of Object.entries(cfg.headers))
|
|
58
55
|
add(`models.json ${p}.headers.${h}`, v);
|
|
59
56
|
}
|
|
@@ -62,11 +59,11 @@ export function piCredentialValues(modelsPath = piModelsPath()) {
|
|
|
62
59
|
const auth = readJsonFile(path.join(path.dirname(modelsPath), "auth.json"));
|
|
63
60
|
if (auth) {
|
|
64
61
|
for (const [p, cred] of Object.entries(auth)) {
|
|
65
|
-
if (!
|
|
62
|
+
if (!isJsonObject(cred))
|
|
66
63
|
continue;
|
|
67
64
|
for (const f of ["key", "access", "refresh"])
|
|
68
65
|
add(`auth.json ${p}.${f}`, cred[f]);
|
|
69
|
-
if (
|
|
66
|
+
if (isJsonObject(cred.env)) {
|
|
70
67
|
for (const [n, v] of Object.entries(cred.env)) {
|
|
71
68
|
if (SECRET_NAME.test(n))
|
|
72
69
|
add(`auth.json ${p}.env.${n}`, v);
|
|
@@ -85,12 +82,21 @@ export function knownSecrets(env = process.env, modelsPath = piModelsPath()) {
|
|
|
85
82
|
];
|
|
86
83
|
return all.filter((s, i) => all.findIndex((o) => o.value === s.value) === i);
|
|
87
84
|
}
|
|
85
|
+
/** Whether `err` says the path holds no file (deleted, or a parent replaced). */
|
|
86
|
+
function noFile(err) {
|
|
87
|
+
const code = errCode(err);
|
|
88
|
+
return code === "ENOENT" || code === "ENOTDIR";
|
|
89
|
+
}
|
|
90
|
+
/** The finding for a changed file the gate could not read. */
|
|
91
|
+
function unreadable(file, err) {
|
|
92
|
+
return `\`${file}\` could not be read to check for leaked secrets (${errCode(err) ?? "error"})`;
|
|
93
|
+
}
|
|
88
94
|
/** The deterministic gate/stage finding for a change that writes the value of a secret
|
|
89
95
|
* environment variable or stored pi credential into a file (a Node diagnostic report dumps
|
|
90
96
|
* the whole environment). A value already present in the file at the merge-base is not this
|
|
91
97
|
* change's leak. The reason
|
|
92
|
-
* names files and variables, never the value. undefined when nothing leaked
|
|
93
|
-
*
|
|
98
|
+
* names files and variables, never the value. undefined when nothing leaked. A changed file
|
|
99
|
+
* that exists but cannot be read counts as a finding; a deleted file does not. */
|
|
94
100
|
export async function secretLeakReason(wt, mainBranch, files, secrets = knownSecrets()) {
|
|
95
101
|
if (secrets.length === 0)
|
|
96
102
|
return undefined;
|
|
@@ -100,16 +106,30 @@ export async function secretLeakReason(wt, mainBranch, files, secrets = knownSec
|
|
|
100
106
|
const full = path.join(wt, file);
|
|
101
107
|
let stat;
|
|
102
108
|
try {
|
|
103
|
-
stat
|
|
109
|
+
// lstat, not stat: a symlink in the change set is not followed. The gate scans the
|
|
110
|
+
// content each change writes, and a change that adds a symlink writes no content — its
|
|
111
|
+
// target (which lstat's isFile() leaves unreadable, unlike stat's, which follows it out
|
|
112
|
+
// of the worktree) is not what the change put there. Following it would read an
|
|
113
|
+
// arbitrary host path a malicious repo can point a link at, and would flag that outside
|
|
114
|
+
// file's contents as this change's leak.
|
|
115
|
+
stat = fs.lstatSync(full);
|
|
104
116
|
}
|
|
105
|
-
catch {
|
|
117
|
+
catch (err) {
|
|
118
|
+
if (!noFile(err))
|
|
119
|
+
leaks.push(unreadable(file, err));
|
|
106
120
|
continue;
|
|
107
121
|
}
|
|
108
122
|
if (!stat.isFile() || stat.size > MAX_SCAN_BYTES)
|
|
109
123
|
continue;
|
|
110
|
-
|
|
111
|
-
|
|
124
|
+
let head;
|
|
125
|
+
try {
|
|
126
|
+
head = fs.readFileSync(full, "utf8");
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
if (!noFile(err))
|
|
130
|
+
leaks.push(unreadable(file, err));
|
|
112
131
|
continue;
|
|
132
|
+
}
|
|
113
133
|
const hits = secrets.filter((s) => head.includes(s.value));
|
|
114
134
|
if (hits.length === 0)
|
|
115
135
|
continue;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
/** Detecting a reviewer run that re-ran the full suite on a tree the gate's pre-check already
|
|
3
2
|
* verified — pure string logic over the bash command lines a pi run started, no subprocess or
|
|
4
3
|
* file I/O. The review prompt tells such a reviewer not to (src/prompt/gate-prompts.ts), but on
|
|
@@ -1,23 +1,56 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
+
import { readJsonFile, writeJsonAtomic } from "../files/json-files.js";
|
|
2
3
|
import { deleteRefIfAt, refSha } from "../git/git.js";
|
|
3
4
|
import { gitTry, runGit } from "../git/git-run.js";
|
|
4
5
|
import { branchName, mergeRefName, rejectedRefName, reviewSessionDir, roleInboxDir, roleNotesPath, sessionDir, statePath } from "../paths.js";
|
|
5
6
|
import { errorMessage } from "../text/text.js";
|
|
6
7
|
import { LEGACY_ROLE_IDS } from "./legacy-role-ids.js";
|
|
8
|
+
/** Rewrite a JSON state file's `role` field to the id its file name now names; a non-JSON file
|
|
9
|
+
* (or one without a `role` field) is left untouched. `role` is the one field that must match
|
|
10
|
+
* the file name — saveRunnerState writes `statePath(root, state.role)` — so a file moved by
|
|
11
|
+
* migration must not keep its old id inside or it would be saved back to the retired file. */
|
|
12
|
+
function rewriteStateRole(file, role) {
|
|
13
|
+
try {
|
|
14
|
+
const parsed = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
15
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
16
|
+
return;
|
|
17
|
+
const rec = parsed;
|
|
18
|
+
if (rec.role === role)
|
|
19
|
+
return;
|
|
20
|
+
rec.role = role;
|
|
21
|
+
// writeJsonAtomic, not a plain writeFileSync like every other production state writer
|
|
22
|
+
// (INV-AF4): the rewritten file is a role's runner state, and a tmp+rename keeps a crash
|
|
23
|
+
// mid-write (or a concurrent reader) from ever seeing a torn file. A migration that dies
|
|
24
|
+
// before the rename leaves the target at its pre-rewrite bytes — retried next startup —
|
|
25
|
+
// never a truncated state file the runner would read as no state.
|
|
26
|
+
writeJsonAtomic(file, rec);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
/* not a JSON state file — leave it alone */
|
|
30
|
+
}
|
|
31
|
+
}
|
|
7
32
|
/** Move each retired role id's branch, refs and files to the new id (plans/terminology.md "Role
|
|
8
|
-
* names"). Returns one line per artifact
|
|
9
|
-
*
|
|
33
|
+
* names"). Returns one line per artifact, sorted into moved, kept (both
|
|
34
|
+
* ids exist) and failed. State files are the one exception to "kept": when both id-named copies
|
|
35
|
+
* exist and the old-id copy carries the newer end-of-run stamp (`lastRunEndedAt`, or the
|
|
36
|
+
* pre-rename `lastTickEndedAt` a frozen copy carries), that copy is folded over the stale
|
|
37
|
+
* new-name one under the new name (the earlier migration renamed only the file list, not the
|
|
38
|
+
* `role` field inside, so the runner kept writing the old-id name and the two copies drifted —
|
|
39
|
+
* BUGS.md 2026-10-23); otherwise both are left in place. Nothing other than a state file that
|
|
40
|
+
* exists under the new id is overwritten, each artifact fails alone, and pi and native logs stay
|
|
41
|
+
* put as history. */
|
|
10
42
|
export async function migrateLegacyRoleIds(root, legacy = LEGACY_ROLE_IDS) {
|
|
11
|
-
const notes = [];
|
|
43
|
+
const notes = { moved: [], kept: [], failed: [] };
|
|
12
44
|
for (const [oldId, newId] of Object.entries(legacy)) {
|
|
13
45
|
const attempt = async (what, move) => {
|
|
14
46
|
try {
|
|
15
47
|
const note = await move();
|
|
16
|
-
if (note
|
|
17
|
-
|
|
48
|
+
if (note === null)
|
|
49
|
+
return;
|
|
50
|
+
(note.startsWith("kept ") ? notes.kept : notes.moved).push(note);
|
|
18
51
|
}
|
|
19
52
|
catch (err) {
|
|
20
|
-
notes.push(`could not move ${what}: ${errorMessage(err)}`);
|
|
53
|
+
notes.failed.push(`could not move ${what}: ${errorMessage(err)}`);
|
|
21
54
|
}
|
|
22
55
|
};
|
|
23
56
|
await attempt("branch", async () => {
|
|
@@ -45,7 +78,47 @@ export async function migrateLegacyRoleIds(root, legacy = LEGACY_ROLE_IDS) {
|
|
|
45
78
|
return `moved ${from} to ${to}`;
|
|
46
79
|
});
|
|
47
80
|
}
|
|
48
|
-
|
|
81
|
+
// State files get a one-time heal, not "kept": when both id-named copies exist (a state
|
|
82
|
+
// object the earlier migration renamed without rewriting `role`, so the runner kept saving
|
|
83
|
+
// under the old-id name and the two files drifted), fold them into one — when the old-id copy
|
|
84
|
+
// is the newer one, keep it under the new name and drop the stale new-name copy. A live copy
|
|
85
|
+
// carries `lastRunEndedAt`; a frozen copy (never saved since the earlier rename) carries only
|
|
86
|
+
// the pre-rename `lastTickEndedAt`, so the stamp reads either. When either copy is not a state
|
|
87
|
+
// object (unreadable/torn, or a non-object), their stamps tie, or the new-name copy is the
|
|
88
|
+
// newer one, keep both untouched, so the heal never fabricates or destroys a file it does not
|
|
89
|
+
// understand.
|
|
90
|
+
await attempt(`state ${statePath(root, oldId)}`, async () => {
|
|
91
|
+
const from = statePath(root, oldId);
|
|
92
|
+
const to = statePath(root, newId);
|
|
93
|
+
if (!fs.existsSync(from))
|
|
94
|
+
return null;
|
|
95
|
+
if (!fs.existsSync(to)) {
|
|
96
|
+
fs.renameSync(from, to);
|
|
97
|
+
rewriteStateRole(to, newId);
|
|
98
|
+
return `moved ${from} to ${to}`;
|
|
99
|
+
}
|
|
100
|
+
const stamp = (p) => {
|
|
101
|
+
const j = readJsonFile(p);
|
|
102
|
+
if (typeof j?.lastRunEndedAt === "number")
|
|
103
|
+
return j.lastRunEndedAt;
|
|
104
|
+
return typeof j?.lastTickEndedAt === "number" ? j.lastTickEndedAt : -2; // retired-name-ok: legacy state field the frozen copy carries
|
|
105
|
+
};
|
|
106
|
+
const oldStamp = stamp(from);
|
|
107
|
+
const newStamp = stamp(to);
|
|
108
|
+
if (oldStamp < 0 || newStamp < 0 || oldStamp === newStamp)
|
|
109
|
+
return `kept ${from} and ${to}: both exist`;
|
|
110
|
+
if (oldStamp < newStamp)
|
|
111
|
+
return `kept ${from} and ${to}: both exist`;
|
|
112
|
+
// The old-id file holds the newer state (the live runner kept saving under the old name
|
|
113
|
+
// after the earlier migration). Fold it into the new-name path atomically: renameSync
|
|
114
|
+
// replaces the destination and removes the source in one step, so a crash between the two
|
|
115
|
+
// cannot leave the new-name file torn over the still-present old copy (which would read as
|
|
116
|
+
// -2 next time and wedge the heal in "kept").
|
|
117
|
+
fs.renameSync(from, to);
|
|
118
|
+
rewriteStateRole(to, newId);
|
|
119
|
+
return `healed ${from} and ${to}: kept ${from}, newer`;
|
|
120
|
+
});
|
|
121
|
+
for (const pathFor of [roleNotesPath, roleInboxDir, sessionDir, reviewSessionDir]) {
|
|
49
122
|
const from = pathFor(root, oldId);
|
|
50
123
|
const to = pathFor(root, newId);
|
|
51
124
|
await attempt(from, async () => {
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
/** 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"
|
|
3
2
|
* instruction text. Split out of roles.ts (2026-10-01, organize) so the catalog's embedded
|
|
4
3
|
* prompt prose lives apart from the derived registries and classification helpers, which stayed
|
|
5
4
|
* in roles.ts. Pure catalog data — the shared instruction fragments role prompts embed live in
|
|
6
5
|
* role-guidance.ts (import-only downward, so prompt assembly depends on both without a cycle).
|
|
7
6
|
* roles.ts re-exports ROLES and Role, so every existing importer keeps its import path. */
|
|
8
|
-
import { backlogMoveGuidance, DECOMPOSITION_GUIDANCE, NEEDS_REPLAN_NOTE, NEEDS_REVIEW_NOTE, PLAN_SIZING, searchGuidance, VALIDATION_GAP_GUIDANCE, VALIDATION_GAP_QUERY, VALIDATION_GAP_TALLY, WAITING_FOR_FAILURE_NOTE, WAITING_FOR_FAILURE_PREFIX, } from "./role-guidance.js";
|
|
7
|
+
import { backlogMoveGuidance, CONVERGENCE_HOLD_MARKER, 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";
|
|
9
8
|
import { roleCommitGrep } from "./legacy-role-ids.js";
|
|
10
9
|
import { NOTHING_TO_DO } from "../verdict/reply-contract.js";
|
|
11
10
|
/** The trailer the readme role's commits carry and its `git log --grep` reads back; git parses
|
|
@@ -14,10 +13,10 @@ import { NOTHING_TO_DO } from "../verdict/reply-contract.js";
|
|
|
14
13
|
const README_TRAILER = "Run: readme #";
|
|
15
14
|
const README_TRAILER_GREP = "^(Run|Tick): readme #"; // vocabulary-ok: legacy name read from old refs or commits
|
|
16
15
|
const README_TRAILER_LEGACY = "Tick: readme #"; // vocabulary-ok: legacy name read from old refs or commits
|
|
17
|
-
/** The opinionated role catalog. Every
|
|
18
|
-
* the role-specific "find something to do" half of the
|
|
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.
|
|
19
18
|
*
|
|
20
|
-
* Order matters: it is the scheduling priority when
|
|
19
|
+
* Order matters: it is the scheduling priority when roles are otherwise tied
|
|
21
20
|
* (e.g. the startup burst), so shipping work (feature, bugfix) outranks hygiene. */
|
|
22
21
|
export const ROLES = [
|
|
23
22
|
{
|
|
@@ -37,12 +36,18 @@ export const ROLES = [
|
|
|
37
36
|
4. A plan too large to finish in this run is not split by you: append the note
|
|
38
37
|
${NEEDS_REVIEW_NOTE}
|
|
39
38
|
under its heading, skip it, and implement the next available plan that fits. You may mark
|
|
40
|
-
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.
|
|
41
46
|
5. Implement it completely: code, tests, and any docs. The reviewer checks your diff against
|
|
42
47
|
the entry's files-touched list and acceptance criteria, so land everything the entry
|
|
43
48
|
promises, or update the entry to say what changed and why. When a plan's anchors no longer
|
|
44
49
|
match the code, correct the entry in the same change instead of refusing.
|
|
45
|
-
6. Mark the plan done in PLANS.md — ${backlogMoveGuidance("PLANS.md", "## Planned", "## Done", "PLANS-DONE.md")}
|
|
50
|
+
6. Mark the plan done in PLANS.md — ${backlogMoveGuidance("PLANS.md", "## Planned", "## Done", "PLANS-DONE.md", "done")}
|
|
46
51
|
7. Verify last, after the PLANS.md edit, so one run of the project's check covers everything
|
|
47
52
|
you changed (see "Leave the project working" below).
|
|
48
53
|
A plan that resists implementation is a finding: refuse it with the objection recorded rather
|
|
@@ -63,7 +68,7 @@ than forcing it.`,
|
|
|
63
68
|
heading, and end the run. Do not keep investigating without new evidence.
|
|
64
69
|
3. Fix it, and add a regression test that fails without the fix — run that test to watch it
|
|
65
70
|
fail before the fix and pass after.
|
|
66
|
-
4. Mark it fixed in BUGS.md — ${backlogMoveGuidance("BUGS.md", "## Open", "## Fixed", "BUGS-FIXED.md")}
|
|
71
|
+
4. Mark it fixed in BUGS.md — ${backlogMoveGuidance("BUGS.md", "## Open", "## Fixed", "BUGS-FIXED.md", "fixed")}
|
|
67
72
|
5. In the moved entry, write the required validation-gap trace line (format below).
|
|
68
73
|
6. Verify last, after the BUGS.md edits, so one run of the project's check covers everything
|
|
69
74
|
you changed (see "Leave the project working" below).
|
|
@@ -90,11 +95,30 @@ within that budget, there is nothing to do.`,
|
|
|
90
95
|
- A plan carrying a ${NEEDS_REVIEW_NOTE} note outranks adding another plan: split it into
|
|
91
96
|
independently mergeable sub-plans that cross-reference each other (per PLAN_SIZING below,
|
|
92
97
|
each with its own acceptance criteria), then remove the note. That split is this run's task.
|
|
98
|
+
- A BUGS.md \`## Open\` entry carrying a ${NEEDS_REVIEW_NOTE} or ${NEEDS_REPLAN_NOTE} note
|
|
99
|
+
(the feature or bugfix role parked it as too large for one run) also outranks adding another
|
|
100
|
+
plan: resolve it in the same run by splitting it into independently fixable sub-bugs (each
|
|
101
|
+
its own BUGS.md heading) then removing the note, or by lifting the note when the work does
|
|
102
|
+
not decompose, since no
|
|
103
|
+
other role takes a held bug. That split is this run's task.
|
|
104
|
+
- A plan held by the automatic convergence hold (${CONVERGENCE_HOLD_MARKER}) also outranks
|
|
105
|
+
adding another plan: the text after the dash is the reviewer's surviving objections, so read
|
|
106
|
+
the quoted objections and the code they name and rewrite the plan so an implementation
|
|
107
|
+
following it would answer each — correcting the approach or the anchors, tightening the
|
|
108
|
+
acceptance criteria, or splitting it per PLAN_SIZING — then remove the note.
|
|
93
109
|
- A plan carrying a ${NEEDS_REPLAN_NOTE} note also outranks adding another plan: read the
|
|
94
110
|
quoted objections and the code they name, then rewrite the plan so an implementation
|
|
95
111
|
following it would answer them — correcting the approach or the anchors, tightening the
|
|
96
112
|
acceptance criteria, splitting it per PLAN_SIZING, or refusing it with the objection
|
|
97
113
|
recorded when it should not be done — and remove both the note and the quoted objections.
|
|
114
|
+
- When you lift a Needs-review or Needs-replan note (a split or a rewrite) and the change
|
|
115
|
+
has NOT merged, keep the held count instead of letting it reset: remove any existing
|
|
116
|
+
\`**Previously held N**\` line on the surviving parent and every child part the split
|
|
117
|
+
produces, then write \`${PRIOR_HELD_PREFIX}<N>**\` at the lifted note's count on the
|
|
118
|
+
parent and copy it to each child, so exactly one marker survives and heldCount reads the
|
|
119
|
+
lifted count everywhere — a merged parent (one whose plan left \`## Planned\`) leaves no
|
|
120
|
+
marker, and a note with no \`(held N)\` tag (the automatic convergence hold) is lifted
|
|
121
|
+
without writing a \`**Previously held 0**\` marker.
|
|
98
122
|
- Otherwise, when PLANS.md \`## Planned\` already holds one more eligible plan than there
|
|
99
123
|
are feature instances (one waiting per instance, plus one for the next planner run),
|
|
100
124
|
end with ${NOTHING_TO_DO} — feature has work, and a waiting plan is refined by the
|
|
@@ -113,6 +137,7 @@ within that budget, there is nothing to do.`,
|
|
|
113
137
|
at them in ranges.
|
|
114
138
|
5. Write it as a short markdown section under \`## Planned\` in PLANS.md: goal, approach, files
|
|
115
139
|
touched, acceptance criteria.
|
|
140
|
+
${PLAN_QUEUE_GUIDANCE}
|
|
116
141
|
${PLAN_SIZING}
|
|
117
142
|
${DECOMPOSITION_GUIDANCE}`,
|
|
118
143
|
},
|
|
@@ -154,7 +179,7 @@ edit the brief between the tumwater:prompt markers.`,
|
|
|
154
179
|
title: "code organizer",
|
|
155
180
|
// Written against the 2026-10-05/06 churn: with minor fixes exhausted and the shared
|
|
156
181
|
// small-and-self-contained scope rule in force, organize reorganized the whole tree one
|
|
157
|
-
// directory per
|
|
182
|
+
// directory per run (45 of 86 merges in four hours) with no target structure ever
|
|
158
183
|
// stated. Major refactors stay welcome; they must be considered whole and merge whole.
|
|
159
184
|
find: `Find ONE way the code could be better organized, and restructure it.
|
|
160
185
|
1. First rank the production source files (not the tests) by \`wc -l\`. A production module
|
|
@@ -163,7 +188,8 @@ edit the brief between the tumwater:prompt markers.`,
|
|
|
163
188
|
file of similar size: a test file's shape follows the module it covers. An outlier that is
|
|
164
189
|
mostly one large function or closure cannot be split in one run: do not start the split,
|
|
165
190
|
write it as a plan in PLANS.md under ## Planned that states the target structure (which
|
|
166
|
-
state and handlers move into which module).
|
|
191
|
+
state and handlers move into which module).
|
|
192
|
+
${PLAN_QUEUE_GUIDANCE} Then look for other minor improvements to
|
|
167
193
|
the existing structure: a module in the wrong directory, a missing separation between
|
|
168
194
|
layers, or inconsistent file naming.
|
|
169
195
|
2. When the minor improvements are exhausted, a major refactor — new directories, a
|
|
@@ -233,7 +259,8 @@ scratch analysis scripts — that is a different, much larger task.`,
|
|
|
233
259
|
this run's ONE task: move each listed entry to the section its heading's dates say it belongs in
|
|
234
260
|
(cut and paste, under the existing \`## \` heading — never add, remove, or rename a \`## \`
|
|
235
261
|
heading), leave its text verbatim, and change nothing else. An entry listed under PLANS-DONE.md's
|
|
236
|
-
\`## Done\` with no done date
|
|
262
|
+
\`## Done\` with no done date is already finished and archived there: keep it in place and only add the
|
|
263
|
+
missing \`done YYYY-MM-DD\` to its \`### \` heading — never move it back under PLANS.md's \`## Planned\`.
|
|
237
264
|
|
|
238
265
|
Otherwise, pick ONE kind of uncleanliness — dead code, misleading names, commented-out blocks,
|
|
239
266
|
overly clever constructs, missing or wrong doc comments on public surfaces, inconsistent
|
|
@@ -319,6 +346,52 @@ Safety rails for anything you launch:
|
|
|
319
346
|
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>:
|
|
320
347
|
FLOW: <name> — passed
|
|
321
348
|
${NOTHING_TO_DO}`,
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
id: "ci",
|
|
352
|
+
tier: "default",
|
|
353
|
+
title: "CI parity runner",
|
|
354
|
+
find: `Run the CI workflow's own jobs against main's tip and repair what fails. You close the gap
|
|
355
|
+
between what GitHub CI runs and what the team's own merge gate skips: the workflow's test job runs
|
|
356
|
+
the project's whole test suite and e2e suite, while the merge gate runs only the affected tests —
|
|
357
|
+
so only you run the whole thing where it counts, before a user, a release tag, or a post-merge
|
|
358
|
+
reviewer finds what a green gate missed.
|
|
359
|
+
|
|
360
|
+
Steps:
|
|
361
|
+
1. Read .github/workflows/ci.yml fresh each run and execute its jobs' own run: steps verbatim
|
|
362
|
+
against main's tip in this worktree, in order — for an npm project like this repo, that is
|
|
363
|
+
\`npm ci\`, then \`npm test\`, then \`npm run test:e2e\`; when the tip is a push-to-main tip,
|
|
364
|
+
also \`npm pack\` (the workflow's package job). The actions/checkout, setup-node and git
|
|
365
|
+
identity are this worktree's own. Reading the workflow means a step added to it is picked
|
|
366
|
+
up without a code change.
|
|
367
|
+
2. A failing step is the work: reproduce it, fix the source/tests/docs it names, re-run that
|
|
368
|
+
step until green, and commit the fix as the run's one change. A step that fails once and
|
|
369
|
+
passes on the re-run is a flake — file ONE BUGS.md entry naming the test and the flake and
|
|
370
|
+
change nothing else.
|
|
371
|
+
3. Whatever a failing step's own cause you cannot fix is filed in BUGS.md with the failing
|
|
372
|
+
output quoted.
|
|
373
|
+
|
|
374
|
+
Boundaries:
|
|
375
|
+
- You never edit .github/workflows/* (you read them) and never weaken a test to make a step
|
|
376
|
+
pass.
|
|
377
|
+
- Your product is a verdict and a fix: when everything is green, declare nothing-to-do (here
|
|
378
|
+
\`no_change\` means "checked, green") rather than inventing busywork.
|
|
379
|
+
|
|
380
|
+
The parity block and the CI line — both required on every run: your prompt carries a CI parity
|
|
381
|
+
block from this team's own record naming the main tip and lock hash the last run covered. When it
|
|
382
|
+
says \`current\` (main unmoved since the last green run covered exactly this tip with exactly this
|
|
383
|
+
lock), declare nothing-to-do in ONE model run without running the suite — that is the cheap no-op
|
|
384
|
+
the block exists for. When it is stale (main moved, the lock changed, or the last run failed), run
|
|
385
|
+
the full workflow as the steps above say. Your final reply then carries one result-carrying line —
|
|
386
|
+
\`CI: <sha> — <passed|failed>\` — naming the main tip you covered and whether it passed or failed,
|
|
387
|
+
placed just before your ending (the nothing-to-do line, or the SUMMARY block when you committed a
|
|
388
|
+
fix). The verdict is required and the sha must be a hex id: a bare \`CI: <sha>\` is not a result and
|
|
389
|
+
is not recorded, so the parity block cannot advance on a truncated reply (the same rule as qa's
|
|
390
|
+
FLOW line). tumwater records it for the next run's parity block. A passing run's reply ends with two
|
|
391
|
+
lines in this form:
|
|
392
|
+
CI: <sha> — passed
|
|
393
|
+
${NOTHING_TO_DO}
|
|
394
|
+
`,
|
|
322
395
|
},
|
|
323
396
|
{
|
|
324
397
|
id: "selfcheck",
|
|
@@ -330,6 +403,9 @@ the last day (per-role outcome counts, each role's time and spend by outcome, no
|
|
|
330
403
|
warning clusters, review rejections, and what merged). It is your entire evidence base — do not go
|
|
331
404
|
looking for the event log or per-role transcripts yourself; tumwater injects the digest because
|
|
332
405
|
the live log lives outside your worktree.
|
|
406
|
+
The digest ends with a ## Fast merge guardrails section when the post-merge machinery is failing
|
|
407
|
+
quietly (main red over 30 minutes, quarantine aged or oversized). Each line there is tumwater's
|
|
408
|
+
own response failing, so it is fileable as it stands under rule 1.
|
|
333
409
|
1. A cluster is a bug ONLY when tumwater's RESPONSE to it is wrong — a failure that raised no
|
|
334
410
|
alarm, drove the wrong state or sleep ladder, latched a stale verdict, or hid itself from
|
|
335
411
|
the user. A mere infrastructure failure (the model server was slow, pi exited non-zero)
|
|
@@ -349,6 +425,44 @@ the live log lives outside your worktree.
|
|
|
349
425
|
entry, so the bugfix role can reproduce it.
|
|
350
426
|
BUGS.md is your only write; never edit source, tests, or docs. If every cluster is ordinary
|
|
351
427
|
infrastructure weather or already filed, there is nothing to do.`,
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
id: "feedback",
|
|
431
|
+
tier: "default",
|
|
432
|
+
title: "feedback: files tumwater bugs upstream on GitHub",
|
|
433
|
+
find: `File ONE bug per run as a GitHub issue on github.com/znation/tumwater, or declare
|
|
434
|
+
nothing-to-do, from the <failure-digest> block in your prompt: a deterministic digest of this
|
|
435
|
+
project's own event log over the last day (per-role outcome counts, each role's time and spend by
|
|
436
|
+
outcome, normalized error and warning clusters, review rejections, and what merged). It is your
|
|
437
|
+
entire evidence base — do not go looking for the event log or per-role transcripts yourself; tumwater
|
|
438
|
+
injects the digest because the live log lives outside your worktree.
|
|
439
|
+
The digest ends with a ## Fast merge guardrails section when the post-merge machinery is failing
|
|
440
|
+
quietly (main red over 30 minutes, quarantine aged or oversized). Each line there is tumwater's
|
|
441
|
+
own response failing, so it is fileable as it stands under rule 1.
|
|
442
|
+
1. A cluster is a bug ONLY when tumwater's RESPONSE to it is wrong — a failure that raised no
|
|
443
|
+
alarm, drove the wrong state or sleep ladder, latched a stale verdict, or hid itself from
|
|
444
|
+
the user. A mere infrastructure failure (the model server was slow, pi exited non-zero)
|
|
445
|
+
is weather, not a bug: filing it produces an issue no maintainer can act on.
|
|
446
|
+
2. Read the digest for that wrong response — 44 identical errors that raised no warning, a run
|
|
447
|
+
that failed in 200 ms then climbed the idle ladder, a cluster that begins on the date a
|
|
448
|
+
specific commit merged.
|
|
449
|
+
3. Rank what you would file by LOSS, not by run count: the digest's time-and-spend table and
|
|
450
|
+
top loss causes price each cause in agent-hours and dollars, and a cluster that burned hours
|
|
451
|
+
outranks one that burned seconds — cite its cost when it is the reason you file.
|
|
452
|
+
4. Before filing, dedupe: check the "Previously filed from this install" block in your prompt
|
|
453
|
+
and run \`gh issue list --repo znation/tumwater --search <cluster terms>\` — never file a
|
|
454
|
+
duplicate. When the same cluster is already filed, there is nothing to do.
|
|
455
|
+
5. File it with \`gh issue create --repo znation/tumwater --title … --body …\` from the shell
|
|
456
|
+
and verify the issue URL in the command's output before you report it. The body cites the
|
|
457
|
+
cluster's normalized key, its count and roles, the correlated \`merged\` commit, and the
|
|
458
|
+
output of \`tumwater version\`; redact absolute paths and secrets — file only what the digest
|
|
459
|
+
itself already shows.
|
|
460
|
+
You never edit files in this repo — \`gh\` is your only write. End every run with the
|
|
461
|
+
${NOTHING_TO_DO} sentinel; when you filed, one \`FILED: #<n> — <title>\` line rides just above it
|
|
462
|
+
(named as qa's FLOW line is). A run that cannot file because \`gh\` is missing, unauthenticated,
|
|
463
|
+
or failed ends WITHOUT the sentinel, naming the failure in your final prose so tumwater's
|
|
464
|
+
finished-without-changes warning surfaces it. If every cluster is ordinary infrastructure weather
|
|
465
|
+
or already filed, there is nothing to do.`,
|
|
352
466
|
},
|
|
353
467
|
{
|
|
354
468
|
id: "security",
|
|
@@ -461,6 +575,7 @@ arguments, config files, environment), and rough edges you meet while running th
|
|
|
461
575
|
- promote a recurring non-\`none\` \`gap:\` tag — three or more Fixed entries carrying it —
|
|
462
576
|
into a PLANS.md entry for the infrastructure that would retire it, citing those entries.
|
|
463
577
|
${VALIDATION_GAP_TALLY}
|
|
578
|
+
${PLAN_QUEUE_GUIDANCE}
|
|
464
579
|
You edit only markdown — never source.
|
|
465
580
|
|
|
466
581
|
Reading the backlog files: PLANS.md and BUGS.md hold open work, so read them whole when your move
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
/** Shared instruction fragments role prompts and prompt assembly embed verbatim. Pure
|
|
3
2
|
* data: this module imports only the dependency-free legacy-role-ids, so prompt assembly
|
|
4
3
|
* can depend on it without a cycle.
|
|
5
4
|
* Split from roles.ts, whose catalog (now role-catalog.ts) find texts embed these fragments
|
|
6
5
|
* while prompt.ts embeds them too — the wording is one concern, the catalog another. */
|
|
7
6
|
import { roleCommitGrep } from "./legacy-role-ids.js";
|
|
8
|
-
/** Shared guidance for any
|
|
7
|
+
/** Shared guidance for any role about to record a plan or bug: split independent parts
|
|
9
8
|
* into their own entries. Defined once so the director and role prompts cannot drift.
|
|
10
9
|
* Lives here (not in prompt.ts) because two role `find` texts embed it — keeping this
|
|
11
10
|
* module import-free, with the dependency running one way: prompt assembly → roles,
|
|
@@ -14,8 +13,8 @@ export const DECOMPOSITION_GUIDANCE = `Before recording a plan or bug, check whe
|
|
|
14
13
|
into independent subparts (separate features, or separate bugs). If it does, record each part as
|
|
15
14
|
its own PLANS.md/BUGS.md entry that cross-references its siblings, so roles can pick them up
|
|
16
15
|
independently; if the parts are not truly independent, keep a single entry.`;
|
|
17
|
-
/** Shared instruction for closing a backlog entry (the feature
|
|
18
|
-
* the bugfix
|
|
16
|
+
/** Shared instruction for closing a backlog entry (the feature role moving a plan to Done,
|
|
17
|
+
* the bugfix role moving a bug to Fixed). Written against the observed failure (PLANS.md
|
|
19
18
|
* 2026-09-30, part 1/3): "move it to a Done section" reads as "create a section", and five
|
|
20
19
|
* commits left PLANS.md with two `## Done` headings — so the wording names the file's EXISTING
|
|
21
20
|
* resolved heading, forbids touching `## ` structure, and gives the verifiable invariant
|
|
@@ -23,11 +22,16 @@ independently; if the parts are not truly independent, keep a single entry.`;
|
|
|
23
22
|
* numbered step of their task. The pasted entry does not stay there: tumwater moves it to the top
|
|
24
23
|
* of `archive` when the change commits (plans/backlog-archive.md), which the last line says so no
|
|
25
24
|
* run opens the archive to do it by hand. Takes the file, section and archive names so the feature
|
|
26
|
-
* and bugfix texts cannot drift apart; lives here with the other shared fragments.
|
|
27
|
-
|
|
25
|
+
* and bugfix texts cannot drift apart; lives here with the other shared fragments. Also takes
|
|
26
|
+
* the closing token ("done" for a finished plan, "fixed" for a BUGS.md record) chosen by the
|
|
27
|
+
* caller, so the verb and the heading-key rule are named instead of left for the role to guess. */
|
|
28
|
+
export function backlogMoveGuidance(file, openSection, resolvedSection, archive, token) {
|
|
28
29
|
return `move the entry, step by step:
|
|
29
30
|
a. cut the entry out of \`${openSection}\`;
|
|
30
|
-
b. add the closing
|
|
31
|
+
b. add the closing stamp to its \`### \` heading, at the end — \`— ${token} YYYY-MM-DD by the <role> role\`
|
|
32
|
+
(a finished plan appends it after its existing \`(planned …)\` parenthetical; the heading
|
|
33
|
+
text before its first \` (\` must not change, or the gate reads it as a brand-new entry
|
|
34
|
+
under \`${resolvedSection}\` rather than a move);
|
|
31
35
|
c. paste it as the first entry under the file's existing \`${resolvedSection}\` heading;
|
|
32
36
|
d. if it was the last entry under \`${openSection}\`, leave a \`_None yet._\` placeholder
|
|
33
37
|
there.
|
|
@@ -39,7 +43,7 @@ export function backlogMoveGuidance(file, openSection, resolvedSection, archive)
|
|
|
39
43
|
* a comment inside the template would become prompt text. */
|
|
40
44
|
const REQUIRES_PART_FORM = "requires part N/M landed"; // vocabulary-ok: requiredParts parses this heading syntax
|
|
41
45
|
/** Shared sizing rule for anyone writing a plan (the plan role and the director): the feature
|
|
42
|
-
*
|
|
46
|
+
* role is one mid-sized local model working alone in one run, and the review gate rejects a
|
|
43
47
|
* change that lands less than its entry promises — so a plan must fit that run. Oversized plans
|
|
44
48
|
* were the pattern behind "half-done against its own plan" rejections. The last sentence is the
|
|
45
49
|
* self-hosting build lag (BUGS.md 2026-09-23): plan 4b bundled "the merge preserves the live
|
|
@@ -58,6 +62,17 @@ ranges, because line anchors go stale with every merge. When tumwater is buildin
|
|
|
58
62
|
every commit merges under the build that predates it, so a
|
|
59
63
|
change to how merges behave and any step that depends on it are separate sub-plans, the second
|
|
60
64
|
merge only once the first is the running build.`;
|
|
65
|
+
/** Shared guidance for anyone writing a plan (the plan role, the organize role, and the
|
|
66
|
+
* director): a new plan joins the BACK of the `## Planned` queue, never the top. Part of the
|
|
67
|
+
* define-once pattern of DECOMPOSITION_GUIDANCE/PLAN_SIZING — file order under `## Planned` IS
|
|
68
|
+
* the work queue: claim assignment takes the first free entry in file order (`assignNext`,
|
|
69
|
+
* src/scheduling/claims.ts), so an entry set at the top jumps ahead of work already waiting.
|
|
70
|
+
* Lives here because three role `find` texts and the director's routing bullet embed it. */
|
|
71
|
+
export const PLAN_QUEUE_GUIDANCE = `A new plan joins the queue at the BACK: append the entry at the
|
|
72
|
+
END of \`## Planned\`, after every existing entry, never at the top. File order under
|
|
73
|
+
\`## Planned\` is the work queue — claim assignment takes the first free entry in that order
|
|
74
|
+
(\`assignNext\`, src/scheduling/claims.ts) — so an entry inserted at the top jumps ahead of work
|
|
75
|
+
already waiting.`;
|
|
61
76
|
/** The closed vocabulary for the validation-gap trace (plans/repair-traces.md): what made a bug
|
|
62
77
|
* hard to *confirm*, which is the only evidence of where this project's test infrastructure is
|
|
63
78
|
* weakest. Closed on purpose so the traces aggregate, and `none` is a written value rather than an
|
|
@@ -109,36 +124,66 @@ export const VALIDATION_GAP_QUERY = `grep -snE '\\*\\*Validation gap:\\*\\* (${V
|
|
|
109
124
|
* parsing the date or the wording out of the full template — the same split as
|
|
110
125
|
* NEEDS_REPLAN_PREFIX. */
|
|
111
126
|
export const NEEDS_REVIEW_PREFIX = `**Needs review `;
|
|
112
|
-
/** The
|
|
113
|
-
*
|
|
127
|
+
/** The tag text before the held count, shared by the note templates and the parser
|
|
128
|
+
* (backlog-eligibility's heldCount) so the two cannot drift: the live count on a Needs-review
|
|
129
|
+
* or Needs-replan note is written inline as `(held N)`, with `N` one past the surviving prior
|
|
130
|
+
* count (the feature role appends it, the plan role's split carries it via PRIOR_HELD_NOTE). */
|
|
131
|
+
export const HELD_TAG_PREFIX = `(held `;
|
|
132
|
+
/** The markdown note the feature role appends to a plan it cannot finish in one run, so the plan
|
|
133
|
+
* role can split it. Mirrors the **Refused …** note convention: a note the next fresh run reads,
|
|
114
134
|
* with no code parsing it. Defined once so the feature and plan texts and the director's routing
|
|
115
|
-
* clause cannot drift.
|
|
116
|
-
|
|
135
|
+
* clause cannot drift. The trailing `(held <N>)` tag (HELD_TAG_PREFIX) is the live held count,
|
|
136
|
+
* written as one past the count surviving on the entry; it sits inside the line, so
|
|
137
|
+
* NEEDS_REVIEW_PREFIX still recognizes the note. */
|
|
138
|
+
export const NEEDS_REVIEW_NOTE = `${NEEDS_REVIEW_PREFIX}<YYYY-MM-DD> by feature: too large for one run ${HELD_TAG_PREFIX}<N>)**`;
|
|
139
|
+
/** The literal reason the automatic convergence hold writes into a held plan's note
|
|
140
|
+
* (holdEntryAfterExhaustion, src/runner/revision.ts, builds the note as
|
|
141
|
+
* `**Needs review … by <role>: could not converge — <surviving objections>**`, INV-BH4).
|
|
142
|
+
* Exported so the writer and the reader share one literal: it sits between holdEntryAfterExhaustion
|
|
143
|
+
* (which writes the note) and the plan role's charter (role-catalog.ts `find`) which reads it, so
|
|
144
|
+
* reason to recognize the automatic hold as distinct from the feature role's too-large
|
|
145
|
+
* ${NEEDS_REVIEW_NOTE} note and the ${NEEDS_REPLAN_PREFIX} note — both carry no
|
|
146
|
+
* `could not converge` text, so the charter routes each hold to its own action without matching
|
|
147
|
+
* on a second literal. Add no second spelling of this text. */
|
|
148
|
+
export const CONVERGENCE_HOLD_MARKER = "could not converge";
|
|
149
|
+
/** The marker a lifted hold leaves behind, so a split or rewrite carries the count instead of
|
|
150
|
+
* letting it reset: `**Previously held N**` on the note's line. The live count is `(held N)` on
|
|
151
|
+
* the note; the surviving marker after a lift is `**Previously held N**` — heldCount reads the
|
|
152
|
+
* first as the priority, then the second. */
|
|
153
|
+
export const PRIOR_HELD_PREFIX = `**Previously held `;
|
|
154
|
+
/** The literal marker a lift leaves on a split or rewrite so the held count survives instead of
|
|
155
|
+
* resetting: a `**Previously held <N>**` line at the same count the lifted note carried (the
|
|
156
|
+
* <N> here is the value the note's `(held N)` tag held). heldCount reads this as the fallback
|
|
157
|
+
* when no live note is present, so the count round-trips a split. */
|
|
158
|
+
export const PRIOR_HELD_NOTE = `${PRIOR_HELD_PREFIX}<N>**`;
|
|
117
159
|
/** The literal prefix every Needs-replan note starts with. Exported so a reader that only has to
|
|
118
160
|
* recognize one (the backlog index's ` [blocked: needs replan]` mark) can match on it instead of
|
|
119
161
|
* parsing the date or the round count out of the full template. */
|
|
120
162
|
export const NEEDS_REPLAN_PREFIX = `**Needs replan `;
|
|
121
|
-
/** The markdown note the feature
|
|
122
|
-
* final revision round, carrying the reviewer's objections back to the strong-tier plan
|
|
163
|
+
/** The markdown note the feature role appends under a plan whose change was rejected after its
|
|
164
|
+
* final revision round, carrying the reviewer's objections back to the strong-tier plan role
|
|
123
165
|
* instead of letting feature re-author the same plan. Same convention as NEEDS_REVIEW_NOTE: a
|
|
124
|
-
* note a later fresh
|
|
125
|
-
|
|
166
|
+
* note a later fresh run reads, with no code parsing it. The trailing `(held <H>)` tag
|
|
167
|
+
* (HELD_TAG_PREFIX) is the live held count, one past the count surviving on the entry; the
|
|
168
|
+
* placeholder is `<H>` (for held) so it reads apart from the `<N>` review-round count earlier
|
|
169
|
+
* in the same line. It sits inside the line, so NEEDS_REPLAN_PREFIX still recognizes the note. */
|
|
170
|
+
export const NEEDS_REPLAN_NOTE = `${NEEDS_REPLAN_PREFIX}<YYYY-MM-DD> by feature: rejected after <N> review rounds ${HELD_TAG_PREFIX}<H>)**`;
|
|
126
171
|
/** The literal prefix every Waiting-for-the-next-failure note starts with. Exported so a reader
|
|
127
172
|
* that only has to recognize one (the backlog index's ` [blocked: waiting for the next failure]`
|
|
128
173
|
* mark) can match on it instead of parsing the date or the wording out of the full template. */
|
|
129
174
|
export const WAITING_FOR_FAILURE_PREFIX = `**Waiting for the next failure `;
|
|
130
|
-
/** The markdown note the bugfix
|
|
175
|
+
/** The markdown note the bugfix role writes under an open bug it cannot reproduce once it has made
|
|
131
176
|
* the failure explain itself, so bugfix stops spending runs without new evidence. Same convention
|
|
132
|
-
* as NEEDS_REPLAN_NOTE: a note a later fresh
|
|
177
|
+
* as NEEDS_REPLAN_NOTE: a note a later fresh run reads. It lifts when whoever records the next
|
|
133
178
|
* occurrence deletes the line, or by `tumwater bug --release <n>`. */
|
|
134
179
|
export const WAITING_FOR_FAILURE_NOTE = `${WAITING_FOR_FAILURE_PREFIX}<YYYY-MM-DD> by bugfix: <what the next failure's message will show>**`;
|
|
135
180
|
/** How a role with no backlog (organize, clean, dedupe, perf, security, robustness, improve) finds
|
|
136
181
|
* its one task, as numbered steps. Written against the observed failure: with nothing to point
|
|
137
182
|
* at, a local model reads the codebase file by file — thirty whole-file reads, ~300 KB of tool
|
|
138
|
-
* output — and then either fills its window or declares nothing-to-do (improve: 41 of 44
|
|
183
|
+
* output — and then either fills its window or declares nothing-to-do (improve: 41 of 44 runs in
|
|
139
184
|
* the first week of September landed nothing). Cheap signals shortlist candidates; a decision
|
|
140
185
|
* deadline ends the search; the harness's own commit subjects (`tumwater(<role>): …`) are the
|
|
141
|
-
* only cross-
|
|
186
|
+
* only cross-run memory of what the role did lately, so the text names them. Takes the role id
|
|
142
187
|
* so the git command is literal, not a placeholder the model has to fill in. */
|
|
143
188
|
export function searchGuidance(roleId) {
|
|
144
189
|
return `How to search — do not read the codebase file by file: a whole-tree survey costs most of
|