@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
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Hook wrapper for the short-lived operational-hazard ledger
|
|
3
|
+
# (CodySwannGT/lisa#3681).
|
|
4
|
+
#
|
|
5
|
+
# Two events, one script:
|
|
6
|
+
# --session-start SessionStart / SubagentStart — deliver every hazard that
|
|
7
|
+
# applies right now, and stamp what this session was born
|
|
8
|
+
# knowing. This is the half a fan-out cannot reach: a
|
|
9
|
+
# session that starts after the warning still gets it.
|
|
10
|
+
# --hook PostToolUse — announce only what was declared or lifted
|
|
11
|
+
# since this session started, once each. This is the only
|
|
12
|
+
# thing that reaches a session already running.
|
|
13
|
+
#
|
|
14
|
+
# Advisory by construction — ALWAYS exit 0. A session that cannot read the
|
|
15
|
+
# ledger must keep working; a broken hook that wedges every tool call would be
|
|
16
|
+
# a far worse defect than the one this closes. Every infrastructure gap (no
|
|
17
|
+
# node, unreadable stdin) is also exit 0, and `bun run check:operational-hazards`
|
|
18
|
+
# is what guarantees the ledger itself still parses.
|
|
19
|
+
set -uo pipefail
|
|
20
|
+
|
|
21
|
+
input="$(cat 2>/dev/null || true)"
|
|
22
|
+
|
|
23
|
+
command -v node >/dev/null 2>&1 || exit 0
|
|
24
|
+
|
|
25
|
+
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
26
|
+
|
|
27
|
+
printf '%s' "$input" | node "$script_dir/operational-hazards.mjs" "$@" || true
|
|
28
|
+
exit 0
|
|
@@ -118,6 +118,27 @@ trap 'printf "%s\n" "Blocked by safety-net: hook failed while parsing its input;
|
|
|
118
118
|
|
|
119
119
|
input="$(cat)"
|
|
120
120
|
|
|
121
|
+
# Evaluate once per tool call when this guard is registered on both channels.
|
|
122
|
+
#
|
|
123
|
+
# Lisa reaches an agent through the repository dispatcher AND the plugin
|
|
124
|
+
# manifest, and where both are live the harness runs this guard twice for one
|
|
125
|
+
# tool call. `guard-dedupe.bash` short-circuits the second run ONLY when a
|
|
126
|
+
# byte-identical copy already ALLOWED this exact payload on this exact tool
|
|
127
|
+
# call; a differing vintage, a refusal, and a host with one channel all
|
|
128
|
+
# evaluate exactly as before. Nothing is de-registered by it
|
|
129
|
+
# (CodySwannGT/lisa#3814).
|
|
130
|
+
#
|
|
131
|
+
# Absent library means no dedupe, which is the pre-existing behaviour, so an
|
|
132
|
+
# older channel copy that predates it is unaffected.
|
|
133
|
+
lisa_guard_hook_dir="${BASH_SOURCE[0]%/*}"
|
|
134
|
+
lisa_guard_dedupe_lib="$lisa_guard_hook_dir/guard-dedupe.bash"
|
|
135
|
+
if [ -r "$lisa_guard_dedupe_lib" ]; then
|
|
136
|
+
# shellcheck source=guard-dedupe.bash
|
|
137
|
+
. "$lisa_guard_dedupe_lib"
|
|
138
|
+
trap 'lisa_guard_dedupe_record $?' EXIT
|
|
139
|
+
lisa_guard_dedupe parity-safety-net "$input"
|
|
140
|
+
fi
|
|
141
|
+
|
|
121
142
|
tool_name="$(printf '%s' "$input" | jq -r '.tool_name // empty')"
|
|
122
143
|
if [ "$tool_name" != "Bash" ]; then
|
|
123
144
|
exit 0
|
|
@@ -244,12 +265,19 @@ later with `git apply "$patch"`.
|
|
|
244
265
|
|
|
245
266
|
If the work is NOT yours -- a concurrent agent dirtied this worktree and your
|
|
246
267
|
judgement is "none of this is mine" -- that same capture is how you return the
|
|
247
|
-
tree to HEAD:
|
|
268
|
+
tree to HEAD. This block is self-contained; paste it as it stands:
|
|
248
269
|
|
|
270
|
+
patch="$(mktemp "${TMPDIR:-/tmp}/lisa-preserve-XXXXXX")"
|
|
249
271
|
git reset
|
|
250
272
|
git diff --binary HEAD > "$patch"
|
|
251
273
|
git apply -R "$patch"
|
|
252
274
|
|
|
275
|
+
It names the file itself rather than inheriting one from the block above,
|
|
276
|
+
because the two blocks are alternatives and only one of them gets run. A remedy
|
|
277
|
+
printed at the moment an agent is blocked is followed literally; one that
|
|
278
|
+
depends on a variable the reader never set fails on its first line, and the
|
|
279
|
+
guard that printed it stops being believed.
|
|
280
|
+
|
|
253
281
|
`git reset` clears staged and unmerged entries first, so the capture sees the
|
|
254
282
|
whole tree as one diff; reversing it leaves the tree at HEAD with "$patch" as
|
|
255
283
|
the record of what you discarded. Untracked files survive, exactly as they
|
|
@@ -7,6 +7,9 @@
|
|
|
7
7
|
* for the CLI.
|
|
8
8
|
*/
|
|
9
9
|
import {
|
|
10
|
+
ALLOW_STATE,
|
|
11
|
+
classifyAllowEntry,
|
|
12
|
+
describeAllowScope,
|
|
10
13
|
extractAllowEntries,
|
|
11
14
|
extractK6Constraints,
|
|
12
15
|
extractLighthouseAssertions,
|
|
@@ -221,7 +224,7 @@ function compareAllowList(relPath, base, current) {
|
|
|
221
224
|
file: relPath,
|
|
222
225
|
key: `thresholdRatchet.allow ${entry.file}#${entry.key}`,
|
|
223
226
|
type: "allow-added",
|
|
224
|
-
message: `${relPath}: new threshold exception
|
|
227
|
+
message: `${relPath}: new threshold exception — ${describeAllowScope(entry)}. Exceptions are a human decision: land this entry in its own human-approved change first, then make the threshold change. It needs a reason saying what resolves it and an "until": "YYYY-MM-DD" naming the day it is reviewed, because an exemption that cannot end is a permanent reduction in what the ratchet covers.`,
|
|
225
228
|
});
|
|
226
229
|
}
|
|
227
230
|
}
|
|
@@ -311,29 +314,106 @@ export function compareFile(relPath, baselineText, currentText) {
|
|
|
311
314
|
}
|
|
312
315
|
|
|
313
316
|
/**
|
|
314
|
-
*
|
|
315
|
-
*
|
|
317
|
+
* Whether an allow entry's file and key cover a finding.
|
|
318
|
+
* @param {{ file: string, key: string }} entry An allow entry
|
|
319
|
+
* @param {Finding} finding A finding from the change
|
|
320
|
+
* @returns {boolean} True when the entry's scope reaches this finding
|
|
321
|
+
*/
|
|
322
|
+
function entryCovers(entry, finding) {
|
|
323
|
+
return (
|
|
324
|
+
(finding.file === entry.file || finding.file.endsWith(`/${entry.file}`)) &&
|
|
325
|
+
(entry.key === "*" || entry.key === finding.key)
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Report the allow entries a human has to act on, whether or not this change
|
|
331
|
+
* touched anything they cover.
|
|
332
|
+
*
|
|
333
|
+
* Separate from {@link applyAllowList} because the two answer different
|
|
334
|
+
* questions and only one of them depends on the change under review. An
|
|
335
|
+
* exemption that has outlived its condition is dead weight the moment the
|
|
336
|
+
* condition passes — the way `_thresholdsDivergence` is stale the moment the
|
|
337
|
+
* two floors agree — and saying so is not conditional on anybody happening to
|
|
338
|
+
* touch the gate it covered.
|
|
339
|
+
* @param {Array<{ file: string, key: string, reason?: string, until?: unknown }>} allowEntries
|
|
340
|
+
* The allow list being honoured
|
|
341
|
+
* @param {number} [now] Clock reading, injected so the check is deterministic
|
|
342
|
+
* @returns {string[]} One line per entry that is expired or unevaluable; empty
|
|
343
|
+
* when every entry still names a condition that holds
|
|
344
|
+
*/
|
|
345
|
+
export function describeAllowList(allowEntries, now = Date.now()) {
|
|
346
|
+
const lines = [];
|
|
347
|
+
for (const entry of allowEntries) {
|
|
348
|
+
const { state, detail } = classifyAllowEntry(entry, now);
|
|
349
|
+
if (state !== ALLOW_STATE.LIVE) lines.push(detail);
|
|
350
|
+
}
|
|
351
|
+
return lines;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Drop findings covered by a LIVE baseline-side allow entry.
|
|
356
|
+
*
|
|
357
|
+
* Three ways a finding leaves here, and they are deliberately distinct:
|
|
358
|
+
*
|
|
359
|
+
* allowed a covering entry's condition still holds. Reported, not blocked —
|
|
360
|
+
* a project mid-migration is not red-walled by expiry.
|
|
361
|
+
* expired every covering entry's condition has passed. The weakening the
|
|
362
|
+
* entry used to permit is REFUSED again, and the refusal names the
|
|
363
|
+
* entry, its scope, its reason and the remedy. An expiry that
|
|
364
|
+
* lapsed into "allowed" would be worse than no expiry.
|
|
365
|
+
* blocked nothing covered it, or everything that covered it has expired.
|
|
366
|
+
*
|
|
367
|
+
* An entry whose condition nothing can evaluate counts as covering, so the
|
|
368
|
+
* allow list keeps working for entries written before `until` existed;
|
|
369
|
+
* `describeAllowList` reports those every run instead.
|
|
370
|
+
*
|
|
371
|
+
* `allow-added` findings are never dropped, by any entry in any state — an
|
|
372
|
+
* exception cannot approve its own creation, which is the baseline-side fence
|
|
373
|
+
* and is untouched here.
|
|
316
374
|
* @param {Finding[]} findings All findings from the change
|
|
317
|
-
* @param {Array<{ file: string, key: string }>} allowEntries
|
|
318
|
-
* (already-merged) allow list
|
|
319
|
-
* @
|
|
320
|
-
*
|
|
375
|
+
* @param {Array<{ file: string, key: string, reason?: string, until?: unknown }>} allowEntries
|
|
376
|
+
* Baseline (already-merged) allow list
|
|
377
|
+
* @param {number} [now] Clock reading, injected so the check is deterministic
|
|
378
|
+
* @returns {{
|
|
379
|
+
* blocked: Finding[],
|
|
380
|
+
* allowed: Array<{ finding: Finding, entry: { file: string, key: string }, message: string }>,
|
|
381
|
+
* expired: Array<{ finding: Finding, entry: { file: string, key: string }, message: string }>,
|
|
382
|
+
* }} Findings that still block, findings a live exemption covers, and the
|
|
383
|
+
* refusals produced by exemptions that have ended
|
|
321
384
|
*/
|
|
322
|
-
export function applyAllowList(findings, allowEntries) {
|
|
385
|
+
export function applyAllowList(findings, allowEntries, now = Date.now()) {
|
|
386
|
+
const classified = allowEntries.map(entry => ({
|
|
387
|
+
entry,
|
|
388
|
+
...classifyAllowEntry(entry, now),
|
|
389
|
+
}));
|
|
323
390
|
const blocked = [];
|
|
324
391
|
const allowed = [];
|
|
392
|
+
const expired = [];
|
|
325
393
|
for (const finding of findings) {
|
|
326
|
-
const
|
|
327
|
-
finding.type
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
394
|
+
const covering =
|
|
395
|
+
finding.type === "allow-added"
|
|
396
|
+
? []
|
|
397
|
+
: classified.filter(c => entryCovers(c.entry, finding));
|
|
398
|
+
const live = covering.find(c => c.state !== ALLOW_STATE.EXPIRED);
|
|
399
|
+
if (live) {
|
|
400
|
+
allowed.push({
|
|
401
|
+
finding,
|
|
402
|
+
entry: live.entry,
|
|
403
|
+
message: `allowed by ${live.scope}, which ${live.summary}. It covers: ${finding.message}`,
|
|
404
|
+
});
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
blocked.push(finding);
|
|
408
|
+
for (const dead of covering) {
|
|
409
|
+
expired.push({
|
|
410
|
+
finding,
|
|
411
|
+
entry: dead.entry,
|
|
412
|
+
message: `${dead.detail} It used to cover: ${finding.message}`,
|
|
413
|
+
});
|
|
414
|
+
}
|
|
335
415
|
}
|
|
336
|
-
return { blocked, allowed };
|
|
416
|
+
return { blocked, allowed, expired };
|
|
337
417
|
}
|
|
338
418
|
|
|
339
419
|
/**
|
|
@@ -351,8 +431,9 @@ export function formatReport(findings) {
|
|
|
351
431
|
"Quality thresholds are a one-way ratchet: they may tighten but never",
|
|
352
432
|
"loosen. Fix the code so it meets the current gate instead of lowering the",
|
|
353
433
|
"gate. If a human decides an exception is genuinely correct, they record it",
|
|
354
|
-
"in .lisa.config.json under thresholdRatchet.allow
|
|
355
|
-
"
|
|
356
|
-
"
|
|
434
|
+
"in .lisa.config.json under thresholdRatchet.allow — with a reason saying",
|
|
435
|
+
'what resolves it, and an "until": "YYYY-MM-DD" naming the day it is',
|
|
436
|
+
"reviewed — in a separate human-approved change; this check honors an",
|
|
437
|
+
"exception only after it is merged, and only until its until date passes.",
|
|
357
438
|
].join("\n");
|
|
358
439
|
}
|
|
@@ -379,8 +379,8 @@ export function extractK6Constraints(conf) {
|
|
|
379
379
|
/**
|
|
380
380
|
* Extract thresholdRatchet.allow entries from parsed .lisa.config.json.
|
|
381
381
|
* @param {unknown} config Parsed config (may be undefined)
|
|
382
|
-
* @returns {Array<{ file: string, key: string, reason?: string }>}
|
|
383
|
-
* well-formed allow entries; malformed entries are dropped
|
|
382
|
+
* @returns {Array<{ file: string, key: string, reason?: string, until?: unknown }>}
|
|
383
|
+
* The well-formed allow entries; malformed entries are dropped
|
|
384
384
|
*/
|
|
385
385
|
export function extractAllowEntries(config) {
|
|
386
386
|
const raw = config?.thresholdRatchet?.allow;
|
|
@@ -389,3 +389,131 @@ export function extractAllowEntries(config) {
|
|
|
389
389
|
e => e && typeof e.file === "string" && typeof e.key === "string"
|
|
390
390
|
);
|
|
391
391
|
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* The three states an allow entry's expiry condition can be in.
|
|
395
|
+
*
|
|
396
|
+
* THE DEFECT THESE EXIST FOR (#3856). An allow entry is the human-approved way
|
|
397
|
+
* for a weakening to pass the ratchet, and it had no expiry, no review and no
|
|
398
|
+
* removal path — nothing read the `reason`, so an exemption granted for a
|
|
399
|
+
* temporary condition (a migration in flight, a suite being rewritten, a
|
|
400
|
+
* dependency waiting upstream) outlived the condition and kept applying,
|
|
401
|
+
* silently, forever. The set of gates actually enforced therefore shrank
|
|
402
|
+
* monotonically while every individual decision that shrank it was correct at
|
|
403
|
+
* the time. A control whose exception list only grows converges on no control.
|
|
404
|
+
*
|
|
405
|
+
* The shape is taken from `_thresholdsDivergence` in `stryker.conf.json`,
|
|
406
|
+
* governed by `src/sync/stryker-thresholds-ownership.ts` — the one exemption
|
|
407
|
+
* surface in this repository that already stops exempting when it goes stale.
|
|
408
|
+
* Its three properties are reproduced here: the entry records its condition in
|
|
409
|
+
* a form something can evaluate, the reason says what resolves it, and once the
|
|
410
|
+
* condition passes the entry stops exempting AND says so, naming the remedy.
|
|
411
|
+
*
|
|
412
|
+
* `unchecked` is deliberately NOT `expired`. An entry written before `until`
|
|
413
|
+
* existed names a condition nothing can evaluate, which is the prose situation
|
|
414
|
+
* the ticket describes — it is reported every run, loudly, and it keeps
|
|
415
|
+
* exempting. Refusing it instead would red-wall every project mid-migration
|
|
416
|
+
* that carries a valid exception, which is the failure the ticket names as
|
|
417
|
+
* worse than the defect.
|
|
418
|
+
* @type {Readonly<Record<string, "live"|"expired"|"unchecked">>}
|
|
419
|
+
*/
|
|
420
|
+
export const ALLOW_STATE = Object.freeze({
|
|
421
|
+
LIVE: "live",
|
|
422
|
+
EXPIRED: "expired",
|
|
423
|
+
UNCHECKED: "unchecked",
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
/** A calendar condition, and the only shape `until` may take. */
|
|
427
|
+
const ISO_DAY = /^(\d{4})-(\d{2})-(\d{2})$/u;
|
|
428
|
+
|
|
429
|
+
/** An entry is live through the END of its named day, not up to its start. */
|
|
430
|
+
const DAY_MS = 86_400_000;
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* The instant an `until` condition stops holding.
|
|
434
|
+
*
|
|
435
|
+
* Round-tripped through `toISOString` on purpose: `Date.UTC` accepts
|
|
436
|
+
* out-of-range components and slides them, so `2026-02-31` would silently
|
|
437
|
+
* become March 3rd and `0099-01-01` would become 1999. An exemption dated a day
|
|
438
|
+
* that does not exist is a condition nobody can evaluate, and saying so is the
|
|
439
|
+
* honest answer — quietly moving it would hand the entry a different, longer
|
|
440
|
+
* life than the one written down.
|
|
441
|
+
* @param {unknown} until The entry's `until` field
|
|
442
|
+
* @returns {number | undefined} Epoch ms after which the entry has expired, or
|
|
443
|
+
* undefined when `until` is not a calendar day anything can evaluate
|
|
444
|
+
*/
|
|
445
|
+
export function allowEntryExpiry(until) {
|
|
446
|
+
if (typeof until !== "string") return undefined;
|
|
447
|
+
const day = until.trim();
|
|
448
|
+
const match = ISO_DAY.exec(day);
|
|
449
|
+
if (!match) return undefined;
|
|
450
|
+
const midnight = Date.UTC(
|
|
451
|
+
Number(match[1]),
|
|
452
|
+
Number(match[2]) - 1,
|
|
453
|
+
Number(match[3])
|
|
454
|
+
);
|
|
455
|
+
if (new Date(midnight).toISOString().slice(0, 10) !== day) return undefined;
|
|
456
|
+
return midnight + DAY_MS;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Name an allow entry so a report says WHICH exemption it is talking about,
|
|
461
|
+
* and how much it covers.
|
|
462
|
+
*
|
|
463
|
+
* File-wide and key-scoped entries are spelled differently because they are
|
|
464
|
+
* different risks wearing the same shape: `key: "*"` turns off ratchet
|
|
465
|
+
* protection for every threshold in the file, and in a config diff that reads
|
|
466
|
+
* as one more approved exception.
|
|
467
|
+
* @param {{ file: string, key: string }} entry An allow entry, already
|
|
468
|
+
* well-formed — `extractAllowEntries` is the only source of these
|
|
469
|
+
* @returns {string} Operator-readable identification of the entry
|
|
470
|
+
*/
|
|
471
|
+
export function describeAllowScope(entry) {
|
|
472
|
+
return entry.key === "*"
|
|
473
|
+
? `thresholdRatchet.allow entry ${entry.file} → * (file-wide: every key in the file)`
|
|
474
|
+
: `thresholdRatchet.allow entry ${entry.file} → ${entry.key} (key-scoped)`;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Classify one allow entry's expiry condition, and say what to do about it.
|
|
479
|
+
* @param {{ file: string, key: string, reason?: unknown, until?: unknown }} entry
|
|
480
|
+
* An allow entry
|
|
481
|
+
* @param {number} now Clock reading, injected so the check is deterministic
|
|
482
|
+
* @returns {{ state: "live"|"expired"|"unchecked", scope: string, summary: string, detail: string }}
|
|
483
|
+
* The state, the entry's identification, a short phrase for a one-line
|
|
484
|
+
* mention, and the full sentence naming the entry, its reason and the remedy
|
|
485
|
+
*/
|
|
486
|
+
export function classifyAllowEntry(entry, now) {
|
|
487
|
+
const scope = describeAllowScope(entry);
|
|
488
|
+
const because =
|
|
489
|
+
typeof entry.reason === "string" && entry.reason.trim() !== ""
|
|
490
|
+
? ` Reason on record: ${entry.reason.trim()}`
|
|
491
|
+
: " No reason is recorded.";
|
|
492
|
+
const expiresAt = allowEntryExpiry(entry.until);
|
|
493
|
+
if (expiresAt === undefined) {
|
|
494
|
+
const summary = `names no condition anything can evaluate (until = ${JSON.stringify(entry.until ?? null)})`;
|
|
495
|
+
return {
|
|
496
|
+
state: ALLOW_STATE.UNCHECKED,
|
|
497
|
+
scope,
|
|
498
|
+
summary,
|
|
499
|
+
detail: `${scope} ${summary}, so nothing can ever end it. Give it "until": "YYYY-MM-DD" naming the day the exemption is reviewed, or delete it.${because}`,
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
const day = String(entry.until).trim();
|
|
503
|
+
if (now >= expiresAt) {
|
|
504
|
+
const summary = `expired after ${day}`;
|
|
505
|
+
return {
|
|
506
|
+
state: ALLOW_STATE.EXPIRED,
|
|
507
|
+
scope,
|
|
508
|
+
summary,
|
|
509
|
+
detail: `${scope} ${summary} and no longer exempts anything. Delete it, or record a fresh human-approved entry naming the new condition.${because}`,
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
const summary = `is live until ${day}`;
|
|
513
|
+
return {
|
|
514
|
+
state: ALLOW_STATE.LIVE,
|
|
515
|
+
scope,
|
|
516
|
+
summary,
|
|
517
|
+
detail: `${scope} ${summary}.`,
|
|
518
|
+
};
|
|
519
|
+
}
|
|
@@ -19,10 +19,20 @@
|
|
|
19
19
|
* every entry carries a written decision.
|
|
20
20
|
*
|
|
21
21
|
* Human override: `.lisa.config.json` → `thresholdRatchet.allow` entries
|
|
22
|
-
* ({ file, key, reason }). Honored ONLY from the baseline side (HEAD /
|
|
22
|
+
* ({ file, key, reason, until }). Honored ONLY from the baseline side (HEAD /
|
|
23
23
|
* merge-base), never from the change under review — an agent cannot grant
|
|
24
24
|
* itself an exception in the same change that weakens a gate. `key: "*"`
|
|
25
|
-
* allows every key in the file
|
|
25
|
+
* allows every key in the file, and reports as file-wide so it is not mistaken
|
|
26
|
+
* for a key-scoped one.
|
|
27
|
+
*
|
|
28
|
+
* Exemptions END (#3856). `until` is a `YYYY-MM-DD` day the entry is live
|
|
29
|
+
* through; past it the entry stops exempting and the weakening it permitted is
|
|
30
|
+
* refused again, naming the entry, its scope, its reason and the remedy. An
|
|
31
|
+
* entry naming no evaluable condition still exempts — that keeps a project
|
|
32
|
+
* mid-migration off a red wall — but is reported on every run until somebody
|
|
33
|
+
* gives it a condition or deletes it. Modelled on `_thresholdsDivergence` in
|
|
34
|
+
* `stryker.conf.json`, the sibling exemption that already stops exempting when
|
|
35
|
+
* it goes stale; see `threshold-ratchet-families.mjs` `ALLOW_STATE`.
|
|
26
36
|
*
|
|
27
37
|
* One exception, and only one: a PROMOTION between deploy-chain branches
|
|
28
38
|
* (`--base` + `--head`, both named in `deploy.branches`, head upstream of
|
|
@@ -46,6 +56,7 @@ import {
|
|
|
46
56
|
import {
|
|
47
57
|
applyAllowList,
|
|
48
58
|
compareFile,
|
|
59
|
+
describeAllowList,
|
|
49
60
|
formatReport,
|
|
50
61
|
} from "./threshold-ratchet-compare.mjs";
|
|
51
62
|
|
|
@@ -387,6 +398,13 @@ function run(mode, baseRef, onlyFiles, headRef) {
|
|
|
387
398
|
);
|
|
388
399
|
}
|
|
389
400
|
|
|
401
|
+
const allow = resolveAllowList(
|
|
402
|
+
root,
|
|
403
|
+
plan.baselineRef,
|
|
404
|
+
mode,
|
|
405
|
+
baseRef,
|
|
406
|
+
headRef
|
|
407
|
+
);
|
|
390
408
|
const findings = watched.flatMap(f =>
|
|
391
409
|
compareFile(
|
|
392
410
|
f,
|
|
@@ -394,28 +412,60 @@ function run(mode, baseRef, onlyFiles, headRef) {
|
|
|
394
412
|
plan.readCurrent(f)
|
|
395
413
|
)
|
|
396
414
|
);
|
|
397
|
-
|
|
415
|
+
// The allow-list inventory is printed whether or not the change produced
|
|
416
|
+
// findings. An exemption that has outlived its condition is dead weight the
|
|
417
|
+
// moment the condition passes, and reporting it only when something else has
|
|
418
|
+
// already failed is how a list nobody reads stays a list nobody reads.
|
|
419
|
+
if (findings.length === 0) {
|
|
420
|
+
reportAllowList(allow.entries, []);
|
|
421
|
+
return 0;
|
|
422
|
+
}
|
|
423
|
+
return reportFindings(findings, allow, mode);
|
|
424
|
+
}
|
|
398
425
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
426
|
+
/**
|
|
427
|
+
* Print the allow entries a human has to act on, minus the ones a refusal is
|
|
428
|
+
* about to name in full.
|
|
429
|
+
* @param {object[]} entries The resolved allow list
|
|
430
|
+
* @param {Array<{ message: string }>} expired Refusals already being printed
|
|
431
|
+
* @returns {void}
|
|
432
|
+
*/
|
|
433
|
+
function reportAllowList(entries, expired) {
|
|
434
|
+
for (const line of describeAllowList(entries)) {
|
|
435
|
+
if (expired.some(item => item.message.startsWith(line))) continue;
|
|
436
|
+
process.stdout.write(`threshold-ratchet: ${line}\n`);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Print the verdict for a change that produced findings.
|
|
442
|
+
* @param {object[]} findings Findings from every watched file
|
|
443
|
+
* @param {{ entries: object[], promotion: boolean, note: string | null }} allow
|
|
444
|
+
* The resolved allow list and its provenance
|
|
445
|
+
* @param {"hook"|"staged"|"base"} mode Comparison mode
|
|
446
|
+
* @returns {number} Process exit code (2 for hook mode, 1 otherwise; 0 clean)
|
|
447
|
+
*/
|
|
448
|
+
function reportFindings(findings, allow, mode) {
|
|
406
449
|
const split = partitionCarriedEntries(findings, allow.promotion);
|
|
407
|
-
const { blocked, allowed } = applyAllowList(
|
|
450
|
+
const { blocked, allowed, expired } = applyAllowList(
|
|
451
|
+
split.rest,
|
|
452
|
+
allow.entries
|
|
453
|
+
);
|
|
408
454
|
if (allow.note) process.stdout.write(`${allow.note}\n`);
|
|
455
|
+
reportAllowList(allow.entries, expired);
|
|
409
456
|
for (const finding of split.carried) {
|
|
410
457
|
process.stdout.write(
|
|
411
458
|
`threshold-ratchet: carried forward by this promotion, approved upstream — ${finding.message}\n`
|
|
412
459
|
);
|
|
413
460
|
}
|
|
414
|
-
for (const
|
|
461
|
+
for (const item of allowed) {
|
|
415
462
|
process.stdout.write(
|
|
416
|
-
`threshold-ratchet:
|
|
463
|
+
`threshold-ratchet: ${item.message} (.lisa.config.json exception)\n`
|
|
417
464
|
);
|
|
418
465
|
}
|
|
466
|
+
for (const item of expired) {
|
|
467
|
+
process.stderr.write(`threshold-ratchet: refused — ${item.message}\n`);
|
|
468
|
+
}
|
|
419
469
|
if (blocked.length === 0) return 0;
|
|
420
470
|
process.stderr.write(`${formatReport(blocked)}\n`);
|
|
421
471
|
return mode === "hook" ? 2 : 1;
|