@codyswann/lisa 4.54.13 → 4.55.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/all/copy-contents/.gitattributes +8 -0
- package/all/copy-overwrite/scripts/check-orphaned-branches.mjs +78 -9
- package/all/copy-overwrite/scripts/check-third-party-action-pins.mjs +17 -1
- package/all/copy-overwrite/scripts/lib/process-tree-runner.mjs +194 -7
- package/all/copy-overwrite/scripts/lisa-enforcement-fallback.sh +31 -0
- package/all/copy-overwrite/scripts/lisa-hooks/block-blind-automerge.sh +81 -2
- package/all/copy-overwrite/scripts/lisa-hooks/block-direct-issue-create.sh +293 -8
- package/all/copy-overwrite/scripts/lisa-hooks/block-instruction-file-edits.sh +21 -0
- package/all/copy-overwrite/scripts/lisa-hooks/block-managed-file-edits.sh +78 -15
- package/all/copy-overwrite/scripts/lisa-hooks/block-no-verify.sh +21 -0
- package/all/copy-overwrite/scripts/lisa-hooks/block-shell-json-parsing.sh +21 -0
- package/all/copy-overwrite/scripts/lisa-hooks/guard-dedupe.bash +340 -0
- package/all/copy-overwrite/scripts/lisa-hooks/parity-safety-net.sh +29 -1
- package/all/copy-overwrite/scripts/lisa-hooks/worktree-binding-guard.mjs +183 -1
- package/all/copy-overwrite/scripts/lisa-hooks/worktree-binding-guard.sh +21 -0
- package/all/copy-overwrite/scripts/lisa-postinstall.mjs +21 -1
- package/all/copy-overwrite/scripts/lisa-run-gates.mjs +100 -5
- package/all/copy-overwrite/scripts/lisa-work-item.mjs +1085 -80
- package/all/create-only/.github/workflows/continuous-gates.yml +7 -0
- package/cdk/create-only/.github/workflows/ci.yml +7 -0
- package/cdk/create-only/.github/workflows/deploy.yml +21 -0
- package/dist/cli/apply.d.ts.map +1 -1
- package/dist/cli/apply.js +9 -1
- package/dist/cli/apply.js.map +1 -1
- package/dist/cli/doctor-apply-deletions.d.ts +61 -0
- package/dist/cli/doctor-apply-deletions.d.ts.map +1 -0
- package/dist/cli/doctor-apply-deletions.js +137 -0
- package/dist/cli/doctor-apply-deletions.js.map +1 -0
- package/dist/cli/doctor-cdk-preset-adoption.d.ts +15 -0
- package/dist/cli/doctor-cdk-preset-adoption.d.ts.map +1 -0
- package/dist/cli/doctor-cdk-preset-adoption.js +316 -0
- package/dist/cli/doctor-cdk-preset-adoption.js.map +1 -0
- package/dist/cli/doctor-config-shadowing.d.ts +22 -0
- package/dist/cli/doctor-config-shadowing.d.ts.map +1 -0
- package/dist/cli/doctor-config-shadowing.js +123 -0
- package/dist/cli/doctor-config-shadowing.js.map +1 -0
- package/dist/cli/doctor-rails-deploy-intent.d.ts +15 -0
- package/dist/cli/doctor-rails-deploy-intent.d.ts.map +1 -0
- package/dist/cli/doctor-rails-deploy-intent.js +197 -0
- package/dist/cli/doctor-rails-deploy-intent.js.map +1 -0
- package/dist/cli/doctor-seeded-artifacts.d.ts +12 -0
- package/dist/cli/doctor-seeded-artifacts.d.ts.map +1 -0
- package/dist/cli/doctor-seeded-artifacts.js +54 -0
- package/dist/cli/doctor-seeded-artifacts.js.map +1 -0
- package/dist/cli/doctor-stale-banner-scan.d.ts +44 -0
- package/dist/cli/doctor-stale-banner-scan.d.ts.map +1 -0
- package/dist/cli/doctor-stale-banner-scan.js +152 -0
- package/dist/cli/doctor-stale-banner-scan.js.map +1 -0
- package/dist/cli/doctor-stale-managed-banner.d.ts +19 -0
- package/dist/cli/doctor-stale-managed-banner.d.ts.map +1 -0
- package/dist/cli/doctor-stale-managed-banner.js +198 -0
- package/dist/cli/doctor-stale-managed-banner.js.map +1 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +16 -0
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/ui-detected-stacks.d.ts.map +1 -1
- package/dist/cli/ui-detected-stacks.js +3 -2
- package/dist/cli/ui-detected-stacks.js.map +1 -1
- package/dist/cli/update-check.d.ts.map +1 -1
- package/dist/cli/update-check.js +14 -0
- package/dist/cli/update-check.js.map +1 -1
- package/dist/cli/worktree-liveness.d.ts +5 -0
- package/dist/cli/worktree-liveness.d.ts.map +1 -1
- package/dist/cli/worktree-liveness.js +7 -6
- package/dist/cli/worktree-liveness.js.map +1 -1
- package/dist/cli/worktree-ownership.d.ts +13 -0
- package/dist/cli/worktree-ownership.d.ts.map +1 -1
- package/dist/cli/worktree-ownership.js +14 -0
- package/dist/cli/worktree-ownership.js.map +1 -1
- package/dist/configs/eslint/base.d.ts +34 -0
- package/dist/configs/eslint/base.d.ts.map +1 -1
- package/dist/configs/eslint/base.js +34 -0
- package/dist/configs/eslint/base.js.map +1 -1
- package/dist/core/apply-receipt.d.ts +65 -0
- package/dist/core/apply-receipt.d.ts.map +1 -1
- package/dist/core/apply-receipt.js +62 -2
- package/dist/core/apply-receipt.js.map +1 -1
- package/dist/core/cdk-preset-adoption.d.ts +136 -0
- package/dist/core/cdk-preset-adoption.d.ts.map +1 -0
- package/dist/core/cdk-preset-adoption.js +135 -0
- package/dist/core/cdk-preset-adoption.js.map +1 -0
- package/dist/core/config-shadowing.d.ts +36 -0
- package/dist/core/config-shadowing.d.ts.map +1 -1
- package/dist/core/config-shadowing.js +38 -0
- package/dist/core/config-shadowing.js.map +1 -1
- package/dist/core/config.d.ts +11 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js.map +1 -1
- package/dist/core/learnings-merge-driver.d.ts +10 -0
- package/dist/core/learnings-merge-driver.d.ts.map +1 -1
- package/dist/core/learnings-merge-driver.js +18 -0
- package/dist/core/learnings-merge-driver.js.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.js +136 -0
- package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
- package/dist/core/lisa.d.ts.map +1 -1
- package/dist/core/lisa.js +9 -1
- package/dist/core/lisa.js.map +1 -1
- package/dist/core/nightly-e2e-guard-behavior-certificate.d.ts +5 -5
- package/dist/core/nightly-e2e-guard-behavior-certificate.js +7 -7
- package/dist/core/nightly-e2e-guard-behavior-certificate.js.map +1 -1
- package/dist/core/ownership-header.d.ts +74 -0
- package/dist/core/ownership-header.d.ts.map +1 -0
- package/dist/core/ownership-header.js +76 -0
- package/dist/core/ownership-header.js.map +1 -0
- package/dist/core/rails-deploy-production-intent.d.ts +36 -0
- package/dist/core/rails-deploy-production-intent.d.ts.map +1 -0
- package/dist/core/rails-deploy-production-intent.js +79 -0
- package/dist/core/rails-deploy-production-intent.js.map +1 -0
- package/dist/core/stale-managed-banner.d.ts +78 -0
- package/dist/core/stale-managed-banner.d.ts.map +1 -0
- package/dist/core/stale-managed-banner.js +118 -0
- package/dist/core/stale-managed-banner.js.map +1 -0
- package/dist/core/two-channel-delivery-scan.d.ts +33 -1
- package/dist/core/two-channel-delivery-scan.d.ts.map +1 -1
- package/dist/core/two-channel-delivery-scan.js +133 -6
- package/dist/core/two-channel-delivery-scan.js.map +1 -1
- package/dist/core/two-channel-delivery.d.ts +101 -4
- package/dist/core/two-channel-delivery.d.ts.map +1 -1
- package/dist/core/two-channel-delivery.js +121 -13
- package/dist/core/two-channel-delivery.js.map +1 -1
- package/dist/core/two-channel-staleness.d.ts +137 -0
- package/dist/core/two-channel-staleness.d.ts.map +1 -0
- package/dist/core/two-channel-staleness.js +268 -0
- package/dist/core/two-channel-staleness.js.map +1 -0
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +265 -121
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/dist/core/workflow-deletion-ownership.d.ts +6 -24
- package/dist/core/workflow-deletion-ownership.d.ts.map +1 -1
- package/dist/core/workflow-deletion-ownership.js +22 -42
- package/dist/core/workflow-deletion-ownership.js.map +1 -1
- package/dist/detection/detectors/cdk.d.ts.map +1 -1
- package/dist/detection/detectors/cdk.js +2 -1
- package/dist/detection/detectors/cdk.js.map +1 -1
- package/dist/health/template-inspection.d.ts.map +1 -1
- package/dist/health/template-inspection.js +2 -1
- package/dist/health/template-inspection.js.map +1 -1
- package/dist/migrations/ensure-lisa-postinstall.d.ts +16 -0
- package/dist/migrations/ensure-lisa-postinstall.d.ts.map +1 -1
- package/dist/migrations/ensure-lisa-postinstall.js +16 -0
- package/dist/migrations/ensure-lisa-postinstall.js.map +1 -1
- package/dist/migrations/ensure-pinned-reusable-workflow-refs.d.ts +2 -2
- package/dist/migrations/ensure-pinned-reusable-workflow-refs.d.ts.map +1 -1
- package/dist/migrations/ensure-pinned-reusable-workflow-refs.js +98 -34
- package/dist/migrations/ensure-pinned-reusable-workflow-refs.js.map +1 -1
- package/dist/migrations/ensure-playwright-dedicated-caller.d.ts.map +1 -1
- package/dist/migrations/ensure-playwright-dedicated-caller.js +1 -0
- package/dist/migrations/ensure-playwright-dedicated-caller.js.map +1 -1
- package/dist/opencode/hooks-installer.d.ts.map +1 -1
- package/dist/opencode/hooks-installer.js +1 -0
- package/dist/opencode/hooks-installer.js.map +1 -1
- package/dist/opencode/plugin-templates/block-managed-file-edits.sh +78 -15
- package/dist/opencode/plugin-templates/block-no-verify.sh +21 -0
- package/dist/opencode/plugin-templates/guard-dedupe.bash +337 -0
- package/dist/opencode/plugin-templates/lisa-block-direct-issue-create.ts +242 -55
- package/dist/opencode/plugin-templates/parity-safety-net.sh +29 -1
- package/dist/strategies/package-lisa.d.ts.map +1 -1
- package/dist/strategies/package-lisa.js +2 -1
- package/dist/strategies/package-lisa.js.map +1 -1
- package/dist/utils/path-utils.d.ts +29 -0
- package/dist/utils/path-utils.d.ts.map +1 -1
- package/dist/utils/path-utils.js +41 -0
- package/dist/utils/path-utils.js.map +1 -1
- package/expo/create-only/.github/workflows/ci.yml +21 -0
- package/expo/create-only/.github/workflows/deploy.yml +28 -0
- package/expo/create-only/.github/workflows/maestro-e2e.yml +7 -0
- package/expo/create-only/.github/workflows/nightly-e2e-bypass-reaper.yml +124 -13
- package/expo/create-only/.github/workflows/nightly-e2e-health.yml +7 -0
- package/expo/create-only/.github/workflows/nightly-e2e-report.yml +7 -0
- package/expo/create-only/.github/workflows/nightly-e2e-tracking.yml +8 -0
- package/expo/create-only/.github/workflows/playwright-e2e.yml +7 -0
- package/harper-fabric/copy-overwrite/.github/workflows/ci.yml +7 -0
- package/harper-fabric/create-only/.github/workflows/deploy.yml +14 -0
- package/nestjs/create-only/.github/workflows/ci.yml +14 -0
- package/nestjs/create-only/.github/workflows/deploy.yml +28 -0
- package/package.json +10 -5
- package/phaser/copy-overwrite/.github/workflows/ci.yml +7 -0
- package/plugins/lisa/.claude-plugin/plugin.json +28 -1
- package/plugins/lisa/.codex-plugin/hooks.json +27 -0
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-drive-pr-to-merge/SKILL.md +130 -19
- package/plugins/lisa/.codex-plugin/skills/lisa-github-build-intake/SKILL.md +27 -4
- package/plugins/lisa/.codex-plugin/skills/lisa-github-prd-intake/SKILL.md +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-github-validate-issue/SKILL.md +22 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-github-verify/SKILL.md +14 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-github-write-issue/SKILL.md +51 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-intake/SKILL.md +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-jira-build-intake/SKILL.md +27 -4
- package/plugins/lisa/.codex-plugin/skills/lisa-jira-validate-ticket/SKILL.md +22 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-jira-verify/SKILL.md +14 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-jira-write-ticket/SKILL.md +51 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-access/SKILL.md +55 -2
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-build-intake/SKILL.md +27 -4
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-prd-intake/SKILL.md +47 -30
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-to-tracker/SKILL.md +3 -3
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-validate-issue/SKILL.md +22 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-verify/SKILL.md +14 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-write-issue/SKILL.md +54 -3
- package/plugins/lisa/.codex-plugin/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
- package/plugins/lisa/.codex-plugin/skills/lisa-qa-clear/SKILL.md +19 -7
- package/plugins/lisa/.codex-plugin/skills/lisa-qa-fail/SKILL.md +28 -3
- package/plugins/lisa/.codex-plugin/skills/lisa-qa-queue/SKILL.md +28 -3
- package/plugins/lisa/.codex-plugin/skills/lisa-repair-intake/SKILL.md +94 -24
- package/plugins/lisa/.codex-plugin/skills/lisa-rework-triage/SKILL.md +32 -2
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-linear/SKILL.md +4 -4
- package/plugins/lisa/.codex-plugin/skills/lisa-track/SKILL.md +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-tracker-build-intake/SKILL.md +9 -0
- package/plugins/lisa/agents/linear-prd-intake.md +8 -8
- package/plugins/lisa/hooks/block-blind-automerge.sh +81 -2
- package/plugins/lisa/hooks/block-direct-issue-create.agy.sh +64 -16
- package/plugins/lisa/hooks/block-direct-issue-create.sh +293 -8
- package/plugins/lisa/hooks/block-instruction-file-edits.sh +21 -0
- package/plugins/lisa/hooks/block-managed-file-edits.sh +78 -15
- package/plugins/lisa/hooks/block-no-verify.sh +21 -0
- package/plugins/lisa/hooks/block-shell-json-parsing.sh +21 -0
- package/plugins/lisa/hooks/failure-signature-index.mjs +240 -5
- package/plugins/lisa/hooks/guard-dedupe.bash +337 -0
- package/plugins/lisa/hooks/inject-rules.sh +13 -5
- package/plugins/lisa/hooks/operational-hazards.mjs +736 -0
- package/plugins/lisa/hooks/operational-hazards.sh +28 -0
- package/plugins/lisa/hooks/parity-safety-net.sh +29 -1
- package/plugins/lisa/hooks/threshold-ratchet-compare.mjs +102 -21
- package/plugins/lisa/hooks/threshold-ratchet-families.mjs +130 -2
- package/plugins/lisa/hooks/threshold-ratchet.mjs +63 -13
- package/plugins/lisa/hooks/worktree-binding-guard.mjs +183 -1
- package/plugins/lisa/hooks/worktree-binding-guard.sh +21 -0
- package/plugins/lisa/rules/eager/00-rule-index.md +1 -0
- package/plugins/lisa/rules/eager/operational-hazards.md +50 -0
- package/plugins/lisa/rules/eager/tracked-work.md +1 -1
- package/plugins/lisa/rules/reference/config-resolution.md +1 -1
- package/plugins/lisa/rules/reference/leaf-only-lifecycle.md +1 -1
- package/plugins/lisa/rules/reference/operational-hazards.md +115 -0
- package/plugins/lisa/rules/reference/work-item-trailer-definition.md +129 -0
- package/plugins/lisa/scripts/intake-blocker-reprobe.mjs +407 -26
- package/plugins/lisa/scripts/qa-signal-lifecycle.mjs +507 -0
- package/plugins/lisa/skills/lisa-drive-pr-to-merge/SKILL.md +130 -19
- package/plugins/lisa/skills/lisa-github-build-intake/SKILL.md +27 -4
- package/plugins/lisa/skills/lisa-github-prd-intake/SKILL.md +1 -1
- package/plugins/lisa/skills/lisa-github-validate-issue/SKILL.md +22 -0
- package/plugins/lisa/skills/lisa-github-verify/SKILL.md +14 -0
- package/plugins/lisa/skills/lisa-github-write-issue/SKILL.md +51 -0
- package/plugins/lisa/skills/lisa-intake/SKILL.md +1 -1
- package/plugins/lisa/skills/lisa-jira-build-intake/SKILL.md +27 -4
- package/plugins/lisa/skills/lisa-jira-validate-ticket/SKILL.md +22 -0
- package/plugins/lisa/skills/lisa-jira-verify/SKILL.md +14 -0
- package/plugins/lisa/skills/lisa-jira-write-ticket/SKILL.md +51 -0
- package/plugins/lisa/skills/lisa-linear-access/SKILL.md +55 -2
- package/plugins/lisa/skills/lisa-linear-build-intake/SKILL.md +27 -4
- package/plugins/lisa/skills/lisa-linear-prd-intake/SKILL.md +48 -31
- package/plugins/lisa/skills/lisa-linear-to-tracker/SKILL.md +3 -3
- package/plugins/lisa/skills/lisa-linear-validate-issue/SKILL.md +22 -0
- package/plugins/lisa/skills/lisa-linear-verify/SKILL.md +14 -0
- package/plugins/lisa/skills/lisa-linear-write-issue/SKILL.md +54 -3
- package/plugins/lisa/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
- package/plugins/lisa/skills/lisa-qa-clear/SKILL.md +19 -7
- package/plugins/lisa/skills/lisa-qa-fail/SKILL.md +28 -3
- package/plugins/lisa/skills/lisa-qa-queue/SKILL.md +28 -3
- package/plugins/lisa/skills/lisa-repair-intake/SKILL.md +94 -24
- package/plugins/lisa/skills/lisa-rework-triage/SKILL.md +32 -2
- package/plugins/lisa/skills/lisa-setup-linear/SKILL.md +5 -5
- package/plugins/lisa/skills/lisa-track/SKILL.md +1 -1
- package/plugins/lisa/skills/lisa-tracker-build-intake/SKILL.md +9 -0
- package/plugins/lisa-agy/agents/linear-prd-intake.md +8 -8
- package/plugins/lisa-agy/hooks/block-blind-automerge.sh +81 -2
- package/plugins/lisa-agy/hooks/block-direct-issue-create.agy.sh +64 -16
- package/plugins/lisa-agy/hooks/block-direct-issue-create.sh +293 -8
- package/plugins/lisa-agy/hooks/block-instruction-file-edits.sh +21 -0
- package/plugins/lisa-agy/hooks/block-managed-file-edits.sh +78 -15
- package/plugins/lisa-agy/hooks/block-shell-json-parsing.sh +21 -0
- package/plugins/lisa-agy/hooks/guard-dedupe.bash +337 -0
- package/plugins/lisa-agy/hooks/parity-safety-net.sh +29 -1
- package/plugins/lisa-agy/hooks.json +1 -1
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/scripts/intake-blocker-reprobe.mjs +407 -26
- package/plugins/lisa-agy/scripts/qa-signal-lifecycle.mjs +507 -0
- package/plugins/lisa-agy/skills/lisa-drive-pr-to-merge/SKILL.md +130 -19
- package/plugins/lisa-agy/skills/lisa-github-build-intake/SKILL.md +27 -4
- package/plugins/lisa-agy/skills/lisa-github-prd-intake/SKILL.md +1 -1
- package/plugins/lisa-agy/skills/lisa-github-validate-issue/SKILL.md +22 -0
- package/plugins/lisa-agy/skills/lisa-github-verify/SKILL.md +14 -0
- package/plugins/lisa-agy/skills/lisa-github-write-issue/SKILL.md +51 -0
- package/plugins/lisa-agy/skills/lisa-intake/SKILL.md +1 -1
- package/plugins/lisa-agy/skills/lisa-jira-build-intake/SKILL.md +27 -4
- package/plugins/lisa-agy/skills/lisa-jira-validate-ticket/SKILL.md +22 -0
- package/plugins/lisa-agy/skills/lisa-jira-verify/SKILL.md +14 -0
- package/plugins/lisa-agy/skills/lisa-jira-write-ticket/SKILL.md +51 -0
- package/plugins/lisa-agy/skills/lisa-linear-access/SKILL.md +55 -2
- package/plugins/lisa-agy/skills/lisa-linear-build-intake/SKILL.md +27 -4
- package/plugins/lisa-agy/skills/lisa-linear-prd-intake/SKILL.md +48 -31
- package/plugins/lisa-agy/skills/lisa-linear-to-tracker/SKILL.md +3 -3
- package/plugins/lisa-agy/skills/lisa-linear-validate-issue/SKILL.md +22 -0
- package/plugins/lisa-agy/skills/lisa-linear-verify/SKILL.md +14 -0
- package/plugins/lisa-agy/skills/lisa-linear-write-issue/SKILL.md +54 -3
- package/plugins/lisa-agy/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
- package/plugins/lisa-agy/skills/lisa-qa-clear/SKILL.md +19 -7
- package/plugins/lisa-agy/skills/lisa-qa-fail/SKILL.md +28 -3
- package/plugins/lisa-agy/skills/lisa-qa-queue/SKILL.md +28 -3
- package/plugins/lisa-agy/skills/lisa-repair-intake/SKILL.md +94 -24
- package/plugins/lisa-agy/skills/lisa-rework-triage/SKILL.md +32 -2
- package/plugins/lisa-agy/skills/lisa-setup-linear/SKILL.md +5 -5
- package/plugins/lisa-agy/skills/lisa-track/SKILL.md +1 -1
- package/plugins/lisa-agy/skills/lisa-tracker-build-intake/SKILL.md +9 -0
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +19 -1
- package/plugins/lisa-copilot/agents/linear-prd-intake.agent.md +8 -8
- package/plugins/lisa-copilot/hooks/block-blind-automerge.sh +81 -2
- package/plugins/lisa-copilot/hooks/block-direct-issue-create.sh +293 -8
- package/plugins/lisa-copilot/hooks/block-instruction-file-edits.sh +21 -0
- package/plugins/lisa-copilot/hooks/block-managed-file-edits.sh +78 -15
- package/plugins/lisa-copilot/hooks/block-no-verify.sh +21 -0
- package/plugins/lisa-copilot/hooks/block-shell-json-parsing.sh +21 -0
- package/plugins/lisa-copilot/hooks/failure-signature-index.mjs +240 -5
- package/plugins/lisa-copilot/hooks/guard-dedupe.bash +337 -0
- package/plugins/lisa-copilot/hooks/inject-rules.sh +13 -5
- package/plugins/lisa-copilot/hooks/operational-hazards.mjs +736 -0
- package/plugins/lisa-copilot/hooks/operational-hazards.sh +28 -0
- package/plugins/lisa-copilot/hooks/parity-safety-net.sh +29 -1
- package/plugins/lisa-copilot/hooks/threshold-ratchet-compare.mjs +102 -21
- package/plugins/lisa-copilot/hooks/threshold-ratchet-families.mjs +130 -2
- package/plugins/lisa-copilot/hooks/threshold-ratchet.mjs +63 -13
- package/plugins/lisa-copilot/hooks/worktree-binding-guard.mjs +183 -1
- package/plugins/lisa-copilot/hooks/worktree-binding-guard.sh +21 -0
- package/plugins/lisa-copilot/rules/eager/00-rule-index.md +1 -0
- package/plugins/lisa-copilot/rules/eager/operational-hazards.md +50 -0
- package/plugins/lisa-copilot/rules/eager/tracked-work.md +1 -1
- package/plugins/lisa-copilot/rules/reference/config-resolution.md +1 -1
- package/plugins/lisa-copilot/rules/reference/leaf-only-lifecycle.md +1 -1
- package/plugins/lisa-copilot/rules/reference/operational-hazards.md +115 -0
- package/plugins/lisa-copilot/rules/reference/work-item-trailer-definition.md +129 -0
- package/plugins/lisa-copilot/scripts/intake-blocker-reprobe.mjs +407 -26
- package/plugins/lisa-copilot/scripts/qa-signal-lifecycle.mjs +507 -0
- package/plugins/lisa-copilot/skills/lisa-drive-pr-to-merge/SKILL.md +130 -19
- package/plugins/lisa-copilot/skills/lisa-github-build-intake/SKILL.md +27 -4
- package/plugins/lisa-copilot/skills/lisa-github-prd-intake/SKILL.md +1 -1
- package/plugins/lisa-copilot/skills/lisa-github-validate-issue/SKILL.md +22 -0
- package/plugins/lisa-copilot/skills/lisa-github-verify/SKILL.md +14 -0
- package/plugins/lisa-copilot/skills/lisa-github-write-issue/SKILL.md +51 -0
- package/plugins/lisa-copilot/skills/lisa-intake/SKILL.md +1 -1
- package/plugins/lisa-copilot/skills/lisa-jira-build-intake/SKILL.md +27 -4
- package/plugins/lisa-copilot/skills/lisa-jira-validate-ticket/SKILL.md +22 -0
- package/plugins/lisa-copilot/skills/lisa-jira-verify/SKILL.md +14 -0
- package/plugins/lisa-copilot/skills/lisa-jira-write-ticket/SKILL.md +51 -0
- package/plugins/lisa-copilot/skills/lisa-linear-access/SKILL.md +55 -2
- package/plugins/lisa-copilot/skills/lisa-linear-build-intake/SKILL.md +27 -4
- package/plugins/lisa-copilot/skills/lisa-linear-prd-intake/SKILL.md +48 -31
- package/plugins/lisa-copilot/skills/lisa-linear-to-tracker/SKILL.md +3 -3
- package/plugins/lisa-copilot/skills/lisa-linear-validate-issue/SKILL.md +22 -0
- package/plugins/lisa-copilot/skills/lisa-linear-verify/SKILL.md +14 -0
- package/plugins/lisa-copilot/skills/lisa-linear-write-issue/SKILL.md +54 -3
- package/plugins/lisa-copilot/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
- package/plugins/lisa-copilot/skills/lisa-qa-clear/SKILL.md +19 -7
- package/plugins/lisa-copilot/skills/lisa-qa-fail/SKILL.md +28 -3
- package/plugins/lisa-copilot/skills/lisa-qa-queue/SKILL.md +28 -3
- package/plugins/lisa-copilot/skills/lisa-repair-intake/SKILL.md +94 -24
- package/plugins/lisa-copilot/skills/lisa-rework-triage/SKILL.md +32 -2
- package/plugins/lisa-copilot/skills/lisa-setup-linear/SKILL.md +5 -5
- package/plugins/lisa-copilot/skills/lisa-track/SKILL.md +1 -1
- package/plugins/lisa-copilot/skills/lisa-tracker-build-intake/SKILL.md +9 -0
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/agents/linear-prd-intake.md +8 -8
- package/plugins/lisa-cursor/hooks/block-blind-automerge.sh +81 -2
- package/plugins/lisa-cursor/hooks/block-direct-issue-create.sh +293 -8
- package/plugins/lisa-cursor/hooks/block-instruction-file-edits.sh +21 -0
- package/plugins/lisa-cursor/hooks/block-managed-file-edits.sh +78 -15
- package/plugins/lisa-cursor/hooks/block-no-verify.sh +21 -0
- package/plugins/lisa-cursor/hooks/block-shell-json-parsing.sh +21 -0
- package/plugins/lisa-cursor/hooks/failure-signature-index.mjs +240 -5
- package/plugins/lisa-cursor/hooks/guard-dedupe.bash +337 -0
- package/plugins/lisa-cursor/hooks/hooks.json +10 -0
- package/plugins/lisa-cursor/hooks/operational-hazards.mjs +736 -0
- package/plugins/lisa-cursor/hooks/operational-hazards.sh +28 -0
- package/plugins/lisa-cursor/hooks/parity-safety-net.sh +29 -1
- package/plugins/lisa-cursor/hooks/threshold-ratchet-compare.mjs +102 -21
- package/plugins/lisa-cursor/hooks/threshold-ratchet-families.mjs +130 -2
- package/plugins/lisa-cursor/hooks/threshold-ratchet.mjs +63 -13
- package/plugins/lisa-cursor/hooks/worktree-binding-guard.mjs +183 -1
- package/plugins/lisa-cursor/hooks/worktree-binding-guard.sh +21 -0
- package/plugins/lisa-cursor/rules/00-rule-index.mdc +1 -0
- package/plugins/lisa-cursor/rules/config-resolution-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/leaf-only-lifecycle-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/operational-hazards-reference.mdc +120 -0
- package/plugins/lisa-cursor/rules/operational-hazards.mdc +55 -0
- package/plugins/lisa-cursor/rules/tracked-work.mdc +1 -1
- package/plugins/lisa-cursor/rules/work-item-trailer-definition-reference.mdc +134 -0
- package/plugins/lisa-cursor/scripts/intake-blocker-reprobe.mjs +407 -26
- package/plugins/lisa-cursor/scripts/qa-signal-lifecycle.mjs +507 -0
- package/plugins/lisa-cursor/skills/lisa-drive-pr-to-merge/SKILL.md +130 -19
- package/plugins/lisa-cursor/skills/lisa-github-build-intake/SKILL.md +27 -4
- package/plugins/lisa-cursor/skills/lisa-github-prd-intake/SKILL.md +1 -1
- package/plugins/lisa-cursor/skills/lisa-github-validate-issue/SKILL.md +22 -0
- package/plugins/lisa-cursor/skills/lisa-github-verify/SKILL.md +14 -0
- package/plugins/lisa-cursor/skills/lisa-github-write-issue/SKILL.md +51 -0
- package/plugins/lisa-cursor/skills/lisa-intake/SKILL.md +1 -1
- package/plugins/lisa-cursor/skills/lisa-jira-build-intake/SKILL.md +27 -4
- package/plugins/lisa-cursor/skills/lisa-jira-validate-ticket/SKILL.md +22 -0
- package/plugins/lisa-cursor/skills/lisa-jira-verify/SKILL.md +14 -0
- package/plugins/lisa-cursor/skills/lisa-jira-write-ticket/SKILL.md +51 -0
- package/plugins/lisa-cursor/skills/lisa-linear-access/SKILL.md +55 -2
- package/plugins/lisa-cursor/skills/lisa-linear-build-intake/SKILL.md +27 -4
- package/plugins/lisa-cursor/skills/lisa-linear-prd-intake/SKILL.md +48 -31
- package/plugins/lisa-cursor/skills/lisa-linear-to-tracker/SKILL.md +3 -3
- package/plugins/lisa-cursor/skills/lisa-linear-validate-issue/SKILL.md +22 -0
- package/plugins/lisa-cursor/skills/lisa-linear-verify/SKILL.md +14 -0
- package/plugins/lisa-cursor/skills/lisa-linear-write-issue/SKILL.md +54 -3
- package/plugins/lisa-cursor/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
- package/plugins/lisa-cursor/skills/lisa-qa-clear/SKILL.md +19 -7
- package/plugins/lisa-cursor/skills/lisa-qa-fail/SKILL.md +28 -3
- package/plugins/lisa-cursor/skills/lisa-qa-queue/SKILL.md +28 -3
- package/plugins/lisa-cursor/skills/lisa-repair-intake/SKILL.md +94 -24
- package/plugins/lisa-cursor/skills/lisa-rework-triage/SKILL.md +32 -2
- package/plugins/lisa-cursor/skills/lisa-setup-linear/SKILL.md +5 -5
- package/plugins/lisa-cursor/skills/lisa-track/SKILL.md +1 -1
- package/plugins/lisa-cursor/skills/lisa-tracker-build-intake/SKILL.md +9 -0
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/hooks/inject-rules.sh +14 -3
- package/plugins/lisa-harper-fabric/rules/eager/harper-fabric.md +31 -0
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/hooks/inject-rules.sh +14 -3
- package/plugins/lisa-harper-fabric-copilot/rules/eager/harper-fabric.md +31 -0
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/rules/harper-fabric-reference.mdc +57 -0
- package/plugins/lisa-harper-fabric-cursor/rules/harper-fabric.mdc +32 -53
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/hooks/inject-rules.sh +14 -3
- package/plugins/lisa-phaser/rules/eager/phaser.md +44 -0
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/hooks/inject-rules.sh +14 -3
- package/plugins/lisa-phaser-copilot/rules/eager/phaser.md +44 -0
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/rules/phaser-reference.mdc +189 -0
- package/plugins/lisa-phaser-cursor/rules/phaser.mdc +45 -185
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/hooks/inject-rules.sh +14 -4
- package/plugins/lisa-rails/rules/eager/rails-conventions.md +23 -0
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/hooks/inject-rules.sh +14 -4
- package/plugins/lisa-rails-copilot/rules/eager/rails-conventions.md +23 -0
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/rules/rails-conventions-reference.mdc +181 -0
- package/plugins/lisa-rails-cursor/rules/rails-conventions.mdc +24 -177
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/materialized-artifacts.json +1 -0
- package/plugins/src/base/.claude-plugin/plugin.json +27 -0
- package/plugins/src/base/agents/linear-prd-intake.md +8 -8
- package/plugins/src/base/hooks/block-blind-automerge.sh +81 -2
- package/plugins/src/base/hooks/block-direct-issue-create.agy.sh +64 -16
- package/plugins/src/base/hooks/block-direct-issue-create.sh +293 -8
- package/plugins/src/base/hooks/block-instruction-file-edits.sh +21 -0
- package/plugins/src/base/hooks/block-managed-file-edits.sh +78 -15
- package/plugins/src/base/hooks/block-no-verify.sh +21 -0
- package/plugins/src/base/hooks/block-shell-json-parsing.sh +21 -0
- package/plugins/src/base/hooks/failure-signature-index.mjs +240 -5
- package/plugins/src/base/hooks/guard-dedupe.bash +337 -0
- package/plugins/src/base/hooks/inject-rules.sh +13 -5
- package/plugins/src/base/hooks/operational-hazards.mjs +736 -0
- package/plugins/src/base/hooks/operational-hazards.sh +28 -0
- package/plugins/src/base/hooks/parity-safety-net.sh +29 -1
- package/plugins/src/base/hooks/threshold-ratchet-compare.mjs +102 -21
- package/plugins/src/base/hooks/threshold-ratchet-families.mjs +130 -2
- package/plugins/src/base/hooks/threshold-ratchet.mjs +63 -13
- package/plugins/src/base/hooks/worktree-binding-guard.mjs +183 -1
- package/plugins/src/base/hooks/worktree-binding-guard.sh +21 -0
- package/plugins/src/base/rules/eager/00-rule-index.md +1 -0
- package/plugins/src/base/rules/eager/operational-hazards.md +50 -0
- package/plugins/src/base/rules/eager/tracked-work.md +1 -1
- package/plugins/src/base/rules/reference/config-resolution.md +1 -1
- package/plugins/src/base/rules/reference/leaf-only-lifecycle.md +1 -1
- package/plugins/src/base/rules/reference/operational-hazards.md +115 -0
- package/plugins/src/base/rules/reference/work-item-trailer-definition.md +129 -0
- package/plugins/src/base/scripts/intake-blocker-reprobe.mjs +407 -26
- package/plugins/src/base/scripts/qa-signal-lifecycle.mjs +507 -0
- package/plugins/src/base/skills/lisa-drive-pr-to-merge/SKILL.md +130 -19
- package/plugins/src/base/skills/lisa-github-build-intake/SKILL.md +27 -4
- package/plugins/src/base/skills/lisa-github-prd-intake/SKILL.md +1 -1
- package/plugins/src/base/skills/lisa-github-validate-issue/SKILL.md +22 -0
- package/plugins/src/base/skills/lisa-github-verify/SKILL.md +14 -0
- package/plugins/src/base/skills/lisa-github-write-issue/SKILL.md +51 -0
- package/plugins/src/base/skills/lisa-intake/SKILL.md +1 -1
- package/plugins/src/base/skills/lisa-jira-build-intake/SKILL.md +27 -4
- package/plugins/src/base/skills/lisa-jira-validate-ticket/SKILL.md +22 -0
- package/plugins/src/base/skills/lisa-jira-verify/SKILL.md +14 -0
- package/plugins/src/base/skills/lisa-jira-write-ticket/SKILL.md +51 -0
- package/plugins/src/base/skills/lisa-linear-access/SKILL.md +55 -2
- package/plugins/src/base/skills/lisa-linear-build-intake/SKILL.md +27 -4
- package/plugins/src/base/skills/lisa-linear-prd-intake/SKILL.md +48 -31
- package/plugins/src/base/skills/lisa-linear-to-tracker/SKILL.md +3 -3
- package/plugins/src/base/skills/lisa-linear-validate-issue/SKILL.md +22 -0
- package/plugins/src/base/skills/lisa-linear-verify/SKILL.md +14 -0
- package/plugins/src/base/skills/lisa-linear-write-issue/SKILL.md +54 -3
- package/plugins/src/base/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
- package/plugins/src/base/skills/lisa-qa-clear/SKILL.md +19 -7
- package/plugins/src/base/skills/lisa-qa-fail/SKILL.md +28 -3
- package/plugins/src/base/skills/lisa-qa-queue/SKILL.md +28 -3
- package/plugins/src/base/skills/lisa-repair-intake/SKILL.md +94 -24
- package/plugins/src/base/skills/lisa-rework-triage/SKILL.md +32 -2
- package/plugins/src/base/skills/lisa-setup-linear/SKILL.md +5 -5
- package/plugins/src/base/skills/lisa-track/SKILL.md +1 -1
- package/plugins/src/base/skills/lisa-tracker-build-intake/SKILL.md +9 -0
- package/plugins/src/harper-fabric/hooks/inject-rules.sh +14 -3
- package/plugins/src/harper-fabric/rules/eager/harper-fabric.md +31 -0
- package/plugins/src/phaser/hooks/inject-rules.sh +14 -3
- package/plugins/src/phaser/rules/eager/phaser.md +44 -0
- package/plugins/src/rails/hooks/inject-rules.sh +14 -4
- package/plugins/src/rails/rules/eager/rails-conventions.md +23 -0
- package/rails/copy-overwrite/scripts/check-threshold-ratchet.mjs +63 -13
- package/rails/copy-overwrite/scripts/threshold-ratchet-compare.mjs +102 -21
- package/rails/copy-overwrite/scripts/threshold-ratchet-families.mjs +130 -2
- package/rails/create-only/.github/workflows/ci.yml +8 -0
- package/rails/create-only/.github/workflows/deploy.yml +22 -0
- package/scripts/build-plugins.sh +2 -1
- package/scripts/check-engine-floor.mjs +361 -0
- package/scripts/check-guard-parity-notes.mjs +709 -0
- package/scripts/check-template-workflow-refs.mjs +9 -0
- package/scripts/check-third-party-action-pins.mjs +17 -1
- package/scripts/check-workflow-contract-assertions.mjs +480 -0
- package/scripts/copy-opencode-plugin-templates.mjs +1 -0
- package/scripts/deployed-guard-advice.mjs +636 -0
- package/scripts/generate-agy-plugin-artifacts.mjs +35 -10
- package/scripts/generate-export-surface.mjs +105 -19
- package/scripts/generate-two-channel-couplings.ts +143 -212
- package/scripts/lisa-enforcement-fallback.sh +31 -0
- package/scripts/measure-scripts-profile-gap.mts +361 -0
- package/scripts/mutation-performance-measure.mjs +21 -5
- package/scripts/reconcile-release-tags.mjs +65 -84
- package/scripts/two-channel-couplings.json +302 -70
- package/scripts/workflow-contract-assertion.sh +47 -0
- package/typescript/copy-overwrite/.lintstagedrc.json +1 -0
- package/typescript/copy-overwrite/eslint.ignore.config.json +1 -0
- package/typescript/copy-overwrite/scripts/check-nightly-e2e-health.mjs +527 -53
- package/typescript/copy-overwrite/scripts/check-skipped-required-checks.mjs +301 -13
- package/typescript/copy-overwrite/scripts/check-threshold-ratchet.mjs +63 -13
- package/typescript/copy-overwrite/scripts/threshold-ratchet-compare.mjs +102 -21
- package/typescript/copy-overwrite/scripts/threshold-ratchet-families.mjs +130 -2
- package/typescript/create-only/.github/workflows/ci.yml +7 -0
- /package/plugins/lisa-harper-fabric/rules/{harper-fabric.md → reference/harper-fabric.md} +0 -0
- /package/plugins/lisa-harper-fabric-copilot/rules/{harper-fabric.md → reference/harper-fabric.md} +0 -0
- /package/plugins/lisa-phaser/rules/{phaser.md → reference/phaser.md} +0 -0
- /package/plugins/lisa-phaser-copilot/rules/{phaser.md → reference/phaser.md} +0 -0
- /package/plugins/lisa-rails/rules/{rails-conventions.md → reference/rails-conventions.md} +0 -0
- /package/plugins/lisa-rails-copilot/rules/{rails-conventions.md → reference/rails-conventions.md} +0 -0
- /package/plugins/src/harper-fabric/rules/{harper-fabric.md → reference/harper-fabric.md} +0 -0
- /package/plugins/src/phaser/rules/{phaser.md → reference/phaser.md} +0 -0
- /package/plugins/src/rails/rules/{rails-conventions.md → reference/rails-conventions.md} +0 -0
|
@@ -345,6 +345,8 @@ export const VIOLATIONS = Object.freeze({
|
|
|
345
345
|
reviewWaived: "review_evidence_waived",
|
|
346
346
|
reviewUnsatisfied: "review_evidence_unsatisfied",
|
|
347
347
|
reviewCarried: "review_evidence_carried_unreviewed",
|
|
348
|
+
reviewObjected: "review_evidence_objected",
|
|
349
|
+
reviewObjectionUnread: "review_evidence_objection_unread",
|
|
348
350
|
});
|
|
349
351
|
|
|
350
352
|
/**
|
|
@@ -395,10 +397,14 @@ export const REVIEW_DESCRIPTION_DEFAULTS = Object.freeze({
|
|
|
395
397
|
* what any change here can achieve: **the description is not a function of
|
|
396
398
|
* whether a review happened.** `proof` is matched whole-string, so a
|
|
397
399
|
* reviewed-and-objected pull request still carrying `Review rate limited` can
|
|
398
|
-
* never reach it. Settling the question needs a second input —
|
|
399
|
-
*
|
|
400
|
-
*
|
|
401
|
-
*
|
|
400
|
+
* never reach it. Settling the question needs a second input — the review
|
|
401
|
+
* OBJECTS — and that input now exists, in the one place it can exist without
|
|
402
|
+
* turning this classifier into a network client (CodySwannGT/lisa#3706, #3827):
|
|
403
|
+
* {@link readReviewObjection} fetches `pulls/{pr}/reviews` from the ALREADY
|
|
404
|
+
* network-bound {@link inspectVacuity} arm, beside the check, carried-batch and
|
|
405
|
+
* waive-rate reads it already makes, and {@link readObjectionAtHead} judges the
|
|
406
|
+
* result purely. Everything in THIS classifier still reads only a description,
|
|
407
|
+
* and still may not conclude from `rate limited` that nothing ran.
|
|
402
408
|
*
|
|
403
409
|
* So the phrase stays in `no_work` — denying credit on it remains correct and
|
|
404
410
|
* remains the safe direction — and only the WORDING changes. For these phrases
|
|
@@ -482,6 +488,12 @@ export const NEVER_BLOCKING = Object.freeze([
|
|
|
482
488
|
// constituents' own gates already went red, on branches no ruleset watches.
|
|
483
489
|
// What was missing was that the batch rendered green anyway.
|
|
484
490
|
VIOLATIONS.reviewCarried,
|
|
491
|
+
// "The objection probe could not read the reviews" is the ABSENCE of a
|
|
492
|
+
// reading, not a finding about the code. It is reported — and it caps the
|
|
493
|
+
// rendered verdict, see `reviewGateVerdict` — but reddening a build because
|
|
494
|
+
// one API call failed would punish an author for a network, which is the
|
|
495
|
+
// "gate that gets deleted" shape this file names three times already.
|
|
496
|
+
VIOLATIONS.reviewObjectionUnread,
|
|
485
497
|
]);
|
|
486
498
|
|
|
487
499
|
/**
|
|
@@ -521,6 +533,7 @@ export const NEVER_BLOCKING = Object.freeze([
|
|
|
521
533
|
export const REPORT_ONLY = Object.freeze([
|
|
522
534
|
VIOLATIONS.reviewWaived,
|
|
523
535
|
VIOLATIONS.reviewCarried,
|
|
536
|
+
VIOLATIONS.reviewObjectionUnread,
|
|
524
537
|
]);
|
|
525
538
|
|
|
526
539
|
/**
|
|
@@ -534,6 +547,15 @@ export const REPORT_ONLY = Object.freeze([
|
|
|
534
547
|
*/
|
|
535
548
|
export const REVIEW_GATE_BLOCKING = Object.freeze([
|
|
536
549
|
VIOLATIONS.reviewUnsatisfied,
|
|
550
|
+
// A review that RAN AND OBJECTED is the one condition no waiver covers, and
|
|
551
|
+
// this file has said so in prose since #3221 while having no way to observe
|
|
552
|
+
// it: the objection lives in a review OBJECT, and until #3706 nothing here
|
|
553
|
+
// read one. MEASURED on this repository, 60 most recently updated merged
|
|
554
|
+
// pull requests: 2 carried a standing `CHANGES_REQUESTED` at the merged head
|
|
555
|
+
// and the gate published `REVIEWED — CodeRabbit reported "Review completed"`.
|
|
556
|
+
// Blocking on it is the same policy `reviewUnsatisfied` already carries, and
|
|
557
|
+
// it is armed by the same `--require-review-evidence` flag.
|
|
558
|
+
VIOLATIONS.reviewObjected,
|
|
537
559
|
]);
|
|
538
560
|
|
|
539
561
|
/**
|
|
@@ -588,6 +610,36 @@ const REQUIRE_REVIEW_EVIDENCE_FLAG = "--require-review-evidence";
|
|
|
588
610
|
*/
|
|
589
611
|
const WAIVE_RATE_SAMPLE_FLAG = "--waive-rate-sample";
|
|
590
612
|
|
|
613
|
+
/**
|
|
614
|
+
* How many waivers in the sample escalate a waiver from `neutral` to `failure`.
|
|
615
|
+
*
|
|
616
|
+
* ## Unset by default, and that is the whole safety property
|
|
617
|
+
*
|
|
618
|
+
* CodySwannGT/lisa#3706 asks a question this script cannot answer for a
|
|
619
|
+
* repository: "should N waivers in a row stop being tolerated?" The waiver
|
|
620
|
+
* itself is the repository owner's ruling on CodySwannGT/lisa#3221 — a pull
|
|
621
|
+
* request author cannot fix a vendor entitlement — and that ruling stands until
|
|
622
|
+
* an owner replaces it. What was missing was not the judgement but the LEVER:
|
|
623
|
+
* the rate was already computed, printed, and acted on by nothing.
|
|
624
|
+
*
|
|
625
|
+
* So this ships the lever and leaves it down. With the flag absent, every
|
|
626
|
+
* waiver renders exactly as it did before, and no workflow in this tree passes
|
|
627
|
+
* it. Passing `--waive-rate-escalate=N` is a deliberate act with a number
|
|
628
|
+
* attached, and the number is measurable first: the same run prints the rate it
|
|
629
|
+
* would be compared against.
|
|
630
|
+
*
|
|
631
|
+
* ## It escalates the RENDERING, not the exit code
|
|
632
|
+
*
|
|
633
|
+
* {@link VIOLATIONS.reviewWaived} stays in {@link NEVER_BLOCKING} and in
|
|
634
|
+
* {@link REPORT_ONLY} whatever this is set to. Those two arrays ARE the #3221
|
|
635
|
+
* ruling, and a flag that reached through them would repeal an owner's decision
|
|
636
|
+
* from a command line. What escalation changes is the conclusion published on
|
|
637
|
+
* the check run — the one surface a merge decision reads — from `neutral` to
|
|
638
|
+
* `failure`. Whether that red can block anything is a separate, deliberate,
|
|
639
|
+
* human act: promoting the context in the live ruleset.
|
|
640
|
+
*/
|
|
641
|
+
const WAIVE_RATE_ESCALATE_FLAG = "--waive-rate-escalate";
|
|
642
|
+
|
|
591
643
|
/**
|
|
592
644
|
* The one call the waive-rate sample makes.
|
|
593
645
|
*
|
|
@@ -2082,6 +2134,166 @@ export function evaluateReviewGate(declaration, checks, options = {}) {
|
|
|
2082
2134
|
return { violations, states, conditions, descriptions, checked };
|
|
2083
2135
|
}
|
|
2084
2136
|
|
|
2137
|
+
/**
|
|
2138
|
+
* The review-OBJECT state that means a reviewer objected.
|
|
2139
|
+
*
|
|
2140
|
+
* A review object, never a status description. The two are different data and
|
|
2141
|
+
* the distinction is the entire content of CodySwannGT/lisa#3706: measured on
|
|
2142
|
+
* #3762, `CodeRabbit` reported `success` with the description
|
|
2143
|
+
* `Review rate limited` on a pull request it HAD reviewed, posting
|
|
2144
|
+
* `CHANGES_REQUESTED` that found a real defect. The same string, on a different
|
|
2145
|
+
* pull request the same week, meant nobody had read anything. A classifier
|
|
2146
|
+
* reading the string collapses those two, and it collapses them PERMISSIVELY.
|
|
2147
|
+
*/
|
|
2148
|
+
export const REVIEW_OBJECTION_STATE = "CHANGES_REQUESTED";
|
|
2149
|
+
|
|
2150
|
+
/**
|
|
2151
|
+
* Whether an objection STANDS at this head, from the review objects.
|
|
2152
|
+
*
|
|
2153
|
+
* ## Filtered to the head, in both directions
|
|
2154
|
+
*
|
|
2155
|
+
* A review is counted only when its `commit_id` is this head. Leaving the
|
|
2156
|
+
* filter out breaks the gate in whichever direction the data happens to point:
|
|
2157
|
+
* a stale `CHANGES_REQUESTED` from three pushes ago would block work a newer
|
|
2158
|
+
* head already fixed (CodySwannGT/lisa#3720), and that is a false RED, which
|
|
2159
|
+
* this file argues repeatedly is the expensive kind to introduce while chasing
|
|
2160
|
+
* a false green. A review with no `commit_id` is dropped for the same reason —
|
|
2161
|
+
* unknown is not "at this head".
|
|
2162
|
+
*
|
|
2163
|
+
* MEASURED on the 60 most recently updated merged pull requests in this
|
|
2164
|
+
* repository: 4 carried a `CHANGES_REQUESTED` from the reviewer, and only 2 of
|
|
2165
|
+
* those were at the merged head. An unfiltered read would have reddened the
|
|
2166
|
+
* other two for objections their authors had already addressed.
|
|
2167
|
+
*
|
|
2168
|
+
* ## Reported, never inferred
|
|
2169
|
+
*
|
|
2170
|
+
* This says only what the review objects say. It does NOT consult the status
|
|
2171
|
+
* description, and nothing about a waiver, a rate limit or an entitlement
|
|
2172
|
+
* reaches it — that is the point of having a second input at all.
|
|
2173
|
+
* @param {ReadonlyArray<{state?: string, commitSha?: string, author?: string}>} reviews - Review objects
|
|
2174
|
+
* @param {string|undefined} headSha - The head commit under inspection
|
|
2175
|
+
* @returns {{objected: boolean, reviewers: string[], staleDropped: number}} What stands at head
|
|
2176
|
+
*/
|
|
2177
|
+
export function readObjectionAtHead(reviews, headSha) {
|
|
2178
|
+
const all = reviews ?? [];
|
|
2179
|
+
const atHead =
|
|
2180
|
+
headSha === undefined || headSha === ""
|
|
2181
|
+
? []
|
|
2182
|
+
: all.filter(review => review?.commitSha === headSha);
|
|
2183
|
+
const objections = atHead.filter(
|
|
2184
|
+
review =>
|
|
2185
|
+
String(review?.state ?? "").toUpperCase() === REVIEW_OBJECTION_STATE
|
|
2186
|
+
);
|
|
2187
|
+
return {
|
|
2188
|
+
objected: objections.length > 0,
|
|
2189
|
+
reviewers: [
|
|
2190
|
+
...new Set(objections.map(review => String(review?.author ?? "unknown"))),
|
|
2191
|
+
].sort((left, right) => left.localeCompare(right)),
|
|
2192
|
+
staleDropped: all.length - atHead.length,
|
|
2193
|
+
};
|
|
2194
|
+
}
|
|
2195
|
+
|
|
2196
|
+
/**
|
|
2197
|
+
* Reads the review objects on one pull request.
|
|
2198
|
+
*
|
|
2199
|
+
* REST rather than the rollup, for the reason the description read is REST:
|
|
2200
|
+
* `gh pr checks` and `gh pr view --json statusCheckRollup` cannot see a review
|
|
2201
|
+
* object at all, so neither can say whether an objection stands. The endpoint
|
|
2202
|
+
* carries `commit_id`, which is what makes the staleness filter possible.
|
|
2203
|
+
* @param {string|number} pr - The pull request
|
|
2204
|
+
* @param {string} [repo] - `OWNER/NAME`; defaults to the current repository
|
|
2205
|
+
* @returns {Array<{state: string, commitSha: string, author: string}>} Review objects
|
|
2206
|
+
* @throws {Error} When the slug cannot be resolved or `gh` cannot answer
|
|
2207
|
+
*/
|
|
2208
|
+
export function fetchPullRequestReviews(pr, repo) {
|
|
2209
|
+
const slug = resolveRepoSlug(repo);
|
|
2210
|
+
if (slug === undefined) {
|
|
2211
|
+
throw new Error(
|
|
2212
|
+
`check-skipped-required-checks: cannot read the reviews on PR ${pr} without an OWNER/NAME. Pass \`--repo=OWNER/NAME\`, or set GITHUB_REPOSITORY.`
|
|
2213
|
+
);
|
|
2214
|
+
}
|
|
2215
|
+
return ghApiPaginatedArray(
|
|
2216
|
+
`repos/${slug}/pulls/${pr}/reviews?per_page=100`,
|
|
2217
|
+
"[.[] | {state: .state, commitSha: .commit_id, author: .user.login}]"
|
|
2218
|
+
);
|
|
2219
|
+
}
|
|
2220
|
+
|
|
2221
|
+
/**
|
|
2222
|
+
* Reads and judges whether a review objection stands at this head.
|
|
2223
|
+
*
|
|
2224
|
+
* FAILING TO READ IS NOT PASSING, the same way {@link readCarriedReview} means
|
|
2225
|
+
* it: an unreadable reviews endpoint reports UNREAD, which caps the rendered
|
|
2226
|
+
* verdict below `REVIEWED` rather than reporting a clean one nothing looked at.
|
|
2227
|
+
* It does not redden the build — see {@link NEVER_BLOCKING} — because the
|
|
2228
|
+
* failure is the gate's own, not the author's.
|
|
2229
|
+
* @param {string|number} pr - The pull request under inspection
|
|
2230
|
+
* @param {string|undefined} repo - `OWNER/NAME`; defaults to the current repository
|
|
2231
|
+
* @param {string|undefined} headSha - The head commit under inspection
|
|
2232
|
+
* @param {{fetchReviews?: Function}} [options] - Injection seam
|
|
2233
|
+
* @returns {{violations: object[], objected: boolean, reviewers: string[], staleDropped: number, unread?: string}} Findings and the standing
|
|
2234
|
+
*/
|
|
2235
|
+
export function readReviewObjection(pr, repo, headSha, options = {}) {
|
|
2236
|
+
const read = options.fetchReviews ?? fetchPullRequestReviews;
|
|
2237
|
+
let reviews;
|
|
2238
|
+
try {
|
|
2239
|
+
reviews = read(pr, repo);
|
|
2240
|
+
} catch (error) {
|
|
2241
|
+
const why = error instanceof Error ? error.message : String(error);
|
|
2242
|
+
return {
|
|
2243
|
+
violations: [
|
|
2244
|
+
{
|
|
2245
|
+
kind: VIOLATIONS.reviewObjectionUnread,
|
|
2246
|
+
token: "objection",
|
|
2247
|
+
contexts: [],
|
|
2248
|
+
message: `The review objects on this pull request could not be read (${why}), so this run cannot say whether a reviewer OBJECTED at ${headSha ?? "the head commit"}. A status description cannot answer it: the same phrase has been observed on a pull request nothing reviewed and on one a reviewer objected to. Refusing to report a clean review nothing looked at.`,
|
|
2249
|
+
},
|
|
2250
|
+
],
|
|
2251
|
+
objected: false,
|
|
2252
|
+
reviewers: [],
|
|
2253
|
+
staleDropped: 0,
|
|
2254
|
+
unread: why,
|
|
2255
|
+
};
|
|
2256
|
+
}
|
|
2257
|
+
const standing = readObjectionAtHead(reviews, headSha);
|
|
2258
|
+
if (!standing.objected) return { ...standing, violations: [] };
|
|
2259
|
+
return {
|
|
2260
|
+
...standing,
|
|
2261
|
+
violations: [
|
|
2262
|
+
{
|
|
2263
|
+
kind: VIOLATIONS.reviewObjected,
|
|
2264
|
+
condition: REVIEW_GATE_CONDITIONS.objected,
|
|
2265
|
+
token: "objection",
|
|
2266
|
+
contexts: [],
|
|
2267
|
+
message: `A review RAN AND OBJECTED at ${headSha ?? "this head"}: ${standing.reviewers.join(", ")} submitted ${REVIEW_OBJECTION_STATE}. READ THE OBJECTION. This is the one condition no waiver covers, and it is invisible in the check's conclusion and in its description alike — both have been observed reading exactly as they do on a pull request nobody reviewed.${citeHeadSha(headSha)}`,
|
|
2268
|
+
},
|
|
2269
|
+
],
|
|
2270
|
+
};
|
|
2271
|
+
}
|
|
2272
|
+
|
|
2273
|
+
/**
|
|
2274
|
+
* Whether a sampled waive rate has reached the escalation threshold.
|
|
2275
|
+
*
|
|
2276
|
+
* Three refusals, and each one is a direction an escalation could go wrong:
|
|
2277
|
+
*
|
|
2278
|
+
* - **No threshold** — nobody asked. The shipped default, and the reason this
|
|
2279
|
+
* change moves no merge.
|
|
2280
|
+
* - **No rate** — the sample failed. {@link sampleWaiveRate} is best-effort by
|
|
2281
|
+
* construction, so an unreachable API must cost a sentence, never a red. An
|
|
2282
|
+
* escalation on an unmeasured rate would be a verdict from a measurement that
|
|
2283
|
+
* never happened, which is the family of defect this whole file is about.
|
|
2284
|
+
* - **Nothing sampled** — a zero denominator. `0 >= 0` is true and would
|
|
2285
|
+
* escalate every waiver on an empty sample.
|
|
2286
|
+
* @param {{waived?: number, sampled?: number}|undefined} rate - The sampled tally
|
|
2287
|
+
* @param {number|undefined} threshold - Waivers at or above which to escalate
|
|
2288
|
+
* @returns {boolean} Whether the waiver escalates
|
|
2289
|
+
*/
|
|
2290
|
+
export function waiverEscalates(rate, threshold) {
|
|
2291
|
+
if (!Number.isInteger(threshold) || threshold <= 0) return false;
|
|
2292
|
+
if (rate === undefined) return false;
|
|
2293
|
+
if (!Number.isInteger(rate.sampled) || rate.sampled <= 0) return false;
|
|
2294
|
+
return Number(rate.waived) >= threshold;
|
|
2295
|
+
}
|
|
2296
|
+
|
|
2085
2297
|
/**
|
|
2086
2298
|
* How many carried pull requests this will account for before it gives up.
|
|
2087
2299
|
*
|
|
@@ -2244,6 +2456,21 @@ function waiveRateSuffix(rate) {
|
|
|
2244
2456
|
: ` · waived on ${rate.waived} of the last ${rate.sampled} merged pull requests`;
|
|
2245
2457
|
}
|
|
2246
2458
|
|
|
2459
|
+
/**
|
|
2460
|
+
* The unread-objection sentence appended to a verdict title, or nothing.
|
|
2461
|
+
*
|
|
2462
|
+
* Only when the probe FAILED. A probe that ran and found nothing standing is a
|
|
2463
|
+
* reading, and a title that announced it on every clean pull request would be
|
|
2464
|
+
* the noise that gets a sentence skimmed past on the one run it mattered.
|
|
2465
|
+
* @param {{unread?: string}|undefined} objection - The objection standing
|
|
2466
|
+
* @returns {string} The sentence, or an empty string
|
|
2467
|
+
*/
|
|
2468
|
+
function objectionSuffix(objection) {
|
|
2469
|
+
return objection?.unread === undefined
|
|
2470
|
+
? ""
|
|
2471
|
+
: " · whether a reviewer OBJECTED at this head was NOT read";
|
|
2472
|
+
}
|
|
2473
|
+
|
|
2247
2474
|
/**
|
|
2248
2475
|
* The carried-batch sentence appended to a verdict title, or nothing.
|
|
2249
2476
|
*
|
|
@@ -2289,10 +2516,18 @@ function carriedSuffix(carried) {
|
|
|
2289
2516
|
* out: every state above is read from THIS pull request's head, which is the
|
|
2290
2517
|
* one commit a batch integration pull request does not speak for.
|
|
2291
2518
|
*
|
|
2292
|
-
*
|
|
2519
|
+
* AND AN OBJECTION OUTRANKS ALL OF IT (#3706). Every state above is read from a
|
|
2520
|
+
* vendor's status DESCRIPTION, and the description has been measured saying the
|
|
2521
|
+
* opposite of the truth in both directions on the same string: `Review rate
|
|
2522
|
+
* limited` on a pull request nothing read, and `Review rate limited` on one the
|
|
2523
|
+
* reviewer read and objected to. `reading.objection` is the second input that
|
|
2524
|
+
* settles it, and it comes from review OBJECTS.
|
|
2525
|
+
*
|
|
2526
|
+
* @param {{states?: Record<string, string>, conditions?: Record<string, string>, descriptions?: Record<string, string>, refusal?: {kind: string}|null, waiveRate?: {waived: number, sampled: number}, carried?: {unreviewed?: readonly string[], reviewed?: number, unread?: string}, objection?: {objected?: boolean, reviewers?: readonly string[], unread?: string}, escalate?: number}} reading -
|
|
2293
2527
|
* The gate's per-check states and conditions, the descriptions they were read
|
|
2294
|
-
* from, any refusal, an optional sampled waive rate,
|
|
2295
|
-
*
|
|
2528
|
+
* from, any refusal, an optional sampled waive rate, the tally for the pull
|
|
2529
|
+
* requests this one CARRIES, whether a review objection stands at this head,
|
|
2530
|
+
* and any waive-rate escalation threshold this repository set
|
|
2296
2531
|
* @returns {{verdict: string, conclusion: string, title: string}} What to publish
|
|
2297
2532
|
*/
|
|
2298
2533
|
/**
|
|
@@ -2323,7 +2558,27 @@ export function reviewGateVerdict(reading = {}) {
|
|
|
2323
2558
|
const descriptions = reading.descriptions ?? {};
|
|
2324
2559
|
const names = Object.keys(states);
|
|
2325
2560
|
const carried = carriedSuffix(reading.carried);
|
|
2326
|
-
const suffix = `${carried}${waiveRateSuffix(reading.waiveRate)}`;
|
|
2561
|
+
const suffix = `${carried}${objectionSuffix(reading.objection)}${waiveRateSuffix(reading.waiveRate)}`;
|
|
2562
|
+
|
|
2563
|
+
// FIRST, AND ABOVE EVERY STATE READ FROM A DESCRIPTION (#3706). An objection
|
|
2564
|
+
// is the one thing here read from review OBJECTS rather than from a vendor
|
|
2565
|
+
// sentence, and it is the only reading that establishes a review HAPPENED and
|
|
2566
|
+
// said no. Every branch below it is settled by a description, and the
|
|
2567
|
+
// description has now been measured saying the opposite of the truth in both
|
|
2568
|
+
// directions on the same string. So an objection outranks a waiver — which
|
|
2569
|
+
// would otherwise merge a pull request a reviewer objected to, the permissive
|
|
2570
|
+
// collapse this ticket is about — and it outranks `undetermined`, because a
|
|
2571
|
+
// gate that stopped waiting has observed nothing while this has observed
|
|
2572
|
+
// something.
|
|
2573
|
+
if (reading.objection?.objected === true) {
|
|
2574
|
+
return {
|
|
2575
|
+
verdict: REVIEW_GATE_STATES.unsatisfied,
|
|
2576
|
+
conclusion: REVIEW_VERDICT_CONCLUSIONS.unsatisfied,
|
|
2577
|
+
title: fitTitle(
|
|
2578
|
+
`OBJECTED — a review RAN and requested changes at this head: ${reading.objection.reviewers.join(", ")} submitted ${REVIEW_OBJECTION_STATE}. This is NOT a waiver case and NOT an unreviewed one — READ THE OBJECTION${suffix}`
|
|
2579
|
+
),
|
|
2580
|
+
};
|
|
2581
|
+
}
|
|
2327
2582
|
|
|
2328
2583
|
if (reading.refusal || names.length === 0) {
|
|
2329
2584
|
return {
|
|
@@ -2399,6 +2654,11 @@ export function reviewGateVerdict(reading = {}) {
|
|
|
2399
2654
|
name => states[name] === REVIEW_GATE_STATES.waived
|
|
2400
2655
|
);
|
|
2401
2656
|
if (waived.length > 0) {
|
|
2657
|
+
// The lever from #3706, and it is DOWN unless a repository set it. See
|
|
2658
|
+
// `WAIVE_RATE_ESCALATE_FLAG`: the waiver's severity is the owner's ruling on
|
|
2659
|
+
// #3221 and stays report-only in the exit code either way; what a threshold
|
|
2660
|
+
// changes is the conclusion published where a merge decision reads it.
|
|
2661
|
+
const escalated = waiverEscalates(reading.waiveRate, reading.escalate);
|
|
2402
2662
|
// AND THE TITLE IS WHERE THE CLAIM IS READ (#3706). "This pull request is
|
|
2403
2663
|
// UNREVIEWED" is the sentence an operator quotes into a merge disclosure,
|
|
2404
2664
|
// and it was printed unconditionally — measured false on 7 of the last 34
|
|
@@ -2406,17 +2666,18 @@ export function reviewGateVerdict(reading = {}) {
|
|
|
2406
2666
|
// head. Severity does not move: both leads publish `neutral`, and the
|
|
2407
2667
|
// waiver's rationale is untouched. Only the claim changes, and only when
|
|
2408
2668
|
// EVERY waived check saw review activity, so one genuinely silent check
|
|
2409
|
-
// alongside a reviewed one still leads with UNREVIEWED.
|
|
2669
|
+
// alongside a reviewed one still leads with UNREVIEWED. Orthogonal to the
|
|
2670
|
+
// escalation above: the rate decides the LEAD, this decides the CLAIM.
|
|
2410
2671
|
const allWithReview = waived.every(
|
|
2411
2672
|
name => conditions[name] === REVIEW_GATE_CONDITIONS.waivedWithReview
|
|
2412
2673
|
);
|
|
2413
2674
|
return {
|
|
2414
2675
|
verdict: REVIEW_GATE_STATES.waived,
|
|
2415
|
-
conclusion:
|
|
2676
|
+
conclusion: escalated
|
|
2677
|
+
? REVIEW_VERDICT_CONCLUSIONS.unsatisfied
|
|
2678
|
+
: REVIEW_VERDICT_CONCLUSIONS.waived,
|
|
2416
2679
|
title: fitTitle(
|
|
2417
|
-
allWithReview
|
|
2418
|
-
? `WAIVED — the review check could not review, and merging is a decision taken on that basis; but this pull request DOES carry review activity that raised no objection, so do NOT record it as unreviewed: ${waived.map(quote).join("; ")}${suffix}`
|
|
2419
|
-
: `WAIVED — this pull request is UNREVIEWED and merging it is a decision taken on that basis: ${waived.map(quote).join("; ")}${suffix}`
|
|
2680
|
+
`${escalated ? "WAIVED, AND THE WAIVER RATE HAS PASSED THE THRESHOLD THIS REPOSITORY SET" : "WAIVED"} — ${allWithReview ? "the review check could not review, and merging is a decision taken on that basis; but this pull request DOES carry review activity that raised no objection, so do NOT record it as unreviewed" : "this pull request is UNREVIEWED and merging it is a decision taken on that basis"}: ${waived.map(quote).join("; ")}${suffix}`
|
|
2420
2681
|
),
|
|
2421
2682
|
};
|
|
2422
2683
|
}
|
|
@@ -2443,6 +2704,22 @@ export function reviewGateVerdict(reading = {}) {
|
|
|
2443
2704
|
};
|
|
2444
2705
|
}
|
|
2445
2706
|
|
|
2707
|
+
// A review ran and nothing here read whether it OBJECTED. Capped at `waived`
|
|
2708
|
+
// for the reason the carried branch is: `REVIEWED` would report a clean
|
|
2709
|
+
// review on the strength of a probe that failed, and the two states this file
|
|
2710
|
+
// exists to keep apart are "a review said nothing was wrong" and "nothing
|
|
2711
|
+
// established that". It blocks nothing — the failed read is the gate's, not
|
|
2712
|
+
// the author's — and it stops looking like a pass.
|
|
2713
|
+
if (reading.objection?.unread !== undefined) {
|
|
2714
|
+
return {
|
|
2715
|
+
verdict: REVIEW_GATE_STATES.waived,
|
|
2716
|
+
conclusion: REVIEW_VERDICT_CONCLUSIONS.waived,
|
|
2717
|
+
title: fitTitle(
|
|
2718
|
+
`REVIEWED, OBJECTION STANDING UNKNOWN — the review ran, and whether it requested changes at this head could not be read: ${names.map(quote).join("; ")}${suffix}`
|
|
2719
|
+
),
|
|
2720
|
+
};
|
|
2721
|
+
}
|
|
2722
|
+
|
|
2446
2723
|
return {
|
|
2447
2724
|
verdict: REVIEW_GATE_STATES.satisfied,
|
|
2448
2725
|
conclusion: REVIEW_VERDICT_CONCLUSIONS.satisfied,
|
|
@@ -3615,6 +3892,13 @@ export function inspectVacuity(argv, declaration, options = {}) {
|
|
|
3615
3892
|
const carried = requireReviewEvidence
|
|
3616
3893
|
? readCarriedReview(declaration, pr, repo, options)
|
|
3617
3894
|
: undefined;
|
|
3895
|
+
// #3706. Everything above is settled by a vendor's status DESCRIPTION, and
|
|
3896
|
+
// the description does not answer the question the gate is asking. This is
|
|
3897
|
+
// the second input — the review OBJECTS — and it is armed by the same flag as
|
|
3898
|
+
// the carried arm, so an ordinary run pays no read it did not ask for.
|
|
3899
|
+
const objection = requireReviewEvidence
|
|
3900
|
+
? readReviewObjection(pr, repo, read.headSha, options)
|
|
3901
|
+
: undefined;
|
|
3618
3902
|
// Sampled ONLY when this pull request is itself waived. The rate answers
|
|
3619
3903
|
// "is this the exception or the rule?", a question that only arises once a
|
|
3620
3904
|
// waiver is on the table, and every other run keeps the sampler's network
|
|
@@ -3639,6 +3923,7 @@ export function inspectVacuity(argv, declaration, options = {}) {
|
|
|
3639
3923
|
...absent.violations,
|
|
3640
3924
|
...gate.violations,
|
|
3641
3925
|
...(carried?.violations ?? []),
|
|
3926
|
+
...(objection?.violations ?? []),
|
|
3642
3927
|
],
|
|
3643
3928
|
absent: absent.absent,
|
|
3644
3929
|
gateStates: gate.states,
|
|
@@ -3646,12 +3931,15 @@ export function inspectVacuity(argv, declaration, options = {}) {
|
|
|
3646
3931
|
gateDescriptions: gate.descriptions,
|
|
3647
3932
|
waiveRate,
|
|
3648
3933
|
carried,
|
|
3934
|
+
objection,
|
|
3649
3935
|
verdict: reviewGateVerdict({
|
|
3650
3936
|
states: gate.states,
|
|
3651
3937
|
conditions: gate.conditions,
|
|
3652
3938
|
descriptions: gate.descriptions,
|
|
3653
3939
|
waiveRate,
|
|
3654
3940
|
carried,
|
|
3941
|
+
objection,
|
|
3942
|
+
escalate: readIntegerFlag(argv, WAIVE_RATE_ESCALATE_FLAG, undefined),
|
|
3655
3943
|
}),
|
|
3656
3944
|
settled: read.settled,
|
|
3657
3945
|
refusal: null,
|
|
@@ -22,10 +22,20 @@
|
|
|
22
22
|
* every entry carries a written decision.
|
|
23
23
|
*
|
|
24
24
|
* Human override: `.lisa.config.json` → `thresholdRatchet.allow` entries
|
|
25
|
-
* ({ file, key, reason }). Honored ONLY from the baseline side (HEAD /
|
|
25
|
+
* ({ file, key, reason, until }). Honored ONLY from the baseline side (HEAD /
|
|
26
26
|
* merge-base), never from the change under review — an agent cannot grant
|
|
27
27
|
* itself an exception in the same change that weakens a gate. `key: "*"`
|
|
28
|
-
* allows every key in the file
|
|
28
|
+
* allows every key in the file, and reports as file-wide so it is not mistaken
|
|
29
|
+
* for a key-scoped one.
|
|
30
|
+
*
|
|
31
|
+
* Exemptions END (#3856). `until` is a `YYYY-MM-DD` day the entry is live
|
|
32
|
+
* through; past it the entry stops exempting and the weakening it permitted is
|
|
33
|
+
* refused again, naming the entry, its scope, its reason and the remedy. An
|
|
34
|
+
* entry naming no evaluable condition still exempts — that keeps a project
|
|
35
|
+
* mid-migration off a red wall — but is reported on every run until somebody
|
|
36
|
+
* gives it a condition or deletes it. Modelled on `_thresholdsDivergence` in
|
|
37
|
+
* `stryker.conf.json`, the sibling exemption that already stops exempting when
|
|
38
|
+
* it goes stale; see `threshold-ratchet-families.mjs` `ALLOW_STATE`.
|
|
29
39
|
*
|
|
30
40
|
* One exception, and only one: a PROMOTION between deploy-chain branches
|
|
31
41
|
* (`--base` + `--head`, both named in `deploy.branches`, head upstream of
|
|
@@ -49,6 +59,7 @@ import {
|
|
|
49
59
|
import {
|
|
50
60
|
applyAllowList,
|
|
51
61
|
compareFile,
|
|
62
|
+
describeAllowList,
|
|
52
63
|
formatReport,
|
|
53
64
|
} from "./threshold-ratchet-compare.mjs";
|
|
54
65
|
|
|
@@ -390,6 +401,13 @@ function run(mode, baseRef, onlyFiles, headRef) {
|
|
|
390
401
|
);
|
|
391
402
|
}
|
|
392
403
|
|
|
404
|
+
const allow = resolveAllowList(
|
|
405
|
+
root,
|
|
406
|
+
plan.baselineRef,
|
|
407
|
+
mode,
|
|
408
|
+
baseRef,
|
|
409
|
+
headRef
|
|
410
|
+
);
|
|
393
411
|
const findings = watched.flatMap(f =>
|
|
394
412
|
compareFile(
|
|
395
413
|
f,
|
|
@@ -397,28 +415,60 @@ function run(mode, baseRef, onlyFiles, headRef) {
|
|
|
397
415
|
plan.readCurrent(f)
|
|
398
416
|
)
|
|
399
417
|
);
|
|
400
|
-
|
|
418
|
+
// The allow-list inventory is printed whether or not the change produced
|
|
419
|
+
// findings. An exemption that has outlived its condition is dead weight the
|
|
420
|
+
// moment the condition passes, and reporting it only when something else has
|
|
421
|
+
// already failed is how a list nobody reads stays a list nobody reads.
|
|
422
|
+
if (findings.length === 0) {
|
|
423
|
+
reportAllowList(allow.entries, []);
|
|
424
|
+
return 0;
|
|
425
|
+
}
|
|
426
|
+
return reportFindings(findings, allow, mode);
|
|
427
|
+
}
|
|
401
428
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
429
|
+
/**
|
|
430
|
+
* Print the allow entries a human has to act on, minus the ones a refusal is
|
|
431
|
+
* about to name in full.
|
|
432
|
+
* @param {object[]} entries The resolved allow list
|
|
433
|
+
* @param {Array<{ message: string }>} expired Refusals already being printed
|
|
434
|
+
* @returns {void}
|
|
435
|
+
*/
|
|
436
|
+
function reportAllowList(entries, expired) {
|
|
437
|
+
for (const line of describeAllowList(entries)) {
|
|
438
|
+
if (expired.some(item => item.message.startsWith(line))) continue;
|
|
439
|
+
process.stdout.write(`threshold-ratchet: ${line}\n`);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Print the verdict for a change that produced findings.
|
|
445
|
+
* @param {object[]} findings Findings from every watched file
|
|
446
|
+
* @param {{ entries: object[], promotion: boolean, note: string | null }} allow
|
|
447
|
+
* The resolved allow list and its provenance
|
|
448
|
+
* @param {"hook"|"staged"|"base"} mode Comparison mode
|
|
449
|
+
* @returns {number} Process exit code (2 for hook mode, 1 otherwise; 0 clean)
|
|
450
|
+
*/
|
|
451
|
+
function reportFindings(findings, allow, mode) {
|
|
409
452
|
const split = partitionCarriedEntries(findings, allow.promotion);
|
|
410
|
-
const { blocked, allowed } = applyAllowList(
|
|
453
|
+
const { blocked, allowed, expired } = applyAllowList(
|
|
454
|
+
split.rest,
|
|
455
|
+
allow.entries
|
|
456
|
+
);
|
|
411
457
|
if (allow.note) process.stdout.write(`${allow.note}\n`);
|
|
458
|
+
reportAllowList(allow.entries, expired);
|
|
412
459
|
for (const finding of split.carried) {
|
|
413
460
|
process.stdout.write(
|
|
414
461
|
`threshold-ratchet: carried forward by this promotion, approved upstream — ${finding.message}\n`
|
|
415
462
|
);
|
|
416
463
|
}
|
|
417
|
-
for (const
|
|
464
|
+
for (const item of allowed) {
|
|
418
465
|
process.stdout.write(
|
|
419
|
-
`threshold-ratchet:
|
|
466
|
+
`threshold-ratchet: ${item.message} (.lisa.config.json exception)\n`
|
|
420
467
|
);
|
|
421
468
|
}
|
|
469
|
+
for (const item of expired) {
|
|
470
|
+
process.stderr.write(`threshold-ratchet: refused — ${item.message}\n`);
|
|
471
|
+
}
|
|
422
472
|
if (blocked.length === 0) return 0;
|
|
423
473
|
process.stderr.write(`${formatReport(blocked)}\n`);
|
|
424
474
|
return mode === "hook" ? 2 : 1;
|