@codyswann/lisa 4.49.0 → 4.50.1
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-overwrite/scripts/check-conflict-markers.mjs +4 -1
- package/all/copy-overwrite/scripts/lib/gate-failure-diagnosis.mjs +163 -0
- package/all/copy-overwrite/scripts/lisa-enforcement-fallback.sh +178 -1
- package/all/copy-overwrite/scripts/lisa-hooks/block-direct-issue-create.sh +89 -10
- package/all/copy-overwrite/scripts/lisa-hooks/parity-safety-net.sh +44 -0
- package/all/copy-overwrite/scripts/lisa-lint-staged-preflight.mjs +1 -1
- package/all/copy-overwrite/scripts/lisa-run-gates.mjs +24 -24
- package/all/copy-overwrite/scripts/lisa-work-item.mjs +490 -81
- package/cdk/package-lisa/package.lisa.json +45 -15
- package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.js +76 -0
- package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
- package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +121 -227
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/dist/opencode/plugin-templates/lisa-block-direct-issue-create.ts +45 -1
- package/dist/opencode/plugin-templates/parity-safety-net.sh +44 -0
- package/expo/package-lisa/package.lisa.json +110 -53
- package/harper-fabric/package-lisa/package.lisa.json +62 -32
- package/nestjs/package-lisa/package.lisa.json +57 -27
- package/npm-package/package-lisa/package.lisa.json +43 -7
- package/package.json +11 -7
- package/phaser/copy-overwrite/ast-grep/rules/no-day-truncating-file-age-predicate.yml +50 -0
- package/phaser/package-lisa/package.lisa.json +62 -32
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-drive-pr-to-merge/SKILL.md +17 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-github-build-intake/SKILL.md +4 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-jira-build-intake/SKILL.md +4 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-build-intake/SKILL.md +4 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-repair-intake/SKILL.md +4 -1
- package/plugins/lisa/hooks/block-direct-issue-create.sh +89 -10
- package/plugins/lisa/hooks/discharge-work-item-gates.sh +7 -1
- package/plugins/lisa/hooks/parity-safety-net.sh +44 -0
- package/plugins/lisa/hooks/threshold-ratchet-families.mjs +12 -0
- package/plugins/lisa/rules/eager/00-rule-index.md +79 -0
- package/plugins/lisa/rules/eager/base-rules.md +10 -0
- package/plugins/lisa/rules/eager/config-resolution.md +1 -88
- package/plugins/lisa/rules/reference/automation-runbook-contract.md +97 -0
- package/plugins/lisa/rules/reference/bdd-e2e-coverage.md +56 -0
- package/plugins/lisa/rules/reference/blocker-containment.md +58 -0
- package/plugins/lisa/rules/reference/claim-archaeology.md +42 -0
- package/plugins/lisa/rules/reference/claim-evidence-mapping.md +83 -0
- package/plugins/lisa/rules/reference/claim-time-guards.md +37 -0
- package/plugins/lisa/rules/reference/config-resolution.md +97 -0
- package/plugins/lisa/rules/reference/control-reachability.md +44 -0
- package/plugins/lisa/rules/reference/convergent-review.md +31 -0
- package/plugins/lisa/rules/reference/credential-substrate-precedence.md +57 -0
- package/plugins/lisa/rules/reference/dependency-decision-records.md +37 -0
- package/plugins/lisa/rules/reference/dependency-internalization-kit.md +47 -0
- package/plugins/lisa/rules/reference/dependency-trust-classes.md +48 -0
- package/plugins/lisa/rules/reference/deployed-state-readback.md +52 -0
- package/plugins/lisa/rules/reference/derived-branch-plan.md +52 -0
- package/plugins/lisa/rules/reference/design-source-of-truth.md +43 -0
- package/plugins/lisa/rules/reference/design-value-binding.md +103 -0
- package/plugins/lisa/rules/reference/documentation-source-paths.md +18 -0
- package/plugins/lisa/rules/reference/leaf-only-lifecycle.md +75 -0
- package/plugins/lisa/rules/reference/observability-audit.md +20 -0
- package/plugins/lisa/rules/reference/prd-definition-of-ready.md +37 -0
- package/plugins/lisa/rules/reference/prd-lifecycle-rollup.md +36 -0
- package/plugins/lisa/rules/reference/pre-flight-autofill.md +88 -0
- package/plugins/lisa/rules/reference/promotion-contract.md +21 -0
- package/plugins/lisa/rules/reference/readiness-rubric.md +63 -0
- package/plugins/lisa/rules/reference/ready-role-filing.md +34 -0
- package/plugins/lisa/rules/reference/rejection-detection.md +69 -0
- package/plugins/lisa/rules/reference/repo-scope-split.md +48 -0
- package/plugins/lisa/rules/reference/reset-seed-coverage.md +55 -0
- package/plugins/lisa/rules/reference/usage-accounting.md +38 -0
- package/plugins/lisa/rules/reference/work-item-definition-of-ready.md +32 -0
- package/plugins/lisa/scripts/intake-blocker-reprobe.mjs +158 -1
- package/plugins/lisa/skills/lisa-drive-pr-to-merge/SKILL.md +17 -1
- package/plugins/lisa/skills/lisa-github-build-intake/SKILL.md +4 -0
- package/plugins/lisa/skills/lisa-jira-build-intake/SKILL.md +4 -0
- package/plugins/lisa/skills/lisa-linear-build-intake/SKILL.md +4 -0
- package/plugins/lisa/skills/lisa-repair-intake/SKILL.md +4 -1
- package/plugins/lisa-agy/hooks/block-direct-issue-create.sh +89 -10
- package/plugins/lisa-agy/hooks/parity-safety-net.sh +44 -0
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/scripts/intake-blocker-reprobe.mjs +158 -1
- package/plugins/lisa-agy/skills/lisa-drive-pr-to-merge/SKILL.md +17 -1
- package/plugins/lisa-agy/skills/lisa-github-build-intake/SKILL.md +4 -0
- package/plugins/lisa-agy/skills/lisa-jira-build-intake/SKILL.md +4 -0
- package/plugins/lisa-agy/skills/lisa-linear-build-intake/SKILL.md +4 -0
- package/plugins/lisa-agy/skills/lisa-repair-intake/SKILL.md +4 -1
- 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 +1 -1
- package/plugins/lisa-copilot/hooks/block-direct-issue-create.sh +89 -10
- package/plugins/lisa-copilot/hooks/discharge-work-item-gates.sh +7 -1
- package/plugins/lisa-copilot/hooks/parity-safety-net.sh +44 -0
- package/plugins/lisa-copilot/hooks/threshold-ratchet-families.mjs +12 -0
- package/plugins/lisa-copilot/rules/eager/00-rule-index.md +79 -0
- package/plugins/lisa-copilot/rules/eager/base-rules.md +10 -0
- package/plugins/lisa-copilot/rules/eager/config-resolution.md +1 -88
- package/plugins/lisa-copilot/rules/reference/automation-runbook-contract.md +97 -0
- package/plugins/lisa-copilot/rules/reference/bdd-e2e-coverage.md +56 -0
- package/plugins/lisa-copilot/rules/reference/blocker-containment.md +58 -0
- package/plugins/lisa-copilot/rules/reference/claim-archaeology.md +42 -0
- package/plugins/lisa-copilot/rules/reference/claim-evidence-mapping.md +83 -0
- package/plugins/lisa-copilot/rules/reference/claim-time-guards.md +37 -0
- package/plugins/lisa-copilot/rules/reference/config-resolution.md +97 -0
- package/plugins/lisa-copilot/rules/reference/control-reachability.md +44 -0
- package/plugins/lisa-copilot/rules/reference/convergent-review.md +31 -0
- package/plugins/lisa-copilot/rules/reference/credential-substrate-precedence.md +57 -0
- package/plugins/lisa-copilot/rules/reference/dependency-decision-records.md +37 -0
- package/plugins/lisa-copilot/rules/reference/dependency-internalization-kit.md +47 -0
- package/plugins/lisa-copilot/rules/reference/dependency-trust-classes.md +48 -0
- package/plugins/lisa-copilot/rules/reference/deployed-state-readback.md +52 -0
- package/plugins/lisa-copilot/rules/reference/derived-branch-plan.md +52 -0
- package/plugins/lisa-copilot/rules/reference/design-source-of-truth.md +43 -0
- package/plugins/lisa-copilot/rules/reference/design-value-binding.md +103 -0
- package/plugins/lisa-copilot/rules/reference/documentation-source-paths.md +18 -0
- package/plugins/lisa-copilot/rules/reference/leaf-only-lifecycle.md +75 -0
- package/plugins/lisa-copilot/rules/reference/observability-audit.md +20 -0
- package/plugins/lisa-copilot/rules/reference/prd-definition-of-ready.md +37 -0
- package/plugins/lisa-copilot/rules/reference/prd-lifecycle-rollup.md +36 -0
- package/plugins/lisa-copilot/rules/reference/pre-flight-autofill.md +88 -0
- package/plugins/lisa-copilot/rules/reference/promotion-contract.md +21 -0
- package/plugins/lisa-copilot/rules/reference/readiness-rubric.md +63 -0
- package/plugins/lisa-copilot/rules/reference/ready-role-filing.md +34 -0
- package/plugins/lisa-copilot/rules/reference/rejection-detection.md +69 -0
- package/plugins/lisa-copilot/rules/reference/repo-scope-split.md +48 -0
- package/plugins/lisa-copilot/rules/reference/reset-seed-coverage.md +55 -0
- package/plugins/lisa-copilot/rules/reference/usage-accounting.md +38 -0
- package/plugins/lisa-copilot/rules/reference/work-item-definition-of-ready.md +32 -0
- package/plugins/lisa-copilot/scripts/intake-blocker-reprobe.mjs +158 -1
- package/plugins/lisa-copilot/skills/lisa-drive-pr-to-merge/SKILL.md +17 -1
- package/plugins/lisa-copilot/skills/lisa-github-build-intake/SKILL.md +4 -0
- package/plugins/lisa-copilot/skills/lisa-jira-build-intake/SKILL.md +4 -0
- package/plugins/lisa-copilot/skills/lisa-linear-build-intake/SKILL.md +4 -0
- package/plugins/lisa-copilot/skills/lisa-repair-intake/SKILL.md +4 -1
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/hooks/block-direct-issue-create.sh +89 -10
- package/plugins/lisa-cursor/hooks/discharge-work-item-gates.sh +7 -1
- package/plugins/lisa-cursor/hooks/parity-safety-net.sh +44 -0
- package/plugins/lisa-cursor/hooks/threshold-ratchet-families.mjs +12 -0
- package/plugins/lisa-cursor/rules/00-rule-index.mdc +84 -0
- package/plugins/lisa-cursor/rules/automation-runbook-contract-reference.mdc +97 -0
- package/plugins/lisa-cursor/rules/base-rules.mdc +10 -0
- package/plugins/lisa-cursor/rules/bdd-e2e-coverage-reference.mdc +56 -0
- package/plugins/lisa-cursor/rules/blocker-containment-reference.mdc +58 -0
- package/plugins/lisa-cursor/rules/claim-archaeology-reference.mdc +42 -0
- package/plugins/lisa-cursor/rules/claim-evidence-mapping-reference.mdc +83 -0
- package/plugins/lisa-cursor/rules/claim-time-guards-reference.mdc +37 -0
- package/plugins/lisa-cursor/rules/config-resolution-reference.mdc +97 -0
- package/plugins/lisa-cursor/rules/config-resolution.mdc +1 -88
- package/plugins/lisa-cursor/rules/control-reachability-reference.mdc +44 -0
- package/plugins/lisa-cursor/rules/convergent-review-reference.mdc +31 -0
- package/plugins/lisa-cursor/rules/credential-substrate-precedence-reference.mdc +57 -0
- package/plugins/lisa-cursor/rules/dependency-decision-records-reference.mdc +37 -0
- package/plugins/lisa-cursor/rules/dependency-internalization-kit-reference.mdc +47 -0
- package/plugins/lisa-cursor/rules/dependency-trust-classes-reference.mdc +48 -0
- package/plugins/lisa-cursor/rules/deployed-state-readback-reference.mdc +52 -0
- package/plugins/lisa-cursor/rules/derived-branch-plan-reference.mdc +52 -0
- package/plugins/lisa-cursor/rules/design-source-of-truth-reference.mdc +43 -0
- package/plugins/lisa-cursor/rules/design-value-binding-reference.mdc +103 -0
- package/plugins/lisa-cursor/rules/documentation-source-paths-reference.mdc +18 -0
- package/plugins/lisa-cursor/rules/leaf-only-lifecycle-reference.mdc +75 -0
- package/plugins/lisa-cursor/rules/observability-audit-reference.mdc +20 -0
- package/plugins/lisa-cursor/rules/prd-definition-of-ready-reference.mdc +37 -0
- package/plugins/lisa-cursor/rules/prd-lifecycle-rollup-reference.mdc +36 -0
- package/plugins/lisa-cursor/rules/pre-flight-autofill-reference.mdc +88 -0
- package/plugins/lisa-cursor/rules/promotion-contract-reference.mdc +21 -0
- package/plugins/lisa-cursor/rules/readiness-rubric-reference.mdc +63 -0
- package/plugins/lisa-cursor/rules/ready-role-filing-reference.mdc +34 -0
- package/plugins/lisa-cursor/rules/rejection-detection-reference.mdc +69 -0
- package/plugins/lisa-cursor/rules/repo-scope-split-reference.mdc +48 -0
- package/plugins/lisa-cursor/rules/reset-seed-coverage-reference.mdc +55 -0
- package/plugins/lisa-cursor/rules/usage-accounting-reference.mdc +38 -0
- package/plugins/lisa-cursor/rules/work-item-definition-of-ready-reference.mdc +32 -0
- package/plugins/lisa-cursor/scripts/intake-blocker-reprobe.mjs +158 -1
- package/plugins/lisa-cursor/skills/lisa-drive-pr-to-merge/SKILL.md +17 -1
- package/plugins/lisa-cursor/skills/lisa-github-build-intake/SKILL.md +4 -0
- package/plugins/lisa-cursor/skills/lisa-jira-build-intake/SKILL.md +4 -0
- package/plugins/lisa-cursor/skills/lisa-linear-build-intake/SKILL.md +4 -0
- package/plugins/lisa-cursor/skills/lisa-repair-intake/SKILL.md +4 -1
- 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-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- 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-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- 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/src/base/hooks/block-direct-issue-create.sh +89 -10
- package/plugins/src/base/hooks/discharge-work-item-gates.sh +7 -1
- package/plugins/src/base/hooks/parity-safety-net.sh +44 -0
- package/plugins/src/base/hooks/threshold-ratchet-families.mjs +12 -0
- package/plugins/src/base/rules/eager/00-rule-index.md +79 -0
- package/plugins/src/base/rules/eager/base-rules.md +10 -0
- package/plugins/src/base/rules/eager/config-resolution.md +1 -88
- package/plugins/src/base/rules/reference/automation-runbook-contract.md +97 -0
- package/plugins/src/base/rules/reference/bdd-e2e-coverage.md +56 -0
- package/plugins/src/base/rules/reference/blocker-containment.md +58 -0
- package/plugins/src/base/rules/reference/claim-archaeology.md +42 -0
- package/plugins/src/base/rules/reference/claim-evidence-mapping.md +83 -0
- package/plugins/src/base/rules/reference/claim-time-guards.md +37 -0
- package/plugins/src/base/rules/reference/config-resolution.md +97 -0
- package/plugins/src/base/rules/reference/control-reachability.md +44 -0
- package/plugins/src/base/rules/reference/convergent-review.md +31 -0
- package/plugins/src/base/rules/reference/credential-substrate-precedence.md +57 -0
- package/plugins/src/base/rules/reference/dependency-decision-records.md +37 -0
- package/plugins/src/base/rules/reference/dependency-internalization-kit.md +47 -0
- package/plugins/src/base/rules/reference/dependency-trust-classes.md +48 -0
- package/plugins/src/base/rules/reference/deployed-state-readback.md +52 -0
- package/plugins/src/base/rules/reference/derived-branch-plan.md +52 -0
- package/plugins/src/base/rules/reference/design-source-of-truth.md +43 -0
- package/plugins/src/base/rules/reference/design-value-binding.md +103 -0
- package/plugins/src/base/rules/reference/documentation-source-paths.md +18 -0
- package/plugins/src/base/rules/reference/leaf-only-lifecycle.md +75 -0
- package/plugins/src/base/rules/reference/observability-audit.md +20 -0
- package/plugins/src/base/rules/reference/prd-definition-of-ready.md +37 -0
- package/plugins/src/base/rules/reference/prd-lifecycle-rollup.md +36 -0
- package/plugins/src/base/rules/reference/pre-flight-autofill.md +88 -0
- package/plugins/src/base/rules/reference/promotion-contract.md +21 -0
- package/plugins/src/base/rules/reference/readiness-rubric.md +63 -0
- package/plugins/src/base/rules/reference/ready-role-filing.md +34 -0
- package/plugins/src/base/rules/reference/rejection-detection.md +69 -0
- package/plugins/src/base/rules/reference/repo-scope-split.md +48 -0
- package/plugins/src/base/rules/reference/reset-seed-coverage.md +55 -0
- package/plugins/src/base/rules/reference/usage-accounting.md +38 -0
- package/plugins/src/base/rules/reference/work-item-definition-of-ready.md +32 -0
- package/plugins/src/base/scripts/intake-blocker-reprobe.mjs +158 -1
- package/plugins/src/base/skills/lisa-drive-pr-to-merge/SKILL.md +17 -1
- package/plugins/src/base/skills/lisa-github-build-intake/SKILL.md +4 -0
- package/plugins/src/base/skills/lisa-jira-build-intake/SKILL.md +4 -0
- package/plugins/src/base/skills/lisa-linear-build-intake/SKILL.md +4 -0
- package/plugins/src/base/skills/lisa-repair-intake/SKILL.md +4 -1
- package/rails/copy-overwrite/ast-grep/rules/no-day-truncating-file-age-predicate.yml +50 -0
- package/rails/copy-overwrite/scripts/threshold-ratchet-families.mjs +12 -0
- package/scripts/check-eager-rule-budget.mjs +176 -0
- package/scripts/check-generated-artifact-merge-coverage.mjs +7 -0
- package/scripts/check-rules-pairing.sh +45 -14
- package/scripts/check-shipped-surface-removals.mjs +851 -0
- package/scripts/generate-export-surface.mjs +318 -0
- package/scripts/lib/shipped-surface.mjs +212 -0
- package/scripts/lisa-enforcement-fallback.sh +178 -1
- package/scripts/remedy-conformance.mjs +435 -0
- package/scripts/two-channel-couplings.json +2 -2
- package/typescript/copy-contents/.husky/pre-push +147 -2
- package/typescript/copy-overwrite/ast-grep/rules/no-day-truncating-file-age-predicate.yml +50 -0
- package/typescript/copy-overwrite/audit.ignore.config.json +0 -10
- package/typescript/copy-overwrite/scripts/lisa-mutation.mjs +180 -29
- package/typescript/copy-overwrite/scripts/threshold-ratchet-families.mjs +12 -0
- package/typescript/package-lisa/package.lisa.json +72 -42
- package/plugins/lisa/rules/eager/automation-runbook-contract.md +0 -92
- package/plugins/lisa/rules/eager/bdd-e2e-coverage.md +0 -51
- package/plugins/lisa/rules/eager/blocker-containment.md +0 -53
- package/plugins/lisa/rules/eager/claim-archaeology.md +0 -37
- package/plugins/lisa/rules/eager/claim-evidence-mapping.md +0 -78
- package/plugins/lisa/rules/eager/claim-time-guards.md +0 -32
- package/plugins/lisa/rules/eager/control-reachability.md +0 -39
- package/plugins/lisa/rules/eager/convergent-review.md +0 -24
- package/plugins/lisa/rules/eager/credential-substrate-precedence.md +0 -54
- package/plugins/lisa/rules/eager/dependency-decision-records.md +0 -32
- package/plugins/lisa/rules/eager/dependency-internalization-kit.md +0 -42
- package/plugins/lisa/rules/eager/dependency-trust-classes.md +0 -43
- package/plugins/lisa/rules/eager/deployed-state-readback.md +0 -47
- package/plugins/lisa/rules/eager/derived-branch-plan.md +0 -47
- package/plugins/lisa/rules/eager/design-source-of-truth.md +0 -38
- package/plugins/lisa/rules/eager/design-value-binding.md +0 -98
- package/plugins/lisa/rules/eager/documentation-source-paths.md +0 -13
- package/plugins/lisa/rules/eager/factory-model.md +0 -41
- package/plugins/lisa/rules/eager/leaf-only-lifecycle.md +0 -70
- package/plugins/lisa/rules/eager/observability-audit.md +0 -15
- package/plugins/lisa/rules/eager/prd-definition-of-ready.md +0 -32
- package/plugins/lisa/rules/eager/prd-lifecycle-rollup.md +0 -31
- package/plugins/lisa/rules/eager/pre-flight-autofill.md +0 -84
- package/plugins/lisa/rules/eager/project-learnings.md +0 -22
- package/plugins/lisa/rules/eager/promotion-contract.md +0 -18
- package/plugins/lisa/rules/eager/readiness-rubric.md +0 -58
- package/plugins/lisa/rules/eager/ready-role-filing.md +0 -29
- package/plugins/lisa/rules/eager/rejection-detection.md +0 -64
- package/plugins/lisa/rules/eager/repo-scope-split.md +0 -43
- package/plugins/lisa/rules/eager/reset-seed-coverage.md +0 -50
- package/plugins/lisa/rules/eager/usage-accounting.md +0 -33
- package/plugins/lisa/rules/eager/work-item-definition-of-ready.md +0 -27
- package/plugins/lisa-copilot/rules/eager/automation-runbook-contract.md +0 -92
- package/plugins/lisa-copilot/rules/eager/bdd-e2e-coverage.md +0 -51
- package/plugins/lisa-copilot/rules/eager/blocker-containment.md +0 -53
- package/plugins/lisa-copilot/rules/eager/claim-archaeology.md +0 -37
- package/plugins/lisa-copilot/rules/eager/claim-evidence-mapping.md +0 -78
- package/plugins/lisa-copilot/rules/eager/claim-time-guards.md +0 -32
- package/plugins/lisa-copilot/rules/eager/control-reachability.md +0 -39
- package/plugins/lisa-copilot/rules/eager/convergent-review.md +0 -24
- package/plugins/lisa-copilot/rules/eager/credential-substrate-precedence.md +0 -54
- package/plugins/lisa-copilot/rules/eager/dependency-decision-records.md +0 -32
- package/plugins/lisa-copilot/rules/eager/dependency-internalization-kit.md +0 -42
- package/plugins/lisa-copilot/rules/eager/dependency-trust-classes.md +0 -43
- package/plugins/lisa-copilot/rules/eager/deployed-state-readback.md +0 -47
- package/plugins/lisa-copilot/rules/eager/derived-branch-plan.md +0 -47
- package/plugins/lisa-copilot/rules/eager/design-source-of-truth.md +0 -38
- package/plugins/lisa-copilot/rules/eager/design-value-binding.md +0 -98
- package/plugins/lisa-copilot/rules/eager/documentation-source-paths.md +0 -13
- package/plugins/lisa-copilot/rules/eager/factory-model.md +0 -41
- package/plugins/lisa-copilot/rules/eager/leaf-only-lifecycle.md +0 -70
- package/plugins/lisa-copilot/rules/eager/observability-audit.md +0 -15
- package/plugins/lisa-copilot/rules/eager/prd-definition-of-ready.md +0 -32
- package/plugins/lisa-copilot/rules/eager/prd-lifecycle-rollup.md +0 -31
- package/plugins/lisa-copilot/rules/eager/pre-flight-autofill.md +0 -84
- package/plugins/lisa-copilot/rules/eager/project-learnings.md +0 -22
- package/plugins/lisa-copilot/rules/eager/promotion-contract.md +0 -18
- package/plugins/lisa-copilot/rules/eager/readiness-rubric.md +0 -58
- package/plugins/lisa-copilot/rules/eager/ready-role-filing.md +0 -29
- package/plugins/lisa-copilot/rules/eager/rejection-detection.md +0 -64
- package/plugins/lisa-copilot/rules/eager/repo-scope-split.md +0 -43
- package/plugins/lisa-copilot/rules/eager/reset-seed-coverage.md +0 -50
- package/plugins/lisa-copilot/rules/eager/usage-accounting.md +0 -33
- package/plugins/lisa-copilot/rules/eager/work-item-definition-of-ready.md +0 -27
- package/plugins/lisa-cursor/rules/automation-runbook-contract.mdc +0 -97
- package/plugins/lisa-cursor/rules/bdd-e2e-coverage.mdc +0 -56
- package/plugins/lisa-cursor/rules/blocker-containment.mdc +0 -58
- package/plugins/lisa-cursor/rules/claim-archaeology.mdc +0 -42
- package/plugins/lisa-cursor/rules/claim-evidence-mapping.mdc +0 -83
- package/plugins/lisa-cursor/rules/claim-time-guards.mdc +0 -37
- package/plugins/lisa-cursor/rules/control-reachability.mdc +0 -44
- package/plugins/lisa-cursor/rules/convergent-review.mdc +0 -29
- package/plugins/lisa-cursor/rules/credential-substrate-precedence.mdc +0 -59
- package/plugins/lisa-cursor/rules/dependency-decision-records.mdc +0 -37
- package/plugins/lisa-cursor/rules/dependency-internalization-kit.mdc +0 -47
- package/plugins/lisa-cursor/rules/dependency-trust-classes.mdc +0 -48
- package/plugins/lisa-cursor/rules/deployed-state-readback.mdc +0 -52
- package/plugins/lisa-cursor/rules/derived-branch-plan.mdc +0 -52
- package/plugins/lisa-cursor/rules/design-source-of-truth.mdc +0 -43
- package/plugins/lisa-cursor/rules/design-value-binding.mdc +0 -103
- package/plugins/lisa-cursor/rules/documentation-source-paths.mdc +0 -18
- package/plugins/lisa-cursor/rules/factory-model.mdc +0 -46
- package/plugins/lisa-cursor/rules/leaf-only-lifecycle.mdc +0 -75
- package/plugins/lisa-cursor/rules/observability-audit.mdc +0 -20
- package/plugins/lisa-cursor/rules/prd-definition-of-ready.mdc +0 -37
- package/plugins/lisa-cursor/rules/prd-lifecycle-rollup.mdc +0 -36
- package/plugins/lisa-cursor/rules/pre-flight-autofill.mdc +0 -89
- package/plugins/lisa-cursor/rules/project-learnings.mdc +0 -27
- package/plugins/lisa-cursor/rules/promotion-contract.mdc +0 -23
- package/plugins/lisa-cursor/rules/readiness-rubric.mdc +0 -63
- package/plugins/lisa-cursor/rules/ready-role-filing.mdc +0 -34
- package/plugins/lisa-cursor/rules/rejection-detection.mdc +0 -69
- package/plugins/lisa-cursor/rules/repo-scope-split.mdc +0 -48
- package/plugins/lisa-cursor/rules/reset-seed-coverage.mdc +0 -55
- package/plugins/lisa-cursor/rules/usage-accounting.mdc +0 -38
- package/plugins/lisa-cursor/rules/work-item-definition-of-ready.mdc +0 -32
- package/plugins/src/base/rules/eager/automation-runbook-contract.md +0 -92
- package/plugins/src/base/rules/eager/bdd-e2e-coverage.md +0 -51
- package/plugins/src/base/rules/eager/blocker-containment.md +0 -53
- package/plugins/src/base/rules/eager/claim-archaeology.md +0 -37
- package/plugins/src/base/rules/eager/claim-evidence-mapping.md +0 -78
- package/plugins/src/base/rules/eager/claim-time-guards.md +0 -32
- package/plugins/src/base/rules/eager/control-reachability.md +0 -39
- package/plugins/src/base/rules/eager/convergent-review.md +0 -24
- package/plugins/src/base/rules/eager/credential-substrate-precedence.md +0 -54
- package/plugins/src/base/rules/eager/dependency-decision-records.md +0 -32
- package/plugins/src/base/rules/eager/dependency-internalization-kit.md +0 -42
- package/plugins/src/base/rules/eager/dependency-trust-classes.md +0 -43
- package/plugins/src/base/rules/eager/deployed-state-readback.md +0 -47
- package/plugins/src/base/rules/eager/derived-branch-plan.md +0 -47
- package/plugins/src/base/rules/eager/design-source-of-truth.md +0 -38
- package/plugins/src/base/rules/eager/design-value-binding.md +0 -98
- package/plugins/src/base/rules/eager/documentation-source-paths.md +0 -13
- package/plugins/src/base/rules/eager/factory-model.md +0 -41
- package/plugins/src/base/rules/eager/leaf-only-lifecycle.md +0 -70
- package/plugins/src/base/rules/eager/observability-audit.md +0 -15
- package/plugins/src/base/rules/eager/prd-definition-of-ready.md +0 -32
- package/plugins/src/base/rules/eager/prd-lifecycle-rollup.md +0 -31
- package/plugins/src/base/rules/eager/pre-flight-autofill.md +0 -84
- package/plugins/src/base/rules/eager/project-learnings.md +0 -22
- package/plugins/src/base/rules/eager/promotion-contract.md +0 -18
- package/plugins/src/base/rules/eager/readiness-rubric.md +0 -58
- package/plugins/src/base/rules/eager/ready-role-filing.md +0 -29
- package/plugins/src/base/rules/eager/rejection-detection.md +0 -64
- package/plugins/src/base/rules/eager/repo-scope-split.md +0 -43
- package/plugins/src/base/rules/eager/reset-seed-coverage.md +0 -50
- package/plugins/src/base/rules/eager/usage-accounting.md +0 -33
- package/plugins/src/base/rules/eager/work-item-definition-of-ready.md +0 -27
|
@@ -76,6 +76,51 @@ unset LISA_PUSHED_REFS LISA_PUSHED_REF_COUNT LISA_PUSHED_COMMIT_COUNT
|
|
|
76
76
|
unset LISA_PUSHED_LOCAL_REF LISA_PUSHED_LOCAL_SHA LISA_PUSHED_TAIL
|
|
77
77
|
# END: deletion-only push guard
|
|
78
78
|
|
|
79
|
+
# BEGIN: pushed refs file
|
|
80
|
+
# ---------------------------------------------------------------------------
|
|
81
|
+
# The pushed refs, kept somewhere every later reader can still find them.
|
|
82
|
+
#
|
|
83
|
+
# READING THE STREAM SPENDS IT. Git delivers `<local ref> <local sha> <remote
|
|
84
|
+
# ref> <remote sha>` on stdin exactly once, and this hook has four readers: the
|
|
85
|
+
# deletion guard above, the destination guard below, `validate-push`, and every
|
|
86
|
+
# declared gate. Each one that reads it replays it — but a replay only reaches
|
|
87
|
+
# the NEXT reader in this file. A gate the runner spawns is a different process
|
|
88
|
+
# started at a different time, and by then whichever gate ran before it may
|
|
89
|
+
# already have drained the stream for good.
|
|
90
|
+
#
|
|
91
|
+
# That is not hypothetical, it is CodySwannGT/lisa#3874: on a project that
|
|
92
|
+
# declares `gates.traceability`, the built-in call below stands down and the
|
|
93
|
+
# work-item check runs from inside the gate runner instead. It found empty
|
|
94
|
+
# stdin, fell back to `git rev-list HEAD --not --remotes=<remote>` — the
|
|
95
|
+
# PUSHER'S branch, not the pushed one — and printed
|
|
96
|
+
# `WORK_ITEM_TRACKING_OK 0 commit(s)` for a branch whose commit carried a
|
|
97
|
+
# perfectly good `Work-Item:` trailer. A green meaning "I had nothing to look
|
|
98
|
+
# at", in the same shape as a green meaning "I looked and it was clean".
|
|
99
|
+
#
|
|
100
|
+
# A named file has none of that ordering. It is written once, read as many
|
|
101
|
+
# times as anything likes, and removed on exit. Stdin is still replayed byte
|
|
102
|
+
# for byte, so nothing that reads the stream today has to change.
|
|
103
|
+
#
|
|
104
|
+
# If no scratch file can be created this stands down without reading a byte and
|
|
105
|
+
# the hook behaves exactly as it did before — the same fail-towards-running
|
|
106
|
+
# direction the deletion guard takes.
|
|
107
|
+
# ---------------------------------------------------------------------------
|
|
108
|
+
LISA_PUSHED_REFS_FILE="$(mktemp "${TMPDIR:-/tmp}/lisa-pushed-refs-file.XXXXXXXX")" || LISA_PUSHED_REFS_FILE=""
|
|
109
|
+
if [ -n "$LISA_PUSHED_REFS_FILE" ]; then
|
|
110
|
+
cat > "$LISA_PUSHED_REFS_FILE"
|
|
111
|
+
# Put the stream back for the guards and gates that still read stdin.
|
|
112
|
+
exec < "$LISA_PUSHED_REFS_FILE"
|
|
113
|
+
# Exported, because the reader that needs it most is a grandchild process:
|
|
114
|
+
# the gate runner's `check:work-item:push`. `--refs` names the same file for
|
|
115
|
+
# anyone invoking the validator directly.
|
|
116
|
+
export LISA_PUSHED_REFS_FILE
|
|
117
|
+
# Both traps remove both files, so whichever is installed last still cleans
|
|
118
|
+
# up everything. A single-file trap here would be silently replaced by the
|
|
119
|
+
# gate-coverage trap further down and leak this file on every push.
|
|
120
|
+
trap 'rm -f "$LISA_PUSHED_REFS_FILE" "$LISA_GATE_COVERAGE"' EXIT
|
|
121
|
+
fi
|
|
122
|
+
# END: pushed refs file
|
|
123
|
+
|
|
79
124
|
WORK_ITEM_SCRIPT="node_modules/@codyswann/lisa/all/copy-overwrite/scripts/lisa-work-item.mjs"
|
|
80
125
|
if [ ! -f "$WORK_ITEM_SCRIPT" ]; then
|
|
81
126
|
WORK_ITEM_SCRIPT="scripts/lisa-work-item.mjs"
|
|
@@ -322,11 +367,109 @@ process.stdin.on("data", chunk => { raw += chunk }).on("end", () => {
|
|
|
322
367
|
')
|
|
323
368
|
fi
|
|
324
369
|
|
|
370
|
+
LISA_TRACEABILITY_RAN=""
|
|
325
371
|
if [ "$TRACEABILITY_DECLARED" = "declared" ]; then
|
|
326
372
|
echo "ℹ️ gates.traceability is declared at push; the gate registry decides what runs."
|
|
327
373
|
else
|
|
328
374
|
node "$WORK_ITEM_SCRIPT" validate-push "${1:-origin}" || exit 1
|
|
375
|
+
LISA_TRACEABILITY_RAN=1
|
|
376
|
+
fi
|
|
377
|
+
|
|
378
|
+
# BEGIN: pushed-tree scope guard
|
|
379
|
+
# ---------------------------------------------------------------------------
|
|
380
|
+
# Everything below this line reads the FILES IN THIS WORKING TREE — lint,
|
|
381
|
+
# types, tests, dead code. That is correct when the branch being pushed is the
|
|
382
|
+
# branch checked out here, which is the ordinary case and is left untouched.
|
|
383
|
+
#
|
|
384
|
+
# It is wrong the moment it is not. A session pinned to one worktree can only
|
|
385
|
+
# push another worktree's branch cross-tree, and when it does, `eslint .` and
|
|
386
|
+
# `knip` walk the PUSHER'S tree while the push carries a commit from somewhere
|
|
387
|
+
# else — and then print PASSED. A green meaning "I examined a different tree"
|
|
388
|
+
# arrives in the same shape as a green meaning "I examined this and it was
|
|
389
|
+
# clean" (CodySwannGT/lisa#3874). Because the worktree binding makes the
|
|
390
|
+
# cross-tree route the only permitted one for a pinned agent, this is not an
|
|
391
|
+
# edge case; it is the normal path for a growing share of the fleet.
|
|
392
|
+
#
|
|
393
|
+
# REFUSING IS THE HONEST ANSWER AND PASSING IS NOT. An operator told "these
|
|
394
|
+
# gates cannot see the tree you are pushing, push it from that tree" has been
|
|
395
|
+
# given a true statement they can act on; one told PASSED has been given a
|
|
396
|
+
# false one. This adds no bypass and takes nothing away: no gate is skipped,
|
|
397
|
+
# relaxed, or made optional, and the push does not proceed.
|
|
398
|
+
#
|
|
399
|
+
# TRACEABILITY RUNS FIRST, and unconditionally, because it is the one push gate
|
|
400
|
+
# that CAN answer correctly from here: it reads git objects, which every
|
|
401
|
+
# worktree of a repository shares, so the pushed range is fully visible from
|
|
402
|
+
# any tree. Refusing before it ran would throw away the one true answer
|
|
403
|
+
# available at this moment — and its verdict is the one an operator most needs,
|
|
404
|
+
# because a missing work item is fixed by rewriting the commit, not by moving
|
|
405
|
+
# to another terminal.
|
|
406
|
+
#
|
|
407
|
+
# ANCESTOR, NOT EQUALITY. A pushed commit reachable from local `HEAD` is in
|
|
408
|
+
# this tree's history — the ordinary "push something older" case — so only a
|
|
409
|
+
# commit this checkout has never contained is out of scope.
|
|
410
|
+
#
|
|
411
|
+
# WHAT IT DELIBERATELY DOES NOT EXAMINE: deletions (the guard above exits
|
|
412
|
+
# first, and a deleted ref has no tree), and any local ref that is neither
|
|
413
|
+
# `refs/heads/*` nor `HEAD` — a tag push moves a label rather than proposing a
|
|
414
|
+
# tree, and release automation pushes tags for commits that shipped long ago.
|
|
415
|
+
# If the refs file could not be written, or `HEAD` is unborn, this stands down
|
|
416
|
+
# rather than guessing.
|
|
417
|
+
# ---------------------------------------------------------------------------
|
|
418
|
+
LISA_OUT_OF_TREE=""
|
|
419
|
+
if [ -n "$LISA_PUSHED_REFS_FILE" ] && git rev-parse -q --verify HEAD >/dev/null 2>&1; then
|
|
420
|
+
# The `||` keeps a final line with no trailing newline, exactly as the
|
|
421
|
+
# deletion guard reads the same stream.
|
|
422
|
+
while read -r LISA_SCOPE_REF LISA_SCOPE_SHA LISA_SCOPE_TAIL || [ -n "$LISA_SCOPE_REF" ]; do
|
|
423
|
+
case "$LISA_SCOPE_REF" in
|
|
424
|
+
refs/heads/* | HEAD) ;;
|
|
425
|
+
*) continue ;;
|
|
426
|
+
esac
|
|
427
|
+
# A zeroed or non-hex local sha is a deletion or an unreadable line, and
|
|
428
|
+
# neither is a tree this can ask a question about.
|
|
429
|
+
case "$LISA_SCOPE_SHA" in
|
|
430
|
+
"" | *[!0-9a-f]*) continue ;;
|
|
431
|
+
esac
|
|
432
|
+
case "$LISA_SCOPE_SHA" in
|
|
433
|
+
*[!0]*) ;;
|
|
434
|
+
*) continue ;;
|
|
435
|
+
esac
|
|
436
|
+
if ! git merge-base --is-ancestor "$LISA_SCOPE_SHA" HEAD >/dev/null 2>&1; then
|
|
437
|
+
LISA_OUT_OF_TREE="$LISA_OUT_OF_TREE
|
|
438
|
+
$LISA_SCOPE_REF -> $LISA_SCOPE_SHA"
|
|
439
|
+
fi
|
|
440
|
+
done < "$LISA_PUSHED_REFS_FILE"
|
|
441
|
+
fi
|
|
442
|
+
unset LISA_SCOPE_REF LISA_SCOPE_SHA LISA_SCOPE_TAIL
|
|
443
|
+
|
|
444
|
+
if [ -n "$LISA_OUT_OF_TREE" ]; then
|
|
445
|
+
# The one gate that can answer correctly from here, run before the refusal so
|
|
446
|
+
# its verdict is not lost to it. Skipped only when it has already run above.
|
|
447
|
+
if [ -z "$LISA_TRACEABILITY_RAN" ] && [ -f "$WORK_ITEM_SCRIPT" ]; then
|
|
448
|
+
node "$WORK_ITEM_SCRIPT" validate-push "${1:-origin}" || exit 1
|
|
449
|
+
fi
|
|
450
|
+
echo ""
|
|
451
|
+
echo "❌ Push refused: the push checks cannot see the commits being pushed."
|
|
452
|
+
echo ""
|
|
453
|
+
echo " Being pushed, but not in this working tree:$LISA_OUT_OF_TREE"
|
|
454
|
+
echo ""
|
|
455
|
+
echo " This checkout is on $(git rev-parse --abbrev-ref HEAD 2>/dev/null)."
|
|
456
|
+
echo " The checks after this point read the files in THIS folder — lint,"
|
|
457
|
+
echo " types, tests, dead code. Run here they would report on this"
|
|
458
|
+
echo " checkout, not on what is leaving the machine, and report it as a"
|
|
459
|
+
echo " pass. That pass would be false, and a false pass is worse than no"
|
|
460
|
+
echo " answer, so this stops instead of printing one."
|
|
461
|
+
echo ""
|
|
462
|
+
echo " What to do: push each branch from the folder it is checked out in."
|
|
463
|
+
echo " These are the folders this repository is checked out into:"
|
|
464
|
+
git worktree list 2>/dev/null | sed 's/^/ /'
|
|
465
|
+
echo ""
|
|
466
|
+
echo " Work-item traceability above DID examine the pushed commits — it"
|
|
467
|
+
echo " reads git history, which every folder shares — so that answer stands."
|
|
468
|
+
echo ""
|
|
469
|
+
exit 1
|
|
329
470
|
fi
|
|
471
|
+
unset LISA_OUT_OF_TREE
|
|
472
|
+
# END: pushed-tree scope guard
|
|
330
473
|
|
|
331
474
|
# Git supplies repository-local GIT_* variables to hooks. Keep them for push
|
|
332
475
|
# validation above, then remove exactly Git's documented local set so nested
|
|
@@ -386,7 +529,9 @@ fi
|
|
|
386
529
|
LISA_GATE_COVERAGE=""
|
|
387
530
|
if [ -f "$GATE_RUNNER" ] && command -v node >/dev/null 2>&1; then
|
|
388
531
|
LISA_GATE_COVERAGE="$(mktemp "${TMPDIR:-/tmp}/lisa-gate-coverage.XXXXXXXX")" || LISA_GATE_COVERAGE=""
|
|
389
|
-
|
|
532
|
+
# Removes the pushed-refs file too: this trap REPLACES the one installed by
|
|
533
|
+
# the pushed refs file block above, so a single-file body here would leak it.
|
|
534
|
+
trap 'rm -f "$LISA_GATE_COVERAGE" "$LISA_PUSHED_REFS_FILE"' EXIT
|
|
390
535
|
if [ -n "$LISA_GATE_COVERAGE" ]; then
|
|
391
536
|
node "$GATE_RUNNER" --moment=push --coverage="$LISA_GATE_COVERAGE"
|
|
392
537
|
else
|
|
@@ -846,7 +991,7 @@ fi
|
|
|
846
991
|
# measured, and the honest command for such a project is still `test:cov` —
|
|
847
992
|
# slower, but answering to the floor that was configured for what it runs.
|
|
848
993
|
COVERAGE_SCRIPT="test:cov"
|
|
849
|
-
if node -e 'const s=require("./package.json").scripts||{};const
|
|
994
|
+
if node -e 'const s=require("./package.json").scripts||{};const resolve=(k,d)=>{const v=s[k];const hop=/^\$npm_execpath\s+run\s+(\S+)$/.exec((v||"").trim());return hop&&d<4?resolve(hop[1],d+1):v;};const u=resolve("test:cov:unit",0);const marker=/^(?:env(?:\s+-\S+)*\s+)?(?:[A-Za-z_][A-Za-z0-9_]*=\S+\s+)*LISA_COVERAGE_SCOPE=unit(?:\s|$)/;process.exit(typeof u==="string"&&marker.test(u.trim())?0:1)' >/dev/null 2>&1; then
|
|
850
995
|
COVERAGE_SCRIPT="test:cov:unit"
|
|
851
996
|
fi
|
|
852
997
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# This file is managed by Lisa and IS replaced on each `lisa` run.
|
|
2
|
+
# Do not edit directly — durable changes belong upstream in Lisa.
|
|
3
|
+
|
|
4
|
+
id: no-day-truncating-file-age-predicate
|
|
5
|
+
language: bash
|
|
6
|
+
severity: error
|
|
7
|
+
message: |
|
|
8
|
+
`-mtime`, `-atime` and `-ctime` do NOT mean "older than N days".
|
|
9
|
+
|
|
10
|
+
`find` divides the file's age by 86400 and DISCARDS the remainder, so
|
|
11
|
+
`-mtime +N` matches only files older than N+1 days. Measured on this
|
|
12
|
+
repository's own platform with fixtures stamped at known ages:
|
|
13
|
+
|
|
14
|
+
age -mtime +2 -mmin +2880
|
|
15
|
+
47h no no
|
|
16
|
+
49h NO yes <- the whole disagreement
|
|
17
|
+
71h NO yes
|
|
18
|
+
73h yes yes
|
|
19
|
+
|
|
20
|
+
The 49h-71h band is silently dropped. The failure direction is what makes
|
|
21
|
+
this worth a rule: the under-selection reports "nothing to do", and nobody
|
|
22
|
+
questions an empty result from a cleanup predicate, so it prevents needed
|
|
23
|
+
work instead of causing visible harm. Reported once as a broken `find`; it
|
|
24
|
+
is not. `find` is answering a different question than the flag appears to
|
|
25
|
+
ask, which is exactly why it survives review.
|
|
26
|
+
|
|
27
|
+
Write the question you mean:
|
|
28
|
+
|
|
29
|
+
older than N days -> -mmin +$((N * 1440))
|
|
30
|
+
older than N days -> ! -newermt "<an ISO timestamp N days back>"
|
|
31
|
+
older than N hours -> -mmin +$((N * 60))
|
|
32
|
+
|
|
33
|
+
`-mmin` is minute-granularity and is not truncated to days, so it means
|
|
34
|
+
what it reads. `-newermt` is exact but needs a timestamp, and the two
|
|
35
|
+
`date` implementations disagree on how to produce one: `date -v-2d` is
|
|
36
|
+
BSD/macOS and `date -d '2 days ago'` is GNU/Linux. Prefer `-mmin` in any
|
|
37
|
+
script that runs on both.
|
|
38
|
+
note: |
|
|
39
|
+
This rule matches the flag itself rather than a `find` invocation, so it
|
|
40
|
+
still fires through `/usr/bin/find`, `$FIND`, and `xargs find`. There are
|
|
41
|
+
no legitimate uses in this repository: every shipped age predicate already
|
|
42
|
+
uses `-mmin`, and this rule exists to keep it that way, because `-mtime` is
|
|
43
|
+
the form a maintainer reaches for by reflex and the shell hooks that carry
|
|
44
|
+
these predicates are copied across five per-agent plugin variants, so one
|
|
45
|
+
wrong edit lands in eight files at once.
|
|
46
|
+
|
|
47
|
+
See CodySwannGT/lisa#3905.
|
|
48
|
+
rule:
|
|
49
|
+
kind: word
|
|
50
|
+
regex: ^-(mtime|atime|ctime)$
|
|
@@ -137,16 +137,6 @@
|
|
|
137
137
|
"id": "GHSA-j759-j44w-7fr8",
|
|
138
138
|
"package": "@xmldom/xmldom",
|
|
139
139
|
"reason": "XML node injection via unvalidated comment serialization. Transitive via expo > @expo/config-plugins > @expo/plist; only serializes developer-authored plist files at build/prebuild time, no runtime code path serializes attacker-controlled XML."
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
"id": "GHSA-v39h-62p7-jpjc",
|
|
143
|
-
"package": "fast-uri",
|
|
144
|
-
"reason": "Host confusion via percent-encoded authority delimiters in fast-uri parser. Reachable transitively via eslint > @eslint/eslintrc > ajv > fast-uri and (in CDK projects) via aws-cdk-lib's bundled JSON Schema validator. aws-cdk-lib is invoked only at build/synth/deploy time \u2014 its ajv usage validates CloudFormation/CDK schemas authored by the developer, not attacker-controlled URIs. No runtime/production code path passes attacker-controlled URIs through ajv schema validation that relies on fast-uri parsing."
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
"id": "GHSA-q3j6-qgpj-74h6",
|
|
148
|
-
"package": "fast-uri",
|
|
149
|
-
"reason": "Path traversal via percent-encoded dot segments in fast-uri parser. Reachable transitively via eslint > @eslint/eslintrc > ajv > fast-uri and (in CDK projects) via aws-cdk-lib's bundled JSON Schema validator. aws-cdk-lib is invoked only at build/synth/deploy time \u2014 its ajv usage validates CloudFormation/CDK schemas authored by the developer, not attacker-controlled URIs. No runtime/production code path passes attacker-controlled URIs through ajv schema validation that relies on fast-uri parsing."
|
|
150
140
|
}
|
|
151
141
|
]
|
|
152
142
|
}
|
|
@@ -196,8 +196,96 @@ export const OUTCOMES = Object.freeze({
|
|
|
196
196
|
inflatedByTimeouts: "mutation-gate: score-below-break-without-timeouts",
|
|
197
197
|
clearedBreakThreshold: "mutation-gate: cleared-break-threshold",
|
|
198
198
|
noFloorApplied: "mutation-gate: no-floor-applied",
|
|
199
|
+
notMeasured: "mutation-gate: not-measured",
|
|
199
200
|
});
|
|
200
201
|
|
|
202
|
+
/**
|
|
203
|
+
* The one-line denial a green-but-unmeasured job puts on the check list.
|
|
204
|
+
*
|
|
205
|
+
* Exported so the exact wording is assertable, and built here rather than in
|
|
206
|
+
* the workflow because the workflow cannot see WHICH exit happened.
|
|
207
|
+
*
|
|
208
|
+
* It deliberately avoids the words "mutation score", even in a negation.
|
|
209
|
+
* `tests/integration/mutation-gate-diff-bite.test.ts` asserts that a
|
|
210
|
+
* nothing-to-mutate run's output does not match /mutation score/i, and that
|
|
211
|
+
* control is right: a run that scored nothing must not put the phrase in front
|
|
212
|
+
* of a reader at all, because a skim keeps the noun and drops the "no". The
|
|
213
|
+
* first draft of this line read "no mutation score was produced" and failed it.
|
|
214
|
+
* @param {string} outcome - The {@link OUTCOMES} marker this run ended on.
|
|
215
|
+
* @returns {string} A GitHub Actions warning command, one line.
|
|
216
|
+
*/
|
|
217
|
+
export const unmeasuredAnnotation = outcome =>
|
|
218
|
+
`::warning title=Mutation gate measured nothing::${outcome} — no mutant was ` +
|
|
219
|
+
"executed, so this job's green says the run ended cleanly, NOT that mutation " +
|
|
220
|
+
"coverage was verified. Read it as NOT MEASURED, never as nothing to " +
|
|
221
|
+
'measure. Change a file this project\'s Stryker "mutate" list selects to get ' +
|
|
222
|
+
"a measurement.";
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Put the denial where a reader of the check list will meet it.
|
|
226
|
+
*
|
|
227
|
+
* ## Why an annotation and not a conclusion — CodySwannGT/lisa#3968
|
|
228
|
+
*
|
|
229
|
+
* The honest answer would be a `neutral` check-run conclusion, and it is not
|
|
230
|
+
* available: `test_mutation` in `quality.yml` runs under `contents: read`, and
|
|
231
|
+
* `quality.yml` is `workflow_call`-only, where asking for `checks: write` is a
|
|
232
|
+
* `startup_failure` for the caller's entire run (#2049). So the job's row will
|
|
233
|
+
* read `pass`, and the only thing that can travel with it is an annotation —
|
|
234
|
+
* the same device the `gates.unproven` family already uses one job away.
|
|
235
|
+
*
|
|
236
|
+
* REPORT-ONLY, and that is the decision rather than an accident: this returns
|
|
237
|
+
* nothing and touches no exit code. A gate that failed a push because a change
|
|
238
|
+
* touched no mutate target would red-wall every docs-only branch, which is the
|
|
239
|
+
* frequent, benign state this whole file exists to make legible rather than to
|
|
240
|
+
* punish. The fail-CLOSED half of the fix is `mutation_measured`, which is the
|
|
241
|
+
* signal that actually composes into a coverage claim.
|
|
242
|
+
*
|
|
243
|
+
* `disabled` is the one outcome excluded, and it is excluded for a reason that
|
|
244
|
+
* does not generalise: an opt-out is a decision somebody recorded, not a
|
|
245
|
+
* question this gate failed to evaluate, and its own exit already prints a
|
|
246
|
+
* notice naming itself. Every other unmeasured exit annotates, including ones
|
|
247
|
+
* added later — the condition is `measured !== true`, not a roster.
|
|
248
|
+
* @param {string} outcome - The {@link OUTCOMES} marker this run ended on.
|
|
249
|
+
* @param {number} code - The exit code being returned.
|
|
250
|
+
* @param {boolean} measured - Whether this run produced a score.
|
|
251
|
+
* @param {NodeJS.ProcessEnv} env - Environment, injectable for tests.
|
|
252
|
+
* @returns {void}
|
|
253
|
+
*/
|
|
254
|
+
const annotateUnmeasured = (outcome, code, measured, env) => {
|
|
255
|
+
const onCi = env.GITHUB_ACTIONS === "true";
|
|
256
|
+
const greenAndUnmeasured = code === 0 && measured !== true;
|
|
257
|
+
const optedOut = outcome === OUTCOMES.disabled;
|
|
258
|
+
if (onCi && greenAndUnmeasured && !optedOut) {
|
|
259
|
+
console.log(unmeasuredAnnotation(outcome));
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Append the outcome pair to `$GITHUB_OUTPUT`, when there is one to append to.
|
|
265
|
+
*
|
|
266
|
+
* Best-effort by construction: it returns nothing, so no failure in here has a
|
|
267
|
+
* value the caller could mistake for an exit code. A lost output line must
|
|
268
|
+
* never change the code the gate worked to earn.
|
|
269
|
+
* @param {string} outcome - The {@link OUTCOMES} marker this run ended on.
|
|
270
|
+
* @param {boolean} measured - Whether this run produced a score.
|
|
271
|
+
* @param {NodeJS.ProcessEnv} env - Environment, injectable for tests.
|
|
272
|
+
* @returns {void}
|
|
273
|
+
*/
|
|
274
|
+
const writeOutcomeOutputs = (outcome, measured, env) => {
|
|
275
|
+
const target = env.GITHUB_OUTPUT;
|
|
276
|
+
if (target === undefined || target === "") return;
|
|
277
|
+
try {
|
|
278
|
+
fs.appendFileSync(
|
|
279
|
+
target,
|
|
280
|
+
`mutation_outcome=${outcome}\nmutation_measured=${measured === true}\n`
|
|
281
|
+
);
|
|
282
|
+
} catch (error) {
|
|
283
|
+
console.error(
|
|
284
|
+
`[mutation-gate] outcome outputs not written: ${error.message}`
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
|
|
201
289
|
/**
|
|
202
290
|
* Publishes the outcome where the workflow can render it, then returns the code.
|
|
203
291
|
*
|
|
@@ -225,18 +313,8 @@ export const OUTCOMES = Object.freeze({
|
|
|
225
313
|
* @returns {number} `code`, unchanged
|
|
226
314
|
*/
|
|
227
315
|
export const finish = (outcome, code, measured = false, env = process.env) => {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
try {
|
|
231
|
-
fs.appendFileSync(
|
|
232
|
-
target,
|
|
233
|
-
`mutation_outcome=${outcome}\nmutation_measured=${measured === true}\n`
|
|
234
|
-
);
|
|
235
|
-
} catch (error) {
|
|
236
|
-
console.error(
|
|
237
|
-
`[mutation-gate] outcome outputs not written: ${error.message}`
|
|
238
|
-
);
|
|
239
|
-
}
|
|
316
|
+
annotateUnmeasured(outcome, code, measured, env);
|
|
317
|
+
writeOutcomeOutputs(outcome, measured, env);
|
|
240
318
|
return code;
|
|
241
319
|
};
|
|
242
320
|
|
|
@@ -1119,6 +1197,67 @@ const unmeasuredBlock = () =>
|
|
|
1119
1197
|
' Add "clear-text" to `reporters` in your Stryker config to measure it, or set\n' +
|
|
1120
1198
|
" MUTATION_CAPTURE=0 to say out loud that this run is not being accounted for.";
|
|
1121
1199
|
|
|
1200
|
+
/**
|
|
1201
|
+
* The verdict for a run that executed no mutant at all.
|
|
1202
|
+
*
|
|
1203
|
+
* ## The defect this closes — CodySwannGT/lisa#3968
|
|
1204
|
+
*
|
|
1205
|
+
* "I looked and found nothing" and "I did not look" are opposite facts, and a
|
|
1206
|
+
* vocabulary missing the second inevitably prints the first. A tally of all
|
|
1207
|
+
* zeros scores `NaN`, and this file used to hand that to the FLOOR sentence:
|
|
1208
|
+
* the run was reported as one where "no floor was applied", `measured` stayed
|
|
1209
|
+
* `true`, and the exit stayed 0. Three surfaces then said the same wrong thing
|
|
1210
|
+
* — the pre-push block read as a benign footnote on a pass, `mutation_measured`
|
|
1211
|
+
* went out as `true`, and the one job whose entire purpose is to distinguish a
|
|
1212
|
+
* measured run RENDERED GREEN saying "Stryker generated mutants against this
|
|
1213
|
+
* change and produced a score."
|
|
1214
|
+
*
|
|
1215
|
+
* The reachable cause is not exotic. Stryker excludes errored mutants from
|
|
1216
|
+
* every denominator, so a change where every mutant fails to compile — a mutant
|
|
1217
|
+
* whose source no longer parses yields zero tests, not failures — lands here
|
|
1218
|
+
* with `errors` set and everything else zero. So does a run whose generated
|
|
1219
|
+
* mutants were all discarded. Both are runs that measured nothing while looking
|
|
1220
|
+
* exactly like a run that measured zero.
|
|
1221
|
+
*
|
|
1222
|
+
* ## This surface is REPORT-ONLY, deliberately
|
|
1223
|
+
*
|
|
1224
|
+
* It never changes an exit code: a gate that failed a push because a mutant
|
|
1225
|
+
* would not compile is a throughput governor masquerading as a correctness
|
|
1226
|
+
* guard, and `nothing-to-mutate` states are frequent and benign here. What it
|
|
1227
|
+
* does instead is refuse to report a measurement — {@link judgeTimeoutAccounting}
|
|
1228
|
+
* returns `measured: false` from this arm, which is a fail-CLOSED answer on the
|
|
1229
|
+
* one signal that composes into a coverage claim. Report-only on the code,
|
|
1230
|
+
* fail-closed on the claim.
|
|
1231
|
+
* @param {{killed: number, timedOut: number, survived: number,
|
|
1232
|
+
* noCoverage: number, errors?: number}} tally - From
|
|
1233
|
+
* {@link parseMutantTally}.
|
|
1234
|
+
* @param {number|null} breakThreshold - `thresholds.break`, or null.
|
|
1235
|
+
* @returns {string} The block, appended to the accounting report.
|
|
1236
|
+
*/
|
|
1237
|
+
const notMeasuredBlock = (tally, breakThreshold) => {
|
|
1238
|
+
const errored = Number.isFinite(tally.errors) ? tally.errors : 0;
|
|
1239
|
+
const floorNote =
|
|
1240
|
+
breakThreshold === null
|
|
1241
|
+
? ' Your Stryker config declares no "thresholds.break", and there is no score to\n' +
|
|
1242
|
+
" judge against one anyway.\n"
|
|
1243
|
+
: ` A break threshold of ${breakThreshold} is declared and was NOT applied, because a\n` +
|
|
1244
|
+
" floor needs a number to compare against.\n";
|
|
1245
|
+
return (
|
|
1246
|
+
`\n⚪ ${OUTCOMES.notMeasured}\n` +
|
|
1247
|
+
` NO mutant produced a verdict on this run: 0 killed, 0 timed out, 0 survived\n` +
|
|
1248
|
+
` and 0 without coverage, against ${errored} errored mutant(s). Stryker excludes an\n` +
|
|
1249
|
+
` errored mutant from every denominator — it never ran, so it was neither\n` +
|
|
1250
|
+
` caught nor missed — which leaves nothing to take a score of.\n` +
|
|
1251
|
+
` READ THIS AS NOT MEASURED, NEVER AS NOTHING TO MEASURE. Mutate targets\n` +
|
|
1252
|
+
` changed and Stryker was invoked; what did not happen is the measurement.\n` +
|
|
1253
|
+
` Nothing here is a verdict about your tests, in either direction.\n` +
|
|
1254
|
+
`${floorNote}` +
|
|
1255
|
+
` This gate does NOT fail the run for it, and reports mutation_measured=false\n` +
|
|
1256
|
+
` so no check row may claim this change was measured. Read Stryker's own\n` +
|
|
1257
|
+
` output above for why the mutants errored, then re-run for a score.`
|
|
1258
|
+
);
|
|
1259
|
+
};
|
|
1260
|
+
|
|
1122
1261
|
/**
|
|
1123
1262
|
* The floor a completed run was judged against, named with its value.
|
|
1124
1263
|
*
|
|
@@ -1135,13 +1274,14 @@ const unmeasuredBlock = () =>
|
|
|
1135
1274
|
*
|
|
1136
1275
|
* ## Where no floor was applied it says so, rather than inventing one
|
|
1137
1276
|
*
|
|
1138
|
-
*
|
|
1139
|
-
*
|
|
1140
|
-
*
|
|
1141
|
-
*
|
|
1142
|
-
*
|
|
1143
|
-
* is
|
|
1144
|
-
*
|
|
1277
|
+
* A project that declared no `thresholds.break` has not asked for a floor (see
|
|
1278
|
+
* {@link resolveBreakThreshold}, which returns null and not zero for exactly
|
|
1279
|
+
* this reason), so this says NO floor was applied rather than naming one.
|
|
1280
|
+
*
|
|
1281
|
+
* A run that produced no score at all never reaches here: it is answered by
|
|
1282
|
+
* {@link notMeasuredBlock} above, which is a statement about the RUN and not
|
|
1283
|
+
* about the floor. Routing it through a floor sentence was the older shape and
|
|
1284
|
+
* it read as a benign footnote to a passing verdict — see CodySwannGT/lisa#3968.
|
|
1145
1285
|
*
|
|
1146
1286
|
* This is reporting only. It changes no threshold and gates nothing — the arm
|
|
1147
1287
|
* that fails a run is below, and it is untouched.
|
|
@@ -1159,13 +1299,6 @@ const clearedFloorBlock = (tally, accounting, breakThreshold) => {
|
|
|
1159
1299
|
" to this run. The scores above are reported, not cleared — nothing here says\n" +
|
|
1160
1300
|
" they are good enough, because nothing said what good enough is."
|
|
1161
1301
|
);
|
|
1162
|
-
if (!Number.isFinite(accounting.withoutTimeouts))
|
|
1163
|
-
return (
|
|
1164
|
-
`\n⚪ ${OUTCOMES.noFloorApplied}\n` +
|
|
1165
|
-
` A break threshold of ${breakThreshold} is declared, but this run produced no score to\n` +
|
|
1166
|
-
" judge against it, so NO floor was applied. Nothing here is a verdict about\n" +
|
|
1167
|
-
" your tests."
|
|
1168
|
-
);
|
|
1169
1302
|
return (
|
|
1170
1303
|
`\n✅ ${OUTCOMES.clearedBreakThreshold}\n` +
|
|
1171
1304
|
` Without crediting the ${tally.timedOut} timed-out mutant(s), this run scores\n` +
|
|
@@ -1178,7 +1311,13 @@ const clearedFloorBlock = (tally, accounting, breakThreshold) => {
|
|
|
1178
1311
|
/**
|
|
1179
1312
|
* Judge a completed run on what it can prove, rather than on what it counted.
|
|
1180
1313
|
*
|
|
1181
|
-
*
|
|
1314
|
+
* Three answers, not two. A run that executed no mutant is NOT-MEASURED and is
|
|
1315
|
+
* answered by {@link notMeasuredBlock}; the two below are verdicts about a run
|
|
1316
|
+
* that produced a score. Collapsing the first into the third is CodySwannGT/lisa#3968:
|
|
1317
|
+
* a green row then composes into "mutation coverage was verified here", a claim
|
|
1318
|
+
* nobody proved.
|
|
1319
|
+
*
|
|
1320
|
+
* Neither verdict below can turn a red run green — both are checks the gate
|
|
1182
1321
|
* applies IN ADDITION to Stryker's own, on a run Stryker already judged:
|
|
1183
1322
|
*
|
|
1184
1323
|
* - the score recomputed without crediting timeouts is under the project's
|
|
@@ -1186,16 +1325,28 @@ const clearedFloorBlock = (tally, accounting, breakThreshold) => {
|
|
|
1186
1325
|
* helped it;
|
|
1187
1326
|
* - the timed-out share of detected mutants is over the ceiling, so the score is
|
|
1188
1327
|
* more a property of the machine than of the tests, whatever its value.
|
|
1189
|
-
* @param {{killed: number, timedOut: number
|
|
1328
|
+
* @param {{killed: number, timedOut: number, survived?: number,
|
|
1329
|
+
* noCoverage?: number, errors?: number}} tally - The counts.
|
|
1190
1330
|
* @param {number|null} breakThreshold - `thresholds.break`, or null.
|
|
1191
1331
|
* @param {number} ceiling - The share ceiling in force.
|
|
1192
1332
|
* @returns {{failed: boolean, measured: boolean, message: string}} The block,
|
|
1193
|
-
* whether
|
|
1333
|
+
* whether this run produced a score, and whether it fails.
|
|
1194
1334
|
*/
|
|
1195
1335
|
export const judgeTimeoutAccounting = (tally, breakThreshold, ceiling) => {
|
|
1196
1336
|
const accounting = timeoutAccounting(tally);
|
|
1197
1337
|
const report = accountingBlock(tally, accounting, ceiling);
|
|
1198
1338
|
|
|
1339
|
+
// FIRST, because every arm below reads a score this run does not have, and
|
|
1340
|
+
// the two that guard for it would fall through to the third — which reported
|
|
1341
|
+
// a floor that was not applied and called that a measured pass (#3968).
|
|
1342
|
+
if (!Number.isFinite(accounting.withoutTimeouts)) {
|
|
1343
|
+
return {
|
|
1344
|
+
failed: false,
|
|
1345
|
+
measured: false,
|
|
1346
|
+
message: `${report}${notMeasuredBlock(tally, breakThreshold)}`,
|
|
1347
|
+
};
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1199
1350
|
if (
|
|
1200
1351
|
breakThreshold !== null &&
|
|
1201
1352
|
Number.isFinite(accounting.withoutTimeouts) &&
|
|
@@ -75,6 +75,18 @@ export const FAMILIES = [
|
|
|
75
75
|
match: /(^|\/)\.github\/k6\/thresholds\/[^/]+\.json$/,
|
|
76
76
|
kind: "k6",
|
|
77
77
|
},
|
|
78
|
+
{
|
|
79
|
+
// #3992. The always-on eager rule tier is concatenated into every session
|
|
80
|
+
// AND every subagent start, so its byte ceiling is a quality threshold like
|
|
81
|
+
// any other. `max` because the number is a ceiling: lowering it tightens the
|
|
82
|
+
// gate and is free, raising it re-authorises context the cleanup removed and
|
|
83
|
+
// is the change a human has to see. The tier was cut to 26,540 bytes once
|
|
84
|
+
// and regrew to 201,083 in fourteen weeks with nothing watching it.
|
|
85
|
+
id: "eager-rules",
|
|
86
|
+
match: /(^|\/)eager-rules\.thresholds\.json$/,
|
|
87
|
+
kind: "json-num",
|
|
88
|
+
direction: "max",
|
|
89
|
+
},
|
|
78
90
|
{
|
|
79
91
|
id: "lisa-config",
|
|
80
92
|
match: /(^|\/)\.lisa\.config\.json$/,
|