@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
|
@@ -402,6 +402,11 @@ function applyCd(current, target) {
|
|
|
402
402
|
* disagreeing. The scripted form is the one neither covers, and it is the only
|
|
403
403
|
* cell this arm fills.
|
|
404
404
|
*
|
|
405
|
+
* That reason is a dependency on a runtime Lisa does not ship, and it can
|
|
406
|
+
* expire without anything here failing. It is pinned at
|
|
407
|
+
* {@link VERIFIED_RUNTIME_VERSION} and reported when the runtime moves off it
|
|
408
|
+
* — read that constant before widening this arm.
|
|
409
|
+
*
|
|
405
410
|
* ## A relative script path is resolved against the cwd the command will have
|
|
406
411
|
*
|
|
407
412
|
* A leading `cd` establishes the directory this guard resolves relative tokens
|
|
@@ -511,11 +516,28 @@ function readState(sessionId) {
|
|
|
511
516
|
}
|
|
512
517
|
}
|
|
513
518
|
|
|
519
|
+
/**
|
|
520
|
+
* Write the session's binding state, MERGING over whatever is already there.
|
|
521
|
+
*
|
|
522
|
+
* Every caller below hands in all three lifecycle fields explicitly, so the
|
|
523
|
+
* merge changes nothing for them — `claimedRoot: null` still clears a claim.
|
|
524
|
+
* What it buys is that a field one writer owns is not silently dropped by
|
|
525
|
+
* another writer that had no opinion about it: `runtimeNoticed` is written by
|
|
526
|
+
* {@link noticeRuntimeDrift} and read by nobody else, and a clobbering write
|
|
527
|
+
* would turn its "reported once" into "reported again after the next
|
|
528
|
+
* acknowledgement", which is the noise the notice is designed not to be.
|
|
529
|
+
* @param sessionId - The session whose state file this is
|
|
530
|
+
* @param state - Fields to write over the recorded state
|
|
531
|
+
* @returns Whether the write succeeded
|
|
532
|
+
*/
|
|
514
533
|
function writeState(sessionId, state) {
|
|
515
534
|
const file = stateFile(sessionId);
|
|
516
535
|
try {
|
|
517
536
|
mkdirSync(dirname(file), { recursive: true });
|
|
518
|
-
writeFileSync(
|
|
537
|
+
writeFileSync(
|
|
538
|
+
file,
|
|
539
|
+
`${JSON.stringify({ ...readState(sessionId), ...state }, null, 2)}\n`
|
|
540
|
+
);
|
|
519
541
|
return true;
|
|
520
542
|
} catch (error) {
|
|
521
543
|
say(`could not record the binding (${error.message}); NOT enforcing`);
|
|
@@ -695,6 +717,162 @@ function displaced(bound, observed) {
|
|
|
695
717
|
]);
|
|
696
718
|
}
|
|
697
719
|
|
|
720
|
+
/**
|
|
721
|
+
* The runtime version the inline-redirect gap was last verified at.
|
|
722
|
+
*
|
|
723
|
+
* ## What this constant is a pin ON
|
|
724
|
+
*
|
|
725
|
+
* This guard deliberately does NOT refuse an INLINE redirect into another
|
|
726
|
+
* worktree — `cd <other> && git …`, `git -C <other> …`. The reason is good and
|
|
727
|
+
* is written out at {@link scriptReachingForeignTree}: the runtime's own
|
|
728
|
+
* worktree isolation already refuses them, and duplicating a control is how two
|
|
729
|
+
* controls drift into disagreeing about the same command.
|
|
730
|
+
*
|
|
731
|
+
* That reason is a DEPENDENCY on behaviour Lisa does not ship. It was verified
|
|
732
|
+
* refusing at this version, with the refusal wording "this command names git in
|
|
733
|
+
* a form too complex to verify that it stays inside the worktree" and
|
|
734
|
+
* "redirects git to the shared checkout via -C".
|
|
735
|
+
*
|
|
736
|
+
* ## Why a pin rather than a test
|
|
737
|
+
*
|
|
738
|
+
* The runtime's isolation is not reachable from a unit test: it adjudicates
|
|
739
|
+
* inside a live worktree-isolated session, and there is no entry point that
|
|
740
|
+
* takes one hook envelope and returns a verdict the way this guard does. So the
|
|
741
|
+
* dependency cannot be turned red by writing a test, and a claim that cannot go
|
|
742
|
+
* red goes stale silently instead (CodySwannGT/lisa#3944).
|
|
743
|
+
*
|
|
744
|
+
* What CAN be measured is whether the runtime is still the one the claim was
|
|
745
|
+
* checked against. That does not prove the behaviour changed — only that nobody
|
|
746
|
+
* has checked since, which is the honest thing to report and the whole of what
|
|
747
|
+
* this pin does.
|
|
748
|
+
*
|
|
749
|
+
* ## Moving it
|
|
750
|
+
*
|
|
751
|
+
* Re-run both inline forms in a worktree-isolated session. Still refused: move
|
|
752
|
+
* this pin, and say where. Permitted: those two cells are UNCOVERED, and #3944
|
|
753
|
+
* owns the decision about which of them Lisa takes on.
|
|
754
|
+
*/
|
|
755
|
+
const VERIFIED_RUNTIME_VERSION = "2.1.261";
|
|
756
|
+
|
|
757
|
+
/** The ticket that owns the inline-redirect dependency and its expiry. */
|
|
758
|
+
const RUNTIME_ASSUMPTION_TICKET = "CodySwannGT/lisa#3944";
|
|
759
|
+
|
|
760
|
+
/**
|
|
761
|
+
* This session's runtime version, or null when this is not that runtime.
|
|
762
|
+
*
|
|
763
|
+
* Three answers, and the difference between the last two is the point:
|
|
764
|
+
* - `null` — not Claude Code. Codex, Cursor and Copilot ship this guard too,
|
|
765
|
+
* and the assumption above is about a control none of them has. A notice that
|
|
766
|
+
* fires on every session of every harness is noise, and noise gets switched
|
|
767
|
+
* off.
|
|
768
|
+
* - `""` — Claude Code, which will not say which version. Read as a DIVERGENCE
|
|
769
|
+
* rather than as a match: the assumption is unconfirmed either way, and
|
|
770
|
+
* treating an unreadable version as "still 2.1.261" is exactly the silent
|
|
771
|
+
* expiry #3944 was filed about.
|
|
772
|
+
* - a version — take it at its word.
|
|
773
|
+
*
|
|
774
|
+
* Both env vars are read because either can be the one a future release keeps.
|
|
775
|
+
* `AI_AGENT` carries `claude-code_2-1-261_agent`; `CLAUDE_CODE_EXECPATH` ends
|
|
776
|
+
* in the version directory the running build was launched from.
|
|
777
|
+
* @param env - Environment to read
|
|
778
|
+
* @returns The version, `""` when unreadable, or null for another runtime
|
|
779
|
+
*/
|
|
780
|
+
const isDigit = ch => ch >= "0" && ch <= "9";
|
|
781
|
+
|
|
782
|
+
/** @param value - Segment to test @returns Whether it is all digits */
|
|
783
|
+
const allDigits = value => value.length > 0 && [...value].every(isDigit);
|
|
784
|
+
|
|
785
|
+
/** @param value - Segment to read @returns Its trailing digit run, else `""` */
|
|
786
|
+
const trailingDigits = value => {
|
|
787
|
+
let start = value.length;
|
|
788
|
+
while (start > 0 && isDigit(value[start - 1])) start -= 1;
|
|
789
|
+
return value.slice(start);
|
|
790
|
+
};
|
|
791
|
+
|
|
792
|
+
function runtimeVersion(env) {
|
|
793
|
+
if (!env.CLAUDECODE) return null;
|
|
794
|
+
const tagged = /claude-code[_-](\d+)[-.](\d+)[-.](\d+)/u.exec(
|
|
795
|
+
env.AI_AGENT ?? ""
|
|
796
|
+
);
|
|
797
|
+
if (tagged) return `${tagged[1]}.${tagged[2]}.${tagged[3]}`;
|
|
798
|
+
// Read the version off the final path segment by scanning characters rather
|
|
799
|
+
// than by regex: an unanchored `\d+\.\d+\.\d+` before `$` backtracks
|
|
800
|
+
// super-linearly on a long execpath, and the version Claude Code launches
|
|
801
|
+
// from is always the trailing directory name.
|
|
802
|
+
const segments = (env.CLAUDE_CODE_EXECPATH ?? "").split("/").filter(Boolean);
|
|
803
|
+
const trailing = segments.length ? segments[segments.length - 1] : "";
|
|
804
|
+
const parts = trailing.split(".");
|
|
805
|
+
if (parts.length < 3) return "";
|
|
806
|
+
const [major, minor, patch] = parts.slice(-3);
|
|
807
|
+
const majorDigits = trailingDigits(major);
|
|
808
|
+
if (!majorDigits || !allDigits(minor) || !allDigits(patch)) return "";
|
|
809
|
+
return `${majorDigits}.${minor}.${patch}`;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
/**
|
|
813
|
+
* The notice text for a runtime the inline-redirect claim was not checked at.
|
|
814
|
+
* @param version - The observed runtime version, `""` when unreadable
|
|
815
|
+
* @returns The lines to report
|
|
816
|
+
*/
|
|
817
|
+
function driftNotice(version) {
|
|
818
|
+
return [
|
|
819
|
+
"worktree-binding-guard: the inline-redirect gap is UNVERIFIED here.",
|
|
820
|
+
"",
|
|
821
|
+
"This guard does not refuse `cd <other-worktree> && git …` or",
|
|
822
|
+
"`git -C <other-worktree> …`. Those two cells are covered by the runtime's",
|
|
823
|
+
`own worktree isolation, verified refusing at Claude Code ${VERIFIED_RUNTIME_VERSION}.`,
|
|
824
|
+
version
|
|
825
|
+
? `This session is running ${version}, so that check does not cover it.`
|
|
826
|
+
: "This session's runtime version could not be read, so nothing covers it.",
|
|
827
|
+
"",
|
|
828
|
+
"This does NOT say the runtime stopped refusing them — only that nobody has",
|
|
829
|
+
"checked since. Run both forms in a worktree-isolated session: still",
|
|
830
|
+
"refused, move VERIFIED_RUNTIME_VERSION in worktree-binding-guard.mjs;",
|
|
831
|
+
`permitted, the two cells are uncovered and ${RUNTIME_ASSUMPTION_TICKET}`,
|
|
832
|
+
"owns what Lisa does about it.",
|
|
833
|
+
];
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
/**
|
|
837
|
+
* Report, once per session, that the runtime moved off the verified version.
|
|
838
|
+
*
|
|
839
|
+
* ## Why SessionStart and not the guarded call
|
|
840
|
+
*
|
|
841
|
+
* SessionStart is the guard's first evaluation of a session, it fires exactly
|
|
842
|
+
* once per start, and its `additionalContext` is the one channel here that the
|
|
843
|
+
* agent actually reads — the `say()` lines elsewhere in this file are for a
|
|
844
|
+
* human reading a transcript. A notice attached to a guarded tool call would
|
|
845
|
+
* either repeat on every Bash command or need a suppression rule of its own.
|
|
846
|
+
*
|
|
847
|
+
* ## Why it is recorded rather than counted
|
|
848
|
+
*
|
|
849
|
+
* A resume fires SessionStart again for the same session id. The recorded
|
|
850
|
+
* version is what makes the second one silent, and recording the VERSION rather
|
|
851
|
+
* than a flag means a runtime that moves twice inside one resumed session is
|
|
852
|
+
* still reported the second time.
|
|
853
|
+
*
|
|
854
|
+
* Never refuses. The dependency is a reporting gap, not a live displacement,
|
|
855
|
+
* and blocking a session over a version number would be a wall where an
|
|
856
|
+
* observation belongs.
|
|
857
|
+
* @param sessionId - The session being started
|
|
858
|
+
* @param env - Environment to read the runtime version from
|
|
859
|
+
* @returns Nothing; every path through this allows
|
|
860
|
+
*/
|
|
861
|
+
function noticeRuntimeDrift(sessionId, env) {
|
|
862
|
+
const version = runtimeVersion(env);
|
|
863
|
+
if (version === null || version === VERIFIED_RUNTIME_VERSION) return;
|
|
864
|
+
if (readState(sessionId)?.runtimeNoticed === version) return;
|
|
865
|
+
writeState(sessionId, { runtimeNoticed: version });
|
|
866
|
+
process.stdout.write(
|
|
867
|
+
`${JSON.stringify({
|
|
868
|
+
hookSpecificOutput: {
|
|
869
|
+
hookEventName: "SessionStart",
|
|
870
|
+
additionalContext: driftNotice(version).join("\n"),
|
|
871
|
+
},
|
|
872
|
+
})}\n`
|
|
873
|
+
);
|
|
874
|
+
}
|
|
875
|
+
|
|
698
876
|
function evaluate(payload) {
|
|
699
877
|
const sessionId = payload.session_id;
|
|
700
878
|
const cwd = payload.cwd;
|
|
@@ -707,6 +885,10 @@ function evaluate(payload) {
|
|
|
707
885
|
|
|
708
886
|
if (payload.hook_event_name === "SessionStart") {
|
|
709
887
|
recordBaseline(sessionId, observed);
|
|
888
|
+
// After the baseline, never before: `recordBaseline` writes a fresh state
|
|
889
|
+
// for a session it has not seen, and the notice's record has to go on top
|
|
890
|
+
// of that write rather than under it.
|
|
891
|
+
noticeRuntimeDrift(sessionId, process.env);
|
|
710
892
|
return 0;
|
|
711
893
|
}
|
|
712
894
|
if (payload.tool_name === "EnterWorktree") {
|
|
@@ -36,6 +36,27 @@ set -uo pipefail
|
|
|
36
36
|
|
|
37
37
|
input="$(cat)"
|
|
38
38
|
|
|
39
|
+
# Evaluate once per tool call when this guard is registered on both channels.
|
|
40
|
+
#
|
|
41
|
+
# Lisa reaches an agent through the repository dispatcher AND the plugin
|
|
42
|
+
# manifest, and where both are live the harness runs this guard twice for one
|
|
43
|
+
# tool call. `guard-dedupe.bash` short-circuits the second run ONLY when a
|
|
44
|
+
# byte-identical copy already ALLOWED this exact payload on this exact tool
|
|
45
|
+
# call; a differing vintage, a refusal, and a host with one channel all
|
|
46
|
+
# evaluate exactly as before. Nothing is de-registered by it
|
|
47
|
+
# (CodySwannGT/lisa#3814).
|
|
48
|
+
#
|
|
49
|
+
# Absent library means no dedupe, which is the pre-existing behaviour, so an
|
|
50
|
+
# older channel copy that predates it is unaffected.
|
|
51
|
+
lisa_guard_hook_dir="${BASH_SOURCE[0]%/*}"
|
|
52
|
+
lisa_guard_dedupe_lib="$lisa_guard_hook_dir/guard-dedupe.bash"
|
|
53
|
+
if [ -r "$lisa_guard_dedupe_lib" ]; then
|
|
54
|
+
# shellcheck source=guard-dedupe.bash
|
|
55
|
+
. "$lisa_guard_dedupe_lib"
|
|
56
|
+
trap 'lisa_guard_dedupe_record $?' EXIT
|
|
57
|
+
lisa_guard_dedupe worktree-binding-guard "$input"
|
|
58
|
+
fi
|
|
59
|
+
|
|
39
60
|
if ! command -v node >/dev/null 2>&1; then
|
|
40
61
|
printf 'worktree-binding-guard: node not found; worktree-binding enforcement is NOT active\n' >&2
|
|
41
62
|
exit 0
|
|
@@ -29,6 +29,7 @@ Paths are relative to this file.
|
|
|
29
29
|
| `prd-definition-of-ready` | authoring or validating a PRD's requirement atoms | [../reference/prd-definition-of-ready.md](../reference/prd-definition-of-ready.md) |
|
|
30
30
|
| `prd-lifecycle-rollup` | rolling a PRD up from its generated top-level work | [../reference/prd-lifecycle-rollup.md](../reference/prd-lifecycle-rollup.md) |
|
|
31
31
|
| `usage-accounting` | writing the managed `## Lisa Usage` section on an artifact | [../reference/usage-accounting.md](../reference/usage-accounting.md) |
|
|
32
|
+
| `work-item-trailer-definition` | reading, counting, or auditing a `Work-Item:` trailer — BEFORE reaching for `%(trailers)` | [../reference/work-item-trailer-definition.md](../reference/work-item-trailer-definition.md) |
|
|
32
33
|
|
|
33
34
|
## Build-intake claim time
|
|
34
35
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Operational Hazards — Short-Lived, Expiring, and Read by Sessions That Do Not Exist Yet
|
|
2
|
+
|
|
3
|
+
**A broadcast cannot reach a session that starts after it, and the sessions that missed it never
|
|
4
|
+
knew there was something to miss.** The lanes most likely to collide on a port, saturate the
|
|
5
|
+
workers, or re-hit a defect somebody diagnosed an hour ago are precisely the ones that just
|
|
6
|
+
started — so the population a fan-out structurally cannot reach is the population most exposed.
|
|
7
|
+
|
|
8
|
+
Enumerating peers does not fix it: two sessions listing peers at the same moment returned different
|
|
9
|
+
rosters, so "I told everyone" carries an unknown hole.
|
|
10
|
+
|
|
11
|
+
## Mandatory
|
|
12
|
+
|
|
13
|
+
- **Declare a transient hazard instead of announcing it.** A condition another session will hit —
|
|
14
|
+
a port another lane holds, a saturated resource, a command that dumps credentials, a gate that is
|
|
15
|
+
red for an environmental reason — is not communicated until this has run:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
node "$CLAUDE_PLUGIN_ROOT/hooks/operational-hazards.mjs" --declare <id> \
|
|
19
|
+
--hazard "<what will go wrong>" \
|
|
20
|
+
--avoid "<what to do instead>" \
|
|
21
|
+
--until <YYYY-MM-DD>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`--until` is required and has no default. **An entry that never expires is doctrine, and doctrine
|
|
25
|
+
belongs in a rule** — a hazard surface without an expiry becomes permanent scripture, which is
|
|
26
|
+
the failure this exists against. Past its `until`, an entry stops being shown with nobody
|
|
27
|
+
remembering to remove it.
|
|
28
|
+
|
|
29
|
+
- **Lift it when it ends.** A declaration nothing can void is the defect the QA-failure signal and
|
|
30
|
+
the human gate each closed:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
node "$CLAUDE_PLUGIN_ROOT/hooks/operational-hazards.mjs" --lift <id> --because "<what resolved it>"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- **Read it where no hook runs:** `node "$CLAUDE_PLUGIN_ROOT/hooks/operational-hazards.mjs" --list`.
|
|
37
|
+
|
|
38
|
+
## What arrives on its own
|
|
39
|
+
|
|
40
|
+
On Claude Code the ledger is read for you at SessionStart **and SubagentStart** — a subagent
|
|
41
|
+
spawned an hour from now reads it, which no fan-out reaches at all — and re-checked after every
|
|
42
|
+
tool call, so a hazard declared or lifted **while you are running** arrives on your next tool
|
|
43
|
+
result. Two `stat` calls when nothing changed.
|
|
44
|
+
|
|
45
|
+
An entry naming no evaluable expiry still applies and is reported as `unchecked`, loudly. An expiry
|
|
46
|
+
that lapsed into "no longer shown" would restore permanent scripture while every signal read
|
|
47
|
+
healthy.
|
|
48
|
+
|
|
49
|
+
Both ledger tiers, what belongs here versus in a rule, and the surfaces with no hook runtime:
|
|
50
|
+
[reference/operational-hazards.md](../reference/operational-hazards.md).
|
|
@@ -4,4 +4,4 @@ Before the first durable project mutation (code, tests, config, docs, committed
|
|
|
4
4
|
|
|
5
5
|
The mandatory order is: live-validate an explicit ref, or conservatively search and create exactly one valid leaf through `lisa-tracker-write` when no unique match exists; idempotently claim it through `lisa-tracker-claim`; then persist and verify the worktree-local binding with `node scripts/lisa-work-item.mjs link <ref>`. A tracker that answers no, and any claim or binding failure, blocks durable work; a tracker that cannot be reached does not block a commit — the offline checks still run, the skip is loud on stderr, and the required `Work-Item Traceability` check re-runs the live checks with credentials before anything merges.
|
|
6
6
|
|
|
7
|
-
Carry that canonical ref through the branch, every ordinary commit's `Work-Item:` trailer, the PR, usage/evidence, and `lisa-tracker-sync`. Hooks and CI never create tickets. Keep the binding through interruptions or blocked outcomes; run `node scripts/lisa-work-item.mjs clear` only after merge/deploy/verification, two-way linkage/evidence, and the tracker item have all reached true terminal completion.
|
|
7
|
+
Carry that canonical ref through the branch, every ordinary commit's `Work-Item:` trailer, the PR, usage/evidence, and `lisa-tracker-sync`. Hooks and CI never create tickets. Anything that READS a `Work-Item:` trailer — a gate, an audit, a count, a report — must import `workItemLines` from the shipped `scripts/lisa-work-item.mjs` rather than reach for `git interpret-trailers` or `%(trailers)`, which see only a message's final block and miss 92% of this fleet's trailers; read the `work-item-trailer-definition` rule before writing such a reader. Keep the binding through interruptions or blocked outcomes; run `node scripts/lisa-work-item.mjs clear` only after merge/deploy/verification, two-way linkage/evidence, and the tracker item have all reached true terminal completion.
|
|
@@ -1028,7 +1028,7 @@ When `github-to-tracker` is invoked AND `tracker = "github"`, both reads and wri
|
|
|
1028
1028
|
|
|
1029
1029
|
Never overload one label across both lifecycles.
|
|
1030
1030
|
|
|
1031
|
-
The same separation applies for Linear self-host (`source = "linear"` AND `tracker = "linear"`), with one asymmetry: project-level **labels** (`prd-*`) drive the PRD lifecycle, because a PRD is a Linear Project and Projects carry their own status object rather than Issue workflow states; issue-level **workflow states** (`linear.workflow`) drive the build lifecycle; the
|
|
1031
|
+
The same separation applies for Linear self-host (`source = "linear"` AND `tracker = "linear"`), with one asymmetry: project-level **labels** (`prd-*`) drive the PRD lifecycle, because a PRD is a Linear Project and Projects carry their own status object rather than Issue workflow states; issue-level **workflow states** (`linear.workflow`) drive the build lifecycle; clarifying-question comments go on the Project itself via `commentCreate(input: { projectId, body })`, so the PRD lane needs no issue label of its own (`prd-intake-feedback` survives only to recognise the fabricated feedback issues earlier versions created). So on Linear the two lanes are not merely different vocabularies, they are different *mechanisms* — never move a PRD by state or an Issue by `status:*` label.
|
|
1032
1032
|
|
|
1033
1033
|
## Notion access (substrate ladder)
|
|
1034
1034
|
|
|
@@ -182,7 +182,7 @@ The env rungs are whatever the project configures for `done` — which is **env-
|
|
|
182
182
|
|
|
183
183
|
Intermediate-env rollup and terminal native closure are distinct: a parent **rolls up to** an intermediate env (`On Dev`/`On Stg`) as its required leaves reach it, but native closure (next section) fires **only** at the production/terminal `done` value. A parent sitting at `On Stg` is correctly rolled up *and* still open.
|
|
184
184
|
|
|
185
|
-
**Single-environment collapse (this repo).**
|
|
185
|
+
**Single-environment collapse (this repo).** The collapse is a property of the **resolution**, not of the declaration. `.lisa.config.json` declares `github.labels.build.done` as the generic **env-keyed map** — `dev: status:on-dev`, `staging: status:on-stg`, `production: status:done` — which is exactly the shape `lisa-setup-github` creates by default. What this repo lacks is deploy *branches*: `deploy.branches` maps only `production → main`, so `production` is the sole reachable rung and every merge this repo can make resolves to `status:done`. For GitHub the build lifecycle therefore runs one chain in practice: `ready → claimed (in-progress) → done`, and the rollup terminal state is `status:done`. Do not read the collapse as an absent map: code that reads the `done` role must still resolve the merged PR's base branch through `deploy.branches` and take that env's rung, in this repo as in any other — assuming a scalar here would read the wrong rung the moment a deploy branch is added. Projects with more deploy branches differ only in how many rungs are reachable, not in the declared shape.
|
|
186
186
|
|
|
187
187
|
## Terminal native closure
|
|
188
188
|
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Operational Hazards — reference
|
|
2
|
+
|
|
3
|
+
Full contract behind the `operational-hazards` slug (CodySwannGT/lisa#3681). The eager rule carries
|
|
4
|
+
the two commands; this is the reasoning, the tiers, and the boundary against doctrine.
|
|
5
|
+
|
|
6
|
+
## The general property
|
|
7
|
+
|
|
8
|
+
**A detector whose only failure mode is staying quiet cannot be audited.** A fan-out reaches the
|
|
9
|
+
sessions alive at one instant. The sessions that were not alive receive nothing and are told
|
|
10
|
+
nothing, so nobody — the sender included — can name who was missed.
|
|
11
|
+
|
|
12
|
+
Measured on one machine in one hour: one session started 18 minutes after a warning it needed;
|
|
13
|
+
another started 8 minutes after a different one; four more appeared and vanished entirely inside
|
|
14
|
+
the hour. And the lanes most likely to collide are the ones that just started and are standing up
|
|
15
|
+
fresh environments — so the warning that would have prevented the collision cannot reach the
|
|
16
|
+
session that causes it, because that session does not exist yet.
|
|
17
|
+
|
|
18
|
+
**The hole is unmeasurable, not merely growing.** Two sessions on the same machine, enumerating
|
|
19
|
+
peers at the same moment, returned different rosters: one session appeared in one listing and had
|
|
20
|
+
never appeared in four consecutive reads by the other. So "I enumerated the roster and checked the
|
|
21
|
+
list" carries an unknown hole, and a fan-out audited against one session's view cannot be audited
|
|
22
|
+
at all.
|
|
23
|
+
|
|
24
|
+
## What the existing rule injector cannot do
|
|
25
|
+
|
|
26
|
+
`inject-rules.sh` reads `CLAUDE_PLUGIN_ROOT/rules/eager` — the plugin root, not the project. A
|
|
27
|
+
project cannot register anything there without editing an installed plugin, which the next apply
|
|
28
|
+
overwrites. And it concatenates every `.md` unconditionally: no front matter, no date, no filter.
|
|
29
|
+
Anything written there is injected on every start, permanently, until a human deletes the file.
|
|
30
|
+
|
|
31
|
+
So the injector is the right *reach* and the wrong *store*. This ledger reuses the reach — the same
|
|
32
|
+
two start events, plus the tool-result event — and supplies a project-owned store whose entries
|
|
33
|
+
carry a condition something evaluates.
|
|
34
|
+
|
|
35
|
+
## Why the expiry is the mechanism, not a convenience
|
|
36
|
+
|
|
37
|
+
**The expiry is what separates a transient hazard from doctrine**, and it is the only reason the
|
|
38
|
+
surface can be trusted with transient content: nobody has to remember to remove anything. A hazard
|
|
39
|
+
surface without an expiry becomes the permanent-scripture problem, and a project that has watched
|
|
40
|
+
that happen once will correctly refuse to use the surface again.
|
|
41
|
+
|
|
42
|
+
The shape is deliberately the threshold-ratchet exemption's (CodySwannGT/lisa#3856) rather than a
|
|
43
|
+
third scheme:
|
|
44
|
+
|
|
45
|
+
- record the condition in a form something can evaluate — `until`, a `YYYY-MM-DD` day or an
|
|
46
|
+
ISO-8601 timestamp, live *through* the day named;
|
|
47
|
+
- never let an unevaluable condition lapse into the permissive answer. An entry naming no evaluable
|
|
48
|
+
expiry — hand-written, or written before `until` existed — **still applies**, and is reported as
|
|
49
|
+
`unchecked` every time it is read.
|
|
50
|
+
|
|
51
|
+
An expiry that lapses into "no longer shown" is worse than no expiry: it restores permanent
|
|
52
|
+
scripture in reverse — the hazard vanishes — while every signal still reads healthy. That is why
|
|
53
|
+
the writer refuses `--declare` without `--until`, and refuses an `until` it cannot parse, while the
|
|
54
|
+
reader tolerates one and says so.
|
|
55
|
+
|
|
56
|
+
## The inverse
|
|
57
|
+
|
|
58
|
+
A hazard also ends before its expiry. A declaration nothing can void is the defect closed twice
|
|
59
|
+
already — the QA-failure signal (CodySwannGT/lisa#3855) and the human gate (CodySwannGT/lisa#3852)
|
|
60
|
+
— so `--lift` appends a void record naming what resolved it.
|
|
61
|
+
|
|
62
|
+
Matching is **time-ordered**: a lift voids only a declaration that pre-dates it. A hazard
|
|
63
|
+
re-declared after an earlier lift is therefore not born discharged, which is the unsafe direction
|
|
64
|
+
#3852 records as the one this must not introduce. For the same reason the ledger union keeps the
|
|
65
|
+
**newest** declaration for an id, not the first one read.
|
|
66
|
+
|
|
67
|
+
## The ledger's two tiers
|
|
68
|
+
|
|
69
|
+
- **`.lisa/HAZARDS.jsonl`**, committed — reaches every future reader of this project and merges by
|
|
70
|
+
git's built-in union driver. This is also the tier that answers "does `lisa apply` preserve it":
|
|
71
|
+
it is host-authored content under `.lisa/`, like the withdrawal tombstones beside it, and no
|
|
72
|
+
managed-file reconciliation writes it.
|
|
73
|
+
- **`${LISA_STATE_HOME:-~/.lisa}/operational-hazards.jsonl`** — reaches sibling sessions in OTHER
|
|
74
|
+
worktrees on this machine *now*, which a committed file cannot do until it is merged and pulled.
|
|
75
|
+
For the fleet case above, this is the tier that matters.
|
|
76
|
+
|
|
77
|
+
`--declare` and `--lift` write both. Reads are the union. Both files are append-only JSONL, so
|
|
78
|
+
concurrent writers on their own branches reconstruct exactly under `merge=union`.
|
|
79
|
+
|
|
80
|
+
## How a running session is reached
|
|
81
|
+
|
|
82
|
+
`--session-start` delivers everything applying and stamps what the session was born knowing.
|
|
83
|
+
`--hook` runs as a PostToolUse hook and announces only what changed since that stamp: a hazard
|
|
84
|
+
declared while this session runs, and a **lift** of a hazard this session was told about. Both
|
|
85
|
+
directions were measured — the provenance of #3681 is a session that was sent a lift for a hold it
|
|
86
|
+
had never received.
|
|
87
|
+
|
|
88
|
+
A missing stamp is deliberately silent. A session whose starting knowledge is unknown would
|
|
89
|
+
otherwise be told every historical hazard, which degrades the mechanism into distrusting
|
|
90
|
+
everything.
|
|
91
|
+
|
|
92
|
+
The common path is cheap: when neither tier's `size:mtime` has moved, `--hook` exits after two
|
|
93
|
+
`stat` calls without parsing anything. It fires on every tool call in every session, so anything
|
|
94
|
+
expensive multiplies.
|
|
95
|
+
|
|
96
|
+
## Surface parity
|
|
97
|
+
|
|
98
|
+
The hook pair ships into every payload that carries the base hooks, and the injector fires on
|
|
99
|
+
`SubagentStart` as well as `SessionStart` — which makes this better than a broadcast rather than
|
|
100
|
+
merely equivalent, since a fan-out never reaches a subagent at all.
|
|
101
|
+
|
|
102
|
+
Surfaces with no PostToolUse runtime get the start-event half and `--list`. That is the honest
|
|
103
|
+
split: **the durable half — reaching every session that starts later — is closed everywhere the
|
|
104
|
+
hook installs. The already-running half depends on a tool-result event, so where there is none, a
|
|
105
|
+
running session is reached only when it runs `--list`.**
|
|
106
|
+
|
|
107
|
+
## What deliberately does not belong here
|
|
108
|
+
|
|
109
|
+
Anything that should still be true next month. A hazard is a condition of *this machine, this
|
|
110
|
+
branch, this hour*: a port another lane holds, a resource one run has saturated, a command that
|
|
111
|
+
dumps more than you asked for, a gate red for an environmental reason. If the entry would want
|
|
112
|
+
renewing when it expires, it was never a hazard — promote it through the learnings ladder to a rule
|
|
113
|
+
or an executable control, and let the entry lapse.
|
|
114
|
+
|
|
115
|
+
Not a severity taxonomy, not a notification system, and not a change to how eager rules work.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Work-Item Trailer Definition — What Counts As One, And Which Reader Is Authoritative
|
|
2
|
+
|
|
3
|
+
Read this **before** writing anything that reads, counts, audits, or verifies a
|
|
4
|
+
`Work-Item:` reference in a commit message or a pull-request body. There are two
|
|
5
|
+
plausible definitions of "a `Work-Item:` trailer", they disagree about real
|
|
6
|
+
commits in this fleet, and the obvious tool — git's own trailer parser — is the
|
|
7
|
+
wrong one.
|
|
8
|
+
|
|
9
|
+
## The two definitions
|
|
10
|
+
|
|
11
|
+
**Definition A — git's.** `git log --format='%(trailers:key=Work-Item)'` and
|
|
12
|
+
`git interpret-trailers --parse` read only the **final contiguous block** of
|
|
13
|
+
`Key: value` lines. Any non-trailer line after a trailer ends that block, and
|
|
14
|
+
everything above it becomes invisible to the parser.
|
|
15
|
+
|
|
16
|
+
**Definition B — Lisa's.** A `Work-Item:` line is any line of the **whole
|
|
17
|
+
message** whose first character begins the ASCII-case-insensitive prefix
|
|
18
|
+
`Work-Item:` at **column zero**, with a non-empty value after it. Position in
|
|
19
|
+
the message carries no information. Repeats of the same reference are accepted.
|
|
20
|
+
|
|
21
|
+
## Definition B is authoritative. This is settled, not open.
|
|
22
|
+
|
|
23
|
+
Definition A was tried and abandoned in CodySwannGT/lisa#2672: it reported
|
|
24
|
+
`found 0` about messages that plainly contained a trailer, because a blank line
|
|
25
|
+
before the `Co-Authored-By:` attribution block — or a bot appending release
|
|
26
|
+
notes below it — was enough to end the block. Making Definition A work would
|
|
27
|
+
require that nothing ever append to a commit message, which is precisely the
|
|
28
|
+
assumption #2672 recorded as false.
|
|
29
|
+
|
|
30
|
+
The `🤖 Generated with Claude Code` convention puts boilerplate **after** the
|
|
31
|
+
trailer by default, so under Definition A a large share of this repository's own
|
|
32
|
+
commits read as untrailered. **The failure is the common case, not the edge
|
|
33
|
+
case.**
|
|
34
|
+
|
|
35
|
+
### Measured, not asserted
|
|
36
|
+
|
|
37
|
+
Both definitions run over real history, non-merge commits, counting only commits
|
|
38
|
+
where at least one definition finds a reference:
|
|
39
|
+
|
|
40
|
+
| Range | Commits naming an item | Agree | A finds none, B finds one | Other disagreement |
|
|
41
|
+
|---|---|---|---|---|
|
|
42
|
+
| A single multi-agent branch | 51 | 4 | **47 (92%)** | 0 |
|
|
43
|
+
| Full default-branch history | 1,730 | 1,248 | **477 (27.6%)** | 5 |
|
|
44
|
+
|
|
45
|
+
The five "other" disagreements are commits carrying a bare `Work-Item: #1234`
|
|
46
|
+
above the block as well as the canonical reference inside it; B sees both, A
|
|
47
|
+
sees only the one in the final block.
|
|
48
|
+
|
|
49
|
+
**The undercount is clean, plausible and well-formed**, which is why it survives
|
|
50
|
+
review. `%(trailers)` printing nothing is genuinely convincing evidence until
|
|
51
|
+
you know this rule exists — which is why at least three separate audits have
|
|
52
|
+
shipped confident, specific, wrong findings from it, including an instruction to
|
|
53
|
+
amend a commit whose trailer was fine.
|
|
54
|
+
|
|
55
|
+
## Do not reimplement it. Import it.
|
|
56
|
+
|
|
57
|
+
`workItemLines(message)` and `soleWorkItem(text, contract, subject)` are
|
|
58
|
+
exported from the shipped `scripts/lisa-work-item.mjs`. They are the definition.
|
|
59
|
+
A second parser is a second answer to "which item is this?", and two answers is
|
|
60
|
+
the state this rule exists to end.
|
|
61
|
+
|
|
62
|
+
```js
|
|
63
|
+
import { workItemLines } from "./lisa-work-item.mjs";
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`workItemLines` returns every value found, in order of appearance, untouched
|
|
67
|
+
beyond trimming. `soleWorkItem` canonicalizes them against the tracker contract
|
|
68
|
+
and refuses a text naming two **different** items.
|
|
69
|
+
|
|
70
|
+
## What each layer owns, and why the shape filter stays at the call site
|
|
71
|
+
|
|
72
|
+
`workItemLines` deliberately does **not** validate the shape of a value. It
|
|
73
|
+
answers "what does this text say?" — nothing more. Canonicalization,
|
|
74
|
+
repository-membership, and the refusal of the full issue-URL form all live in
|
|
75
|
+
`canonicalizeRef`, above it.
|
|
76
|
+
|
|
77
|
+
That split is load-bearing and must not be converged away. A reader that
|
|
78
|
+
filtered malformed values out during the scan would make a bad value
|
|
79
|
+
**invisible** rather than **refused**: `Work-Item: https://github.com/o/r/issues/7`
|
|
80
|
+
would read as no trailer at all, and the gate would report "no Work-Item trailer
|
|
81
|
+
anywhere in the commit message" about a message containing exactly one, which is
|
|
82
|
+
the #2672 failure re-created one layer down. The reader sees everything; the
|
|
83
|
+
layer above decides what is acceptable.
|
|
84
|
+
|
|
85
|
+
The consequence a caller must respect: **a filter you apply to `workItemLines`'
|
|
86
|
+
output is your filter, not the definition.** State what it drops.
|
|
87
|
+
|
|
88
|
+
## Column zero is part of the definition
|
|
89
|
+
|
|
90
|
+
The prefix is anchored at column zero, so `# Work-Item: …` in a comment never
|
|
91
|
+
matches, and neither does a unified-diff line — every one of those carries a
|
|
92
|
+
space, `+` or `-` in that column. A reader that tolerates leading whitespace
|
|
93
|
+
matches the **context line of a verbose commit's own diff**. Measured over full
|
|
94
|
+
default-branch history: 2,059 `Work-Item:` lines at column zero, **zero**
|
|
95
|
+
indented ones. There is no real input that needs the looser form and one class
|
|
96
|
+
of false positive that needs the anchor.
|
|
97
|
+
|
|
98
|
+
The prefix is matched with a non-Unicode `/i` regex rather than
|
|
99
|
+
`toLowerCase().startsWith(…)` on purpose: `toLowerCase()` applies full Unicode
|
|
100
|
+
case mapping, so U+212A KELVIN SIGN would fold to `k` and `WorK-Item:` written
|
|
101
|
+
with it would be accepted — a form this has never accepted.
|
|
102
|
+
|
|
103
|
+
## Testing a trailer reader
|
|
104
|
+
|
|
105
|
+
**A checker exercised only against well-formed messages passes under either
|
|
106
|
+
definition.** That is why three audits shipped with the bug undetected. The only
|
|
107
|
+
input that distinguishes them is a `Work-Item:` line sitting **above** a
|
|
108
|
+
non-trailer line, and any test of a trailer reader must pin one:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
feat: something
|
|
112
|
+
|
|
113
|
+
Work-Item: owner/repo#123
|
|
114
|
+
|
|
115
|
+
🤖 Generated with Claude Code
|
|
116
|
+
|
|
117
|
+
Co-Authored-By: Claude <noreply@anthropic.com>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Under Definition A this message has no work item. Under Definition B — the
|
|
121
|
+
authoritative one — it names exactly one. Assert **present**.
|
|
122
|
+
|
|
123
|
+
## Related
|
|
124
|
+
|
|
125
|
+
- `tracked-work` (eager) — the obligation to carry the ref on every commit
|
|
126
|
+
- `settled-decisions` — why this is recorded as closed rather than re-litigated
|
|
127
|
+
- CodySwannGT/lisa#2672 — where Definition A was tried and abandoned
|
|
128
|
+
- CodySwannGT/lisa#3747 — where the decision was made discoverable
|
|
129
|
+
- CodySwannGT/lisa#3859 — the same undercount measured on the audit side
|