@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.
Files changed (578) hide show
  1. package/all/copy-contents/.gitattributes +8 -0
  2. package/all/copy-overwrite/scripts/check-orphaned-branches.mjs +78 -9
  3. package/all/copy-overwrite/scripts/check-third-party-action-pins.mjs +17 -1
  4. package/all/copy-overwrite/scripts/lib/process-tree-runner.mjs +194 -7
  5. package/all/copy-overwrite/scripts/lisa-enforcement-fallback.sh +31 -0
  6. package/all/copy-overwrite/scripts/lisa-hooks/block-blind-automerge.sh +81 -2
  7. package/all/copy-overwrite/scripts/lisa-hooks/block-direct-issue-create.sh +293 -8
  8. package/all/copy-overwrite/scripts/lisa-hooks/block-instruction-file-edits.sh +21 -0
  9. package/all/copy-overwrite/scripts/lisa-hooks/block-managed-file-edits.sh +78 -15
  10. package/all/copy-overwrite/scripts/lisa-hooks/block-no-verify.sh +21 -0
  11. package/all/copy-overwrite/scripts/lisa-hooks/block-shell-json-parsing.sh +21 -0
  12. package/all/copy-overwrite/scripts/lisa-hooks/guard-dedupe.bash +340 -0
  13. package/all/copy-overwrite/scripts/lisa-hooks/parity-safety-net.sh +29 -1
  14. package/all/copy-overwrite/scripts/lisa-hooks/worktree-binding-guard.mjs +183 -1
  15. package/all/copy-overwrite/scripts/lisa-hooks/worktree-binding-guard.sh +21 -0
  16. package/all/copy-overwrite/scripts/lisa-postinstall.mjs +21 -1
  17. package/all/copy-overwrite/scripts/lisa-run-gates.mjs +100 -5
  18. package/all/copy-overwrite/scripts/lisa-work-item.mjs +1085 -80
  19. package/all/create-only/.github/workflows/continuous-gates.yml +7 -0
  20. package/cdk/create-only/.github/workflows/ci.yml +7 -0
  21. package/cdk/create-only/.github/workflows/deploy.yml +21 -0
  22. package/dist/cli/apply.d.ts.map +1 -1
  23. package/dist/cli/apply.js +9 -1
  24. package/dist/cli/apply.js.map +1 -1
  25. package/dist/cli/doctor-apply-deletions.d.ts +61 -0
  26. package/dist/cli/doctor-apply-deletions.d.ts.map +1 -0
  27. package/dist/cli/doctor-apply-deletions.js +137 -0
  28. package/dist/cli/doctor-apply-deletions.js.map +1 -0
  29. package/dist/cli/doctor-cdk-preset-adoption.d.ts +15 -0
  30. package/dist/cli/doctor-cdk-preset-adoption.d.ts.map +1 -0
  31. package/dist/cli/doctor-cdk-preset-adoption.js +316 -0
  32. package/dist/cli/doctor-cdk-preset-adoption.js.map +1 -0
  33. package/dist/cli/doctor-config-shadowing.d.ts +22 -0
  34. package/dist/cli/doctor-config-shadowing.d.ts.map +1 -0
  35. package/dist/cli/doctor-config-shadowing.js +123 -0
  36. package/dist/cli/doctor-config-shadowing.js.map +1 -0
  37. package/dist/cli/doctor-rails-deploy-intent.d.ts +15 -0
  38. package/dist/cli/doctor-rails-deploy-intent.d.ts.map +1 -0
  39. package/dist/cli/doctor-rails-deploy-intent.js +197 -0
  40. package/dist/cli/doctor-rails-deploy-intent.js.map +1 -0
  41. package/dist/cli/doctor-seeded-artifacts.d.ts +12 -0
  42. package/dist/cli/doctor-seeded-artifacts.d.ts.map +1 -0
  43. package/dist/cli/doctor-seeded-artifacts.js +54 -0
  44. package/dist/cli/doctor-seeded-artifacts.js.map +1 -0
  45. package/dist/cli/doctor-stale-banner-scan.d.ts +44 -0
  46. package/dist/cli/doctor-stale-banner-scan.d.ts.map +1 -0
  47. package/dist/cli/doctor-stale-banner-scan.js +152 -0
  48. package/dist/cli/doctor-stale-banner-scan.js.map +1 -0
  49. package/dist/cli/doctor-stale-managed-banner.d.ts +19 -0
  50. package/dist/cli/doctor-stale-managed-banner.d.ts.map +1 -0
  51. package/dist/cli/doctor-stale-managed-banner.js +198 -0
  52. package/dist/cli/doctor-stale-managed-banner.js.map +1 -0
  53. package/dist/cli/doctor.d.ts.map +1 -1
  54. package/dist/cli/doctor.js +16 -0
  55. package/dist/cli/doctor.js.map +1 -1
  56. package/dist/cli/ui-detected-stacks.d.ts.map +1 -1
  57. package/dist/cli/ui-detected-stacks.js +3 -2
  58. package/dist/cli/ui-detected-stacks.js.map +1 -1
  59. package/dist/cli/update-check.d.ts.map +1 -1
  60. package/dist/cli/update-check.js +14 -0
  61. package/dist/cli/update-check.js.map +1 -1
  62. package/dist/cli/worktree-liveness.d.ts +5 -0
  63. package/dist/cli/worktree-liveness.d.ts.map +1 -1
  64. package/dist/cli/worktree-liveness.js +7 -6
  65. package/dist/cli/worktree-liveness.js.map +1 -1
  66. package/dist/cli/worktree-ownership.d.ts +13 -0
  67. package/dist/cli/worktree-ownership.d.ts.map +1 -1
  68. package/dist/cli/worktree-ownership.js +14 -0
  69. package/dist/cli/worktree-ownership.js.map +1 -1
  70. package/dist/configs/eslint/base.d.ts +34 -0
  71. package/dist/configs/eslint/base.d.ts.map +1 -1
  72. package/dist/configs/eslint/base.js +34 -0
  73. package/dist/configs/eslint/base.js.map +1 -1
  74. package/dist/core/apply-receipt.d.ts +65 -0
  75. package/dist/core/apply-receipt.d.ts.map +1 -1
  76. package/dist/core/apply-receipt.js +62 -2
  77. package/dist/core/apply-receipt.js.map +1 -1
  78. package/dist/core/cdk-preset-adoption.d.ts +136 -0
  79. package/dist/core/cdk-preset-adoption.d.ts.map +1 -0
  80. package/dist/core/cdk-preset-adoption.js +135 -0
  81. package/dist/core/cdk-preset-adoption.js.map +1 -0
  82. package/dist/core/config-shadowing.d.ts +36 -0
  83. package/dist/core/config-shadowing.d.ts.map +1 -1
  84. package/dist/core/config-shadowing.js +38 -0
  85. package/dist/core/config-shadowing.js.map +1 -1
  86. package/dist/core/config.d.ts +11 -0
  87. package/dist/core/config.d.ts.map +1 -1
  88. package/dist/core/config.js.map +1 -1
  89. package/dist/core/learnings-merge-driver.d.ts +10 -0
  90. package/dist/core/learnings-merge-driver.d.ts.map +1 -1
  91. package/dist/core/learnings-merge-driver.js +18 -0
  92. package/dist/core/learnings-merge-driver.js.map +1 -1
  93. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  94. package/dist/core/lisa-owned-hash-ledger.js +136 -0
  95. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  96. package/dist/core/lisa.d.ts.map +1 -1
  97. package/dist/core/lisa.js +9 -1
  98. package/dist/core/lisa.js.map +1 -1
  99. package/dist/core/nightly-e2e-guard-behavior-certificate.d.ts +5 -5
  100. package/dist/core/nightly-e2e-guard-behavior-certificate.js +7 -7
  101. package/dist/core/nightly-e2e-guard-behavior-certificate.js.map +1 -1
  102. package/dist/core/ownership-header.d.ts +74 -0
  103. package/dist/core/ownership-header.d.ts.map +1 -0
  104. package/dist/core/ownership-header.js +76 -0
  105. package/dist/core/ownership-header.js.map +1 -0
  106. package/dist/core/rails-deploy-production-intent.d.ts +36 -0
  107. package/dist/core/rails-deploy-production-intent.d.ts.map +1 -0
  108. package/dist/core/rails-deploy-production-intent.js +79 -0
  109. package/dist/core/rails-deploy-production-intent.js.map +1 -0
  110. package/dist/core/stale-managed-banner.d.ts +78 -0
  111. package/dist/core/stale-managed-banner.d.ts.map +1 -0
  112. package/dist/core/stale-managed-banner.js +118 -0
  113. package/dist/core/stale-managed-banner.js.map +1 -0
  114. package/dist/core/two-channel-delivery-scan.d.ts +33 -1
  115. package/dist/core/two-channel-delivery-scan.d.ts.map +1 -1
  116. package/dist/core/two-channel-delivery-scan.js +133 -6
  117. package/dist/core/two-channel-delivery-scan.js.map +1 -1
  118. package/dist/core/two-channel-delivery.d.ts +101 -4
  119. package/dist/core/two-channel-delivery.d.ts.map +1 -1
  120. package/dist/core/two-channel-delivery.js +121 -13
  121. package/dist/core/two-channel-delivery.js.map +1 -1
  122. package/dist/core/two-channel-staleness.d.ts +137 -0
  123. package/dist/core/two-channel-staleness.d.ts.map +1 -0
  124. package/dist/core/two-channel-staleness.js +268 -0
  125. package/dist/core/two-channel-staleness.js.map +1 -0
  126. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  127. package/dist/core/upstream-evidence-manifest.js +265 -121
  128. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  129. package/dist/core/workflow-deletion-ownership.d.ts +6 -24
  130. package/dist/core/workflow-deletion-ownership.d.ts.map +1 -1
  131. package/dist/core/workflow-deletion-ownership.js +22 -42
  132. package/dist/core/workflow-deletion-ownership.js.map +1 -1
  133. package/dist/detection/detectors/cdk.d.ts.map +1 -1
  134. package/dist/detection/detectors/cdk.js +2 -1
  135. package/dist/detection/detectors/cdk.js.map +1 -1
  136. package/dist/health/template-inspection.d.ts.map +1 -1
  137. package/dist/health/template-inspection.js +2 -1
  138. package/dist/health/template-inspection.js.map +1 -1
  139. package/dist/migrations/ensure-lisa-postinstall.d.ts +16 -0
  140. package/dist/migrations/ensure-lisa-postinstall.d.ts.map +1 -1
  141. package/dist/migrations/ensure-lisa-postinstall.js +16 -0
  142. package/dist/migrations/ensure-lisa-postinstall.js.map +1 -1
  143. package/dist/migrations/ensure-pinned-reusable-workflow-refs.d.ts +2 -2
  144. package/dist/migrations/ensure-pinned-reusable-workflow-refs.d.ts.map +1 -1
  145. package/dist/migrations/ensure-pinned-reusable-workflow-refs.js +98 -34
  146. package/dist/migrations/ensure-pinned-reusable-workflow-refs.js.map +1 -1
  147. package/dist/migrations/ensure-playwright-dedicated-caller.d.ts.map +1 -1
  148. package/dist/migrations/ensure-playwright-dedicated-caller.js +1 -0
  149. package/dist/migrations/ensure-playwright-dedicated-caller.js.map +1 -1
  150. package/dist/opencode/hooks-installer.d.ts.map +1 -1
  151. package/dist/opencode/hooks-installer.js +1 -0
  152. package/dist/opencode/hooks-installer.js.map +1 -1
  153. package/dist/opencode/plugin-templates/block-managed-file-edits.sh +78 -15
  154. package/dist/opencode/plugin-templates/block-no-verify.sh +21 -0
  155. package/dist/opencode/plugin-templates/guard-dedupe.bash +337 -0
  156. package/dist/opencode/plugin-templates/lisa-block-direct-issue-create.ts +242 -55
  157. package/dist/opencode/plugin-templates/parity-safety-net.sh +29 -1
  158. package/dist/strategies/package-lisa.d.ts.map +1 -1
  159. package/dist/strategies/package-lisa.js +2 -1
  160. package/dist/strategies/package-lisa.js.map +1 -1
  161. package/dist/utils/path-utils.d.ts +29 -0
  162. package/dist/utils/path-utils.d.ts.map +1 -1
  163. package/dist/utils/path-utils.js +41 -0
  164. package/dist/utils/path-utils.js.map +1 -1
  165. package/expo/create-only/.github/workflows/ci.yml +21 -0
  166. package/expo/create-only/.github/workflows/deploy.yml +28 -0
  167. package/expo/create-only/.github/workflows/maestro-e2e.yml +7 -0
  168. package/expo/create-only/.github/workflows/nightly-e2e-bypass-reaper.yml +124 -13
  169. package/expo/create-only/.github/workflows/nightly-e2e-health.yml +7 -0
  170. package/expo/create-only/.github/workflows/nightly-e2e-report.yml +7 -0
  171. package/expo/create-only/.github/workflows/nightly-e2e-tracking.yml +8 -0
  172. package/expo/create-only/.github/workflows/playwright-e2e.yml +7 -0
  173. package/harper-fabric/copy-overwrite/.github/workflows/ci.yml +7 -0
  174. package/harper-fabric/create-only/.github/workflows/deploy.yml +14 -0
  175. package/nestjs/create-only/.github/workflows/ci.yml +14 -0
  176. package/nestjs/create-only/.github/workflows/deploy.yml +28 -0
  177. package/package.json +10 -5
  178. package/phaser/copy-overwrite/.github/workflows/ci.yml +7 -0
  179. package/plugins/lisa/.claude-plugin/plugin.json +28 -1
  180. package/plugins/lisa/.codex-plugin/hooks.json +27 -0
  181. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  182. package/plugins/lisa/.codex-plugin/skills/lisa-drive-pr-to-merge/SKILL.md +130 -19
  183. package/plugins/lisa/.codex-plugin/skills/lisa-github-build-intake/SKILL.md +27 -4
  184. package/plugins/lisa/.codex-plugin/skills/lisa-github-prd-intake/SKILL.md +1 -1
  185. package/plugins/lisa/.codex-plugin/skills/lisa-github-validate-issue/SKILL.md +22 -0
  186. package/plugins/lisa/.codex-plugin/skills/lisa-github-verify/SKILL.md +14 -0
  187. package/plugins/lisa/.codex-plugin/skills/lisa-github-write-issue/SKILL.md +51 -0
  188. package/plugins/lisa/.codex-plugin/skills/lisa-intake/SKILL.md +1 -1
  189. package/plugins/lisa/.codex-plugin/skills/lisa-jira-build-intake/SKILL.md +27 -4
  190. package/plugins/lisa/.codex-plugin/skills/lisa-jira-validate-ticket/SKILL.md +22 -0
  191. package/plugins/lisa/.codex-plugin/skills/lisa-jira-verify/SKILL.md +14 -0
  192. package/plugins/lisa/.codex-plugin/skills/lisa-jira-write-ticket/SKILL.md +51 -0
  193. package/plugins/lisa/.codex-plugin/skills/lisa-linear-access/SKILL.md +55 -2
  194. package/plugins/lisa/.codex-plugin/skills/lisa-linear-build-intake/SKILL.md +27 -4
  195. package/plugins/lisa/.codex-plugin/skills/lisa-linear-prd-intake/SKILL.md +47 -30
  196. package/plugins/lisa/.codex-plugin/skills/lisa-linear-to-tracker/SKILL.md +3 -3
  197. package/plugins/lisa/.codex-plugin/skills/lisa-linear-validate-issue/SKILL.md +22 -0
  198. package/plugins/lisa/.codex-plugin/skills/lisa-linear-verify/SKILL.md +14 -0
  199. package/plugins/lisa/.codex-plugin/skills/lisa-linear-write-issue/SKILL.md +54 -3
  200. package/plugins/lisa/.codex-plugin/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
  201. package/plugins/lisa/.codex-plugin/skills/lisa-qa-clear/SKILL.md +19 -7
  202. package/plugins/lisa/.codex-plugin/skills/lisa-qa-fail/SKILL.md +28 -3
  203. package/plugins/lisa/.codex-plugin/skills/lisa-qa-queue/SKILL.md +28 -3
  204. package/plugins/lisa/.codex-plugin/skills/lisa-repair-intake/SKILL.md +94 -24
  205. package/plugins/lisa/.codex-plugin/skills/lisa-rework-triage/SKILL.md +32 -2
  206. package/plugins/lisa/.codex-plugin/skills/lisa-setup-linear/SKILL.md +4 -4
  207. package/plugins/lisa/.codex-plugin/skills/lisa-track/SKILL.md +1 -1
  208. package/plugins/lisa/.codex-plugin/skills/lisa-tracker-build-intake/SKILL.md +9 -0
  209. package/plugins/lisa/agents/linear-prd-intake.md +8 -8
  210. package/plugins/lisa/hooks/block-blind-automerge.sh +81 -2
  211. package/plugins/lisa/hooks/block-direct-issue-create.agy.sh +64 -16
  212. package/plugins/lisa/hooks/block-direct-issue-create.sh +293 -8
  213. package/plugins/lisa/hooks/block-instruction-file-edits.sh +21 -0
  214. package/plugins/lisa/hooks/block-managed-file-edits.sh +78 -15
  215. package/plugins/lisa/hooks/block-no-verify.sh +21 -0
  216. package/plugins/lisa/hooks/block-shell-json-parsing.sh +21 -0
  217. package/plugins/lisa/hooks/failure-signature-index.mjs +240 -5
  218. package/plugins/lisa/hooks/guard-dedupe.bash +337 -0
  219. package/plugins/lisa/hooks/inject-rules.sh +13 -5
  220. package/plugins/lisa/hooks/operational-hazards.mjs +736 -0
  221. package/plugins/lisa/hooks/operational-hazards.sh +28 -0
  222. package/plugins/lisa/hooks/parity-safety-net.sh +29 -1
  223. package/plugins/lisa/hooks/threshold-ratchet-compare.mjs +102 -21
  224. package/plugins/lisa/hooks/threshold-ratchet-families.mjs +130 -2
  225. package/plugins/lisa/hooks/threshold-ratchet.mjs +63 -13
  226. package/plugins/lisa/hooks/worktree-binding-guard.mjs +183 -1
  227. package/plugins/lisa/hooks/worktree-binding-guard.sh +21 -0
  228. package/plugins/lisa/rules/eager/00-rule-index.md +1 -0
  229. package/plugins/lisa/rules/eager/operational-hazards.md +50 -0
  230. package/plugins/lisa/rules/eager/tracked-work.md +1 -1
  231. package/plugins/lisa/rules/reference/config-resolution.md +1 -1
  232. package/plugins/lisa/rules/reference/leaf-only-lifecycle.md +1 -1
  233. package/plugins/lisa/rules/reference/operational-hazards.md +115 -0
  234. package/plugins/lisa/rules/reference/work-item-trailer-definition.md +129 -0
  235. package/plugins/lisa/scripts/intake-blocker-reprobe.mjs +407 -26
  236. package/plugins/lisa/scripts/qa-signal-lifecycle.mjs +507 -0
  237. package/plugins/lisa/skills/lisa-drive-pr-to-merge/SKILL.md +130 -19
  238. package/plugins/lisa/skills/lisa-github-build-intake/SKILL.md +27 -4
  239. package/plugins/lisa/skills/lisa-github-prd-intake/SKILL.md +1 -1
  240. package/plugins/lisa/skills/lisa-github-validate-issue/SKILL.md +22 -0
  241. package/plugins/lisa/skills/lisa-github-verify/SKILL.md +14 -0
  242. package/plugins/lisa/skills/lisa-github-write-issue/SKILL.md +51 -0
  243. package/plugins/lisa/skills/lisa-intake/SKILL.md +1 -1
  244. package/plugins/lisa/skills/lisa-jira-build-intake/SKILL.md +27 -4
  245. package/plugins/lisa/skills/lisa-jira-validate-ticket/SKILL.md +22 -0
  246. package/plugins/lisa/skills/lisa-jira-verify/SKILL.md +14 -0
  247. package/plugins/lisa/skills/lisa-jira-write-ticket/SKILL.md +51 -0
  248. package/plugins/lisa/skills/lisa-linear-access/SKILL.md +55 -2
  249. package/plugins/lisa/skills/lisa-linear-build-intake/SKILL.md +27 -4
  250. package/plugins/lisa/skills/lisa-linear-prd-intake/SKILL.md +48 -31
  251. package/plugins/lisa/skills/lisa-linear-to-tracker/SKILL.md +3 -3
  252. package/plugins/lisa/skills/lisa-linear-validate-issue/SKILL.md +22 -0
  253. package/plugins/lisa/skills/lisa-linear-verify/SKILL.md +14 -0
  254. package/plugins/lisa/skills/lisa-linear-write-issue/SKILL.md +54 -3
  255. package/plugins/lisa/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
  256. package/plugins/lisa/skills/lisa-qa-clear/SKILL.md +19 -7
  257. package/plugins/lisa/skills/lisa-qa-fail/SKILL.md +28 -3
  258. package/plugins/lisa/skills/lisa-qa-queue/SKILL.md +28 -3
  259. package/plugins/lisa/skills/lisa-repair-intake/SKILL.md +94 -24
  260. package/plugins/lisa/skills/lisa-rework-triage/SKILL.md +32 -2
  261. package/plugins/lisa/skills/lisa-setup-linear/SKILL.md +5 -5
  262. package/plugins/lisa/skills/lisa-track/SKILL.md +1 -1
  263. package/plugins/lisa/skills/lisa-tracker-build-intake/SKILL.md +9 -0
  264. package/plugins/lisa-agy/agents/linear-prd-intake.md +8 -8
  265. package/plugins/lisa-agy/hooks/block-blind-automerge.sh +81 -2
  266. package/plugins/lisa-agy/hooks/block-direct-issue-create.agy.sh +64 -16
  267. package/plugins/lisa-agy/hooks/block-direct-issue-create.sh +293 -8
  268. package/plugins/lisa-agy/hooks/block-instruction-file-edits.sh +21 -0
  269. package/plugins/lisa-agy/hooks/block-managed-file-edits.sh +78 -15
  270. package/plugins/lisa-agy/hooks/block-shell-json-parsing.sh +21 -0
  271. package/plugins/lisa-agy/hooks/guard-dedupe.bash +337 -0
  272. package/plugins/lisa-agy/hooks/parity-safety-net.sh +29 -1
  273. package/plugins/lisa-agy/hooks.json +1 -1
  274. package/plugins/lisa-agy/plugin.json +1 -1
  275. package/plugins/lisa-agy/scripts/intake-blocker-reprobe.mjs +407 -26
  276. package/plugins/lisa-agy/scripts/qa-signal-lifecycle.mjs +507 -0
  277. package/plugins/lisa-agy/skills/lisa-drive-pr-to-merge/SKILL.md +130 -19
  278. package/plugins/lisa-agy/skills/lisa-github-build-intake/SKILL.md +27 -4
  279. package/plugins/lisa-agy/skills/lisa-github-prd-intake/SKILL.md +1 -1
  280. package/plugins/lisa-agy/skills/lisa-github-validate-issue/SKILL.md +22 -0
  281. package/plugins/lisa-agy/skills/lisa-github-verify/SKILL.md +14 -0
  282. package/plugins/lisa-agy/skills/lisa-github-write-issue/SKILL.md +51 -0
  283. package/plugins/lisa-agy/skills/lisa-intake/SKILL.md +1 -1
  284. package/plugins/lisa-agy/skills/lisa-jira-build-intake/SKILL.md +27 -4
  285. package/plugins/lisa-agy/skills/lisa-jira-validate-ticket/SKILL.md +22 -0
  286. package/plugins/lisa-agy/skills/lisa-jira-verify/SKILL.md +14 -0
  287. package/plugins/lisa-agy/skills/lisa-jira-write-ticket/SKILL.md +51 -0
  288. package/plugins/lisa-agy/skills/lisa-linear-access/SKILL.md +55 -2
  289. package/plugins/lisa-agy/skills/lisa-linear-build-intake/SKILL.md +27 -4
  290. package/plugins/lisa-agy/skills/lisa-linear-prd-intake/SKILL.md +48 -31
  291. package/plugins/lisa-agy/skills/lisa-linear-to-tracker/SKILL.md +3 -3
  292. package/plugins/lisa-agy/skills/lisa-linear-validate-issue/SKILL.md +22 -0
  293. package/plugins/lisa-agy/skills/lisa-linear-verify/SKILL.md +14 -0
  294. package/plugins/lisa-agy/skills/lisa-linear-write-issue/SKILL.md +54 -3
  295. package/plugins/lisa-agy/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
  296. package/plugins/lisa-agy/skills/lisa-qa-clear/SKILL.md +19 -7
  297. package/plugins/lisa-agy/skills/lisa-qa-fail/SKILL.md +28 -3
  298. package/plugins/lisa-agy/skills/lisa-qa-queue/SKILL.md +28 -3
  299. package/plugins/lisa-agy/skills/lisa-repair-intake/SKILL.md +94 -24
  300. package/plugins/lisa-agy/skills/lisa-rework-triage/SKILL.md +32 -2
  301. package/plugins/lisa-agy/skills/lisa-setup-linear/SKILL.md +5 -5
  302. package/plugins/lisa-agy/skills/lisa-track/SKILL.md +1 -1
  303. package/plugins/lisa-agy/skills/lisa-tracker-build-intake/SKILL.md +9 -0
  304. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  305. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  306. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  307. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  308. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  309. package/plugins/lisa-copilot/.claude-plugin/plugin.json +19 -1
  310. package/plugins/lisa-copilot/agents/linear-prd-intake.agent.md +8 -8
  311. package/plugins/lisa-copilot/hooks/block-blind-automerge.sh +81 -2
  312. package/plugins/lisa-copilot/hooks/block-direct-issue-create.sh +293 -8
  313. package/plugins/lisa-copilot/hooks/block-instruction-file-edits.sh +21 -0
  314. package/plugins/lisa-copilot/hooks/block-managed-file-edits.sh +78 -15
  315. package/plugins/lisa-copilot/hooks/block-no-verify.sh +21 -0
  316. package/plugins/lisa-copilot/hooks/block-shell-json-parsing.sh +21 -0
  317. package/plugins/lisa-copilot/hooks/failure-signature-index.mjs +240 -5
  318. package/plugins/lisa-copilot/hooks/guard-dedupe.bash +337 -0
  319. package/plugins/lisa-copilot/hooks/inject-rules.sh +13 -5
  320. package/plugins/lisa-copilot/hooks/operational-hazards.mjs +736 -0
  321. package/plugins/lisa-copilot/hooks/operational-hazards.sh +28 -0
  322. package/plugins/lisa-copilot/hooks/parity-safety-net.sh +29 -1
  323. package/plugins/lisa-copilot/hooks/threshold-ratchet-compare.mjs +102 -21
  324. package/plugins/lisa-copilot/hooks/threshold-ratchet-families.mjs +130 -2
  325. package/plugins/lisa-copilot/hooks/threshold-ratchet.mjs +63 -13
  326. package/plugins/lisa-copilot/hooks/worktree-binding-guard.mjs +183 -1
  327. package/plugins/lisa-copilot/hooks/worktree-binding-guard.sh +21 -0
  328. package/plugins/lisa-copilot/rules/eager/00-rule-index.md +1 -0
  329. package/plugins/lisa-copilot/rules/eager/operational-hazards.md +50 -0
  330. package/plugins/lisa-copilot/rules/eager/tracked-work.md +1 -1
  331. package/plugins/lisa-copilot/rules/reference/config-resolution.md +1 -1
  332. package/plugins/lisa-copilot/rules/reference/leaf-only-lifecycle.md +1 -1
  333. package/plugins/lisa-copilot/rules/reference/operational-hazards.md +115 -0
  334. package/plugins/lisa-copilot/rules/reference/work-item-trailer-definition.md +129 -0
  335. package/plugins/lisa-copilot/scripts/intake-blocker-reprobe.mjs +407 -26
  336. package/plugins/lisa-copilot/scripts/qa-signal-lifecycle.mjs +507 -0
  337. package/plugins/lisa-copilot/skills/lisa-drive-pr-to-merge/SKILL.md +130 -19
  338. package/plugins/lisa-copilot/skills/lisa-github-build-intake/SKILL.md +27 -4
  339. package/plugins/lisa-copilot/skills/lisa-github-prd-intake/SKILL.md +1 -1
  340. package/plugins/lisa-copilot/skills/lisa-github-validate-issue/SKILL.md +22 -0
  341. package/plugins/lisa-copilot/skills/lisa-github-verify/SKILL.md +14 -0
  342. package/plugins/lisa-copilot/skills/lisa-github-write-issue/SKILL.md +51 -0
  343. package/plugins/lisa-copilot/skills/lisa-intake/SKILL.md +1 -1
  344. package/plugins/lisa-copilot/skills/lisa-jira-build-intake/SKILL.md +27 -4
  345. package/plugins/lisa-copilot/skills/lisa-jira-validate-ticket/SKILL.md +22 -0
  346. package/plugins/lisa-copilot/skills/lisa-jira-verify/SKILL.md +14 -0
  347. package/plugins/lisa-copilot/skills/lisa-jira-write-ticket/SKILL.md +51 -0
  348. package/plugins/lisa-copilot/skills/lisa-linear-access/SKILL.md +55 -2
  349. package/plugins/lisa-copilot/skills/lisa-linear-build-intake/SKILL.md +27 -4
  350. package/plugins/lisa-copilot/skills/lisa-linear-prd-intake/SKILL.md +48 -31
  351. package/plugins/lisa-copilot/skills/lisa-linear-to-tracker/SKILL.md +3 -3
  352. package/plugins/lisa-copilot/skills/lisa-linear-validate-issue/SKILL.md +22 -0
  353. package/plugins/lisa-copilot/skills/lisa-linear-verify/SKILL.md +14 -0
  354. package/plugins/lisa-copilot/skills/lisa-linear-write-issue/SKILL.md +54 -3
  355. package/plugins/lisa-copilot/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
  356. package/plugins/lisa-copilot/skills/lisa-qa-clear/SKILL.md +19 -7
  357. package/plugins/lisa-copilot/skills/lisa-qa-fail/SKILL.md +28 -3
  358. package/plugins/lisa-copilot/skills/lisa-qa-queue/SKILL.md +28 -3
  359. package/plugins/lisa-copilot/skills/lisa-repair-intake/SKILL.md +94 -24
  360. package/plugins/lisa-copilot/skills/lisa-rework-triage/SKILL.md +32 -2
  361. package/plugins/lisa-copilot/skills/lisa-setup-linear/SKILL.md +5 -5
  362. package/plugins/lisa-copilot/skills/lisa-track/SKILL.md +1 -1
  363. package/plugins/lisa-copilot/skills/lisa-tracker-build-intake/SKILL.md +9 -0
  364. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  365. package/plugins/lisa-cursor/agents/linear-prd-intake.md +8 -8
  366. package/plugins/lisa-cursor/hooks/block-blind-automerge.sh +81 -2
  367. package/plugins/lisa-cursor/hooks/block-direct-issue-create.sh +293 -8
  368. package/plugins/lisa-cursor/hooks/block-instruction-file-edits.sh +21 -0
  369. package/plugins/lisa-cursor/hooks/block-managed-file-edits.sh +78 -15
  370. package/plugins/lisa-cursor/hooks/block-no-verify.sh +21 -0
  371. package/plugins/lisa-cursor/hooks/block-shell-json-parsing.sh +21 -0
  372. package/plugins/lisa-cursor/hooks/failure-signature-index.mjs +240 -5
  373. package/plugins/lisa-cursor/hooks/guard-dedupe.bash +337 -0
  374. package/plugins/lisa-cursor/hooks/hooks.json +10 -0
  375. package/plugins/lisa-cursor/hooks/operational-hazards.mjs +736 -0
  376. package/plugins/lisa-cursor/hooks/operational-hazards.sh +28 -0
  377. package/plugins/lisa-cursor/hooks/parity-safety-net.sh +29 -1
  378. package/plugins/lisa-cursor/hooks/threshold-ratchet-compare.mjs +102 -21
  379. package/plugins/lisa-cursor/hooks/threshold-ratchet-families.mjs +130 -2
  380. package/plugins/lisa-cursor/hooks/threshold-ratchet.mjs +63 -13
  381. package/plugins/lisa-cursor/hooks/worktree-binding-guard.mjs +183 -1
  382. package/plugins/lisa-cursor/hooks/worktree-binding-guard.sh +21 -0
  383. package/plugins/lisa-cursor/rules/00-rule-index.mdc +1 -0
  384. package/plugins/lisa-cursor/rules/config-resolution-reference.mdc +1 -1
  385. package/plugins/lisa-cursor/rules/leaf-only-lifecycle-reference.mdc +1 -1
  386. package/plugins/lisa-cursor/rules/operational-hazards-reference.mdc +120 -0
  387. package/plugins/lisa-cursor/rules/operational-hazards.mdc +55 -0
  388. package/plugins/lisa-cursor/rules/tracked-work.mdc +1 -1
  389. package/plugins/lisa-cursor/rules/work-item-trailer-definition-reference.mdc +134 -0
  390. package/plugins/lisa-cursor/scripts/intake-blocker-reprobe.mjs +407 -26
  391. package/plugins/lisa-cursor/scripts/qa-signal-lifecycle.mjs +507 -0
  392. package/plugins/lisa-cursor/skills/lisa-drive-pr-to-merge/SKILL.md +130 -19
  393. package/plugins/lisa-cursor/skills/lisa-github-build-intake/SKILL.md +27 -4
  394. package/plugins/lisa-cursor/skills/lisa-github-prd-intake/SKILL.md +1 -1
  395. package/plugins/lisa-cursor/skills/lisa-github-validate-issue/SKILL.md +22 -0
  396. package/plugins/lisa-cursor/skills/lisa-github-verify/SKILL.md +14 -0
  397. package/plugins/lisa-cursor/skills/lisa-github-write-issue/SKILL.md +51 -0
  398. package/plugins/lisa-cursor/skills/lisa-intake/SKILL.md +1 -1
  399. package/plugins/lisa-cursor/skills/lisa-jira-build-intake/SKILL.md +27 -4
  400. package/plugins/lisa-cursor/skills/lisa-jira-validate-ticket/SKILL.md +22 -0
  401. package/plugins/lisa-cursor/skills/lisa-jira-verify/SKILL.md +14 -0
  402. package/plugins/lisa-cursor/skills/lisa-jira-write-ticket/SKILL.md +51 -0
  403. package/plugins/lisa-cursor/skills/lisa-linear-access/SKILL.md +55 -2
  404. package/plugins/lisa-cursor/skills/lisa-linear-build-intake/SKILL.md +27 -4
  405. package/plugins/lisa-cursor/skills/lisa-linear-prd-intake/SKILL.md +48 -31
  406. package/plugins/lisa-cursor/skills/lisa-linear-to-tracker/SKILL.md +3 -3
  407. package/plugins/lisa-cursor/skills/lisa-linear-validate-issue/SKILL.md +22 -0
  408. package/plugins/lisa-cursor/skills/lisa-linear-verify/SKILL.md +14 -0
  409. package/plugins/lisa-cursor/skills/lisa-linear-write-issue/SKILL.md +54 -3
  410. package/plugins/lisa-cursor/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
  411. package/plugins/lisa-cursor/skills/lisa-qa-clear/SKILL.md +19 -7
  412. package/plugins/lisa-cursor/skills/lisa-qa-fail/SKILL.md +28 -3
  413. package/plugins/lisa-cursor/skills/lisa-qa-queue/SKILL.md +28 -3
  414. package/plugins/lisa-cursor/skills/lisa-repair-intake/SKILL.md +94 -24
  415. package/plugins/lisa-cursor/skills/lisa-rework-triage/SKILL.md +32 -2
  416. package/plugins/lisa-cursor/skills/lisa-setup-linear/SKILL.md +5 -5
  417. package/plugins/lisa-cursor/skills/lisa-track/SKILL.md +1 -1
  418. package/plugins/lisa-cursor/skills/lisa-tracker-build-intake/SKILL.md +9 -0
  419. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  420. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  421. package/plugins/lisa-expo-agy/plugin.json +1 -1
  422. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  423. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  424. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  425. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  426. package/plugins/lisa-harper-fabric/hooks/inject-rules.sh +14 -3
  427. package/plugins/lisa-harper-fabric/rules/eager/harper-fabric.md +31 -0
  428. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  429. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  430. package/plugins/lisa-harper-fabric-copilot/hooks/inject-rules.sh +14 -3
  431. package/plugins/lisa-harper-fabric-copilot/rules/eager/harper-fabric.md +31 -0
  432. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  433. package/plugins/lisa-harper-fabric-cursor/rules/harper-fabric-reference.mdc +57 -0
  434. package/plugins/lisa-harper-fabric-cursor/rules/harper-fabric.mdc +32 -53
  435. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  436. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  437. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  438. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  439. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  440. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  441. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  442. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  443. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  444. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  445. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  446. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  447. package/plugins/lisa-phaser/hooks/inject-rules.sh +14 -3
  448. package/plugins/lisa-phaser/rules/eager/phaser.md +44 -0
  449. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  450. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  451. package/plugins/lisa-phaser-copilot/hooks/inject-rules.sh +14 -3
  452. package/plugins/lisa-phaser-copilot/rules/eager/phaser.md +44 -0
  453. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  454. package/plugins/lisa-phaser-cursor/rules/phaser-reference.mdc +189 -0
  455. package/plugins/lisa-phaser-cursor/rules/phaser.mdc +45 -185
  456. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  457. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  458. package/plugins/lisa-rails/hooks/inject-rules.sh +14 -4
  459. package/plugins/lisa-rails/rules/eager/rails-conventions.md +23 -0
  460. package/plugins/lisa-rails-agy/plugin.json +1 -1
  461. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  462. package/plugins/lisa-rails-copilot/hooks/inject-rules.sh +14 -4
  463. package/plugins/lisa-rails-copilot/rules/eager/rails-conventions.md +23 -0
  464. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  465. package/plugins/lisa-rails-cursor/rules/rails-conventions-reference.mdc +181 -0
  466. package/plugins/lisa-rails-cursor/rules/rails-conventions.mdc +24 -177
  467. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  468. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  469. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  470. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  471. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  472. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  473. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  474. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  475. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  476. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  477. package/plugins/materialized-artifacts.json +1 -0
  478. package/plugins/src/base/.claude-plugin/plugin.json +27 -0
  479. package/plugins/src/base/agents/linear-prd-intake.md +8 -8
  480. package/plugins/src/base/hooks/block-blind-automerge.sh +81 -2
  481. package/plugins/src/base/hooks/block-direct-issue-create.agy.sh +64 -16
  482. package/plugins/src/base/hooks/block-direct-issue-create.sh +293 -8
  483. package/plugins/src/base/hooks/block-instruction-file-edits.sh +21 -0
  484. package/plugins/src/base/hooks/block-managed-file-edits.sh +78 -15
  485. package/plugins/src/base/hooks/block-no-verify.sh +21 -0
  486. package/plugins/src/base/hooks/block-shell-json-parsing.sh +21 -0
  487. package/plugins/src/base/hooks/failure-signature-index.mjs +240 -5
  488. package/plugins/src/base/hooks/guard-dedupe.bash +337 -0
  489. package/plugins/src/base/hooks/inject-rules.sh +13 -5
  490. package/plugins/src/base/hooks/operational-hazards.mjs +736 -0
  491. package/plugins/src/base/hooks/operational-hazards.sh +28 -0
  492. package/plugins/src/base/hooks/parity-safety-net.sh +29 -1
  493. package/plugins/src/base/hooks/threshold-ratchet-compare.mjs +102 -21
  494. package/plugins/src/base/hooks/threshold-ratchet-families.mjs +130 -2
  495. package/plugins/src/base/hooks/threshold-ratchet.mjs +63 -13
  496. package/plugins/src/base/hooks/worktree-binding-guard.mjs +183 -1
  497. package/plugins/src/base/hooks/worktree-binding-guard.sh +21 -0
  498. package/plugins/src/base/rules/eager/00-rule-index.md +1 -0
  499. package/plugins/src/base/rules/eager/operational-hazards.md +50 -0
  500. package/plugins/src/base/rules/eager/tracked-work.md +1 -1
  501. package/plugins/src/base/rules/reference/config-resolution.md +1 -1
  502. package/plugins/src/base/rules/reference/leaf-only-lifecycle.md +1 -1
  503. package/plugins/src/base/rules/reference/operational-hazards.md +115 -0
  504. package/plugins/src/base/rules/reference/work-item-trailer-definition.md +129 -0
  505. package/plugins/src/base/scripts/intake-blocker-reprobe.mjs +407 -26
  506. package/plugins/src/base/scripts/qa-signal-lifecycle.mjs +507 -0
  507. package/plugins/src/base/skills/lisa-drive-pr-to-merge/SKILL.md +130 -19
  508. package/plugins/src/base/skills/lisa-github-build-intake/SKILL.md +27 -4
  509. package/plugins/src/base/skills/lisa-github-prd-intake/SKILL.md +1 -1
  510. package/plugins/src/base/skills/lisa-github-validate-issue/SKILL.md +22 -0
  511. package/plugins/src/base/skills/lisa-github-verify/SKILL.md +14 -0
  512. package/plugins/src/base/skills/lisa-github-write-issue/SKILL.md +51 -0
  513. package/plugins/src/base/skills/lisa-intake/SKILL.md +1 -1
  514. package/plugins/src/base/skills/lisa-jira-build-intake/SKILL.md +27 -4
  515. package/plugins/src/base/skills/lisa-jira-validate-ticket/SKILL.md +22 -0
  516. package/plugins/src/base/skills/lisa-jira-verify/SKILL.md +14 -0
  517. package/plugins/src/base/skills/lisa-jira-write-ticket/SKILL.md +51 -0
  518. package/plugins/src/base/skills/lisa-linear-access/SKILL.md +55 -2
  519. package/plugins/src/base/skills/lisa-linear-build-intake/SKILL.md +27 -4
  520. package/plugins/src/base/skills/lisa-linear-prd-intake/SKILL.md +48 -31
  521. package/plugins/src/base/skills/lisa-linear-to-tracker/SKILL.md +3 -3
  522. package/plugins/src/base/skills/lisa-linear-validate-issue/SKILL.md +22 -0
  523. package/plugins/src/base/skills/lisa-linear-verify/SKILL.md +14 -0
  524. package/plugins/src/base/skills/lisa-linear-write-issue/SKILL.md +54 -3
  525. package/plugins/src/base/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
  526. package/plugins/src/base/skills/lisa-qa-clear/SKILL.md +19 -7
  527. package/plugins/src/base/skills/lisa-qa-fail/SKILL.md +28 -3
  528. package/plugins/src/base/skills/lisa-qa-queue/SKILL.md +28 -3
  529. package/plugins/src/base/skills/lisa-repair-intake/SKILL.md +94 -24
  530. package/plugins/src/base/skills/lisa-rework-triage/SKILL.md +32 -2
  531. package/plugins/src/base/skills/lisa-setup-linear/SKILL.md +5 -5
  532. package/plugins/src/base/skills/lisa-track/SKILL.md +1 -1
  533. package/plugins/src/base/skills/lisa-tracker-build-intake/SKILL.md +9 -0
  534. package/plugins/src/harper-fabric/hooks/inject-rules.sh +14 -3
  535. package/plugins/src/harper-fabric/rules/eager/harper-fabric.md +31 -0
  536. package/plugins/src/phaser/hooks/inject-rules.sh +14 -3
  537. package/plugins/src/phaser/rules/eager/phaser.md +44 -0
  538. package/plugins/src/rails/hooks/inject-rules.sh +14 -4
  539. package/plugins/src/rails/rules/eager/rails-conventions.md +23 -0
  540. package/rails/copy-overwrite/scripts/check-threshold-ratchet.mjs +63 -13
  541. package/rails/copy-overwrite/scripts/threshold-ratchet-compare.mjs +102 -21
  542. package/rails/copy-overwrite/scripts/threshold-ratchet-families.mjs +130 -2
  543. package/rails/create-only/.github/workflows/ci.yml +8 -0
  544. package/rails/create-only/.github/workflows/deploy.yml +22 -0
  545. package/scripts/build-plugins.sh +2 -1
  546. package/scripts/check-engine-floor.mjs +361 -0
  547. package/scripts/check-guard-parity-notes.mjs +709 -0
  548. package/scripts/check-template-workflow-refs.mjs +9 -0
  549. package/scripts/check-third-party-action-pins.mjs +17 -1
  550. package/scripts/check-workflow-contract-assertions.mjs +480 -0
  551. package/scripts/copy-opencode-plugin-templates.mjs +1 -0
  552. package/scripts/deployed-guard-advice.mjs +636 -0
  553. package/scripts/generate-agy-plugin-artifacts.mjs +35 -10
  554. package/scripts/generate-export-surface.mjs +105 -19
  555. package/scripts/generate-two-channel-couplings.ts +143 -212
  556. package/scripts/lisa-enforcement-fallback.sh +31 -0
  557. package/scripts/measure-scripts-profile-gap.mts +361 -0
  558. package/scripts/mutation-performance-measure.mjs +21 -5
  559. package/scripts/reconcile-release-tags.mjs +65 -84
  560. package/scripts/two-channel-couplings.json +302 -70
  561. package/scripts/workflow-contract-assertion.sh +47 -0
  562. package/typescript/copy-overwrite/.lintstagedrc.json +1 -0
  563. package/typescript/copy-overwrite/eslint.ignore.config.json +1 -0
  564. package/typescript/copy-overwrite/scripts/check-nightly-e2e-health.mjs +527 -53
  565. package/typescript/copy-overwrite/scripts/check-skipped-required-checks.mjs +301 -13
  566. package/typescript/copy-overwrite/scripts/check-threshold-ratchet.mjs +63 -13
  567. package/typescript/copy-overwrite/scripts/threshold-ratchet-compare.mjs +102 -21
  568. package/typescript/copy-overwrite/scripts/threshold-ratchet-families.mjs +130 -2
  569. package/typescript/create-only/.github/workflows/ci.yml +7 -0
  570. /package/plugins/lisa-harper-fabric/rules/{harper-fabric.md → reference/harper-fabric.md} +0 -0
  571. /package/plugins/lisa-harper-fabric-copilot/rules/{harper-fabric.md → reference/harper-fabric.md} +0 -0
  572. /package/plugins/lisa-phaser/rules/{phaser.md → reference/phaser.md} +0 -0
  573. /package/plugins/lisa-phaser-copilot/rules/{phaser.md → reference/phaser.md} +0 -0
  574. /package/plugins/lisa-rails/rules/{rails-conventions.md → reference/rails-conventions.md} +0 -0
  575. /package/plugins/lisa-rails-copilot/rules/{rails-conventions.md → reference/rails-conventions.md} +0 -0
  576. /package/plugins/src/harper-fabric/rules/{harper-fabric.md → reference/harper-fabric.md} +0 -0
  577. /package/plugins/src/phaser/rules/{phaser.md → reference/phaser.md} +0 -0
  578. /package/plugins/src/rails/rules/{rails-conventions.md → reference/rails-conventions.md} +0 -0
