@joshuafolkken/kit 1.1784.0 → 1.2116.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/.claude/agents/reviewer-verification.md +19 -0
- package/.claude/agents/reviewer.md +19 -0
- package/.claude/settings.json +5 -6
- package/.claude/skills/dependency-update/SKILL.md +9 -10
- package/.claude/skills/workflow-commands/SKILL.md +6 -6
- package/.claude/skills/workflow-commands/background-commands.md +8 -5
- package/.claude/skills/workflow-commands/backlogrun-child.md +3 -1
- package/.claude/skills/workflow-commands/backlogrun-lanes.md +1 -1
- package/.claude/skills/workflow-commands/backlogrun-park.md +5 -2
- package/.claude/skills/workflow-commands/backlogrun-progress.md +2 -3
- package/.claude/skills/workflow-commands/backlogrun-recovery.md +1 -1
- package/.claude/skills/workflow-commands/backlogrun-steps.md +3 -2
- package/.claude/skills/workflow-commands/backlogrun.md +1 -1
- package/.claude/skills/workflow-commands/chain-rule.md +41 -32
- package/.claude/skills/workflow-commands/delegation.md +6 -6
- package/.claude/skills/workflow-commands/entry-sequence.md +2 -2
- package/.claude/skills/workflow-commands/followup.md +7 -5
- package/.claude/skills/workflow-commands/fullrun-steps.md +6 -6
- package/.claude/skills/workflow-commands/fullrun.md +1 -1
- package/.claude/skills/workflow-commands/issue-comments.md +9 -4
- package/.claude/skills/workflow-commands/issue-fold-existing.md +2 -1
- package/.claude/skills/workflow-commands/kickoff.md +2 -2
- package/.claude/skills/workflow-commands/observation-filing.md +1 -1
- package/.claude/skills/workflow-commands/observation-ledger.md +6 -4
- package/.claude/skills/workflow-commands/pre-gate-cut.md +9 -7
- package/.claude/skills/workflow-commands/prerequisite.md +3 -2
- package/.claude/skills/workflow-commands/retrospective.md +2 -2
- package/.claude/skills/workflow-commands/split-assessment.md +7 -5
- package/.codex/hooks.json +5 -5
- package/.github/actions/setup-pnpm/action.yml +9 -16
- package/.github/dependabot.yml +16 -0
- package/.github/workflows/auto-tag.yml +45 -0
- package/.github/workflows/ci.yml +155 -15
- package/.github/workflows/dependabot-auto-merge.yml +63 -4
- package/.github/workflows/production.yml +8 -0
- package/.github/workflows/publish.yml +60 -45
- package/.vscode/settings.json +19 -0
- package/CLAUDE.md +5 -12
- package/SECURITY.md +2 -2
- package/dist/CLAUDE.md +5 -12
- package/dist/commands/document-read-cli.js +2 -1
- package/dist/commands/document-section-main.js +2 -1
- package/dist/commands/read-set-cli.js +194 -134
- package/dist/commands/run-prep-main.js +9694 -10173
- package/dist/commands/run-step-cli.js +22138 -18285
- package/dist/hooks/audit-provision.js +23 -5
- package/dist/hooks/chunk-3GKE653K.js +6204 -0
- package/dist/hooks/chunk-45CJJOO7.js +1243 -0
- package/dist/hooks/{chunk-CWMBGKYW.js → chunk-5PM2JRGV.js} +2153 -856
- package/dist/hooks/{chunk-WR2KQAYZ.js → chunk-7SIUNQXK.js} +1207 -1470
- package/dist/hooks/{chunk-O2YBIDSI.js → chunk-CQD4LJE6.js} +1682 -1130
- package/dist/hooks/{chunk-VWWCFGWK.js → chunk-OPSRGWFU.js} +1 -1
- package/dist/hooks/{chunk-XGBNSWEI.js → chunk-UJ3FPMMM.js} +132 -49
- package/dist/hooks/chunk-VVNYJWEI.js +30 -0
- package/dist/hooks/chunk-Z6DQJKH3.js +2806 -0
- package/dist/hooks/codex-hook-adapter.js +8 -8
- package/dist/hooks/format-edited.js +4 -5
- package/dist/hooks/inputs.json +386 -360
- package/dist/hooks/pretool-guard.js +7 -6
- package/dist/hooks/session-lang.js +101 -258
- package/dist/hooks/stop-guard.js +1744 -2576
- package/dist/josh.js +7133 -6368
- package/dist/version/index.js +161 -1
- package/eslint/rules/comment-why-only.js +108 -0
- package/package.json +16 -9
- package/prompts/coding-standards.md +1 -1
- package/prompts/collaboration-workflow/file-edits.md +14 -11
- package/prompts/collaboration-workflow/issue-citation.md +0 -4
- package/prompts/collaboration-workflow/issue-template.md +40 -21
- package/prompts/collaboration-workflow/lane-instructions.md +3 -1
- package/prompts/collaboration-workflow/measurement.md +8 -1
- package/prompts/collaboration-workflow/operating-rules.md +11 -2
- package/prompts/collaboration-workflow/output-bounds.md +6 -2
- package/prompts/collaboration-workflow/plan-comment.md +1 -1
- package/prompts/collaboration-workflow/principles.md +9 -0
- package/prompts/collaboration-workflow/residency.md +3 -2
- package/prompts/collaboration-workflow/rule-delivery.md +13 -1
- package/prompts/collaboration-workflow/upstream-interrupt.md +2 -2
- package/prompts/collaboration-workflow/wip-cap.md +3 -1
- package/prompts/review-rubric.md +8 -0
- package/prompts/review.md +31 -22
- package/prompts/testing-guide.md +1 -0
- package/scripts/agent/agent-argv.ts +14 -16
- package/scripts/agent/agent-provider.ts +138 -0
- package/scripts/agent/agent-role-profile.ts +108 -156
- package/scripts/agent/agent-safe-text.ts +20 -5
- package/scripts/agent/api-usage-limit.ts +65 -0
- package/scripts/agent/claude-agent-argv.ts +19 -9
- package/scripts/agent/codex-agent-argv.ts +118 -22
- package/scripts/agent/usage-limit-reset.ts +179 -0
- package/scripts/auth/claude-token-output.ts +2 -2
- package/scripts/auto-ok/auto-ok-author.ts +53 -0
- package/scripts/auto-ok/auto-ok-cli.ts +20 -9
- package/scripts/backlog/backlog-defect-priority.ts +1 -1
- package/scripts/backlog/backlog-drive-cli.ts +6 -1
- package/scripts/backlog/backlog-drive-hold.ts +3 -3
- package/scripts/backlog/backlog-drive-idle.ts +10 -0
- package/scripts/backlog/backlog-drive-launch-pass.ts +90 -0
- package/scripts/backlog/backlog-drive-launch.ts +8 -2
- package/scripts/backlog/backlog-drive-named-offer.ts +73 -30
- package/scripts/backlog/backlog-drive-named.ts +28 -7
- package/scripts/backlog/backlog-drive-paused.ts +5 -4
- package/scripts/backlog/backlog-drive-restore.ts +11 -3
- package/scripts/backlog/backlog-drive.ts +21 -60
- package/scripts/backlog/backlog-gate-scope.ts +61 -0
- package/scripts/backlog/backlog-measure-close.ts +112 -0
- package/scripts/backlog/backlog-next.ts +39 -49
- package/scripts/backlog/backlog-occupied.ts +2 -2
- package/scripts/backlog/backlog-overlap.ts +42 -8
- package/scripts/backlog/backlog-plan-cli.ts +4 -1
- package/scripts/backlog/backlog-plan-comment.ts +81 -0
- package/scripts/backlog/backlog-plan-read.ts +19 -6
- package/scripts/backlog/backlog-pool.ts +50 -12
- package/scripts/backlog/backlog-rank.ts +60 -13
- package/scripts/backlog/backlog-stalled-detect.ts +2 -1
- package/scripts/backlog/backlog-waves.ts +17 -2
- package/scripts/backlog/backlogrun-launch.ts +7 -4
- package/scripts/cost-runtime/context-cut-payback.ts +27 -25
- package/scripts/cost-runtime/cost-cli.ts +37 -16
- package/scripts/cost-runtime/cost-pricing.ts +9 -0
- package/scripts/cost-runtime/cost-verdict.ts +4 -1
- package/scripts/delegation/delegation-policy.ts +2 -2
- package/scripts/delegation/duplicate-read-guard.ts +1 -0
- package/scripts/delegation/investigation-guard.ts +14 -2
- package/scripts/delegation/investigation-reads.ts +45 -23
- package/scripts/dependabot/dependabot-cooldown.ts +3 -2
- package/scripts/discovery/repo-party.ts +80 -20
- package/scripts/discovery/session-owner-pin.ts +51 -0
- package/scripts/document/capped-print.ts +1 -1
- package/scripts/document/command-reference-line-budget.ts +42 -0
- package/scripts/document/document-byte-budget.ts +17 -7
- package/scripts/document/document-checks.ts +20 -0
- package/scripts/document/document-ratchet-check.ts +101 -0
- package/scripts/document/document-section.ts +1 -0
- package/scripts/document/entry-read-budget.ts +7 -3
- package/scripts/document/issue-citation-budget.ts +94 -0
- package/scripts/epic/epic-cli-argv.ts +2 -2
- package/scripts/epic/epic-fetch.ts +4 -2
- package/scripts/epic/epic-graph.ts +7 -2
- package/scripts/epic/epic-issue.ts +3 -1
- package/scripts/epic/epic-rank.ts +5 -0
- package/scripts/exports/unused-members-check.ts +62 -0
- package/scripts/exports/unused-members-cli.ts +6 -51
- package/scripts/followup/followup-ci-path.ts +67 -0
- package/scripts/followup/followup-coderabbit-retrigger.ts +261 -0
- package/scripts/followup/followup-coderabbit-wait.ts +13 -10
- package/scripts/followup/followup-failed-tests.ts +160 -0
- package/scripts/followup/followup-job-needs.ts +100 -0
- package/scripts/followup/followup-job-rerun.ts +303 -0
- package/scripts/followup/followup-main-move.ts +113 -0
- package/scripts/followup/git-followup-finish.ts +43 -11
- package/scripts/followup/git-followup-pending.ts +3 -3
- package/scripts/followup/git-followup-stages.ts +41 -11
- package/scripts/followup/git-pr-followup-checks.ts +55 -16
- package/scripts/followup/git-pr-followup-wrapup.ts +24 -5
- package/scripts/followup/git-pr-followup.ts +62 -27
- package/scripts/fresh-machine/fresh-machine-script.ts +5 -9
- package/scripts/fresh-machine/specs/kit-test-backlogrun-python.json +2 -2
- package/scripts/fresh-machine/specs/kit-test-backlogrun.json +2 -2
- package/scripts/gate/busy-average.ts +34 -2
- package/scripts/gate/check-related-pinned.ts +43 -0
- package/scripts/gate/check-related-reuse.ts +64 -0
- package/scripts/gate/check-related-section.ts +57 -0
- package/scripts/gate/check-related-unplanned.ts +34 -0
- package/scripts/gate/check-related.ts +265 -0
- package/scripts/gate/command-memory.ts +1 -1
- package/scripts/gate/core-admission.ts +24 -6
- package/scripts/gate/core-budget-timing.ts +20 -6
- package/scripts/gate/core-budget.ts +40 -11
- package/scripts/gate/core-wait-record.ts +3 -2
- package/scripts/gate/core-wait.ts +25 -2
- package/scripts/gate/core-weights.ts +15 -7
- package/scripts/gate/gate-labels.ts +46 -0
- package/scripts/gate/gate-ledger.ts +14 -6
- package/scripts/gate/gate-plan.ts +103 -58
- package/scripts/gate/gate-report.ts +9 -7
- package/scripts/gate/gate-run-steps.ts +26 -3
- package/scripts/gate/gate-skip.ts +45 -6
- package/scripts/gate/gate-static-group.ts +60 -0
- package/scripts/gate/gate-steps.ts +2 -1
- package/scripts/gate/gate-tree.ts +4 -2
- package/scripts/gate/hook-gate-reuse.ts +19 -2
- package/scripts/gate/metrics-totals.ts +59 -0
- package/scripts/gate/scoped-green.ts +68 -15
- package/scripts/gate/since-green.ts +14 -6
- package/scripts/gate/structural-checks.ts +96 -0
- package/scripts/gate/verification-gate.ts +51 -16
- package/scripts/gate/verification-inputs.ts +21 -6
- package/scripts/gate/verification-tail.ts +52 -0
- package/scripts/gh/gh-author-association.ts +23 -2
- package/scripts/gh/git-ai-review-scan.ts +1 -1
- package/scripts/gh/git-gh-api-path.ts +12 -3
- package/scripts/gh/git-gh-comments-unreadable.ts +36 -0
- package/scripts/gh/git-gh-exec.ts +32 -2
- package/scripts/gh/git-gh-issue-read.ts +4 -2
- package/scripts/gh/git-gh-issue-rest.ts +1 -0
- package/scripts/gh/git-gh-issue-write.ts +8 -2
- package/scripts/gh/git-gh-issue.ts +12 -5
- package/scripts/gh/git-gh-pr-auto-merge.ts +13 -6
- package/scripts/gh/git-gh-pr-graphql-state.ts +56 -0
- package/scripts/gh/git-gh-pr-read.ts +74 -13
- package/scripts/gh/git-gh-pr-rest.ts +3 -1
- package/scripts/gh/git-gh-pr-snapshot.ts +22 -7
- package/scripts/gh/git-gh-pr-too-large.ts +20 -0
- package/scripts/gh/git-gh-pr.ts +21 -7
- package/scripts/gh/git-gh-retry.ts +141 -0
- package/scripts/gh/git-pr-ai-review.ts +15 -6
- package/scripts/gh/git-pr-checks-eval.ts +3 -0
- package/scripts/gh/git-pr-checks.ts +5 -5
- package/scripts/git/base-tree.ts +30 -0
- package/scripts/git/change-base.ts +4 -10
- package/scripts/git/changed-paths-sync.ts +63 -0
- package/scripts/git/changed-paths.ts +16 -1
- package/scripts/git/git-common-directory.ts +11 -1
- package/scripts/git/git-diff-reads.ts +66 -20
- package/scripts/git/git-error.ts +9 -2
- package/scripts/git/git-schemas.ts +13 -0
- package/scripts/git/git-worktree.ts +13 -0
- package/scripts/git/gone-branch.ts +4 -1
- package/scripts/git/main-merge-budget-conflict.ts +89 -0
- package/scripts/git/main-merge-guard.ts +55 -18
- package/scripts/git/main-merge-regenerate.ts +59 -25
- package/scripts/git/main-merge.ts +53 -5
- package/scripts/git/no-base-checkout.ts +127 -0
- package/scripts/git/stash/git-stash.ts +11 -2
- package/scripts/git/stash/stash-push-cli.ts +10 -0
- package/scripts/hooks/batch-guard.ts +40 -21
- package/scripts/hooks/edited-cspell.ts +37 -11
- package/scripts/hooks/format-edited-file.ts +22 -2
- package/scripts/hooks/lane-plan-guard.ts +50 -0
- package/scripts/hooks/pre-commit-lint-switch.ts +9 -0
- package/scripts/hooks/pre-commit-lint.ts +14 -1
- package/scripts/hooks/pre-push-related-switch.ts +10 -0
- package/scripts/hooks/pre-push-unit.ts +76 -10
- package/scripts/hooks/pretool-guard.ts +2 -0
- package/scripts/hooks/reserved-run.ts +14 -1
- package/scripts/hooks/run-hook.sh +23 -8
- package/scripts/hooks/step-zero-notice.ts +6 -1
- package/scripts/hooks/stop-actions.ts +3 -15
- package/scripts/hooks/stop-guard.ts +7 -6
- package/scripts/init/distributed-paths.ts +1 -0
- package/scripts/init/hook-command-rewrite.ts +5 -1
- package/scripts/init/hook-launch.ts +4 -2
- package/scripts/issue/aggregation-split.ts +52 -0
- package/scripts/issue/defect-origin-line.ts +19 -1
- package/scripts/issue/defect-rate-cli.ts +5 -102
- package/scripts/issue/defect-report.ts +4 -4
- package/scripts/issue/effect-audit-cli.ts +178 -0
- package/scripts/issue/effect-audit.ts +185 -0
- package/scripts/issue/expected-effect-lint.ts +64 -9
- package/scripts/issue/git-next-issues.ts +5 -0
- package/scripts/issue/issue-body-or-comment.ts +38 -4
- package/scripts/issue/issue-cite-cli.ts +1 -3
- package/scripts/issue/issue-classification.ts +1 -0
- package/scripts/issue/issue-closing-pr.ts +8 -1
- package/scripts/issue/issue-evidence-exit.ts +4 -2
- package/scripts/issue/issue-file-cap.ts +58 -0
- package/scripts/issue/issue-file-cli.ts +111 -38
- package/scripts/issue/issue-file-deferral.ts +52 -0
- package/scripts/issue/issue-file-fold.ts +29 -10
- package/scripts/issue/issue-file-interrupt.ts +85 -0
- package/scripts/issue/issue-file-lane-hint.ts +30 -0
- package/scripts/issue/issue-file.ts +43 -6
- package/scripts/issue/issue-labels.ts +19 -2
- package/scripts/issue/issue-lint-cli.ts +27 -2
- package/scripts/issue/issue-measured-cli.ts +13 -35
- package/scripts/issue/issue-measured-close.ts +58 -0
- package/scripts/issue/issue-not-before-label.ts +2 -2
- package/scripts/issue/issue-not-before.ts +4 -1
- package/scripts/issue/issue-priority-cli.ts +60 -0
- package/scripts/issue/issue-priority-raise.ts +55 -0
- package/scripts/issue/issue-priority.ts +174 -43
- package/scripts/issue/issue-rank.ts +21 -4
- package/scripts/issue/issue-read-cli.ts +32 -6
- package/scripts/issue/issue-read.ts +37 -12
- package/scripts/issue/issue-sample-gate.ts +95 -74
- package/scripts/issue/issue-sample-prime.ts +127 -0
- package/scripts/issue/issue-sample-required.ts +57 -0
- package/scripts/issue/issue-sample-source.ts +12 -11
- package/scripts/issue/issue-search.ts +124 -0
- package/scripts/issue/issue-state.ts +13 -1
- package/scripts/issue/issue-template-section.ts +43 -0
- package/scripts/issue/issue-watch-diff.ts +31 -1
- package/scripts/issue/issue-watch-hook.ts +11 -2
- package/scripts/issue/issue-watch.ts +55 -12
- package/scripts/issue/markdown-section.ts +1 -0
- package/scripts/issue/measure-declaration.ts +121 -0
- package/scripts/issue/measure-rerun-cli.ts +7 -70
- package/scripts/issue/plan-consumers-section.ts +22 -1
- package/scripts/issue/reproduction-measure.ts +3 -1
- package/scripts/issue/size-estimate.ts +90 -0
- package/scripts/issue/trusted-measure.ts +84 -0
- package/scripts/josh/command-usage.ts +3 -2
- package/scripts/josh/durable-state-migrate.ts +105 -0
- package/scripts/josh/durable-state.ts +112 -0
- package/scripts/josh/josh-aliases.ts +95 -0
- package/scripts/josh/josh-command-map.ts +1 -82
- package/scripts/josh/josh-commands-agent-hooks.ts +6 -6
- package/scripts/josh/josh-commands-ai.ts +5 -5
- package/scripts/josh/josh-commands-development.ts +59 -58
- package/scripts/josh/josh-commands-issue-write.ts +23 -4
- package/scripts/josh/josh-commands-issue.ts +32 -0
- package/scripts/josh/josh-commands-lane.ts +87 -4
- package/scripts/josh/josh-commands-lint.ts +16 -3
- package/scripts/josh/josh-commands-maintenance.ts +15 -0
- package/scripts/josh/josh-commands-review.ts +41 -6
- package/scripts/josh/josh-commands-ship.ts +56 -8
- package/scripts/josh/josh-commands-test-check.ts +80 -0
- package/scripts/josh/josh-commands-workflow.ts +1 -1
- package/scripts/josh/josh-environment-file.ts +43 -3
- package/scripts/josh/josh-in-process.ts +2 -2
- package/scripts/josh/josh-logic.ts +5 -3
- package/scripts/josh/josh-run.ts +19 -1
- package/scripts/josh/run-record-path.ts +15 -0
- package/scripts/josh/stamp-file.ts +11 -2
- package/scripts/lane/lane-adopt-cli.ts +98 -0
- package/scripts/lane/lane-adopt.ts +208 -0
- package/scripts/lane/lane-await.ts +5 -8
- package/scripts/lane/lane-baseline.ts +123 -0
- package/scripts/lane/lane-breakdown-cli.ts +64 -0
- package/scripts/lane/lane-breakdown-implement.ts +170 -0
- package/scripts/lane/lane-breakdown-laps.ts +107 -0
- package/scripts/lane/lane-breakdown-pinned.ts +76 -0
- package/scripts/lane/lane-breakdown-text.ts +145 -0
- package/scripts/lane/lane-breakdown.ts +239 -0
- package/scripts/lane/lane-check-stats.ts +29 -8
- package/scripts/lane/lane-child-invocation.ts +9 -2
- package/scripts/lane/lane-child-mark-keys.ts +12 -0
- package/scripts/lane/lane-child-marker.ts +20 -1
- package/scripts/lane/lane-ci-path-stats.ts +73 -0
- package/scripts/lane/lane-claim-stats.ts +84 -0
- package/scripts/lane/lane-close.ts +8 -3
- package/scripts/lane/lane-dispatch-log.ts +3 -3
- package/scripts/lane/lane-dispatch.ts +2 -2
- package/scripts/lane/lane-gap-stats.ts +7 -6
- package/scripts/lane/lane-guard-policy.ts +7 -1
- package/scripts/lane/lane-implement-stats.ts +207 -0
- package/scripts/lane/lane-implement-subagents.ts +90 -0
- package/scripts/lane/lane-investigation-switch.ts +16 -0
- package/scripts/lane/lane-ledger-kind.ts +31 -0
- package/scripts/lane/lane-ledger-schema-ship.ts +49 -0
- package/scripts/lane/lane-ledger-schema.ts +119 -36
- package/scripts/lane/lane-ledger-write.ts +257 -0
- package/scripts/lane/lane-ledger.ts +31 -177
- package/scripts/lane/lane-load.ts +1 -1
- package/scripts/lane/lane-measure-cli.ts +176 -59
- package/scripts/lane/lane-net-read.ts +44 -0
- package/scripts/lane/lane-net-time.ts +212 -0
- package/scripts/lane/lane-open.ts +16 -7
- package/scripts/lane/lane-output.ts +2 -4
- package/scripts/lane/lane-overrun-prompt.ts +147 -0
- package/scripts/lane/lane-overrun.ts +274 -0
- package/scripts/lane/lane-paths.ts +24 -1
- package/scripts/lane/lane-pause-cli.ts +4 -1
- package/scripts/lane/lane-paused-spans.ts +97 -0
- package/scripts/lane/lane-plan-check.ts +207 -0
- package/scripts/lane/lane-plan-cli.ts +41 -0
- package/scripts/lane/lane-plan.ts +144 -0
- package/scripts/lane/lane-registry.ts +14 -1
- package/scripts/lane/lane-relaunch.ts +1 -1
- package/scripts/lane/lane-round-one-stats.ts +51 -0
- package/scripts/lane/lane-sampler.ts +23 -4
- package/scripts/lane/lane-session-action.ts +93 -18
- package/scripts/lane/lane-session-broker.ts +49 -21
- package/scripts/lane/lane-session-reread-main.ts +14 -0
- package/scripts/lane/lane-session-reread.ts +51 -0
- package/scripts/lane/lane-ship-lap-stats.ts +74 -0
- package/scripts/lane/lane-sleep.ts +58 -0
- package/scripts/lane/lane-spent.ts +1 -1
- package/scripts/lane/lane-split-stats.ts +28 -0
- package/scripts/lane/lane-stage-stats.ts +13 -1
- package/scripts/lane/lane-state.ts +41 -9
- package/scripts/lane/lane-stats-tables.ts +58 -0
- package/scripts/lane/lane-stats.ts +21 -5
- package/scripts/lane/lane-stop-stats.ts +51 -19
- package/scripts/lane/lane-tail-stats.ts +32 -0
- package/scripts/lane/lane-transcript-calls.ts +67 -10
- package/scripts/lane/lane-transcript-stats.ts +44 -12
- package/scripts/lane/lane-value-cell.ts +72 -0
- package/scripts/lane/lane-value.ts +118 -0
- package/scripts/lane/lane-withdraw-closed.ts +124 -0
- package/scripts/lane/lane-withdraw.ts +108 -31
- package/scripts/lane/lane-yield.ts +85 -0
- package/scripts/lane/openai-lane-ship.ts +12 -11
- package/scripts/lane/openai-lane-supervisor-decision.ts +6 -8
- package/scripts/lane/openai-lane-supervisor-owner.ts +5 -8
- package/scripts/lane/openai-lane-supervisor.ts +5 -4
- package/scripts/lib/poll.ts +38 -9
- package/scripts/lib/settled-together.ts +10 -0
- package/scripts/lib/shell-quote.ts +21 -0
- package/scripts/lib/token-shape.ts +111 -0
- package/scripts/lint/eslint-daemon-sources.ts +79 -0
- package/scripts/lint/eslint-daemon.ts +45 -6
- package/scripts/lint/eslint-warm-cli.ts +7 -0
- package/scripts/lint/eslint-warm.ts +66 -0
- package/scripts/lint/import-graph.ts +141 -11
- package/scripts/lint/lint-gate-scope.ts +2 -2
- package/scripts/lint/lint-parallel.ts +54 -6
- package/scripts/lint/lint-related.ts +154 -33
- package/scripts/lint/rename-cli.ts +179 -0
- package/scripts/lint/rename-identifier.ts +192 -0
- package/scripts/lint/type-only-imports.ts +58 -0
- package/scripts/notify/telegram-notify.ts +12 -3
- package/scripts/observations/observation-record.ts +42 -16
- package/scripts/observations/observations-flush.ts +32 -9
- package/scripts/overrides/overrides-check.ts +9 -1
- package/scripts/release/release-approval-prune.ts +7 -1
- package/scripts/repo/required-checks-logic.ts +4 -1
- package/scripts/repo/ruleset-check.ts +4 -3
- package/scripts/report/markdown-shape.ts +28 -0
- package/scripts/report/report-format-reference.ts +15 -1
- package/scripts/report/report-labels.ts +12 -1
- package/scripts/report/report-lint-child-summary.ts +94 -0
- package/scripts/report/report-lint-cli.ts +26 -7
- package/scripts/report/report-lint.ts +2 -20
- package/scripts/review/prose-stale-cli.ts +88 -0
- package/scripts/review/prose-stale-scan.ts +152 -0
- package/scripts/review/review-attest.ts +73 -23
- package/scripts/review/review-brief-cli.ts +68 -19
- package/scripts/review/review-brief-paths.ts +22 -0
- package/scripts/review/review-brief.ts +14 -7
- package/scripts/review/review-comment-carry.ts +47 -0
- package/scripts/review/review-comment-round.ts +85 -22
- package/scripts/review/review-finding-ledger.ts +109 -7
- package/scripts/review/review-finding-text.ts +43 -0
- package/scripts/review/review-interaction.ts +11 -0
- package/scripts/review/review-lane-handover.ts +68 -0
- package/scripts/review/review-lint-cli.ts +57 -0
- package/scripts/review/review-lint-findings.ts +92 -0
- package/scripts/review/review-lint-sections.ts +80 -0
- package/scripts/review/review-lint.ts +221 -0
- package/scripts/review/review-prior-findings.ts +102 -0
- package/scripts/review/review-readers-scan.ts +4 -2
- package/scripts/review/review-record-cli.ts +177 -54
- package/scripts/review/review-record-code-round.ts +55 -0
- package/scripts/review/review-record-comment.ts +60 -0
- package/scripts/review/review-record-interaction.ts +35 -0
- package/scripts/review/review-record-pinned.ts +108 -0
- package/scripts/review/review-record.ts +25 -1
- package/scripts/review/review-reviewed-tree.ts +307 -0
- package/scripts/review/review-round-one-closure.ts +62 -0
- package/scripts/review/review-round-reuse.ts +106 -0
- package/scripts/review/review-round2-cli.ts +91 -29
- package/scripts/review/review-round2-skip-comment.ts +55 -0
- package/scripts/review/review-round2.ts +24 -8
- package/scripts/review/review-stamps.ts +7 -3
- package/scripts/review/review-stop-log.ts +20 -6
- package/scripts/review/review-stops-cli.ts +2 -1
- package/scripts/review/review-submit-cli.ts +101 -0
- package/scripts/rules/agent-model.ts +1 -1
- package/scripts/rules/bash-triggers.ts +3 -3
- package/scripts/rules/concise-reply.ts +88 -0
- package/scripts/rules/credential-body.ts +77 -0
- package/scripts/rules/decision-oracle.ts +1 -1
- package/scripts/rules/delivered-rules.ts +36 -17
- package/scripts/rules/destructive-command.ts +3 -11
- package/scripts/rules/direct-issue-comment.ts +34 -12
- package/scripts/rules/direct-issue-read.ts +191 -0
- package/scripts/rules/direct-pr-create.ts +4 -24
- package/scripts/rules/early-heartbeat.ts +2 -0
- package/scripts/rules/edit-tool.ts +27 -0
- package/scripts/rules/file-edit-rows.ts +17 -0
- package/scripts/rules/file-rewrite.ts +146 -0
- package/scripts/rules/firing-point.ts +3 -2
- package/scripts/rules/gh-api.ts +128 -7
- package/scripts/rules/gh-repo-selector.ts +84 -0
- package/scripts/rules/git-force.ts +2 -2
- package/scripts/rules/guard-remedy.ts +14 -5
- package/scripts/rules/implementation-cut.ts +61 -28
- package/scripts/rules/investigator-foreground.ts +231 -0
- package/scripts/rules/issue-citation.ts +15 -60
- package/scripts/rules/issue-comments.ts +9 -4
- package/scripts/rules/josh-git-bare.ts +1 -1
- package/scripts/rules/lane-background.ts +41 -13
- package/scripts/rules/lane-direct-tool.ts +107 -9
- package/scripts/rules/lane-interactive-ask.ts +4 -1
- package/scripts/rules/lane-park.ts +4 -2
- package/scripts/rules/lane-spilled-read.ts +90 -0
- package/scripts/rules/lane-split-park.ts +1 -1
- package/scripts/rules/lane-switch-main.ts +4 -4
- package/scripts/rules/last-prompt.ts +20 -47
- package/scripts/rules/oracle-consulted.ts +1 -1
- package/scripts/rules/permission-guards.ts +5 -1
- package/scripts/rules/piped-verification-shapes.ts +110 -0
- package/scripts/rules/piped-verification.ts +67 -17
- package/scripts/rules/poll-loop.ts +72 -9
- package/scripts/rules/pr-merge.ts +5 -5
- package/scripts/rules/pre-gate-cut.ts +3 -3
- package/scripts/rules/protected-files.ts +88 -24
- package/scripts/rules/reply-language.ts +3 -17
- package/scripts/rules/reply-prose.ts +34 -0
- package/scripts/rules/repo-admin.ts +132 -0
- package/scripts/rules/reviewer-foreground.ts +88 -0
- package/scripts/rules/round-one-check-related.ts +120 -0
- package/scripts/rules/rule-body-guard.ts +5 -15
- package/scripts/rules/rule-value-cache.ts +53 -5
- package/scripts/rules/rule-value-candidates.ts +84 -0
- package/scripts/rules/rule-value-cli.ts +59 -11
- package/scripts/rules/rule-value.ts +17 -4
- package/scripts/rules/run-tail-rule.ts +1 -1
- package/scripts/rules/sed-in-place.ts +196 -0
- package/scripts/rules/shell-segments.ts +10 -2
- package/scripts/rules/stop-rule-rows.ts +1 -13
- package/scripts/rules/stop-rules.ts +33 -58
- package/scripts/rules/test-declared-commit.ts +1 -1
- package/scripts/rules/third-party-write.ts +110 -23
- package/scripts/rules/timed-rerun.ts +1 -1
- package/scripts/rules/turn-filings.ts +90 -0
- package/scripts/rules/worktree-guard.ts +22 -7
- package/scripts/run/board/run-board-ending-reason.ts +6 -2
- package/scripts/run/board/run-board-fit.ts +24 -1
- package/scripts/run/board/run-board-found.ts +134 -0
- package/scripts/run/board/run-board-header.ts +8 -0
- package/scripts/run/board/run-board-labels.ts +11 -1
- package/scripts/run/board/run-board-lane-time.ts +1 -0
- package/scripts/run/board/run-board-link.ts +15 -2
- package/scripts/run/board/run-board-notes.ts +7 -1
- package/scripts/run/board/run-board-operation.ts +4 -2
- package/scripts/run/board/run-board-phase.ts +2 -5
- package/scripts/run/board/run-board-plan.ts +1 -1
- package/scripts/run/board/run-board-read.ts +46 -1
- package/scripts/run/board/run-board-reason.ts +20 -8
- package/scripts/run/board/run-board-render-checks.ts +3 -2
- package/scripts/run/board/run-board-render-drawn.ts +11 -0
- package/scripts/run/board/run-board-render-found.ts +157 -0
- package/scripts/run/board/run-board-render-lead.ts +9 -0
- package/scripts/run/board/run-board-render-legend.ts +19 -0
- package/scripts/run/board/run-board-render-tail.ts +1 -1
- package/scripts/run/board/run-board-render.ts +82 -18
- package/scripts/run/board/run-board-spin.ts +1 -3
- package/scripts/run/board/run-board-status.ts +2 -0
- package/scripts/run/board/run-board-tick.ts +39 -10
- package/scripts/run/carry/run-carry-ended.ts +3 -2
- package/scripts/run/carry/run-carry.ts +3 -2
- package/scripts/run/cut/run-cut-cli.ts +33 -133
- package/scripts/run/cut/run-cut-digest.ts +152 -0
- package/scripts/run/cut/run-cut-handoff.ts +52 -8
- package/scripts/run/cut/run-cut-report.ts +24 -3
- package/scripts/run/cut/run-cut-resume.ts +129 -0
- package/scripts/run/cut/run-cut-review.ts +105 -0
- package/scripts/run/cut/run-cut.ts +18 -7
- package/scripts/run/detached-launch.ts +1 -1
- package/scripts/run/entry/run-entry-cli.ts +88 -19
- package/scripts/run/entry/run-entry-spill.ts +83 -0
- package/scripts/run/entry/run-entry-stop.ts +5 -1
- package/scripts/run/entry/run-entry-trust.ts +91 -0
- package/scripts/run/event/run-event-baseline.ts +56 -0
- package/scripts/run/event/run-event-filed.ts +9 -3
- package/scripts/run/event/run-event-overrun.ts +197 -0
- package/scripts/run/event/run-event-render.ts +4 -0
- package/scripts/run/event/run-event-stream.ts +25 -3
- package/scripts/run/hold/run-stop-notify.ts +3 -8
- package/scripts/run/merge/run-merge-cap.ts +57 -0
- package/scripts/run/merge/run-merge-cli.ts +66 -23
- package/scripts/run/merge/run-merge-outcome.ts +2 -0
- package/scripts/run/merge/run-merge-ship.ts +13 -3
- package/scripts/run/merge/run-merge-signals.ts +40 -23
- package/scripts/run/merge/run-merge-steps.ts +56 -36
- package/scripts/run/merge/run-merge-usage-limit.ts +53 -0
- package/scripts/run/merge/run-merge-withdrawn.ts +53 -0
- package/scripts/run/merge/run-merge.ts +41 -14
- package/scripts/run/review/run-review-cli.ts +306 -20
- package/scripts/run/review/run-review-early-push.ts +121 -0
- package/scripts/run/review/run-review-join-read.ts +94 -0
- package/scripts/run/review/run-review-pinned-accepted.ts +126 -0
- package/scripts/run/review/run-review-pinned-join.ts +216 -0
- package/scripts/run/review/run-review-pinned-steps.ts +383 -0
- package/scripts/run/review/run-review-pinned-tree.ts +37 -0
- package/scripts/run/review/run-review-pinned.ts +53 -0
- package/scripts/run/review/run-review-steps.ts +70 -34
- package/scripts/run/review/run-review.ts +26 -6
- package/scripts/run/run-parent-cut-hook.ts +3 -4
- package/scripts/run/run-prep.ts +1 -0
- package/scripts/run/run-stage-read.ts +2 -6
- package/scripts/run/run-step-cli.ts +17 -5
- package/scripts/run/run-step-lane-plan.ts +27 -0
- package/scripts/run/run-step-section.ts +26 -7
- package/scripts/run/run-step.ts +5 -2
- package/scripts/run/ship/run-ship-args.ts +19 -0
- package/scripts/run/ship/run-ship-brokered-review.ts +106 -0
- package/scripts/run/ship/run-ship-cli.ts +131 -39
- package/scripts/run/ship/run-ship-conflict-probe.ts +59 -0
- package/scripts/run/ship/run-ship-detach.ts +10 -4
- package/scripts/run/ship/run-ship-handover.ts +106 -0
- package/scripts/run/ship/run-ship-infra-retry.ts +16 -1
- package/scripts/run/ship/run-ship-lap.ts +63 -0
- package/scripts/run/ship/run-ship-next.ts +27 -26
- package/scripts/run/ship/run-ship-overlap.ts +8 -3
- package/scripts/run/ship/run-ship-place.ts +9 -2
- package/scripts/run/ship/run-ship-planned.ts +92 -0
- package/scripts/run/ship/run-ship-pre-detach-pinned.ts +197 -0
- package/scripts/run/ship/run-ship-pre-detach-timed.ts +7 -8
- package/scripts/run/ship/run-ship-pre-detach.ts +77 -23
- package/scripts/run/ship/run-ship-preflight.ts +16 -4
- package/scripts/run/ship/run-ship-probe.ts +23 -9
- package/scripts/run/ship/run-ship-relaunch-cap.ts +43 -7
- package/scripts/run/ship/run-ship-relaunch.ts +51 -0
- package/scripts/run/ship/run-ship-return.ts +103 -29
- package/scripts/run/ship/run-ship-review-reason.ts +24 -0
- package/scripts/run/ship/run-ship-review-steps.ts +230 -59
- package/scripts/run/ship/run-ship-review.ts +171 -51
- package/scripts/run/ship/run-ship-reviewer.ts +138 -42
- package/scripts/run/ship/run-ship-scoped.ts +39 -10
- package/scripts/run/ship/run-ship-stage.ts +49 -13
- package/scripts/run/ship/run-ship-steps.ts +24 -4
- package/scripts/run/ship/run-ship-stop-cause.ts +43 -2
- package/scripts/run/ship/run-ship-stop-context.ts +50 -13
- package/scripts/run/ship/run-ship-sync.ts +171 -30
- package/scripts/run/ship/run-ship-synced-scope.ts +178 -0
- package/scripts/run/ship/run-ship-wait-cli.ts +145 -0
- package/scripts/run/ship/run-ship-waiter.ts +114 -0
- package/scripts/run/ship/run-ship.ts +16 -2
- package/scripts/run/wake/run-wake-caffeinate.ts +48 -0
- package/scripts/run/wake/run-wake-cli.ts +6 -113
- package/scripts/run/wake/run-wake-code.ts +53 -11
- package/scripts/run/wake/run-wake-driver.ts +5 -3
- package/scripts/run/wake/run-wake-finish.ts +137 -0
- package/scripts/run/wake/run-wake-loop.ts +5 -3
- package/scripts/run/wake/run-wake-ports.ts +11 -3
- package/scripts/run/wake/run-wake-session.ts +2 -0
- package/scripts/run/wake/run-wake.ts +3 -2
- package/scripts/safe-chain/ci-installer-pin.ts +49 -8
- package/scripts/safe-chain/project-config.ts +3 -2
- package/scripts/security/secretlint-scan.ts +42 -9
- package/scripts/security/security-audit-provision-main.ts +9 -1
- package/scripts/security/security-audit-provision.ts +1 -1
- package/scripts/security/security-audit.ts +21 -1
- package/scripts/security/sonar-file.ts +10 -5
- package/scripts/split/split-assess.ts +12 -3
- package/scripts/split/split-early-notice.ts +116 -0
- package/scripts/split/split-measure.ts +20 -2
- package/scripts/split/split-resolution.ts +107 -0
- package/scripts/test/direct-importers.ts +185 -0
- package/scripts/test/pure-files-entries.ts +83 -0
- package/scripts/test/related-heavy-tests.ts +81 -0
- package/scripts/test/test-no-base.ts +88 -0
- package/scripts/test/test-pinned-cache-logic.ts +363 -0
- package/scripts/test/test-pinned-cache.ts +337 -0
- package/scripts/test/test-pinned-emit.ts +49 -0
- package/scripts/test/test-pinned-functions.ts +116 -0
- package/scripts/test/test-pinned-ledger.ts +80 -0
- package/scripts/test/test-pinned-logic.ts +208 -20
- package/scripts/test/test-pinned-main.ts +84 -18
- package/scripts/test/test-pinned-pool.ts +73 -0
- package/scripts/test/test-pinned-probe.ts +254 -0
- package/scripts/test/test-pinned-prune-logic.ts +118 -0
- package/scripts/test/test-pinned-reach.ts +194 -0
- package/scripts/test/test-pinned-record.ts +196 -0
- package/scripts/test/test-pinned-rewire.ts +148 -0
- package/scripts/test/test-pinned-spawn.ts +81 -0
- package/scripts/test/test-pinned-stage.ts +70 -0
- package/scripts/test/test-pinned.ts +258 -47
- package/scripts/test/test-reach-cli.ts +61 -0
- package/scripts/test/test-read-map.ts +35 -11
- package/scripts/test/test-read-recording.ts +17 -5
- package/scripts/test/test-read-trace.ts +26 -8
- package/scripts/test/test-red-logic.ts +46 -7
- package/scripts/test/test-red.ts +34 -14
- package/scripts/test/test-related-claim.ts +37 -0
- package/scripts/test/test-related-main.ts +4 -1
- package/scripts/test/test-related-moved.ts +91 -0
- package/scripts/test/test-related-record.ts +43 -23
- package/scripts/test/test-related-scope.ts +99 -34
- package/scripts/test/test-related-synced.ts +135 -0
- package/scripts/test/test-related-touched.ts +84 -0
- package/scripts/test/test-related.ts +167 -83
- package/scripts/test/test-unit-guard.ts +28 -5
- package/scripts/test/unit-durations.ts +41 -0
- package/scripts/test/unit-worker-share.ts +5 -4
- package/scripts/test/vitest-cache-directory.ts +19 -0
- package/scripts/test/vitest-cli-excludes.ts +14 -0
- package/scripts/test/vitest-failure-summary.ts +111 -0
- package/scripts/test/whole-suite-files.ts +12 -1
- package/scripts/time-runtime/time-batch-guard.ts +42 -4
- package/scripts/time-runtime/time-bundle-call.ts +1 -1
- package/scripts/time-runtime/time-bundles.ts +36 -5
- package/scripts/time-runtime/time-markers.ts +2 -2
- package/scripts/time-runtime/time-search-call.ts +38 -0
- package/scripts/time-runtime/time-shell.ts +1 -1
- package/scripts/time-runtime/time-transcript-line.ts +17 -5
- package/scripts/version/development-engines-verdict.ts +124 -0
- package/scripts/version/latest-corepack.ts +2 -0
- package/templates/gitignore +2 -0
- package/templates/workflows/ci.yml +41 -0
- package/dist/hooks/chunk-AZX4FGQ3.js +0 -207
- package/dist/hooks/chunk-PT5R6UJD.js +0 -7131
- package/dist/hooks/chunk-TUIFS5E7.js +0 -72
- package/dist/hooks/chunk-YCDOIR3I.js +0 -3456
- package/scripts/cost-runtime/context-cut-threshold.ts +0 -11
- package/scripts/rules/filing-cap.ts +0 -139
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { lane_breakdown, type Breakdown, type Segment, type Stage } from './lane-breakdown'
|
|
2
|
+
import { lane_breakdown_implement } from './lane-breakdown-implement'
|
|
3
|
+
import { lane_ledger, type LedgerEntry } from './lane-ledger'
|
|
4
|
+
import type { ToolCall } from './lane-transcript-calls'
|
|
5
|
+
|
|
6
|
+
// What each ship stage of a lane's breakdown spent its time on (joshuafolkken/kit#5294): the laps the
|
|
7
|
+
// ship wrote for its inner steps (`run-ship-lap.ts`), the lane's core-budget waits and the checks of
|
|
8
|
+
// the lane's gates, each under the stage it ended in, and the time between two ship stages split by
|
|
9
|
+
// the Bash the lane child ran there, by the implementation's kinds (`lane-breakdown-implement.ts`).
|
|
10
|
+
// A lap and a wait or a check inside it overlap — the gate's wait for cores and its checks, run side
|
|
11
|
+
// by side, are part of its `josh gate` lap — so a stage's laps can add up to more.
|
|
12
|
+
|
|
13
|
+
const { KIND } = lane_ledger
|
|
14
|
+
const CORE_WAIT_STEP = 'core-budget wait'
|
|
15
|
+
|
|
16
|
+
// Each stage's laps, longest first, keyed by the stage's name in the breakdown.
|
|
17
|
+
type Laps = ReadonlyMap<string, ReadonlyArray<Stage>>
|
|
18
|
+
|
|
19
|
+
interface Placed {
|
|
20
|
+
at_ms: number
|
|
21
|
+
part: Stage
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function lap_of(entry: LedgerEntry, issue: number): ReadonlyArray<Placed> {
|
|
25
|
+
if (entry.kind !== KIND.SHIP_LAP || entry.issue !== issue) return []
|
|
26
|
+
|
|
27
|
+
return [{ at_ms: Date.parse(entry.at), part: { name: entry.step, ms: entry.elapsed_ms } }]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function wait_of(entry: LedgerEntry, issue: number): ReadonlyArray<Placed> {
|
|
31
|
+
if (entry.kind !== KIND.CORE_WAIT || entry.issue !== issue) return []
|
|
32
|
+
|
|
33
|
+
return [{ at_ms: Date.parse(entry.at), part: { name: CORE_WAIT_STEP, ms: entry.waited_ms } }]
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Each check the lane's gate ran, placed where the gate ended (joshuafolkken/kit#5319). A row with no
|
|
37
|
+
// `issue` — outside a lane, or written before the gate recorded it — is no lane's; a reused check
|
|
38
|
+
// started nothing, so its zero is no time spent.
|
|
39
|
+
function checks_of(entry: LedgerEntry, issue: number): ReadonlyArray<Placed> {
|
|
40
|
+
if (entry.kind !== KIND.GATE || entry.issue !== issue) return []
|
|
41
|
+
const at_ms = Date.parse(entry.at)
|
|
42
|
+
|
|
43
|
+
return (entry.checks ?? [])
|
|
44
|
+
.filter((check) => check.is_reused !== true)
|
|
45
|
+
.map((check) => ({ at_ms, part: { name: check.label, ms: check.elapsed_ms } }))
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// The ship stage a lap, a wait or a check ended in — never the time between stages, which the ship runs nothing in.
|
|
49
|
+
function stage_at(segments: ReadonlyArray<Segment>, at_ms: number): string | undefined {
|
|
50
|
+
const segment = segments.find((span) => at_ms > span.from_ms && at_ms <= span.to_ms)
|
|
51
|
+
|
|
52
|
+
return segment?.stage === lane_breakdown.BETWEEN_STAGE ? undefined : segment?.stage
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function grouped(
|
|
56
|
+
placed: ReadonlyArray<Placed>,
|
|
57
|
+
segments: ReadonlyArray<Segment>,
|
|
58
|
+
): Map<string, Array<Stage>> {
|
|
59
|
+
const groups = new Map<string, Array<Stage>>()
|
|
60
|
+
|
|
61
|
+
for (const { at_ms, part } of placed) {
|
|
62
|
+
const stage = stage_at(segments, at_ms)
|
|
63
|
+
|
|
64
|
+
if (stage !== undefined) groups.set(stage, [...(groups.get(stage) ?? []), part])
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return groups
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function between_of(
|
|
71
|
+
calls: ReadonlyArray<ToolCall>,
|
|
72
|
+
segments: ReadonlyArray<Segment>,
|
|
73
|
+
): Array<Stage> {
|
|
74
|
+
const between = segments.filter((segment) => segment.stage === lane_breakdown.BETWEEN_STAGE)
|
|
75
|
+
|
|
76
|
+
return lane_breakdown_implement.bash_kinds(calls, between)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** `issue`'s ship stages split by their laps, and the time between them by the lane child's Bash. */
|
|
80
|
+
function of(
|
|
81
|
+
entries: ReadonlyArray<LedgerEntry>,
|
|
82
|
+
issue: number,
|
|
83
|
+
breakdown: Breakdown,
|
|
84
|
+
calls: ReadonlyArray<ToolCall>,
|
|
85
|
+
): Laps {
|
|
86
|
+
const placed = entries.flatMap((entry) => [
|
|
87
|
+
...lap_of(entry, issue),
|
|
88
|
+
...wait_of(entry, issue),
|
|
89
|
+
...checks_of(entry, issue),
|
|
90
|
+
])
|
|
91
|
+
const laps = new Map(
|
|
92
|
+
[...grouped(placed, breakdown.ship)].map(([stage, parts]) => [
|
|
93
|
+
stage,
|
|
94
|
+
lane_breakdown.ranked(parts),
|
|
95
|
+
]),
|
|
96
|
+
)
|
|
97
|
+
const between = between_of(calls, breakdown.ship)
|
|
98
|
+
|
|
99
|
+
if (between.length > 0) laps.set(lane_breakdown.BETWEEN_STAGE, between)
|
|
100
|
+
|
|
101
|
+
return laps
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const lane_breakdown_laps = { CORE_WAIT_STEP, of }
|
|
105
|
+
|
|
106
|
+
export { lane_breakdown_laps }
|
|
107
|
+
export type { Laps }
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { lane_breakdown, type Breakdown } from './lane-breakdown'
|
|
2
|
+
import { lane_ledger, type LedgerEntry, type TestPinnedEntry } from './lane-ledger'
|
|
3
|
+
|
|
4
|
+
// What a lane's ship pre-detach spent on `josh test:pinned` (joshuafolkken/kit#5078): the lane's
|
|
5
|
+
// `test-pinned` rows written inside that stage, as hunks the cache answered and the probed hunks'
|
|
6
|
+
// test files and wall time, the longest first.
|
|
7
|
+
|
|
8
|
+
type PinnedProbe = TestPinnedEntry['probes'][number]
|
|
9
|
+
|
|
10
|
+
// The longest probes named; the rest are counted in the head alone.
|
|
11
|
+
const MAX_SHOWN = 5
|
|
12
|
+
|
|
13
|
+
// `run:review`'s check and the pre-detach's probe past its stop (joshuafolkken/kit#5327) alike.
|
|
14
|
+
const DISCARDED_LABEL = 'background test:pinned probes discarded'
|
|
15
|
+
|
|
16
|
+
function is_lane_row(entry: LedgerEntry, issue: number): entry is TestPinnedEntry {
|
|
17
|
+
return entry.kind === lane_ledger.KIND.TEST_PINNED && entry.issue === issue
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function is_discarded(entry: TestPinnedEntry): boolean {
|
|
21
|
+
return entry.discarded === true
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function is_in_pre_detach(entry: TestPinnedEntry, breakdown: Breakdown): boolean {
|
|
25
|
+
const at_ms = Date.parse(entry.at)
|
|
26
|
+
|
|
27
|
+
return breakdown.pre_detach.some((span) => at_ms >= span.from_ms && at_ms <= span.to_ms)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// `issue`'s `test-pinned` rows written inside its ship pre-detach stage.
|
|
31
|
+
function rows_of(
|
|
32
|
+
entries: ReadonlyArray<LedgerEntry>,
|
|
33
|
+
issue: number,
|
|
34
|
+
breakdown: Breakdown,
|
|
35
|
+
): Array<TestPinnedEntry> {
|
|
36
|
+
return entries
|
|
37
|
+
.filter((entry) => is_lane_row(entry, issue))
|
|
38
|
+
.filter((entry) => !is_discarded(entry) && is_in_pre_detach(entry, breakdown))
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// `issue`'s background probes stopped before their answer (joshuafolkken/kit#5262, #5327), as a
|
|
42
|
+
// count and their wall time; `''` when none was.
|
|
43
|
+
function discarded_text(entries: ReadonlyArray<LedgerEntry>, issue: number): string {
|
|
44
|
+
const rows = entries
|
|
45
|
+
.filter((entry) => is_lane_row(entry, issue))
|
|
46
|
+
.filter((entry) => is_discarded(entry))
|
|
47
|
+
if (rows.length === 0) return ''
|
|
48
|
+
const elapsed_ms = rows.reduce((sum, row) => sum + row.elapsed_ms, 0)
|
|
49
|
+
|
|
50
|
+
return `${DISCARDED_LABEL} ${String(rows.length)}, ${lane_breakdown.minutes_text(elapsed_ms)}`
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function probe_text(probe: PinnedProbe): string {
|
|
54
|
+
const tests = probe.tests === undefined ? '' : ` ${String(probe.tests)} test files`
|
|
55
|
+
|
|
56
|
+
return `${probe.file}${tests} ${lane_breakdown.minutes_text(probe.elapsed_ms)}`
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// The detail the pre-detach line carries, or `''` when no probe ran inside it.
|
|
60
|
+
function detail_text(rows: ReadonlyArray<TestPinnedEntry>): string {
|
|
61
|
+
if (rows.length === 0) return ''
|
|
62
|
+
const probes = rows
|
|
63
|
+
.flatMap((row) => row.probes)
|
|
64
|
+
.toSorted((left, right) => right.elapsed_ms - left.elapsed_ms)
|
|
65
|
+
const held = rows.reduce((sum, row) => sum + row.held, 0)
|
|
66
|
+
const rewired = rows.reduce((sum, row) => sum + (row.rewired ?? 0), 0)
|
|
67
|
+
const total = held + rewired + probes.length
|
|
68
|
+
const head = `test:pinned ${String(total)} hunks, ${String(held)} cached, ${String(probes.length)} probed`
|
|
69
|
+
const counts = rewired === 0 ? [head] : [head, `${String(rewired)} rewired`]
|
|
70
|
+
|
|
71
|
+
return ` (${[...counts, ...probes.slice(0, MAX_SHOWN).map((probe) => probe_text(probe))].join(', ')})`
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const lane_breakdown_pinned = { detail_text, discarded_text, rows_of }
|
|
75
|
+
|
|
76
|
+
export { lane_breakdown_pinned }
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { lane_breakdown, type Breakdown, type Stage } from './lane-breakdown'
|
|
2
|
+
import { lane_breakdown_implement, type ImplementDetail } from './lane-breakdown-implement'
|
|
3
|
+
import { lane_breakdown_laps, type Laps } from './lane-breakdown-laps'
|
|
4
|
+
import { lane_breakdown_pinned } from './lane-breakdown-pinned'
|
|
5
|
+
import { lane_ci_path_stats } from './lane-ci-path-stats'
|
|
6
|
+
import type { LedgerEntry } from './lane-ledger'
|
|
7
|
+
|
|
8
|
+
// A lane's breakdown in words (joshuafolkken/kit#4995): the stages longest first, the implementation's
|
|
9
|
+
// tool-call kinds beside it, and the waits taken out last. `josh lane:breakdown` prints it, the overrun
|
|
10
|
+
// investigation comments it on the lane's Issue and leads its prompt with it (`lane-overrun.ts`).
|
|
11
|
+
|
|
12
|
+
const HEADING = 'Net time by stage, longest first'
|
|
13
|
+
const EXCLUDED = 'waits taken out (park, outage, usage limit, yield, host sleep)'
|
|
14
|
+
const SLEPT = 'of which host sleep'
|
|
15
|
+
const YIELDED = 'of which yield wait'
|
|
16
|
+
|
|
17
|
+
interface Report {
|
|
18
|
+
breakdown: Breakdown
|
|
19
|
+
detail: ImplementDetail
|
|
20
|
+
// The ship pre-detach line's `test:pinned` detail, `''` when none (joshuafolkken/kit#5078).
|
|
21
|
+
pinned?: string
|
|
22
|
+
// The discarded `run:review` background probes' line, `''` when none (joshuafolkken/kit#5262).
|
|
23
|
+
discarded?: string
|
|
24
|
+
// The followup's CI wait's last check to settle, `''` when none was recorded (joshuafolkken/kit#5295).
|
|
25
|
+
critical?: string
|
|
26
|
+
// Each ship stage's laps, and the Bash between ship stages, longest first (joshuafolkken/kit#5294).
|
|
27
|
+
laps?: Laps
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// A stage's line and the laps printed under it.
|
|
31
|
+
interface Entry {
|
|
32
|
+
text: string
|
|
33
|
+
laps: ReadonlyArray<string>
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function part_text(part: Stage): string {
|
|
37
|
+
return `${part.name} ${lane_breakdown.minutes_text(part.ms)}`
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// A kind's minutes, and the backgrounded subagent calls it counted at no time.
|
|
41
|
+
function kind_text(kind: Stage, untimed: ImplementDetail['untimed']): string {
|
|
42
|
+
const count = untimed.get(kind.name) ?? 0
|
|
43
|
+
|
|
44
|
+
return count > 0 ? `${part_text(kind)} + ${String(count)} backgrounded, untimed` : part_text(kind)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function detail_text(detail: ImplementDetail): string {
|
|
48
|
+
const kinds = detail.kinds.map((kind) => kind_text(kind, detail.untimed))
|
|
49
|
+
const count = String(detail.background)
|
|
50
|
+
const background =
|
|
51
|
+
detail.background > 0 ? [`${count} backgrounded calls, their waits in editing & thinking`] : []
|
|
52
|
+
|
|
53
|
+
return ` (${[...kinds, ...background].join(', ')})`
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Why a ship stage ran or was skipped, as its event line said (joshuafolkken/kit#5296).
|
|
57
|
+
function reason_text(reason: string | undefined): string {
|
|
58
|
+
return reason === undefined ? '' : ` (${reason})`
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// The detail a stage's line carries after its minutes, `''` for a stage with none.
|
|
62
|
+
function suffix_of(name: string, report: Report): string {
|
|
63
|
+
const suffixes: Record<string, string | undefined> = {
|
|
64
|
+
[lane_breakdown.IMPLEMENT_STAGE]: detail_text(report.detail),
|
|
65
|
+
[lane_breakdown.PRE_DETACH_STAGE]: report.pinned,
|
|
66
|
+
[lane_breakdown.FOLLOWUP_STAGE]: report.critical,
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return suffixes[name] ?? reason_text(report.breakdown.reasons?.get(name))
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function stage_entry(stage: Stage, report: Report): Entry {
|
|
73
|
+
const laps = report.laps?.get(stage.name) ?? []
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
text: `${part_text(stage)}${suffix_of(stage.name, report)}`,
|
|
77
|
+
laps: laps.map((lap) => part_text(lap)),
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function entries_of(report: Report): Array<Entry> {
|
|
82
|
+
const { breakdown } = report
|
|
83
|
+
const yielded = `${YIELDED} ${lane_breakdown.minutes_text(breakdown.yield_ms)}`
|
|
84
|
+
const slept = `${SLEPT} ${lane_breakdown.minutes_text(breakdown.slept_ms)}`
|
|
85
|
+
const excluded = `${EXCLUDED} ${lane_breakdown.minutes_text(breakdown.excluded_ms)}, ${yielded}, ${slept}`
|
|
86
|
+
|
|
87
|
+
const discarded =
|
|
88
|
+
report.discarded === undefined || report.discarded === '' ? [] : [report.discarded]
|
|
89
|
+
|
|
90
|
+
const tail = [...discarded, excluded].map((text) => ({ text, laps: [] }))
|
|
91
|
+
|
|
92
|
+
return [...breakdown.stages.map((stage) => stage_entry(stage, report)), ...tail]
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function bullets_of(entry: Entry): Array<string> {
|
|
96
|
+
return [`- ${entry.text}`, ...entry.laps.map((lap) => ` - ${lap}`)]
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function inline_of(entry: Entry): string {
|
|
100
|
+
return entry.laps.length > 0 ? `${entry.text} [${entry.laps.join(', ')}]` : entry.text
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// `issue`'s breakdown with its implementation's tool calls read off its transcripts, and its ship
|
|
104
|
+
// pre-detach's `test:pinned` rows read off `entries`.
|
|
105
|
+
function report_of(
|
|
106
|
+
issue: number,
|
|
107
|
+
breakdown: Breakdown,
|
|
108
|
+
entries: ReadonlyArray<LedgerEntry>,
|
|
109
|
+
): Report {
|
|
110
|
+
const calls = lane_breakdown_implement.read(issue, breakdown)
|
|
111
|
+
const rows = lane_breakdown_pinned.rows_of(entries, issue, breakdown)
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
breakdown,
|
|
115
|
+
detail: lane_breakdown_implement.of(calls, breakdown),
|
|
116
|
+
laps: lane_breakdown_laps.of(entries, issue, breakdown, calls),
|
|
117
|
+
pinned: lane_breakdown_pinned.detail_text(rows),
|
|
118
|
+
discarded: lane_breakdown_pinned.discarded_text(entries, issue),
|
|
119
|
+
critical: lane_ci_path_stats.last_check_text(entries, issue),
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// The Issue comment and the printout: a heading, then one bullet per stage.
|
|
124
|
+
function comment(issue: number, minutes: number, report: Report): string {
|
|
125
|
+
const lead = `${HEADING}, ${String(minutes)} min of net time`
|
|
126
|
+
const source = `(\`pnpm josh lane:breakdown ${String(issue)}\`):`
|
|
127
|
+
|
|
128
|
+
return [
|
|
129
|
+
`${lead} ${source}`,
|
|
130
|
+
'',
|
|
131
|
+
...entries_of(report).flatMap((entry) => bullets_of(entry)),
|
|
132
|
+
].join('\n')
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// One line, the form the investigation's prompt leads with.
|
|
136
|
+
function line(report: Report): string {
|
|
137
|
+
return `${HEADING}: ${entries_of(report)
|
|
138
|
+
.map((entry) => inline_of(entry))
|
|
139
|
+
.join('; ')}.`
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const lane_breakdown_text = { comment, line, report_of }
|
|
143
|
+
|
|
144
|
+
export { lane_breakdown_text }
|
|
145
|
+
export type { Report }
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { MS_PER_MINUTE } from '#scripts/lib/timeouts'
|
|
2
|
+
import { run_event_stream, type RunEvent } from '#scripts/run/event/run-event-stream'
|
|
3
|
+
import { run_ship_stage } from '#scripts/run/ship/run-ship-stage'
|
|
4
|
+
import { lane_ledger, type LedgerEntry } from './lane-ledger'
|
|
5
|
+
import { lane_net_time, type LaneSpan } from './lane-net-time'
|
|
6
|
+
import { lane_stop_stats } from './lane-stop-stats'
|
|
7
|
+
|
|
8
|
+
// A lane's net time by stage (joshuafolkken/kit#4995), read off the run events it already leaves: from
|
|
9
|
+
// its dispatch to its `plan`, the implementation from the `plan` (or `lane-phase implement`) to the first
|
|
10
|
+
// ship stage, each ship stage from its start to its end, and the time between ship stages — a stopped
|
|
11
|
+
// stage's fix included. The waits `lane:net` takes out are taken out of the stage they fell in and
|
|
12
|
+
// counted apart, so the stages add up to the net time. A cut and its resume open no stage: the
|
|
13
|
+
// implementation stays one stage across them.
|
|
14
|
+
|
|
15
|
+
const { EVENT_KIND } = run_event_stream
|
|
16
|
+
const { PHASE } = run_ship_stage
|
|
17
|
+
|
|
18
|
+
const PLAN_STAGE = 'start to plan'
|
|
19
|
+
const IMPLEMENT_STAGE = 'implement'
|
|
20
|
+
const BETWEEN_STAGE = 'between ship stages'
|
|
21
|
+
const SHIP_LEAD = 'ship '
|
|
22
|
+
const IMPLEMENT_SUFFIX = ' implement'
|
|
23
|
+
const PRE_DETACH_STAGE = `${SHIP_LEAD}${lane_ledger.PRE_DETACH_STAGE}`
|
|
24
|
+
const FOLLOWUP_STAGE = `${SHIP_LEAD}${run_ship_stage.STAGE.FOLLOWUP}`
|
|
25
|
+
|
|
26
|
+
// One stage's net milliseconds.
|
|
27
|
+
interface Stage {
|
|
28
|
+
name: string
|
|
29
|
+
ms: number
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface Breakdown {
|
|
33
|
+
// Longest first, the waits taken out.
|
|
34
|
+
stages: ReadonlyArray<Stage>
|
|
35
|
+
// The waits taken out, together.
|
|
36
|
+
excluded_ms: number
|
|
37
|
+
// The host's sleeps among them (joshuafolkken/kit#5032).
|
|
38
|
+
slept_ms: number
|
|
39
|
+
// The yields' waits for a redispatch among them (joshuafolkken/kit#5216).
|
|
40
|
+
yield_ms: number
|
|
41
|
+
// The waits taken out, each — the implementation's split leaves them out of its remainder too.
|
|
42
|
+
waits: ReadonlyArray<LaneSpan>
|
|
43
|
+
// The implementation's spans, waits left in — the window its tool calls are read in.
|
|
44
|
+
implement: ReadonlyArray<LaneSpan>
|
|
45
|
+
// The ship pre-detach stage's spans — the window its `test:pinned` rows are read in
|
|
46
|
+
// (joshuafolkken/kit#5078).
|
|
47
|
+
pre_detach: ReadonlyArray<LaneSpan>
|
|
48
|
+
// Each ship stage's spans and the spans between them, waits left in — the windows its laps and the
|
|
49
|
+
// fixes between stages are read in (joshuafolkken/kit#5294).
|
|
50
|
+
ship: ReadonlyArray<Segment>
|
|
51
|
+
// Why each ship stage last ran or was skipped, where its event line said (joshuafolkken/kit#5296).
|
|
52
|
+
reasons?: ReadonlyMap<string, string>
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
interface Segment extends LaneSpan {
|
|
56
|
+
stage: string
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function is_ship(segment: Segment): boolean {
|
|
60
|
+
return segment.stage.startsWith(SHIP_LEAD) || segment.stage === BETWEEN_STAGE
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface Marker {
|
|
64
|
+
at_ms: number
|
|
65
|
+
stage: string
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function ship_stage_of(text: string): string {
|
|
69
|
+
const { stage, phase } = run_ship_stage.words_of(text)
|
|
70
|
+
|
|
71
|
+
return phase === PHASE.START ? `${SHIP_LEAD}${stage}` : BETWEEN_STAGE
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// The stage an event opens, `undefined` for one that opens none.
|
|
75
|
+
function stage_of(event: RunEvent): string | undefined {
|
|
76
|
+
if (event.kind === EVENT_KIND.SHIP_STAGE) return ship_stage_of(event.text)
|
|
77
|
+
const is_implement =
|
|
78
|
+
event.kind === EVENT_KIND.PLAN ||
|
|
79
|
+
(event.kind === EVENT_KIND.LANE_PHASE && event.text.endsWith(IMPLEMENT_SUFFIX))
|
|
80
|
+
|
|
81
|
+
return is_implement ? IMPLEMENT_STAGE : undefined
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function is_inside(at_ms: number, span: LaneSpan): boolean {
|
|
85
|
+
return at_ms >= span.from_ms && at_ms < span.to_ms
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function is_lane_event(event: RunEvent, issue: number, span: LaneSpan): boolean {
|
|
89
|
+
return lane_stop_stats.issue_of(event) === issue && is_inside(Date.parse(event.at), span)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function marker_of(event: RunEvent, issue: number, span: LaneSpan): ReadonlyArray<Marker> {
|
|
93
|
+
const stage = stage_of(event)
|
|
94
|
+
const at_ms = Date.parse(event.at)
|
|
95
|
+
|
|
96
|
+
return stage !== undefined && is_lane_event(event, issue, span) ? [{ at_ms, stage }] : []
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function reason_of(event: RunEvent, issue: number, span: LaneSpan): Array<[string, string]> {
|
|
100
|
+
if (event.kind !== EVENT_KIND.SHIP_STAGE || !is_lane_event(event, issue, span)) return []
|
|
101
|
+
|
|
102
|
+
const reason = run_ship_stage.reason_of(event.text)
|
|
103
|
+
const stage = `${SHIP_LEAD}${run_ship_stage.words_of(event.text).stage}`
|
|
104
|
+
|
|
105
|
+
return reason === undefined ? [] : [[stage, reason]]
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// The newest reason each ship stage's event line gave, by the stage's name.
|
|
109
|
+
function reasons_of(
|
|
110
|
+
events: ReadonlyArray<RunEvent>,
|
|
111
|
+
issue: number,
|
|
112
|
+
span: LaneSpan,
|
|
113
|
+
): Map<string, string> {
|
|
114
|
+
const ordered = events.toSorted((left, right) => Date.parse(left.at) - Date.parse(right.at))
|
|
115
|
+
|
|
116
|
+
return new Map(ordered.flatMap((event) => reason_of(event, issue, span)))
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function segments_of(
|
|
120
|
+
events: ReadonlyArray<RunEvent>,
|
|
121
|
+
issue: number,
|
|
122
|
+
span: LaneSpan,
|
|
123
|
+
): Array<Segment> {
|
|
124
|
+
const opened = events
|
|
125
|
+
.flatMap((event) => marker_of(event, issue, span))
|
|
126
|
+
.toSorted((left, right) => left.at_ms - right.at_ms)
|
|
127
|
+
// A marker of the stage already open opens nothing: the `plan` and `lane-phase implement` of one
|
|
128
|
+
// start, or of a resumed session, leave the implementation one span.
|
|
129
|
+
const markers = [{ at_ms: span.from_ms, stage: PLAN_STAGE }, ...opened].filter(
|
|
130
|
+
(marker, index, all) => marker.stage !== all[index - 1]?.stage,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
return markers.map((marker, index) => ({
|
|
134
|
+
stage: marker.stage,
|
|
135
|
+
from_ms: marker.at_ms,
|
|
136
|
+
to_ms: markers[index + 1]?.at_ms ?? span.to_ms,
|
|
137
|
+
}))
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function clipped(segment: LaneSpan, parts: ReadonlyArray<LaneSpan>): Array<LaneSpan> {
|
|
141
|
+
return parts
|
|
142
|
+
.map((part) => ({
|
|
143
|
+
from_ms: Math.max(segment.from_ms, part.from_ms),
|
|
144
|
+
to_ms: Math.min(segment.to_ms, part.to_ms),
|
|
145
|
+
}))
|
|
146
|
+
.filter((part) => part.to_ms > part.from_ms)
|
|
147
|
+
.toSorted((left, right) => left.from_ms - right.from_ms)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// The milliseconds of `segment` that any of `parts` covers, each covered millisecond once — parallel
|
|
151
|
+
// tool calls, or a call across a wait, overlap.
|
|
152
|
+
function covered_ms(segment: LaneSpan, parts: ReadonlyArray<LaneSpan>): number {
|
|
153
|
+
let reached_ms = segment.from_ms
|
|
154
|
+
let total_ms = 0
|
|
155
|
+
|
|
156
|
+
for (const part of clipped(segment, parts)) {
|
|
157
|
+
total_ms += Math.max(0, part.to_ms - Math.max(part.from_ms, reached_ms))
|
|
158
|
+
reached_ms = Math.max(reached_ms, part.to_ms)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return total_ms
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Each name's milliseconds summed, longest first — the stages here and the tool-call kinds of the
|
|
165
|
+
// implementation (`lane-breakdown-implement.ts`) alike.
|
|
166
|
+
function ranked(parts: ReadonlyArray<Stage>): Array<Stage> {
|
|
167
|
+
const totals = new Map<string, number>()
|
|
168
|
+
|
|
169
|
+
for (const part of parts) totals.set(part.name, (totals.get(part.name) ?? 0) + part.ms)
|
|
170
|
+
|
|
171
|
+
return [...totals]
|
|
172
|
+
.map(([name, ms]) => ({ name, ms }))
|
|
173
|
+
.toSorted((left, right) => right.ms - left.ms)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function spans_ms(spans: ReadonlyArray<LaneSpan>): number {
|
|
177
|
+
return spans.reduce((sum, span) => sum + span.to_ms - span.from_ms, 0)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* `issue`'s lane by stage, or `undefined` when the ledger holds no dispatch and merge of it — the same
|
|
182
|
+
* span and waits `lane_net_time.net_ms` reads, so the stages add up to it.
|
|
183
|
+
*/
|
|
184
|
+
function of(
|
|
185
|
+
entries: ReadonlyArray<LedgerEntry>,
|
|
186
|
+
events: ReadonlyArray<RunEvent>,
|
|
187
|
+
issue: number,
|
|
188
|
+
): Breakdown | undefined {
|
|
189
|
+
const span = lane_net_time.span_of(entries, issue)
|
|
190
|
+
|
|
191
|
+
if (span === undefined) return undefined
|
|
192
|
+
|
|
193
|
+
const waits = lane_net_time.waits(entries, events, issue, span)
|
|
194
|
+
const segments = segments_of(events, issue, span)
|
|
195
|
+
const parts = segments.map((segment) => ({
|
|
196
|
+
name: segment.stage,
|
|
197
|
+
ms: segment.to_ms - segment.from_ms - covered_ms(segment, waits),
|
|
198
|
+
}))
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
stages: ranked(parts),
|
|
202
|
+
excluded_ms: spans_ms(waits),
|
|
203
|
+
slept_ms: spans_ms(lane_net_time.slept(events, span)),
|
|
204
|
+
yield_ms: spans_ms(lane_net_time.yielded(entries, events, issue, span)),
|
|
205
|
+
waits,
|
|
206
|
+
implement: segments.filter((segment) => segment.stage === IMPLEMENT_STAGE),
|
|
207
|
+
pre_detach: segments.filter((segment) => segment.stage === PRE_DETACH_STAGE),
|
|
208
|
+
ship: segments.filter((segment) => is_ship(segment)),
|
|
209
|
+
reasons: reasons_of(events, issue, span),
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function minutes_text(ms: number): string {
|
|
214
|
+
return `${(ms / MS_PER_MINUTE).toFixed(1)} min`
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// The longest stage in whole minutes, the words the overrun's start note carries.
|
|
218
|
+
function longest_of(breakdown: Breakdown): { name: string; minutes: number } | undefined {
|
|
219
|
+
const [longest] = breakdown.stages
|
|
220
|
+
|
|
221
|
+
return longest === undefined
|
|
222
|
+
? undefined
|
|
223
|
+
: { name: longest.name, minutes: Math.round(longest.ms / MS_PER_MINUTE) }
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const lane_breakdown = {
|
|
227
|
+
BETWEEN_STAGE,
|
|
228
|
+
FOLLOWUP_STAGE,
|
|
229
|
+
IMPLEMENT_STAGE,
|
|
230
|
+
PRE_DETACH_STAGE,
|
|
231
|
+
covered_ms,
|
|
232
|
+
longest_of,
|
|
233
|
+
minutes_text,
|
|
234
|
+
of,
|
|
235
|
+
ranked,
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export { lane_breakdown }
|
|
239
|
+
export type { Breakdown, Segment, Stage }
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { MS_PER_SECOND } from '#scripts/lib/timeouts'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
lane_ledger,
|
|
4
|
+
type GateCheckRecord,
|
|
5
|
+
type GateEntry,
|
|
6
|
+
type LedgerEntry,
|
|
7
|
+
type PushMissEntry,
|
|
8
|
+
} from './lane-ledger'
|
|
3
9
|
import { lane_stage_stats } from './lane-stage-stats'
|
|
4
10
|
import { lane_stats, type StatsWindow } from './lane-stats'
|
|
5
11
|
|
|
6
12
|
// Which check a gate waited on: one period's per-check rows reduced to one row per check — median,
|
|
7
|
-
// maximum, runs, reuses, no-ops and whole-suite fallbacks — printed
|
|
13
|
+
// maximum, runs, reuses, no-ops and whole-suite fallbacks — printed by `josh lane:stats`.
|
|
8
14
|
//
|
|
9
15
|
// The whole gate is the first row, since its reuse started no check (joshuafolkken/kit#4397); the
|
|
10
16
|
// checks follow in the order they first appear.
|
|
@@ -15,7 +21,8 @@ import { lane_stats, type StatsWindow } from './lane-stats'
|
|
|
15
21
|
// would stand for a run that tested nothing.
|
|
16
22
|
//
|
|
17
23
|
// **The fallbacks are broken down by why** in a second table, one row per reason kind, so a slow unit
|
|
18
|
-
// leg can be read as the full suite it ran and the reason it had to.
|
|
24
|
+
// leg can be read as the full suite it ran and the reason it had to. A pre-push hook that ran a suite
|
|
25
|
+
// over a record it could not reuse joins it, prefixed `pre-push <scope>:`.
|
|
19
26
|
|
|
20
27
|
const DECIMALS = 1
|
|
21
28
|
const WHOLE_GATE_LABEL = 'gate (whole)'
|
|
@@ -69,8 +76,21 @@ function whole_gate(gate: GateEntry): GateCheckRecord {
|
|
|
69
76
|
}
|
|
70
77
|
}
|
|
71
78
|
|
|
72
|
-
function
|
|
73
|
-
|
|
79
|
+
function is_push_miss(entry: LedgerEntry): entry is PushMissEntry {
|
|
80
|
+
return entry.kind === lane_ledger.KIND.PUSH_MISS
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// A pre-push hook's miss, told apart from the gate's own fallbacks by its scope (joshuafolkken/kit#5234).
|
|
84
|
+
function push_reason(miss: PushMissEntry): string {
|
|
85
|
+
return `pre-push ${miss.scope}: ${miss.reason}`
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function fallback_table(
|
|
89
|
+
checks: ReadonlyArray<GateCheckRecord>,
|
|
90
|
+
misses: ReadonlyArray<PushMissEntry>,
|
|
91
|
+
): string {
|
|
92
|
+
const fallbacks = checks.map((check) => check.fallback).filter((reason) => reason !== undefined)
|
|
93
|
+
const reasons = [...fallbacks, ...misses.map((miss) => push_reason(miss))]
|
|
74
94
|
const kinds = [...new Set(reasons)]
|
|
75
95
|
const rows = kinds.map((kind) =>
|
|
76
96
|
lane_stats.to_row([kind, String(reasons.filter((reason) => reason === kind).length)]),
|
|
@@ -81,17 +101,18 @@ function fallback_table(checks: ReadonlyArray<GateCheckRecord>): string {
|
|
|
81
101
|
|
|
82
102
|
// The period's tables: `entries` is the whole ledger, filtered here to `window`.
|
|
83
103
|
function table(entries: ReadonlyArray<LedgerEntry>, window: StatsWindow): string {
|
|
84
|
-
const
|
|
104
|
+
const windowed = lane_stats.in_window(entries, window)
|
|
105
|
+
const gates = windowed.filter(is_gate)
|
|
85
106
|
const checks = gates.flatMap((gate) => gate.checks ?? [])
|
|
86
107
|
const rows = [...gates.map((gate) => whole_gate(gate)), ...checks]
|
|
87
108
|
const labels = [...new Set(rows.map((row) => row.label))]
|
|
88
109
|
|
|
89
110
|
return [
|
|
90
111
|
[...header(COLUMNS), ...labels.map((label) => check_row(label, rows))].join('\n'),
|
|
91
|
-
fallback_table(checks),
|
|
112
|
+
fallback_table(checks, windowed.filter(is_push_miss)),
|
|
92
113
|
].join('\n\n')
|
|
93
114
|
}
|
|
94
115
|
|
|
95
|
-
const lane_check_stats = { WHOLE_GATE_LABEL, table }
|
|
116
|
+
const lane_check_stats = { WHOLE_GATE_LABEL, cell, header, table }
|
|
96
117
|
|
|
97
118
|
export { lane_check_stats }
|
|
@@ -95,8 +95,8 @@ function outage_resume_invocation(issue: string): string {
|
|
|
95
95
|
// tail and the changed files (`run-ship-stop-context.ts`), so the session starts at the fix rather than
|
|
96
96
|
// at `josh ship --log` and `git diff` (joshuafolkken/kit#3923).
|
|
97
97
|
//
|
|
98
|
-
// The context gets what the rest of the prompt leaves of
|
|
99
|
-
//
|
|
98
|
+
// The context gets what the rest of the prompt leaves of `MAX_VALUE_LENGTH`, so the whole prompt
|
|
99
|
+
// stays within it and launches (joshuafolkken/kit#3964).
|
|
100
100
|
function known_stop_lines(
|
|
101
101
|
issue: string,
|
|
102
102
|
stop: ShipStop,
|
|
@@ -127,6 +127,12 @@ function ship_stop_invocation(issue: string, stop?: ShipStop): string {
|
|
|
127
127
|
return [opening, ...middle, closing].join(LINE_BREAK)
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
// The same stop for the session that launched the ship and still waits on it (`run-ship-waiter.ts`):
|
|
131
|
+
// the next command and the context alone, since that session has the run in front of it already.
|
|
132
|
+
function ship_stop_note(issue: string, stop: ShipStop): string {
|
|
133
|
+
return known_stop_lines(issue, stop, []).join(LINE_BREAK)
|
|
134
|
+
}
|
|
135
|
+
|
|
130
136
|
const lane_child_invocation = {
|
|
131
137
|
child_invocation,
|
|
132
138
|
outage_resume_invocation,
|
|
@@ -135,6 +141,7 @@ const lane_child_invocation = {
|
|
|
135
141
|
review_invocation,
|
|
136
142
|
ship_pattern,
|
|
137
143
|
ship_stop_invocation,
|
|
144
|
+
ship_stop_note,
|
|
138
145
|
}
|
|
139
146
|
|
|
140
147
|
export type { ShipStop }
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// The environment keys a launcher marks a lane child with, in a module of their own so the unit
|
|
2
|
+
// suite's vitest config reads them without widening its import graph (`whole-suite-files.ts`).
|
|
3
|
+
// `lane-child-marker.ts` documents each mark; a mark added there is added here, and the unit suite
|
|
4
|
+
// then blanks it with no list of its own (joshuafolkken/kit#5029).
|
|
5
|
+
|
|
6
|
+
const KEY = 'JOSH_LANE_CHILD'
|
|
7
|
+
const OVERRUN_KEY = 'JOSH_LANE_OVERRUN'
|
|
8
|
+
const MARK_KEYS: ReadonlyArray<string> = [KEY, OVERRUN_KEY]
|
|
9
|
+
|
|
10
|
+
const lane_child_mark_keys = { KEY, MARK_KEYS, OVERRUN_KEY }
|
|
11
|
+
|
|
12
|
+
export { lane_child_mark_keys }
|