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,32 +1,33 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
/** Collection half of the usage report: read the harness's event log (through the shared
|
|
3
2
|
* event-folding layer in src/report/report-fold.ts) and the backlog history over a window of
|
|
4
3
|
* local calendar days and distill it into a `ReportData` / `SinceReport` — per-day
|
|
5
|
-
*
|
|
4
|
+
* run/token/commit/cost counts plus features-done and bugs-fixed tallies from PLANS.md and
|
|
6
5
|
* BUGS.md. The Markdown rendering of this data lives in src/report/report-render.ts, a pure
|
|
7
6
|
* function of it; the split mirrors the failure report's (src/failure/failure-data.ts /
|
|
8
7
|
* src/failure/failure-render.ts) and keeps "what happened" (window math, aggregation, bounds)
|
|
9
8
|
* apart from "how it prints" (bars, cell wording), which change for different reasons — and
|
|
10
9
|
* keeps core data collection out of the presentation layer, so a core consumer (as
|
|
11
10
|
* /api/report already is) never forces a core→ui import. This file holds the two window
|
|
12
|
-
* collectors
|
|
13
|
-
* per-window cache
|
|
14
|
-
|
|
15
|
-
import {
|
|
11
|
+
* collectors; the report shapes they produce live in src/report/report-types.ts, and the
|
|
12
|
+
* event-log folding and its memoized per-window cache in src/report/report-fold.ts (its own
|
|
13
|
+
* test, report-fold-cache). */
|
|
14
|
+
import { assertReportSinceMs, eventWindowCovers, readWindowEvents, sinceWindowTiming } from "../events/event-window.js";
|
|
15
|
+
import { DONE_DATE_RE, FIXED_DATE_RE, completionDate, finishedFiles, fixedBugEntries, sectionCompletionDates, sectionCompletionLags, sectionFilingDates, } from "../backlog/backlog.js";
|
|
16
16
|
import { validationGapTag } from "../backlog/backlog-md.js";
|
|
17
17
|
import { dayAt, dayKey, dayWindow, formatDate } from "../text/datetime.js";
|
|
18
18
|
import { addTo, lowerMedian } from "../collections.js";
|
|
19
|
-
import { baseRoleOf } from "../roles/loop-ids.js";
|
|
20
19
|
import { commitTier } from "../roles/roles.js";
|
|
21
|
-
import { foldUsageEvent, foldWindowEvents, narrowToRole, roleSum, scopedByRole, zeroCommitCounts, zeroMergeCounts, } from "./report-fold.js";
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
import { foldUsageEvent, foldWindowEvents, narrowToRole, roleSum, scopeBases, scopedByRole, zeroCommitCounts, zeroMergeCounts, } from "./report-fold.js";
|
|
21
|
+
import { mainRedMinutesByDay } from "./report-main-red.js";
|
|
22
|
+
/** Aggregate team usage over the trailing `sinceMs` window ending now (or `untilMs` ago, which
|
|
23
|
+
* drops events at or after that end; `coversFullWindow` still judges the far edge
|
|
24
|
+
* only), from the event log only (run_end/merged — see SinceReport for why the backlog files
|
|
25
|
+
* are not read). Kept a
|
|
24
26
|
* separate function rather than a `collectReport` variant flag: the day collector's
|
|
25
27
|
* zero-filled series and backlog-file reads have no place in a window totals view. */
|
|
26
|
-
export function collectReportSince(root, sinceMs, role) {
|
|
28
|
+
export function collectReportSince(root, sinceMs, role, untilMs) {
|
|
27
29
|
assertReportSinceMs(sinceMs);
|
|
28
|
-
const now =
|
|
29
|
-
const cutoff = now - sinceMs;
|
|
30
|
+
const { now, cutoff, end, slice } = sinceWindowTiming(sinceMs, untilMs);
|
|
30
31
|
// The window key is the cutoff's local calendar day, from the shared dayKey helper
|
|
31
32
|
// eventDayKey buckets events with, so the read's day keys cannot disagree with the ts
|
|
32
33
|
// filter below; the day-keyed read may include earlier hours of that day, which the ts
|
|
@@ -38,13 +39,18 @@ export function collectReportSince(root, sinceMs, role) {
|
|
|
38
39
|
runs: 0,
|
|
39
40
|
runsByRole: {},
|
|
40
41
|
rejectionsByRole: {},
|
|
42
|
+
postMergeRejectionsByRole: {},
|
|
41
43
|
revisionsByRole: {},
|
|
42
44
|
refusalsByRole: {},
|
|
43
45
|
checkDurationsMs: [],
|
|
44
46
|
checkFailures: 0,
|
|
45
47
|
mergeWaitsMs: [],
|
|
48
|
+
mergeDurationsMs: [],
|
|
49
|
+
runDurationsMs: [],
|
|
46
50
|
providerWaitsMs: [],
|
|
47
51
|
slotWaitsMs: [],
|
|
52
|
+
checkWaitsMs: [],
|
|
53
|
+
reviewDurationsMs: [],
|
|
48
54
|
failedRunsByRole: {},
|
|
49
55
|
fallbacksByRole: {},
|
|
50
56
|
imageReroutesByRole: {},
|
|
@@ -61,11 +67,12 @@ export function collectReportSince(root, sinceMs, role) {
|
|
|
61
67
|
mergeFailedByReason: {},
|
|
62
68
|
costByProvider: {},
|
|
63
69
|
notionalByProvider: {},
|
|
70
|
+
notionalByBackend: {},
|
|
64
71
|
runsByModel: {},
|
|
65
72
|
deferredByReason: {},
|
|
66
73
|
};
|
|
67
74
|
for (const ev of raw.events) {
|
|
68
|
-
if (typeof ev.ts !== "number" || ev.ts < cutoff || ev.ts > now)
|
|
75
|
+
if (typeof ev.ts !== "number" || ev.ts < cutoff || ev.ts > now || (untilMs !== undefined && ev.ts >= end))
|
|
69
76
|
continue;
|
|
70
77
|
foldUsageEvent(acc, ev);
|
|
71
78
|
}
|
|
@@ -74,18 +81,19 @@ export function collectReportSince(root, sinceMs, role) {
|
|
|
74
81
|
// history that never existed. When neither proof holds, the oldest retained event lies inside
|
|
75
82
|
// the window and the render notes the possible truncation.
|
|
76
83
|
const coversFullWindow = eventWindowCovers(raw, cutoff);
|
|
77
|
-
// Role scope: every total derives from the fold's per-role maps for the named base
|
|
84
|
+
// Role scope: every total derives from the fold's per-role maps for the named base roles alone
|
|
78
85
|
// — merge usage (the merge slot's, not the role's) and the team-only fields stay out, so
|
|
79
86
|
// a scoped --since report sums exactly the same events the scoped day report would. The scope
|
|
80
|
-
// is the base
|
|
81
|
-
const
|
|
82
|
-
const scopedTotals =
|
|
87
|
+
// is the base roles, so instances (`feature-2`) aggregate into their group as the cap does.
|
|
88
|
+
const bases = scopeBases(role);
|
|
89
|
+
const scopedTotals = bases === undefined
|
|
83
90
|
? {
|
|
84
91
|
tokensOut: acc.tokensOut + (acc.mergeTokens ?? 0),
|
|
85
92
|
runs: acc.runs ?? 0,
|
|
86
93
|
commits: acc.commits,
|
|
87
94
|
costUsd: acc.costUsd + (acc.mergeCostUsd ?? 0),
|
|
88
95
|
...(acc.notionalCostUsd > 0 ? { notionalCostUsd: acc.notionalCostUsd } : {}),
|
|
96
|
+
...nonemptyObj("notionalByBackend", acc.notionalByBackend),
|
|
89
97
|
mergeRuns: acc.mergeRuns ?? 0,
|
|
90
98
|
mergeTokens: acc.mergeTokens ?? 0,
|
|
91
99
|
mergeCostUsd: acc.mergeCostUsd ?? 0,
|
|
@@ -94,12 +102,12 @@ export function collectReportSince(root, sinceMs, role) {
|
|
|
94
102
|
: (() => {
|
|
95
103
|
// The role's own notional spend, from its run_end events; the merge slot's
|
|
96
104
|
// notional is team-wide and stays out like its cost.
|
|
97
|
-
const notional = roleSum(acc.notionalByRole,
|
|
105
|
+
const notional = roleSum(acc.notionalByRole, bases);
|
|
98
106
|
return {
|
|
99
|
-
tokensOut: roleSum(acc.tokensByRole,
|
|
100
|
-
runs: roleSum(acc.runsByRole,
|
|
101
|
-
commits: roleSum(acc.commitsByRole,
|
|
102
|
-
costUsd: roleSum(acc.costByRole,
|
|
107
|
+
tokensOut: roleSum(acc.tokensByRole, bases),
|
|
108
|
+
runs: roleSum(acc.runsByRole, bases),
|
|
109
|
+
commits: roleSum(acc.commitsByRole, bases),
|
|
110
|
+
costUsd: roleSum(acc.costByRole, bases),
|
|
103
111
|
...(notional > 0 ? { notionalCostUsd: notional } : {}),
|
|
104
112
|
...zeroMergeCounts(),
|
|
105
113
|
};
|
|
@@ -108,49 +116,81 @@ export function collectReportSince(root, sinceMs, role) {
|
|
|
108
116
|
// notional spend, scoped to base when a role is given — the same conditional the day
|
|
109
117
|
// collector applies to ReportDay.notionalByRole (line ~573), so a role-scoped window
|
|
110
118
|
// whose role spent no notional carries no notionalByRole instead of an empty map.
|
|
111
|
-
const notionalByRole = scopedByRole(acc.notionalByRole,
|
|
119
|
+
const notionalByRole = scopedByRole(acc.notionalByRole, bases);
|
|
112
120
|
// Deferred runs are bucketed by a reason code (not a role), so a role-scoped window
|
|
113
121
|
// carries no entries — the same team-only rule runsByModel follows. Only set when the
|
|
114
122
|
// window actually deferred (zero means absent), so a deferral-free --since JSON omits it.
|
|
115
|
-
const deferred = scopedByRole(acc.deferredByReason,
|
|
123
|
+
const deferred = scopedByRole(acc.deferredByReason, bases);
|
|
116
124
|
return {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
...(base === undefined ? {} : { role: base }),
|
|
125
|
+
...slice,
|
|
126
|
+
...(bases === undefined ? {} : { role: bases.join(",") }),
|
|
120
127
|
totals: scopedTotals,
|
|
121
|
-
runsByRole: scopedByRole(acc.runsByRole,
|
|
122
|
-
costByRole: scopedByRole(acc.costByRole,
|
|
123
|
-
rejectionsByRole: scopedByRole(acc.rejectionsByRole,
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
128
|
+
runsByRole: scopedByRole(acc.runsByRole, bases),
|
|
129
|
+
costByRole: scopedByRole(acc.costByRole, bases),
|
|
130
|
+
rejectionsByRole: scopedByRole(acc.rejectionsByRole, bases),
|
|
131
|
+
postMergeRejectionsByRole: scopedByRole(acc.postMergeRejectionsByRole, bases),
|
|
132
|
+
revisionsByRole: scopedByRole(acc.revisionsByRole, bases),
|
|
133
|
+
refusalsByRole: scopedByRole(acc.refusalsByRole, bases),
|
|
134
|
+
failedRunsByRole: scopedByRole(acc.failedRunsByRole, bases),
|
|
135
|
+
fallbacksByRole: scopedByRole(acc.fallbacksByRole, bases),
|
|
136
|
+
imageReroutesByRole: scopedByRole(acc.imageReroutesByRole, bases),
|
|
137
|
+
tokensByRole: scopedByRole(acc.tokensByRole, bases),
|
|
138
|
+
commitsByRole: scopedByRole(acc.commitsByRole, bases),
|
|
139
|
+
mergedByRole: scopedByRole(acc.mergedByRole, bases),
|
|
140
|
+
mergeFailedByRole: scopedByRole(acc.mergeFailedByRole, bases),
|
|
133
141
|
// A result code is not a role, so a role-scoped window carries an empty map (a code
|
|
134
142
|
// never baseRoleOf to the role) — the render gates the reason line to the team report.
|
|
135
|
-
mergeFailedByReason: scopedByRole(acc.mergeFailedByReason,
|
|
136
|
-
...(
|
|
143
|
+
mergeFailedByReason: scopedByRole(acc.mergeFailedByReason, bases),
|
|
144
|
+
...nonemptyObj("notionalByRole", notionalByRole),
|
|
137
145
|
// Provider spend is a team attribution (a provider is not a role), so a role-scoped
|
|
138
146
|
// window carries empty maps — providers never baseRoleOf to the role — and the render
|
|
139
147
|
// gates the provider lines to the team report anyway. Always present, empty when none.
|
|
140
|
-
costByProvider: scopedByRole(acc.costByProvider,
|
|
141
|
-
notionalByProvider: scopedByRole(acc.notionalByProvider,
|
|
148
|
+
costByProvider: scopedByRole(acc.costByProvider, bases),
|
|
149
|
+
notionalByProvider: scopedByRole(acc.notionalByProvider, bases),
|
|
150
|
+
// Backend spend is a team attribution (a backend is not a role), so a role-scoped window
|
|
151
|
+
// omits it — the same absent-when-empty rule the day collector applies.
|
|
152
|
+
...nonemptyObj("notionalByBackend", scopedByRole(acc.notionalByBackend, bases)),
|
|
142
153
|
// Model attribution is team-only (a model is not a role, so no model folds to the
|
|
143
154
|
// scoped role), the same full-map-for-team / empty-for-scoped rule costByProvider
|
|
144
155
|
// follows. Always present so the render can gate on the window's own events.
|
|
145
|
-
runsByModel: scopedByRole(acc.runsByModel,
|
|
146
|
-
...(
|
|
156
|
+
runsByModel: scopedByRole(acc.runsByModel, bases),
|
|
157
|
+
...nonemptyObj("deferredByReason", deferred),
|
|
158
|
+
// Main's red time is main's own (G1's rule), not any role's, so a role-scoped window
|
|
159
|
+
// carries 0 — the type's always-present default for the team-only field.
|
|
160
|
+
mainRedMs: bases === undefined
|
|
161
|
+
? [...mainRedMinutesByDay(raw.events, cutoff, end).values()].reduce((a, b) => a + b, 0)
|
|
162
|
+
: 0,
|
|
147
163
|
coversFullWindow,
|
|
148
164
|
};
|
|
149
165
|
}
|
|
166
|
+
/** Set one per-day median cell only when the day actually has samples (`ms` non-empty), so a
|
|
167
|
+
* medians-free day keeps its exact pre-feature shape (the field stays absent). The single home
|
|
168
|
+
* of that guard — the day collector's eight `…MedianMs` cells all followed it inline before. */
|
|
169
|
+
function setLowerMedian(day, key, ms) {
|
|
170
|
+
if (ms.length > 0)
|
|
171
|
+
day[key] = lowerMedian(ms);
|
|
172
|
+
}
|
|
173
|
+
/** Set one per-day role/product map cell only when the day actually has entries (`map`
|
|
174
|
+
* non-empty), so a map-free day keeps its exact pre-feature shape (the field stays absent).
|
|
175
|
+
* The single home of that guard — the day collector's per-role-and-product map cells all
|
|
176
|
+
* followed it inline before. */
|
|
177
|
+
function setMapIfNonempty(day, key, map) {
|
|
178
|
+
if (map !== undefined && Object.keys(map).length > 0) {
|
|
179
|
+
day[key] = map;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/** Build one object-literal spread cell for a per-slice role/product map only when the map has
|
|
183
|
+
* entries (`map` non-empty), so an entry-free window omits the field instead of carrying an
|
|
184
|
+
* empty map. The single home of that guard — the window and totals object-literal spreads all
|
|
185
|
+
* followed it inline before. */
|
|
186
|
+
function nonemptyObj(key, map) {
|
|
187
|
+
return Object.keys(map).length > 0 ? { [key]: map } : {};
|
|
188
|
+
}
|
|
150
189
|
/** Aggregate team usage over exactly `days` local calendar days ending today, from the event
|
|
151
190
|
* log (run_end/merged) and the backlog history (`## Done` in PLANS.md and PLANS-DONE.md,
|
|
152
191
|
* `## Fixed` in BUGS.md and BUGS-FIXED.md). */
|
|
153
192
|
export function collectReport(root, days, role) {
|
|
193
|
+
const bases = scopeBases(role);
|
|
154
194
|
const now = new Date();
|
|
155
195
|
// One captured instant for the whole window, so every day key derives from the same day.
|
|
156
196
|
const { from, to } = dayWindow(days, now);
|
|
@@ -175,38 +215,35 @@ export function collectReport(root, days, role) {
|
|
|
175
215
|
const day = byDate.get(dayKey);
|
|
176
216
|
if (!day)
|
|
177
217
|
continue; // Out-of-window day key (e.g. future-dated) — no series slot to fill.
|
|
178
|
-
if (
|
|
218
|
+
if (bases === undefined) {
|
|
179
219
|
day.tokensOut = fold.tokensOut;
|
|
180
220
|
day.runsByRole = fold.runsByRole;
|
|
181
221
|
day.tokensByRole = fold.tokensByRole;
|
|
182
222
|
day.costByRole = fold.costByRole;
|
|
183
223
|
// Only set when nonzero, so a rejection-free day keeps its exact pre-feature shape.
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
if (Object.keys(fold.refusalsByRole).length > 0)
|
|
189
|
-
day.refusalsByRole = fold.refusalsByRole;
|
|
224
|
+
setMapIfNonempty(day, "rejectionsByRole", fold.rejectionsByRole);
|
|
225
|
+
setMapIfNonempty(day, "postMergeRejectionsByRole", fold.postMergeRejectionsByRole);
|
|
226
|
+
setMapIfNonempty(day, "revisionsByRole", fold.revisionsByRole);
|
|
227
|
+
setMapIfNonempty(day, "refusalsByRole", fold.refusalsByRole);
|
|
190
228
|
// Checks belong to the merge slot, so only the team series carries the median.
|
|
191
|
-
|
|
192
|
-
day.checkMedianMs = lowerMedian(fold.checkDurationsMs);
|
|
193
|
-
}
|
|
229
|
+
setLowerMedian(day, "checkMedianMs", fold.checkDurationsMs);
|
|
194
230
|
if (fold.checkFailures > 0)
|
|
195
231
|
day.checkFailures = fold.checkFailures;
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
232
|
+
setLowerMedian(day, "mergeWaitMedianMs", fold.mergeWaitsMs);
|
|
233
|
+
setLowerMedian(day, "mergeSlotMedianMs", fold.mergeDurationsMs);
|
|
234
|
+
setLowerMedian(day, "runMedianMs", fold.runDurationsMs);
|
|
235
|
+
setLowerMedian(day, "providerWaitMedianMs", fold.providerWaitsMs);
|
|
200
236
|
// A workspace wait is the pool's, not a role's, so only the team series carries it.
|
|
201
|
-
|
|
202
|
-
|
|
237
|
+
setLowerMedian(day, "slotWaitMedianMs", fold.slotWaitsMs);
|
|
238
|
+
// A check permit is the team's, not a role's, so only the team series carries it.
|
|
239
|
+
setLowerMedian(day, "checkWaitMedianMs", fold.checkWaitsMs);
|
|
240
|
+
// A review belongs to the merge slot/reviewer, not the author role, so only the team
|
|
241
|
+
// series carries the median, mirroring checkMedianMs.
|
|
242
|
+
setLowerMedian(day, "reviewMedianMs", fold.reviewDurationsMs);
|
|
203
243
|
// Only set when nonzero, so a failure-free day keeps its exact pre-feature shape.
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
day.fallbacksByRole = fold.fallbacksByRole;
|
|
208
|
-
if (Object.keys(fold.imageReroutesByRole).length > 0)
|
|
209
|
-
day.imageReroutesByRole = fold.imageReroutesByRole;
|
|
244
|
+
setMapIfNonempty(day, "failedRunsByRole", fold.failedRunsByRole);
|
|
245
|
+
setMapIfNonempty(day, "fallbacksByRole", fold.fallbacksByRole);
|
|
246
|
+
setMapIfNonempty(day, "imageReroutesByRole", fold.imageReroutesByRole);
|
|
210
247
|
day.commits = fold.commits;
|
|
211
248
|
day.commitsByRole = fold.commitsByRole;
|
|
212
249
|
day.workCommits = fold.workCommits;
|
|
@@ -215,24 +252,23 @@ export function collectReport(root, days, role) {
|
|
|
215
252
|
// Only set when nonzero, so zero-notional days keep their exact pre-feature shape.
|
|
216
253
|
if (fold.notionalCostUsd > 0)
|
|
217
254
|
day.notionalCostUsd = fold.notionalCostUsd;
|
|
218
|
-
|
|
219
|
-
day.notionalByRole = fold.notionalByRole;
|
|
255
|
+
setMapIfNonempty(day, "notionalByRole", fold.notionalByRole);
|
|
220
256
|
// Only set when a provider actually spent (zero means absent), so a provider-free day
|
|
221
257
|
// keeps its exact pre-feature shape and `report --json` omits the maps when empty.
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
258
|
+
setMapIfNonempty(day, "costByProvider", fold.costByProvider);
|
|
259
|
+
setMapIfNonempty(day, "notionalByProvider", fold.notionalByProvider);
|
|
260
|
+
// Backends are a team attribution (a backend is not a role), so only the team series
|
|
261
|
+
// carries the map; only set when a backend actually spent (zero means absent), so a
|
|
262
|
+
// backend-free day keeps its exact pre-feature shape.
|
|
263
|
+
setMapIfNonempty(day, "notionalByBackend", fold.notionalByBackend);
|
|
226
264
|
// Models are a team attribution (a model is not a role), so only the team series
|
|
227
265
|
// carries the map; only set when a modelled start happened (zero means absent), so a
|
|
228
266
|
// model-less day keeps its exact pre-feature shape.
|
|
229
|
-
|
|
230
|
-
day.runsByModel = fold.runsByModel;
|
|
267
|
+
setMapIfNonempty(day, "runsByModel", fold.runsByModel);
|
|
231
268
|
// Deferred runs are a team attribution (a reason is not a role), so only the team
|
|
232
269
|
// series carries the map; only set when a day actually deferred (zero means absent),
|
|
233
270
|
// so a deferral-free day keeps its exact pre-feature shape.
|
|
234
|
-
|
|
235
|
-
day.deferredByReason = fold.deferredByReason;
|
|
271
|
+
setMapIfNonempty(day, "deferredByReason", fold.deferredByReason);
|
|
236
272
|
day.mergeRuns = fold.mergeRuns;
|
|
237
273
|
day.mergeTokens = fold.mergeTokens;
|
|
238
274
|
day.mergeCostUsd = fold.mergeCostUsd;
|
|
@@ -241,68 +277,49 @@ export function collectReport(root, days, role) {
|
|
|
241
277
|
day.mergeFailed = fold.mergeFailed;
|
|
242
278
|
// Only set when a role actually merged/failed that day (zero means absent), so a
|
|
243
279
|
// merge-free day keeps its exact pre-feature shape.
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
if (Object.keys(fold.mergeFailedByRole).length > 0)
|
|
247
|
-
day.mergeFailedByRole = fold.mergeFailedByRole;
|
|
280
|
+
setMapIfNonempty(day, "mergedByRole", fold.mergedByRole);
|
|
281
|
+
setMapIfNonempty(day, "mergeFailedByRole", fold.mergeFailedByRole);
|
|
248
282
|
// Reason codes are a team attribution (a result is not a role), so only the team
|
|
249
283
|
// series carries the map; only set when nonzero, so a failure-free day keeps its
|
|
250
284
|
// exact pre-feature shape. The role branch below leaves it unset — merge runs are
|
|
251
285
|
// the merge slot's.
|
|
252
|
-
|
|
253
|
-
day.mergeFailedByReason = fold.mergeFailedByReason;
|
|
286
|
+
setMapIfNonempty(day, "mergeFailedByReason", fold.mergeFailedByReason);
|
|
254
287
|
}
|
|
255
288
|
else {
|
|
256
289
|
// Role scope: derive this day from the fold's per-role maps, so the series carries only
|
|
257
|
-
// the named role's
|
|
290
|
+
// the named role's runs/tokens/cost and (base-role-keyed) commits. The scope is the
|
|
258
291
|
// base role, so an instance id's usage and its siblings' commits fold into one group and
|
|
259
292
|
// the numbers match the per-role cap, which is base-role keyed too. The merge fields
|
|
260
293
|
// stay unset — merge runs are the merge slot's, not this role's — and the work /
|
|
261
294
|
// maintenance split follows the base role's own tier rather than the day's whole split.
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
day.
|
|
266
|
-
day.
|
|
267
|
-
day
|
|
268
|
-
day
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
day.revisionsByRole = revs;
|
|
275
|
-
const refusals = narrowToRole(fold.refusalsByRole, base);
|
|
276
|
-
if (Object.keys(refusals).length > 0)
|
|
277
|
-
day.refusalsByRole = refusals;
|
|
278
|
-
const fails = narrowToRole(fold.failedRunsByRole, base);
|
|
279
|
-
if (Object.keys(fails).length > 0)
|
|
280
|
-
day.failedRunsByRole = fails;
|
|
281
|
-
const falls = narrowToRole(fold.fallbacksByRole, base);
|
|
282
|
-
if (Object.keys(falls).length > 0)
|
|
283
|
-
day.fallbacksByRole = falls;
|
|
284
|
-
const reroutes = narrowToRole(fold.imageReroutesByRole, base);
|
|
285
|
-
if (Object.keys(reroutes).length > 0)
|
|
286
|
-
day.imageReroutesByRole = reroutes;
|
|
295
|
+
const commits = roleSum(fold.commitsByRole, bases);
|
|
296
|
+
day.tokensOut = roleSum(fold.tokensByRole, bases);
|
|
297
|
+
day.runsByRole = narrowToRole(fold.runsByRole, bases);
|
|
298
|
+
day.tokensByRole = narrowToRole(fold.tokensByRole, bases);
|
|
299
|
+
day.costByRole = narrowToRole(fold.costByRole, bases);
|
|
300
|
+
setMapIfNonempty(day, "rejectionsByRole", narrowToRole(fold.rejectionsByRole, bases));
|
|
301
|
+
setMapIfNonempty(day, "postMergeRejectionsByRole", narrowToRole(fold.postMergeRejectionsByRole, bases));
|
|
302
|
+
setMapIfNonempty(day, "revisionsByRole", narrowToRole(fold.revisionsByRole, bases));
|
|
303
|
+
setMapIfNonempty(day, "refusalsByRole", narrowToRole(fold.refusalsByRole, bases));
|
|
304
|
+
setMapIfNonempty(day, "failedRunsByRole", narrowToRole(fold.failedRunsByRole, bases));
|
|
305
|
+
setMapIfNonempty(day, "fallbacksByRole", narrowToRole(fold.fallbacksByRole, bases));
|
|
306
|
+
setMapIfNonempty(day, "imageReroutesByRole", narrowToRole(fold.imageReroutesByRole, bases));
|
|
287
307
|
day.commits = commits;
|
|
288
|
-
day.commitsByRole = narrowToRole(fold.commitsByRole,
|
|
289
|
-
|
|
290
|
-
day.
|
|
291
|
-
day.
|
|
292
|
-
|
|
308
|
+
day.commitsByRole = narrowToRole(fold.commitsByRole, bases);
|
|
309
|
+
const tierCommits = (tier) => bases.filter((b) => commitTier(b) === tier).reduce((n, b) => n + roleSum(fold.commitsByRole, b), 0);
|
|
310
|
+
day.workCommits = tierCommits("work");
|
|
311
|
+
day.maintenanceCommits = tierCommits("maintenance");
|
|
312
|
+
day.costUsd = roleSum(fold.costByRole, bases);
|
|
313
|
+
const notional = roleSum(fold.notionalByRole, bases);
|
|
293
314
|
if (notional > 0) {
|
|
294
315
|
day.notionalCostUsd = notional;
|
|
295
|
-
day.notionalByRole = narrowToRole(fold.notionalByRole,
|
|
316
|
+
day.notionalByRole = narrowToRole(fold.notionalByRole, bases);
|
|
296
317
|
}
|
|
297
318
|
// Merge runs belong to the merge slot, not this role, so the role-scoped series
|
|
298
319
|
// keeps them unset (matching the merge-share fields) — the render omits the merge
|
|
299
320
|
// line for a scoped report, so these are carried only for shape consistency.
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
day.mergedByRole = mergeDone;
|
|
303
|
-
const mergeDoneFailed = narrowToRole(fold.mergeFailedByRole, base);
|
|
304
|
-
if (Object.keys(mergeDoneFailed).length > 0)
|
|
305
|
-
day.mergeFailedByRole = mergeDoneFailed;
|
|
321
|
+
setMapIfNonempty(day, "mergedByRole", narrowToRole(fold.mergedByRole, bases));
|
|
322
|
+
setMapIfNonempty(day, "mergeFailedByRole", narrowToRole(fold.mergeFailedByRole, bases));
|
|
306
323
|
}
|
|
307
324
|
}
|
|
308
325
|
// The merge share joins its day's tokensOut/costUsd (the budget charges these same
|
|
@@ -312,6 +329,19 @@ export function collectReport(root, days, role) {
|
|
|
312
329
|
d.tokensOut += d.mergeTokens ?? 0;
|
|
313
330
|
d.costUsd += d.mergeCostUsd ?? 0;
|
|
314
331
|
}
|
|
332
|
+
// Main's red wall-clock per day, from G1's rule (main_red_hold / failed ran main_check open a
|
|
333
|
+
// spell, a passing ran main_check closes it, an open spell runs to now). Team-only: main's
|
|
334
|
+
// red time is main's own, not any role's, so a role-scoped series leaves every day unset —
|
|
335
|
+
// exactly as checkFailures is team-only. Only set when a day actually was red (zero-absent,
|
|
336
|
+
// like checkMedianMs).
|
|
337
|
+
if (bases === undefined) {
|
|
338
|
+
const redByDay = mainRedMinutesByDay(foldEntry.redEvents, dayAt(days - 1, now).getTime(), now.getTime());
|
|
339
|
+
for (const d of series) {
|
|
340
|
+
const ms = redByDay.get(d.date);
|
|
341
|
+
if (ms !== undefined)
|
|
342
|
+
d.mainRedMs = ms;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
315
345
|
const countOn = (date, field) => {
|
|
316
346
|
const day = byDate.get(date);
|
|
317
347
|
if (day)
|
|
@@ -366,6 +396,36 @@ export function collectReport(root, days, role) {
|
|
|
366
396
|
}
|
|
367
397
|
}
|
|
368
398
|
}
|
|
399
|
+
// The per-day backlog lag median: how long each finished plan or bug waited from its filing
|
|
400
|
+
// stamp to its done/fixed stamp, folded per completion day — the median backlog age at
|
|
401
|
+
// which the day's items closed. Team-only (a lag has no role, like the validation tally
|
|
402
|
+
// and the filing stamps above) and zero-means-absent: a day with no lag-carrying completion
|
|
403
|
+
// keeps its exact pre-feature shape, and an out-of-window completion date drops out (it
|
|
404
|
+
// must be a byDate key, the same drop countOn applies). The same entry detection and date
|
|
405
|
+
// rules (sectionCompletionLags / entryLags) the completion and filing reads use, so the
|
|
406
|
+
// spans pair the days `featuresDone`/`bugsFixed` count.
|
|
407
|
+
if (role === undefined) {
|
|
408
|
+
const lagsByDay = new Map();
|
|
409
|
+
const foldLag = (date, lagDays) => {
|
|
410
|
+
const list = lagsByDay.get(date);
|
|
411
|
+
if (list)
|
|
412
|
+
list.push(lagDays);
|
|
413
|
+
else
|
|
414
|
+
lagsByDay.set(date, [lagDays]);
|
|
415
|
+
};
|
|
416
|
+
for (const file of finishedFiles("PLANS.md")) {
|
|
417
|
+
for (const { date, lagDays } of sectionCompletionLags(root, file, "Done", DONE_DATE_RE))
|
|
418
|
+
if (byDate.has(date))
|
|
419
|
+
foldLag(date, lagDays);
|
|
420
|
+
}
|
|
421
|
+
for (const file of finishedFiles("BUGS.md")) {
|
|
422
|
+
for (const { date, lagDays } of sectionCompletionLags(root, file, "Fixed", FIXED_DATE_RE))
|
|
423
|
+
if (byDate.has(date))
|
|
424
|
+
foldLag(date, lagDays);
|
|
425
|
+
}
|
|
426
|
+
for (const [date, lags] of lagsByDay)
|
|
427
|
+
byDate.get(date).backlogLagMedianDays = lowerMedian(lags);
|
|
428
|
+
}
|
|
369
429
|
const totals = {
|
|
370
430
|
tokensOut: 0,
|
|
371
431
|
runs: 0,
|
|
@@ -383,6 +443,7 @@ export function collectReport(root, days, role) {
|
|
|
383
443
|
let mergeFailed = 0;
|
|
384
444
|
let plansAdded = 0;
|
|
385
445
|
let bugsFiled = 0;
|
|
446
|
+
const notionalByBackend = {};
|
|
386
447
|
for (const d of series) {
|
|
387
448
|
totals.tokensOut += d.tokensOut;
|
|
388
449
|
for (const n of Object.values(d.runsByRole))
|
|
@@ -394,6 +455,8 @@ export function collectReport(root, days, role) {
|
|
|
394
455
|
totals.maintenanceCommits += d.maintenanceCommits ?? 0;
|
|
395
456
|
totals.costUsd += d.costUsd;
|
|
396
457
|
notionalCostUsd += d.notionalCostUsd ?? 0;
|
|
458
|
+
for (const [backend, c] of Object.entries(d.notionalByBackend ?? {}))
|
|
459
|
+
addTo(notionalByBackend, backend, c);
|
|
397
460
|
totals.featuresDone += d.featuresDone;
|
|
398
461
|
totals.bugsFixed += d.bugsFixed;
|
|
399
462
|
plansAdded += d.plansAdded ?? 0;
|
|
@@ -419,15 +482,16 @@ export function collectReport(root, days, role) {
|
|
|
419
482
|
days,
|
|
420
483
|
from,
|
|
421
484
|
to,
|
|
422
|
-
...(
|
|
485
|
+
...(bases === undefined ? {} : { role: bases.join(",") }),
|
|
423
486
|
series,
|
|
424
487
|
totals: {
|
|
425
488
|
...totals,
|
|
426
489
|
...(notionalCostUsd > 0 ? { notionalCostUsd } : {}),
|
|
490
|
+
...nonemptyObj("notionalByBackend", notionalByBackend),
|
|
427
491
|
...(mergeFailed > 0 ? { mergeFailed } : {}),
|
|
428
492
|
...(plansAdded > 0 ? { plansAdded } : {}),
|
|
429
493
|
...(bugsFiled > 0 ? { bugsFiled } : {}),
|
|
430
|
-
...(
|
|
494
|
+
...nonemptyObj("validationGapsByTag", validationGaps),
|
|
431
495
|
},
|
|
432
496
|
coversFullWindow,
|
|
433
497
|
};
|