@@ -5,103 +5,103 @@
5
5
  },
6
6
  "staleness": {
7
7
  "create-github-issue-on-failure.yml::scripts/nightly-e2e-provider-action.mjs": {
8
- "detects": "existence-only",
9
- "reason": "The read files a tracker issue after a nightly failure; it posts no required check and gates no merge. A stale copy files a slightly wrong issue body, which a human reads and corrects, rather than turning a merge green or red from superseded logic. The harm this classification exists to catch is a verdict nobody can see is old, and this coupling produces no verdict."
8
+ "decision": "not-needed",
9
+ "reason": "Advisory transport, not a verdict. The script files and reconciles a tracker issue about a nightly run that has ALREADY failed; it posts no check context and no job depends on its answer. A superseded copy files a differently-shaped issue, which lands in front of a human who can see it the visible failure, not the believed-red one this dimension exists to catch. A handshake here would gate issue filing on a version comparison and buy no cover."
10
10
  },
11
11
  "create-jira-issue-on-failure.yml::scripts/nightly-e2e-provider-action.mjs": {
12
- "detects": "existence-only",
13
- "reason": "Same provider action as the GitHub arm, same reasoning: it files a tracker issue after a nightly failure, posts no required check, and gates no merge. A stale copy misformats a report a human reads; it cannot produce a merge verdict derived from superseded logic."
12
+ "decision": "not-needed",
13
+ "reason": "Advisory transport, not a verdict. The script files and reconciles a tracker issue about a nightly run that has ALREADY failed; it posts no check context and no job depends on its answer. A superseded copy files a differently-shaped issue, which lands in front of a human who can see it the visible failure, not the believed-red one this dimension exists to catch. A handshake here would gate issue filing on a version comparison and buy no cover."
14
14
  },
15
15
  "create-linear-issue-on-failure.yml::scripts/nightly-e2e-provider-action.mjs": {
16
- "detects": "existence-only",
17
- "reason": "Same provider action as the GitHub and Jira arms, same reasoning: it files a tracker issue after a nightly failure, posts no required check, and gates no merge. A stale copy degrades a report rather than a verdict."
16
+ "decision": "not-needed",
17
+ "reason": "Advisory transport, not a verdict. The script files and reconciles a tracker issue about a nightly run that has ALREADY failed; it posts no check context and no job depends on its answer. A superseded copy files a differently-shaped issue, which lands in front of a human who can see it — the visible failure, not the believed-red one this dimension exists to catch. A handshake here would gate issue filing on a version comparison and buy no cover."
18
18
  },
19
19
  "create-sentry-issue-on-failure.yml::scripts/nightly-e2e-provider-action.mjs": {
20
- "detects": "existence-only",
21
- "reason": "Same provider action as the other three failure arms, same reasoning: it files an issue after a nightly failure, posts no required check, and gates no merge. A stale copy degrades a report rather than a verdict."
20
+ "decision": "not-needed",
21
+ "reason": "Advisory transport, not a verdict. The script files and reconciles a tracker issue about a nightly run that has ALREADY failed; it posts no check context and no job depends on its answer. A superseded copy files a differently-shaped issue, which lands in front of a human who can see it — the visible failure, not the believed-red one this dimension exists to catch. A handshake here would gate issue filing on a version comparison and buy no cover."
22
22
  },
23
23
  "maestro-native-e2e.yml::scripts/classify-maestro-failures.mjs": {
24
- "detects": "existence-only",
25
- "reason": "Classifies native E2E failures for the run summary so an operator can tell an infrastructure flake from a product regression. It labels a failure that has already been decided elsewhere; it does not decide one. A stale classifier mislabels a red the operator is already looking at, which is visible in the same output."
24
+ "decision": "not-needed",
25
+ "reason": "Advisory classifier over a failure that has already happened. The step carries `exit-zero` and `failure-suppression`, and the job's verdict comes from the suite it annotates rather than from this script a superseded copy mislabels a failure, it cannot invent or suppress one. Not verdict-bearing, so a handshake is cost without cover."
26
26
  },
27
27
  "nightly-e2e-health.yml::scripts/check-nightly-e2e-health.mjs": {
28
- "detects": "version-handshake"
28
+ "decision": "handshake"
29
29
  },
30
30
  "nightly-e2e-health.yml::scripts/nightly-e2e-suites.schema.json": {
31
- "detects": "existence-only",
32
- "reason": "A JSON schema has no executable surface, so it cannot answer a contract-version call at all no handshake is constructible here. It is covered transitively rather than left unguarded: the schema and check-nightly-e2e-health.mjs ship on the same typescript/copy-overwrite lane and are read by the same workflow, and that checker DOES handshake, so a tree old enough to carry a stale schema carries a stale checker and the existing handshake fails first."
31
+ "decision": "not-needed",
32
+ "reason": "Data, not logic: a JSON schema has no branch that can reach a wrong verdict, only a shape that does or does not validate. Its one reader is `scripts/check-nightly-e2e-health.mjs`, which DOES carry a version handshake, so the vintage of the pair is already named in the run output a second handshake on the schema would restate an answer that is already given."
33
33
  },
34
34
  "nightly-e2e-report.yml::scripts/check-nightly-e2e-health.mjs": {
35
- "detects": "version-handshake"
35
+ "decision": "handshake"
36
36
  },
37
37
  "nightly-e2e-tracking.yml::scripts/reconcile-nightly-e2e-tracking.mjs": {
38
- "detects": "existence-only",
39
- "reason": "Reconciles the nightly tracking issue opens, refreshes or closes it to match the latest health verdict. It consumes a verdict rather than producing one, so a stale copy mismanages a tracking issue a human reads and cannot make a merge gate green."
38
+ "decision": "not-needed",
39
+ "reason": "Advisory transport, not a verdict. The script files and reconciles a tracker issue about a nightly run that has ALREADY failed; it posts no check context and no job depends on its answer. A superseded copy files a differently-shaped issue, which lands in front of a human who can see it the visible failure, not the believed-red one this dimension exists to catch. A handshake here would gate issue filing on a version comparison and buy no cover."
40
40
  },
41
41
  "publish-to-npm.yml::scripts/check-npm-publish-landed.mjs": {
42
- "detects": "existence-only",
43
- "reason": "A GENUINE GAP, recorded rather than waved through. It verifies a publish actually landed, so a stale copy can attest to a release that did not happen. It runs post-merge in the release workflow and posts no merge-blocking required context, which is why it is not the first handshake to build but it is verdict-bearing and belongs at the front of the queue when this classification is next acted on."
42
+ "decision": "warranted",
43
+ "reason": "Verdict-bearing on the release path: this prover decides whether a publish actually landed, and a superseded copy can report a landed publish that did not, or redden one that did. The evidence it produces is exactly the kind read once and believed. Not closed here because a handshake on the release path needs its own red-before-green control against a real registry response, which is more than the classification this entry exists to record; the obligation is recorded rather than defaulted so it is counted on every run."
44
44
  },
45
45
  "publish-to-npm.yml::scripts/check-release-package-identity.mjs": {
46
- "detects": "existence-only",
47
- "reason": "A GENUINE GAP, recorded rather than waved through, and the sibling of the publish-landed read: it attests that the published package is the one intended, so a stale copy can attest to an identity it no longer checks the same way. Post-merge and not merge-blocking, so it queues behind the merge gates rather than ahead of them."
46
+ "decision": "warranted",
47
+ "reason": "Verdict-bearing on the release path, same shape as `check-npm-publish-landed.mjs`: it decides whether the artifact about to be published is the one this repository built. A copy behind a major can compare a field that has since changed meaning and pass. Not closed here for the same reason, and counted every run rather than exempted."
48
48
  },
49
49
  "quality-rails.yml::scripts/check-threshold-ratchet.mjs": {
50
- "detects": "existence-only",
51
- "reason": "Same prover as the quality.yml read and the same GENUINE GAP, reached from the Rails caller tree. Recorded separately because the two callers can drift apart: a handshake added to one workflow does not reach the other, which is how a fleet ends up half-covered."
50
+ "decision": "warranted",
51
+ "reason": "Verdict-bearing required gate: it compares committed thresholds against measured coverage and posts a red check. A copy predating a threshold-semantics change enforces the old comparison and its red is believed — the precise harm CodySwannGT/lisa#3477 measured on the work-item gate. The artifact exports no contract version yet, so closing this needs the artifact half authored first; recorded as an open obligation rather than exempted."
52
52
  },
53
53
  "quality-rails.yml::scripts/lisa-mutation.sh": {
54
- "detects": "existence-only",
55
- "reason": "A shell wrapper that shapes a mutation-testing invocation; the verdict comes from Stryker and its configured thresholds, not from this file. A stale wrapper passes older flags, which fails loudly as a runner usage error rather than producing a wrong mutation score."
54
+ "decision": "not-needed",
55
+ "reason": "A runner, not a judge. The gate's verdict is mutant's exit code, and what it runs is read from the project's own `mutation.gate.yml` and `.mutant.yml`; this script's own logic decides whether the gate is enabled and what ref to diff against, both of which come from configuration it does not own. A superseded copy runs the wrong subjects loudly rather than returning a wrong verdict quietly."
56
56
  },
57
57
  "quality-rails.yml::scripts/lisa-scratch-run.sh": {
58
- "detects": "existence-only",
59
- "reason": "A shell wrapper that isolates a run's scratch namespace. It carries no verdict-bearing logic at all it prepares a directory and execs the real command so there is no superseded judgement for a stale copy to apply."
58
+ "decision": "not-needed",
59
+ "reason": "A supervisor that hosts a verdict rather than computing one: it owns run-scoped scratch and cleanup around whatever it wraps. Nothing it does can turn a passing suite red or a failing one green a superseded copy misplaces or fails to reap a scratch directory, which surfaces as its own visible failure rather than as a believed verdict."
60
60
  },
61
61
  "quality-rails.yml::scripts/lisa-work-item.mjs": {
62
- "detects": "version-handshake"
62
+ "decision": "handshake"
63
63
  },
64
64
  "quality.yml::scripts/check-e2e-coverage.mjs": {
65
- "detects": "existence-only",
66
- "reason": "Guarded by an existence test and scoped to Expo consumers. It reports route coverage against a declared threshold; a stale copy computes coverage by an older rule and says which rule it used in its own output, so the number it prints is interpretable rather than silently wrong."
65
+ "decision": "warranted",
66
+ "reason": "Verdict-bearing required gate: it computes route coverage against a configured floor and posts a red check every reader believes. A copy predating a change to how routes are enumerated reports a coverage number derived from superseded logic, with nothing in the output naming its vintage. The artifact exports no contract version yet, so closing this needs the artifact half authored first; recorded as an open obligation rather than exempted."
67
67
  },
68
68
  "quality.yml::scripts/check-learnings-budget.ts": {
69
- "detects": "existence-only",
70
- "reason": "Already ratified as a Lisa-source-only branch: every consumer takes the else arm and runs the prover from the PACKAGE channel at their own declared version, which is a version pin rather than an unversioned copy. The two-channel skew this field is about does not arise on the path consumers actually take."
69
+ "decision": "not-needed",
70
+ "reason": "Unreachable outside this repository, and ratified above on that ground: the step tests for two paths that co-exist only here, and every consumer takes the else arm and runs the prover from the PACKAGE channel, whose vintage is their declared dependency version. There is no delivered artifact at this path for a consumer to hold a stale copy of which is why the detection is `unchecked` rather than a measured negative."
71
71
  },
72
72
  "quality.yml::scripts/check-skipped-required-checks.mjs": {
73
- "detects": "existence-only",
74
- "reason": "A GENUINE GAP and the sharpest one in this registry: it is the vacuity and review-evidence prover, so a stale copy posts a review verdict from superseded logic on a merge gate. Its own workflow resolves a second in-repo address when scripts/ has no copy, which bounds the absent case but says nothing about age. Highest-value handshake candidate here."
73
+ "decision": "warranted",
74
+ "reason": "Verdict-bearing required gate: it compares skip tokens against the ruleset's required contexts, and the step states that its absence is a failure precisely because a skipped required check reads as satisfied. A superseded copy comparing against a stale notion of the required set is the same false green arriving by the other door. The artifact exports no contract version yet; recorded as an open obligation rather than exempted."
75
75
  },
76
76
  "quality.yml::scripts/check-state-classification.mjs": {
77
- "detects": "existence-only",
78
- "reason": "Guarded by an existence test and advisory in effect: it classifies demo/fixture state against a declared contract and reports what it found. A stale copy reports against an older contract version, which surfaces as a classification mismatch in its own output rather than as a green merge gate, so the failure is self-announcing."
77
+ "decision": "warranted",
78
+ "reason": "Verdict-bearing required gate whose subject is classification itself it decides which states a change is allowed to leave behind. A copy behind a classification change enforces the superseded taxonomy and names states that no longer mean what it thinks. The artifact exports no contract version yet; recorded as an open obligation rather than exempted."
79
79
  },
80
80
  "quality.yml::scripts/check-threshold-ratchet.mjs": {
81
- "detects": "existence-only",
82
- "reason": "A GENUINE GAP. The ratchet decides whether a threshold moved the wrong way, so a stale copy can pass a loosened threshold it does not yet know how to refuse. It is declared optional at push in this repository's own gate set, which lowers the blast radius but does not remove it."
81
+ "decision": "warranted",
82
+ "reason": "Verdict-bearing required gate, the same artifact and the same exposure as the `quality-rails.yml` entry: a copy predating a threshold-semantics change enforces the old comparison and its red is believed. Closing it once closes both couplings, since they read the same script down two stack lanes. The artifact exports no contract version yet; recorded as an open obligation rather than exempted."
83
83
  },
84
84
  "quality.yml::scripts/check-verification-coverage.mjs": {
85
- "detects": "existence-only",
86
- "reason": "Bespoke and conditional it requires a verification-spec delta on feat/fix changes. A stale copy applies an older definition of what counts as a spec delta, which produces a visible disagreement with the spec in the pull request rather than a silent pass."
85
+ "decision": "warranted",
86
+ "reason": "Verdict-bearing gate over whether shipped work carries its verification evidence. A superseded copy looks for evidence in a shape the repository has moved off and reports a gap that is not there, or misses one that is. The artifact exports no contract version yet; recorded as an open obligation rather than exempted."
87
87
  },
88
88
  "quality.yml::scripts/generate-nightly-e2e-guard-certificate.mjs": {
89
- "detects": "existence-only",
90
- "reason": "Already ratified as undelivered: no lane ships this path, so no consumer tree carries a copy that could be stale. The staleness question is vacuous here for the same reason the delivery question was, and it is recorded rather than left blank so the entry is not mistaken for one nobody examined."
89
+ "decision": "not-needed",
90
+ "reason": "Unreachable outside this repository, and ratified above on that ground: both reusable jobs require this repository before the step can start, and the run body repeats the guard. No consumer ever reads this path from their own tree, so there is no copy of it anywhere to go stale which is why the detection is `unchecked` rather than a measured negative."
91
91
  },
92
92
  "quality.yml::scripts/lisa-floor-collisions.mjs": {
93
- "detects": "existence-only",
94
- "reason": "Reports collisions between declared security floors. A stale copy knows a smaller set of floors, so it under-reports rather than mis-decides, and the floors it does know it still checks correctly. Under-reporting is the benign direction for a collision detector."
93
+ "decision": "warranted",
94
+ "reason": "Verdict-bearing gate: it decides whether two declared floors collide and fails the job when they do. A copy predating a change to how a floor is spelled can miss a live collision, and a missed collision is silent by construction. The artifact exports no contract version yet; recorded as an open obligation rather than exempted."
95
95
  },
96
96
  "quality.yml::scripts/lisa-work-item.mjs": {
97
- "detects": "version-handshake"
97
+ "decision": "handshake"
98
98
  }
99
99
  },
