@quickchatai/pi-quickreview 0.0.0-stage → 1.1.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/LICENSE +23 -0
- package/README.md +75 -2
- package/assets/agents/pass-abstraction.md +64 -0
- package/assets/agents/pass-ask-human.md +134 -0
- package/assets/agents/pass-backcompat.md +67 -0
- package/assets/agents/pass-baseline.md +61 -0
- package/assets/agents/pass-behaviour-delta.md +64 -0
- package/assets/agents/pass-bounds.md +36 -0
- package/assets/agents/pass-claims.md +31 -0
- package/assets/agents/pass-concurrency.md +168 -0
- package/assets/agents/pass-consistency.md +57 -0
- package/assets/agents/pass-contracts.md +30 -0
- package/assets/agents/pass-data-safety.md +54 -0
- package/assets/agents/pass-deferred.md +35 -0
- package/assets/agents/pass-delivery.md +37 -0
- package/assets/agents/pass-duplication.md +60 -0
- package/assets/agents/pass-intent.md +63 -0
- package/assets/agents/pass-lint-conformance.md +46 -0
- package/assets/agents/pass-maintainability.md +67 -0
- package/assets/agents/pass-placement.md +68 -0
- package/assets/agents/pass-prod-risk.md +24 -0
- package/assets/agents/pass-rollout.md +32 -0
- package/assets/agents/pass-roundtrip.md +46 -0
- package/assets/agents/pass-security.md +31 -0
- package/assets/agents/pass-simplicity.md +68 -0
- package/assets/agents/pass-statelessness.md +27 -0
- package/assets/agents/pass-style.md +37 -0
- package/assets/agents/pass-sweep.md +57 -0
- package/assets/agents/pass-tests.md +58 -0
- package/assets/agents/pass-ui.md +23 -0
- package/assets/agents/pass-validate.md +50 -0
- package/assets/agents/pass-widened.md +46 -0
- package/assets/agents/scan/pass-scan.md +86 -0
- package/assets/config.example.toml +1067 -0
- package/assets/deploy/reviewer/AGENTS.override.md +12 -0
- package/assets/profiles/default/README.md +21 -0
- package/assets/profiles/default/addenda/.gitkeep +0 -0
- package/assets/profiles/default/profile.toml +17 -0
- package/assets/profiles/example-django/README.md +21 -0
- package/assets/profiles/example-django/addenda/10-migration-discipline.md +13 -0
- package/assets/profiles/example-django/addenda/20-new-column-nullability.md +12 -0
- package/assets/profiles/example-django/addenda/30-test-doctrine.md +12 -0
- package/assets/profiles/example-django/addenda/40-orm-usage.md +19 -0
- package/assets/profiles/example-django/addenda/50-declared-shape.md +10 -0
- package/assets/profiles/example-django/addenda/60-config-placement.md +14 -0
- package/assets/profiles/example-django/heuristics.toml +24 -0
- package/assets/profiles/example-django/profile.toml +9 -0
- package/assets/profiles/fast/README.md +24 -0
- package/assets/profiles/fast/profile.toml +59 -0
- package/assets/profiles/minimal/README.md +17 -0
- package/assets/profiles/minimal/addenda/.gitkeep +0 -0
- package/assets/profiles/minimal/profile.toml +8 -0
- package/assets/profiles/snappy/README.md +24 -0
- package/assets/profiles/snappy/addenda/10-race-as-question.md +6 -0
- package/assets/profiles/snappy/profile.toml +46 -0
- package/assets/prompts/companion-day-open.md +46 -0
- package/assets/prompts/companion-first-run.md +104 -0
- package/assets/prompts/companion.md +821 -0
- package/assets/prompts/conversation-system.md +117 -0
- package/assets/prompts/eod-sweep.md +120 -0
- package/assets/prompts/onboarding.md +74 -0
- package/assets/prompts/pass-common.md +52 -0
- package/assets/prompts/pass-quality-common.md +22 -0
- package/assets/prompts/round-first.md +874 -0
- package/assets/prompts/round-follow-up.md +991 -0
- package/assets/prompts/round-re-review.md +889 -0
- package/assets/prompts/round-recheck.md +196 -0
- package/assets/prompts/round-staleness.md +856 -0
- package/assets/schemas/review-result.v1.json +391 -0
- package/assets/schemas/scan-result.v1.json +421 -0
- package/assets/schemas/version.v1.json +57 -0
- package/assets/seed-manifest.json +19 -0
- package/assets/seeds/agents/pass-baseline.md +61 -0
- package/assets/seeds/agents/pass-contracts.md +30 -0
- package/assets/seeds/agents/pass-data-safety.md +54 -0
- package/assets/seeds/agents/pass-delivery.md +37 -0
- package/assets/seeds/agents/pass-prod-risk.md +24 -0
- package/assets/seeds/agents/pass-security.md +31 -0
- package/assets/seeds/agents/pass-statelessness.md +27 -0
- package/assets/seeds/agents/pass-ui.md +23 -0
- package/assets/seeds/agents/pass-validate.md +50 -0
- package/assets/seeds/prompts/conversation-system.md +117 -0
- package/assets/seeds/prompts/eod-sweep.md +120 -0
- package/assets/seeds/prompts/pass-common.md +52 -0
- package/dist/extensions/bash-guard.d.ts +467 -0
- package/dist/extensions/bash-guard.d.ts.map +1 -0
- package/dist/extensions/bash-guard.js +3058 -0
- package/dist/extensions/bash-guard.js.map +1 -0
- package/dist/extensions/finding-clusters.d.ts +33 -0
- package/dist/extensions/finding-clusters.d.ts.map +1 -0
- package/dist/extensions/finding-clusters.js +218 -0
- package/dist/extensions/finding-clusters.js.map +1 -0
- package/dist/extensions/ledger-pin.d.ts +76 -0
- package/dist/extensions/ledger-pin.d.ts.map +1 -0
- package/dist/extensions/ledger-pin.js +331 -0
- package/dist/extensions/ledger-pin.js.map +1 -0
- package/dist/extensions/lens.d.ts +43 -0
- package/dist/extensions/lens.d.ts.map +1 -0
- package/dist/extensions/lens.js +150 -0
- package/dist/extensions/lens.js.map +1 -0
- package/dist/extensions/pi-tool.d.ts +22 -0
- package/dist/extensions/pi-tool.d.ts.map +1 -0
- package/dist/extensions/pi-tool.js +20 -0
- package/dist/extensions/pi-tool.js.map +1 -0
- package/dist/extensions/quickreview.d.ts +21 -0
- package/dist/extensions/quickreview.d.ts.map +1 -0
- package/dist/extensions/quickreview.js +132 -0
- package/dist/extensions/quickreview.js.map +1 -0
- package/dist/src/anchors.d.ts +54 -0
- package/dist/src/anchors.d.ts.map +1 -0
- package/dist/src/anchors.js +127 -0
- package/dist/src/anchors.js.map +1 -0
- package/dist/src/assetroot.d.ts +16 -0
- package/dist/src/assetroot.d.ts.map +1 -0
- package/dist/src/assetroot.js +77 -0
- package/dist/src/assetroot.js.map +1 -0
- package/dist/src/authwatch.d.ts +61 -0
- package/dist/src/authwatch.d.ts.map +1 -0
- package/dist/src/authwatch.js +210 -0
- package/dist/src/authwatch.js.map +1 -0
- package/dist/src/budget.d.ts +15 -0
- package/dist/src/budget.d.ts.map +1 -0
- package/dist/src/budget.js +32 -0
- package/dist/src/budget.js.map +1 -0
- package/dist/src/casebudget.d.ts +3 -0
- package/dist/src/casebudget.d.ts.map +1 -0
- package/dist/src/casebudget.js +3 -0
- package/dist/src/casebudget.js.map +1 -0
- package/dist/src/cigate.d.ts +116 -0
- package/dist/src/cigate.d.ts.map +1 -0
- package/dist/src/cigate.js +176 -0
- package/dist/src/cigate.js.map +1 -0
- package/dist/src/codespan.d.ts +46 -0
- package/dist/src/codespan.d.ts.map +1 -0
- package/dist/src/codespan.js +75 -0
- package/dist/src/codespan.js.map +1 -0
- package/dist/src/contextpack.d.ts +56 -0
- package/dist/src/contextpack.d.ts.map +1 -0
- package/dist/src/contextpack.js +195 -0
- package/dist/src/contextpack.js.map +1 -0
- package/dist/src/contract.d.ts +8 -0
- package/dist/src/contract.d.ts.map +1 -0
- package/dist/src/contract.js +21 -0
- package/dist/src/contract.js.map +1 -0
- package/dist/src/coverage.d.ts +32 -0
- package/dist/src/coverage.d.ts.map +1 -0
- package/dist/src/coverage.js +85 -0
- package/dist/src/coverage.js.map +1 -0
- package/dist/src/datafence.d.ts +19 -0
- package/dist/src/datafence.d.ts.map +1 -0
- package/dist/src/datafence.js +60 -0
- package/dist/src/datafence.js.map +1 -0
- package/dist/src/dedup.d.ts +65 -0
- package/dist/src/dedup.d.ts.map +1 -0
- package/dist/src/dedup.js +459 -0
- package/dist/src/dedup.js.map +1 -0
- package/dist/src/depsources.d.ts +304 -0
- package/dist/src/depsources.d.ts.map +1 -0
- package/dist/src/depsources.js +3367 -0
- package/dist/src/depsources.js.map +1 -0
- package/dist/src/diffinput.d.ts +10 -0
- package/dist/src/diffinput.d.ts.map +1 -0
- package/dist/src/diffinput.js +172 -0
- package/dist/src/diffinput.js.map +1 -0
- package/dist/src/doubtwords.d.ts +10 -0
- package/dist/src/doubtwords.d.ts.map +1 -0
- package/dist/src/doubtwords.js +13 -0
- package/dist/src/doubtwords.js.map +1 -0
- package/dist/src/ecosystem.d.ts +148 -0
- package/dist/src/ecosystem.d.ts.map +1 -0
- package/dist/src/ecosystem.js +338 -0
- package/dist/src/ecosystem.js.map +1 -0
- package/dist/src/engine/agentdir.d.ts +5 -0
- package/dist/src/engine/agentdir.d.ts.map +1 -0
- package/dist/src/engine/agentdir.js +21 -0
- package/dist/src/engine/agentdir.js.map +1 -0
- package/dist/src/engine/auth.d.ts +214 -0
- package/dist/src/engine/auth.d.ts.map +1 -0
- package/dist/src/engine/auth.js +374 -0
- package/dist/src/engine/auth.js.map +1 -0
- package/dist/src/engine/budget.d.ts +60 -0
- package/dist/src/engine/budget.d.ts.map +1 -0
- package/dist/src/engine/budget.js +113 -0
- package/dist/src/engine/budget.js.map +1 -0
- package/dist/src/engine/capfd.d.ts +6 -0
- package/dist/src/engine/capfd.d.ts.map +1 -0
- package/dist/src/engine/capfd.js +21 -0
- package/dist/src/engine/capfd.js.map +1 -0
- package/dist/src/engine/caseout.d.ts +66 -0
- package/dist/src/engine/caseout.d.ts.map +1 -0
- package/dist/src/engine/caseout.js +107 -0
- package/dist/src/engine/caseout.js.map +1 -0
- package/dist/src/engine/context.d.ts +57 -0
- package/dist/src/engine/context.d.ts.map +1 -0
- package/dist/src/engine/context.js +212 -0
- package/dist/src/engine/context.js.map +1 -0
- package/dist/src/engine/envmap.d.ts +13 -0
- package/dist/src/engine/envmap.d.ts.map +1 -0
- package/dist/src/engine/envmap.js +372 -0
- package/dist/src/engine/envmap.js.map +1 -0
- package/dist/src/engine/extfiles.d.ts +7 -0
- package/dist/src/engine/extfiles.d.ts.map +1 -0
- package/dist/src/engine/extfiles.js +23 -0
- package/dist/src/engine/extfiles.js.map +1 -0
- package/dist/src/engine/keyroute.d.ts +21 -0
- package/dist/src/engine/keyroute.d.ts.map +1 -0
- package/dist/src/engine/keyroute.js +58 -0
- package/dist/src/engine/keyroute.js.map +1 -0
- package/dist/src/engine/lens/cache-group.d.ts +20 -0
- package/dist/src/engine/lens/cache-group.d.ts.map +1 -0
- package/dist/src/engine/lens/cache-group.js +31 -0
- package/dist/src/engine/lens/cache-group.js.map +1 -0
- package/dist/src/engine/lens/cache-run.d.ts +65 -0
- package/dist/src/engine/lens/cache-run.d.ts.map +1 -0
- package/dist/src/engine/lens/cache-run.js +159 -0
- package/dist/src/engine/lens/cache-run.js.map +1 -0
- package/dist/src/engine/lens/deadline.d.ts +54 -0
- package/dist/src/engine/lens/deadline.d.ts.map +1 -0
- package/dist/src/engine/lens/deadline.js +111 -0
- package/dist/src/engine/lens/deadline.js.map +1 -0
- package/dist/src/engine/lens/engine-tools.d.ts +13 -0
- package/dist/src/engine/lens/engine-tools.d.ts.map +1 -0
- package/dist/src/engine/lens/engine-tools.js +37 -0
- package/dist/src/engine/lens/engine-tools.js.map +1 -0
- package/dist/src/engine/lens/env.d.ts +23 -0
- package/dist/src/engine/lens/env.d.ts.map +1 -0
- package/dist/src/engine/lens/env.js +42 -0
- package/dist/src/engine/lens/env.js.map +1 -0
- package/dist/src/engine/lens/launch-plan.d.ts +63 -0
- package/dist/src/engine/lens/launch-plan.d.ts.map +1 -0
- package/dist/src/engine/lens/launch-plan.js +203 -0
- package/dist/src/engine/lens/launch-plan.js.map +1 -0
- package/dist/src/engine/lens/leaf-cache.d.ts +22 -0
- package/dist/src/engine/lens/leaf-cache.d.ts.map +1 -0
- package/dist/src/engine/lens/leaf-cache.js +115 -0
- package/dist/src/engine/lens/leaf-cache.js.map +1 -0
- package/dist/src/engine/lens/permits.d.ts +14 -0
- package/dist/src/engine/lens/permits.d.ts.map +1 -0
- package/dist/src/engine/lens/permits.js +18 -0
- package/dist/src/engine/lens/permits.js.map +1 -0
- package/dist/src/engine/lens/registry.d.ts +55 -0
- package/dist/src/engine/lens/registry.d.ts.map +1 -0
- package/dist/src/engine/lens/registry.js +140 -0
- package/dist/src/engine/lens/registry.js.map +1 -0
- package/dist/src/engine/lens/round-lens.d.ts +16 -0
- package/dist/src/engine/lens/round-lens.d.ts.map +1 -0
- package/dist/src/engine/lens/round-lens.js +46 -0
- package/dist/src/engine/lens/round-lens.js.map +1 -0
- package/dist/src/engine/lens/runlens.d.ts +103 -0
- package/dist/src/engine/lens/runlens.d.ts.map +1 -0
- package/dist/src/engine/lens/runlens.js +538 -0
- package/dist/src/engine/lens/runlens.js.map +1 -0
- package/dist/src/engine/lens/section.d.ts +19 -0
- package/dist/src/engine/lens/section.d.ts.map +1 -0
- package/dist/src/engine/lens/section.js +40 -0
- package/dist/src/engine/lens/section.js.map +1 -0
- package/dist/src/engine/lens/semaphore.d.ts +13 -0
- package/dist/src/engine/lens/semaphore.d.ts.map +1 -0
- package/dist/src/engine/lens/semaphore.js +44 -0
- package/dist/src/engine/lens/semaphore.js.map +1 -0
- package/dist/src/engine/lens/tool.d.ts +34 -0
- package/dist/src/engine/lens/tool.d.ts.map +1 -0
- package/dist/src/engine/lens/tool.js +345 -0
- package/dist/src/engine/lens/tool.js.map +1 -0
- package/dist/src/engine/lens/wave.d.ts +63 -0
- package/dist/src/engine/lens/wave.d.ts.map +1 -0
- package/dist/src/engine/lens/wave.js +95 -0
- package/dist/src/engine/lens/wave.js.map +1 -0
- package/dist/src/engine/livesessions.d.ts +21 -0
- package/dist/src/engine/livesessions.d.ts.map +1 -0
- package/dist/src/engine/livesessions.js +57 -0
- package/dist/src/engine/livesessions.js.map +1 -0
- package/dist/src/engine/livewire.d.ts +18 -0
- package/dist/src/engine/livewire.d.ts.map +1 -0
- package/dist/src/engine/livewire.js +31 -0
- package/dist/src/engine/livewire.js.map +1 -0
- package/dist/src/engine/openable.d.ts +37 -0
- package/dist/src/engine/openable.d.ts.map +1 -0
- package/dist/src/engine/openable.js +120 -0
- package/dist/src/engine/openable.js.map +1 -0
- package/dist/src/engine/pisdk.d.ts +226 -0
- package/dist/src/engine/pisdk.d.ts.map +1 -0
- package/dist/src/engine/pisdk.js +552 -0
- package/dist/src/engine/pisdk.js.map +1 -0
- package/dist/src/engine/port.d.ts +144 -0
- package/dist/src/engine/port.d.ts.map +1 -0
- package/dist/src/engine/port.js +16 -0
- package/dist/src/engine/port.js.map +1 -0
- package/dist/src/engine/prompts.d.ts +159 -0
- package/dist/src/engine/prompts.d.ts.map +1 -0
- package/dist/src/engine/prompts.js +339 -0
- package/dist/src/engine/prompts.js.map +1 -0
- package/dist/src/engine/render.d.ts +10 -0
- package/dist/src/engine/render.d.ts.map +1 -0
- package/dist/src/engine/render.js +23 -0
- package/dist/src/engine/render.js.map +1 -0
- package/dist/src/engine/reviewruntime.d.ts +13 -0
- package/dist/src/engine/reviewruntime.d.ts.map +1 -0
- package/dist/src/engine/reviewruntime.js +35 -0
- package/dist/src/engine/reviewruntime.js.map +1 -0
- package/dist/src/engine/reviewsdk.d.ts +75 -0
- package/dist/src/engine/reviewsdk.d.ts.map +1 -0
- package/dist/src/engine/reviewsdk.js +180 -0
- package/dist/src/engine/reviewsdk.js.map +1 -0
- package/dist/src/engine/round.d.ts +166 -0
- package/dist/src/engine/round.d.ts.map +1 -0
- package/dist/src/engine/round.js +543 -0
- package/dist/src/engine/round.js.map +1 -0
- package/dist/src/engine/roundagents.d.ts +17 -0
- package/dist/src/engine/roundagents.d.ts.map +1 -0
- package/dist/src/engine/roundagents.js +49 -0
- package/dist/src/engine/roundagents.js.map +1 -0
- package/dist/src/engine/roundevents.d.ts +110 -0
- package/dist/src/engine/roundevents.d.ts.map +1 -0
- package/dist/src/engine/roundevents.js +276 -0
- package/dist/src/engine/roundevents.js.map +1 -0
- package/dist/src/engine/roundsdk.d.ts +33 -0
- package/dist/src/engine/roundsdk.d.ts.map +1 -0
- package/dist/src/engine/roundsdk.js +76 -0
- package/dist/src/engine/roundsdk.js.map +1 -0
- package/dist/src/engine/sdkruntime.d.ts +23 -0
- package/dist/src/engine/sdkruntime.d.ts.map +1 -0
- package/dist/src/engine/sdkruntime.js +340 -0
- package/dist/src/engine/sdkruntime.js.map +1 -0
- package/dist/src/engine/select.d.ts +16 -0
- package/dist/src/engine/select.d.ts.map +1 -0
- package/dist/src/engine/select.js +32 -0
- package/dist/src/engine/select.js.map +1 -0
- package/dist/src/engine/sessionwrap.d.ts +4 -0
- package/dist/src/engine/sessionwrap.d.ts.map +1 -0
- package/dist/src/engine/sessionwrap.js +31 -0
- package/dist/src/engine/sessionwrap.js.map +1 -0
- package/dist/src/engine/toolfence.d.ts +90 -0
- package/dist/src/engine/toolfence.d.ts.map +1 -0
- package/dist/src/engine/toolfence.js +378 -0
- package/dist/src/engine/toolfence.js.map +1 -0
- package/dist/src/engine/tooluid.d.ts +128 -0
- package/dist/src/engine/tooluid.d.ts.map +1 -0
- package/dist/src/engine/tooluid.js +401 -0
- package/dist/src/engine/tooluid.js.map +1 -0
- package/dist/src/envstrip.d.ts +10 -0
- package/dist/src/envstrip.d.ts.map +1 -0
- package/dist/src/envstrip.js +15 -0
- package/dist/src/envstrip.js.map +1 -0
- package/dist/src/escalationprompt.d.ts +22 -0
- package/dist/src/escalationprompt.d.ts.map +1 -0
- package/dist/src/escalationprompt.js +54 -0
- package/dist/src/escalationprompt.js.map +1 -0
- package/dist/src/execfn.d.ts +29 -0
- package/dist/src/execfn.d.ts.map +1 -0
- package/dist/src/execfn.js +55 -0
- package/dist/src/execfn.js.map +1 -0
- package/dist/src/finding-chain.d.ts +40 -0
- package/dist/src/finding-chain.d.ts.map +1 -0
- package/dist/src/finding-chain.js +76 -0
- package/dist/src/finding-chain.js.map +1 -0
- package/dist/src/finding-row.d.ts +24 -0
- package/dist/src/finding-row.d.ts.map +1 -0
- package/dist/src/finding-row.js +26 -0
- package/dist/src/finding-row.js.map +1 -0
- package/dist/src/findingkey.d.ts +99 -0
- package/dist/src/findingkey.d.ts.map +1 -0
- package/dist/src/findingkey.js +210 -0
- package/dist/src/findingkey.js.map +1 -0
- package/dist/src/findingsrecord.d.ts +175 -0
- package/dist/src/findingsrecord.d.ts.map +1 -0
- package/dist/src/findingsrecord.js +410 -0
- package/dist/src/findingsrecord.js.map +1 -0
- package/dist/src/followup-mode.d.ts +4 -0
- package/dist/src/followup-mode.d.ts.map +1 -0
- package/dist/src/followup-mode.js +6 -0
- package/dist/src/followup-mode.js.map +1 -0
- package/dist/src/gate.d.ts +199 -0
- package/dist/src/gate.d.ts.map +1 -0
- package/dist/src/gate.js +315 -0
- package/dist/src/gate.js.map +1 -0
- package/dist/src/ghcred.d.ts +58 -0
- package/dist/src/ghcred.d.ts.map +1 -0
- package/dist/src/ghcred.js +139 -0
- package/dist/src/ghcred.js.map +1 -0
- package/dist/src/githubAuth.d.ts +32 -0
- package/dist/src/githubAuth.d.ts.map +1 -0
- package/dist/src/githubAuth.js +116 -0
- package/dist/src/githubAuth.js.map +1 -0
- package/dist/src/githubcore.d.ts +20 -0
- package/dist/src/githubcore.d.ts.map +1 -0
- package/dist/src/githubcore.js +20 -0
- package/dist/src/githubcore.js.map +1 -0
- package/dist/src/glob.d.ts +11 -0
- package/dist/src/glob.d.ts.map +1 -0
- package/dist/src/glob.js +69 -0
- package/dist/src/glob.js.map +1 -0
- package/dist/src/guards.d.ts +93 -0
- package/dist/src/guards.d.ts.map +1 -0
- package/dist/src/guards.js +306 -0
- package/dist/src/guards.js.map +1 -0
- package/dist/src/heartbeat.d.ts +29 -0
- package/dist/src/heartbeat.d.ts.map +1 -0
- package/dist/src/heartbeat.js +87 -0
- package/dist/src/heartbeat.js.map +1 -0
- package/dist/src/heuristics.d.ts +247 -0
- package/dist/src/heuristics.d.ts.map +1 -0
- package/dist/src/heuristics.js +927 -0
- package/dist/src/heuristics.js.map +1 -0
- package/dist/src/homes.d.ts +181 -0
- package/dist/src/homes.d.ts.map +1 -0
- package/dist/src/homes.js +242 -0
- package/dist/src/homes.js.map +1 -0
- package/dist/src/hunkheader.d.ts +11 -0
- package/dist/src/hunkheader.d.ts.map +1 -0
- package/dist/src/hunkheader.js +18 -0
- package/dist/src/hunkheader.js.map +1 -0
- package/dist/src/include.d.ts +435 -0
- package/dist/src/include.d.ts.map +1 -0
- package/dist/src/include.js +1692 -0
- package/dist/src/include.js.map +1 -0
- package/dist/src/launchvocab.d.ts +36 -0
- package/dist/src/launchvocab.d.ts.map +1 -0
- package/dist/src/launchvocab.js +59 -0
- package/dist/src/launchvocab.js.map +1 -0
- package/dist/src/ledgercarry.d.ts +24 -0
- package/dist/src/ledgercarry.d.ts.map +1 -0
- package/dist/src/ledgercarry.js +109 -0
- package/dist/src/ledgercarry.js.map +1 -0
- package/dist/src/lensids.d.ts +7 -0
- package/dist/src/lensids.d.ts.map +1 -0
- package/dist/src/lensids.js +53 -0
- package/dist/src/lensids.js.map +1 -0
- package/dist/src/lensplanning.d.ts +8 -0
- package/dist/src/lensplanning.d.ts.map +1 -0
- package/dist/src/lensplanning.js +126 -0
- package/dist/src/lensplanning.js.map +1 -0
- package/dist/src/lensresult.d.ts +94 -0
- package/dist/src/lensresult.d.ts.map +1 -0
- package/dist/src/lensresult.js +162 -0
- package/dist/src/lensresult.js.map +1 -0
- package/dist/src/lenstuning.d.ts +97 -0
- package/dist/src/lenstuning.d.ts.map +1 -0
- package/dist/src/lenstuning.js +326 -0
- package/dist/src/lenstuning.js.map +1 -0
- package/dist/src/lintconfig.d.ts +31 -0
- package/dist/src/lintconfig.d.ts.map +1 -0
- package/dist/src/lintconfig.js +543 -0
- package/dist/src/lintconfig.js.map +1 -0
- package/dist/src/live/events.d.ts +188 -0
- package/dist/src/live/events.d.ts.map +1 -0
- package/dist/src/live/events.js +136 -0
- package/dist/src/live/events.js.map +1 -0
- package/dist/src/live/writer.d.ts +54 -0
- package/dist/src/live/writer.d.ts.map +1 -0
- package/dist/src/live/writer.js +516 -0
- package/dist/src/live/writer.js.map +1 -0
- package/dist/src/localreview.d.ts +128 -0
- package/dist/src/localreview.d.ts.map +1 -0
- package/dist/src/localreview.js +426 -0
- package/dist/src/localreview.js.map +1 -0
- package/dist/src/loosenedtests.d.ts +13 -0
- package/dist/src/loosenedtests.d.ts.map +1 -0
- package/dist/src/loosenedtests.js +188 -0
- package/dist/src/loosenedtests.js.map +1 -0
- package/dist/src/memoryport.d.ts +264 -0
- package/dist/src/memoryport.d.ts.map +1 -0
- package/dist/src/memoryport.js +445 -0
- package/dist/src/memoryport.js.map +1 -0
- package/dist/src/migrations.d.ts +106 -0
- package/dist/src/migrations.d.ts.map +1 -0
- package/dist/src/migrations.js +373 -0
- package/dist/src/migrations.js.map +1 -0
- package/dist/src/oneshot.d.ts +12 -0
- package/dist/src/oneshot.d.ts.map +1 -0
- package/dist/src/oneshot.js +8 -0
- package/dist/src/oneshot.js.map +1 -0
- package/dist/src/packing.d.ts +11 -0
- package/dist/src/packing.d.ts.map +1 -0
- package/dist/src/packing.js +31 -0
- package/dist/src/packing.js.map +1 -0
- package/dist/src/passes.d.ts +16 -0
- package/dist/src/passes.d.ts.map +1 -0
- package/dist/src/passes.js +104 -0
- package/dist/src/passes.js.map +1 -0
- package/dist/src/passtasks.d.ts +68 -0
- package/dist/src/passtasks.d.ts.map +1 -0
- package/dist/src/passtasks.js +360 -0
- package/dist/src/passtasks.js.map +1 -0
- package/dist/src/pathinside.d.ts +5 -0
- package/dist/src/pathinside.d.ts.map +1 -0
- package/dist/src/pathinside.js +9 -0
- package/dist/src/pathinside.js.map +1 -0
- package/dist/src/pibuiltins.d.ts +36 -0
- package/dist/src/pibuiltins.d.ts.map +1 -0
- package/dist/src/pibuiltins.js +83 -0
- package/dist/src/pibuiltins.js.map +1 -0
- package/dist/src/plankey.d.ts +4 -0
- package/dist/src/plankey.d.ts.map +1 -0
- package/dist/src/plankey.js +10 -0
- package/dist/src/plankey.js.map +1 -0
- package/dist/src/planner.d.ts +375 -0
- package/dist/src/planner.d.ts.map +1 -0
- package/dist/src/planner.js +722 -0
- package/dist/src/planner.js.map +1 -0
- package/dist/src/plugin/args.d.ts +19 -0
- package/dist/src/plugin/args.d.ts.map +1 -0
- package/dist/src/plugin/args.js +107 -0
- package/dist/src/plugin/args.js.map +1 -0
- package/dist/src/plugin/index.d.ts +3 -0
- package/dist/src/plugin/index.d.ts.map +1 -0
- package/dist/src/plugin/index.js +14 -0
- package/dist/src/plugin/index.js.map +1 -0
- package/dist/src/plugin/login.d.ts +39 -0
- package/dist/src/plugin/login.d.ts.map +1 -0
- package/dist/src/plugin/login.js +73 -0
- package/dist/src/plugin/login.js.map +1 -0
- package/dist/src/plugin/review.d.ts +27 -0
- package/dist/src/plugin/review.d.ts.map +1 -0
- package/dist/src/plugin/review.js +298 -0
- package/dist/src/plugin/review.js.map +1 -0
- package/dist/src/plugin/runner.d.ts +6 -0
- package/dist/src/plugin/runner.d.ts.map +1 -0
- package/dist/src/plugin/runner.js +65 -0
- package/dist/src/plugin/runner.js.map +1 -0
- package/dist/src/plugin/scan.d.ts +79 -0
- package/dist/src/plugin/scan.d.ts.map +1 -0
- package/dist/src/plugin/scan.js +348 -0
- package/dist/src/plugin/scan.js.map +1 -0
- package/dist/src/plugin/session.d.ts +56 -0
- package/dist/src/plugin/session.d.ts.map +1 -0
- package/dist/src/plugin/session.js +2 -0
- package/dist/src/plugin/session.js.map +1 -0
- package/dist/src/plugin/setup.d.ts +19 -0
- package/dist/src/plugin/setup.d.ts.map +1 -0
- package/dist/src/plugin/setup.js +142 -0
- package/dist/src/plugin/setup.js.map +1 -0
- package/dist/src/plugin/versiongate.d.ts +26 -0
- package/dist/src/plugin/versiongate.d.ts.map +1 -0
- package/dist/src/plugin/versiongate.js +83 -0
- package/dist/src/plugin/versiongate.js.map +1 -0
- package/dist/src/postingkey.d.ts +8 -0
- package/dist/src/postingkey.d.ts.map +1 -0
- package/dist/src/postingkey.js +25 -0
- package/dist/src/postingkey.js.map +1 -0
- package/dist/src/postingpolicy.d.ts +108 -0
- package/dist/src/postingpolicy.d.ts.map +1 -0
- package/dist/src/postingpolicy.js +341 -0
- package/dist/src/postingpolicy.js.map +1 -0
- package/dist/src/pr-identity.d.ts +3 -0
- package/dist/src/pr-identity.d.ts.map +1 -0
- package/dist/src/pr-identity.js +9 -0
- package/dist/src/pr-identity.js.map +1 -0
- package/dist/src/prdelta.d.ts +181 -0
- package/dist/src/prdelta.d.ts.map +1 -0
- package/dist/src/prdelta.js +501 -0
- package/dist/src/prdelta.js.map +1 -0
- package/dist/src/pricing.d.ts +94 -0
- package/dist/src/pricing.d.ts.map +1 -0
- package/dist/src/pricing.js +209 -0
- package/dist/src/pricing.js.map +1 -0
- package/dist/src/priorfindings.d.ts +167 -0
- package/dist/src/priorfindings.d.ts.map +1 -0
- package/dist/src/priorfindings.js +445 -0
- package/dist/src/priorfindings.js.map +1 -0
- package/dist/src/priortasks.d.ts +31 -0
- package/dist/src/priortasks.d.ts.map +1 -0
- package/dist/src/priortasks.js +119 -0
- package/dist/src/priortasks.js.map +1 -0
- package/dist/src/profilelookup.d.ts +59 -0
- package/dist/src/profilelookup.d.ts.map +1 -0
- package/dist/src/profilelookup.js +98 -0
- package/dist/src/profilelookup.js.map +1 -0
- package/dist/src/profileoverrides.d.ts +91 -0
- package/dist/src/profileoverrides.d.ts.map +1 -0
- package/dist/src/profileoverrides.js +313 -0
- package/dist/src/profileoverrides.js.map +1 -0
- package/dist/src/profiles.d.ts +144 -0
- package/dist/src/profiles.d.ts.map +1 -0
- package/dist/src/profiles.js +604 -0
- package/dist/src/profiles.js.map +1 -0
- package/dist/src/promptdoc.d.ts +3 -0
- package/dist/src/promptdoc.d.ts.map +1 -0
- package/dist/src/promptdoc.js +18 -0
- package/dist/src/promptdoc.js.map +1 -0
- package/dist/src/prtarget.d.ts +70 -0
- package/dist/src/prtarget.d.ts.map +1 -0
- package/dist/src/prtarget.js +181 -0
- package/dist/src/prtarget.js.map +1 -0
- package/dist/src/recheckorder.d.ts +32 -0
- package/dist/src/recheckorder.d.ts.map +1 -0
- package/dist/src/recheckorder.js +5 -0
- package/dist/src/recheckorder.js.map +1 -0
- package/dist/src/reviewapi.d.ts +207 -0
- package/dist/src/reviewapi.d.ts.map +1 -0
- package/dist/src/reviewapi.js +939 -0
- package/dist/src/reviewapi.js.map +1 -0
- package/dist/src/reviewbotfindings.d.ts +33 -0
- package/dist/src/reviewbotfindings.d.ts.map +1 -0
- package/dist/src/reviewbotfindings.js +80 -0
- package/dist/src/reviewbotfindings.js.map +1 -0
- package/dist/src/reviewconfig.d.ts +741 -0
- package/dist/src/reviewconfig.d.ts.map +1 -0
- package/dist/src/reviewconfig.js +797 -0
- package/dist/src/reviewconfig.js.map +1 -0
- package/dist/src/reviewdelta.d.ts +51 -0
- package/dist/src/reviewdelta.d.ts.map +1 -0
- package/dist/src/reviewdelta.js +119 -0
- package/dist/src/reviewdelta.js.map +1 -0
- package/dist/src/reviewdest.d.ts +86 -0
- package/dist/src/reviewdest.d.ts.map +1 -0
- package/dist/src/reviewdest.js +142 -0
- package/dist/src/reviewdest.js.map +1 -0
- package/dist/src/reviewerstub.d.ts +12 -0
- package/dist/src/reviewerstub.d.ts.map +1 -0
- package/dist/src/reviewerstub.js +28 -0
- package/dist/src/reviewerstub.js.map +1 -0
- package/dist/src/reviewhost.d.ts +58 -0
- package/dist/src/reviewhost.d.ts.map +1 -0
- package/dist/src/reviewhost.js +135 -0
- package/dist/src/reviewhost.js.map +1 -0
- package/dist/src/reviewpost.d.ts +79 -0
- package/dist/src/reviewpost.d.ts.map +1 -0
- package/dist/src/reviewpost.js +233 -0
- package/dist/src/reviewpost.js.map +1 -0
- package/dist/src/reviewrender.d.ts +154 -0
- package/dist/src/reviewrender.d.ts.map +1 -0
- package/dist/src/reviewrender.js +480 -0
- package/dist/src/reviewrender.js.map +1 -0
- package/dist/src/reviewstate.d.ts +62 -0
- package/dist/src/reviewstate.d.ts.map +1 -0
- package/dist/src/reviewstate.js +167 -0
- package/dist/src/reviewstate.js.map +1 -0
- package/dist/src/reviewstore.d.ts +17 -0
- package/dist/src/reviewstore.d.ts.map +1 -0
- package/dist/src/reviewstore.js +105 -0
- package/dist/src/reviewstore.js.map +1 -0
- package/dist/src/round-progress.d.ts +120 -0
- package/dist/src/round-progress.d.ts.map +1 -0
- package/dist/src/round-progress.js +172 -0
- package/dist/src/round-progress.js.map +1 -0
- package/dist/src/round-stage-deadlines.d.ts +12 -0
- package/dist/src/round-stage-deadlines.d.ts.map +1 -0
- package/dist/src/round-stage-deadlines.js +10 -0
- package/dist/src/round-stage-deadlines.js.map +1 -0
- package/dist/src/session-command.d.ts +19 -0
- package/dist/src/session-command.d.ts.map +1 -0
- package/dist/src/session-command.js +20 -0
- package/dist/src/session-command.js.map +1 -0
- package/dist/src/settledread.d.ts +61 -0
- package/dist/src/settledread.d.ts.map +1 -0
- package/dist/src/settledread.js +135 -0
- package/dist/src/settledread.js.map +1 -0
- package/dist/src/severity.d.ts +167 -0
- package/dist/src/severity.d.ts.map +1 -0
- package/dist/src/severity.js +364 -0
- package/dist/src/severity.js.map +1 -0
- package/dist/src/severityrank.d.ts +8 -0
- package/dist/src/severityrank.d.ts.map +1 -0
- package/dist/src/severityrank.js +16 -0
- package/dist/src/severityrank.js.map +1 -0
- package/dist/src/standing-review.d.ts +45 -0
- package/dist/src/standing-review.d.ts.map +1 -0
- package/dist/src/standing-review.js +43 -0
- package/dist/src/standing-review.js.map +1 -0
- package/dist/src/storerows.d.ts +225 -0
- package/dist/src/storerows.d.ts.map +1 -0
- package/dist/src/storerows.js +7 -0
- package/dist/src/storerows.js.map +1 -0
- package/dist/src/styleguide.d.ts +25 -0
- package/dist/src/styleguide.d.ts.map +1 -0
- package/dist/src/styleguide.js +272 -0
- package/dist/src/styleguide.js.map +1 -0
- package/dist/src/sweepstatus.d.ts +42 -0
- package/dist/src/sweepstatus.d.ts.map +1 -0
- package/dist/src/sweepstatus.js +97 -0
- package/dist/src/sweepstatus.js.map +1 -0
- package/dist/src/templates.d.ts +243 -0
- package/dist/src/templates.d.ts.map +1 -0
- package/dist/src/templates.js +847 -0
- package/dist/src/templates.js.map +1 -0
- package/dist/src/types.d.ts +639 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +90 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/unifieddiff.d.ts +22 -0
- package/dist/src/unifieddiff.d.ts.map +1 -0
- package/dist/src/unifieddiff.js +176 -0
- package/dist/src/unifieddiff.js.map +1 -0
- package/dist/src/yieldloop.d.ts +2 -0
- package/dist/src/yieldloop.d.ts.map +1 -0
- package/dist/src/yieldloop.js +14 -0
- package/dist/src/yieldloop.js.map +1 -0
- package/package.json +60 -4
|
@@ -0,0 +1,722 @@
|
|
|
1
|
+
import { REVIEW_DEFAULTS } from "./reviewconfig.js";
|
|
2
|
+
import { coverageEligible } from "./coverage.js";
|
|
3
|
+
import { DJANGO_ECOSYSTEM } from "./ecosystem.js";
|
|
4
|
+
import { promptTargetsFor } from "./escalationprompt.js";
|
|
5
|
+
import { deltaFollowUpEnabled } from "./followup-mode.js";
|
|
6
|
+
import { INTENT_PASS, passTier, selectLenses, selectSubLenses, SWEEP_PASS, sweepGroups, isLightSweepFile, baselineGroups, baselineSplitLines, BEHAVIOUR_DELTA_PASS, behaviourDeltaGroups, CODE_FILE_RE, TESTS_PASS, STYLE_PASS, LINT_CONFORMANCE_PASS, selectQualityLenses, QUALITY_PASSES, qualityReason, } from "./heuristics.js";
|
|
7
|
+
import { VALIDATE_PASS } from "./include.js";
|
|
8
|
+
import { LENS_PLANNING } from "./lensplanning.js";
|
|
9
|
+
import { flooredTier, lensEnabled } from "./lenstuning.js";
|
|
10
|
+
import { lintersForFiles } from "./lintconfig.js";
|
|
11
|
+
import { detectLoosenedAssertions, loosenedReason } from "./loosenedtests.js";
|
|
12
|
+
import { ALL_PASSES } from "./passes.js";
|
|
13
|
+
import { isDefaultPosting } from "./postingpolicy.js";
|
|
14
|
+
import { roundPostingKey } from "./postingkey.js";
|
|
15
|
+
import { deltaAsPrFiles } from "./prdelta.js";
|
|
16
|
+
import { assignPriorFindings } from "./priortasks.js";
|
|
17
|
+
import { PASS_TIER_ORDER } from "./types.js";
|
|
18
|
+
/** A plan's lens names, each once, in plan order — the compatibility list
|
|
19
|
+
* the rounds table, the event log and every order carry (a lens with several
|
|
20
|
+
* rows, the sweep, once). */
|
|
21
|
+
export function lensesOf(plan) {
|
|
22
|
+
return [...new Set(plan.map((p) => p.lens))];
|
|
23
|
+
}
|
|
24
|
+
/** The head a round reviews: the prepared tree's, else the PR row's (a
|
|
25
|
+
* caller with no worktree seam). The one rule the round row, the posting key
|
|
26
|
+
* and the prompt all name their head by. */
|
|
27
|
+
export function reviewedHeadOf(tree, row) {
|
|
28
|
+
return tree?.head_sha || row.head_sha;
|
|
29
|
+
}
|
|
30
|
+
/** raisable_to lists the higher rungs only — a session may raise a pass, never
|
|
31
|
+
* lower it. */
|
|
32
|
+
function raisableFrom(lens, tier) {
|
|
33
|
+
return PASS_TIER_ORDER.slice(PASS_TIER_ORDER.indexOf(tier) + 1).map((t) => `${lens}--${t}`);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The tier the round's validator runs at: its own tier, the configured
|
|
37
|
+
* `validate_tier` under the profile's `min_tier` for it, whatever tier or
|
|
38
|
+
* effort any lens runs at. It is never raised to match a lens: a finding the
|
|
39
|
+
* validator cannot stand behind is kept as `doubted` in the findings record
|
|
40
|
+
* (never posted, shown in the TUI), not discarded, so a cheaper validator
|
|
41
|
+
* cannot make a stronger lens's finding vanish. Lens tiers are deliberately
|
|
42
|
+
* not an input.
|
|
43
|
+
*/
|
|
44
|
+
export function validatorTier(cfg) {
|
|
45
|
+
return flooredTier(cfg.lenses, VALIDATE_PASS, cfg.models.validate_tier);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The tier a lens ADDED by the session runs at (the round templates' add
|
|
49
|
+
* rule): a risk pass exists only as `sol-high`; every other lens at `sol-med`,
|
|
50
|
+
* or at the profile's `min_tier` for it when that is higher.
|
|
51
|
+
*/
|
|
52
|
+
export function addTierOf(cfg, lens) {
|
|
53
|
+
return cfg.models.risk_passes.includes(lens)
|
|
54
|
+
? "sol-high"
|
|
55
|
+
: flooredTier(cfg.lenses, lens, "sol-med");
|
|
56
|
+
}
|
|
57
|
+
/** Deterministic per-round pass plan (agent = `${lens}--${tier}`):
|
|
58
|
+
* - risk passes are always "sol-high", single variant, not raisable;
|
|
59
|
+
* - pass-validate runs at validatorTier() — its own configured tier, never
|
|
60
|
+
* raised to match a lens — is not raisable, and is always last;
|
|
61
|
+
* - every other selected lens gets the passTier() tier and may be raised to
|
|
62
|
+
* any higher tier's variant (ascending order).
|
|
63
|
+
* addable_lenses = every known pass not already in the plan.
|
|
64
|
+
* The rows come back in launch order, slowest first (`slowestFirst`).
|
|
65
|
+
*
|
|
66
|
+
* The profile's per-lens tuning (`cfg.lenses`) wins over all of
|
|
67
|
+
* that: a `min_tier` floors the lens's row (and so its `raisable_to`) and the
|
|
68
|
+
* sweep rows; `enabled = false` removes a lens from the plan AND the addable
|
|
69
|
+
* list whatever selected it — the validator included, when the round
|
|
70
|
+
* has no validator row at all; `enabled = true` on a lever-gated lens switches
|
|
71
|
+
* it on whatever its `[review]` lever says. */
|
|
72
|
+
export function buildPassPlan(cfg, files, intent,
|
|
73
|
+
/** Whose tier-forcing gate applies. Default Django; `none` never forces
|
|
74
|
+
* sol-med off a migrations path. */
|
|
75
|
+
ecosystem = DJANGO_ECOSYSTEM,
|
|
76
|
+
/** Profile lens-heuristics extension; absent ⇒ generic core. */
|
|
77
|
+
heuristics,
|
|
78
|
+
/** The repo's written style guide references (packages/pi-plugin/src/styleguide.ts); empty or
|
|
79
|
+
* absent ⇒ the style lens only on the profile's guide, if any. */
|
|
80
|
+
styleGuide = [],
|
|
81
|
+
/** The linters and formatters a CI job of the repo runs (packages/pi-plugin/src/lintconfig.ts);
|
|
82
|
+
* empty or absent ⇒ no lint-conformance row. */
|
|
83
|
+
ciLinters = [],
|
|
84
|
+
/** `tierFiles` — the files the round's default TIER is chosen from, when
|
|
85
|
+
* the plan is built over fewer files than the PR (a follow-up round plans
|
|
86
|
+
* from the delta, but a small fix push keeps the PR's tier and its
|
|
87
|
+
* migration floor). Absent ⇒ `files`. */
|
|
88
|
+
opts = {}) {
|
|
89
|
+
const tierBasis = opts.tierFiles ?? files;
|
|
90
|
+
const defaultTier = passTier(tierBasis, {
|
|
91
|
+
migrationGate: ecosystem.migrationGate(tierBasis),
|
|
92
|
+
smallDiffLines: cfg.models.small_diff_lines,
|
|
93
|
+
});
|
|
94
|
+
const risk = new Set(cfg.models.risk_passes);
|
|
95
|
+
// The profile's switch for one lens — explicit `enabled` wins,
|
|
96
|
+
// otherwise the `[review]` lever that gates it (true for an ungated lens).
|
|
97
|
+
const on = (lens, lever = true) => lensEnabled(cfg.lenses, lens, lever);
|
|
98
|
+
// The plan explains why each lens was chosen — the path-shaped lenses
|
|
99
|
+
// included, not only sub-lenses.
|
|
100
|
+
const reasons0 = new Map();
|
|
101
|
+
const selected0 = selectLenses(files, intent, heuristics, {
|
|
102
|
+
intentMinWords: cfg.review.intent_min_words,
|
|
103
|
+
placementMinCodeFiles: cfg.review.placement_min_code_files,
|
|
104
|
+
placementMinNewFileLines: cfg.review.placement_min_new_file_lines,
|
|
105
|
+
}, reasons0);
|
|
106
|
+
// Sub-lenses ride after the path-selected lenses, each with the reason its
|
|
107
|
+
// trigger fired (`[review] sublenses`).
|
|
108
|
+
const sub = selectSubLenses(files, intent).filter((s) => on(s.lens, cfg.review.sublenses) && !selected0.includes(s.lens));
|
|
109
|
+
const whyOf = new Map([
|
|
110
|
+
...reasons0,
|
|
111
|
+
...sub.map((s) => [s.lens, s.why]),
|
|
112
|
+
]);
|
|
113
|
+
// Existing tests are consumers of every code change, and the PR's own
|
|
114
|
+
// tests are claims about the code — one lens reads both.
|
|
115
|
+
// The loosened-test hint: weakened assertions
|
|
116
|
+
// found deterministically in the PR's test files are handed to the lens.
|
|
117
|
+
const loosened = cfg.review.loosened_test_hint ? detectLoosenedAssertions(files) : [];
|
|
118
|
+
const tests = on(TESTS_PASS, cfg.review.tests_lens) &&
|
|
119
|
+
(files.some((f) => CODE_FILE_RE.test(f.filename)) || loosened.length > 0)
|
|
120
|
+
? [TESTS_PASS]
|
|
121
|
+
: [];
|
|
122
|
+
// The code-quality lenses: maintainability, duplication, abstraction — never
|
|
123
|
+
// style, which rides only on the repo's own written guide.
|
|
124
|
+
const quality = selectQualityLenses(files, cfg.review.quality_min_added_lines).filter((l) => on(l, cfg.review.quality_lenses) && !selected0.includes(l));
|
|
125
|
+
if (tests.length)
|
|
126
|
+
whyOf.set(TESTS_PASS, "the PR changes code: existing tests are its consumers, and its own tests are claims" +
|
|
127
|
+
(loosened.length ? `; and ${loosenedReason(loosened)}` : ""));
|
|
128
|
+
for (const l of quality)
|
|
129
|
+
whyOf.set(l, qualityReason(files, cfg.review.quality_min_added_lines));
|
|
130
|
+
// A guide the repo writes wins; the profile's drafted guide is
|
|
131
|
+
// the standard only when the repo writes none.
|
|
132
|
+
const profileGuide = cfg.lenses?.[STYLE_PASS]?.guide;
|
|
133
|
+
const style = on(STYLE_PASS, cfg.review.style_lens) &&
|
|
134
|
+
(styleGuide.length > 0 || profileGuide !== undefined) &&
|
|
135
|
+
files.some((f) => CODE_FILE_RE.test(f.filename))
|
|
136
|
+
? [STYLE_PASS]
|
|
137
|
+
: [];
|
|
138
|
+
if (style.length)
|
|
139
|
+
whyOf.set(STYLE_PASS, styleGuide.length > 0
|
|
140
|
+
? `the repo's written style guide: ${styleGuide.join(", ")}`
|
|
141
|
+
: `this repo's profile style guide (\`${profileGuide.file}\`, in your instructions) — the repo writes none of its own`);
|
|
142
|
+
// Lint conformance only where a CI job runs a linter whose
|
|
143
|
+
// rules cover a changed file — the plan names the tools and their CI files.
|
|
144
|
+
const coveredLinters = lintersForFiles(ciLinters, files.filter((f) => f.status !== "removed").map((f) => f.filename));
|
|
145
|
+
const lint = on(LINT_CONFORMANCE_PASS, cfg.review.lint_conformance) && coveredLinters.length > 0
|
|
146
|
+
? [LINT_CONFORMANCE_PASS]
|
|
147
|
+
: [];
|
|
148
|
+
if (lint.length)
|
|
149
|
+
whyOf.set(LINT_CONFORMANCE_PASS, `CI runs ${coveredLinters
|
|
150
|
+
.map((l) => `${l.tool} (${l.ci.join(", ")}${l.configs.length ? `; config ${l.configs.join(", ")}` : ""})`)
|
|
151
|
+
.join("; ")} on the changed files`);
|
|
152
|
+
// `[review] skip_lenses` (cost tuning): a listed lens is neither planned
|
|
153
|
+
// nor addable. pass-validate is refused at config parse, and is re-appended
|
|
154
|
+
// unconditionally here besides.
|
|
155
|
+
const skip = new Set((cfg.review.skip_lenses ?? []).filter((l) => l !== VALIDATE_PASS));
|
|
156
|
+
// `enabled = false` is the last word on every lens, whatever selected it —
|
|
157
|
+
// a profile-level subtraction, separate from the ADD-only heuristics.
|
|
158
|
+
const lenses = [
|
|
159
|
+
...[...selected0, ...sub.map((s) => s.lens), ...tests, ...quality, ...style, ...lint].filter((l) => !skip.has(l)),
|
|
160
|
+
VALIDATE_PASS,
|
|
161
|
+
].filter((l) => on(l));
|
|
162
|
+
// `[models.pass_tiers]`: a pinned lens runs at its pinned tier on every PR,
|
|
163
|
+
// whatever the diff size, and is not raisable (config refuses a pin on a
|
|
164
|
+
// risk pass or on pass-validate). A profile `min_tier` still floors it.
|
|
165
|
+
const pins = cfg.models.pass_tiers ?? {};
|
|
166
|
+
// pass-intent starts at terra-med whatever the round's default:
|
|
167
|
+
// reading comprehension over two short texts, not a judgment over production
|
|
168
|
+
// risk. It is NOT pinned — the session may raise it like any other lens.
|
|
169
|
+
// A profile `min_tier` floors whatever this picks (it never lowers one).
|
|
170
|
+
const tierOf = (lens) => flooredTier(cfg.lenses, lens, risk.has(lens)
|
|
171
|
+
? "sol-high"
|
|
172
|
+
: (pins[lens] ?? (lens === INTENT_PASS ? "terra-med" : defaultTier)));
|
|
173
|
+
// The sweep's rows run at the cheapest tier unless pinned (`[models.pass_tiers]`)
|
|
174
|
+
// or floored by the profile.
|
|
175
|
+
const sweepOn = on(SWEEP_PASS, cfg.review.sweep) && !skip.has(SWEEP_PASS);
|
|
176
|
+
const sweepTier = flooredTier(cfg.lenses, SWEEP_PASS, pins[SWEEP_PASS] ?? "terra-med");
|
|
177
|
+
// The validator runs at its own tier — never raised to match a lens,
|
|
178
|
+
// pinned or not.
|
|
179
|
+
const validate = validatorTier(cfg);
|
|
180
|
+
const pass_plan = lenses.map((lens) => {
|
|
181
|
+
const pinned = lens === VALIDATE_PASS || risk.has(lens) || pins[lens] !== undefined;
|
|
182
|
+
const tier = lens === VALIDATE_PASS ? validate : tierOf(lens);
|
|
183
|
+
// Every planned lens says why: the signal that fired, else the lens's
|
|
184
|
+
// documented planning rule.
|
|
185
|
+
const why = whyOf.get(lens) ?? (lens !== VALIDATE_PASS ? LENS_PLANNING[lens]?.when : undefined);
|
|
186
|
+
return {
|
|
187
|
+
lens,
|
|
188
|
+
agent: `${lens}--${tier}`,
|
|
189
|
+
tier,
|
|
190
|
+
raisable_to: pinned ? [] : raisableFrom(lens, tier),
|
|
191
|
+
...(why !== undefined ? { why } : {}),
|
|
192
|
+
...(lens === BASELINE_PASS || risk.has(lens) ? { required: true } : {}),
|
|
193
|
+
};
|
|
194
|
+
});
|
|
195
|
+
// On a very large change pass-baseline — one row, and the round's
|
|
196
|
+
// critical path once the fan-out launches in one turn — is planned as 2–3
|
|
197
|
+
// rows, each STARTING from one group of the change's files; every row keeps
|
|
198
|
+
// the whole PR as its charter (`[review] baseline_split_lines`, 0 = never).
|
|
199
|
+
// At or under the threshold nothing here runs.
|
|
200
|
+
const baselineAt = pass_plan.findIndex((p) => p.lens === BASELINE_PASS);
|
|
201
|
+
const baselineSplit = baselineAt < 0
|
|
202
|
+
? []
|
|
203
|
+
: baselineGroups(files, cfg.review.baseline_split_lines ?? REVIEW_DEFAULTS.baseline_split_lines);
|
|
204
|
+
if (baselineSplit.length > 1) {
|
|
205
|
+
const row = pass_plan[baselineAt];
|
|
206
|
+
const lines = baselineSplitLines(files);
|
|
207
|
+
pass_plan.splice(baselineAt, 1, ...baselineSplit.map((focus, i) => ({
|
|
208
|
+
...row,
|
|
209
|
+
why: `pass-baseline split ${i + 1} of ${baselineSplit.length}: the change is ${lines} changed lines, over [review] baseline_split_lines (${cfg.review.baseline_split_lines}) — this row starts from its files; its charter stays whole`,
|
|
210
|
+
focus,
|
|
211
|
+
})));
|
|
212
|
+
}
|
|
213
|
+
// The sweep (`[review] sweep`): one row per group of
|
|
214
|
+
// changed files, at the cheapest tier — its job is attention, line by line,
|
|
215
|
+
// not deep reasoning. Appended: `slowestFirst` below puts the validator
|
|
216
|
+
// last whatever is appended after it.
|
|
217
|
+
let sweep_unswept = [];
|
|
218
|
+
if (sweepOn) {
|
|
219
|
+
const { groups, unswept } = sweepGroups(files, cfg.review.sweep_max_groups, cfg.review.sweep_group_files, cfg.review.sweep_group_lines, cfg.review.sweep_wide_files);
|
|
220
|
+
sweep_unswept = unswept;
|
|
221
|
+
// `[review] sweep_light_tier`: a row holding no production
|
|
222
|
+
// code — tests, prose, config/data only — runs at the light tier when it
|
|
223
|
+
// is below the sweep's own (the profile's floor still applies).
|
|
224
|
+
const light = cfg.review.sweep_light_tier
|
|
225
|
+
? flooredTier(cfg.lenses, SWEEP_PASS, cfg.review.sweep_light_tier)
|
|
226
|
+
: undefined;
|
|
227
|
+
const lightApplies = light !== undefined && PASS_TIER_ORDER.indexOf(light) < PASS_TIER_ORDER.indexOf(sweepTier);
|
|
228
|
+
const rows = groups.map((focus) => {
|
|
229
|
+
const isLight = lightApplies && focus.every(isLightSweepFile);
|
|
230
|
+
const tier = isLight ? light : sweepTier;
|
|
231
|
+
return {
|
|
232
|
+
lens: SWEEP_PASS,
|
|
233
|
+
agent: `${SWEEP_PASS}--${tier}`,
|
|
234
|
+
tier,
|
|
235
|
+
raisable_to: pins[SWEEP_PASS] !== undefined && !isLight ? [] : raisableFrom(SWEEP_PASS, tier),
|
|
236
|
+
why: `every changed line of ${focus.length === 1 ? focus[0] : `${focus.length} changed files`}, read one by one${isLight ? " (tests, prose or config only: the light tier, [review] sweep_light_tier)" : ""}`,
|
|
237
|
+
focus,
|
|
238
|
+
};
|
|
239
|
+
});
|
|
240
|
+
pass_plan.push(...rows);
|
|
241
|
+
}
|
|
242
|
+
// The behaviour-delta lens: one row per group of files the
|
|
243
|
+
// PR modifies or deletes code in, at the round's tier — comparing base and
|
|
244
|
+
// head is reasoning, not attention. Appended, as the sweep's rows are.
|
|
245
|
+
let behaviour_unread = [];
|
|
246
|
+
if (on(BEHAVIOUR_DELTA_PASS, cfg.review.behaviour_delta) && !skip.has(BEHAVIOUR_DELTA_PASS)) {
|
|
247
|
+
const { groups, unread } = behaviourDeltaGroups(files, cfg.review.behaviour_delta_max_groups, cfg.review.sweep_group_lines);
|
|
248
|
+
const tier = tierOf(BEHAVIOUR_DELTA_PASS);
|
|
249
|
+
const rows = groups.map((focus) => ({
|
|
250
|
+
lens: BEHAVIOUR_DELTA_PASS,
|
|
251
|
+
agent: `${BEHAVIOUR_DELTA_PASS}--${tier}`,
|
|
252
|
+
tier,
|
|
253
|
+
raisable_to: pins[BEHAVIOUR_DELTA_PASS] !== undefined ? [] : raisableFrom(BEHAVIOUR_DELTA_PASS, tier),
|
|
254
|
+
why: `base behaviour is at risk in ${focus.length === 1 ? focus[0] : `${focus.length} files`}: removed or replaced guards, conditions, calls, returns or values, or existing code wrapped in a new branch`,
|
|
255
|
+
focus,
|
|
256
|
+
}));
|
|
257
|
+
pass_plan.push(...rows);
|
|
258
|
+
behaviour_unread = unread;
|
|
259
|
+
}
|
|
260
|
+
const selected = new Set(pass_plan.map((p) => p.lens));
|
|
261
|
+
const addable_lenses = [...new Set([...ALL_PASSES, ...cfg.models.risk_passes])].filter((l) => !selected.has(l) && on(l) && !skip.has(l));
|
|
262
|
+
return {
|
|
263
|
+
pass_plan: slowestFirst(pass_plan, files, risk),
|
|
264
|
+
addable_lenses,
|
|
265
|
+
sweep_unswept,
|
|
266
|
+
...(behaviour_unread.length > 0 ? { behaviour_unread } : {}),
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
/** The lenses `slowestFirst` launches last within their tier: conditional
|
|
270
|
+
* lenses that read the change for one narrow concern. */
|
|
271
|
+
const CHEAP_LAST_PASSES = new Set([
|
|
272
|
+
INTENT_PASS,
|
|
273
|
+
...QUALITY_PASSES,
|
|
274
|
+
STYLE_PASS,
|
|
275
|
+
LINT_CONFORMANCE_PASS,
|
|
276
|
+
]);
|
|
277
|
+
/**
|
|
278
|
+
* The plan's rows in LAUNCH order — the expected-slowest first.
|
|
279
|
+
*
|
|
280
|
+
* The session launches a turn's rows in table order, and the lens runner
|
|
281
|
+
* (packages/pi-plugin/src/engine/lens/runlens.ts) runs them under a process-wide cap in that order,
|
|
282
|
+
* so a 15–27 row plan runs in waves: a slow row listed late starts in the
|
|
283
|
+
* last wave and sets the round's critical path (typically pass-baseline,
|
|
284
|
+
* sol-high sweep and behaviour-delta rows). The order:
|
|
285
|
+
* pass-baseline; then by tier, highest first; within a tier the risk passes,
|
|
286
|
+
* then the focused rows (behaviour-delta, then sweep) by the changed lines
|
|
287
|
+
* their focus covers, larger first, then every other lens, then the cheap
|
|
288
|
+
* conditional lenses (`CHEAP_LAST_PASSES`); pass-validate stays last. Ties
|
|
289
|
+
* keep their planned order (a stable sort).
|
|
290
|
+
*
|
|
291
|
+
* Only the ORDER moves — the same rows, each byte-identical. Every consumer
|
|
292
|
+
* that indexes rows (the task files, `lenses`, lesson rows, the recorded
|
|
293
|
+
* pass_plan) reads this one array, so they agree. Exported for
|
|
294
|
+
* `planFollowUp`, which splices a carried row into an already-ordered plan.
|
|
295
|
+
*/
|
|
296
|
+
export function slowestFirst(rows, files, risk) {
|
|
297
|
+
const lines = new Map(files.map((f) => [f.filename, (f.additions ?? 0) + (f.deletions ?? 0)]));
|
|
298
|
+
const weight = (p) => (p.focus ?? []).reduce((n, f) => n + (lines.get(f) ?? 0), 0);
|
|
299
|
+
const cls = (p) => risk.has(p.lens)
|
|
300
|
+
? 0
|
|
301
|
+
: p.lens === BEHAVIOUR_DELTA_PASS
|
|
302
|
+
? 1
|
|
303
|
+
: p.lens === SWEEP_PASS
|
|
304
|
+
? 2
|
|
305
|
+
: CHEAP_LAST_PASSES.has(p.lens)
|
|
306
|
+
? 4
|
|
307
|
+
: 3;
|
|
308
|
+
const key = (p) => [
|
|
309
|
+
p.lens === VALIDATE_PASS ? 1 : 0,
|
|
310
|
+
p.lens === BASELINE_PASS ? 0 : 1,
|
|
311
|
+
-PASS_TIER_ORDER.indexOf(p.tier),
|
|
312
|
+
cls(p),
|
|
313
|
+
-weight(p),
|
|
314
|
+
];
|
|
315
|
+
const keyed = rows.map((p, i) => ({ p, i, k: key(p) }));
|
|
316
|
+
keyed.sort((a, b) => {
|
|
317
|
+
for (let j = 0; j < a.k.length; j++)
|
|
318
|
+
if (a.k[j] !== b.k[j])
|
|
319
|
+
return a.k[j] - b.k[j];
|
|
320
|
+
return a.i - b.i;
|
|
321
|
+
});
|
|
322
|
+
return keyed.map((e) => e.p);
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Decide whether a non-first round is a FOLLOW-UP round
|
|
326
|
+
* (docs/follow-up-rounds.md), and plan it. Total: any doubt — the knob, no
|
|
327
|
+
* reviewed-head mark, no git seam, a delta git could not compute, a delta
|
|
328
|
+
* above `follow_up_max_delta_ratio` of the PR's diff lines, a delta plan
|
|
329
|
+
* without pass-baseline — answers `{full: reason}`, and the caller runs a
|
|
330
|
+
* full re-review.
|
|
331
|
+
*
|
|
332
|
+
* The plan is built over the DELTA's files with the intent text arms off
|
|
333
|
+
* (the title and body did not change since the last review), its tier chosen
|
|
334
|
+
* from the WHOLE PR. The sweep is owed as `followUpSweepOwed` decides (the
|
|
335
|
+
* standing verdict not APPROVE and no full look since the first round, or a
|
|
336
|
+
* large enough post-approval delta); its plan is
|
|
337
|
+
* the whole PR's full plan, exactly as a full round would run it.
|
|
338
|
+
*/
|
|
339
|
+
export async function decideFollowUp(deps, args) {
|
|
340
|
+
const { cfg, history } = deps;
|
|
341
|
+
const full = (reason, detail) => ({ kind: "full", reason, ...(detail ? { detail } : {}) });
|
|
342
|
+
if (!deltaFollowUpEnabled(cfg))
|
|
343
|
+
return full("follow_up_full");
|
|
344
|
+
if (!args.markHead)
|
|
345
|
+
return full("no-reviewed-head");
|
|
346
|
+
if (!args.tree || !args.tree.merge_base || !deps.prOwnedDelta)
|
|
347
|
+
return full("no-adapter");
|
|
348
|
+
// The merge base the reviewed head's round recorded (the latest live round
|
|
349
|
+
// dispatched to that head, a verdicted one first): a base force-pushed
|
|
350
|
+
// since then is caught by `prOwnedDelta` as `base-rewound`. Unknown (a
|
|
351
|
+
// round recorded before the column existed) ⇒ only the base-tip check runs.
|
|
352
|
+
const atMark = history
|
|
353
|
+
.roundsFor(args.pr)
|
|
354
|
+
.filter((r) => r.backfilled === 0 && r.head_sha === args.markHead && r.merge_base)
|
|
355
|
+
.sort((a, b) => Number(b.verdict !== null) - Number(a.verdict !== null) || b.round_no - a.round_no);
|
|
356
|
+
const fromMergeBase = atMark[0]?.merge_base ?? undefined;
|
|
357
|
+
let delta;
|
|
358
|
+
try {
|
|
359
|
+
delta = await deps.prOwnedDelta({
|
|
360
|
+
pr: args.pr,
|
|
361
|
+
from: args.markHead,
|
|
362
|
+
to: args.tree.head_sha,
|
|
363
|
+
mergeBase: args.tree.merge_base,
|
|
364
|
+
...(args.tree.base_sha ? { baseSha: args.tree.base_sha } : {}),
|
|
365
|
+
...(fromMergeBase ? { fromMergeBase } : {}),
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
catch (err) {
|
|
369
|
+
return full("delta-threw", { error: err instanceof Error ? err.message : String(err) });
|
|
370
|
+
}
|
|
371
|
+
if (!delta.ok)
|
|
372
|
+
return full(delta.reason, delta.detail ? { detail: delta.detail } : undefined);
|
|
373
|
+
return planFollowUp(cfg, deps.heuristics, {
|
|
374
|
+
delta,
|
|
375
|
+
fromSha: args.markHead,
|
|
376
|
+
files: args.files,
|
|
377
|
+
fullPlan: args.fullPlan,
|
|
378
|
+
ecosystem: args.ecosystem,
|
|
379
|
+
styleGuide: args.styleGuide,
|
|
380
|
+
ciLinters: args.ciLinters,
|
|
381
|
+
sweepOwed: (deltaLines) => followUpSweepOwed(cfg, {
|
|
382
|
+
standing: args.standing,
|
|
383
|
+
approvalWithheld: args.approvalWithheld === true,
|
|
384
|
+
fullLookSinceFirst: () => history.fullLookSinceFirst(args.pr),
|
|
385
|
+
deltaLines,
|
|
386
|
+
}),
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Whether a follow-up round owes the pre-approval sweep, the
|
|
391
|
+
* `[review] follow_up_sweep` knob aside. Before a posted approval (a withheld
|
|
392
|
+
* one never reached GitHub, so it counts as none): owed until a full look has
|
|
393
|
+
* happened since the first round. After a posted approval: owed only when the
|
|
394
|
+
* change since it reaches `follow_up_post_approval_sweep_lines` — a large push
|
|
395
|
+
* onto an approved PR is where live re-reviews found blockers outside the
|
|
396
|
+
* change; a small one stays delta-only.
|
|
397
|
+
*/
|
|
398
|
+
export function followUpSweepOwed(cfg, args) {
|
|
399
|
+
if (args.standing === "APPROVE" && !args.approvalWithheld) {
|
|
400
|
+
const floor = cfg.review.follow_up_post_approval_sweep_lines ??
|
|
401
|
+
REVIEW_DEFAULTS.follow_up_post_approval_sweep_lines;
|
|
402
|
+
return floor > 0 && args.deltaLines >= floor;
|
|
403
|
+
}
|
|
404
|
+
return !args.fullLookSinceFirst();
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* The PURE half of `decideFollowUp`: given a computed delta, plan
|
|
408
|
+
* the follow-up round — or answer `{full: reason}`. The daemon reaches it
|
|
409
|
+
* through `decideFollowUp`; the bench's follow-up replay (src/bench/
|
|
410
|
+
* followup.ts) calls it directly with a delta computed by the same
|
|
411
|
+
* `WorktreeManager.prOwnedDelta` over its replay tree, so the two never
|
|
412
|
+
* disagree about what a follow-up round plans.
|
|
413
|
+
*
|
|
414
|
+
* `sweepOwed` is consulted only when the `[review] follow_up_sweep` knob is on
|
|
415
|
+
* and the plan stands: the daemon's answer reads the standing verdict and the
|
|
416
|
+
* store; the bench's is the recorded case's.
|
|
417
|
+
*/
|
|
418
|
+
export function planFollowUp(cfg, heuristics, args) {
|
|
419
|
+
const { delta } = args;
|
|
420
|
+
const prLines = args.files.reduce((n, f) => n + (f.additions ?? 0) + (f.deletions ?? 0), 0);
|
|
421
|
+
const ratio = cfg.review.follow_up_max_delta_ratio ?? REVIEW_DEFAULTS.follow_up_max_delta_ratio;
|
|
422
|
+
if (delta.lines > ratio * prLines)
|
|
423
|
+
return {
|
|
424
|
+
kind: "full",
|
|
425
|
+
reason: "delta-too-large",
|
|
426
|
+
detail: { delta_lines: delta.lines, pr_lines: prLines, ratio },
|
|
427
|
+
};
|
|
428
|
+
const deltaFiles = deltaAsPrFiles(delta.files);
|
|
429
|
+
let plan = buildPassPlan(cfg, deltaFiles, undefined, args.ecosystem, heuristics, args.styleGuide, args.ciLinters, { tierFiles: args.files });
|
|
430
|
+
// The migration gate and the pre-check read the WHOLE PR, and their notes
|
|
431
|
+
// name pass-data-safety (a degraded pre-check un-muzzles that lens, never
|
|
432
|
+
// goes quiet). A PR whose migrations sit outside the delta
|
|
433
|
+
// still gets the lens the gate names: the full plan's row rides the delta
|
|
434
|
+
// plan, before the validator.
|
|
435
|
+
if (args.ecosystem.migrationGate(args.files) &&
|
|
436
|
+
!plan.pass_plan.some((p) => p.lens === DATA_SAFETY_PASS)) {
|
|
437
|
+
const carried = args.fullPlan.pass_plan.filter((p) => p.lens === DATA_SAFETY_PASS);
|
|
438
|
+
if (carried.length > 0) {
|
|
439
|
+
const at = plan.pass_plan.findIndex((p) => p.lens === VALIDATE_PASS);
|
|
440
|
+
const rows = [...plan.pass_plan];
|
|
441
|
+
rows.splice(at < 0 ? rows.length : at, 0, ...carried);
|
|
442
|
+
plan = {
|
|
443
|
+
...plan,
|
|
444
|
+
pass_plan: slowestFirst(rows, deltaFiles, new Set(cfg.models.risk_passes)),
|
|
445
|
+
addable_lenses: plan.addable_lenses.filter((l) => l !== DATA_SAFETY_PASS),
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
// A small delta gets the LEAN plan (`[review] follow_up_small_delta_lines`):
|
|
450
|
+
// pass-baseline reads it whole, so the per-file sweep rows add agents and
|
|
451
|
+
// no coverage, and the quality and style lenses — which judged the PR in
|
|
452
|
+
// round 1 — move to the addable list rather than leaving the round.
|
|
453
|
+
// Under `follow_up_extent = "session"` every follow-up round plans the
|
|
454
|
+
// lean core, and the rows it leaves out are offered as optional rows for
|
|
455
|
+
// the session to run, partly run or skip — the small-delta threshold is the
|
|
456
|
+
// session's call. Under `"rules"`, the lean plan at or under the threshold.
|
|
457
|
+
let optionalPlan = [];
|
|
458
|
+
if ((cfg.review.follow_up_extent ?? REVIEW_DEFAULTS.follow_up_extent) === "session") {
|
|
459
|
+
const lean = leanFollowUpPlan(plan);
|
|
460
|
+
const kept = new Set(lean.pass_plan);
|
|
461
|
+
optionalPlan = plan.pass_plan.filter((p) => !kept.has(p));
|
|
462
|
+
const optionalLenses = new Set(optionalPlan.map((p) => p.lens));
|
|
463
|
+
plan = {
|
|
464
|
+
...lean,
|
|
465
|
+
sweep_unswept: plan.sweep_unswept,
|
|
466
|
+
addable_lenses: lean.addable_lenses.filter((l) => !optionalLenses.has(l)),
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
const smallDelta = cfg.review.follow_up_small_delta_lines ?? REVIEW_DEFAULTS.follow_up_small_delta_lines;
|
|
471
|
+
if (smallDelta > 0 && delta.lines <= smallDelta)
|
|
472
|
+
plan = leanFollowUpPlan(plan);
|
|
473
|
+
}
|
|
474
|
+
// pass-baseline carries every prior finding no other planned lens owns: a
|
|
475
|
+
// follow-up plan without it (a profile switched it off) cannot verify them.
|
|
476
|
+
if (!plan.pass_plan.some((p) => p.lens === BASELINE_PASS))
|
|
477
|
+
return { kind: "full", reason: "baseline-unplanned" };
|
|
478
|
+
// An owed sweep needs a plan to run: an empty full plan records nothing
|
|
479
|
+
// owed rather than a sweep no round could ever satisfy.
|
|
480
|
+
const sweepOwed = (cfg.review.follow_up_sweep ?? REVIEW_DEFAULTS.follow_up_sweep) &&
|
|
481
|
+
args.fullPlan.pass_plan.length > 0 &&
|
|
482
|
+
args.sweepOwed(delta.lines);
|
|
483
|
+
return {
|
|
484
|
+
kind: "delta",
|
|
485
|
+
decision: {
|
|
486
|
+
delta,
|
|
487
|
+
fromSha: args.fromSha,
|
|
488
|
+
deltaFiles,
|
|
489
|
+
plan,
|
|
490
|
+
...(optionalPlan.length > 0 ? { optionalPlan } : {}),
|
|
491
|
+
...(sweepOwed
|
|
492
|
+
? {
|
|
493
|
+
sweepPlan: args.fullPlan.pass_plan,
|
|
494
|
+
...(args.fullPlan.sweep_unswept.length > 0
|
|
495
|
+
? { sweepUnswept: args.fullPlan.sweep_unswept }
|
|
496
|
+
: {}),
|
|
497
|
+
...(args.fullPlan.behaviour_unread?.length
|
|
498
|
+
? { sweepBehaviourUnread: args.fullPlan.behaviour_unread }
|
|
499
|
+
: {}),
|
|
500
|
+
}
|
|
501
|
+
: {}),
|
|
502
|
+
},
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
const BASELINE_PASS = "pass-baseline";
|
|
506
|
+
const DATA_SAFETY_PASS = "pass-data-safety";
|
|
507
|
+
/** The lenses a lean follow-up plan offers as addable instead of planning. */
|
|
508
|
+
export const LEAN_ADDABLE_PASSES = [...QUALITY_PASSES, STYLE_PASS];
|
|
509
|
+
/**
|
|
510
|
+
* The LEAN follow-up plan: the plan without its per-file
|
|
511
|
+
* pass-sweep rows, and with the quality and style lenses moved to
|
|
512
|
+
* `addable_lenses`. Every other row — baseline, the triggered risk lenses,
|
|
513
|
+
* the validator — is kept as planned, and so is a quality or style row the
|
|
514
|
+
* plan marks `required` (one the operator made a risk pass): a required row
|
|
515
|
+
* is an obligation, never an offer. No lens leaves the round: a session that
|
|
516
|
+
* sees a quality or style question in the change adds the lens.
|
|
517
|
+
*/
|
|
518
|
+
export function leanFollowUpPlan(plan) {
|
|
519
|
+
const movable = (p) => LEAN_ADDABLE_PASSES.includes(p.lens) && p.required !== true;
|
|
520
|
+
const moved = lensesOf(plan.pass_plan.filter(movable));
|
|
521
|
+
return {
|
|
522
|
+
...plan,
|
|
523
|
+
pass_plan: plan.pass_plan.filter((p) => p.lens !== SWEEP_PASS && !movable(p)),
|
|
524
|
+
addable_lenses: [
|
|
525
|
+
...plan.addable_lenses,
|
|
526
|
+
...moved.filter((l) => !plan.addable_lenses.includes(l)),
|
|
527
|
+
],
|
|
528
|
+
sweep_unswept: [],
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
/** A delta's files as one git-style patch (the hunks `prOwnedDelta` read,
|
|
532
|
+
* each under its file header). */
|
|
533
|
+
export function renderDeltaPatch(files) {
|
|
534
|
+
const out = [];
|
|
535
|
+
for (const f of files) {
|
|
536
|
+
const oldPath = f.old_path ?? f.path;
|
|
537
|
+
out.push(`diff --git a/${oldPath} b/${f.path}`);
|
|
538
|
+
if (f.conflict)
|
|
539
|
+
out.push("# CONFLICT: the replay of the reviewed head conflicted here; the PR's own hunks follow");
|
|
540
|
+
if (f.binary) {
|
|
541
|
+
out.push(`Binary files a/${oldPath} and b/${f.path} differ`);
|
|
542
|
+
continue;
|
|
543
|
+
}
|
|
544
|
+
out.push(f.status === "added" ? "--- /dev/null" : `--- a/${oldPath}`);
|
|
545
|
+
out.push(f.status === "removed" ? "+++ /dev/null" : `+++ b/${f.path}`);
|
|
546
|
+
if (f.patch)
|
|
547
|
+
out.push(f.patch.endsWith("\n") ? f.patch.slice(0, -1) : f.patch);
|
|
548
|
+
}
|
|
549
|
+
return out.length ? `${out.join("\n")}\n` : "";
|
|
550
|
+
}
|
|
551
|
+
/** The order's view of a delta (types.ts `RoundDelta`). */
|
|
552
|
+
export function roundDeltaOf(d, patchFile) {
|
|
553
|
+
return {
|
|
554
|
+
from_sha: d.fromSha,
|
|
555
|
+
tree: d.delta.tree,
|
|
556
|
+
lines: d.delta.lines,
|
|
557
|
+
files: d.delta.files.map((f) => ({
|
|
558
|
+
path: f.path,
|
|
559
|
+
...(f.old_path !== undefined ? { old_path: f.old_path } : {}),
|
|
560
|
+
status: f.status,
|
|
561
|
+
ranges: f.ranges.map(([a, b]) => [a, b]),
|
|
562
|
+
...(f.whole_file ? { whole_file: true } : {}),
|
|
563
|
+
...(f.conflict ? { conflict: true } : {}),
|
|
564
|
+
})),
|
|
565
|
+
patch_file: patchFile,
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
/** The order the follow-up round's OPTIONAL rows render their task files
|
|
569
|
+
* from: the follow-up order itself — the change since the last
|
|
570
|
+
* review stays their scope — with `optional_plan` as its plan. Prior
|
|
571
|
+
* findings ride the core rows only (their assignment indexes `pass_plan`),
|
|
572
|
+
* so none ride here. Pure. */
|
|
573
|
+
export function optionalOrderOf(order, optionalPlan) {
|
|
574
|
+
const { prior_assignments: _p, optional_plan: _o, optional_task_files: _f, ...rest } = order;
|
|
575
|
+
return {
|
|
576
|
+
...rest,
|
|
577
|
+
pass_plan: optionalPlan,
|
|
578
|
+
lenses: lensesOf(optionalPlan),
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
/** The order the pre-approval sweep's task files render from: the
|
|
582
|
+
* follow-up order minus its follow-up fields, planned with the whole PR's
|
|
583
|
+
* full plan — exactly the order a full round would hand its lenses. Pure;
|
|
584
|
+
* the daemon and the bench's follow-up replay render the sweep's tasks from
|
|
585
|
+
* it alike. */
|
|
586
|
+
export function sweepOrderOf(order, sweepPlan) {
|
|
587
|
+
const { scope: _s, delta: _d, prior_findings_note: _p, sweep_plan: _sp, sweep_plan_unswept: _su, sweep_plan_behaviour_unread: _bu, sweep_task_files: _st,
|
|
588
|
+
// The delta plan's facts, not the whole PR's: the sweep carries its own.
|
|
589
|
+
sweep_unswept: _du, behaviour_unread: _db, coverage_files: _cf, ...whole } = order;
|
|
590
|
+
return {
|
|
591
|
+
...whole,
|
|
592
|
+
pass_plan: sweepPlan,
|
|
593
|
+
lenses: lensesOf(sweepPlan),
|
|
594
|
+
...(order.sweep_plan_unswept && order.sweep_plan_unswept.length > 0
|
|
595
|
+
? { sweep_unswept: order.sweep_plan_unswept }
|
|
596
|
+
: {}),
|
|
597
|
+
...(order.sweep_plan_behaviour_unread?.length
|
|
598
|
+
? { behaviour_unread: order.sweep_plan_behaviour_unread }
|
|
599
|
+
: {}),
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
/** Build the round order for one PR — pure once the files list is in hand. */
|
|
603
|
+
export function buildRoundOrder(args) {
|
|
604
|
+
const eco = args.ecosystem ?? DJANGO_ECOSYSTEM;
|
|
605
|
+
const { pass_plan, addable_lenses, sweep_unswept, behaviour_unread } = args.plan ??
|
|
606
|
+
buildPassPlan(args.cfg, args.files, { title: args.row.title, body: args.prBody }, eco, args.heuristics, args.styleGuide ?? [], args.ciLinters ?? []);
|
|
607
|
+
const headSha = reviewedHeadOf(args.tree, args.row);
|
|
608
|
+
// An addable lens the profile floors above the add rule's own
|
|
609
|
+
// variant is named with its variant in the prompt.
|
|
610
|
+
const addable_tiers = Object.fromEntries(addable_lenses
|
|
611
|
+
.filter((l) => !args.cfg.models.risk_passes.includes(l))
|
|
612
|
+
.map((l) => [l, addTierOf(args.cfg, l)])
|
|
613
|
+
.filter(([, t]) => t !== "sol-med"));
|
|
614
|
+
return {
|
|
615
|
+
pr: args.row.number,
|
|
616
|
+
title: args.row.title,
|
|
617
|
+
round_id: args.roundId,
|
|
618
|
+
round_no: args.roundNo,
|
|
619
|
+
posting_key: roundPostingKey(args.row.number, args.roundNo, headSha),
|
|
620
|
+
...(args.reviewNo !== undefined ? { review_no: args.reviewNo } : {}),
|
|
621
|
+
round_type: args.roundType,
|
|
622
|
+
// Kept for compatibility with the rounds table / event log: always the
|
|
623
|
+
// pass_plan's lens names in plan order (a lens with several rows — the
|
|
624
|
+
// sweep — once).
|
|
625
|
+
lenses: lensesOf(pass_plan),
|
|
626
|
+
pass_plan,
|
|
627
|
+
addable_lenses,
|
|
628
|
+
...(Object.keys(addable_tiers).length > 0 ? { addable_tiers } : {}),
|
|
629
|
+
...(sweep_unswept.length > 0 ? { sweep_unswept } : {}),
|
|
630
|
+
...(behaviour_unread && behaviour_unread.length > 0 ? { behaviour_unread } : {}),
|
|
631
|
+
...(args.dependencyNote ? { dependency_note: args.dependencyNote } : {}),
|
|
632
|
+
...(args.cfg.review.nits === "open" ? { nit_policy: "open" } : {}),
|
|
633
|
+
...(isDefaultPosting(args.cfg.posting) ? {} : { posting_policy: args.cfg.posting }),
|
|
634
|
+
// `[review] render_outputs` (packages/pi-plugin/src/reviewrender.ts): the round renders its
|
|
635
|
+
// posted review from the findings record. Absent ⇒ the session writes
|
|
636
|
+
// both files itself.
|
|
637
|
+
...(args.cfg.review?.render_outputs ? { render_outputs: true } : {}),
|
|
638
|
+
// `[review] dedup_merge` (packages/pi-plugin/src/templates.ts renderDedupNote): only when
|
|
639
|
+
// the plan has a validator to hand the groups to.
|
|
640
|
+
...(args.cfg.review?.dedup_merge && pass_plan.some((p) => p.lens === "pass-validate")
|
|
641
|
+
? { dedup_merge: true }
|
|
642
|
+
: {}),
|
|
643
|
+
// `[review] validate_compact` (packages/pi-plugin/src/templates.ts
|
|
644
|
+
// renderValidatorOutputNote): only when the plan has a validator.
|
|
645
|
+
...(args.cfg.review?.validate_compact && pass_plan.some((p) => p.lens === "pass-validate")
|
|
646
|
+
? { validate_compact: true }
|
|
647
|
+
: {}),
|
|
648
|
+
// `[review] coverage_check` (packages/pi-plugin/src/coverage.ts): only when the plan has a
|
|
649
|
+
// sweep to launch for the uncovered files and there is a file to hold it to.
|
|
650
|
+
...(() => {
|
|
651
|
+
if (!args.cfg.review?.coverage_check || !pass_plan.some((p) => p.lens === "pass-sweep"))
|
|
652
|
+
return {};
|
|
653
|
+
// A follow-up round's coverage is the delta's — the rest of
|
|
654
|
+
// the PR was covered by the round that reviewed it.
|
|
655
|
+
const coverage_files = coverageEligible(args.followUp?.deltaFiles ?? args.files);
|
|
656
|
+
return coverage_files.length > 0 ? { coverage_files } : {};
|
|
657
|
+
})(),
|
|
658
|
+
// `[review] validator_shards` (templates.ts renderValidatorShardNote):
|
|
659
|
+
// only above 1, and only when the plan has a validator to shard.
|
|
660
|
+
...((args.cfg.review?.validator_shards ?? 1) > 1
|
|
661
|
+
? { validator_shards: args.cfg.review.validator_shards }
|
|
662
|
+
: {}),
|
|
663
|
+
migration_gate: eco.migrationGate(args.files),
|
|
664
|
+
migration_collisions: args.migrationCollisions ?? [],
|
|
665
|
+
...(args.migrationCollisionsUndelivered && (args.migrationCollisions ?? []).length > 0
|
|
666
|
+
? { migration_collisions_undelivered: true }
|
|
667
|
+
: {}),
|
|
668
|
+
migration_precheck_degraded: args.migrationPrecheckDegraded ?? false,
|
|
669
|
+
...(args.firstPartyDirectives !== undefined
|
|
670
|
+
? { first_party_directives: args.firstPartyDirectives }
|
|
671
|
+
: {}),
|
|
672
|
+
// Absent unless escalation is enabled AND session judgement is on, so the
|
|
673
|
+
// default install's order (and prompt) carries no escalation targets.
|
|
674
|
+
...(() => {
|
|
675
|
+
const targets = promptTargetsFor(args.cfg.escalation);
|
|
676
|
+
return targets ? { escalation_targets: targets } : {};
|
|
677
|
+
})(),
|
|
678
|
+
...(args.recovery?.target_head_sha === headSha ? { recovery: args.recovery } : {}),
|
|
679
|
+
head_sha: headSha,
|
|
680
|
+
base_ref: args.tree?.base_ref ?? "",
|
|
681
|
+
base_sha: args.tree?.base_sha ?? "",
|
|
682
|
+
merge_base: args.tree?.merge_base ?? "",
|
|
683
|
+
worktree: args.worktree,
|
|
684
|
+
settled_digest: args.settledDigest,
|
|
685
|
+
...(args.ledgerCarry ? { ledger_carry: args.ledgerCarry } : {}),
|
|
686
|
+
issued_at: args.issuedAt,
|
|
687
|
+
...(args.lensRuntime ? { lens_runtime: args.lensRuntime } : {}),
|
|
688
|
+
...(args.prBody !== undefined ? { pr_body: args.prBody } : {}),
|
|
689
|
+
...(args.followUp
|
|
690
|
+
? {
|
|
691
|
+
scope: "delta",
|
|
692
|
+
delta: args.followUp.delta,
|
|
693
|
+
prior_findings_note: args.followUp.priorFindingsNote,
|
|
694
|
+
...((args.cfg.review.follow_up_extent ?? REVIEW_DEFAULTS.follow_up_extent) === "session"
|
|
695
|
+
? { follow_up_extent: "session" }
|
|
696
|
+
: {}),
|
|
697
|
+
...(args.followUp.optionalPlan && args.followUp.optionalPlan.length > 0
|
|
698
|
+
? { optional_plan: args.followUp.optionalPlan }
|
|
699
|
+
: {}),
|
|
700
|
+
...(() => {
|
|
701
|
+
const list = args.followUp.priorFindings;
|
|
702
|
+
if (!list || list.findings.length === 0)
|
|
703
|
+
return {};
|
|
704
|
+
const assigned = assignPriorFindings(list, pass_plan, new Set(args.followUp.delta.files.map((f) => f.path)));
|
|
705
|
+
return assigned.length > 0 ? { prior_assignments: assigned } : {};
|
|
706
|
+
})(),
|
|
707
|
+
...(args.followUp.sweepPlan && args.followUp.sweepPlan.length > 0
|
|
708
|
+
? {
|
|
709
|
+
sweep_plan: args.followUp.sweepPlan,
|
|
710
|
+
...(args.followUp.sweepUnswept && args.followUp.sweepUnswept.length > 0
|
|
711
|
+
? { sweep_plan_unswept: args.followUp.sweepUnswept }
|
|
712
|
+
: {}),
|
|
713
|
+
...(args.followUp.sweepBehaviourUnread?.length
|
|
714
|
+
? { sweep_plan_behaviour_unread: args.followUp.sweepBehaviourUnread }
|
|
715
|
+
: {}),
|
|
716
|
+
}
|
|
717
|
+
: {}),
|
|
718
|
+
}
|
|
719
|
+
: {}),
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
//# sourceMappingURL=planner.js.map
|