@joshuafolkken/kit 1.1784.0 → 1.2114.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 +59 -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 +415 -389
- 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 +15 -8
- 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
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto'
|
|
2
2
|
import { mkdirSync, readFileSync, rmSync, unlinkSync } from 'node:fs'
|
|
3
3
|
import path from 'node:path'
|
|
4
|
-
import { setTimeout as sleep } from 'node:timers/promises'
|
|
5
4
|
import { git_common_directory } from '#scripts/git/git-common-directory'
|
|
6
5
|
import { issue_cite } from '#scripts/issue/issue-cite'
|
|
7
6
|
import { stamp_file } from '#scripts/josh/stamp-file'
|
|
8
7
|
import { atomic_write } from '#scripts/lib/atomic-write'
|
|
9
8
|
import { json_value } from '#scripts/lib/json-value'
|
|
9
|
+
import { poll } from '#scripts/lib/poll'
|
|
10
10
|
import { run_event_stream } from '#scripts/run/event/run-event-stream'
|
|
11
11
|
import { run_event_stream_emit } from '#scripts/run/event/run-event-stream-emit'
|
|
12
12
|
import { z } from 'zod'
|
|
13
13
|
import { lane_broker_server, type BrokerServer } from './lane-broker-server'
|
|
14
14
|
import type { LaneInfo } from './lane-registry'
|
|
15
15
|
import { lane_session_action, type BrokerAction, type BrokerAnswer } from './lane-session-action'
|
|
16
|
+
import { lane_session_reread } from './lane-session-reread'
|
|
16
17
|
|
|
17
18
|
// The sessions a lane child's detached `josh ship` cannot start itself, started for it by a process
|
|
18
19
|
// that can: the round-1 and round-2 reviewer, and the fresh child a stopped ship hands back to. An
|
|
@@ -38,9 +39,7 @@ const REQUEST_LIMIT_MINUTES: Readonly<Record<BrokerAction['kind'], number>> = {
|
|
|
38
39
|
review: 30,
|
|
39
40
|
relaunch: 2,
|
|
40
41
|
}
|
|
41
|
-
const request_schema =
|
|
42
|
-
.object({ session: z.uuid(), nonce: z.uuid(), action: lane_session_action.action_schema })
|
|
43
|
-
.strict()
|
|
42
|
+
const { request_schema } = lane_session_action
|
|
44
43
|
// **A request this broker cannot read is still answered**: the supervisor reloads on new code only at
|
|
45
44
|
// its next pass boundary (`run-wake-code.ts`), so until then a lane's ship can run a newer main than
|
|
46
45
|
// the broker's, and a field the ship added made the request unreadable and
|
|
@@ -49,6 +48,15 @@ const request_schema = z
|
|
|
49
48
|
// broker's schema had never learned even on one main (joshuafolkken/kit#4489).
|
|
50
49
|
const envelope_schema = z.looseObject({ session: z.uuid(), nonce: z.uuid() })
|
|
51
50
|
const UNREADABLE_REASON = 'the broker could not read the request'
|
|
51
|
+
// **A refused request is read as a version difference, never dropped silently** (joshuafolkken/kit#4714):
|
|
52
|
+
// the refusal marks the supervisor's code as suspect, so its next pass re-hashes the code even where the
|
|
53
|
+
// commit did not move or the hash at its start could not be read, and reloads when it differs. Only the
|
|
54
|
+
// `run:wake` supervisor takes the mark: an OpenAI lane's own supervisor never re-checks its code.
|
|
55
|
+
// **Before it is refused, the code on disk reads it** (`lane-session-reread.ts`), so a schema main widened
|
|
56
|
+
// since the supervisor started is answered now rather than after the reload (joshuafolkken/kit#4732).
|
|
57
|
+
const VERSION_NOTE =
|
|
58
|
+
"the broker's code differs from the ship's; a run:wake supervisor re-checks its code at its next pass"
|
|
59
|
+
const refusal = { is_pending: false }
|
|
52
60
|
const response_schema = z
|
|
53
61
|
.object({
|
|
54
62
|
session: z.uuid(),
|
|
@@ -103,15 +111,31 @@ function refused_field(issue: z.core.$ZodIssue): ReadonlyArray<string> {
|
|
|
103
111
|
function unreadable(error: z.ZodError): BrokerAnswer {
|
|
104
112
|
const fields = error.issues.flatMap((issue) => refused_field(issue))
|
|
105
113
|
|
|
106
|
-
return failure(`${UNREADABLE_REASON} — ${fields.join('; ')}`)
|
|
114
|
+
return failure(`${UNREADABLE_REASON} — ${VERSION_NOTE} — ${fields.join('; ')}`)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// The answer of a broker on code older than the request, which the ship can still fall back from.
|
|
118
|
+
function is_unreadable(answer: BrokerAnswer): boolean {
|
|
119
|
+
return !answer.is_success && answer.reason.includes(UNREADABLE_REASON)
|
|
107
120
|
}
|
|
108
121
|
|
|
109
122
|
async function answer_request(lane: LaneInfo, received: BrokerEnvelope): Promise<BrokerAnswer> {
|
|
110
123
|
const parsed = request_schema.safeParse(received)
|
|
124
|
+
if (parsed.success) return await lane_session_action.answer(lane, parsed.data.action)
|
|
111
125
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
126
|
+
refusal.is_pending = true
|
|
127
|
+
|
|
128
|
+
return (await lane_session_reread.reread(lane.issue, received)) ?? unreadable(parsed.error)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Whether a request was refused since the supervisor last asked, clearing the mark — the supervisor
|
|
132
|
+
// re-checks its code on it (`run-wake-code.ts`).
|
|
133
|
+
function take_refusal(): boolean {
|
|
134
|
+
const { is_pending } = refusal
|
|
135
|
+
|
|
136
|
+
refusal.is_pending = false
|
|
137
|
+
|
|
138
|
+
return is_pending
|
|
115
139
|
}
|
|
116
140
|
|
|
117
141
|
// The requests this process's servers are answering now — what the supervisor's reload waits out
|
|
@@ -152,21 +176,23 @@ async function serve(
|
|
|
152
176
|
response: string,
|
|
153
177
|
state: { is_running: boolean; current: BrokerResponse },
|
|
154
178
|
): Promise<void> {
|
|
155
|
-
|
|
179
|
+
const served = { nonce: '' }
|
|
156
180
|
const target = request_path(lane.directory, lane.issue)
|
|
157
181
|
|
|
158
|
-
|
|
182
|
+
// Requests are served one at a time, in arrival order: a pass ends only once its request is answered.
|
|
183
|
+
async function serve_pass(): Promise<true | undefined> {
|
|
184
|
+
if (!state.is_running) return true
|
|
159
185
|
const received = read_record(target, envelope_schema)
|
|
160
186
|
|
|
161
|
-
if (received?.session === session && received.nonce !==
|
|
162
|
-
|
|
163
|
-
// eslint-disable-next-line no-await-in-loop -- requests are served one at a time, in arrival order
|
|
187
|
+
if (received?.session === session && received.nonce !== served.nonce) {
|
|
188
|
+
served.nonce = received.nonce
|
|
164
189
|
await process_request(lane, response, received, state)
|
|
165
190
|
}
|
|
166
191
|
|
|
167
|
-
|
|
168
|
-
await sleep(POLL_MS)
|
|
192
|
+
return undefined
|
|
169
193
|
}
|
|
194
|
+
|
|
195
|
+
await poll.wait_for(serve_pass, { interval_ms: POLL_MS })
|
|
170
196
|
}
|
|
171
197
|
|
|
172
198
|
// The server record is written before the response, so a ship that finds the response finds it too.
|
|
@@ -291,15 +317,15 @@ async function wait_response(
|
|
|
291
317
|
const limit_minutes = REQUEST_LIMIT_MINUTES[kind]
|
|
292
318
|
const deadline = Date.now() + limit_minutes * MINUTE_MS
|
|
293
319
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
320
|
+
function verdict_by_deadline(): BrokerAnswer | undefined {
|
|
321
|
+
if (Date.now() >= deadline) {
|
|
322
|
+
return failure(`the broker gave no answer within ${String(limit_minutes)} minutes`)
|
|
323
|
+
}
|
|
297
324
|
|
|
298
|
-
|
|
299
|
-
await sleep(POLL_MS)
|
|
325
|
+
return response_verdict(target, session, nonce)
|
|
300
326
|
}
|
|
301
327
|
|
|
302
|
-
return
|
|
328
|
+
return await poll.wait_for(verdict_by_deadline, { interval_ms: POLL_MS })
|
|
303
329
|
}
|
|
304
330
|
|
|
305
331
|
function live_response(target: string): BrokerResponse | undefined {
|
|
@@ -374,11 +400,13 @@ async function request(
|
|
|
374
400
|
const lane_session_broker = {
|
|
375
401
|
is_answering,
|
|
376
402
|
is_serving,
|
|
403
|
+
is_unreadable,
|
|
377
404
|
request,
|
|
378
405
|
request_path,
|
|
379
406
|
response_path,
|
|
380
407
|
review_paths: lane_session_action.review_paths,
|
|
381
408
|
serving_session,
|
|
409
|
+
take_refusal,
|
|
382
410
|
with_server,
|
|
383
411
|
}
|
|
384
412
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { fileURLToPath } from 'node:url'
|
|
3
|
+
import { lane_session_reread } from './lane-session-reread'
|
|
4
|
+
|
|
5
|
+
// The fresh process a lane broker starts for a request its own code refused (`lane-session-reread.ts`):
|
|
6
|
+
// `<issue> <request JSON>` in, the answer's JSON out, exit 1 where it read nothing.
|
|
7
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
8
|
+
const ARGV_OFFSET = 2
|
|
9
|
+
const [issue = '', text = ''] = process.argv.slice(ARGV_OFFSET)
|
|
10
|
+
const answer = await lane_session_reread.answer_text(issue, text)
|
|
11
|
+
|
|
12
|
+
if (answer === undefined) process.exitCode = 1
|
|
13
|
+
else process.stdout.write(`${JSON.stringify(answer)}\n`)
|
|
14
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { fileURLToPath } from 'node:url'
|
|
2
|
+
import { json_value } from '#scripts/lib/json-value'
|
|
3
|
+
import { execa } from 'execa'
|
|
4
|
+
import { z } from 'zod'
|
|
5
|
+
import { lane_registry } from './lane-registry'
|
|
6
|
+
import { lane_session_action, type BrokerAnswer } from './lane-session-action'
|
|
7
|
+
|
|
8
|
+
// **A request the supervisor's loaded code refuses is read again by the code on disk**
|
|
9
|
+
// (joshuafolkken/kit#4732): the `run:wake` supervisor reloads only at a pass boundary, so a schema main
|
|
10
|
+
// widened after it started refused the request a stopped ship sent, and the lane it should have
|
|
11
|
+
// relaunched was parked instead. A fresh process of this file's sibling entry reads the request with
|
|
12
|
+
// the schema main has now and performs the action; it prints the answer only when it read the request,
|
|
13
|
+
// so a disk as old as the supervisor leaves the refusal to the broker.
|
|
14
|
+
|
|
15
|
+
const ENTRY = fileURLToPath(new URL('lane-session-reread-main.ts', import.meta.url))
|
|
16
|
+
const answer_schema = z.discriminatedUnion('is_success', [
|
|
17
|
+
z.object({ is_success: z.literal(true) }).strict(),
|
|
18
|
+
z.object({ is_success: z.literal(false), reason: z.string() }).strict(),
|
|
19
|
+
])
|
|
20
|
+
|
|
21
|
+
// The fresh process's side: the answer to a request read with the schema on disk, or `undefined` where
|
|
22
|
+
// the request is unreadable or no open lane carries the issue.
|
|
23
|
+
async function answer_text(issue: string, text: string): Promise<BrokerAnswer | undefined> {
|
|
24
|
+
const request = json_value.parse_with(text, lane_session_action.request_schema)
|
|
25
|
+
if (request === undefined) return undefined
|
|
26
|
+
|
|
27
|
+
const lane = await lane_registry.find_open_lane(issue)
|
|
28
|
+
if (lane === undefined) return undefined
|
|
29
|
+
|
|
30
|
+
return await lane_session_action.answer(lane, request.action)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function last_line(text: string): string {
|
|
34
|
+
return text.trimEnd().split('\n').at(-1) ?? ''
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// The supervisor's side: the fresh process's answer, or `undefined` where it read nothing.
|
|
38
|
+
async function reread(issue: string, received: unknown): Promise<BrokerAnswer | undefined> {
|
|
39
|
+
const result = await execa(
|
|
40
|
+
process.execPath,
|
|
41
|
+
[...process.execArgv, ENTRY, issue, JSON.stringify(received)],
|
|
42
|
+
{ reject: false, stderr: 'inherit' },
|
|
43
|
+
)
|
|
44
|
+
if (result.exitCode !== 0) return undefined
|
|
45
|
+
|
|
46
|
+
return json_value.parse_with(last_line(result.stdout), answer_schema)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const lane_session_reread = { answer_text, reread }
|
|
50
|
+
|
|
51
|
+
export { lane_session_reread }
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { lane_check_stats } from './lane-check-stats'
|
|
2
|
+
import { lane_ledger, type LedgerEntry, type ShipLapEntry } from './lane-ledger'
|
|
3
|
+
import { lane_stage_stats } from './lane-stage-stats'
|
|
4
|
+
import { lane_stats, type StatsWindow } from './lane-stats'
|
|
5
|
+
|
|
6
|
+
// What the ship stages spent their time on (joshuafolkken/kit#5294): one period's `ship-lap` entries
|
|
7
|
+
// reduced to one row per stage and inner step — median, maximum and runs — printed by `josh lane:stats`
|
|
8
|
+
// under the stage table. The rows follow the stages' running order, a stage's steps longest first.
|
|
9
|
+
//
|
|
10
|
+
// **A row's first cell names both, `<stage>: <step>`**: `lane:value cell` finds a row by its first
|
|
11
|
+
// cell alone, and a stage records several steps while a step (`scoped pair`) runs in several stages.
|
|
12
|
+
|
|
13
|
+
const COLUMNS = ['ship step', 'median (min)', 'max (min)', 'runs'] as const
|
|
14
|
+
const STAGE_ORDER: ReadonlyArray<string> = lane_stage_stats.STAGES
|
|
15
|
+
|
|
16
|
+
interface Group {
|
|
17
|
+
stage: string
|
|
18
|
+
step: string
|
|
19
|
+
elapsed: ReadonlyArray<number>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function is_ship_lap(entry: LedgerEntry): entry is ShipLapEntry {
|
|
23
|
+
return entry.kind === lane_ledger.KIND.SHIP_LAP
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function groups_of(laps: ReadonlyArray<ShipLapEntry>): Array<Group> {
|
|
27
|
+
const keys = [...new Map(laps.map((lap) => [`${lap.stage}\n${lap.step}`, lap])).values()]
|
|
28
|
+
|
|
29
|
+
return keys.map(({ stage, step }) => ({
|
|
30
|
+
stage,
|
|
31
|
+
step,
|
|
32
|
+
elapsed: laps
|
|
33
|
+
.filter((lap) => lap.stage === stage && lap.step === step)
|
|
34
|
+
.map((lap) => lap.elapsed_ms),
|
|
35
|
+
}))
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// A stage `STAGES` does not name sorts after every stage it does.
|
|
39
|
+
function stage_rank(stage: string): number {
|
|
40
|
+
const index = STAGE_ORDER.indexOf(stage)
|
|
41
|
+
|
|
42
|
+
return index === -1 ? STAGE_ORDER.length : index
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function compare(left: Group, right: Group): number {
|
|
46
|
+
const by_stage = stage_rank(left.stage) - stage_rank(right.stage)
|
|
47
|
+
|
|
48
|
+
if (by_stage !== 0) return by_stage
|
|
49
|
+
|
|
50
|
+
return (lane_stats.median(right.elapsed) ?? 0) - (lane_stats.median(left.elapsed) ?? 0)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function row_of(group: Group): string {
|
|
54
|
+
return lane_stats.to_row([
|
|
55
|
+
`${group.stage}: ${group.step}`,
|
|
56
|
+
lane_stage_stats.cell(lane_stats.median(group.elapsed)),
|
|
57
|
+
lane_stage_stats.cell(lane_stats.peak(group.elapsed)),
|
|
58
|
+
String(group.elapsed.length),
|
|
59
|
+
])
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// The period's table: `entries` is the whole ledger, filtered here to `window`.
|
|
63
|
+
function table(entries: ReadonlyArray<LedgerEntry>, window: StatsWindow): string {
|
|
64
|
+
const laps = lane_stats.in_window(entries, window).filter(is_ship_lap)
|
|
65
|
+
const rows = groups_of(laps)
|
|
66
|
+
.toSorted(compare)
|
|
67
|
+
.map((group) => row_of(group))
|
|
68
|
+
|
|
69
|
+
return [...lane_check_stats.header(COLUMNS), ...rows].join('\n')
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const lane_ship_lap_stats = { table }
|
|
73
|
+
|
|
74
|
+
export { lane_ship_lap_stats }
|
|
@@ -0,0 +1,58 @@
|
|
|
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_event_stream_emit } from '#scripts/run/event/run-event-stream-emit'
|
|
4
|
+
import type { LaneSpan } from './lane-net-time'
|
|
5
|
+
|
|
6
|
+
// The host's sleep (joshuafolkken/kit#5032): a closed lid stops every lane, yet no park, outage or
|
|
7
|
+
// usage-limit event says so, and its minutes read as work. The load sampler's timer does not fire while
|
|
8
|
+
// the host sleeps, so a tick later than a few intervals is the sign: the wall clock past the tick that
|
|
9
|
+
// was due is recorded as one `sleep` event, and every lane's net time takes it out (`lane-net-time.ts`).
|
|
10
|
+
// A tick merely slowed by load runs well inside the threshold, so a busy host is not read as asleep.
|
|
11
|
+
|
|
12
|
+
const { EVENT_KIND } = run_event_stream
|
|
13
|
+
|
|
14
|
+
const GAP_INTERVALS = 3
|
|
15
|
+
|
|
16
|
+
/** The sleep between two ticks `interval_ms` apart, or `undefined` when the later one was on time. */
|
|
17
|
+
function gap_of(last_ms: number, now_ms: number, interval_ms: number): LaneSpan | undefined {
|
|
18
|
+
if (now_ms - last_ms <= interval_ms * GAP_INTERVALS) return undefined
|
|
19
|
+
|
|
20
|
+
return { from_ms: last_ms + interval_ms, to_ms: now_ms }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function event_of(span: LaneSpan): Omit<RunEvent, 'pos'> {
|
|
24
|
+
const elapsed_ms = span.to_ms - span.from_ms
|
|
25
|
+
const minutes = (elapsed_ms / MS_PER_MINUTE).toFixed(1)
|
|
26
|
+
|
|
27
|
+
// Stamped at the wake, when it is appended: a stream reader takes its newest line for the newest time.
|
|
28
|
+
return {
|
|
29
|
+
at: new Date(span.to_ms).toISOString(),
|
|
30
|
+
kind: EVENT_KIND.SLEEP,
|
|
31
|
+
text: `host slept ${minutes} min`,
|
|
32
|
+
elapsed_ms,
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Append `span` as a `sleep` event to `events_path`, or to this checkout's run stream when absent. */
|
|
37
|
+
async function record(span: LaneSpan, events_path?: string): Promise<void> {
|
|
38
|
+
const target = events_path ?? (await run_event_stream_emit.stream_target())
|
|
39
|
+
|
|
40
|
+
if (target === undefined) return
|
|
41
|
+
|
|
42
|
+
run_event_stream.append_event(target, event_of(span))
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Every sleep on `events`, oldest first.
|
|
46
|
+
function spans(events: ReadonlyArray<RunEvent>): Array<LaneSpan> {
|
|
47
|
+
return events
|
|
48
|
+
.filter((event) => event.kind === EVENT_KIND.SLEEP)
|
|
49
|
+
.map((event) => {
|
|
50
|
+
const to_ms = Date.parse(event.at)
|
|
51
|
+
|
|
52
|
+
return { from_ms: to_ms - (event.elapsed_ms ?? 0), to_ms }
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const lane_sleep = { gap_of, record, spans }
|
|
57
|
+
|
|
58
|
+
export { lane_sleep }
|
|
@@ -203,7 +203,7 @@ function idle_lanes(
|
|
|
203
203
|
return issues_traced(traced_of(lanes, probes), PROCESS_NONE)
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
-
const lane_spent = { idle_lanes, kept_reason, lanes_in_use, sort_lanes }
|
|
206
|
+
const lane_spent = { idle_lanes, kept_reason, lanes_in_use, read_unpushed_commits, sort_lanes }
|
|
207
207
|
|
|
208
208
|
export type { KeptLane, LaneUse, SpentProbes, SpentSort }
|
|
209
209
|
export { lane_spent }
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { split_resolution } from '#scripts/split/split-resolution'
|
|
2
|
+
import type { LedgerEntry } from './lane-ledger'
|
|
3
|
+
import { lane_stats, type StatsWindow } from './lane-stats'
|
|
4
|
+
|
|
5
|
+
// Whether the split notice works: the lanes the notice reached in one period, and how many of them
|
|
6
|
+
// filed a split child, printed by `josh lane:stats` so the notice's effect is read off the ledger
|
|
7
|
+
// rather than searched for in lane transcripts (joshuafolkken/kit#4695). A split child counts
|
|
8
|
+
// whenever it was filed, since a lane may carve the rest out before the notice reaches it.
|
|
9
|
+
|
|
10
|
+
const COLUMNS = ['noticed lanes', 'split'] as const
|
|
11
|
+
|
|
12
|
+
// The period's table: `entries` is the whole ledger; the notices are filtered here to `window`.
|
|
13
|
+
function table(entries: ReadonlyArray<LedgerEntry>, window: StatsWindow): string {
|
|
14
|
+
const in_period = split_resolution.notices(lane_stats.in_window(entries, window))
|
|
15
|
+
const noticed = new Set(in_period.map((entry) => entry.issue))
|
|
16
|
+
const split = split_resolution.split_issues(entries)
|
|
17
|
+
const split_count = [...noticed].filter((issue) => split.has(issue)).length
|
|
18
|
+
|
|
19
|
+
return [
|
|
20
|
+
lane_stats.to_row(COLUMNS),
|
|
21
|
+
lane_stats.to_row(COLUMNS.map(() => '---')),
|
|
22
|
+
lane_stats.to_row([String(noticed.size), String(split_count)]),
|
|
23
|
+
].join('\n')
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const lane_split_stats = { table }
|
|
27
|
+
|
|
28
|
+
export { lane_split_stats }
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { MS_PER_MINUTE } from '#scripts/lib/timeouts'
|
|
2
2
|
import { run_ship_stage } from '#scripts/run/ship/run-ship-stage'
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
lane_ledger,
|
|
5
|
+
type DispatchEntry,
|
|
6
|
+
type LedgerEntry,
|
|
7
|
+
type MergeEntry,
|
|
8
|
+
type StageEntry,
|
|
9
|
+
} from './lane-ledger'
|
|
4
10
|
import { lane_stats, type StatsWindow } from './lane-stats'
|
|
5
11
|
|
|
6
12
|
// Where a lane's time goes: the ledger's `stage` and `dispatch` entries of one period reduced to one
|
|
@@ -37,6 +43,7 @@ const STAGES = [
|
|
|
37
43
|
lane_ledger.CI_WAIT_STAGE,
|
|
38
44
|
lane_ledger.CODERABBIT_WAIT_STAGE,
|
|
39
45
|
lane_ledger.CODERABBIT_RATE_LIMIT_STAGE,
|
|
46
|
+
lane_ledger.CODERABBIT_RETRIGGER_STAGE,
|
|
40
47
|
STAGE.REPORT,
|
|
41
48
|
] as const
|
|
42
49
|
|
|
@@ -53,6 +60,10 @@ function is_dispatch(entry: LedgerEntry): entry is DispatchEntry {
|
|
|
53
60
|
return entry.kind === lane_ledger.KIND.DISPATCH
|
|
54
61
|
}
|
|
55
62
|
|
|
63
|
+
function is_merge(entry: LedgerEntry): entry is MergeEntry {
|
|
64
|
+
return entry.kind === lane_ledger.KIND.MERGE
|
|
65
|
+
}
|
|
66
|
+
|
|
56
67
|
function is_number(value: number | undefined): value is number {
|
|
57
68
|
return value !== undefined
|
|
58
69
|
}
|
|
@@ -154,6 +165,7 @@ const lane_stage_stats = {
|
|
|
154
165
|
STAGES,
|
|
155
166
|
cell,
|
|
156
167
|
is_dispatch,
|
|
168
|
+
is_merge,
|
|
157
169
|
is_number,
|
|
158
170
|
is_stage,
|
|
159
171
|
medians,
|
|
@@ -2,6 +2,7 @@ import { readdirSync } from 'node:fs'
|
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import { repository_lock } from '#scripts/git/repository-lock'
|
|
4
4
|
import { session_cite } from '#scripts/issue/session-cite'
|
|
5
|
+
import { durable_state } from '#scripts/josh/durable-state'
|
|
5
6
|
import { stamp_file } from '#scripts/josh/stamp-file'
|
|
6
7
|
import { figure_format } from '#scripts/lib/figure-format'
|
|
7
8
|
import { json_value } from '#scripts/lib/json-value'
|
|
@@ -12,10 +13,10 @@ import { z } from 'zod'
|
|
|
12
13
|
// the lane commands (joshuafolkken/kit#4268), so a reader asks the record rather than guessing from
|
|
13
14
|
// the `.env` mtime, the event stream or the `ps` state.
|
|
14
15
|
//
|
|
15
|
-
// **It is a `
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
16
|
+
// **It is a `durable_state` path keyed on the common git directory**, in
|
|
17
|
+
// `<common git dir>/josh/run-state` beside the carry record and the event stream and outside every
|
|
18
|
+
// work tree, so it is the same file from the main checkout and from inside the lane, it outlives
|
|
19
|
+
// `lane:close`'s removal of the lane, and a reboot does not clear it.
|
|
19
20
|
//
|
|
20
21
|
// **The write is `stamp_file.replace_stamp`'s** — a temporary file beside the target, renamed over it —
|
|
21
22
|
// so two commands writing the same lane at once leave one whole record, never a torn one. **The read,
|
|
@@ -26,7 +27,7 @@ import { z } from 'zod'
|
|
|
26
27
|
// warned about and the command carries on, as it does when the record cannot be written at all — the
|
|
27
28
|
// record never fails the command that keeps it.
|
|
28
29
|
|
|
29
|
-
const STATE_PREFIX =
|
|
30
|
+
const STATE_PREFIX = durable_state.PREFIX.LANE_STATE
|
|
30
31
|
const STATE_SUFFIX = '.json'
|
|
31
32
|
const LOCK_SUFFIX = '.lock'
|
|
32
33
|
// A change holds the lock for one read and one rename; a wait this long means a holder is stuck.
|
|
@@ -85,7 +86,7 @@ type RecordOutcome =
|
|
|
85
86
|
{ kind: 'written'; record: LaneStateRecord } | { kind: 'skipped'; reason: string }
|
|
86
87
|
|
|
87
88
|
function state_path(directory: string, issue: string): string {
|
|
88
|
-
return
|
|
89
|
+
return durable_state.path(STATE_PREFIX, directory, `-${issue}${STATE_SUFFIX}`)
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
function is_allowed(from: LaneState | undefined, to: LaneState): boolean {
|
|
@@ -180,9 +181,10 @@ async function outcome_of(change: LaneChange, options: StateOptions): Promise<Re
|
|
|
180
181
|
return apply(change, directory, options.now ?? new Date())
|
|
181
182
|
}
|
|
182
183
|
|
|
183
|
-
|
|
184
|
+
// A write that threw is a write skipped for that reason, never an error out of the lane command.
|
|
185
|
+
async function settled(write: () => Promise<RecordOutcome>): Promise<RecordOutcome> {
|
|
184
186
|
try {
|
|
185
|
-
return await
|
|
187
|
+
return await write()
|
|
186
188
|
} catch (error: unknown) {
|
|
187
189
|
return { kind: 'skipped', reason: error instanceof Error ? error.message : String(error) }
|
|
188
190
|
}
|
|
@@ -192,7 +194,7 @@ async function record_change(
|
|
|
192
194
|
change: LaneChange,
|
|
193
195
|
options: StateOptions = {},
|
|
194
196
|
): Promise<RecordOutcome> {
|
|
195
|
-
const outcome = await
|
|
197
|
+
const outcome = await settled(async () => await outcome_of(change, options))
|
|
196
198
|
|
|
197
199
|
if (outcome.kind === 'skipped') warn(change, outcome.reason)
|
|
198
200
|
|
|
@@ -255,6 +257,35 @@ async function record_stuck(
|
|
|
255
257
|
return locked(root, issue, () => stuck_held(issue, stuck, root))
|
|
256
258
|
}
|
|
257
259
|
|
|
260
|
+
function adopted_held(change: LaneChange, directory: string, now: Date): RecordOutcome {
|
|
261
|
+
if (read_record(directory, change.issue) !== undefined) {
|
|
262
|
+
return { kind: 'skipped', reason: 'a record exists' }
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return apply_held(change, directory, now)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Write `change` for a lane that has no record, and only then: a record that appeared since the caller
|
|
270
|
+
* read none is the lane command's, and is never overwritten (`lane:adopt`).
|
|
271
|
+
*/
|
|
272
|
+
async function adopted_outcome(change: LaneChange, options: StateOptions): Promise<RecordOutcome> {
|
|
273
|
+
const directory = await resolve_directory(options.directory)
|
|
274
|
+
|
|
275
|
+
if (directory === undefined) return NO_DIRECTORY
|
|
276
|
+
|
|
277
|
+
const now = options.now ?? new Date()
|
|
278
|
+
|
|
279
|
+
return locked(directory, change.issue, () => adopted_held(change, directory, now))
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
async function record_adopted(
|
|
283
|
+
change: LaneChange,
|
|
284
|
+
options: StateOptions = {},
|
|
285
|
+
): Promise<RecordOutcome> {
|
|
286
|
+
return await settled(async () => await adopted_outcome(change, options))
|
|
287
|
+
}
|
|
288
|
+
|
|
258
289
|
/** Each of `issues`' records, by issue; an issue with none is left out. */
|
|
259
290
|
async function read_states(
|
|
260
291
|
issues: ReadonlyArray<string>,
|
|
@@ -293,6 +324,7 @@ const lane_state = {
|
|
|
293
324
|
read_records,
|
|
294
325
|
read_state,
|
|
295
326
|
read_states,
|
|
327
|
+
record_adopted,
|
|
296
328
|
record_change,
|
|
297
329
|
record_stuck,
|
|
298
330
|
state_path,
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { RunEvent } from '#scripts/run/event/run-event-stream'
|
|
2
|
+
import { lane_check_stats } from './lane-check-stats'
|
|
3
|
+
import { lane_ci_path_stats } from './lane-ci-path-stats'
|
|
4
|
+
import { lane_claim_stats } from './lane-claim-stats'
|
|
5
|
+
import { lane_core_wait_stats } from './lane-core-wait-stats'
|
|
6
|
+
import { lane_gap_stats } from './lane-gap-stats'
|
|
7
|
+
import { lane_held_stats } from './lane-held-stats'
|
|
8
|
+
import { lane_implement_stats } from './lane-implement-stats'
|
|
9
|
+
import type { lane_ledger } from './lane-ledger'
|
|
10
|
+
import { lane_paused_spans } from './lane-paused-spans'
|
|
11
|
+
import { lane_process_stats } from './lane-process-stats'
|
|
12
|
+
import { lane_round_one_stats } from './lane-round-one-stats'
|
|
13
|
+
import { lane_round_two_stats } from './lane-round-two-stats'
|
|
14
|
+
import { lane_ship_lap_stats } from './lane-ship-lap-stats'
|
|
15
|
+
import { lane_split_stats } from './lane-split-stats'
|
|
16
|
+
import { lane_stage_stats } from './lane-stage-stats'
|
|
17
|
+
import type { StatsWindow } from './lane-stats'
|
|
18
|
+
import { lane_stop_stats } from './lane-stop-stats'
|
|
19
|
+
import { lane_test_related_stats } from './lane-test-related-stats'
|
|
20
|
+
import type { ToolCall } from './lane-transcript-calls'
|
|
21
|
+
import { lane_transcript_stats } from './lane-transcript-stats'
|
|
22
|
+
|
|
23
|
+
// The tables `josh lane:stats` prints under the period's row — the single source `josh lane:value
|
|
24
|
+
// cell` reads one cell of (joshuafolkken/kit#5144), so a measurement never copies an aggregation.
|
|
25
|
+
|
|
26
|
+
interface PeriodRecords {
|
|
27
|
+
entries: ReturnType<typeof lane_ledger.read_entries>
|
|
28
|
+
events: ReadonlyArray<RunEvent>
|
|
29
|
+
calls: ReadonlyArray<ToolCall>
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// The tables under the period's row, in the order `lane:stats` prints them.
|
|
33
|
+
function tables_of({ entries, events, calls }: PeriodRecords, window: StatsWindow): Array<string> {
|
|
34
|
+
return [
|
|
35
|
+
lane_stage_stats.table(entries, window),
|
|
36
|
+
lane_ship_lap_stats.table(entries, window),
|
|
37
|
+
lane_ci_path_stats.table(entries, window),
|
|
38
|
+
lane_implement_stats.table(calls, window, lane_paused_spans.by_lane(entries)),
|
|
39
|
+
lane_stop_stats.table(entries, window, events),
|
|
40
|
+
lane_gap_stats.table(entries, window, events),
|
|
41
|
+
lane_round_one_stats.table(entries, window),
|
|
42
|
+
lane_round_two_stats.table(entries, window),
|
|
43
|
+
lane_split_stats.table(entries, window),
|
|
44
|
+
lane_held_stats.table(entries, window),
|
|
45
|
+
lane_core_wait_stats.table(entries, window),
|
|
46
|
+
lane_process_stats.table(entries, window),
|
|
47
|
+
lane_check_stats.table(entries, window),
|
|
48
|
+
lane_claim_stats.table(entries, window),
|
|
49
|
+
lane_test_related_stats.table(entries, window),
|
|
50
|
+
lane_test_related_stats.trigger_table(entries, window),
|
|
51
|
+
lane_transcript_stats.table(calls, window),
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const lane_stats_tables = { tables_of }
|
|
56
|
+
|
|
57
|
+
export type { PeriodRecords }
|
|
58
|
+
export { lane_stats_tables }
|
|
@@ -2,6 +2,7 @@ import { machine_capacity } from '#scripts/gate/machine-capacity'
|
|
|
2
2
|
import { MS_PER_MINUTE } from '#scripts/lib/timeouts'
|
|
3
3
|
import type { DispatchEntry, GateEntry, LedgerEntry, LoadEntry, MergeEntry } from './lane-ledger'
|
|
4
4
|
import { lane_sampler } from './lane-sampler'
|
|
5
|
+
import { lane_tail_stats } from './lane-tail-stats'
|
|
5
6
|
|
|
6
7
|
// The lane-limit measurement's one table row: the ledger entries of one period
|
|
7
8
|
// reduced to throughput, gate duration and machine load, in the column order
|
|
@@ -41,6 +42,8 @@ const COLUMNS = [
|
|
|
41
42
|
'merges / hour',
|
|
42
43
|
'effective lanes',
|
|
43
44
|
'lane median (min)',
|
|
45
|
+
`lanes over ${String(lane_tail_stats.OVERRUN_LANE_MINUTES)} min`,
|
|
46
|
+
'lane p90 (min)',
|
|
44
47
|
'gate median (min)',
|
|
45
48
|
'gate max (min)',
|
|
46
49
|
'load peak',
|
|
@@ -236,17 +239,30 @@ function lane_minutes(
|
|
|
236
239
|
|
|
237
240
|
// One merge's lane time runs from the latest dispatch of its issue — looked up in the whole ledger,
|
|
238
241
|
// since a lane may start before the window — to the merge. A merge no dispatch preceded is skipped.
|
|
239
|
-
function
|
|
242
|
+
function merge_minutes(
|
|
240
243
|
entries: ReadonlyArray<LedgerEntry>,
|
|
241
244
|
period: ReadonlyArray<LedgerEntry>,
|
|
242
|
-
):
|
|
245
|
+
): Array<number> {
|
|
243
246
|
const dispatches = entries.filter(is_dispatch)
|
|
244
|
-
|
|
247
|
+
|
|
248
|
+
return period
|
|
245
249
|
.filter((entry) => is_merge(entry))
|
|
246
250
|
.map((merge) => lane_minutes(dispatches, merge))
|
|
247
251
|
.filter(is_number)
|
|
252
|
+
}
|
|
248
253
|
|
|
249
|
-
|
|
254
|
+
// The median lane, then its tail (`lane-tail-stats.ts`).
|
|
255
|
+
function lane_cells(
|
|
256
|
+
entries: ReadonlyArray<LedgerEntry>,
|
|
257
|
+
period: ReadonlyArray<LedgerEntry>,
|
|
258
|
+
): Array<string> {
|
|
259
|
+
const minutes = merge_minutes(entries, period)
|
|
260
|
+
|
|
261
|
+
return [
|
|
262
|
+
cell(median(minutes)),
|
|
263
|
+
String(lane_tail_stats.overrun_count(minutes)),
|
|
264
|
+
cell(lane_tail_stats.tail_minutes(minutes)),
|
|
265
|
+
]
|
|
250
266
|
}
|
|
251
267
|
|
|
252
268
|
// A reused gate ran no check, so its few milliseconds would pull the median toward a gate that never ran.
|
|
@@ -301,7 +317,7 @@ function row(entries: ReadonlyArray<LedgerEntry>, window: StatsWindow, label: Ro
|
|
|
301
317
|
label.limit,
|
|
302
318
|
String(label.period_days),
|
|
303
319
|
...throughput_cells(period),
|
|
304
|
-
|
|
320
|
+
...lane_cells(entries, period),
|
|
305
321
|
...gate_cells(period),
|
|
306
322
|
...load_cells(period.filter(is_load)),
|
|
307
323
|
])
|