tumwater 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +42 -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 +4 -3
- 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 +402 -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 +246 -55
- package/dist/src/backlog/backlog-cli-view.js +280 -0
- package/dist/src/backlog/backlog-cli.js +85 -274
- package/dist/src/backlog/backlog-commit.js +4 -5
- package/dist/src/backlog/backlog-eligibility.js +175 -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 +254 -0
- package/dist/src/backlog/backlog-release.js +117 -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-culprit.js +94 -0
- package/dist/src/baseline/main-guardrails.js +209 -0
- package/dist/src/baseline/main-red.js +139 -32
- package/dist/src/baseline/main-revert.js +133 -0
- package/dist/src/baseline/main-watch.js +184 -0
- package/dist/src/brief/brief-edit.js +9 -11
- package/dist/src/brief/brief.js +31 -51
- package/dist/src/budget/budget.js +30 -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 +1 -2
- 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 +118 -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 +150 -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 +308 -590
- package/dist/src/cli/cli-repo-gate.js +11 -1
- package/dist/src/cli/cli-role-command.js +420 -0
- package/dist/src/cli/cli-start-summary.js +160 -0
- package/dist/src/cli/{cli-run.js → cli-start.js} +165 -237
- package/dist/src/cli/completion.js +149 -22
- package/dist/src/cli/config-commands.js +41 -18
- package/dist/src/cli/follow-view.js +75 -0
- package/dist/src/cli/help.js +189 -73
- package/dist/src/cli/log-commands.js +148 -82
- package/dist/src/cli/question-commands.js +205 -10
- package/dist/src/cli.js +106 -43
- package/dist/src/collections.js +26 -10
- 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 +13 -1
- package/dist/src/config/config-fallbacks.js +93 -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 +141 -199
- package/dist/src/config/config-views.js +127 -53
- package/dist/src/config/config-write-core.js +135 -0
- package/dist/src/config/config-write.js +131 -264
- package/dist/src/config/config.js +48 -38
- package/dist/src/config/model-selector.js +34 -34
- package/dist/src/doctor/doctor-backlog-bugs.js +287 -0
- package/dist/src/doctor/doctor-backlog-plans.js +263 -0
- package/dist/src/doctor/doctor-backlog.js +100 -496
- package/dist/src/doctor/doctor-check-names.js +81 -0
- package/dist/src/doctor/doctor-checks.js +52 -579
- package/dist/src/doctor/doctor-claude-checks.js +145 -0
- package/dist/src/doctor/doctor-codex-checks.js +279 -0
- package/dist/src/doctor/doctor-contention-checks.js +380 -0
- package/dist/src/doctor/doctor-holds.js +82 -66
- package/dist/src/doctor/doctor-install.js +2 -1
- package/dist/src/doctor/doctor-model-checks.js +236 -402
- package/dist/src/doctor/doctor-notify.js +3 -4
- package/dist/src/doctor/doctor-opencode-checks.js +162 -0
- package/dist/src/doctor/doctor-orphans.js +182 -63
- package/dist/src/doctor/doctor-project-checks.js +303 -0
- package/dist/src/doctor/doctor.js +121 -77
- package/dist/src/doctor/image-probe.js +21 -8
- package/dist/src/doctor/outcome.js +3 -2
- package/dist/src/doctor/probe.js +7 -11
- package/dist/src/events/event-format.js +181 -86
- package/dist/src/events/event-labels.js +12 -5
- package/dist/src/events/event-legacy.js +39 -15
- package/dist/src/events/event-read.js +39 -39
- package/dist/src/events/event-tally.js +16 -0
- package/dist/src/events/event-window.js +60 -24
- 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 +56 -56
- package/dist/src/failure/failure-render.js +31 -23
- package/dist/src/failure/failure-state-change.js +17 -12
- package/dist/src/failure/time-spend.js +99 -35
- 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 +177 -84
- package/dist/src/gates/disk-gate.js +1 -1
- package/dist/src/gates/gate-polls.js +108 -58
- package/dist/src/gates/maintenance-quota.js +10 -13
- 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 +77 -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 +36 -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 +42 -18
- package/dist/src/gui/gui-backlog-endpoints.js +155 -0
- package/dist/src/gui/gui-command.js +8 -13
- package/dist/src/gui/gui-config-commands.js +94 -72
- package/dist/src/gui/gui-endpoint-commands.js +4 -3
- 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 +108 -13
- package/dist/src/gui/gui-prompt-commands.js +11 -14
- package/dist/src/gui/gui-report-endpoints.js +90 -0
- package/dist/src/gui/gui-server.js +11 -4
- 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 +147 -0
- package/dist/src/history/history-render.js +42 -22
- package/dist/src/history/history.js +193 -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 +25 -9
- 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 +81 -32
- package/dist/src/merge/merge-diff.js +5 -4
- package/dist/src/merge/merge-drain.js +150 -11
- 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 +90 -0
- package/dist/src/merge/merge-queue-render.js +49 -11
- package/dist/src/merge/merge-queue.js +31 -15
- package/dist/src/merge/merge-requeue.js +102 -0
- package/dist/src/merge/merge-slot.js +61 -16
- package/dist/src/merge/merge-stack.js +33 -11
- package/dist/src/merge/merge-to-main.js +86 -27
- package/dist/src/merge/merge-top.js +69 -0
- package/dist/src/merge/merge-verify.js +12 -10
- package/dist/src/notes-cli.js +30 -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 +320 -0
- package/dist/src/orchestrator/orchestrator-scheduling.js +68 -369
- package/dist/src/orchestrator/orchestrator.js +128 -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 +201 -0
- package/dist/src/orchestrator/scheduling-skip.js +185 -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 +116 -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 +18 -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 +121 -211
- package/dist/src/prompt/notes-backlog.js +181 -0
- package/dist/src/prompt/principles.js +1 -2
- package/dist/src/prompt/prompt-followup.js +19 -14
- package/dist/src/prompt/prompt.js +129 -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 +161 -77
- package/dist/src/report/report-fold.js +129 -52
- package/dist/src/report/report-main-red.js +55 -0
- package/dist/src/report/report-render.js +133 -64
- package/dist/src/report/report-types.js +1 -0
- package/dist/src/report/report.js +26 -9
- package/dist/src/request-timeouts.js +2 -2
- package/dist/src/review/known-flakes.js +100 -1
- package/dist/src/review/post-merge-review.js +106 -0
- package/dist/src/review/protected-edits.js +4 -5
- 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 +155 -360
- 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 +69 -12
- package/dist/src/roles/role-guidance.js +55 -20
- package/dist/src/roles/role-labels.js +1 -2
- package/dist/src/roles/role-render.js +67 -50
- package/dist/src/roles/role-view.js +59 -47
- package/dist/src/roles/roles.js +31 -31
- package/dist/src/roles/runner-ids.js +97 -0
- package/dist/src/run/acceptance-greps.js +119 -0
- package/dist/src/run/feedback-filings.js +51 -0
- package/dist/src/{tick → run}/qa-coverage.js +9 -27
- package/dist/src/{tick/tick-apply.js → run/run-apply.js} +95 -94
- package/dist/src/run/run-detail-data.js +179 -0
- package/dist/src/run/run-detail-render.js +98 -0
- package/dist/src/run/run-detail.js +168 -0
- package/dist/src/{tick/tick-finalize.js → run/run-finalize.js} +72 -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} +108 -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} +108 -50
- 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} +91 -56
- 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 +172 -0
- package/dist/src/run/stage-path-checks.js +730 -0
- package/dist/src/{loop → runner}/leftover.js +80 -25
- package/dist/src/{loop → runner}/model-fallback.js +12 -12
- package/dist/src/runner/revision.js +202 -0
- package/dist/src/{loop/loop-fallback.js → runner/runner-fallback.js} +8 -8
- package/dist/src/runner/runner-outcome.js +107 -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} +21 -15
- package/dist/src/{loop/loop-tick.js → runner/runner-run.js} +218 -240
- package/dist/src/{loop/loop-state.js → runner/runner-state-load.js} +61 -114
- package/dist/src/runner/runner-state.js +102 -0
- package/dist/src/{loop/loop.js → runner/runner.js} +123 -120
- package/dist/src/scheduling/backoff.js +38 -38
- 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 +43 -16
- 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 +28 -28
- package/dist/src/status/status-roles.js +39 -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 +5 -6
- 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 +63 -17
- package/dist/src/text/format.js +48 -11
- package/dist/src/text/markdown.js +8 -5
- package/dist/src/text/phrases.js +57 -23
- package/dist/src/text/suggest.js +1 -1
- package/dist/src/text/text.js +67 -13
- package/dist/src/ui/badges.js +65 -37
- package/dist/src/ui/gui/gui-client-backlog.js +292 -0
- package/dist/src/ui/gui/gui-client-boot.js +32 -26
- package/dist/src/ui/gui/gui-client-composer.js +8 -9
- package/dist/src/ui/gui/gui-client-drawer-config.js +212 -0
- package/dist/src/ui/gui/gui-client-drawer.js +126 -285
- package/dist/src/ui/gui/gui-client-feed.js +271 -0
- package/dist/src/ui/gui/gui-client-history.js +434 -67
- package/dist/src/ui/gui/gui-client-labels.js +1 -2
- 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 +55 -51
- package/dist/src/ui/gui/gui-client-pending.js +227 -23
- package/dist/src/ui/gui/gui-client-report-chart.js +464 -0
- package/dist/src/ui/gui/gui-client-report.js +87 -427
- package/dist/src/ui/gui/{gui-client-loops.js → gui-client-roles.js} +43 -44
- package/dist/src/ui/gui/gui-client-settings.js +56 -4
- package/dist/src/ui/gui/gui-client-team.js +25 -465
- package/dist/src/ui/gui/gui-client.js +27 -25
- package/dist/src/ui/gui/gui-icons.js +0 -2
- package/dist/src/ui/gui/gui-page.js +9 -7
- package/dist/src/ui/gui/gui-styles.js +34 -34
- package/dist/src/ui/progress-data.js +9 -11
- package/dist/src/ui/{tick-progress-model.js → run-progress-model.js} +31 -31
- package/dist/src/ui/status-model.js +133 -125
- package/dist/src/ui/status-payload.js +136 -49
- package/dist/src/ui/status-render.js +101 -82
- package/dist/src/ui/team-alerts.js +248 -57
- package/dist/src/ui/tone.js +5 -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 +51 -14
- package/dist/src/ui/tui/tui-editor-answer.js +27 -31
- package/dist/src/ui/tui/tui-editor-attach.js +3 -5
- package/dist/src/ui/tui/tui-editor-backends.js +132 -0
- package/dist/src/ui/tui/tui-editor-brief.js +10 -12
- package/dist/src/ui/tui/tui-editor-budget.js +35 -31
- package/dist/src/ui/tui/tui-editor-claude-reserve.js +24 -0
- package/dist/src/ui/tui/tui-editor-concurrency.js +24 -0
- package/dist/src/ui/tui/tui-editor-config.js +86 -0
- package/dist/src/ui/tui/tui-editor-entry.js +36 -47
- package/dist/src/ui/tui/tui-editor-fallback.js +31 -0
- package/dist/src/ui/tui/tui-editor-instances.js +37 -0
- package/dist/src/ui/tui/tui-editor-instructions.js +136 -0
- package/dist/src/ui/tui/tui-editor-interval.js +11 -9
- package/dist/src/ui/tui/tui-editor-model.js +29 -0
- package/dist/src/ui/tui/tui-editor-notes.js +3 -5
- 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 +99 -35
- package/dist/src/ui/tui/tui-editor-retire.js +4 -6
- package/dist/src/ui/tui/tui-editor-role-key.js +76 -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 +60 -34
- package/dist/src/ui/tui/tui-editor-slots.js +23 -0
- package/dist/src/ui/tui/tui-editors.js +35 -2
- package/dist/src/ui/tui/tui-frame.js +56 -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 +24 -9
- package/dist/src/ui/tui/tui-pane-activity.js +14 -11
- package/dist/src/ui/tui/tui-pane-backlog.js +171 -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 +58 -8
- package/dist/src/ui/tui/tui-pane-history.js +402 -82
- package/dist/src/ui/tui/tui-pane-pending.js +308 -13
- package/dist/src/ui/tui/tui-pane-queued.js +71 -55
- package/dist/src/ui/tui/tui-pane-report.js +46 -14
- package/dist/src/ui/tui/tui-pane-session.js +25 -6
- package/dist/src/ui/tui/tui-pane-transcript.js +111 -37
- package/dist/src/ui/tui/tui-pane.js +80 -23
- package/dist/src/ui/tui/tui-panes.js +100 -30
- package/dist/src/ui/tui/tui.js +14 -14
- package/dist/src/verdict/fix-claim.js +82 -32
- package/dist/src/verdict/no-change.js +4 -4
- package/dist/src/verdict/refusal.js +40 -16
- package/dist/src/verdict/reply-contract.js +42 -31
- package/dist/src/version.js +0 -1
- package/package.json +2 -1
- package/dist/src/loop/revision.js +0 -70
- package/dist/src/roles/loop-ids.js +0 -77
- 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
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { readJsonFile, writeJsonAtomic } from "../files/json-files.js";
|
|
2
|
+
import { postReviewPath, postReviewWorktreePath, nativeLogPath, piLogPath, reviewRunSessionDir } from "../paths.js";
|
|
3
|
+
import { reviewRunConfig } from "../config/config-views.js";
|
|
4
|
+
import { logEventBestEffort, TUMWATER_SOURCE, tryOrWarn } from "../events/events.js";
|
|
5
|
+
import { isJsonObject } from "../files/json-object.js";
|
|
6
|
+
import { git, gitCouldNotStart, gitTry } from "../git/git-run.js";
|
|
7
|
+
import { ensureDetachedWorktree } from "../git/worktree.js";
|
|
8
|
+
import { useWorktree } from "../git/worktree-use.js";
|
|
9
|
+
import { readPrinciples } from "../prompt/principles.js";
|
|
10
|
+
import { buildReviewPrompt } from "../prompt/gate-prompts.js";
|
|
11
|
+
import { baseRoleOf } from "../roles/runner-ids.js";
|
|
12
|
+
import { shortSha } from "../text/format.js";
|
|
13
|
+
import { errorMessage } from "../text/text.js";
|
|
14
|
+
import { parseVerdict } from "./review-verdict.js";
|
|
15
|
+
/** A commit's review is dropped, with a warning, after this many runs with no verdict. */
|
|
16
|
+
export const POST_REVIEW_FAILURE_LIMIT = 3;
|
|
17
|
+
/** Whether `role`'s changes are reviewed after merging instead of before. */
|
|
18
|
+
export function isAfterMergeRole(config, role) {
|
|
19
|
+
return (config.review.afterMerge ?? []).includes(baseRoleOf(role));
|
|
20
|
+
}
|
|
21
|
+
/** The queued entries. A torn or hand-edited entry (not an object with a string commit, role and
|
|
22
|
+
* summary, or a `rejected` that is not an array) is dropped, and the next write leaves it out. */
|
|
23
|
+
export function readPostReviews(root) {
|
|
24
|
+
const saved = readJsonFile(postReviewPath(root));
|
|
25
|
+
if (!Array.isArray(saved?.pending))
|
|
26
|
+
return [];
|
|
27
|
+
const entries = [];
|
|
28
|
+
for (const raw of saved.pending) {
|
|
29
|
+
if (!isJsonObject(raw))
|
|
30
|
+
continue;
|
|
31
|
+
const { commit, role, summary, body, failures, rejected } = raw;
|
|
32
|
+
if (typeof commit !== "string" || typeof role !== "string" || typeof summary !== "string")
|
|
33
|
+
continue;
|
|
34
|
+
if (rejected !== undefined && !Array.isArray(rejected))
|
|
35
|
+
continue;
|
|
36
|
+
const entry = { commit, role, summary };
|
|
37
|
+
if (typeof body === "string")
|
|
38
|
+
entry.body = body;
|
|
39
|
+
if (typeof failures === "number" && Number.isFinite(failures))
|
|
40
|
+
entry.failures = failures;
|
|
41
|
+
if (Array.isArray(rejected))
|
|
42
|
+
entry.rejected = rejected.filter((r) => typeof r === "string");
|
|
43
|
+
entries.push(entry);
|
|
44
|
+
}
|
|
45
|
+
return entries;
|
|
46
|
+
}
|
|
47
|
+
function writePostReviews(root, pending) {
|
|
48
|
+
tryOrWarn(root, TUMWATER_SOURCE, "write post-review.json", () => writeJsonAtomic(postReviewPath(root), { pending }));
|
|
49
|
+
}
|
|
50
|
+
/** Queue the merged commit for its review. Never throws: a failed write warns and leaves the file
|
|
51
|
+
* as it was, so the commit goes unreviewed. */
|
|
52
|
+
export function addPostReview(root, entry) {
|
|
53
|
+
writePostReviews(root, [...readPostReviews(root).filter((e) => e.commit !== entry.commit), entry]);
|
|
54
|
+
}
|
|
55
|
+
/** Replace the entry for `commit` with `next`, or drop it when `next` is null. Never throws: a
|
|
56
|
+
* failed write warns and leaves the file as it was, so a later poll handles the entry again. */
|
|
57
|
+
export function settlePostReview(root, commit, next) {
|
|
58
|
+
const rest = readPostReviews(root).filter((e) => e.commit !== commit);
|
|
59
|
+
writePostReviews(root, next ? [...rest, next] : rest);
|
|
60
|
+
}
|
|
61
|
+
/** Review the merged commit C: the usual reviewer prompt over `git diff C^ C`, run in a detached
|
|
62
|
+
* checkout of C. Logs `review_start` and `review_verdict` / `review_rejected` with
|
|
63
|
+
* `afterMerge: true`. A diff git fails to produce is a failed review with no reviewer run: read
|
|
64
|
+
* as empty, the reviewer approved a commit it never saw. Throws only when git could not start
|
|
65
|
+
* (gitCouldNotStart), which says nothing about C, so the caller keeps the entry as it was for
|
|
66
|
+
* the next poll instead of counting a failed run toward dropping it. */
|
|
67
|
+
export async function reviewMergedCommit(root, config, entry, runGatePi, signal) {
|
|
68
|
+
const { commit, role } = entry;
|
|
69
|
+
try {
|
|
70
|
+
const reviewCfg = reviewRunConfig(config);
|
|
71
|
+
const startedAt = Date.now();
|
|
72
|
+
const pi = await useWorktree(root, postReviewWorktreePath(root), async () => {
|
|
73
|
+
const wt = await ensureDetachedWorktree(root, postReviewWorktreePath(root), commit);
|
|
74
|
+
await gitTry(wt, "checkout", "--detach", "--force", commit);
|
|
75
|
+
const diff = await git(wt, "diff", `${commit}^`, commit);
|
|
76
|
+
logEventBestEffort(root, { source: role, type: "review_start", head: commit, afterMerge: true });
|
|
77
|
+
return runGatePi({
|
|
78
|
+
cwd: wt,
|
|
79
|
+
kind: "gate",
|
|
80
|
+
prompt: buildReviewPrompt(diff, entry.summary, entry.body, readPrinciples(root), undefined, `${commit}^`),
|
|
81
|
+
config: reviewCfg,
|
|
82
|
+
sessionDir: reviewRunSessionDir(root, role, `post-${shortSha(commit)}`),
|
|
83
|
+
sessionName: `tumwater-review-${role}-post-${shortSha(commit)}`,
|
|
84
|
+
rawLogFile: piLogPath(root, role),
|
|
85
|
+
nativeLogFile: nativeLogPath(root, role, reviewCfg.agent ?? "pi"),
|
|
86
|
+
label: "review",
|
|
87
|
+
signal,
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
const verdict = pi.ok && !pi.aborted ? parseVerdict(pi.verdictText ?? "") : null;
|
|
91
|
+
if (!verdict)
|
|
92
|
+
return { kind: "failed", detail: pi.errorMessage ?? "no parseable VERDICT line in the reviewer's reply" };
|
|
93
|
+
const durationMs = Date.now() - startedAt;
|
|
94
|
+
if (verdict.verdict === "reject") {
|
|
95
|
+
logEventBestEffort(root, { source: role, type: "review_rejected", head: commit, reasons: verdict.reasons, durationMs, afterMerge: true });
|
|
96
|
+
return { kind: "reject", reasons: verdict.reasons };
|
|
97
|
+
}
|
|
98
|
+
logEventBestEffort(root, { source: role, type: "review_verdict", head: commit, reason: verdict.reasons[0], durationMs, afterMerge: true });
|
|
99
|
+
return { kind: "approve", reasons: verdict.reasons };
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
if (gitCouldNotStart(err))
|
|
103
|
+
throw err;
|
|
104
|
+
return { kind: "failed", detail: errorMessage(err) };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
import path from "node:path";
|
|
3
2
|
import { promptBlockOf } from "../brief/brief.js";
|
|
4
3
|
import { readTextOrNull } from "../files/files.js";
|
|
5
4
|
import { changeBaseRev, fileContentAt } from "../git/git.js";
|
|
6
5
|
import { briefCandidates } from "../paths.js";
|
|
7
|
-
import { baseRoleOf } from "../roles/
|
|
8
|
-
/** The brief files that may carry the
|
|
6
|
+
import { baseRoleOf } from "../roles/runner-ids.js";
|
|
7
|
+
/** The brief files that may carry the brief text block: the basenames of `briefCandidates`. */
|
|
9
8
|
const BRIEF_FILES = briefCandidates("").map((p) => path.basename(p));
|
|
10
9
|
/** The roles that may edit PRINCIPLES.md. */
|
|
11
10
|
const PRINCIPLES_ROLES = new Set(["director", "steward"]);
|
|
12
|
-
/** The deterministic gate/stage finding for a change that edits what the
|
|
13
|
-
* editing: the
|
|
11
|
+
/** The deterministic gate/stage finding for a change that edits what the role prompts forbid
|
|
12
|
+
* editing: the brief text block of a brief file (changed, removed, or the file deleted —
|
|
14
13
|
* a block that only moves passes), or PRINCIPLES.md from a role other than director or
|
|
15
14
|
* steward. undefined when neither happened. Reads the worktree and the change's merge-base
|
|
16
15
|
* like backlogStructureReason; a missing file reads as empty and never throws. */
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { reviewRunConfig,
|
|
1
|
+
import { backendSessionResumable } from "../agent/agent-backend.js";
|
|
2
|
+
import { reviewRunConfig, resolvedBackendConfig } from "../config/config-views.js";
|
|
3
3
|
import { logEventBestEffort, warnEventBestEffort } from "../events/events.js";
|
|
4
4
|
import { nativeLogPath, piLogPath } from "../paths.js";
|
|
5
5
|
import { buildNoRerunPrompt, buildVerdictRequestPrompt } from "../prompt/gate-prompts.js";
|
|
6
6
|
import { cappedRequestTimeouts } from "../request-timeouts.js";
|
|
7
7
|
/** Hard caps on the VERDICT follow-up turn: it should take one short reply on a warm session,
|
|
8
|
-
* so it never gets the review run's own budget (mirrors
|
|
8
|
+
* so it never gets the review run's own budget (mirrors RunnerPi's SUMMARY-request caps). */
|
|
9
9
|
const VERDICT_REQUEST_TIMEOUT_S = 900;
|
|
10
10
|
const VERDICT_REQUEST_QUIET_S = 300;
|
|
11
11
|
/** One bounded follow-up turn on the reviewer's just-finished session: the shared session
|
|
@@ -19,7 +19,7 @@ async function runFollowupTurn(ctx, opts) {
|
|
|
19
19
|
// backend's own resumable rule keeps a newer line of another kind from being the session a
|
|
20
20
|
// pi continue would actually reach; claude resumes its recorded id (looked up under the
|
|
21
21
|
// team's config dir, so a team that set one continues under it).
|
|
22
|
-
if (!
|
|
22
|
+
if (!backendSessionResumable(dir, { kind: "gate", agent: cfg.agent ?? "pi" }, resolvedBackendConfig(ctx.config, "claude").configDir)) {
|
|
23
23
|
return null;
|
|
24
24
|
}
|
|
25
25
|
return ctx.runGatePi({
|
|
@@ -46,7 +46,7 @@ async function runFollowupTurn(ctx, opts) {
|
|
|
46
46
|
onBlindRead: (path, action) => logEventBestEffort(ctx.root, {
|
|
47
47
|
source: ctx.role,
|
|
48
48
|
type: "image_blind",
|
|
49
|
-
run: ctx.
|
|
49
|
+
run: ctx.runNumber,
|
|
50
50
|
path,
|
|
51
51
|
model: cfg.model,
|
|
52
52
|
action,
|
|
@@ -55,14 +55,14 @@ async function runFollowupTurn(ctx, opts) {
|
|
|
55
55
|
});
|
|
56
56
|
}
|
|
57
57
|
/** Ask the reviewer's own session (--continue) for the missing VERDICT line: one tightly
|
|
58
|
-
* bounded turn on the just-finished review's session, mirroring
|
|
58
|
+
* bounded turn on the just-finished review's session, mirroring RunnerPi.requestSummary on the
|
|
59
59
|
* author side (BUGS.md 2026-09-29). Null when there is no session to continue — the caller
|
|
60
60
|
* then counts the strike exactly as before. The run is returned even when it failed so the
|
|
61
61
|
* caller can honor a shutdown abort and fold the spend. */
|
|
62
62
|
export async function requestVerdict(ctx) {
|
|
63
63
|
return runFollowupTurn(ctx, {
|
|
64
64
|
prompt: buildVerdictRequestPrompt(),
|
|
65
|
-
sessionName: `tumwater-review-${ctx.role}-${ctx.
|
|
65
|
+
sessionName: `tumwater-review-${ctx.role}-${ctx.runNumber}-verdict`,
|
|
66
66
|
label: "review-verdict",
|
|
67
67
|
});
|
|
68
68
|
}
|
|
@@ -76,7 +76,7 @@ export async function requestVerdict(ctx) {
|
|
|
76
76
|
export async function requestNoRerun(ctx, rerun, calls) {
|
|
77
77
|
return runFollowupTurn(ctx, {
|
|
78
78
|
prompt: buildNoRerunPrompt(rerun),
|
|
79
|
-
sessionName: `tumwater-review-${ctx.role}-${ctx.
|
|
79
|
+
sessionName: `tumwater-review-${ctx.role}-${ctx.runNumber}-rerun`,
|
|
80
80
|
label: "review-rerun",
|
|
81
81
|
// Collected unconditionally: a nudge only runs after a detected rerun, so the no-re-run
|
|
82
82
|
// rule stood and the repeat check below needs every call the nudge started.
|
|
@@ -1,22 +1,48 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
/** The review gate's deterministic build pre-check — split out of review.ts so the gate keeps
|
|
3
2
|
* one responsibility (running the model reviewer and acting on its verdict) while this module
|
|
4
3
|
* owns the pre-review verification: the one scoped build-check run, its flake re-run, the
|
|
5
|
-
* sleep-unverified and main-red attributions
|
|
4
|
+
* sleep-unverified and main-red attributions. No model
|
|
6
5
|
* runs here — everything is decided by the project's declared check, so a deterministic
|
|
7
6
|
* rejection never shows as "reviewing" on the dashboards and consumes no reviewer budget. */
|
|
8
7
|
import { warnEventBestEffort } from "../events/events.js";
|
|
9
8
|
import { BUILD_CHECK_TIMEOUT_MS } from "../build/build-check-detect.js";
|
|
10
9
|
import { runScopedBuildCheck } from "../build/build-check-scoped.js";
|
|
11
|
-
import { checkFailureReasons, describeCheck, failureHeadline } from "../build/build-check-report.js";
|
|
10
|
+
import { checkFailureReasons, describeCheck, failureHeadline, FAILING_TESTS_MAX } from "../build/build-check-report.js";
|
|
12
11
|
import { sleptPhrase, UNVERIFIED_TREE, unverifiedTreeOutcome } from "../build/build-check-events.js";
|
|
13
12
|
import { sampleSleepClock } from "../build/host-sleep.js";
|
|
14
|
-
import { recordReview } from "../
|
|
13
|
+
import { recordReview } from "../run/run-apply.js";
|
|
15
14
|
import { mainRedNotMine } from "../text/phrases.js";
|
|
16
15
|
import { shortSha } from "../text/format.js";
|
|
17
16
|
import { checkWaitStage, setMergeStage } from "../merge/merge-slot.js";
|
|
18
17
|
import { mainTipVerdict } from "../baseline/main-red.js";
|
|
19
|
-
import {
|
|
18
|
+
import { onlyKnownMainFailures } from "../baseline/main-watch.js";
|
|
19
|
+
import { watchedBaseline } from "../baseline/main-baseline.js";
|
|
20
|
+
import { changeBaseRev } from "../git/git.js";
|
|
21
|
+
import { FLAKY_WARNING_PREFIX, isKnownFlake, quarantineTests } from "./known-flakes.js";
|
|
22
|
+
/** The tests a gate failure shares with the change's own base, when that base is not main's tip:
|
|
23
|
+
* the main watch recorded the base red with every one of them. A branch behind a fix fails the
|
|
24
|
+
* old test on its base while main's tip is green (2026-10-20, report --role), so the tip verdict
|
|
25
|
+
* alone is the wrong question. Null when the failures are not all the base's, the list may have
|
|
26
|
+
* been cut short (the cap onlyKnownMainFailures uses), or git cannot say. */
|
|
27
|
+
async function staleBaseFailures(wt, mainBranch, head, mainTip, failingTests) {
|
|
28
|
+
if (!failingTests || failingTests.length === 0 || failingTests.length >= FAILING_TESTS_MAX)
|
|
29
|
+
return null;
|
|
30
|
+
try {
|
|
31
|
+
const base = await changeBaseRev(wt, mainBranch, head);
|
|
32
|
+
if (base === mainTip)
|
|
33
|
+
return null;
|
|
34
|
+
const verdict = await watchedBaseline(wt, base);
|
|
35
|
+
if (verdict?.status !== "red")
|
|
36
|
+
return null;
|
|
37
|
+
const baseFailed = verdict.failingTests ?? [];
|
|
38
|
+
if (!failingTests.every((t) => baseFailed.includes(t)))
|
|
39
|
+
return null;
|
|
40
|
+
return { base, tests: [...failingTests] };
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
20
46
|
/** Run the gate's deterministic build pre-check. `reject` is the gate's one shared rejection
|
|
21
47
|
* path (review.ts's reject closure): the pre-check routes a reproduced failure through it so
|
|
22
48
|
* the bookkeeping (lastReview, branch reset, review_rejected event) cannot drift from the
|
|
@@ -41,10 +67,12 @@ export async function gateBuildPrecheck(ctx, state, head, reject) {
|
|
|
41
67
|
// host were exactly that (BUGS.md 2026-09-23). The re-run is one more check, priced as
|
|
42
68
|
// its own build_check event; if it passes, the tree is verified exactly like a
|
|
43
69
|
// first-time pass and the flake is named in a warning (the headline clusters in the
|
|
44
|
-
// digest, so
|
|
70
|
+
// digest, so selfcheck and bugfix can go after the flaky test). A re-run that fails
|
|
45
71
|
// again goes to attribution below; a skipped one says nothing about the tree, so the
|
|
46
72
|
// first failure stands.
|
|
47
|
-
|
|
73
|
+
// A failure naming only known tests (main's, or quarantined) is judged below as it stands:
|
|
74
|
+
// a re-run could only repeat it.
|
|
75
|
+
const retry = onlyKnownMainFailures(root, outcome.failingTests) ? undefined : await runGateCheck();
|
|
48
76
|
if (retry?.outcome.status === "passed") {
|
|
49
77
|
// When the failed run spanned a host sleep, the pass says the tree is fine and the
|
|
50
78
|
// sleep is the story — not a flaky test (BUGS.md 2026-09-30): the digest clusters
|
|
@@ -55,6 +83,8 @@ export async function gateBuildPrecheck(ctx, state, head, reject) {
|
|
|
55
83
|
else {
|
|
56
84
|
const flaky = failureHeadline(outcome.outputTail) ?? describeCheck(check);
|
|
57
85
|
warnEventBestEffort(root, role, `${FLAKY_WARNING_PREFIX}${flaky}`);
|
|
86
|
+
// Each test the failed run named failed and then passed on this same tree: quarantined.
|
|
87
|
+
quarantineTests(root, outcome.failingTests, outcome.outputTail);
|
|
58
88
|
}
|
|
59
89
|
outcome = retry.outcome;
|
|
60
90
|
}
|
|
@@ -78,12 +108,23 @@ export async function gateBuildPrecheck(ctx, state, head, reject) {
|
|
|
78
108
|
// host-sleep path above does. Before this, the repeat was attributed through main's
|
|
79
109
|
// per-SHA baseline cache (usually a green seeded by an earlier merge), so a load- or
|
|
80
110
|
// clock-sensitive test rejected whichever unrelated change hit it (BUGS.md 2026-10-06).
|
|
111
|
+
// The excuse is not a failure of the gate, so the change goes on to the model review
|
|
112
|
+
// instead of ending the merge attempt as review_error and paying a requeue. It carries no
|
|
113
|
+
// verifiedHead — the tree was not verified — so the merge
|
|
114
|
+
// path's own check still judges the tree before it reaches main.
|
|
81
115
|
const flaky = failureHeadline(outcome.outputTail) ?? describeCheck(check);
|
|
116
|
+
// A failure that names only tests main already fails is main's, not this change's: it goes
|
|
117
|
+
// on to review with no fresh run on main. No verifiedHead — the tree did not pass, so the
|
|
118
|
+
// merge path must not seed a green for it — and the merge check judges it by the same rule.
|
|
119
|
+
const known = onlyKnownMainFailures(root, outcome.failingTests);
|
|
120
|
+
if (known) {
|
|
121
|
+
warnEventBestEffort(root, role, `gate check fails only main's known failures: ${known.join(", ")}`);
|
|
122
|
+
return { knownMainFailures: known };
|
|
123
|
+
}
|
|
124
|
+
// The headline excuse stays for a failure that names no test: quarantine covers named ones.
|
|
82
125
|
if (isKnownFlake(root, flaky)) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
warnEventBestEffort(root, role, detail);
|
|
86
|
-
return { resolved: { decision: "failed", detail, unverified: true } };
|
|
126
|
+
warnEventBestEffort(root, role, `known-flaky failure, merge kept: ${flaky}`);
|
|
127
|
+
return {};
|
|
87
128
|
}
|
|
88
129
|
const reasons = checkFailureReasons(check, outcome);
|
|
89
130
|
// A failure that reproduced is attributed, never fixed here: the one merge slot the
|
|
@@ -106,14 +147,24 @@ export async function gateBuildPrecheck(ctx, state, head, reject) {
|
|
|
106
147
|
// Main fails too: not this change's failure. Leave the commit (and with it the pin) and
|
|
107
148
|
// do not advance the discard counter — the transport-failure rule (BUGS.md 2026-09-20):
|
|
108
149
|
// nothing judged this diff. main-red.ts's gate and the bugfix handoff own the repair,
|
|
109
|
-
// and the
|
|
150
|
+
// and the orchestrator poll (requeueMainRedPin) re-queues the kept pin once main's head
|
|
151
|
+
// moves; leftover recovery holds it until then.
|
|
110
152
|
const detail = mainRedNotMine(main.sha);
|
|
111
153
|
recordReview(state, "failed", [detail], head);
|
|
112
154
|
warnEventBestEffort(root, role, `gate check failed on ${shortSha(head)}, but ${detail}; merge kept`);
|
|
113
155
|
return { resolved: { decision: "failed", detail, mainRed: true } };
|
|
114
156
|
}
|
|
157
|
+
if (main.status === "green") {
|
|
158
|
+
const stale = await staleBaseFailures(wt, mainBranch, head, main.sha, outcome.failingTests);
|
|
159
|
+
if (stale) {
|
|
160
|
+
// Same hand-off as the known-failure branch: no verifiedHead, so the merge check on the
|
|
161
|
+
// rebased tree still judges it.
|
|
162
|
+
warnEventBestEffort(root, role, `gate check fails only tests its base ${shortSha(stale.base)} already failed, and main ${shortSha(main.sha)} is green: ${stale.tests.join(", ")}; going on to review`);
|
|
163
|
+
return { knownMainFailures: stale.tests };
|
|
164
|
+
}
|
|
165
|
+
}
|
|
115
166
|
// Main green: the change broke the check — rejected deterministically through the shared
|
|
116
|
-
// reject path, no pi run consumed, reasons injected into the author's next
|
|
167
|
+
// reject path, no pi run consumed, reasons injected into the author's next run. With no
|
|
117
168
|
// verdict for main the author's failure is still the safe default, and the reasons say
|
|
118
169
|
// the attribution could not be made.
|
|
119
170
|
return {
|
|
@@ -126,17 +177,9 @@ export async function gateBuildPrecheck(ctx, state, head, reject) {
|
|
|
126
177
|
// Passed: this exact tree just went green under the project's own declared check. Hand
|
|
127
178
|
// the verdict to the merge path via verifiedHead — it seeds the red-main baseline with
|
|
128
179
|
// the SHA that actually becomes main (the rebased head, which may differ from `head`),
|
|
129
|
-
// so every role's next fresh
|
|
180
|
+
// so every role's next fresh run is a cache hit instead of one redundant full-suite
|
|
130
181
|
// re-run on an already-verified tree.
|
|
131
|
-
|
|
132
|
-
// attesting them here means neither the author nor the reviewer states a total, which is
|
|
133
|
-
// where most record-claim rejections came from (PLANS.md 2026-09-29).
|
|
134
|
-
return {
|
|
135
|
-
verifiedHead: head,
|
|
136
|
-
verifiedByHarness: outcome.counts
|
|
137
|
-
? `${describeCheck(check)} (the project's declared check) passed — ${outcome.counts.pass} pass, ${outcome.counts.fail} fail, ${outcome.counts.skipped} skipped of ${outcome.counts.tests}`
|
|
138
|
-
: `${describeCheck(check)} (the project's declared check) passed`,
|
|
139
|
-
};
|
|
182
|
+
return { verifiedHead: head };
|
|
140
183
|
}
|
|
141
184
|
}
|
|
142
185
|
return {};
|