100
100
  "inspected": {
101
101
  "workflows": 23,
102
- "steps": 719,
102
+ "steps": 747,
103
103
  "couplings": 34,
104
- "inventory": 77
104
+ "inventory": 78
105
105
  },
106
106
  "counts": {
107
107
  "package-backed": 10,
@@ -109,6 +109,18 @@
109
109
  "never-delivered": 0,
110
110
  "undelivered": 2
111
111
  },
112
+ "detectionCounts": {
113
+ "version-handshake": 4,
114
+ "capability-probe": 0,
115
+ "existence-only": 4,
116
+ "no-probe": 14,
117
+ "unchecked": 2
118
+ },
119
+ "decisionCounts": {
120
+ "handshake": 4,
121
+ "not-needed": 11,
122
+ "warranted": 9
123
+ },
112
124
  "couplings": [
113
125
  {
114
126
  "key": "create-github-issue-on-failure.yml::scripts/nightly-e2e-provider-action.mjs",
@@ -118,10 +130,15 @@
118
130
  "verdict": "apply-lagged",
119
131
  "remedy": "run-lisa-apply",
120
132
  "guarded": false,
133
+ "handling": [],
134
+ "detection": "no-probe",
135
+ "stalenessSignals": [],
136
+ "decision": "not-needed",
137
+ "reason": "Advisory transport, not a verdict. The script files and reconciles a tracker issue about a nightly run that has ALREADY failed; it posts no check context and no job depends on its answer. A superseded copy files a differently-shaped issue, which lands in front of a human who can see it — the visible failure, not the believed-red one this dimension exists to catch. A handshake here would gate issue filing on a version comparison and buy no cover.",
121
138
  "lanes": [
122
139
  "typescript/copy-overwrite"
123
140
  ],
124
- "detail": "`create-github-issue-on-failure.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/nightly-e2e-provider-action.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (typescript/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read is unguarded, so an absent path fails the job loudly. Visible, which makes it the better of the two failures."
141
+ "detail": "`create-github-issue-on-failure.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/nightly-e2e-provider-action.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (typescript/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. No existence test guards the read, which is ALL this scan examined of the step's control flow: it did not read anything that could absorb the failure. An absent path most likely fails the job loudly — the better of the two failures, because it is visible — but that is inferred from the missing guard, NOT MEASURED. The step's text carries none of the tokens this scan can see (`else-branch`, `exit-zero`, `exit-nonzero`, `error-annotation`, `notice-annotation`, `failure-suppression`), which is a statement about those names and not about the step's behaviour. STALENESS (a separate dimension from the delivery verdict above): `no-probe`. Neither an existence test nor a version probe bears on this read, so nothing here distinguishes a current artifact from an absent or a superseded one. None of the staleness tokens this scan can see (`artifact-declares-version`, `artifact-answers-version`, `step-requests-version`, `workflow-requests-version`) were found."
125
142
  },
126
143
  {
127
144
  "key": "create-jira-issue-on-failure.yml::scripts/nightly-e2e-provider-action.mjs",
@@ -131,10 +148,15 @@
131
148
  "verdict": "apply-lagged",
132
149
  "remedy": "run-lisa-apply",
133
150
  "guarded": false,
151
+ "handling": [],
152
+ "detection": "no-probe",
153
+ "stalenessSignals": [],
154
+ "decision": "not-needed",
155
+ "reason": "Advisory transport, not a verdict. The script files and reconciles a tracker issue about a nightly run that has ALREADY failed; it posts no check context and no job depends on its answer. A superseded copy files a differently-shaped issue, which lands in front of a human who can see it — the visible failure, not the believed-red one this dimension exists to catch. A handshake here would gate issue filing on a version comparison and buy no cover.",
134
156
  "lanes": [
135
157
  "typescript/copy-overwrite"
136
158
  ],
137
- "detail": "`create-jira-issue-on-failure.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/nightly-e2e-provider-action.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (typescript/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read is unguarded, so an absent path fails the job loudly. Visible, which makes it the better of the two failures."
159
+ "detail": "`create-jira-issue-on-failure.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/nightly-e2e-provider-action.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (typescript/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. No existence test guards the read, which is ALL this scan examined of the step's control flow: it did not read anything that could absorb the failure. An absent path most likely fails the job loudly — the better of the two failures, because it is visible — but that is inferred from the missing guard, NOT MEASURED. The step's text carries none of the tokens this scan can see (`else-branch`, `exit-zero`, `exit-nonzero`, `error-annotation`, `notice-annotation`, `failure-suppression`), which is a statement about those names and not about the step's behaviour. STALENESS (a separate dimension from the delivery verdict above): `no-probe`. Neither an existence test nor a version probe bears on this read, so nothing here distinguishes a current artifact from an absent or a superseded one. None of the staleness tokens this scan can see (`artifact-declares-version`, `artifact-answers-version`, `step-requests-version`, `workflow-requests-version`) were found."
138
160
  },
139
161
  {
140
162
  "key": "create-linear-issue-on-failure.yml::scripts/nightly-e2e-provider-action.mjs",
@@ -144,10 +166,15 @@
144
166
  "verdict": "apply-lagged",
145
167
  "remedy": "run-lisa-apply",
146
168
  "guarded": false,
169
+ "handling": [],
170
+ "detection": "no-probe",
171
+ "stalenessSignals": [],
172
+ "decision": "not-needed",
173
+ "reason": "Advisory transport, not a verdict. The script files and reconciles a tracker issue about a nightly run that has ALREADY failed; it posts no check context and no job depends on its answer. A superseded copy files a differently-shaped issue, which lands in front of a human who can see it — the visible failure, not the believed-red one this dimension exists to catch. A handshake here would gate issue filing on a version comparison and buy no cover.",
147
174
  "lanes": [
148
175
  "typescript/copy-overwrite"
149
176
  ],
150
- "detail": "`create-linear-issue-on-failure.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/nightly-e2e-provider-action.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (typescript/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read is unguarded, so an absent path fails the job loudly. Visible, which makes it the better of the two failures."
177
+ "detail": "`create-linear-issue-on-failure.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/nightly-e2e-provider-action.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (typescript/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. No existence test guards the read, which is ALL this scan examined of the step's control flow: it did not read anything that could absorb the failure. An absent path most likely fails the job loudly — the better of the two failures, because it is visible — but that is inferred from the missing guard, NOT MEASURED. The step's text carries none of the tokens this scan can see (`else-branch`, `exit-zero`, `exit-nonzero`, `error-annotation`, `notice-annotation`, `failure-suppression`), which is a statement about those names and not about the step's behaviour. STALENESS (a separate dimension from the delivery verdict above): `no-probe`. Neither an existence test nor a version probe bears on this read, so nothing here distinguishes a current artifact from an absent or a superseded one. None of the staleness tokens this scan can see (`artifact-declares-version`, `artifact-answers-version`, `step-requests-version`, `workflow-requests-version`) were found."
151
178
  },
152
179
  {
153
180
  "key": "create-sentry-issue-on-failure.yml::scripts/nightly-e2e-provider-action.mjs",
@@ -157,10 +184,15 @@
157
184
  "verdict": "apply-lagged",
158
185
  "remedy": "run-lisa-apply",
159
186
  "guarded": false,
187
+ "handling": [],
188
+ "detection": "no-probe",
189
+ "stalenessSignals": [],
190
+ "decision": "not-needed",
191
+ "reason": "Advisory transport, not a verdict. The script files and reconciles a tracker issue about a nightly run that has ALREADY failed; it posts no check context and no job depends on its answer. A superseded copy files a differently-shaped issue, which lands in front of a human who can see it — the visible failure, not the believed-red one this dimension exists to catch. A handshake here would gate issue filing on a version comparison and buy no cover.",
160
192
  "lanes": [
161
193
  "typescript/copy-overwrite"
162
194
  ],
163
- "detail": "`create-sentry-issue-on-failure.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/nightly-e2e-provider-action.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (typescript/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read is unguarded, so an absent path fails the job loudly. Visible, which makes it the better of the two failures."
195
+ "detail": "`create-sentry-issue-on-failure.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/nightly-e2e-provider-action.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (typescript/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. No existence test guards the read, which is ALL this scan examined of the step's control flow: it did not read anything that could absorb the failure. An absent path most likely fails the job loudly — the better of the two failures, because it is visible — but that is inferred from the missing guard, NOT MEASURED. The step's text carries none of the tokens this scan can see (`else-branch`, `exit-zero`, `exit-nonzero`, `error-annotation`, `notice-annotation`, `failure-suppression`), which is a statement about those names and not about the step's behaviour. STALENESS (a separate dimension from the delivery verdict above): `no-probe`. Neither an existence test nor a version probe bears on this read, so nothing here distinguishes a current artifact from an absent or a superseded one. None of the staleness tokens this scan can see (`artifact-declares-version`, `artifact-answers-version`, `step-requests-version`, `workflow-requests-version`) were found."
164
196
  },
165
197
  {
166
198
  "key": "maestro-native-e2e.yml::scripts/classify-maestro-failures.mjs",
@@ -170,10 +202,18 @@
170
202
  "verdict": "apply-lagged",
171
203
  "remedy": "run-lisa-apply",
172
204
  "guarded": false,
205
+ "handling": [
206
+ "exit-zero",
207
+ "failure-suppression"
208
+ ],
209
+ "detection": "no-probe",
210
+ "stalenessSignals": [],
211
+ "decision": "not-needed",
212
+ "reason": "Advisory classifier over a failure that has already happened. The step carries `exit-zero` and `failure-suppression`, and the job's verdict comes from the suite it annotates rather than from this script — a superseded copy mislabels a failure, it cannot invent or suppress one. Not verdict-bearing, so a handshake is cost without cover.",
173
213
  "lanes": [
174
214
  "expo/copy-overwrite"
175
215
  ],
176
- "detail": "`maestro-native-e2e.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/classify-maestro-failures.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (expo/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read is unguarded, so an absent path fails the job loudly. Visible, which makes it the better of the two failures."
216
+ "detail": "`maestro-native-e2e.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/classify-maestro-failures.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (expo/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. No existence test guards the read, which is ALL this scan examined of the step's control flow: it did not read anything that could absorb the failure. An absent path most likely fails the job loudly — the better of the two failures, because it is visible — but that is inferred from the missing guard, NOT MEASURED. The step's text does carry `exit-zero`, `failure-suppression` — located in the step, deliberately NOT related to this read, and enough to make \"it skips silently\" a claim to check rather than assume. STALENESS (a separate dimension from the delivery verdict above): `no-probe`. Neither an existence test nor a version probe bears on this read, so nothing here distinguishes a current artifact from an absent or a superseded one. None of the staleness tokens this scan can see (`artifact-declares-version`, `artifact-answers-version`, `step-requests-version`, `workflow-requests-version`) were found."
177
217
  },
178
218
  {
179
219
  "key": "nightly-e2e-health.yml::scripts/check-nightly-e2e-health.mjs",
@@ -183,10 +223,19 @@
183
223
  "verdict": "apply-lagged",
184
224
  "remedy": "run-lisa-apply",
185
225
  "guarded": false,
226
+ "handling": [],
227
+ "detection": "version-handshake",
228
+ "stalenessSignals": [
229
+ "artifact-declares-version",
230
+ "artifact-answers-version",
231
+ "workflow-requests-version"
232
+ ],
233
+ "decision": "handshake",
234
+ "reason": null,
186
235
  "lanes": [
187
236
  "typescript/copy-overwrite"
188
237
  ],
189
- "detail": "`nightly-e2e-health.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/check-nightly-e2e-health.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (typescript/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read is unguarded, so an absent path fails the job loudly. Visible, which makes it the better of the two failures."
238
+ "detail": "`nightly-e2e-health.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/check-nightly-e2e-health.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (typescript/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. No existence test guards the read, which is ALL this scan examined of the step's control flow: it did not read anything that could absorb the failure. An absent path most likely fails the job loudly — the better of the two failures, because it is visible — but that is inferred from the missing guard, NOT MEASURED. The step's text carries none of the tokens this scan can see (`else-branch`, `exit-zero`, `exit-nonzero`, `error-annotation`, `notice-annotation`, `failure-suppression`), which is a statement about those names and not about the step's behaviour. STALENESS (a separate dimension from the delivery verdict above): `version-handshake`. The delivered artifact answers a contract version and the workflow asks for one, so a copy too old to speak the same contract is NAMED rather than silently run. Tokens found: `artifact-declares-version`, `artifact-answers-version`, `workflow-requests-version`. `workflow-requests-version` is workflow-scoped — it does not say THIS step asks."
190
239
  },
191
240
  {
192
241
  "key": "nightly-e2e-health.yml::scripts/nightly-e2e-suites.schema.json",
@@ -196,10 +245,17 @@
196
245
  "verdict": "apply-lagged",
197
246
  "remedy": "run-lisa-apply",
198
247
  "guarded": false,
248
+ "handling": [],
249
+ "detection": "no-probe",
250
+ "stalenessSignals": [
251
+ "workflow-requests-version"
252
+ ],
253
+ "decision": "not-needed",
254
+ "reason": "Data, not logic: a JSON schema has no branch that can reach a wrong verdict, only a shape that does or does not validate. Its one reader is `scripts/check-nightly-e2e-health.mjs`, which DOES carry a version handshake, so the vintage of the pair is already named in the run output — a second handshake on the schema would restate an answer that is already given.",
199
255
  "lanes": [
200
256
  "typescript/copy-overwrite"
201
257
  ],
202
- "detail": "`nightly-e2e-health.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/nightly-e2e-suites.schema.json` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (typescript/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read is unguarded, so an absent path fails the job loudly. Visible, which makes it the better of the two failures."
258
+ "detail": "`nightly-e2e-health.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/nightly-e2e-suites.schema.json` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (typescript/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. No existence test guards the read, which is ALL this scan examined of the step's control flow: it did not read anything that could absorb the failure. An absent path most likely fails the job loudly — the better of the two failures, because it is visible — but that is inferred from the missing guard, NOT MEASURED. The step's text carries none of the tokens this scan can see (`else-branch`, `exit-zero`, `exit-nonzero`, `error-annotation`, `notice-annotation`, `failure-suppression`), which is a statement about those names and not about the step's behaviour. STALENESS (a separate dimension from the delivery verdict above): `no-probe`. Neither an existence test nor a version probe bears on this read, so nothing here distinguishes a current artifact from an absent or a superseded one. Tokens found: `workflow-requests-version`. `workflow-requests-version` is workflow-scoped — it does not say THIS step asks."
203
259
  },
204
260
  {
205
261
  "key": "nightly-e2e-report.yml::scripts/check-nightly-e2e-health.mjs",
@@ -209,10 +265,19 @@
209
265
  "verdict": "apply-lagged",
210
266
  "remedy": "run-lisa-apply",
211
267
  "guarded": false,
268
+ "handling": [],
269
+ "detection": "version-handshake",
270
+ "stalenessSignals": [
271
+ "artifact-declares-version",
272
+ "artifact-answers-version",
273
+ "workflow-requests-version"
274
+ ],
275
+ "decision": "handshake",
276
+ "reason": null,
212
277
  "lanes": [
213
278
  "typescript/copy-overwrite"
214
279
  ],
215
- "detail": "`nightly-e2e-report.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/check-nightly-e2e-health.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (typescript/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read is unguarded, so an absent path fails the job loudly. Visible, which makes it the better of the two failures."
280
+ "detail": "`nightly-e2e-report.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/check-nightly-e2e-health.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (typescript/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. No existence test guards the read, which is ALL this scan examined of the step's control flow: it did not read anything that could absorb the failure. An absent path most likely fails the job loudly — the better of the two failures, because it is visible — but that is inferred from the missing guard, NOT MEASURED. The step's text carries none of the tokens this scan can see (`else-branch`, `exit-zero`, `exit-nonzero`, `error-annotation`, `notice-annotation`, `failure-suppression`), which is a statement about those names and not about the step's behaviour. STALENESS (a separate dimension from the delivery verdict above): `version-handshake`. The delivered artifact answers a contract version and the workflow asks for one, so a copy too old to speak the same contract is NAMED rather than silently run. Tokens found: `artifact-declares-version`, `artifact-answers-version`, `workflow-requests-version`. `workflow-requests-version` is workflow-scoped — it does not say THIS step asks."
216
281
  },
217
282
  {
218
283
  "key": "nightly-e2e-tracking.yml::scripts/reconcile-nightly-e2e-tracking.mjs",
@@ -222,10 +287,15 @@
222
287
  "verdict": "apply-lagged",
223
288
  "remedy": "run-lisa-apply",
224
289
  "guarded": false,
290
+ "handling": [],
291
+ "detection": "no-probe",
292
+ "stalenessSignals": [],
293
+ "decision": "not-needed",
294
+ "reason": "Advisory transport, not a verdict. The script files and reconciles a tracker issue about a nightly run that has ALREADY failed; it posts no check context and no job depends on its answer. A superseded copy files a differently-shaped issue, which lands in front of a human who can see it — the visible failure, not the believed-red one this dimension exists to catch. A handshake here would gate issue filing on a version comparison and buy no cover.",
225
295
  "lanes": [
226
296
  "typescript/copy-overwrite"
227
297
  ],
228
- "detail": "`nightly-e2e-tracking.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/reconcile-nightly-e2e-tracking.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (typescript/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read is unguarded, so an absent path fails the job loudly. Visible, which makes it the better of the two failures."
298
+ "detail": "`nightly-e2e-tracking.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/reconcile-nightly-e2e-tracking.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (typescript/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. No existence test guards the read, which is ALL this scan examined of the step's control flow: it did not read anything that could absorb the failure. An absent path most likely fails the job loudly — the better of the two failures, because it is visible — but that is inferred from the missing guard, NOT MEASURED. The step's text carries none of the tokens this scan can see (`else-branch`, `exit-zero`, `exit-nonzero`, `error-annotation`, `notice-annotation`, `failure-suppression`), which is a statement about those names and not about the step's behaviour. STALENESS (a separate dimension from the delivery verdict above): `no-probe`. Neither an existence test nor a version probe bears on this read, so nothing here distinguishes a current artifact from an absent or a superseded one. None of the staleness tokens this scan can see (`artifact-declares-version`, `artifact-answers-version`, `step-requests-version`, `workflow-requests-version`) were found."
229
299
  },
230
300
  {
231
301
  "key": "publish-to-npm.yml::scripts/check-npm-publish-landed.mjs",
@@ -235,10 +305,15 @@
235
305
  "verdict": "apply-lagged",
236
306
  "remedy": "run-lisa-apply",
237
307
  "guarded": false,
308
+ "handling": [],
309
+ "detection": "no-probe",
310
+ "stalenessSignals": [],
311
+ "decision": "warranted",
312
+ "reason": "Verdict-bearing on the release path: this prover decides whether a publish actually landed, and a superseded copy can report a landed publish that did not, or redden one that did. The evidence it produces is exactly the kind read once and believed. Not closed here because a handshake on the release path needs its own red-before-green control against a real registry response, which is more than the classification this entry exists to record; the obligation is recorded rather than defaulted so it is counted on every run.",
238
313
  "lanes": [
239
314
  "all/copy-overwrite"
240
315
  ],
241
- "detail": "`publish-to-npm.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/check-npm-publish-landed.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (all/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read is unguarded, so an absent path fails the job loudly. Visible, which makes it the better of the two failures."
316
+ "detail": "`publish-to-npm.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/check-npm-publish-landed.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (all/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. No existence test guards the read, which is ALL this scan examined of the step's control flow: it did not read anything that could absorb the failure. An absent path most likely fails the job loudly — the better of the two failures, because it is visible — but that is inferred from the missing guard, NOT MEASURED. The step's text carries none of the tokens this scan can see (`else-branch`, `exit-zero`, `exit-nonzero`, `error-annotation`, `notice-annotation`, `failure-suppression`), which is a statement about those names and not about the step's behaviour. STALENESS (a separate dimension from the delivery verdict above): `no-probe`. Neither an existence test nor a version probe bears on this read, so nothing here distinguishes a current artifact from an absent or a superseded one. None of the staleness tokens this scan can see (`artifact-declares-version`, `artifact-answers-version`, `step-requests-version`, `workflow-requests-version`) were found."
242
317
  },
243
318
  {
244
319
  "key": "publish-to-npm.yml::scripts/check-release-package-identity.mjs",
@@ -248,10 +323,15 @@
248
323
  "verdict": "apply-lagged",
249
324
  "remedy": "run-lisa-apply",
250
325
  "guarded": false,
326
+ "handling": [],
327
+ "detection": "no-probe",
328
+ "stalenessSignals": [],
329
+ "decision": "warranted",
330
+ "reason": "Verdict-bearing on the release path, same shape as `check-npm-publish-landed.mjs`: it decides whether the artifact about to be published is the one this repository built. A copy behind a major can compare a field that has since changed meaning and pass. Not closed here for the same reason, and counted every run rather than exempted.",
251
331
  "lanes": [
252
332
  "all/copy-overwrite"
253
333
  ],
254
- "detail": "`publish-to-npm.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/check-release-package-identity.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (all/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read is unguarded, so an absent path fails the job loudly. Visible, which makes it the better of the two failures."
334
+ "detail": "`publish-to-npm.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/check-release-package-identity.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (all/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. No existence test guards the read, which is ALL this scan examined of the step's control flow: it did not read anything that could absorb the failure. An absent path most likely fails the job loudly — the better of the two failures, because it is visible — but that is inferred from the missing guard, NOT MEASURED. The step's text carries none of the tokens this scan can see (`else-branch`, `exit-zero`, `exit-nonzero`, `error-annotation`, `notice-annotation`, `failure-suppression`), which is a statement about those names and not about the step's behaviour. STALENESS (a separate dimension from the delivery verdict above): `no-probe`. Neither an existence test nor a version probe bears on this read, so nothing here distinguishes a current artifact from an absent or a superseded one. None of the staleness tokens this scan can see (`artifact-declares-version`, `artifact-answers-version`, `step-requests-version`, `workflow-requests-version`) were found."
255
335
  },
256
336
  {
257
337
  "key": "quality-rails.yml::scripts/check-threshold-ratchet.mjs",
@@ -261,11 +341,23 @@
261
341
  "verdict": "apply-lagged",
262
342
  "remedy": "run-lisa-apply",
263
343
  "guarded": false,
344
+ "handling": [
345
+ "else-branch",
346
+ "exit-zero",
347
+ "exit-nonzero",
348
+ "error-annotation"
349
+ ],
350
+ "detection": "no-probe",
351
+ "stalenessSignals": [
352
+ "workflow-requests-version"
353
+ ],
354
+ "decision": "warranted",
355
+ "reason": "Verdict-bearing required gate: it compares committed thresholds against measured coverage and posts a red check. A copy predating a threshold-semantics change enforces the old comparison and its red is believed — the precise harm CodySwannGT/lisa#3477 measured on the work-item gate. The artifact exports no contract version yet, so closing this needs the artifact half authored first; recorded as an open obligation rather than exempted.",
264
356
  "lanes": [
265
357
  "rails/copy-overwrite",
266
358
  "typescript/copy-overwrite"
267
359
  ],
268
- "detail": "`quality-rails.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/check-threshold-ratchet.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (rails/copy-overwrite, typescript/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read is unguarded, so an absent path fails the job loudly. Visible, which makes it the better of the two failures."
360
+ "detail": "`quality-rails.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/check-threshold-ratchet.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (rails/copy-overwrite, typescript/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. No existence test guards the read, which is ALL this scan examined of the step's control flow: it did not read anything that could absorb the failure. An absent path most likely fails the job loudly — the better of the two failures, because it is visible — but that is inferred from the missing guard, NOT MEASURED. The step's text does carry `else-branch`, `exit-zero`, `exit-nonzero`, `error-annotation` — located in the step, deliberately NOT related to this read, and enough to make \"it skips silently\" a claim to check rather than assume. STALENESS (a separate dimension from the delivery verdict above): `no-probe`. Neither an existence test nor a version probe bears on this read, so nothing here distinguishes a current artifact from an absent or a superseded one. Tokens found: `workflow-requests-version`. `workflow-requests-version` is workflow-scoped — it does not say THIS step asks."
269
361
  },
270
362
  {
271
363
  "key": "quality-rails.yml::scripts/lisa-mutation.sh",
@@ -275,10 +367,21 @@
275
367
  "verdict": "apply-lagged",
276
368
  "remedy": "run-lisa-apply",
277
369
  "guarded": true,
370
+ "handling": [
371
+ "exit-zero",
372
+ "exit-nonzero",
373
+ "error-annotation"
374
+ ],
375
+ "detection": "existence-only",
376
+ "stalenessSignals": [
377
+ "workflow-requests-version"
378
+ ],
379
+ "decision": "not-needed",
380
+ "reason": "A runner, not a judge. The gate's verdict is mutant's exit code, and what it runs is read from the project's own `mutation.gate.yml` and `.mutant.yml`; this script's own logic decides whether the gate is enabled and what ref to diff against, both of which come from configuration it does not own. A superseded copy runs the wrong subjects loudly rather than returning a wrong verdict quietly.",
278
381
  "lanes": [
279
382
  "rails/copy-contents"
280
383
  ],
281
- "detail": "`quality-rails.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/lisa-mutation.sh` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (rails/copy-contents). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read is guarded by an existence test, so an absent path SKIPS rather than fails — the step posts no context, and an absent required context is not a red one. Nothing reads as broken."
384
+ "detail": "`quality-rails.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/lisa-mutation.sh` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (rails/copy-contents). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read sits behind an existence test, which is ALL this scan examined of the step's control flow: it did not read the test's other branch, any fallback, any explicit `exit`, or any verification of the step's output. Whether an absent path skips quietly, falls back, or fails loudly is therefore NOT MEASURED read the step before concluding it proves nothing. The shape worth ruling out is the silent one, where a skip posts no context and an absent required context is not a red one. The step's text does carry `exit-zero`, `exit-nonzero`, `error-annotation` — located in the step, deliberately NOT related to this read, and enough to make \"it skips silently\" a claim to check rather than assume. STALENESS (a separate dimension from the delivery verdict above): `existence-only`. An existence test and no version probe: this coupling can see that the artifact is MISSING and cannot see that it is OLD. A present copy of any vintage runs, and its verdict is believed. Tokens found: `workflow-requests-version`. `workflow-requests-version` is workflow-scoped — it does not say THIS step asks."
282
385
  },
283
386
  {
284
387
  "key": "quality-rails.yml::scripts/lisa-scratch-run.sh",
@@ -288,10 +391,21 @@
288
391
  "verdict": "apply-lagged",
289
392
  "remedy": "run-lisa-apply",
290
393
  "guarded": true,
394
+ "handling": [
395
+ "exit-zero",
396
+ "exit-nonzero",
397
+ "error-annotation"
398
+ ],
399
+ "detection": "existence-only",
400
+ "stalenessSignals": [
401
+ "workflow-requests-version"
402
+ ],
403
+ "decision": "not-needed",
404
+ "reason": "A supervisor that hosts a verdict rather than computing one: it owns run-scoped scratch and cleanup around whatever it wraps. Nothing it does can turn a passing suite red or a failing one green — a superseded copy misplaces or fails to reap a scratch directory, which surfaces as its own visible failure rather than as a believed verdict.",
291
405
  "lanes": [
292
406
  "rails/copy-overwrite"
293
407
  ],
294
- "detail": "`quality-rails.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/lisa-scratch-run.sh` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (rails/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read is guarded by an existence test, so an absent path SKIPS rather than fails — the step posts no context, and an absent required context is not a red one. Nothing reads as broken."
408
+ "detail": "`quality-rails.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/lisa-scratch-run.sh` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (rails/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read sits behind an existence test, which is ALL this scan examined of the step's control flow: it did not read the test's other branch, any fallback, any explicit `exit`, or any verification of the step's output. Whether an absent path skips quietly, falls back, or fails loudly is therefore NOT MEASURED read the step before concluding it proves nothing. The shape worth ruling out is the silent one, where a skip posts no context and an absent required context is not a red one. The step's text does carry `exit-zero`, `exit-nonzero`, `error-annotation` — located in the step, deliberately NOT related to this read, and enough to make \"it skips silently\" a claim to check rather than assume. STALENESS (a separate dimension from the delivery verdict above): `existence-only`. An existence test and no version probe: this coupling can see that the artifact is MISSING and cannot see that it is OLD. A present copy of any vintage runs, and its verdict is believed. Tokens found: `workflow-requests-version`. `workflow-requests-version` is workflow-scoped — it does not say THIS step asks."
295
409
  },
296
410
  {
297
411
  "key": "quality-rails.yml::scripts/lisa-work-item.mjs",
@@ -301,10 +415,26 @@
301
415
  "verdict": "apply-lagged",
302
416
  "remedy": "run-lisa-apply",
303
417
  "guarded": true,
418
+ "handling": [
419
+ "else-branch",
420
+ "exit-zero",
421
+ "exit-nonzero",
422
+ "error-annotation",
423
+ "notice-annotation"
424
+ ],
425
+ "detection": "version-handshake",
426
+ "stalenessSignals": [
427
+ "artifact-declares-version",
428
+ "artifact-answers-version",
429
+ "step-requests-version",
430
+ "workflow-requests-version"
431
+ ],
432
+ "decision": "handshake",
433
+ "reason": null,
304
434
  "lanes": [
305
435
  "all/copy-overwrite"
306
436
  ],
307
- "detail": "`quality-rails.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/lisa-work-item.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (all/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read is guarded by an existence test, so an absent path SKIPS rather than fails — the step posts no context, and an absent required context is not a red one. Nothing reads as broken."
437
+ "detail": "`quality-rails.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/lisa-work-item.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (all/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read sits behind an existence test, which is ALL this scan examined of the step's control flow: it did not read the test's other branch, any fallback, any explicit `exit`, or any verification of the step's output. Whether an absent path skips quietly, falls back, or fails loudly is therefore NOT MEASURED read the step before concluding it proves nothing. The shape worth ruling out is the silent one, where a skip posts no context and an absent required context is not a red one. The step's text does carry `else-branch`, `exit-zero`, `exit-nonzero`, `error-annotation`, `notice-annotation` — located in the step, deliberately NOT related to this read, and enough to make \"it skips silently\" a claim to check rather than assume. STALENESS (a separate dimension from the delivery verdict above): `version-handshake`. The delivered artifact answers a contract version and the workflow asks for one, so a copy too old to speak the same contract is NAMED rather than silently run. Tokens found: `artifact-declares-version`, `artifact-answers-version`, `step-requests-version`, `workflow-requests-version`. `workflow-requests-version` is workflow-scoped — it does not say THIS step asks."
308
438
  },
309
439
  {
310
440
  "key": "quality.yml::scripts/check-e2e-coverage.mjs",
@@ -314,10 +444,22 @@
314
444
  "verdict": "apply-lagged",
315
445
  "remedy": "run-lisa-apply",
316
446
  "guarded": true,
447
+ "handling": [
448
+ "else-branch",
449
+ "exit-nonzero",
450
+ "error-annotation",
451
+ "notice-annotation"
452
+ ],
453
+ "detection": "existence-only",
454
+ "stalenessSignals": [
455
+ "workflow-requests-version"
456
+ ],
457
+ "decision": "warranted",
458
+ "reason": "Verdict-bearing required gate: it computes route coverage against a configured floor and posts a red check every reader believes. A copy predating a change to how routes are enumerated reports a coverage number derived from superseded logic, with nothing in the output naming its vintage. The artifact exports no contract version yet, so closing this needs the artifact half authored first; recorded as an open obligation rather than exempted.",
317
459
  "lanes": [
318
460
  "expo/copy-overwrite"
319
461
  ],
320
- "detail": "`quality.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/check-e2e-coverage.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (expo/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read is guarded by an existence test, so an absent path SKIPS rather than fails — the step posts no context, and an absent required context is not a red one. Nothing reads as broken."
462
+ "detail": "`quality.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/check-e2e-coverage.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (expo/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read sits behind an existence test, which is ALL this scan examined of the step's control flow: it did not read the test's other branch, any fallback, any explicit `exit`, or any verification of the step's output. Whether an absent path skips quietly, falls back, or fails loudly is therefore NOT MEASURED read the step before concluding it proves nothing. The shape worth ruling out is the silent one, where a skip posts no context and an absent required context is not a red one. The step's text does carry `else-branch`, `exit-nonzero`, `error-annotation`, `notice-annotation` — located in the step, deliberately NOT related to this read, and enough to make \"it skips silently\" a claim to check rather than assume. STALENESS (a separate dimension from the delivery verdict above): `existence-only`. An existence test and no version probe: this coupling can see that the artifact is MISSING and cannot see that it is OLD. A present copy of any vintage runs, and its verdict is believed. Tokens found: `workflow-requests-version`. `workflow-requests-version` is workflow-scoped — it does not say THIS step asks."
321
463
  },
322
464
  {
323
465
  "key": "quality.yml::scripts/check-learnings-budget.ts",
@@ -327,8 +469,20 @@
327
469
  "verdict": "undelivered",
328
470
  "remedy": "author-the-artifact",
329
471
  "guarded": true,
472
+ "handling": [
473
+ "else-branch",
474
+ "exit-nonzero",
475
+ "error-annotation",
476
+ "failure-suppression"
477
+ ],
478
+ "detection": "unchecked",
479
+ "stalenessSignals": [
480
+ "workflow-requests-version"
481
+ ],
482
+ "decision": "not-needed",
483
+ "reason": "Unreachable outside this repository, and ratified above on that ground: the step tests for two paths that co-exist only here, and every consumer takes the else arm and runs the prover from the PACKAGE channel, whose vintage is their declared dependency version. There is no delivered artifact at this path for a consumer to hold a stale copy of — which is why the detection is `unchecked` rather than a measured negative.",
330
484
  "lanes": [],
331
- "detail": "`quality.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/check-learnings-budget.ts` from the CALLER's tree, and Lisa ships no such path in any delivery lane — no apply and no bump ever produces it. Either the consumer authors it or this step proves nothing wherever it is absent. The read is guarded by an existence test, so an absent path SKIPS rather than fails — the step posts no context, and an absent required context is not a red one. Nothing reads as broken."
485
+ "detail": "`quality.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/check-learnings-budget.ts` from the CALLER's tree, and Lisa ships no such path in any delivery lane — no apply and no bump ever produces it. Either the consumer authors it, or whatever the step does where the path is missing runs instead — and that branch is the part this scan does not read. The read sits behind an existence test, which is ALL this scan examined of the step's control flow: it did not read the test's other branch, any fallback, any explicit `exit`, or any verification of the step's output. Whether an absent path skips quietly, falls back, or fails loudly is therefore NOT MEASURED read the step before concluding it proves nothing. The shape worth ruling out is the silent one, where a skip posts no context and an absent required context is not a red one. The step's text does carry `else-branch`, `exit-nonzero`, `error-annotation`, `failure-suppression` — located in the step, deliberately NOT related to this read, and enough to make \"it skips silently\" a claim to check rather than assume. STALENESS (a separate dimension from the delivery verdict above): `unchecked`. Lisa delivers nothing at this path, so there is no artifact to ask whether it could answer a version. The staleness half is UNKNOWN here — not current, and not probe-less. Tokens found: `workflow-requests-version`. `workflow-requests-version` is workflow-scoped — it does not say THIS step asks."
332
486
  },
333
487
  {
334
488
  "key": "quality.yml::scripts/check-skipped-required-checks.mjs",
@@ -338,10 +492,21 @@
338
492
  "verdict": "apply-lagged",
339
493
  "remedy": "run-lisa-apply",
340
494
  "guarded": false,
495
+ "handling": [
496
+ "exit-zero",
497
+ "exit-nonzero",
498
+ "error-annotation"
499
+ ],
500
+ "detection": "no-probe",
501
+ "stalenessSignals": [
502
+ "workflow-requests-version"
503
+ ],
504
+ "decision": "warranted",
505
+ "reason": "Verdict-bearing required gate: it compares skip tokens against the ruleset's required contexts, and the step states that its absence is a failure precisely because a skipped required check reads as satisfied. A superseded copy comparing against a stale notion of the required set is the same false green arriving by the other door. The artifact exports no contract version yet; recorded as an open obligation rather than exempted.",
341
506
  "lanes": [
342
507
  "typescript/copy-overwrite"
343
508
  ],
344
- "detail": "`quality.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/check-skipped-required-checks.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (typescript/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read is unguarded, so an absent path fails the job loudly. Visible, which makes it the better of the two failures."
509
+ "detail": "`quality.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/check-skipped-required-checks.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (typescript/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. No existence test guards the read, which is ALL this scan examined of the step's control flow: it did not read anything that could absorb the failure. An absent path most likely fails the job loudly — the better of the two failures, because it is visible — but that is inferred from the missing guard, NOT MEASURED. The step's text does carry `exit-zero`, `exit-nonzero`, `error-annotation` — located in the step, deliberately NOT related to this read, and enough to make \"it skips silently\" a claim to check rather than assume. STALENESS (a separate dimension from the delivery verdict above): `no-probe`. Neither an existence test nor a version probe bears on this read, so nothing here distinguishes a current artifact from an absent or a superseded one. Tokens found: `workflow-requests-version`. `workflow-requests-version` is workflow-scoped — it does not say THIS step asks."
345
510
  },
346
511
  {
347
512
  "key": "quality.yml::scripts/check-state-classification.mjs",
@@ -351,10 +516,22 @@
351
516
  "verdict": "apply-lagged",
352
517
  "remedy": "run-lisa-apply",
353
518
  "guarded": true,
519
+ "handling": [
520
+ "else-branch",
521
+ "exit-nonzero",
522
+ "error-annotation",
523
+ "notice-annotation"
524
+ ],
525
+ "detection": "existence-only",
526
+ "stalenessSignals": [
527
+ "workflow-requests-version"
528
+ ],
529
+ "decision": "warranted",
530
+ "reason": "Verdict-bearing required gate whose subject is classification itself — it decides which states a change is allowed to leave behind. A copy behind a classification change enforces the superseded taxonomy and names states that no longer mean what it thinks. The artifact exports no contract version yet; recorded as an open obligation rather than exempted.",
354
531
  "lanes": [
355
532
  "all/copy-overwrite"
356
533
  ],
357
- "detail": "`quality.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/check-state-classification.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (all/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read is guarded by an existence test, so an absent path SKIPS rather than fails — the step posts no context, and an absent required context is not a red one. Nothing reads as broken."
534
+ "detail": "`quality.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/check-state-classification.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (all/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read sits behind an existence test, which is ALL this scan examined of the step's control flow: it did not read the test's other branch, any fallback, any explicit `exit`, or any verification of the step's output. Whether an absent path skips quietly, falls back, or fails loudly is therefore NOT MEASURED read the step before concluding it proves nothing. The shape worth ruling out is the silent one, where a skip posts no context and an absent required context is not a red one. The step's text does carry `else-branch`, `exit-nonzero`, `error-annotation`, `notice-annotation` — located in the step, deliberately NOT related to this read, and enough to make \"it skips silently\" a claim to check rather than assume. STALENESS (a separate dimension from the delivery verdict above): `existence-only`. An existence test and no version probe: this coupling can see that the artifact is MISSING and cannot see that it is OLD. A present copy of any vintage runs, and its verdict is believed. Tokens found: `workflow-requests-version`. `workflow-requests-version` is workflow-scoped — it does not say THIS step asks."
358
535
  },
359
536
  {
360
537
  "key": "quality.yml::scripts/check-threshold-ratchet.mjs",
@@ -364,11 +541,23 @@
364
541
  "verdict": "apply-lagged",
365
542
  "remedy": "run-lisa-apply",
366
543
  "guarded": false,
544
+ "handling": [
545
+ "else-branch",
546
+ "exit-zero",
547
+ "exit-nonzero",
548
+ "error-annotation"
549
+ ],
550
+ "detection": "no-probe",
551
+ "stalenessSignals": [
552
+ "workflow-requests-version"
553
+ ],
554
+ "decision": "warranted",
555
+ "reason": "Verdict-bearing required gate, the same artifact and the same exposure as the `quality-rails.yml` entry: a copy predating a threshold-semantics change enforces the old comparison and its red is believed. Closing it once closes both couplings, since they read the same script down two stack lanes. The artifact exports no contract version yet; recorded as an open obligation rather than exempted.",
367
556
  "lanes": [
368
557
  "rails/copy-overwrite",
369
558
  "typescript/copy-overwrite"
370
559
  ],
371
- "detail": "`quality.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/check-threshold-ratchet.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (rails/copy-overwrite, typescript/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read is unguarded, so an absent path fails the job loudly. Visible, which makes it the better of the two failures."
560
+ "detail": "`quality.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/check-threshold-ratchet.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (rails/copy-overwrite, typescript/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. No existence test guards the read, which is ALL this scan examined of the step's control flow: it did not read anything that could absorb the failure. An absent path most likely fails the job loudly — the better of the two failures, because it is visible — but that is inferred from the missing guard, NOT MEASURED. The step's text does carry `else-branch`, `exit-zero`, `exit-nonzero`, `error-annotation` — located in the step, deliberately NOT related to this read, and enough to make \"it skips silently\" a claim to check rather than assume. STALENESS (a separate dimension from the delivery verdict above): `no-probe`. Neither an existence test nor a version probe bears on this read, so nothing here distinguishes a current artifact from an absent or a superseded one. Tokens found: `workflow-requests-version`. `workflow-requests-version` is workflow-scoped — it does not say THIS step asks."
372
561
  },
373
562
  {
374
563
  "key": "quality.yml::scripts/check-verification-coverage.mjs",
@@ -378,10 +567,17 @@
378
567
  "verdict": "apply-lagged",
379
568
  "remedy": "run-lisa-apply",
380
569
  "guarded": false,
570
+ "handling": [],
571
+ "detection": "no-probe",
572
+ "stalenessSignals": [
573
+ "workflow-requests-version"
574
+ ],
575
+ "decision": "warranted",
576
+ "reason": "Verdict-bearing gate over whether shipped work carries its verification evidence. A superseded copy looks for evidence in a shape the repository has moved off and reports a gap that is not there, or misses one that is. The artifact exports no contract version yet; recorded as an open obligation rather than exempted.",
381
577
  "lanes": [
382
578
  "typescript/copy-overwrite"
383
579
  ],
384
- "detail": "`quality.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/check-verification-coverage.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (typescript/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read is unguarded, so an absent path fails the job loudly. Visible, which makes it the better of the two failures."
580
+ "detail": "`quality.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/check-verification-coverage.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (typescript/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. No existence test guards the read, which is ALL this scan examined of the step's control flow: it did not read anything that could absorb the failure. An absent path most likely fails the job loudly — the better of the two failures, because it is visible — but that is inferred from the missing guard, NOT MEASURED. The step's text carries none of the tokens this scan can see (`else-branch`, `exit-zero`, `exit-nonzero`, `error-annotation`, `notice-annotation`, `failure-suppression`), which is a statement about those names and not about the step's behaviour. STALENESS (a separate dimension from the delivery verdict above): `no-probe`. Neither an existence test nor a version probe bears on this read, so nothing here distinguishes a current artifact from an absent or a superseded one. Tokens found: `workflow-requests-version`. `workflow-requests-version` is workflow-scoped — it does not say THIS step asks."
385
581
  },
386
582
  {
387
583
  "key": "quality.yml::scripts/generate-nightly-e2e-guard-certificate.mjs",
@@ -391,8 +587,18 @@
391
587
  "verdict": "undelivered",
392
588
  "remedy": "author-the-artifact",
393
589
  "guarded": true,
590
+ "handling": [
591
+ "exit-zero",
592
+ "notice-annotation"
593
+ ],
594
+ "detection": "unchecked",
595
+ "stalenessSignals": [
596
+ "workflow-requests-version"
597
+ ],
598
+ "decision": "not-needed",
599
+ "reason": "Unreachable outside this repository, and ratified above on that ground: both reusable jobs require this repository before the step can start, and the run body repeats the guard. No consumer ever reads this path from their own tree, so there is no copy of it anywhere to go stale — which is why the detection is `unchecked` rather than a measured negative.",
394
600
  "lanes": [],
395
- "detail": "`quality.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/generate-nightly-e2e-guard-certificate.mjs` from the CALLER's tree, and Lisa ships no such path in any delivery lane — no apply and no bump ever produces it. Either the consumer authors it or this step proves nothing wherever it is absent. The read is guarded by an existence test, so an absent path SKIPS rather than fails — the step posts no context, and an absent required context is not a red one. Nothing reads as broken."
601
+ "detail": "`quality.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/generate-nightly-e2e-guard-certificate.mjs` from the CALLER's tree, and Lisa ships no such path in any delivery lane — no apply and no bump ever produces it. Either the consumer authors it, or whatever the step does where the path is missing runs instead — and that branch is the part this scan does not read. The read sits behind an existence test, which is ALL this scan examined of the step's control flow: it did not read the test's other branch, any fallback, any explicit `exit`, or any verification of the step's output. Whether an absent path skips quietly, falls back, or fails loudly is therefore NOT MEASURED read the step before concluding it proves nothing. The shape worth ruling out is the silent one, where a skip posts no context and an absent required context is not a red one. The step's text does carry `exit-zero`, `notice-annotation` — located in the step, deliberately NOT related to this read, and enough to make \"it skips silently\" a claim to check rather than assume. STALENESS (a separate dimension from the delivery verdict above): `unchecked`. Lisa delivers nothing at this path, so there is no artifact to ask whether it could answer a version. The staleness half is UNKNOWN here — not current, and not probe-less. Tokens found: `workflow-requests-version`. `workflow-requests-version` is workflow-scoped — it does not say THIS step asks."
396
602
  },
397
603
  {
398
604
  "key": "quality.yml::scripts/lisa-floor-collisions.mjs",
@@ -402,10 +608,20 @@
402
608
  "verdict": "apply-lagged",
403
609
  "remedy": "run-lisa-apply",
404
610
  "guarded": false,
611
+ "handling": [
612
+ "exit-nonzero",
613
+ "error-annotation"
614
+ ],
615
+ "detection": "no-probe",
616
+ "stalenessSignals": [
617
+ "workflow-requests-version"
618
+ ],
619
+ "decision": "warranted",
620
+ "reason": "Verdict-bearing gate: it decides whether two declared floors collide and fails the job when they do. A copy predating a change to how a floor is spelled can miss a live collision, and a missed collision is silent by construction. The artifact exports no contract version yet; recorded as an open obligation rather than exempted.",
405
621
  "lanes": [
406
622
  "all/copy-overwrite"
407
623
  ],
408
- "detail": "`quality.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/lisa-floor-collisions.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (all/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read is unguarded, so an absent path fails the job loudly. Visible, which makes it the better of the two failures."
624
+ "detail": "`quality.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/lisa-floor-collisions.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (all/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. No existence test guards the read, which is ALL this scan examined of the step's control flow: it did not read anything that could absorb the failure. An absent path most likely fails the job loudly — the better of the two failures, because it is visible — but that is inferred from the missing guard, NOT MEASURED. The step's text does carry `exit-nonzero`, `error-annotation` — located in the step, deliberately NOT related to this read, and enough to make \"it skips silently\" a claim to check rather than assume. STALENESS (a separate dimension from the delivery verdict above): `no-probe`. Neither an existence test nor a version probe bears on this read, so nothing here distinguishes a current artifact from an absent or a superseded one. Tokens found: `workflow-requests-version`. `workflow-requests-version` is workflow-scoped — it does not say THIS step asks."
409
625
  },
410
626
  {
411
627
  "key": "quality.yml::scripts/lisa-work-item.mjs",
@@ -415,10 +631,26 @@
415
631
  "verdict": "apply-lagged",
416
632
  "remedy": "run-lisa-apply",
417
633
  "guarded": true,
634
+ "handling": [
635
+ "else-branch",
636
+ "exit-zero",
637
+ "exit-nonzero",
638
+ "error-annotation",
639
+ "notice-annotation"
640
+ ],
641
+ "detection": "version-handshake",
642
+ "stalenessSignals": [
643
+ "artifact-declares-version",
644
+ "artifact-answers-version",
645
+ "step-requests-version",
646
+ "workflow-requests-version"
647
+ ],
648
+ "decision": "handshake",
649
+ "reason": null,
418
650
  "lanes": [
419
651
  "all/copy-overwrite"
420
652
  ],
421
- "detail": "`quality.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/lisa-work-item.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (all/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read is guarded by an existence test, so an absent path SKIPS rather than fails — the step posts no context, and an absent required context is not a red one. Nothing reads as broken."
653
+ "detail": "`quality.yml` is delivered at `@main`, so this step is live in every consumer on their next run. It reads `scripts/lisa-work-item.mjs` from the CALLER's tree with no package-relative candidate, and Lisa delivers that path on the `lisa apply` channel (all/copy-overwrite). The two halves land in the wrong order: this step is live everywhere immediately, the file it needs is live only where somebody applied. The read sits behind an existence test, which is ALL this scan examined of the step's control flow: it did not read the test's other branch, any fallback, any explicit `exit`, or any verification of the step's output. Whether an absent path skips quietly, falls back, or fails loudly is therefore NOT MEASURED read the step before concluding it proves nothing. The shape worth ruling out is the silent one, where a skip posts no context and an absent required context is not a red one. The step's text does carry `else-branch`, `exit-zero`, `exit-nonzero`, `error-annotation`, `notice-annotation` — located in the step, deliberately NOT related to this read, and enough to make \"it skips silently\" a claim to check rather than assume. STALENESS (a separate dimension from the delivery verdict above): `version-handshake`. The delivered artifact answers a contract version and the workflow asks for one, so a copy too old to speak the same contract is NAMED rather than silently run. Tokens found: `artifact-declares-version`, `artifact-answers-version`, `step-requests-version`, `workflow-requests-version`. `workflow-requests-version` is workflow-scoped — it does not say THIS step asks."
422
654
  }
423
655
  ]
424
656
  }