@codyswann/lisa 4.48.0 → 4.50.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.
Files changed (426) hide show
  1. package/all/copy-overwrite/scripts/check-conflict-markers.mjs +4 -1
  2. package/all/copy-overwrite/scripts/lib/gate-failure-diagnosis.mjs +163 -0
  3. package/all/copy-overwrite/scripts/lisa-enforcement-fallback.sh +178 -1
  4. package/all/copy-overwrite/scripts/lisa-hooks/block-direct-issue-create.sh +89 -10
  5. package/all/copy-overwrite/scripts/lisa-hooks/parity-safety-net.sh +44 -0
  6. package/all/copy-overwrite/scripts/lisa-lint-staged-preflight.mjs +1 -1
  7. package/all/copy-overwrite/scripts/lisa-run-gates.mjs +24 -24
  8. package/all/copy-overwrite/scripts/lisa-work-item.mjs +490 -81
  9. package/cdk/package-lisa/package.lisa.json +45 -15
  10. package/dist/configs/vitest/base.d.ts +71 -1
  11. package/dist/configs/vitest/base.d.ts.map +1 -1
  12. package/dist/configs/vitest/base.js +141 -23
  13. package/dist/configs/vitest/base.js.map +1 -1
  14. package/dist/configs/vitest/fleet-admission-global-setup.d.ts +34 -0
  15. package/dist/configs/vitest/fleet-admission-global-setup.d.ts.map +1 -0
  16. package/dist/configs/vitest/fleet-admission-global-setup.js +123 -0
  17. package/dist/configs/vitest/fleet-admission-global-setup.js.map +1 -0
  18. package/dist/configs/vitest/fleet-admission.d.ts +129 -0
  19. package/dist/configs/vitest/fleet-admission.d.ts.map +1 -0
  20. package/dist/configs/vitest/fleet-admission.js +239 -0
  21. package/dist/configs/vitest/fleet-admission.js.map +1 -0
  22. package/dist/configs/vitest/synthesis-scratch-reclaim.d.ts +86 -0
  23. package/dist/configs/vitest/synthesis-scratch-reclaim.d.ts.map +1 -0
  24. package/dist/configs/vitest/synthesis-scratch-reclaim.js +226 -0
  25. package/dist/configs/vitest/synthesis-scratch-reclaim.js.map +1 -0
  26. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  27. package/dist/core/lisa-owned-hash-ledger.js +76 -0
  28. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  29. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  30. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  31. package/dist/core/upstream-evidence-manifest.js +129 -228
  32. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  33. package/dist/opencode/plugin-templates/lisa-block-direct-issue-create.ts +45 -1
  34. package/dist/opencode/plugin-templates/parity-safety-net.sh +44 -0
  35. package/expo/package-lisa/package.lisa.json +83 -53
  36. package/harper-fabric/package-lisa/package.lisa.json +62 -32
  37. package/nestjs/package-lisa/package.lisa.json +57 -27
  38. package/npm-package/package-lisa/package.lisa.json +43 -7
  39. package/package.json +11 -7
  40. package/phaser/copy-overwrite/ast-grep/rules/no-day-truncating-file-age-predicate.yml +50 -0
  41. package/phaser/package-lisa/package.lisa.json +62 -32
  42. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  44. package/plugins/lisa/.codex-plugin/skills/lisa-drive-pr-to-merge/SKILL.md +17 -1
  45. package/plugins/lisa/.codex-plugin/skills/lisa-github-build-intake/SKILL.md +4 -0
  46. package/plugins/lisa/.codex-plugin/skills/lisa-jira-build-intake/SKILL.md +4 -0
  47. package/plugins/lisa/.codex-plugin/skills/lisa-linear-build-intake/SKILL.md +4 -0
  48. package/plugins/lisa/.codex-plugin/skills/lisa-repair-intake/SKILL.md +4 -1
  49. package/plugins/lisa/hooks/block-direct-issue-create.sh +89 -10
  50. package/plugins/lisa/hooks/discharge-work-item-gates.sh +7 -1
  51. package/plugins/lisa/hooks/parity-safety-net.sh +44 -0
  52. package/plugins/lisa/hooks/threshold-ratchet-families.mjs +12 -0
  53. package/plugins/lisa/rules/eager/00-rule-index.md +79 -0
  54. package/plugins/lisa/rules/eager/base-rules.md +10 -0
  55. package/plugins/lisa/rules/eager/config-resolution.md +1 -88
  56. package/plugins/lisa/rules/reference/automation-runbook-contract.md +97 -0
  57. package/plugins/lisa/rules/reference/bdd-e2e-coverage.md +56 -0
  58. package/plugins/lisa/rules/reference/blocker-containment.md +58 -0
  59. package/plugins/lisa/rules/reference/claim-archaeology.md +42 -0
  60. package/plugins/lisa/rules/reference/claim-evidence-mapping.md +83 -0
  61. package/plugins/lisa/rules/reference/claim-time-guards.md +37 -0
  62. package/plugins/lisa/rules/reference/config-resolution.md +97 -0
  63. package/plugins/lisa/rules/reference/control-reachability.md +44 -0
  64. package/plugins/lisa/rules/reference/convergent-review.md +31 -0
  65. package/plugins/lisa/rules/reference/credential-substrate-precedence.md +57 -0
  66. package/plugins/lisa/rules/reference/dependency-decision-records.md +37 -0
  67. package/plugins/lisa/rules/reference/dependency-internalization-kit.md +47 -0
  68. package/plugins/lisa/rules/reference/dependency-trust-classes.md +48 -0
  69. package/plugins/lisa/rules/reference/deployed-state-readback.md +52 -0
  70. package/plugins/lisa/rules/reference/derived-branch-plan.md +52 -0
  71. package/plugins/lisa/rules/reference/design-source-of-truth.md +43 -0
  72. package/plugins/lisa/rules/reference/design-value-binding.md +103 -0
  73. package/plugins/lisa/rules/reference/documentation-source-paths.md +18 -0
  74. package/plugins/lisa/rules/reference/leaf-only-lifecycle.md +75 -0
  75. package/plugins/lisa/rules/reference/observability-audit.md +20 -0
  76. package/plugins/lisa/rules/reference/prd-definition-of-ready.md +37 -0
  77. package/plugins/lisa/rules/reference/prd-lifecycle-rollup.md +36 -0
  78. package/plugins/lisa/rules/reference/pre-flight-autofill.md +88 -0
  79. package/plugins/lisa/rules/reference/promotion-contract.md +21 -0
  80. package/plugins/lisa/rules/reference/readiness-rubric.md +63 -0
  81. package/plugins/lisa/rules/reference/ready-role-filing.md +34 -0
  82. package/plugins/lisa/rules/reference/rejection-detection.md +69 -0
  83. package/plugins/lisa/rules/reference/repo-scope-split.md +48 -0
  84. package/plugins/lisa/rules/reference/reset-seed-coverage.md +55 -0
  85. package/plugins/lisa/rules/reference/usage-accounting.md +38 -0
  86. package/plugins/lisa/rules/reference/work-item-definition-of-ready.md +32 -0
  87. package/plugins/lisa/scripts/intake-blocker-reprobe.mjs +158 -1
  88. package/plugins/lisa/skills/lisa-drive-pr-to-merge/SKILL.md +17 -1
  89. package/plugins/lisa/skills/lisa-github-build-intake/SKILL.md +4 -0
  90. package/plugins/lisa/skills/lisa-jira-build-intake/SKILL.md +4 -0
  91. package/plugins/lisa/skills/lisa-linear-build-intake/SKILL.md +4 -0
  92. package/plugins/lisa/skills/lisa-repair-intake/SKILL.md +4 -1
  93. package/plugins/lisa-agy/hooks/block-direct-issue-create.sh +89 -10
  94. package/plugins/lisa-agy/hooks/parity-safety-net.sh +44 -0
  95. package/plugins/lisa-agy/plugin.json +1 -1
  96. package/plugins/lisa-agy/scripts/intake-blocker-reprobe.mjs +158 -1
  97. package/plugins/lisa-agy/skills/lisa-drive-pr-to-merge/SKILL.md +17 -1
  98. package/plugins/lisa-agy/skills/lisa-github-build-intake/SKILL.md +4 -0
  99. package/plugins/lisa-agy/skills/lisa-jira-build-intake/SKILL.md +4 -0
  100. package/plugins/lisa-agy/skills/lisa-linear-build-intake/SKILL.md +4 -0
  101. package/plugins/lisa-agy/skills/lisa-repair-intake/SKILL.md +4 -1
  102. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  103. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  104. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  105. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  106. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  107. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  108. package/plugins/lisa-copilot/hooks/block-direct-issue-create.sh +89 -10
  109. package/plugins/lisa-copilot/hooks/discharge-work-item-gates.sh +7 -1
  110. package/plugins/lisa-copilot/hooks/parity-safety-net.sh +44 -0
  111. package/plugins/lisa-copilot/hooks/threshold-ratchet-families.mjs +12 -0
  112. package/plugins/lisa-copilot/rules/eager/00-rule-index.md +79 -0
  113. package/plugins/lisa-copilot/rules/eager/base-rules.md +10 -0
  114. package/plugins/lisa-copilot/rules/eager/config-resolution.md +1 -88
  115. package/plugins/lisa-copilot/rules/reference/automation-runbook-contract.md +97 -0
  116. package/plugins/lisa-copilot/rules/reference/bdd-e2e-coverage.md +56 -0
  117. package/plugins/lisa-copilot/rules/reference/blocker-containment.md +58 -0
  118. package/plugins/lisa-copilot/rules/reference/claim-archaeology.md +42 -0
  119. package/plugins/lisa-copilot/rules/reference/claim-evidence-mapping.md +83 -0
  120. package/plugins/lisa-copilot/rules/reference/claim-time-guards.md +37 -0
  121. package/plugins/lisa-copilot/rules/reference/config-resolution.md +97 -0
  122. package/plugins/lisa-copilot/rules/reference/control-reachability.md +44 -0
  123. package/plugins/lisa-copilot/rules/reference/convergent-review.md +31 -0
  124. package/plugins/lisa-copilot/rules/reference/credential-substrate-precedence.md +57 -0
  125. package/plugins/lisa-copilot/rules/reference/dependency-decision-records.md +37 -0
  126. package/plugins/lisa-copilot/rules/reference/dependency-internalization-kit.md +47 -0
  127. package/plugins/lisa-copilot/rules/reference/dependency-trust-classes.md +48 -0
  128. package/plugins/lisa-copilot/rules/reference/deployed-state-readback.md +52 -0
  129. package/plugins/lisa-copilot/rules/reference/derived-branch-plan.md +52 -0
  130. package/plugins/lisa-copilot/rules/reference/design-source-of-truth.md +43 -0
  131. package/plugins/lisa-copilot/rules/reference/design-value-binding.md +103 -0
  132. package/plugins/lisa-copilot/rules/reference/documentation-source-paths.md +18 -0
  133. package/plugins/lisa-copilot/rules/reference/leaf-only-lifecycle.md +75 -0
  134. package/plugins/lisa-copilot/rules/reference/observability-audit.md +20 -0
  135. package/plugins/lisa-copilot/rules/reference/prd-definition-of-ready.md +37 -0
  136. package/plugins/lisa-copilot/rules/reference/prd-lifecycle-rollup.md +36 -0
  137. package/plugins/lisa-copilot/rules/reference/pre-flight-autofill.md +88 -0
  138. package/plugins/lisa-copilot/rules/reference/promotion-contract.md +21 -0
  139. package/plugins/lisa-copilot/rules/reference/readiness-rubric.md +63 -0
  140. package/plugins/lisa-copilot/rules/reference/ready-role-filing.md +34 -0
  141. package/plugins/lisa-copilot/rules/reference/rejection-detection.md +69 -0
  142. package/plugins/lisa-copilot/rules/reference/repo-scope-split.md +48 -0
  143. package/plugins/lisa-copilot/rules/reference/reset-seed-coverage.md +55 -0
  144. package/plugins/lisa-copilot/rules/reference/usage-accounting.md +38 -0
  145. package/plugins/lisa-copilot/rules/reference/work-item-definition-of-ready.md +32 -0
  146. package/plugins/lisa-copilot/scripts/intake-blocker-reprobe.mjs +158 -1
  147. package/plugins/lisa-copilot/skills/lisa-drive-pr-to-merge/SKILL.md +17 -1
  148. package/plugins/lisa-copilot/skills/lisa-github-build-intake/SKILL.md +4 -0
  149. package/plugins/lisa-copilot/skills/lisa-jira-build-intake/SKILL.md +4 -0
  150. package/plugins/lisa-copilot/skills/lisa-linear-build-intake/SKILL.md +4 -0
  151. package/plugins/lisa-copilot/skills/lisa-repair-intake/SKILL.md +4 -1
  152. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  153. package/plugins/lisa-cursor/hooks/block-direct-issue-create.sh +89 -10
  154. package/plugins/lisa-cursor/hooks/discharge-work-item-gates.sh +7 -1
  155. package/plugins/lisa-cursor/hooks/parity-safety-net.sh +44 -0
  156. package/plugins/lisa-cursor/hooks/threshold-ratchet-families.mjs +12 -0
  157. package/plugins/lisa-cursor/rules/00-rule-index.mdc +84 -0
  158. package/plugins/lisa-cursor/rules/automation-runbook-contract-reference.mdc +97 -0
  159. package/plugins/lisa-cursor/rules/base-rules.mdc +10 -0
  160. package/plugins/lisa-cursor/rules/bdd-e2e-coverage-reference.mdc +56 -0
  161. package/plugins/lisa-cursor/rules/blocker-containment-reference.mdc +58 -0
  162. package/plugins/lisa-cursor/rules/claim-archaeology-reference.mdc +42 -0
  163. package/plugins/lisa-cursor/rules/claim-evidence-mapping-reference.mdc +83 -0
  164. package/plugins/lisa-cursor/rules/claim-time-guards-reference.mdc +37 -0
  165. package/plugins/lisa-cursor/rules/config-resolution-reference.mdc +97 -0
  166. package/plugins/lisa-cursor/rules/config-resolution.mdc +1 -88
  167. package/plugins/lisa-cursor/rules/control-reachability-reference.mdc +44 -0
  168. package/plugins/lisa-cursor/rules/convergent-review-reference.mdc +31 -0
  169. package/plugins/lisa-cursor/rules/credential-substrate-precedence-reference.mdc +57 -0
  170. package/plugins/lisa-cursor/rules/dependency-decision-records-reference.mdc +37 -0
  171. package/plugins/lisa-cursor/rules/dependency-internalization-kit-reference.mdc +47 -0
  172. package/plugins/lisa-cursor/rules/dependency-trust-classes-reference.mdc +48 -0
  173. package/plugins/lisa-cursor/rules/deployed-state-readback-reference.mdc +52 -0
  174. package/plugins/lisa-cursor/rules/derived-branch-plan-reference.mdc +52 -0
  175. package/plugins/lisa-cursor/rules/design-source-of-truth-reference.mdc +43 -0
  176. package/plugins/lisa-cursor/rules/design-value-binding-reference.mdc +103 -0
  177. package/plugins/lisa-cursor/rules/documentation-source-paths-reference.mdc +18 -0
  178. package/plugins/lisa-cursor/rules/leaf-only-lifecycle-reference.mdc +75 -0
  179. package/plugins/lisa-cursor/rules/observability-audit-reference.mdc +20 -0
  180. package/plugins/lisa-cursor/rules/prd-definition-of-ready-reference.mdc +37 -0
  181. package/plugins/lisa-cursor/rules/prd-lifecycle-rollup-reference.mdc +36 -0
  182. package/plugins/lisa-cursor/rules/pre-flight-autofill-reference.mdc +88 -0
  183. package/plugins/lisa-cursor/rules/promotion-contract-reference.mdc +21 -0
  184. package/plugins/lisa-cursor/rules/readiness-rubric-reference.mdc +63 -0
  185. package/plugins/lisa-cursor/rules/ready-role-filing-reference.mdc +34 -0
  186. package/plugins/lisa-cursor/rules/rejection-detection-reference.mdc +69 -0
  187. package/plugins/lisa-cursor/rules/repo-scope-split-reference.mdc +48 -0
  188. package/plugins/lisa-cursor/rules/reset-seed-coverage-reference.mdc +55 -0
  189. package/plugins/lisa-cursor/rules/usage-accounting-reference.mdc +38 -0
  190. package/plugins/lisa-cursor/rules/work-item-definition-of-ready-reference.mdc +32 -0
  191. package/plugins/lisa-cursor/scripts/intake-blocker-reprobe.mjs +158 -1
  192. package/plugins/lisa-cursor/skills/lisa-drive-pr-to-merge/SKILL.md +17 -1
  193. package/plugins/lisa-cursor/skills/lisa-github-build-intake/SKILL.md +4 -0
  194. package/plugins/lisa-cursor/skills/lisa-jira-build-intake/SKILL.md +4 -0
  195. package/plugins/lisa-cursor/skills/lisa-linear-build-intake/SKILL.md +4 -0
  196. package/plugins/lisa-cursor/skills/lisa-repair-intake/SKILL.md +4 -1
  197. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  198. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  199. package/plugins/lisa-expo-agy/plugin.json +1 -1
  200. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  201. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  202. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  203. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  204. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  205. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  206. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  207. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  208. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  209. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  210. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  211. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  212. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  213. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  214. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  215. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  216. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  217. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  218. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  219. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  220. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  221. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  222. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  223. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  224. package/plugins/lisa-rails-agy/plugin.json +1 -1
  225. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  226. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  227. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  228. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  229. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  230. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  231. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  232. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  233. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  234. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  235. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  236. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  237. package/plugins/src/base/hooks/block-direct-issue-create.sh +89 -10
  238. package/plugins/src/base/hooks/discharge-work-item-gates.sh +7 -1
  239. package/plugins/src/base/hooks/parity-safety-net.sh +44 -0
  240. package/plugins/src/base/hooks/threshold-ratchet-families.mjs +12 -0
  241. package/plugins/src/base/rules/eager/00-rule-index.md +79 -0
  242. package/plugins/src/base/rules/eager/base-rules.md +10 -0
  243. package/plugins/src/base/rules/eager/config-resolution.md +1 -88
  244. package/plugins/src/base/rules/reference/automation-runbook-contract.md +97 -0
  245. package/plugins/src/base/rules/reference/bdd-e2e-coverage.md +56 -0
  246. package/plugins/src/base/rules/reference/blocker-containment.md +58 -0
  247. package/plugins/src/base/rules/reference/claim-archaeology.md +42 -0
  248. package/plugins/src/base/rules/reference/claim-evidence-mapping.md +83 -0
  249. package/plugins/src/base/rules/reference/claim-time-guards.md +37 -0
  250. package/plugins/src/base/rules/reference/config-resolution.md +97 -0
  251. package/plugins/src/base/rules/reference/control-reachability.md +44 -0
  252. package/plugins/src/base/rules/reference/convergent-review.md +31 -0
  253. package/plugins/src/base/rules/reference/credential-substrate-precedence.md +57 -0
  254. package/plugins/src/base/rules/reference/dependency-decision-records.md +37 -0
  255. package/plugins/src/base/rules/reference/dependency-internalization-kit.md +47 -0
  256. package/plugins/src/base/rules/reference/dependency-trust-classes.md +48 -0
  257. package/plugins/src/base/rules/reference/deployed-state-readback.md +52 -0
  258. package/plugins/src/base/rules/reference/derived-branch-plan.md +52 -0
  259. package/plugins/src/base/rules/reference/design-source-of-truth.md +43 -0
  260. package/plugins/src/base/rules/reference/design-value-binding.md +103 -0
  261. package/plugins/src/base/rules/reference/documentation-source-paths.md +18 -0
  262. package/plugins/src/base/rules/reference/leaf-only-lifecycle.md +75 -0
  263. package/plugins/src/base/rules/reference/observability-audit.md +20 -0
  264. package/plugins/src/base/rules/reference/prd-definition-of-ready.md +37 -0
  265. package/plugins/src/base/rules/reference/prd-lifecycle-rollup.md +36 -0
  266. package/plugins/src/base/rules/reference/pre-flight-autofill.md +88 -0
  267. package/plugins/src/base/rules/reference/promotion-contract.md +21 -0
  268. package/plugins/src/base/rules/reference/readiness-rubric.md +63 -0
  269. package/plugins/src/base/rules/reference/ready-role-filing.md +34 -0
  270. package/plugins/src/base/rules/reference/rejection-detection.md +69 -0
  271. package/plugins/src/base/rules/reference/repo-scope-split.md +48 -0
  272. package/plugins/src/base/rules/reference/reset-seed-coverage.md +55 -0
  273. package/plugins/src/base/rules/reference/usage-accounting.md +38 -0
  274. package/plugins/src/base/rules/reference/work-item-definition-of-ready.md +32 -0
  275. package/plugins/src/base/scripts/intake-blocker-reprobe.mjs +158 -1
  276. package/plugins/src/base/skills/lisa-drive-pr-to-merge/SKILL.md +17 -1
  277. package/plugins/src/base/skills/lisa-github-build-intake/SKILL.md +4 -0
  278. package/plugins/src/base/skills/lisa-jira-build-intake/SKILL.md +4 -0
  279. package/plugins/src/base/skills/lisa-linear-build-intake/SKILL.md +4 -0
  280. package/plugins/src/base/skills/lisa-repair-intake/SKILL.md +4 -1
  281. package/rails/copy-overwrite/ast-grep/rules/no-day-truncating-file-age-predicate.yml +50 -0
  282. package/rails/copy-overwrite/scripts/threshold-ratchet-families.mjs +12 -0
  283. package/scripts/check-eager-rule-budget.mjs +176 -0
  284. package/scripts/check-generated-artifact-merge-coverage.mjs +7 -0
  285. package/scripts/check-rules-pairing.sh +45 -14
  286. package/scripts/check-shipped-surface-removals.mjs +851 -0
  287. package/scripts/cleanup-worktrees.sh +69 -16
  288. package/scripts/generate-export-surface.mjs +318 -0
  289. package/scripts/lib/shipped-surface.mjs +212 -0
  290. package/scripts/lisa-enforcement-fallback.sh +178 -1
  291. package/scripts/remedy-conformance.mjs +435 -0
  292. package/scripts/two-channel-couplings.json +2 -2
  293. package/typescript/copy-contents/.husky/pre-push +147 -2
  294. package/typescript/copy-overwrite/ast-grep/rules/no-day-truncating-file-age-predicate.yml +50 -0
  295. package/typescript/copy-overwrite/audit.ignore.config.json +0 -10
  296. package/typescript/copy-overwrite/scripts/lisa-mutation.mjs +180 -29
  297. package/typescript/copy-overwrite/scripts/threshold-ratchet-families.mjs +12 -0
  298. package/typescript/package-lisa/package.lisa.json +72 -42
  299. package/plugins/lisa/rules/eager/automation-runbook-contract.md +0 -92
  300. package/plugins/lisa/rules/eager/bdd-e2e-coverage.md +0 -51
  301. package/plugins/lisa/rules/eager/blocker-containment.md +0 -53
  302. package/plugins/lisa/rules/eager/claim-archaeology.md +0 -37
  303. package/plugins/lisa/rules/eager/claim-evidence-mapping.md +0 -78
  304. package/plugins/lisa/rules/eager/claim-time-guards.md +0 -32
  305. package/plugins/lisa/rules/eager/control-reachability.md +0 -39
  306. package/plugins/lisa/rules/eager/convergent-review.md +0 -24
  307. package/plugins/lisa/rules/eager/credential-substrate-precedence.md +0 -54
  308. package/plugins/lisa/rules/eager/dependency-decision-records.md +0 -32
  309. package/plugins/lisa/rules/eager/dependency-internalization-kit.md +0 -42
  310. package/plugins/lisa/rules/eager/dependency-trust-classes.md +0 -43
  311. package/plugins/lisa/rules/eager/deployed-state-readback.md +0 -47
  312. package/plugins/lisa/rules/eager/derived-branch-plan.md +0 -47
  313. package/plugins/lisa/rules/eager/design-source-of-truth.md +0 -38
  314. package/plugins/lisa/rules/eager/design-value-binding.md +0 -98
  315. package/plugins/lisa/rules/eager/documentation-source-paths.md +0 -13
  316. package/plugins/lisa/rules/eager/factory-model.md +0 -41
  317. package/plugins/lisa/rules/eager/leaf-only-lifecycle.md +0 -70
  318. package/plugins/lisa/rules/eager/observability-audit.md +0 -15
  319. package/plugins/lisa/rules/eager/prd-definition-of-ready.md +0 -32
  320. package/plugins/lisa/rules/eager/prd-lifecycle-rollup.md +0 -31
  321. package/plugins/lisa/rules/eager/pre-flight-autofill.md +0 -84
  322. package/plugins/lisa/rules/eager/project-learnings.md +0 -22
  323. package/plugins/lisa/rules/eager/promotion-contract.md +0 -18
  324. package/plugins/lisa/rules/eager/readiness-rubric.md +0 -58
  325. package/plugins/lisa/rules/eager/ready-role-filing.md +0 -29
  326. package/plugins/lisa/rules/eager/rejection-detection.md +0 -64
  327. package/plugins/lisa/rules/eager/repo-scope-split.md +0 -43
  328. package/plugins/lisa/rules/eager/reset-seed-coverage.md +0 -50
  329. package/plugins/lisa/rules/eager/usage-accounting.md +0 -33
  330. package/plugins/lisa/rules/eager/work-item-definition-of-ready.md +0 -27
  331. package/plugins/lisa-copilot/rules/eager/automation-runbook-contract.md +0 -92
  332. package/plugins/lisa-copilot/rules/eager/bdd-e2e-coverage.md +0 -51
  333. package/plugins/lisa-copilot/rules/eager/blocker-containment.md +0 -53
  334. package/plugins/lisa-copilot/rules/eager/claim-archaeology.md +0 -37
  335. package/plugins/lisa-copilot/rules/eager/claim-evidence-mapping.md +0 -78
  336. package/plugins/lisa-copilot/rules/eager/claim-time-guards.md +0 -32
  337. package/plugins/lisa-copilot/rules/eager/control-reachability.md +0 -39
  338. package/plugins/lisa-copilot/rules/eager/convergent-review.md +0 -24
  339. package/plugins/lisa-copilot/rules/eager/credential-substrate-precedence.md +0 -54
  340. package/plugins/lisa-copilot/rules/eager/dependency-decision-records.md +0 -32
  341. package/plugins/lisa-copilot/rules/eager/dependency-internalization-kit.md +0 -42
  342. package/plugins/lisa-copilot/rules/eager/dependency-trust-classes.md +0 -43
  343. package/plugins/lisa-copilot/rules/eager/deployed-state-readback.md +0 -47
  344. package/plugins/lisa-copilot/rules/eager/derived-branch-plan.md +0 -47
  345. package/plugins/lisa-copilot/rules/eager/design-source-of-truth.md +0 -38
  346. package/plugins/lisa-copilot/rules/eager/design-value-binding.md +0 -98
  347. package/plugins/lisa-copilot/rules/eager/documentation-source-paths.md +0 -13
  348. package/plugins/lisa-copilot/rules/eager/factory-model.md +0 -41
  349. package/plugins/lisa-copilot/rules/eager/leaf-only-lifecycle.md +0 -70
  350. package/plugins/lisa-copilot/rules/eager/observability-audit.md +0 -15
  351. package/plugins/lisa-copilot/rules/eager/prd-definition-of-ready.md +0 -32
  352. package/plugins/lisa-copilot/rules/eager/prd-lifecycle-rollup.md +0 -31
  353. package/plugins/lisa-copilot/rules/eager/pre-flight-autofill.md +0 -84
  354. package/plugins/lisa-copilot/rules/eager/project-learnings.md +0 -22
  355. package/plugins/lisa-copilot/rules/eager/promotion-contract.md +0 -18
  356. package/plugins/lisa-copilot/rules/eager/readiness-rubric.md +0 -58
  357. package/plugins/lisa-copilot/rules/eager/ready-role-filing.md +0 -29
  358. package/plugins/lisa-copilot/rules/eager/rejection-detection.md +0 -64
  359. package/plugins/lisa-copilot/rules/eager/repo-scope-split.md +0 -43
  360. package/plugins/lisa-copilot/rules/eager/reset-seed-coverage.md +0 -50
  361. package/plugins/lisa-copilot/rules/eager/usage-accounting.md +0 -33
  362. package/plugins/lisa-copilot/rules/eager/work-item-definition-of-ready.md +0 -27
  363. package/plugins/lisa-cursor/rules/automation-runbook-contract.mdc +0 -97
  364. package/plugins/lisa-cursor/rules/bdd-e2e-coverage.mdc +0 -56
  365. package/plugins/lisa-cursor/rules/blocker-containment.mdc +0 -58
  366. package/plugins/lisa-cursor/rules/claim-archaeology.mdc +0 -42
  367. package/plugins/lisa-cursor/rules/claim-evidence-mapping.mdc +0 -83
  368. package/plugins/lisa-cursor/rules/claim-time-guards.mdc +0 -37
  369. package/plugins/lisa-cursor/rules/control-reachability.mdc +0 -44
  370. package/plugins/lisa-cursor/rules/convergent-review.mdc +0 -29
  371. package/plugins/lisa-cursor/rules/credential-substrate-precedence.mdc +0 -59
  372. package/plugins/lisa-cursor/rules/dependency-decision-records.mdc +0 -37
  373. package/plugins/lisa-cursor/rules/dependency-internalization-kit.mdc +0 -47
  374. package/plugins/lisa-cursor/rules/dependency-trust-classes.mdc +0 -48
  375. package/plugins/lisa-cursor/rules/deployed-state-readback.mdc +0 -52
  376. package/plugins/lisa-cursor/rules/derived-branch-plan.mdc +0 -52
  377. package/plugins/lisa-cursor/rules/design-source-of-truth.mdc +0 -43
  378. package/plugins/lisa-cursor/rules/design-value-binding.mdc +0 -103
  379. package/plugins/lisa-cursor/rules/documentation-source-paths.mdc +0 -18
  380. package/plugins/lisa-cursor/rules/factory-model.mdc +0 -46
  381. package/plugins/lisa-cursor/rules/leaf-only-lifecycle.mdc +0 -75
  382. package/plugins/lisa-cursor/rules/observability-audit.mdc +0 -20
  383. package/plugins/lisa-cursor/rules/prd-definition-of-ready.mdc +0 -37
  384. package/plugins/lisa-cursor/rules/prd-lifecycle-rollup.mdc +0 -36
  385. package/plugins/lisa-cursor/rules/pre-flight-autofill.mdc +0 -89
  386. package/plugins/lisa-cursor/rules/project-learnings.mdc +0 -27
  387. package/plugins/lisa-cursor/rules/promotion-contract.mdc +0 -23
  388. package/plugins/lisa-cursor/rules/readiness-rubric.mdc +0 -63
  389. package/plugins/lisa-cursor/rules/ready-role-filing.mdc +0 -34
  390. package/plugins/lisa-cursor/rules/rejection-detection.mdc +0 -69
  391. package/plugins/lisa-cursor/rules/repo-scope-split.mdc +0 -48
  392. package/plugins/lisa-cursor/rules/reset-seed-coverage.mdc +0 -55
  393. package/plugins/lisa-cursor/rules/usage-accounting.mdc +0 -38
  394. package/plugins/lisa-cursor/rules/work-item-definition-of-ready.mdc +0 -32
  395. package/plugins/src/base/rules/eager/automation-runbook-contract.md +0 -92
  396. package/plugins/src/base/rules/eager/bdd-e2e-coverage.md +0 -51
  397. package/plugins/src/base/rules/eager/blocker-containment.md +0 -53
  398. package/plugins/src/base/rules/eager/claim-archaeology.md +0 -37
  399. package/plugins/src/base/rules/eager/claim-evidence-mapping.md +0 -78
  400. package/plugins/src/base/rules/eager/claim-time-guards.md +0 -32
  401. package/plugins/src/base/rules/eager/control-reachability.md +0 -39
  402. package/plugins/src/base/rules/eager/convergent-review.md +0 -24
  403. package/plugins/src/base/rules/eager/credential-substrate-precedence.md +0 -54
  404. package/plugins/src/base/rules/eager/dependency-decision-records.md +0 -32
  405. package/plugins/src/base/rules/eager/dependency-internalization-kit.md +0 -42
  406. package/plugins/src/base/rules/eager/dependency-trust-classes.md +0 -43
  407. package/plugins/src/base/rules/eager/deployed-state-readback.md +0 -47
  408. package/plugins/src/base/rules/eager/derived-branch-plan.md +0 -47
  409. package/plugins/src/base/rules/eager/design-source-of-truth.md +0 -38
  410. package/plugins/src/base/rules/eager/design-value-binding.md +0 -98
  411. package/plugins/src/base/rules/eager/documentation-source-paths.md +0 -13
  412. package/plugins/src/base/rules/eager/factory-model.md +0 -41
  413. package/plugins/src/base/rules/eager/leaf-only-lifecycle.md +0 -70
  414. package/plugins/src/base/rules/eager/observability-audit.md +0 -15
  415. package/plugins/src/base/rules/eager/prd-definition-of-ready.md +0 -32
  416. package/plugins/src/base/rules/eager/prd-lifecycle-rollup.md +0 -31
  417. package/plugins/src/base/rules/eager/pre-flight-autofill.md +0 -84
  418. package/plugins/src/base/rules/eager/project-learnings.md +0 -22
  419. package/plugins/src/base/rules/eager/promotion-contract.md +0 -18
  420. package/plugins/src/base/rules/eager/readiness-rubric.md +0 -58
  421. package/plugins/src/base/rules/eager/ready-role-filing.md +0 -29
  422. package/plugins/src/base/rules/eager/rejection-detection.md +0 -64
  423. package/plugins/src/base/rules/eager/repo-scope-split.md +0 -43
  424. package/plugins/src/base/rules/eager/reset-seed-coverage.md +0 -50
  425. package/plugins/src/base/rules/eager/usage-accounting.md +0 -33
  426. 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
- trap 'rm -f "$LISA_GATE_COVERAGE"' EXIT
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 u=s["test:cov:unit"];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
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
- const target = env.GITHUB_OUTPUT;
229
- if (target === undefined || target === "") return code;
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
- * Two arms reach this with nothing to name, and `0` would be a fabrication in
1139
- * both: a project that declared no `thresholds.break` has not asked for a floor
1140
- * (see {@link resolveBreakThreshold}, which returns null and not zero for
1141
- * exactly this reason), and a run whose tally produced no score has nothing to
1142
- * judge against the floor it did declare. Both say NO floor was applied, which
1143
- * is the same answer this gate's `nothing-to-mutate` and `no-diff-base` exits
1144
- * already give: nothing was measured, so nothing passed.
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
- * Two verdicts, and neither can turn a red run green — both are checks the gate
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}} tally - The counts.
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 a tally was read, and whether it fails.
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$/,