@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
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { gate_labels } from './gate-labels'
|
|
2
|
+
import type { GateCheck } from './gate-plan'
|
|
3
|
+
|
|
4
|
+
// **CI runs the static set as three parallel legs, and each leg is still `josh gate`**
|
|
5
|
+
// (joshuafolkken/kit#5215). One runner ran all seven checks for about four minutes while every unit
|
|
6
|
+
// shard was done in two, so `static-checks` was the merge's critical path. The legs are a matrix over
|
|
7
|
+
// the names below, each running `pnpm josh gate --no-unit --static-group=<name>`, so CI keeps the
|
|
8
|
+
// gate's one definition of every check and its all-failures-in-one-pass summary rather than restating
|
|
9
|
+
// the commands per job. `gate-static-group.test.ts` pins the partition: every static check is in
|
|
10
|
+
// exactly one group, and the workflow's matrix names exactly these groups.
|
|
11
|
+
//
|
|
12
|
+
// The split follows the weights: lint alone (the cold-cache outlier), the type check with the
|
|
13
|
+
// unused-export walk (both build a TypeScript program), and the light rest together.
|
|
14
|
+
const STATIC_GROUP_FLAG_PREFIX = '--static-group='
|
|
15
|
+
|
|
16
|
+
const STATIC_GROUPS: Readonly<Record<string, ReadonlyArray<string>>> = {
|
|
17
|
+
lint: [gate_labels.LINT_LABEL],
|
|
18
|
+
types: [gate_labels.TYPE_CHECK_LABEL, gate_labels.EXPORTS_LABEL],
|
|
19
|
+
rest: [
|
|
20
|
+
gate_labels.SPELL_CHECK_LABEL,
|
|
21
|
+
gate_labels.BEHAVIOR_LABEL,
|
|
22
|
+
gate_labels.METRICS_LABEL,
|
|
23
|
+
gate_labels.LOCKFILE_LABEL,
|
|
24
|
+
],
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// The group an argument names, or `undefined` when it is not the flag or names no group — so an
|
|
28
|
+
// unknown group is refused with every other unknown argument.
|
|
29
|
+
function group_of(argument: string): string | undefined {
|
|
30
|
+
if (!argument.startsWith(STATIC_GROUP_FLAG_PREFIX)) return undefined
|
|
31
|
+
|
|
32
|
+
const name = argument.slice(STATIC_GROUP_FLAG_PREFIX.length)
|
|
33
|
+
|
|
34
|
+
return Object.hasOwn(STATIC_GROUPS, name) ? name : undefined
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function find_group(arguments_: ReadonlyArray<string>): string | undefined {
|
|
38
|
+
return arguments_.map((argument) => group_of(argument)).find((name) => name !== undefined)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function narrow_checks(
|
|
42
|
+
checks: ReadonlyArray<GateCheck>,
|
|
43
|
+
group: string | undefined,
|
|
44
|
+
): ReadonlyArray<GateCheck> {
|
|
45
|
+
if (group === undefined) return checks
|
|
46
|
+
|
|
47
|
+
const labels = STATIC_GROUPS[group] ?? []
|
|
48
|
+
|
|
49
|
+
return checks.filter((check) => labels.includes(check.label))
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const gate_static_group = {
|
|
53
|
+
STATIC_GROUPS,
|
|
54
|
+
STATIC_GROUP_FLAG_PREFIX,
|
|
55
|
+
find_group,
|
|
56
|
+
group_of,
|
|
57
|
+
narrow_checks,
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { gate_static_group }
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { gate_labels } from './gate-labels'
|
|
1
2
|
import { gate_plan, type GateCheck, type GatePlan } from './gate-plan'
|
|
2
3
|
import type { GateStep } from './gate-report'
|
|
3
4
|
import { project_checks } from './project-checks'
|
|
4
5
|
import { type_check_step } from './type-check-step'
|
|
5
6
|
|
|
6
7
|
const JOSH = 'josh'
|
|
7
|
-
const { TYPE_CHECK_LABEL, UNIT_LABEL } =
|
|
8
|
+
const { TYPE_CHECK_LABEL, UNIT_LABEL } = gate_labels
|
|
8
9
|
const UNIT_WORKER_FLAG = '--maxWorkers'
|
|
9
10
|
|
|
10
11
|
function unit_worker_args(check: GateCheck, plan: GatePlan): ReadonlyArray<string> {
|
|
@@ -30,9 +30,11 @@ async function read_changed_files(): Promise<Record<string, string>> {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
// The resolver lives in `git/change-base.ts`, because the review brief
|
|
33
|
-
// needs exactly this reading and a second copy of it is the clone `CLAUDE.md` prohibits.
|
|
33
|
+
// needs exactly this reading and a second copy of it is the clone `CLAUDE.md` prohibits. It is read
|
|
34
|
+
// through a merge in progress, as the file map is (joshuafolkken/kit#5307): a map measured from the
|
|
35
|
+
// later base beside `HEAD`'s older one would let a re-merged default branch reuse a stale record.
|
|
34
36
|
async function read_base(): Promise<string | undefined> {
|
|
35
|
-
return await change_base.
|
|
37
|
+
return await change_base.resolved_through_merge()
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
// The two readings are independent, so they are started together rather than one after the other.
|
|
@@ -103,6 +103,12 @@ interface HookReuse {
|
|
|
103
103
|
source?: string | undefined
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
const ARGUMENTS_MISS = 'arguments were passed to the hook'
|
|
107
|
+
|
|
108
|
+
function force_miss(force_environment: string): string {
|
|
109
|
+
return `${force_environment} is set`
|
|
110
|
+
}
|
|
111
|
+
|
|
106
112
|
// The stamp rather than a boolean, for the same reason `gate_skip.gate_reuse` hands one back: the
|
|
107
113
|
// caller prints `taken_at`, and a record that does not describe this tree has no timestamp worth
|
|
108
114
|
// printing. A refusal carries its reason instead.
|
|
@@ -111,19 +117,30 @@ interface HookReuse {
|
|
|
111
117
|
// asked for that run rather than for a recorded result about a whole tree, and a hook's own line passes
|
|
112
118
|
// none, so this costs it nothing.
|
|
113
119
|
function hook_reuse(input: HookReuse): GateReuse {
|
|
114
|
-
if (input.extra_arguments.length > 0) return { miss:
|
|
115
|
-
if (is_force_requested(input.force_env)) return { miss:
|
|
120
|
+
if (input.extra_arguments.length > 0) return { miss: ARGUMENTS_MISS }
|
|
121
|
+
if (is_force_requested(input.force_env)) return { miss: force_miss(input.force_env) }
|
|
116
122
|
if (!input.is_tree_carried) return { miss: input.carry_miss }
|
|
117
123
|
|
|
118
124
|
return gate_skip.gate_reuse(input.tree.files, input.tree.base, input.source)
|
|
119
125
|
}
|
|
120
126
|
|
|
127
|
+
// joshuafolkken/kit#5234: the kind of a refusal `hook_reuse` answered, the hook's own three refusals
|
|
128
|
+
// told apart before the gate's, so a ledger counts each without a second wording of the sentences.
|
|
129
|
+
function miss_kind(miss: string, input: Pick<HookReuse, 'carry_miss' | 'force_env'>): string {
|
|
130
|
+
if (miss === ARGUMENTS_MISS) return 'arguments'
|
|
131
|
+
if (miss === force_miss(input.force_env)) return 'forced'
|
|
132
|
+
if (miss === input.carry_miss) return 'tree-not-carried'
|
|
133
|
+
|
|
134
|
+
return gate_skip.miss_kind(miss)
|
|
135
|
+
}
|
|
136
|
+
|
|
121
137
|
const hook_gate_reuse = {
|
|
122
138
|
GATE_REUSING_TARGETS,
|
|
123
139
|
hook_reuse,
|
|
124
140
|
is_force_requested,
|
|
125
141
|
is_index_matching_worktree,
|
|
126
142
|
is_worktree_clean,
|
|
143
|
+
miss_kind,
|
|
127
144
|
read_status_lines,
|
|
128
145
|
}
|
|
129
146
|
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { buffered_process } from '#scripts/lib/buffered-process'
|
|
2
|
+
import { release_approval_prune } from '#scripts/release/release-approval-prune'
|
|
3
|
+
import { project_checks } from './project-checks'
|
|
4
|
+
|
|
5
|
+
// kit's metrics ratchet totals (`josh metrics --totals-only`), brought forward from the detached
|
|
6
|
+
// `josh ship`'s pre-detach checks to the implementation loop: a feature grows a total almost every
|
|
7
|
+
// time, and a growth first met at the pre-detach stop costs a ship re-run beside the
|
|
8
|
+
// `josh metrics --accept` (joshuafolkken/kit#4594). `josh lint:related` reports it as a notice, never a
|
|
9
|
+
// failure, so a total that grows again within the loop does not demand an accept per edit; the
|
|
10
|
+
// pre-detach check stays the stop. A consumer's kit has no `josh metrics`, so it runs in kit alone.
|
|
11
|
+
|
|
12
|
+
const METRICS_TOTALS_COMMAND: ReadonlyArray<string> = ['josh', 'metrics', '--totals-only']
|
|
13
|
+
// The form ship runs before the detach and before each scoped pair: it also re-records a growth the
|
|
14
|
+
// branch's approval names (joshuafolkken/kit#4716).
|
|
15
|
+
const METRICS_RERECORD_COMMAND: ReadonlyArray<string> = [...METRICS_TOTALS_COMMAND, '--rerecord']
|
|
16
|
+
// Neutral on the cause: a growth and a run that never finished both stop the pre-detach check.
|
|
17
|
+
const NOTICE_HEADING =
|
|
18
|
+
'⚠ josh metrics --totals-only did not pass — settle it before `josh ship`, or the pre-detach check stops the ship (a total the branch approval names is re-recorded there):'
|
|
19
|
+
|
|
20
|
+
async function growth_notice(directory: string): Promise<string | undefined> {
|
|
21
|
+
if (!project_checks.is_kit_repository(directory)) return undefined
|
|
22
|
+
|
|
23
|
+
const result = await buffered_process.run_buffered_process(METRICS_TOTALS_COMMAND, {
|
|
24
|
+
cwd: directory,
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
if (!buffered_process.is_process_failed(result)) return undefined
|
|
28
|
+
|
|
29
|
+
return `${NOTICE_HEADING}\n${result.output.trim()}`
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function carries_approval(files: Readonly<Record<string, string>>): boolean {
|
|
33
|
+
return Object.keys(files).some((file) => release_approval_prune.is_approval(file))
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Re-records the branch's approval before a scoped pair reads the tree, so a review fix that grows a
|
|
37
|
+
// named total again does not stop the gate after it (joshuafolkken/kit#4716). It runs only where the
|
|
38
|
+
// changed tree carries an approval, and answers whether it ran; its verdict is left to the gate's own
|
|
39
|
+
// metrics step.
|
|
40
|
+
async function rerecord(
|
|
41
|
+
directory: string,
|
|
42
|
+
files: Readonly<Record<string, string>>,
|
|
43
|
+
): Promise<boolean> {
|
|
44
|
+
if (!project_checks.is_kit_repository(directory) || !carries_approval(files)) return false
|
|
45
|
+
|
|
46
|
+
await buffered_process.run_buffered_process(METRICS_RERECORD_COMMAND, { cwd: directory })
|
|
47
|
+
|
|
48
|
+
return true
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const metrics_totals = {
|
|
52
|
+
METRICS_RERECORD_COMMAND,
|
|
53
|
+
METRICS_TOTALS_COMMAND,
|
|
54
|
+
NOTICE_HEADING,
|
|
55
|
+
growth_notice,
|
|
56
|
+
rerecord,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export { metrics_totals }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { file_map_stamp, type FileMapStampAccess } from '#scripts/josh/file-map-stamp'
|
|
2
2
|
import { hook_decision } from '#scripts/josh/hook-decision'
|
|
3
|
-
import {
|
|
3
|
+
import { run_record_path } from '#scripts/josh/run-record-path'
|
|
4
4
|
import { review_stamps } from '#scripts/review/review-stamps'
|
|
5
5
|
import { test_unit_guard } from '#scripts/test/test-unit-guard'
|
|
6
6
|
import { gate_tree, type GateTree } from './gate-tree'
|
|
@@ -12,16 +12,20 @@ import { gate_tree, type GateTree } from './gate-tree'
|
|
|
12
12
|
// tree neither check has read return their findings one round trip at a time; one call running both
|
|
13
13
|
// checks first returns most of them at once.
|
|
14
14
|
//
|
|
15
|
-
// **It fixes when the checks run,
|
|
15
|
+
// **It fixes when the checks run, and only one writer decides whether.** Nothing here skips a check or
|
|
16
16
|
// reinterprets its output, and `josh gate` still runs its four checks exactly as before. The one other
|
|
17
17
|
// reader is the checks' own re-run, which narrows to what moved since this record (`since-green.ts`).
|
|
18
|
+
// The one writer without a run behind it is `josh ship`'s scoped pair after a merge with the default
|
|
19
|
+
// branch that shares nothing with the branch (`run-ship-synced-scope.ts`, joshuafolkken/kit#4985).
|
|
18
20
|
//
|
|
19
21
|
// **The judgement is the gate's own, not a second one.** "There is a record and nothing it covers has
|
|
20
|
-
// moved" is `
|
|
22
|
+
// moved" is `file_map_stamp.changed_since` plus the base equality `gate_skip.reusable_green_gate`
|
|
21
23
|
// already compares and the inputs fingerprint each record carries (`verification-inputs.ts`), over the
|
|
22
|
-
// same `FileMapStamp` shape written to the same kind of file. A second
|
|
23
|
-
//
|
|
24
|
-
//
|
|
24
|
+
// same `FileMapStamp` shape written to the same kind of file. A second definition of "this tree is
|
|
25
|
+
// unchanged" is the clone `CLAUDE.md` prohibits, and it is exactly where two commands would start
|
|
26
|
+
// disagreeing about one working tree. The one deliberate difference: this reader ignores josh's own
|
|
27
|
+
// `.josh/` run records, while the gate's own reuse (`gate_skip` via `review_brief.matching_stamp`)
|
|
28
|
+
// does not — safe, because the gate still lints and tests those records.
|
|
25
29
|
//
|
|
26
30
|
// **It refuses `josh review:brief`, and now the local `josh gate` too, but never CI's**.
|
|
27
31
|
// The brief was the first refusal point because it is where `review:attest`
|
|
@@ -56,11 +60,13 @@ interface ScopedCheck {
|
|
|
56
60
|
// The record paths, overridable so a test can plant one without overwriting the record a real run in
|
|
57
61
|
// this checkout relies on — the same reason `gate_skip.reusable_green_gate` takes a `source`.
|
|
58
62
|
// `is_unit_skipped` is overridable for the same reason, so a suite running in a checkout with vitest
|
|
59
|
-
// can stand in for a project without one.
|
|
63
|
+
// can stand in for a project without one. `is_lane_child` is the gate's answer for a dispatched lane
|
|
64
|
+
// child, absent for every other caller.
|
|
60
65
|
interface ScopedSources {
|
|
61
66
|
lint?: string
|
|
62
67
|
test?: string
|
|
63
68
|
is_unit_skipped?: boolean
|
|
69
|
+
is_lane_child?: boolean
|
|
64
70
|
}
|
|
65
71
|
|
|
66
72
|
// **`test:related` is required only where it can ever answer**. In a project
|
|
@@ -88,15 +94,26 @@ function checks_of(sources: ScopedSources): ReadonlyArray<ScopedCheck> {
|
|
|
88
94
|
: [lint, test]
|
|
89
95
|
}
|
|
90
96
|
|
|
97
|
+
// **A record josh itself keeps under `.josh/` does not unseat a green record** (joshuafolkken/kit#4905):
|
|
98
|
+
// `metrics --accept` and the ship's own approval re-record write there after the pair passed, and the
|
|
99
|
+
// preflight re-ran both checks over nothing but that bookkeeping. The gate still lints and tests the
|
|
100
|
+
// whole change, and a later scoped run reads such a file as moved since its record.
|
|
101
|
+
|
|
91
102
|
// **An unreadable record reads as an absent one, and that is the safe direction.** `read` swallows a
|
|
92
103
|
// malformed or foreign file and answers `undefined`, so the two cases are indistinguishable here —
|
|
93
104
|
// and the consequence of treating one as the other is a single 14-second scoped run, against the
|
|
94
105
|
// alternative of briefing a review on a tree nothing has checked.
|
|
95
|
-
function describes_tree(
|
|
96
|
-
|
|
106
|
+
function describes_tree(
|
|
107
|
+
check: ScopedCheck,
|
|
108
|
+
tree: Record<string, string>,
|
|
109
|
+
base: string,
|
|
110
|
+
is_overlooked: (relative: string) => boolean = run_record_path.is_run_record,
|
|
111
|
+
): boolean {
|
|
112
|
+
const stamp = check.stamp.read(check.source)
|
|
97
113
|
|
|
98
114
|
return (
|
|
99
115
|
stamp !== undefined &&
|
|
116
|
+
file_map_stamp.changed_since(stamp, tree).every((relative) => is_overlooked(relative)) &&
|
|
100
117
|
file_map_stamp.describes_base(stamp, base) &&
|
|
101
118
|
check.stamp.describes_inputs(stamp)
|
|
102
119
|
)
|
|
@@ -151,25 +168,60 @@ function missing_scripts(
|
|
|
151
168
|
return stale_checks(tree, base, sources).map((check) => check.script)
|
|
152
169
|
}
|
|
153
170
|
|
|
171
|
+
// The scripts whose green record still describes this tree, which `check:related` need not run again
|
|
172
|
+
// (joshuafolkken/kit#5156). A tree with no answer reuses nothing, never reading silence as green. A
|
|
173
|
+
// moved `.josh/` record counts here: the gate is not behind `check:related` to lint and test it.
|
|
174
|
+
function overlooks_nothing(): boolean {
|
|
175
|
+
return false
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function green_scripts(
|
|
179
|
+
tree: Record<string, string>,
|
|
180
|
+
base: string | undefined,
|
|
181
|
+
sources: ScopedSources = {},
|
|
182
|
+
): ReadonlyArray<string> {
|
|
183
|
+
if (!is_answerable(tree, base)) return []
|
|
184
|
+
|
|
185
|
+
return checks_of(sources)
|
|
186
|
+
.filter((check) => describes_tree(check, tree, base, overlooks_nothing))
|
|
187
|
+
.map((check) => check.script)
|
|
188
|
+
}
|
|
189
|
+
|
|
154
190
|
const REFUSAL_HEADLINE = '⛔ scoped checks not green on this tree'
|
|
155
191
|
|
|
156
192
|
// **The way out travels with the refusal.** A message saying only "not verified" leaves the caller
|
|
157
193
|
// holding the same question and no sanctioned answer, which is how the checks ended up after the
|
|
158
194
|
// review in the first place. So the text names the one command that closes it, what it costs, and
|
|
159
|
-
//
|
|
160
|
-
|
|
195
|
+
// the expected next move: reissuing this call, or for a lane child's gate, handing over to ship.
|
|
196
|
+
const REISSUE_STEP = 'and reissue this command.'
|
|
197
|
+
|
|
198
|
+
// joshuafolkken/kit#4776: a lane child that reissued the gate here ran it in the foreground for three
|
|
199
|
+
// minutes before `ship`, which runs its own gate beside the review, so that green was never used.
|
|
200
|
+
const LANE_CHILD_STEP =
|
|
201
|
+
'then hand over to `pnpm josh ship --detach --review "<title> #<N>"` rather than reissuing the ' +
|
|
202
|
+
'gate — this is a dispatched lane child, and ship runs the gate beside the review ' +
|
|
203
|
+
'(`.claude/skills/workflow-commands/chain-rule.md` step 0).'
|
|
204
|
+
|
|
205
|
+
function refusal(missing: ReadonlyArray<string>, next_step: string): string {
|
|
161
206
|
return (
|
|
162
207
|
`${REFUSAL_HEADLINE}: ${missing.join(' and ')} ` +
|
|
163
208
|
'have not passed on the files this branch changed. The gate and review round 1 start together, ' +
|
|
164
209
|
'so a brief composed now describes a tree neither check has read — joshuafolkken/kit#1503 spent ' +
|
|
165
210
|
'282 seconds, 31% of the run, picking up one lint rule and one failing test at a time after its ' +
|
|
166
211
|
'review had already started. Run them in one call — ' +
|
|
167
|
-
`\`${LINT_COMMAND} && ${TEST_COMMAND}\`, measured at 13.8 seconds —
|
|
168
|
-
'The record fixes when the checks run
|
|
169
|
-
|
|
212
|
+
`\`${LINT_COMMAND} && ${TEST_COMMAND}\`, measured at 13.8 seconds — ${next_step} ` +
|
|
213
|
+
'The record fixes when the checks run: only a merge with the default branch sharing nothing ' +
|
|
214
|
+
"with this branch's change is recorded without a run. " +
|
|
215
|
+
'`.claude/skills/workflow-commands/chain-rule.md` → "Orchestration facts single-sourced here".'
|
|
170
216
|
)
|
|
171
217
|
}
|
|
172
218
|
|
|
219
|
+
// **Only the gate's pre-check sets `is_lane_child`**: a lane child refused at `josh run:review` reissues
|
|
220
|
+
// it as chain-rule step 0 says, so `review:brief`'s callers keep the reissue wording.
|
|
221
|
+
function next_step_of(sources: ScopedSources): string {
|
|
222
|
+
return sources.is_lane_child === true ? LANE_CHILD_STEP : REISSUE_STEP
|
|
223
|
+
}
|
|
224
|
+
|
|
173
225
|
function refusal_for(
|
|
174
226
|
tree: Record<string, string>,
|
|
175
227
|
base: string | undefined,
|
|
@@ -177,7 +229,7 @@ function refusal_for(
|
|
|
177
229
|
): string | undefined {
|
|
178
230
|
const missing = missing_checks(tree, base, sources)
|
|
179
231
|
|
|
180
|
-
return missing.length === 0 ? undefined : refusal(missing)
|
|
232
|
+
return missing.length === 0 ? undefined : refusal(missing, next_step_of(sources))
|
|
181
233
|
}
|
|
182
234
|
|
|
183
235
|
// **A record is written only by a bare invocation, and any argument at all withholds it.** A path
|
|
@@ -254,6 +306,7 @@ const scoped_green = {
|
|
|
254
306
|
SWITCH_ENV_KEY,
|
|
255
307
|
TEST_COMMAND,
|
|
256
308
|
TEST_SCRIPT,
|
|
309
|
+
green_scripts,
|
|
257
310
|
is_recordable_scope,
|
|
258
311
|
is_unmoved,
|
|
259
312
|
missing_checks,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { FileMapStampAccess } from '#scripts/josh/file-map-stamp'
|
|
2
|
-
import { gate_tree } from './gate-tree'
|
|
2
|
+
import { gate_tree, type GateTree } from './gate-tree'
|
|
3
3
|
import { moved_paths, type MovedParts } from './moved-paths'
|
|
4
4
|
import { verification_inputs } from './verification-inputs'
|
|
5
5
|
|
|
@@ -11,7 +11,9 @@ import { verification_inputs } from './verification-inputs'
|
|
|
11
11
|
// **The check is no weaker.** The green record (`scoped-green.ts`) vouches that the check passed over
|
|
12
12
|
// the branch diff of the tree it names; what moved since is every path whose content can differ from
|
|
13
13
|
// that tree (`moved-paths.ts`), a main sync's own changes included. A record written by a narrowed run
|
|
14
|
-
// vouches for the same thing, by the same argument one run earlier
|
|
14
|
+
// vouches for the same thing, by the same argument one run earlier — except a bare `josh test:related`
|
|
15
|
+
// over a file every test imports, which ran only its direct importers, so the gate's unit leg never
|
|
16
|
+
// narrows by it while the branch changes one (`is_green_narrowable` in `test-related.ts`, #5122).
|
|
15
17
|
//
|
|
16
18
|
// **Whatever cannot be narrowed answers `undefined`**, and the caller reads the whole branch change as
|
|
17
19
|
// before: no record, one that cannot be compared, one written under other tools or environment, or a
|
|
@@ -19,6 +21,9 @@ import { verification_inputs } from './verification-inputs'
|
|
|
19
21
|
// says nothing under the new one. An empty list is
|
|
20
22
|
// the positive fact that nothing moved: the gate's unit step on the tree the preflight just passed.
|
|
21
23
|
|
|
24
|
+
// Why a command that found nothing moved ran nothing, in the words both scoped commands print.
|
|
25
|
+
const UNMOVED_REASON = 'nothing moved since its last green run on this checkout'
|
|
26
|
+
|
|
22
27
|
// The narrowing line each command prints before it runs, so a since-green run is never read as one
|
|
23
28
|
// over the whole branch.
|
|
24
29
|
function describe(label: string, moved: ReadonlyArray<string>): string {
|
|
@@ -31,17 +36,19 @@ function is_narrowable(label: string, parts: MovedParts | undefined): parts is M
|
|
|
31
36
|
|
|
32
37
|
// What moved with a main sync's part kept apart, for a caller that records how much of its input the
|
|
33
38
|
// sync brought in (`josh test:related`, joshuafolkken/kit#4465). `label` names the gate check whose
|
|
34
|
-
// declaration (`verification-inputs.ts`) the record vouches for.
|
|
39
|
+
// declaration (`verification-inputs.ts`) the record vouches for. `tree` is the caller's own reading of
|
|
40
|
+
// the gate tree, so a run that also records its green tree reads it once (joshuafolkken/kit#4655).
|
|
35
41
|
async function read_moved_parts(
|
|
36
42
|
stamp: FileMapStampAccess,
|
|
37
43
|
label: string,
|
|
38
44
|
source?: string,
|
|
45
|
+
tree?: GateTree,
|
|
39
46
|
): Promise<MovedParts | undefined> {
|
|
40
47
|
const record = stamp.read(source)
|
|
41
48
|
|
|
42
49
|
if (record === undefined || !stamp.describes_inputs(record)) return undefined
|
|
43
50
|
|
|
44
|
-
const parts = await moved_paths.moved_parts(record, await gate_tree.read_gate_tree())
|
|
51
|
+
const parts = await moved_paths.moved_parts(record, tree ?? (await gate_tree.read_gate_tree()))
|
|
45
52
|
|
|
46
53
|
return is_narrowable(label, parts) ? parts : undefined
|
|
47
54
|
}
|
|
@@ -51,12 +58,13 @@ async function read_moved(
|
|
|
51
58
|
stamp: FileMapStampAccess,
|
|
52
59
|
label: string,
|
|
53
60
|
source?: string,
|
|
61
|
+
tree?: GateTree,
|
|
54
62
|
): Promise<ReadonlyArray<string> | undefined> {
|
|
55
|
-
const parts = await read_moved_parts(stamp, label, source)
|
|
63
|
+
const parts = await read_moved_parts(stamp, label, source, tree)
|
|
56
64
|
|
|
57
65
|
return parts === undefined ? undefined : moved_paths.union_of(parts)
|
|
58
66
|
}
|
|
59
67
|
|
|
60
|
-
const since_green = { describe, read_moved, read_moved_parts }
|
|
68
|
+
const since_green = { UNMOVED_REASON, describe, read_moved, read_moved_parts }
|
|
61
69
|
|
|
62
70
|
export { since_green }
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { project_checks } from '#scripts/gate/project-checks'
|
|
2
|
+
import type { ChangedFileScope } from '#scripts/git/changed-file-scope'
|
|
3
|
+
import { buffered_process, type BufferedProcessResult } from '#scripts/lib/buffered-process'
|
|
4
|
+
|
|
5
|
+
// The guard tests that judge source text alone, yet run only in `josh test:related` or a detached
|
|
6
|
+
// ship's pre-detach stop: a bare Issue citation, a source with no colocated test and a `gh` spawn
|
|
7
|
+
// outside `gh api` (the static half of the network guard; the calls a test *makes* are observed by
|
|
8
|
+
// `test-network-guard.ts`, which only a run can answer). `josh lint:related` runs them beside its
|
|
9
|
+
// lint, so a between-edits loop meets them in seconds rather than at the ship (joshuafolkken/kit#4643).
|
|
10
|
+
// The targets are the pre-detach stop's too, so the two never drift.
|
|
11
|
+
//
|
|
12
|
+
// `josh exports:unused` stays out: its whole-program type-checker pass is several times the lint's
|
|
13
|
+
// own wall clock. `josh lint:related` runs its narrowed members check after a green lint instead
|
|
14
|
+
// (joshuafolkken/kit#4645).
|
|
15
|
+
//
|
|
16
|
+
// They run in kit alone: the guard tests are kit's own, and a consumer meets the pre-detach static
|
|
17
|
+
// checks there. A change with no `.ts` file in it moves none of their verdicts.
|
|
18
|
+
|
|
19
|
+
// A present directory need not hold a test the project's Vitest includes — a consumer's own
|
|
20
|
+
// `scripts/claude` of shell helpers, say — and a filter that matches nothing would stop every ship.
|
|
21
|
+
const GUARD_TEST_COMMAND: ReadonlyArray<string> = ['josh', 'test:unit', '--passWithNoTests']
|
|
22
|
+
const STRUCTURAL_GUARD_TARGETS: ReadonlyArray<string> = [
|
|
23
|
+
'scripts/issue/session-cite-scan.test.ts',
|
|
24
|
+
'tools/test/untested-sources.test.ts',
|
|
25
|
+
'tools/gh/gh-subcommand-guard.test.ts',
|
|
26
|
+
]
|
|
27
|
+
const STRUCTURAL_LISTS: ReadonlyArray<ReadonlyArray<string>> = [
|
|
28
|
+
[...GUARD_TEST_COMMAND, ...STRUCTURAL_GUARD_TARGETS],
|
|
29
|
+
]
|
|
30
|
+
const TYPESCRIPT_SUFFIX = '.ts'
|
|
31
|
+
const FAILURE_EXIT_CODE = 1
|
|
32
|
+
|
|
33
|
+
interface StructuralRun {
|
|
34
|
+
list: ReadonlyArray<string>
|
|
35
|
+
result: BufferedProcessResult
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// The front of a failed check's heading — `josh lane:value metrics-stops` counts a ship output that
|
|
39
|
+
// carries the metrics totals' one.
|
|
40
|
+
function failure_prefix(list: ReadonlyArray<string>): string {
|
|
41
|
+
return `✗ ${list.join(' ')} — `
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Each failure is headed by the check's own command and how it ended: a check that failed with no
|
|
45
|
+
// output of its own (`ELIFECYCLE Command failed` alone, or nothing) otherwise names nothing to fix.
|
|
46
|
+
function failure_heading(list: ReadonlyArray<string>, result: BufferedProcessResult): string {
|
|
47
|
+
const ending =
|
|
48
|
+
result.exit_code === undefined
|
|
49
|
+
? 'no exit code (timed out or ended by a signal)'
|
|
50
|
+
: `exit code ${String(result.exit_code)}`
|
|
51
|
+
|
|
52
|
+
return `${failure_prefix(list)}${ending}`
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function failure_section(list: ReadonlyArray<string>, result: BufferedProcessResult): string {
|
|
56
|
+
const parts = [failure_heading(list, result), result.output.trim()]
|
|
57
|
+
|
|
58
|
+
return parts.filter((part) => part !== '').join('\n')
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// The whole-tree fallback is due as the narrowed run with a source in it is; both stay kit-only.
|
|
62
|
+
function is_due(scope: ChangedFileScope, root: string): boolean {
|
|
63
|
+
if (!project_checks.is_kit_repository(root)) return false
|
|
64
|
+
|
|
65
|
+
return scope.mode === 'all' || scope.files.some((file) => file.endsWith(TYPESCRIPT_SUFFIX))
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function run_in(root: string, list: ReadonlyArray<string>): Promise<StructuralRun> {
|
|
69
|
+
return { list, result: await buffered_process.run_buffered_process(list, { cwd: root }) }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// All at once and buffered, every failure reported, so one run shows all there is to fix.
|
|
73
|
+
async function run_structural(scope: ChangedFileScope, root: string): Promise<number> {
|
|
74
|
+
if (!is_due(scope, root)) return 0
|
|
75
|
+
|
|
76
|
+
const runs = await Promise.all(STRUCTURAL_LISTS.map(async (list) => await run_in(root, list)))
|
|
77
|
+
const failed = runs.filter(({ result }) => buffered_process.is_process_failed(result))
|
|
78
|
+
|
|
79
|
+
if (failed.length === 0) return 0
|
|
80
|
+
|
|
81
|
+
const sections = failed.map(({ list, result }) => failure_section(list, result))
|
|
82
|
+
|
|
83
|
+
process.stdout.write(`\n${sections.join('\n\n')}\n`)
|
|
84
|
+
|
|
85
|
+
return FAILURE_EXIT_CODE
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const structural_checks = {
|
|
89
|
+
GUARD_TEST_COMMAND,
|
|
90
|
+
STRUCTURAL_GUARD_TARGETS,
|
|
91
|
+
failure_prefix,
|
|
92
|
+
failure_section,
|
|
93
|
+
run_structural,
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export { structural_checks }
|
|
@@ -3,7 +3,8 @@ import { fileURLToPath } from 'node:url'
|
|
|
3
3
|
import type { FileMapStamp } from '#scripts/josh/file-map-stamp'
|
|
4
4
|
import { GATE_COMMAND } from '#scripts/josh/josh-command-types'
|
|
5
5
|
import { composite_arguments, USAGE_ERROR_EXIT_CODE } from '#scripts/josh/josh-composite-arguments'
|
|
6
|
-
import {
|
|
6
|
+
import { lane_child_marker } from '#scripts/lane/lane-child-marker'
|
|
7
|
+
import { lane_ledger_write } from '#scripts/lane/lane-ledger-write'
|
|
7
8
|
import { FAIL_EXIT_CODE } from '#scripts/lib/buffered-process'
|
|
8
9
|
import { review_stamps } from '#scripts/review/review-stamps'
|
|
9
10
|
import { review_tree } from '#scripts/review/review-tree'
|
|
@@ -14,6 +15,7 @@ import { gate_plan, type GatePlan } from './gate-plan'
|
|
|
14
15
|
import { gate_report, type GateStepResult } from './gate-report'
|
|
15
16
|
import { gate_run_steps, type ReusedChecks } from './gate-run-steps'
|
|
16
17
|
import { gate_skip } from './gate-skip'
|
|
18
|
+
import { gate_static_group } from './gate-static-group'
|
|
17
19
|
import { build_gate_step, build_gate_steps, UNIT_WORKER_FLAG } from './gate-steps'
|
|
18
20
|
import { gate_tree, type GateTree } from './gate-tree'
|
|
19
21
|
import { project_checks } from './project-checks'
|
|
@@ -168,15 +170,26 @@ async function run_marked_gate<T>(
|
|
|
168
170
|
// **The free cores do not cap the plan** (joshuafolkken/kit#4167). The unit claim's admission narrows it
|
|
169
171
|
// to the room the outside load leaves, read over its wait rather than once at the gate's start — a
|
|
170
172
|
// width fixed off one busy instant held for the whole suite (`core_admission.is_too_narrow`).
|
|
171
|
-
|
|
173
|
+
//
|
|
174
|
+
// A `--static-group` narrows the resolved plan's checks and keeps its concurrency, which the full static
|
|
175
|
+
// set sized: a cap above the narrowed count never binds.
|
|
176
|
+
function announce_gate_plan(
|
|
177
|
+
is_unit_included: boolean,
|
|
178
|
+
available_cores: number,
|
|
179
|
+
static_group?: string,
|
|
180
|
+
): GatePlan {
|
|
172
181
|
const concurrent_runs = unit_worker_share.live_run_count() + unit_worker_share.SOLO_RUNS
|
|
173
182
|
const is_kit_repository = project_checks.is_kit_repository(process.cwd())
|
|
174
|
-
const
|
|
183
|
+
const resolved = gate_plan.resolve_gate_plan(
|
|
175
184
|
available_cores,
|
|
176
185
|
concurrent_runs,
|
|
177
186
|
is_unit_included,
|
|
178
187
|
is_kit_repository,
|
|
179
188
|
)
|
|
189
|
+
const plan = {
|
|
190
|
+
...resolved,
|
|
191
|
+
checks: gate_static_group.narrow_checks(resolved.checks, static_group),
|
|
192
|
+
}
|
|
180
193
|
|
|
181
194
|
process.stdout.write(`${gate_plan.format_gate_plan(plan, available_cores, concurrent_runs)}\n`)
|
|
182
195
|
|
|
@@ -195,6 +208,8 @@ interface GateOptions {
|
|
|
195
208
|
// Whether the unit suite is one of this gate's checks. Defaults to true everywhere; only
|
|
196
209
|
// `--no-unit` turns it off, for the CI job that runs the suite on a runner of its own.
|
|
197
210
|
is_unit_included?: boolean
|
|
211
|
+
// The one static group a CI matrix leg runs (`gate-static-group.ts`); set only with the unit suite off.
|
|
212
|
+
static_group?: string | undefined
|
|
198
213
|
stamp_path?: string
|
|
199
214
|
marker_path?: string
|
|
200
215
|
// The gate log's destination, a parameter for the same reason the two above are: this suite runs
|
|
@@ -253,7 +268,10 @@ function scoped_precheck_refusal(tree: GateTree, options: GateOptions): string |
|
|
|
253
268
|
return undefined
|
|
254
269
|
}
|
|
255
270
|
|
|
256
|
-
return scoped_green.refusal_for(tree.files, tree.base,
|
|
271
|
+
return scoped_green.refusal_for(tree.files, tree.base, {
|
|
272
|
+
is_lane_child: lane_child_marker.is_child_of(process.cwd()),
|
|
273
|
+
...options.scoped_sources,
|
|
274
|
+
})
|
|
257
275
|
}
|
|
258
276
|
|
|
259
277
|
// **A partial gate records nothing green, and this is the same rule as the skip one layer out**.
|
|
@@ -318,7 +336,7 @@ async function run_checked_gate(
|
|
|
318
336
|
// Resolved at the gate's entry, before this gate sets `JOSH_UNIT_RUN_MARKED`, so a gate nested in the
|
|
319
337
|
// unit suite reads the flag as set and reserves nothing.
|
|
320
338
|
const budget = gate_run_steps.default_budget()
|
|
321
|
-
const plan = announce_gate_plan(is_unit_included, budget.available_cores)
|
|
339
|
+
const plan = announce_gate_plan(is_unit_included, budget.available_cores, options.static_group)
|
|
322
340
|
const reused = await checks_to_reuse(plan, tree, options)
|
|
323
341
|
|
|
324
342
|
// **The gate holds the unit-run marker for its whole run, not just its unit step.** The step that
|
|
@@ -406,31 +424,48 @@ const ACCEPTED_FLAGS: ReadonlyArray<string> = [VERBOSE_FLAG, gate_skip.FORCE_FLA
|
|
|
406
424
|
|
|
407
425
|
// The flags are the caller's, the destinations are the run's, so the two are merged here rather than
|
|
408
426
|
// letting an option override a flag the user typed.
|
|
427
|
+
function unknown_arguments(extra_arguments: ReadonlyArray<string>): ReadonlyArray<string> {
|
|
428
|
+
return extra_arguments.filter(
|
|
429
|
+
(argument) =>
|
|
430
|
+
!ACCEPTED_FLAGS.includes(argument) && gate_static_group.group_of(argument) === undefined,
|
|
431
|
+
)
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// The shared refusal, plus the arguments it is actually about. Some flags are accepted, so the bare
|
|
435
|
+
// "takes no extra arguments" would send a reader to drop the ones that work. The list is interpolated
|
|
436
|
+
// rather than spelled out here, so adding a flag cannot leave this line stale.
|
|
437
|
+
function write_refusal(unknown: ReadonlyArray<string>): void {
|
|
438
|
+
const groups = Object.keys(gate_static_group.STATIC_GROUPS).join('|')
|
|
439
|
+
|
|
440
|
+
process.stderr.write(
|
|
441
|
+
`${composite_arguments.format_rejection(GATE_COMMAND, GATE_TARGETS)}\n` +
|
|
442
|
+
` refused: ${unknown.join(' ')}\n` +
|
|
443
|
+
` accepted here: ${ACCEPTED_FLAGS.join(' ')} ${gate_static_group.STATIC_GROUP_FLAG_PREFIX}<${groups}>\n`,
|
|
444
|
+
)
|
|
445
|
+
}
|
|
446
|
+
|
|
409
447
|
async function run_gate_command(
|
|
410
448
|
extra_arguments: ReadonlyArray<string>,
|
|
411
449
|
options: GateOptions = {},
|
|
412
450
|
): Promise<number> {
|
|
413
|
-
const unknown = extra_arguments
|
|
451
|
+
const unknown = unknown_arguments(extra_arguments)
|
|
414
452
|
|
|
415
453
|
if (unknown.length > 0) {
|
|
416
|
-
|
|
417
|
-
// bare "takes no extra arguments" would send a reader to drop the ones that work. The list is
|
|
418
|
-
// interpolated rather than spelled out here, so adding a flag cannot leave this line stale.
|
|
419
|
-
process.stderr.write(
|
|
420
|
-
`${composite_arguments.format_rejection(GATE_COMMAND, GATE_TARGETS)}\n` +
|
|
421
|
-
` refused: ${unknown.join(' ')}\n` +
|
|
422
|
-
` accepted here: ${ACCEPTED_FLAGS.join(' ')}\n`,
|
|
423
|
-
)
|
|
454
|
+
write_refusal(unknown)
|
|
424
455
|
|
|
425
456
|
return USAGE_ERROR_EXIT_CODE
|
|
426
457
|
}
|
|
427
458
|
|
|
459
|
+
// A static group is a part of the static set, so it implies `--no-unit` and every withholding that flag carries.
|
|
460
|
+
const static_group = gate_static_group.find_group(extra_arguments)
|
|
461
|
+
|
|
428
462
|
return await run_verification_gate({
|
|
429
463
|
is_scoped_enforced: true,
|
|
430
464
|
...options,
|
|
431
465
|
is_verbose: extra_arguments.includes(VERBOSE_FLAG),
|
|
432
466
|
is_forced: extra_arguments.includes(gate_skip.FORCE_FLAG),
|
|
433
|
-
is_unit_included: !extra_arguments.includes(NO_UNIT_FLAG),
|
|
467
|
+
is_unit_included: !extra_arguments.includes(NO_UNIT_FLAG) && static_group === undefined,
|
|
468
|
+
static_group,
|
|
434
469
|
})
|
|
435
470
|
}
|
|
436
471
|
|
|
@@ -440,7 +475,7 @@ async function run_gate_command(
|
|
|
440
475
|
// process end on its own, which it can, since every child has already exited by here.
|
|
441
476
|
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
442
477
|
process.exitCode = await run_gate_command(process.argv.slice(FIRST_ARGUMENT_INDEX), {
|
|
443
|
-
ledger_path: await
|
|
478
|
+
ledger_path: await lane_ledger_write.target(),
|
|
444
479
|
check_records: check_reuse.DEFAULT_RECORDS,
|
|
445
480
|
})
|
|
446
481
|
}
|