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,4 +1,3 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
/** Event-log folding for the usage report: turn raw harness events (run_end/merged/…) into
|
|
3
2
|
* per-day and whole-window `UsageFold` accumulators, memoizing the day-keyed read per
|
|
4
3
|
* (root, fromKey) so a dashboard polling /api/report only folds appended lines instead of
|
|
@@ -7,19 +6,21 @@
|
|
|
7
6
|
* --since and day windows present cannot drift apart; it lives here matching its own test
|
|
8
7
|
* (test/report-fold-cache.test.ts). Zero incidental runtime dependencies: node built-ins and
|
|
9
8
|
* the app's own modules only. */
|
|
10
|
-
import { sameStatIdentity, statOrNull } from "../files/files.js";
|
|
9
|
+
import { sameStatIdentity, statIdentityOrZero, statOrNull } from "../files/files.js";
|
|
11
10
|
import { readWindowEvents } from "../events/event-window.js";
|
|
12
11
|
import { eventDayKey, eventRole, eventUsage, parseEventLine } from "../events/event-read.js";
|
|
13
12
|
import { readCompleteLines } from "../files/tail.js";
|
|
14
13
|
import { eventsLogPath } from "../paths.js";
|
|
15
14
|
import { isPassingFullCheck, isRedFullCheck } from "../build/build-check-events.js";
|
|
15
|
+
import { isPassingMainCheck, isRedMain } from "../baseline/main-guardrails.js";
|
|
16
16
|
import { addTo, memoSetLru } from "../collections.js";
|
|
17
|
+
import { asList } from "../text/text.js";
|
|
17
18
|
import { finiteNumber } from "../files/json-object.js";
|
|
18
19
|
import { OUTCOME_CLASS } from "../failure/time-spend.js";
|
|
19
|
-
import { baseRoleOf } from "../roles/
|
|
20
|
+
import { baseRoleOf } from "../roles/runner-ids.js";
|
|
20
21
|
import { commitTier } from "../roles/roles.js";
|
|
21
22
|
/** Fold one event's `providerCost` map (`Record<provider, {costUsd, notionalCostUsd}>` — the
|
|
22
|
-
* shape
|
|
23
|
+
* shape run-finalize.ts's run_end and merge-slot.ts's merge_done/merge_failed emit) into the
|
|
23
24
|
* per-provider tallies, one addTo per provider per nonzero figure so zero stays absent. A
|
|
24
25
|
* missing, foreign, or empty map folds nothing, so old logs render byte-identically. */
|
|
25
26
|
function foldProviderCost(target, providerCost) {
|
|
@@ -37,28 +38,28 @@ function foldProviderCost(target, providerCost) {
|
|
|
37
38
|
addTo(target.notionalByProvider, provider, notionalCostUsd);
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
|
-
/** Push
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (
|
|
47
|
-
list.push(
|
|
41
|
+
/** Push `ms` into the accumulator list a day median reads, when it is positive: the event
|
|
42
|
+
* fields that feed these medians are missing or 0 for the same event kinds (short runs, build
|
|
43
|
+
* pre-checks, precedent legacy events, probe-seam waits), and those contribute nothing — a
|
|
44
|
+
* median over only real durations/wait times. Every median list folds through here, so the
|
|
45
|
+
* "positive-only" rule cannot drift between fields. */
|
|
46
|
+
function pushPositiveMs(list, ms) {
|
|
47
|
+
if (ms > 0)
|
|
48
|
+
list.push(ms);
|
|
48
49
|
}
|
|
49
|
-
/** Fold one event into a usage accumulator: run_end events add a
|
|
50
|
-
* the target counts
|
|
50
|
+
/** Fold one event into a usage accumulator: run_end events add a run (per role and, when
|
|
51
|
+
* the target counts runs, in total), their output tokens, and their cost — zero-cost runs
|
|
51
52
|
* contribute nothing, so they leave no costByRole key, keeping the render's "$0 roles are
|
|
52
53
|
* omitted" rule true on the aggregation itself, not just at display time; merged events add
|
|
53
54
|
* a commit; merge_done/merge_failed events add a merge run and
|
|
54
|
-
* accumulate their tokens/cost into the merge fields only — costByRole stays a
|
|
55
|
+
* accumulate their tokens/cost into the merge fields only — costByRole stays a runs-only
|
|
55
56
|
* breakdown, and the merge line is how the reviewer's share is named. Both collectors fold
|
|
56
57
|
* through this one place, so the two windows' aggregation rules cannot drift apart. */
|
|
57
58
|
export function foldUsageEvent(target, ev) {
|
|
58
59
|
if (ev.type === "run_end") {
|
|
59
60
|
const role = eventRole(ev);
|
|
60
61
|
addTo(target.runsByRole, role, 1);
|
|
61
|
-
// Error-class
|
|
62
|
+
// Error-class runs get their own parallel tally — the day report's ``Failed runs by role``
|
|
62
63
|
// line — reusing the digest's OUTCOME_CLASS so "failed" cannot drift from the failure
|
|
63
64
|
// report's meaning. Never subtracted from runsByRole; the two are independent counts.
|
|
64
65
|
if (OUTCOME_CLASS[ev.result] === "error")
|
|
@@ -66,12 +67,13 @@ export function foldUsageEvent(target, ev) {
|
|
|
66
67
|
// A refusal is its own deliberate outcome (src/verdict/refusal.ts), not error-class, so
|
|
67
68
|
// it needs an explicit result check: the one per-role rejection-without-review count a
|
|
68
69
|
// day report should surface beside rejections, revisions and falls. Never subtracted from
|
|
69
|
-
// runsByRole; a refused
|
|
70
|
+
// runsByRole; a refused run still counts as a run.
|
|
70
71
|
if (ev.result === "refused")
|
|
71
72
|
addTo(target.refusalsByRole, role, 1);
|
|
72
73
|
if (target.runs !== undefined)
|
|
73
74
|
target.runs++;
|
|
74
75
|
const { tokens, costUsd, notionalCostUsd } = eventUsage(ev);
|
|
76
|
+
pushPositiveMs(target.runDurationsMs, finiteNumber(ev.durationMs, 0));
|
|
75
77
|
addTo(target.tokensByRole, role, tokens);
|
|
76
78
|
target.tokensOut += tokens;
|
|
77
79
|
target.costUsd += costUsd;
|
|
@@ -80,26 +82,53 @@ export function foldUsageEvent(target, ev) {
|
|
|
80
82
|
addTo(target.costByRole, role, costUsd);
|
|
81
83
|
if (notionalCostUsd !== 0)
|
|
82
84
|
addTo(target.notionalByRole, role, notionalCostUsd);
|
|
83
|
-
// The
|
|
85
|
+
// The notional spend's backend (plans/codex-backend.md part 3d/9): the subscription seam
|
|
86
|
+
// whose runs made the run's API-equivalent cost, from the run_end's `agent` (run-finalize
|
|
87
|
+
// carries it when the run reported billing/rate windows) — falling back to "claude" when
|
|
88
|
+
// a legacy window event (no agent, subscription billing) attributed its spend, so the old
|
|
89
|
+
// default stays the report's only backend. A run with no backend and no subscription
|
|
90
|
+
// billing is unattributed and adds no key, so the render keeps its generic line for it.
|
|
91
|
+
const notionalBackend = typeof ev.agent === "string" && ev.agent !== ""
|
|
92
|
+
? ev.agent
|
|
93
|
+
: ev.billing === "subscription"
|
|
94
|
+
? "claude"
|
|
95
|
+
: undefined;
|
|
96
|
+
if (notionalBackend !== undefined && notionalCostUsd !== 0)
|
|
97
|
+
addTo(target.notionalByBackend, notionalBackend, notionalCostUsd);
|
|
98
|
+
// The agent runs' per-provider spend (run-finalize.ts emits providerCost on run_end)
|
|
84
99
|
// — folded per provider beside the per-role maps, so a mixed team's `Cost by provider`
|
|
85
100
|
// line names the expensive seam.
|
|
86
101
|
foldProviderCost(target, ev.providerCost);
|
|
87
102
|
}
|
|
88
103
|
else if (ev.type === "review_rejected") {
|
|
89
|
-
// One rejection per event, on the day it happened, per
|
|
104
|
+
// One rejection per event, on the day it happened, per role. Zero-means-absent: a role
|
|
90
105
|
// that never rejected stays absent, like costByRole.
|
|
91
106
|
addTo(target.rejectionsByRole, eventRole(ev), 1);
|
|
107
|
+
// A rejection that carried afterMerge: true is a post-merge one — the commit had already
|
|
108
|
+
// landed, so the reviewer's turn-back reaches the revert path off main. Kept as its own
|
|
109
|
+
// subset of rejectionsByRole because it is a different, costlier kind of rejection.
|
|
110
|
+
if (ev.afterMerge === true)
|
|
111
|
+
addTo(target.postMergeRejectionsByRole, eventRole(ev), 1);
|
|
112
|
+
// A rejection that carried a positive durationMs means a reviewer actually ran the gate
|
|
113
|
+
// and reached a verdict (post-merge rejections do; the build pre-check contributes no
|
|
114
|
+
// duration), so it joins the review-duration median beside approvals. durationMs: 0 and
|
|
115
|
+
// a duration-less event contribute nothing.
|
|
116
|
+
pushPositiveMs(target.reviewDurationsMs, finiteNumber(ev.durationMs, 0));
|
|
117
|
+
}
|
|
118
|
+
else if (ev.type === "review_verdict") {
|
|
119
|
+
// An approval that reached a verdict. Every reviewer run that reached a verdict, approval
|
|
120
|
+
// or rejection, is one entry in the review-duration median; review_failed stays out — it
|
|
121
|
+
// has no verdict. Mirrors the rejection branch above, on the same-day count.
|
|
122
|
+
pushPositiveMs(target.reviewDurationsMs, finiteNumber(ev.durationMs, 0));
|
|
92
123
|
}
|
|
93
124
|
else if (ev.type === "revision") {
|
|
94
|
-
// One rework round per event, on the day it happened, per
|
|
125
|
+
// One rework round per event, on the day it happened, per role. Zero-means-absent: a role
|
|
95
126
|
// that never reworked a rejected change stays absent, like rejectionsByRole.
|
|
96
127
|
addTo(target.revisionsByRole, eventRole(ev), 1);
|
|
97
128
|
}
|
|
98
129
|
else if (isPassingFullCheck(ev)) {
|
|
99
130
|
// The merge slot's passing full-suite checks, for the day report's check-time median.
|
|
100
|
-
|
|
101
|
-
if (durationMs > 0)
|
|
102
|
-
target.checkDurationsMs.push(durationMs);
|
|
131
|
+
pushPositiveMs(target.checkDurationsMs, finiteNumber(ev.durationMs, 0));
|
|
103
132
|
}
|
|
104
133
|
else if (isRedFullCheck(ev)) {
|
|
105
134
|
// The merge slot's red full-suite checks, for the day report's red-check count.
|
|
@@ -114,7 +143,7 @@ export function foldUsageEvent(target, ev) {
|
|
|
114
143
|
addTo(target.imageReroutesByRole, eventRole(ev), 1);
|
|
115
144
|
}
|
|
116
145
|
else if (ev.type === "run_deferred") {
|
|
117
|
-
// One deferral per event, a due maintenance
|
|
146
|
+
// One deferral per event, a due maintenance run that stood down. Bucket by the raw
|
|
118
147
|
// reason code ("backlog", "plans-full", else "no-work" for a missing/foreign/torn
|
|
119
148
|
// reason — the same fallback deferredReasonText applies in the feed), so the collector
|
|
120
149
|
// stays free of a presentation import and the render prints the code the event carried.
|
|
@@ -146,19 +175,24 @@ export function foldUsageEvent(target, ev) {
|
|
|
146
175
|
// The day report's provider-slot wait median, mirroring the slot_wait push: a wait only
|
|
147
176
|
// event-logged at or above the 30 s threshold counts, so a 0 ms wait (a probe seam) adds
|
|
148
177
|
// nothing and the median reflects real blocked admissions only.
|
|
149
|
-
|
|
178
|
+
pushPositiveMs(target.providerWaitsMs, finiteNumber(ev.waitedMs, 0));
|
|
150
179
|
}
|
|
151
180
|
else if (ev.type === "slot_wait") {
|
|
152
181
|
// The day report's workspace-slot wait median, mirroring the provider_wait push: a wait
|
|
153
182
|
// only event-logged at or above the 30 s threshold counts, so a 0 ms wait (a probe seam)
|
|
154
183
|
// or a pre-waitedMs event adds nothing.
|
|
155
|
-
|
|
184
|
+
pushPositiveMs(target.slotWaitsMs, finiteNumber(ev.waitedMs, 0));
|
|
185
|
+
}
|
|
186
|
+
else if (ev.type === "check_wait") {
|
|
187
|
+
// The day report's check-slot wait median, mirroring the slot_wait push: only waits logged
|
|
188
|
+
// at or above the 30 s threshold count, so a 0 ms or pre-waitedMs event adds nothing.
|
|
189
|
+
pushPositiveMs(target.checkWaitsMs, finiteNumber(ev.waitedMs, 0));
|
|
156
190
|
}
|
|
157
191
|
else if (ev.type === "merge_done" || ev.type === "merge_failed") {
|
|
158
192
|
target.mergeRuns = (target.mergeRuns ?? 0) + 1;
|
|
159
193
|
if (ev.type === "merge_failed")
|
|
160
194
|
target.mergeFailed = (target.mergeFailed ?? 0) + 1;
|
|
161
|
-
// Attribute the outcome to the authoring role (writeMergeOutcome logs
|
|
195
|
+
// Attribute the outcome to the authoring role (writeMergeOutcome logs role: entry.role)
|
|
162
196
|
// folded to base role, the same normalization the merged branch uses, so `feature-2`
|
|
163
197
|
// aggregates into `feature`. A parallel tally beside the team run counts, never
|
|
164
198
|
// subtracted from mergeRuns/mergeFailed.
|
|
@@ -166,13 +200,15 @@ export function foldUsageEvent(target, ev) {
|
|
|
166
200
|
if (ev.type === "merge_done") {
|
|
167
201
|
addTo(target.mergedByRole, role, 1);
|
|
168
202
|
// Events logged before queuedMs existed carry none: skipped, not counted as zero.
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
203
|
+
pushPositiveMs(target.mergeWaitsMs, finiteNumber(ev.queuedMs, 0));
|
|
204
|
+
// How long the merge slot itself held the change, from the verification's start to the
|
|
205
|
+
// outcome. Like mergeWaitsMs, only a landed merge feeds it, and a pre-durationMs event
|
|
206
|
+
// (or 0) contributes nothing.
|
|
207
|
+
pushPositiveMs(target.mergeDurationsMs, finiteNumber(ev.durationMs, 0));
|
|
172
208
|
}
|
|
173
209
|
else {
|
|
174
210
|
addTo(target.mergeFailedByRole, role, 1);
|
|
175
|
-
// The event's result (writeMergeOutcome's
|
|
211
|
+
// The event's result (writeMergeOutcome's RunResult) names WHY the merge bounced
|
|
176
212
|
// off the gate — rejected/merge_conflict/merge_blocked/aborted. A legacy event with
|
|
177
213
|
// no result folds under `unknown`, so the reason buckets always sum to mergeFailed.
|
|
178
214
|
const reason = typeof ev.result === "string" && ev.result.length > 0 ? ev.result : "unknown";
|
|
@@ -184,6 +220,14 @@ export function foldUsageEvent(target, ev) {
|
|
|
184
220
|
// A subscription merge's API-equivalent spend joins the notional line, never the
|
|
185
221
|
// budgeted cost totals (plans/agent-backends.md part 6a).
|
|
186
222
|
target.notionalCostUsd += notionalCostUsd;
|
|
223
|
+
// The merge's notional spend per backend (merge-slot.ts emits it on the event, keyed by
|
|
224
|
+
// each subscription run's agent) — folded beside the run-end per-backend map, so a codex
|
|
225
|
+
// merge's subscription spend names codex instead of falling back to the generic line.
|
|
226
|
+
for (const [backend, c] of Object.entries(ev.notionalByBackend ?? {})) {
|
|
227
|
+
const amt = finiteNumber(c, 0);
|
|
228
|
+
if (amt !== 0)
|
|
229
|
+
addTo(target.notionalByBackend, backend, amt);
|
|
230
|
+
}
|
|
187
231
|
// The merge's per-provider spend (merge-slot.ts keys it to its reviewer seam), so a
|
|
188
232
|
// merge's costs appear under the provider that ran the reviewer, matching the author
|
|
189
233
|
// side's foldMergeUsage charge.
|
|
@@ -209,34 +253,61 @@ export function zeroCommitCounts() {
|
|
|
209
253
|
export function zeroMergeCounts() {
|
|
210
254
|
return { mergeRuns: 0, mergeTokens: 0, mergeCostUsd: 0 };
|
|
211
255
|
}
|
|
212
|
-
/**
|
|
213
|
-
*
|
|
214
|
-
*
|
|
256
|
+
/** The base roles a report scope names: undefined and an empty list mean no scope (the team
|
|
257
|
+
* report); otherwise each id folded through `baseRoleOf`, deduplicated in first-seen order, so
|
|
258
|
+
* `feature-2,feature` is one base. */
|
|
259
|
+
export function scopeBases(role) {
|
|
260
|
+
if (role === undefined)
|
|
261
|
+
return undefined;
|
|
262
|
+
const ids = asList(role);
|
|
263
|
+
if (ids.length === 0)
|
|
264
|
+
return undefined;
|
|
265
|
+
const out = [];
|
|
266
|
+
for (const id of ids) {
|
|
267
|
+
const base = baseRoleOf(id);
|
|
268
|
+
if (!out.includes(base))
|
|
269
|
+
out.push(base);
|
|
270
|
+
}
|
|
271
|
+
return out;
|
|
272
|
+
}
|
|
273
|
+
/** Sum a per-role-id count/cost map over the scoped base roles: instance keys (`feature-2`)
|
|
274
|
+
* fold into their base (`feature`), so a scoped report aggregates a whole role group exactly
|
|
275
|
+
* as the per-role cap's group does. Runs/tokens/cost are keyed by exact role id while commits are
|
|
215
276
|
* already base-role keyed; running every key through `baseRoleOf` reads both shapes the same
|
|
216
277
|
* and returns 0 when nothing matches. */
|
|
217
|
-
export function roleSum(record,
|
|
278
|
+
export function roleSum(record, bases) {
|
|
279
|
+
const list = asList(bases);
|
|
218
280
|
let sum = 0;
|
|
219
281
|
for (const [key, n] of Object.entries(record)) {
|
|
220
|
-
if (baseRoleOf(key)
|
|
282
|
+
if (list.includes(baseRoleOf(key)))
|
|
221
283
|
sum += n;
|
|
222
284
|
}
|
|
223
285
|
return sum;
|
|
224
286
|
}
|
|
225
|
-
/** Narrow a per-
|
|
226
|
-
* from the map (no
|
|
227
|
-
* same zero-means-absent rule the team render applies. Used by the
|
|
228
|
-
* scoped series derives from the fold's per-role maps without
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
287
|
+
/** Narrow a per-role-id count/cost map to the scoped base roles, one entry per base keyed by
|
|
288
|
+
* that base; a role absent from the map (no runs, or no nonzero cost) yields no entry, never
|
|
289
|
+
* a zero one — the same zero-means-absent rule the team render applies. Used by the
|
|
290
|
+
* role-scoped collectors so a scoped series derives from the fold's per-role maps without
|
|
291
|
+
* inventing entries. */
|
|
292
|
+
export function narrowToRole(record, bases) {
|
|
293
|
+
const out = {};
|
|
294
|
+
for (const base of asList(bases)) {
|
|
295
|
+
const n = roleSum(record, base);
|
|
296
|
+
if (n !== 0)
|
|
297
|
+
out[base] = n;
|
|
298
|
+
}
|
|
299
|
+
return out;
|
|
232
300
|
}
|
|
233
|
-
/** A per-
|
|
234
|
-
* set (a team report), else the same map narrowed to `
|
|
301
|
+
/** A per-role map scoped to the base roles of a report: the full map as-is when no scope is
|
|
302
|
+
* set (a team report), else the same map narrowed to `bases` — narrowToRole's zero-means-absent
|
|
235
303
|
* rule, so a scoped report never invents a zero entry. The one home of the "keep everything,
|
|
236
|
-
* or keep only the named base role" rule:
|
|
237
|
-
* output
|
|
238
|
-
|
|
239
|
-
|
|
304
|
+
* or keep only the named base role" rule: all 21 per-role, reason-keyed, and team-attribution
|
|
305
|
+
* fields of the `--since` report's output shape through it — the four team maps
|
|
306
|
+
* (costByProvider, notionalByProvider, notionalByBackend, runsByModel) narrow to empty in a
|
|
307
|
+
* scoped window (a provider/backend/model is not a role) but still shape through it — so the
|
|
308
|
+
* scoping rule cannot drift between them. */
|
|
309
|
+
export function scopedByRole(record, bases) {
|
|
310
|
+
return bases === undefined ? record : narrowToRole(record, bases);
|
|
240
311
|
}
|
|
241
312
|
function dayFoldFor(entry, dayKey) {
|
|
242
313
|
let fold = entry.days.get(dayKey);
|
|
@@ -248,13 +319,18 @@ function dayFoldFor(entry, dayKey) {
|
|
|
248
319
|
notionalCostUsd: 0,
|
|
249
320
|
runsByRole: {},
|
|
250
321
|
rejectionsByRole: {},
|
|
322
|
+
postMergeRejectionsByRole: {},
|
|
251
323
|
revisionsByRole: {},
|
|
252
324
|
refusalsByRole: {},
|
|
253
325
|
checkDurationsMs: [],
|
|
254
326
|
checkFailures: 0,
|
|
255
327
|
mergeWaitsMs: [],
|
|
328
|
+
mergeDurationsMs: [],
|
|
329
|
+
runDurationsMs: [],
|
|
256
330
|
providerWaitsMs: [],
|
|
257
331
|
slotWaitsMs: [],
|
|
332
|
+
checkWaitsMs: [],
|
|
333
|
+
reviewDurationsMs: [],
|
|
258
334
|
failedRunsByRole: {},
|
|
259
335
|
fallbacksByRole: {},
|
|
260
336
|
imageReroutesByRole: {},
|
|
@@ -267,6 +343,7 @@ function dayFoldFor(entry, dayKey) {
|
|
|
267
343
|
mergeFailedByReason: {},
|
|
268
344
|
costByProvider: {},
|
|
269
345
|
notionalByProvider: {},
|
|
346
|
+
notionalByBackend: {},
|
|
270
347
|
runsByModel: {},
|
|
271
348
|
deferredByReason: {},
|
|
272
349
|
};
|
|
@@ -286,6 +363,8 @@ function foldEventInto(entry, ev) {
|
|
|
286
363
|
entry.hadEvents = true;
|
|
287
364
|
entry.firstEventTs = typeof ev.ts === "number" ? ev.ts : undefined;
|
|
288
365
|
}
|
|
366
|
+
if (isRedMain(ev) || isPassingMainCheck(ev))
|
|
367
|
+
entry.redEvents.push(ev);
|
|
289
368
|
foldUsageEvent(dayFoldFor(entry, dayKey), ev);
|
|
290
369
|
}
|
|
291
370
|
/** Parse one appended log line and fold it; a torn or non-event line folds nothing. */
|
|
@@ -307,11 +386,7 @@ function foldLineInto(entry, line) {
|
|
|
307
386
|
* carrying yesterday's proof forward. */
|
|
308
387
|
export function foldWindowEvents(root, fromKey) {
|
|
309
388
|
const key = `${root}\0${fromKey}`;
|
|
310
|
-
const
|
|
311
|
-
const size = liveStat?.size ?? 0;
|
|
312
|
-
const mtimeMs = liveStat?.mtimeMs ?? 0;
|
|
313
|
-
const dev = liveStat?.dev ?? 0;
|
|
314
|
-
const ino = liveStat?.ino ?? 0;
|
|
389
|
+
const { size, mtimeMs, dev, ino } = statIdentityOrZero(statOrNull(eventsLogPath(root)));
|
|
315
390
|
const cached = reportFoldCache.get(key);
|
|
316
391
|
if (cached &&
|
|
317
392
|
sameStatIdentity({ dev, ino, mtimeMs, size }, { dev: cached.dev, ino: cached.ino, mtimeMs: cached.mtimeMs, size: cached.offset })) {
|
|
@@ -345,6 +420,7 @@ export function foldWindowEvents(root, fromKey) {
|
|
|
345
420
|
fileCovers: raw.coversFullWindow,
|
|
346
421
|
hadEvents: false,
|
|
347
422
|
days: new Map(),
|
|
423
|
+
redEvents: [],
|
|
348
424
|
};
|
|
349
425
|
for (const ev of raw.events)
|
|
350
426
|
foldEventInto(entry, ev);
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** Main's red time per local calendar day: how long main had no passing full check, from the
|
|
2
|
+
* same `main_check` / `main_red_hold` event trail G1 uses (src/baseline/main-guardrails.ts).
|
|
3
|
+
* Pure and synchronous over an event list and a `[fromMs, toMs)` window, so the usage
|
|
4
|
+
* report's day and --since collectors both call it without reading the clock or the log
|
|
5
|
+
* again. This is main's own wall-clock red time, not any role's, so the report carries it
|
|
6
|
+
* only on the team scope. */
|
|
7
|
+
import { dayKey } from "../text/datetime.js";
|
|
8
|
+
import { isPassingMainCheck, isRedMain } from "../baseline/main-guardrails.js";
|
|
9
|
+
/** Add a spell's ms, split across the local calendar days it spans, to `map` (a Map, so the
|
|
10
|
+
* caller keeps the day-key order the walk produced). */
|
|
11
|
+
function addSpell(map, start, end) {
|
|
12
|
+
let cur = start;
|
|
13
|
+
while (cur < end) {
|
|
14
|
+
// The Date constructor's month/date fields cross the local midnight (and any DST shift
|
|
15
|
+
// at it) exactly as dayAt does, so an hour cannot leak into the next day.
|
|
16
|
+
const d = new Date(cur);
|
|
17
|
+
const nextMidnight = new Date(d.getFullYear(), d.getMonth(), d.getDate() + 1).getTime();
|
|
18
|
+
const segEnd = Math.min(end, nextMidnight);
|
|
19
|
+
const ms = segEnd - cur;
|
|
20
|
+
if (ms > 0)
|
|
21
|
+
map.set(dayKey(cur), (map.get(dayKey(cur)) ?? 0) + ms);
|
|
22
|
+
cur = segEnd;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/** Main's red wall-clock time per local calendar day (`YYYY-MM-DD` → ms), over the window
|
|
26
|
+
* `[fromMs, toMs)`. A red spell is G1's rule (isRedMain / isPassingMainCheck): it opens at a
|
|
27
|
+
* red event while none is open (a further red while open keeps the earliest start) and closes
|
|
28
|
+
* at the next passing full `main_check`; a spell still open at `toMs` runs to the window's
|
|
29
|
+
* end. Every spell is split across local calendar days (dayKey) with midnight arithmetic, so
|
|
30
|
+
* a DST shift cannot leak an hour into the next day; only nonzero daily entries are returned.
|
|
31
|
+
* A spell already open before `fromMs` is not counted, because its opener lies outside the
|
|
32
|
+
* window — the report measures main's own red time within the window it was asked for. */
|
|
33
|
+
export function mainRedMinutesByDay(events, fromMs, toMs) {
|
|
34
|
+
const map = new Map();
|
|
35
|
+
const inWindow = events
|
|
36
|
+
.filter((e) => typeof e.ts === "number" && e.ts >= fromMs && e.ts < toMs)
|
|
37
|
+
.sort((a, b) => a.ts - b.ts);
|
|
38
|
+
let openStart;
|
|
39
|
+
for (const e of inWindow) {
|
|
40
|
+
const ts = e.ts;
|
|
41
|
+
if (isRedMain(e)) {
|
|
42
|
+
if (openStart === undefined)
|
|
43
|
+
openStart = ts;
|
|
44
|
+
}
|
|
45
|
+
else if (isPassingMainCheck(e)) {
|
|
46
|
+
if (openStart !== undefined) {
|
|
47
|
+
addSpell(map, openStart, ts);
|
|
48
|
+
openStart = undefined;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (openStart !== undefined)
|
|
53
|
+
addSpell(map, openStart, toMs);
|
|
54
|
+
return map;
|
|
55
|
+
}
|