@codyswann/lisa 4.55.2 → 4.55.4

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 (395) hide show
  1. package/all/copy-overwrite/scripts/check-orphaned-branches.mjs +49 -13
  2. package/all/copy-overwrite/scripts/lisa-enforcement-fallback.sh +9 -1
  3. package/all/copy-overwrite/scripts/lisa-hooks/block-blind-automerge.sh +10 -5
  4. package/all/copy-overwrite/scripts/lisa-hooks/block-direct-issue-create.sh +4 -0
  5. package/all/copy-overwrite/scripts/lisa-hooks/block-managed-file-edits.sh +73 -2
  6. package/all/copy-overwrite/scripts/lisa-hooks/guard-dedupe.bash +63 -29
  7. package/all/copy-overwrite/scripts/lisa-hooks/parity-safety-net.sh +2 -1
  8. package/all/copy-overwrite/scripts/lisa-hooks/worktree-binding-guard.sh +2 -1
  9. package/all/copy-overwrite/scripts/lisa-run-gates.mjs +7 -2
  10. package/all/copy-overwrite/scripts/lisa-work-item.mjs +50 -14
  11. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  12. package/dist/core/lisa-owned-hash-ledger.js +36 -0
  13. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  14. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  15. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  16. package/dist/core/upstream-evidence-manifest.js +92 -80
  17. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  18. package/dist/opencode/plugin-templates/block-managed-file-edits.sh +76 -2
  19. package/dist/opencode/plugin-templates/block-no-verify.sh +3 -0
  20. package/dist/opencode/plugin-templates/guard-dedupe.bash +66 -29
  21. package/dist/opencode/plugin-templates/parity-safety-net-heredoc.py +3 -0
  22. package/dist/opencode/plugin-templates/parity-safety-net.sh +5 -1
  23. package/dist/opencode/support-file-resolver.d.ts.map +1 -1
  24. package/dist/opencode/support-file-resolver.js +3 -1
  25. package/dist/opencode/support-file-resolver.js.map +1 -1
  26. package/expo/copy-overwrite/plugins/withAndroidSplashNoClientExit.js +23 -21
  27. package/expo/create-only/.github/required-checks.json +1 -1
  28. package/nestjs/create-only/.github/required-checks.json +1 -1
  29. package/package.json +4 -4
  30. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  31. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  32. package/plugins/lisa/.codex-plugin/skills/lisa-github-build-intake/SKILL.md +38 -15
  33. package/plugins/lisa/.codex-plugin/skills/lisa-github-write-issue/SKILL.md +15 -1
  34. package/plugins/lisa/.codex-plugin/skills/lisa-jira-build-intake/SKILL.md +37 -13
  35. package/plugins/lisa/.codex-plugin/skills/lisa-jira-write-ticket/SKILL.md +15 -1
  36. package/plugins/lisa/.codex-plugin/skills/lisa-linear-access/SKILL.md +56 -7
  37. package/plugins/lisa/.codex-plugin/skills/lisa-linear-build-intake/SKILL.md +36 -11
  38. package/plugins/lisa/.codex-plugin/skills/lisa-linear-prd-intake/SKILL.md +12 -2
  39. package/plugins/lisa/.codex-plugin/skills/lisa-linear-validate-issue/SKILL.md +1 -18
  40. package/plugins/lisa/.codex-plugin/skills/lisa-linear-verify/SKILL.md +0 -17
  41. package/plugins/lisa/.codex-plugin/skills/lisa-linear-write-issue/SKILL.md +18 -35
  42. package/plugins/lisa/.codex-plugin/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
  43. package/plugins/lisa/.codex-plugin/skills/lisa-repair-intake/SKILL.md +66 -12
  44. package/plugins/lisa/.codex-plugin/skills/lisa-rework-triage/SKILL.md +2 -1
  45. package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/providers.mjs +2 -1
  46. package/plugins/lisa/.codex-plugin/skills/lisa-setup-linear/SKILL.md +1 -1
  47. package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/scripts/preflight-tools.mjs +7 -2
  48. package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +11 -4
  49. package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/scripts/toolchain.mjs +17 -5
  50. package/plugins/lisa/.codex-plugin/skills/lisa-track/SKILL.md +32 -4
  51. package/plugins/lisa/.codex-plugin/skills/lisa-tracker-build-intake/SKILL.md +15 -1
  52. package/plugins/lisa/hooks/block-blind-automerge.sh +13 -5
  53. package/plugins/lisa/hooks/block-direct-issue-create.sh +7 -0
  54. package/plugins/lisa/hooks/block-instruction-file-edits.sh +3 -0
  55. package/plugins/lisa/hooks/block-managed-file-edits.sh +76 -2
  56. package/plugins/lisa/hooks/block-no-verify.sh +3 -0
  57. package/plugins/lisa/hooks/block-shell-json-parsing.sh +3 -0
  58. package/plugins/lisa/hooks/guard-dedupe.bash +66 -29
  59. package/plugins/lisa/hooks/parity-safety-net-heredoc.py +3 -0
  60. package/plugins/lisa/hooks/parity-safety-net.sh +5 -1
  61. package/plugins/lisa/hooks/worktree-binding-guard.mjs +3 -0
  62. package/plugins/lisa/hooks/worktree-binding-guard.sh +5 -1
  63. package/plugins/lisa/rules/eager/00-rule-index.md +1 -0
  64. package/plugins/lisa/rules/eager/base-rules.md +3 -1
  65. package/plugins/lisa/rules/eager/withdrawn-rulings.md +14 -3
  66. package/plugins/lisa/rules/reference/automation-runbook-contract.md +1 -1
  67. package/plugins/lisa/rules/reference/bdd-e2e-coverage.md +1 -1
  68. package/plugins/lisa/rules/reference/blocker-containment.md +3 -3
  69. package/plugins/lisa/rules/reference/claim-archaeology.md +1 -1
  70. package/plugins/lisa/rules/reference/claim-evidence-mapping.md +1 -1
  71. package/plugins/lisa/rules/reference/claim-time-guards.md +1 -1
  72. package/plugins/lisa/rules/reference/control-reachability.md +1 -1
  73. package/plugins/lisa/rules/reference/convergent-review.md +1 -1
  74. package/plugins/lisa/rules/reference/credential-substrate-precedence.md +1 -1
  75. package/plugins/lisa/rules/reference/dependency-decision-records.md +1 -1
  76. package/plugins/lisa/rules/reference/dependency-internalization-kit.md +1 -1
  77. package/plugins/lisa/rules/reference/dependency-trust-classes.md +1 -1
  78. package/plugins/lisa/rules/reference/deployed-state-readback.md +1 -1
  79. package/plugins/lisa/rules/reference/derived-branch-plan.md +1 -1
  80. package/plugins/lisa/rules/reference/design-source-of-truth.md +1 -1
  81. package/plugins/lisa/rules/reference/design-value-binding.md +1 -1
  82. package/plugins/lisa/rules/reference/documentation-source-paths.md +1 -1
  83. package/plugins/lisa/rules/reference/leaf-only-lifecycle.md +1 -1
  84. package/plugins/lisa/rules/reference/observability-audit.md +1 -1
  85. package/plugins/lisa/rules/reference/prd-definition-of-ready.md +1 -1
  86. package/plugins/lisa/rules/reference/prd-lifecycle-rollup.md +1 -1
  87. package/plugins/lisa/rules/reference/pre-flight-autofill.md +1 -1
  88. package/plugins/lisa/rules/reference/promotion-contract.md +1 -1
  89. package/plugins/lisa/rules/reference/readiness-rubric.md +1 -1
  90. package/plugins/lisa/rules/reference/ready-role-filing.md +37 -1
  91. package/plugins/lisa/rules/reference/rejection-detection.md +1 -1
  92. package/plugins/lisa/rules/reference/repo-scope-split.md +9 -10
  93. package/plugins/lisa/rules/reference/reset-seed-coverage.md +1 -1
  94. package/plugins/lisa/rules/reference/usage-accounting.md +1 -1
  95. package/plugins/lisa/rules/reference/work-item-definition-of-ready.md +1 -1
  96. package/plugins/lisa/scripts/intake-blocker-reprobe.mjs +85 -17
  97. package/plugins/lisa/scripts/qa-signal-lifecycle.mjs +5 -2
  98. package/plugins/lisa/skills/lisa-github-build-intake/SKILL.md +38 -15
  99. package/plugins/lisa/skills/lisa-github-write-issue/SKILL.md +15 -1
  100. package/plugins/lisa/skills/lisa-jira-build-intake/SKILL.md +37 -13
  101. package/plugins/lisa/skills/lisa-jira-write-ticket/SKILL.md +15 -1
  102. package/plugins/lisa/skills/lisa-linear-access/SKILL.md +56 -7
  103. package/plugins/lisa/skills/lisa-linear-build-intake/SKILL.md +36 -11
  104. package/plugins/lisa/skills/lisa-linear-prd-intake/SKILL.md +12 -2
  105. package/plugins/lisa/skills/lisa-linear-validate-issue/SKILL.md +1 -18
  106. package/plugins/lisa/skills/lisa-linear-verify/SKILL.md +0 -17
  107. package/plugins/lisa/skills/lisa-linear-write-issue/SKILL.md +18 -35
  108. package/plugins/lisa/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
  109. package/plugins/lisa/skills/lisa-repair-intake/SKILL.md +66 -12
  110. package/plugins/lisa/skills/lisa-rework-triage/SKILL.md +2 -1
  111. package/plugins/lisa/skills/lisa-secrets-access/scripts/providers.mjs +2 -1
  112. package/plugins/lisa/skills/lisa-setup-linear/SKILL.md +1 -1
  113. package/plugins/lisa/skills/lisa-setup-remote-env/scripts/preflight-tools.mjs +7 -2
  114. package/plugins/lisa/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +11 -4
  115. package/plugins/lisa/skills/lisa-setup-remote-env/scripts/toolchain.mjs +17 -5
  116. package/plugins/lisa/skills/lisa-track/SKILL.md +32 -4
  117. package/plugins/lisa/skills/lisa-tracker-build-intake/SKILL.md +15 -1
  118. package/plugins/lisa-agy/hooks/block-blind-automerge.sh +13 -5
  119. package/plugins/lisa-agy/hooks/block-direct-issue-create.sh +7 -0
  120. package/plugins/lisa-agy/hooks/block-instruction-file-edits.sh +3 -0
  121. package/plugins/lisa-agy/hooks/block-managed-file-edits.sh +76 -2
  122. package/plugins/lisa-agy/hooks/block-shell-json-parsing.sh +3 -0
  123. package/plugins/lisa-agy/hooks/guard-dedupe.bash +66 -29
  124. package/plugins/lisa-agy/hooks/parity-safety-net-heredoc.py +3 -0
  125. package/plugins/lisa-agy/hooks/parity-safety-net.sh +5 -1
  126. package/plugins/lisa-agy/plugin.json +1 -1
  127. package/plugins/lisa-agy/scripts/intake-blocker-reprobe.mjs +85 -17
  128. package/plugins/lisa-agy/scripts/qa-signal-lifecycle.mjs +5 -2
  129. package/plugins/lisa-agy/skills/lisa-github-build-intake/SKILL.md +38 -15
  130. package/plugins/lisa-agy/skills/lisa-github-write-issue/SKILL.md +15 -1
  131. package/plugins/lisa-agy/skills/lisa-jira-build-intake/SKILL.md +37 -13
  132. package/plugins/lisa-agy/skills/lisa-jira-write-ticket/SKILL.md +15 -1
  133. package/plugins/lisa-agy/skills/lisa-linear-access/SKILL.md +56 -7
  134. package/plugins/lisa-agy/skills/lisa-linear-build-intake/SKILL.md +36 -11
  135. package/plugins/lisa-agy/skills/lisa-linear-prd-intake/SKILL.md +12 -2
  136. package/plugins/lisa-agy/skills/lisa-linear-validate-issue/SKILL.md +1 -18
  137. package/plugins/lisa-agy/skills/lisa-linear-verify/SKILL.md +0 -17
  138. package/plugins/lisa-agy/skills/lisa-linear-write-issue/SKILL.md +18 -35
  139. package/plugins/lisa-agy/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
  140. package/plugins/lisa-agy/skills/lisa-repair-intake/SKILL.md +66 -12
  141. package/plugins/lisa-agy/skills/lisa-rework-triage/SKILL.md +2 -1
  142. package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/providers.mjs +2 -1
  143. package/plugins/lisa-agy/skills/lisa-setup-linear/SKILL.md +1 -1
  144. package/plugins/lisa-agy/skills/lisa-setup-remote-env/scripts/preflight-tools.mjs +7 -2
  145. package/plugins/lisa-agy/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +11 -4
  146. package/plugins/lisa-agy/skills/lisa-setup-remote-env/scripts/toolchain.mjs +17 -5
  147. package/plugins/lisa-agy/skills/lisa-track/SKILL.md +32 -4
  148. package/plugins/lisa-agy/skills/lisa-tracker-build-intake/SKILL.md +15 -1
  149. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  150. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  151. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  152. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  153. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  154. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  155. package/plugins/lisa-copilot/hooks/block-blind-automerge.sh +13 -5
  156. package/plugins/lisa-copilot/hooks/block-direct-issue-create.sh +7 -0
  157. package/plugins/lisa-copilot/hooks/block-instruction-file-edits.sh +3 -0
  158. package/plugins/lisa-copilot/hooks/block-managed-file-edits.sh +76 -2
  159. package/plugins/lisa-copilot/hooks/block-no-verify.sh +3 -0
  160. package/plugins/lisa-copilot/hooks/block-shell-json-parsing.sh +3 -0
  161. package/plugins/lisa-copilot/hooks/guard-dedupe.bash +66 -29
  162. package/plugins/lisa-copilot/hooks/parity-safety-net-heredoc.py +3 -0
  163. package/plugins/lisa-copilot/hooks/parity-safety-net.sh +5 -1
  164. package/plugins/lisa-copilot/hooks/worktree-binding-guard.mjs +3 -0
  165. package/plugins/lisa-copilot/hooks/worktree-binding-guard.sh +5 -1
  166. package/plugins/lisa-copilot/rules/eager/00-rule-index.md +1 -0
  167. package/plugins/lisa-copilot/rules/eager/base-rules.md +3 -1
  168. package/plugins/lisa-copilot/rules/eager/withdrawn-rulings.md +14 -3
  169. package/plugins/lisa-copilot/rules/reference/automation-runbook-contract.md +1 -1
  170. package/plugins/lisa-copilot/rules/reference/bdd-e2e-coverage.md +1 -1
  171. package/plugins/lisa-copilot/rules/reference/blocker-containment.md +3 -3
  172. package/plugins/lisa-copilot/rules/reference/claim-archaeology.md +1 -1
  173. package/plugins/lisa-copilot/rules/reference/claim-evidence-mapping.md +1 -1
  174. package/plugins/lisa-copilot/rules/reference/claim-time-guards.md +1 -1
  175. package/plugins/lisa-copilot/rules/reference/control-reachability.md +1 -1
  176. package/plugins/lisa-copilot/rules/reference/convergent-review.md +1 -1
  177. package/plugins/lisa-copilot/rules/reference/credential-substrate-precedence.md +1 -1
  178. package/plugins/lisa-copilot/rules/reference/dependency-decision-records.md +1 -1
  179. package/plugins/lisa-copilot/rules/reference/dependency-internalization-kit.md +1 -1
  180. package/plugins/lisa-copilot/rules/reference/dependency-trust-classes.md +1 -1
  181. package/plugins/lisa-copilot/rules/reference/deployed-state-readback.md +1 -1
  182. package/plugins/lisa-copilot/rules/reference/derived-branch-plan.md +1 -1
  183. package/plugins/lisa-copilot/rules/reference/design-source-of-truth.md +1 -1
  184. package/plugins/lisa-copilot/rules/reference/design-value-binding.md +1 -1
  185. package/plugins/lisa-copilot/rules/reference/documentation-source-paths.md +1 -1
  186. package/plugins/lisa-copilot/rules/reference/leaf-only-lifecycle.md +1 -1
  187. package/plugins/lisa-copilot/rules/reference/observability-audit.md +1 -1
  188. package/plugins/lisa-copilot/rules/reference/prd-definition-of-ready.md +1 -1
  189. package/plugins/lisa-copilot/rules/reference/prd-lifecycle-rollup.md +1 -1
  190. package/plugins/lisa-copilot/rules/reference/pre-flight-autofill.md +1 -1
  191. package/plugins/lisa-copilot/rules/reference/promotion-contract.md +1 -1
  192. package/plugins/lisa-copilot/rules/reference/readiness-rubric.md +1 -1
  193. package/plugins/lisa-copilot/rules/reference/ready-role-filing.md +37 -1
  194. package/plugins/lisa-copilot/rules/reference/rejection-detection.md +1 -1
  195. package/plugins/lisa-copilot/rules/reference/repo-scope-split.md +9 -10
  196. package/plugins/lisa-copilot/rules/reference/reset-seed-coverage.md +1 -1
  197. package/plugins/lisa-copilot/rules/reference/usage-accounting.md +1 -1
  198. package/plugins/lisa-copilot/rules/reference/work-item-definition-of-ready.md +1 -1
  199. package/plugins/lisa-copilot/scripts/intake-blocker-reprobe.mjs +85 -17
  200. package/plugins/lisa-copilot/scripts/qa-signal-lifecycle.mjs +5 -2
  201. package/plugins/lisa-copilot/skills/lisa-github-build-intake/SKILL.md +38 -15
  202. package/plugins/lisa-copilot/skills/lisa-github-write-issue/SKILL.md +15 -1
  203. package/plugins/lisa-copilot/skills/lisa-jira-build-intake/SKILL.md +37 -13
  204. package/plugins/lisa-copilot/skills/lisa-jira-write-ticket/SKILL.md +15 -1
  205. package/plugins/lisa-copilot/skills/lisa-linear-access/SKILL.md +56 -7
  206. package/plugins/lisa-copilot/skills/lisa-linear-build-intake/SKILL.md +36 -11
  207. package/plugins/lisa-copilot/skills/lisa-linear-prd-intake/SKILL.md +12 -2
  208. package/plugins/lisa-copilot/skills/lisa-linear-validate-issue/SKILL.md +1 -18
  209. package/plugins/lisa-copilot/skills/lisa-linear-verify/SKILL.md +0 -17
  210. package/plugins/lisa-copilot/skills/lisa-linear-write-issue/SKILL.md +18 -35
  211. package/plugins/lisa-copilot/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
  212. package/plugins/lisa-copilot/skills/lisa-repair-intake/SKILL.md +66 -12
  213. package/plugins/lisa-copilot/skills/lisa-rework-triage/SKILL.md +2 -1
  214. package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/providers.mjs +2 -1
  215. package/plugins/lisa-copilot/skills/lisa-setup-linear/SKILL.md +1 -1
  216. package/plugins/lisa-copilot/skills/lisa-setup-remote-env/scripts/preflight-tools.mjs +7 -2
  217. package/plugins/lisa-copilot/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +11 -4
  218. package/plugins/lisa-copilot/skills/lisa-setup-remote-env/scripts/toolchain.mjs +17 -5
  219. package/plugins/lisa-copilot/skills/lisa-track/SKILL.md +32 -4
  220. package/plugins/lisa-copilot/skills/lisa-tracker-build-intake/SKILL.md +15 -1
  221. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  222. package/plugins/lisa-cursor/hooks/block-blind-automerge.sh +13 -5
  223. package/plugins/lisa-cursor/hooks/block-direct-issue-create.sh +7 -0
  224. package/plugins/lisa-cursor/hooks/block-instruction-file-edits.sh +3 -0
  225. package/plugins/lisa-cursor/hooks/block-managed-file-edits.sh +76 -2
  226. package/plugins/lisa-cursor/hooks/block-no-verify.sh +3 -0
  227. package/plugins/lisa-cursor/hooks/block-shell-json-parsing.sh +3 -0
  228. package/plugins/lisa-cursor/hooks/guard-dedupe.bash +66 -29
  229. package/plugins/lisa-cursor/hooks/parity-safety-net-heredoc.py +3 -0
  230. package/plugins/lisa-cursor/hooks/parity-safety-net.sh +5 -1
  231. package/plugins/lisa-cursor/hooks/worktree-binding-guard.mjs +3 -0
  232. package/plugins/lisa-cursor/hooks/worktree-binding-guard.sh +5 -1
  233. package/plugins/lisa-cursor/rules/00-rule-index.mdc +1 -0
  234. package/plugins/lisa-cursor/rules/automation-runbook-contract-reference.mdc +1 -1
  235. package/plugins/lisa-cursor/rules/base-rules.mdc +3 -1
  236. package/plugins/lisa-cursor/rules/bdd-e2e-coverage-reference.mdc +1 -1
  237. package/plugins/lisa-cursor/rules/blocker-containment-reference.mdc +3 -3
  238. package/plugins/lisa-cursor/rules/claim-archaeology-reference.mdc +1 -1
  239. package/plugins/lisa-cursor/rules/claim-evidence-mapping-reference.mdc +1 -1
  240. package/plugins/lisa-cursor/rules/claim-time-guards-reference.mdc +1 -1
  241. package/plugins/lisa-cursor/rules/control-reachability-reference.mdc +1 -1
  242. package/plugins/lisa-cursor/rules/convergent-review-reference.mdc +1 -1
  243. package/plugins/lisa-cursor/rules/credential-substrate-precedence-reference.mdc +1 -1
  244. package/plugins/lisa-cursor/rules/dependency-decision-records-reference.mdc +1 -1
  245. package/plugins/lisa-cursor/rules/dependency-internalization-kit-reference.mdc +1 -1
  246. package/plugins/lisa-cursor/rules/dependency-trust-classes-reference.mdc +1 -1
  247. package/plugins/lisa-cursor/rules/deployed-state-readback-reference.mdc +1 -1
  248. package/plugins/lisa-cursor/rules/derived-branch-plan-reference.mdc +1 -1
  249. package/plugins/lisa-cursor/rules/design-source-of-truth-reference.mdc +1 -1
  250. package/plugins/lisa-cursor/rules/design-value-binding-reference.mdc +1 -1
  251. package/plugins/lisa-cursor/rules/documentation-source-paths-reference.mdc +1 -1
  252. package/plugins/lisa-cursor/rules/leaf-only-lifecycle-reference.mdc +1 -1
  253. package/plugins/lisa-cursor/rules/observability-audit-reference.mdc +1 -1
  254. package/plugins/lisa-cursor/rules/prd-definition-of-ready-reference.mdc +1 -1
  255. package/plugins/lisa-cursor/rules/prd-lifecycle-rollup-reference.mdc +1 -1
  256. package/plugins/lisa-cursor/rules/pre-flight-autofill-reference.mdc +1 -1
  257. package/plugins/lisa-cursor/rules/promotion-contract-reference.mdc +1 -1
  258. package/plugins/lisa-cursor/rules/readiness-rubric-reference.mdc +1 -1
  259. package/plugins/lisa-cursor/rules/ready-role-filing-reference.mdc +37 -1
  260. package/plugins/lisa-cursor/rules/rejection-detection-reference.mdc +1 -1
  261. package/plugins/lisa-cursor/rules/repo-scope-split-reference.mdc +9 -10
  262. package/plugins/lisa-cursor/rules/reset-seed-coverage-reference.mdc +1 -1
  263. package/plugins/lisa-cursor/rules/usage-accounting-reference.mdc +1 -1
  264. package/plugins/lisa-cursor/rules/withdrawn-rulings.mdc +14 -3
  265. package/plugins/lisa-cursor/rules/work-item-definition-of-ready-reference.mdc +1 -1
  266. package/plugins/lisa-cursor/scripts/intake-blocker-reprobe.mjs +85 -17
  267. package/plugins/lisa-cursor/scripts/qa-signal-lifecycle.mjs +5 -2
  268. package/plugins/lisa-cursor/skills/lisa-github-build-intake/SKILL.md +38 -15
  269. package/plugins/lisa-cursor/skills/lisa-github-write-issue/SKILL.md +15 -1
  270. package/plugins/lisa-cursor/skills/lisa-jira-build-intake/SKILL.md +37 -13
  271. package/plugins/lisa-cursor/skills/lisa-jira-write-ticket/SKILL.md +15 -1
  272. package/plugins/lisa-cursor/skills/lisa-linear-access/SKILL.md +56 -7
  273. package/plugins/lisa-cursor/skills/lisa-linear-build-intake/SKILL.md +36 -11
  274. package/plugins/lisa-cursor/skills/lisa-linear-prd-intake/SKILL.md +12 -2
  275. package/plugins/lisa-cursor/skills/lisa-linear-validate-issue/SKILL.md +1 -18
  276. package/plugins/lisa-cursor/skills/lisa-linear-verify/SKILL.md +0 -17
  277. package/plugins/lisa-cursor/skills/lisa-linear-write-issue/SKILL.md +18 -35
  278. package/plugins/lisa-cursor/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
  279. package/plugins/lisa-cursor/skills/lisa-repair-intake/SKILL.md +66 -12
  280. package/plugins/lisa-cursor/skills/lisa-rework-triage/SKILL.md +2 -1
  281. package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/providers.mjs +2 -1
  282. package/plugins/lisa-cursor/skills/lisa-setup-linear/SKILL.md +1 -1
  283. package/plugins/lisa-cursor/skills/lisa-setup-remote-env/scripts/preflight-tools.mjs +7 -2
  284. package/plugins/lisa-cursor/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +11 -4
  285. package/plugins/lisa-cursor/skills/lisa-setup-remote-env/scripts/toolchain.mjs +17 -5
  286. package/plugins/lisa-cursor/skills/lisa-track/SKILL.md +32 -4
  287. package/plugins/lisa-cursor/skills/lisa-tracker-build-intake/SKILL.md +15 -1
  288. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  289. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  290. package/plugins/lisa-expo-agy/plugin.json +1 -1
  291. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  292. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  293. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  294. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  295. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  296. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  297. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  298. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  299. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  300. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  301. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  302. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  303. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  304. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  305. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  306. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  307. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  308. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  309. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  310. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  311. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  312. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  313. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  314. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  315. package/plugins/lisa-rails-agy/plugin.json +1 -1
  316. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  317. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  318. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  319. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  320. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  321. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  322. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  323. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  324. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  325. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  326. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  327. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  328. package/plugins/materialized-artifacts.json +11 -0
  329. package/plugins/src/base/hooks/block-blind-automerge.sh +10 -5
  330. package/plugins/src/base/hooks/block-direct-issue-create.sh +4 -0
  331. package/plugins/src/base/hooks/block-managed-file-edits.sh +73 -2
  332. package/plugins/src/base/hooks/guard-dedupe.bash +63 -29
  333. package/plugins/src/base/hooks/parity-safety-net.sh +2 -1
  334. package/plugins/src/base/hooks/worktree-binding-guard.sh +2 -1
  335. package/plugins/src/base/rules/eager/00-rule-index.md +1 -0
  336. package/plugins/src/base/rules/eager/base-rules.md +3 -1
  337. package/plugins/src/base/rules/eager/withdrawn-rulings.md +14 -3
  338. package/plugins/src/base/rules/reference/automation-runbook-contract.md +1 -1
  339. package/plugins/src/base/rules/reference/bdd-e2e-coverage.md +1 -1
  340. package/plugins/src/base/rules/reference/blocker-containment.md +3 -3
  341. package/plugins/src/base/rules/reference/claim-archaeology.md +1 -1
  342. package/plugins/src/base/rules/reference/claim-evidence-mapping.md +1 -1
  343. package/plugins/src/base/rules/reference/claim-time-guards.md +1 -1
  344. package/plugins/src/base/rules/reference/control-reachability.md +1 -1
  345. package/plugins/src/base/rules/reference/convergent-review.md +1 -1
  346. package/plugins/src/base/rules/reference/credential-substrate-precedence.md +1 -1
  347. package/plugins/src/base/rules/reference/dependency-decision-records.md +1 -1
  348. package/plugins/src/base/rules/reference/dependency-internalization-kit.md +1 -1
  349. package/plugins/src/base/rules/reference/dependency-trust-classes.md +1 -1
  350. package/plugins/src/base/rules/reference/deployed-state-readback.md +1 -1
  351. package/plugins/src/base/rules/reference/derived-branch-plan.md +1 -1
  352. package/plugins/src/base/rules/reference/design-source-of-truth.md +1 -1
  353. package/plugins/src/base/rules/reference/design-value-binding.md +1 -1
  354. package/plugins/src/base/rules/reference/documentation-source-paths.md +1 -1
  355. package/plugins/src/base/rules/reference/leaf-only-lifecycle.md +1 -1
  356. package/plugins/src/base/rules/reference/observability-audit.md +1 -1
  357. package/plugins/src/base/rules/reference/prd-definition-of-ready.md +1 -1
  358. package/plugins/src/base/rules/reference/prd-lifecycle-rollup.md +1 -1
  359. package/plugins/src/base/rules/reference/pre-flight-autofill.md +1 -1
  360. package/plugins/src/base/rules/reference/promotion-contract.md +1 -1
  361. package/plugins/src/base/rules/reference/readiness-rubric.md +1 -1
  362. package/plugins/src/base/rules/reference/ready-role-filing.md +37 -1
  363. package/plugins/src/base/rules/reference/rejection-detection.md +1 -1
  364. package/plugins/src/base/rules/reference/repo-scope-split.md +9 -10
  365. package/plugins/src/base/rules/reference/reset-seed-coverage.md +1 -1
  366. package/plugins/src/base/rules/reference/usage-accounting.md +1 -1
  367. package/plugins/src/base/rules/reference/work-item-definition-of-ready.md +1 -1
  368. package/plugins/src/base/scripts/intake-blocker-reprobe.mjs +85 -17
  369. package/plugins/src/base/scripts/qa-signal-lifecycle.mjs +5 -2
  370. package/plugins/src/base/skills/lisa-github-build-intake/SKILL.md +38 -15
  371. package/plugins/src/base/skills/lisa-github-write-issue/SKILL.md +15 -1
  372. package/plugins/src/base/skills/lisa-jira-build-intake/SKILL.md +37 -13
  373. package/plugins/src/base/skills/lisa-jira-write-ticket/SKILL.md +15 -1
  374. package/plugins/src/base/skills/lisa-linear-access/SKILL.md +56 -7
  375. package/plugins/src/base/skills/lisa-linear-build-intake/SKILL.md +36 -11
  376. package/plugins/src/base/skills/lisa-linear-prd-intake/SKILL.md +12 -2
  377. package/plugins/src/base/skills/lisa-linear-validate-issue/SKILL.md +1 -18
  378. package/plugins/src/base/skills/lisa-linear-verify/SKILL.md +0 -17
  379. package/plugins/src/base/skills/lisa-linear-write-issue/SKILL.md +18 -35
  380. package/plugins/src/base/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
  381. package/plugins/src/base/skills/lisa-repair-intake/SKILL.md +66 -12
  382. package/plugins/src/base/skills/lisa-rework-triage/SKILL.md +2 -1
  383. package/plugins/src/base/skills/lisa-secrets-access/scripts/providers.mjs +2 -1
  384. package/plugins/src/base/skills/lisa-setup-linear/SKILL.md +1 -1
  385. package/plugins/src/base/skills/lisa-setup-remote-env/scripts/preflight-tools.mjs +7 -2
  386. package/plugins/src/base/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +11 -4
  387. package/plugins/src/base/skills/lisa-setup-remote-env/scripts/toolchain.mjs +17 -5
  388. package/plugins/src/base/skills/lisa-track/SKILL.md +32 -4
  389. package/plugins/src/base/skills/lisa-tracker-build-intake/SKILL.md +15 -1
  390. package/scripts/build-plugins.sh +4 -0
  391. package/scripts/copy-opencode-plugin-templates.mjs +5 -1
  392. package/scripts/lisa-enforcement-fallback.sh +9 -1
  393. package/scripts/two-channel-couplings.json +5 -33
  394. package/typescript/copy-overwrite/scripts/check-skipped-required-checks.mjs +551 -13
  395. package/typescript/create-only/.github/required-checks.json +1 -1
@@ -6,6 +6,20 @@ allowed-tools: ["Bash", "Skill"]
6
6
 
7
7
  # Write Linear Work Item: $ARGUMENTS
8
8
 
9
+ ## Human-gate release authorization
10
+
11
+ A release requires a trusted human author, not just matching comment text. Follow
12
+ `ready-role-filing` — **Human-gate release authorization**: preserve tracker-supplied comment
13
+ author IDs and bot metadata, resolve `trustedHumanActorIds` only from an explicit user instruction
14
+ or existing human-authored trusted project policy, and pass it with structured `comments` to every
15
+ hold classifier, reconciliation, normalization and release planner. Never derive trust from the
16
+ comment body, a display name, the actor's own assertion, or an automation posting on its own behalf.
17
+ Missing policy, missing/unreadable author identity, raw body strings, untrusted actors and known bots
18
+ cannot discharge a hold. Keep the item held and report the missing authorization; do not silently
19
+ replace these inputs with an empty history or an inferred allowlist. Authorized matching releases
20
+ continue through the existing path and never override an independently declared caller hold.
21
+
22
+
9
23
  Create or update a Linear work item — Project (for Epics), Issue (for Stories), or sub-Issue (for Sub-tasks) — with all required relationships, metadata, and quality gates. Every section below is mandatory. Thin items are rejected.
10
24
 
11
25
  Repository name for scoped comments: `basename $(git rev-parse --show-toplevel)`.
@@ -33,40 +47,7 @@ Linear's data model maps Epic / Story / Sub-task to **different entity types**.
33
47
 
34
48
  The build lifecycle uses native **workflow states** (`Ready`, `In Progress`, `Blocked`, `On Dev`, `On Stg`, `Done`, plus an optional review state a project may bind), resolved per role from `linear.workflow` — see "Why Linear uses states, not labels" in `config-resolution`. A new **leaf** work unit is created in the configured `ready` state only on explicit `build_ready: true`; omitted or `false` leaves it in the team's default backlog state, and a container is never put in `ready` at all (see the Build-ready control input below).
35
49
 
36
- ## Writing by another path? The gates still apply
37
-
38
- A team that talks to its tracker through its own script is doing a normal
39
- thing — the script usually owns the credential plumbing, and Lisa neither
40
- controls nor wants to control it. What that script does NOT get is either half
41
- of this skill's quality gate, and nothing about the write says so.
42
-
43
- **A read-back is not the missing check.** A bespoke path almost always re-reads
44
- the issue after writing and confirms the tracker stored what was sent. That is
45
- worth doing and it is not this. It proves TRANSPORT: the API accepted the
46
- payload and the field values round-tripped. It cannot fail for the reason these
47
- gates exist, because it never looks at whether what was sent was any good — a
48
- issue with no acceptance criteria, no parent, and a human decision left sitting
49
- in the middle of it round-trips perfectly. That is the dangerous half of the
50
- shape: a failing control gets investigated, a misread one gets trusted.
51
-
52
- So a write by any other path still owes both phases, and both run standalone
53
- against an item that already exists:
54
-
55
- | Phase | Skill | What it costs you |
56
- |---|---|---|
57
- | Pre-write validate | `lisa-linear-validate-issue` | Run it on the draft before you send it |
58
- | Post-write verify | `lisa-linear-verify` | Run it on the live issue after you send it |
59
-
60
- ```text
61
- Skill(lisa-linear-validate-issue) with the draft issue, or with a reference to a live one
62
- Skill(lisa-linear-verify) with ENG-1234
63
- ```
64
-
65
- **These are plugin-resident skills invoked through the Skill tool.** They are
66
- not shell scripts and will not appear in any repository's `scripts/` directory,
67
- including yours. An agent that searches the repo it is standing in, finds
68
- nothing, and concludes the capability is absent has made the one mistake that
69
- turns a local script from the convenient option into the only one.
50
+ For direct API or bespoke script writes, the [bespoke-path contract](#writing-by-a-bespoke-path-your-own-script-direct-api-or-graphql) still requires pre-write validation and post-write verification.
70
51
 
71
52
  ## Phase 1 — Resolve Intent
72
53
 
@@ -334,8 +315,10 @@ person scanning a board and to any path that has not yet been routed through the
334
315
  If the label does not exist in the tracker, create it, or record that it could not be applied and
335
316
  proceed — the marker still holds. Never file the label *instead of* the marker.
336
317
 
318
+ **Every marker reader must consult comments.** Use `classifyReadyCandidate` with labels, body, comments and the configured human-needed label, then `planHumanGateRelease` for any release actions. A historical body marker alone is not an active hold after its matching release; unreadable comments leave a hold in place.
319
+
337
320
  **Write a `reason=` the release can name.** The hold's reason is not decoration: a hold ends when a
338
- `[lisa-human-gate-release]` comment repeating that same `reason=` is recorded on the item, and the
321
+ `[lisa-human-gate-release]` comment repeating that same `reason=` is recorded on the item by an authorized human, and the
339
322
  next intake sweep then takes the marker label off and puts the item back in the build-ready role on
340
323
  its own. Matching is per-reason so that a hold declared *after* an earlier release is not born
341
324
  discharged. A keyless hold is legal and is discharged by a keyless release; a hold whose reason is a
@@ -15,7 +15,7 @@ The PRD URL can be a **Notion page URL**, a **Confluence page URL**, a **Linear
15
15
 
16
16
  - `notion.so` / `notion.site` → Notion. Fetch with `mcp__claude_ai_Notion__notion-fetch` (`include_discussions: true`) and `mcp__claude_ai_Notion__notion-get-comments`.
17
17
  - Atlassian Confluence host (e.g. `*.atlassian.net/wiki/...`) → Confluence. Through `lisa-atlassian-access`, fetch the page, its descendants (for child epic pages), and its footer + inline comments including nested replies. State the operation, not a vendor tool name — the access skill owns substrate selection (`integration-access-layer`).
18
- - `linear.app` host → Linear. Fetch with `lisa-linear-access operation: get-project` (capture description, labels, state, attached resources), `lisa-linear-access operation: list-documents({projectId})` + `lisa-linear-access operation: get-document` per attached document, `lisa-linear-access operation: list-issues({project})` for sub-issues that act as child epics / user stories, and `lisa-linear-access operation: list-comments({issueId})` per sub-issue for decisions and engineering notes. Comments do not exist on the project itself in the MCP surface — sub-issue comments are the substitute.
18
+ - `linear.app` host → Linear. Fetch with `lisa-linear-access operation: get-project` (capture description, labels, state, attached resources), `lisa-linear-access operation: list-documents({projectId})` + `lisa-linear-access operation: get-document` per attached document, `lisa-linear-access operation: list-issues({project})` for sub-issues that act as child epics / user stories, and `lisa-linear-access operation: list-comments({issueId})` per sub-issue for decisions and engineering notes. Also fetch all project comments with `lisa-linear-access operation: list-comments project_id:<ID>`; the access layer pages through GraphQL even when the MCP lacks project comments. An incomplete comment read is an access failure, not an empty history.
19
19
  - `github.com` host → GitHub Issues. Fetch with the `gh` CLI (no GitHub MCP — Lisa uses the CLI exclusively for GitHub):
20
20
  - `gh issue view <number> --repo <org>/<repo> --json number,title,body,labels,milestone,assignees,author,createdAt,comments,url` for the PRD body and comments.
21
21
  - `gh api graphql` with the `subIssues` field for native sub-issue children (these stand in for child epic pages — see `lisa-github-read-issue` Phase 3 for the exact query).
@@ -41,7 +41,7 @@ Per-ticket gates (`lisa-jira-validate-ticket`) prove each created ticket is well
41
41
  2. Fetch the PRD using the vendor-appropriate tool surface:
42
42
  - **Notion**: `notion-fetch` with `include_discussions: true`. Capture: title, body, child Epic pages, all comment threads.
43
43
  - **Confluence**: `getConfluencePage` (capture title, body, labels), `getConfluencePageFooterComments` + `getConfluencePageInlineComments` (capture all comments; walk replies via `getConfluenceCommentChildren` for any thread with children).
44
- - **Linear**: `get_project` (capture name, description, labels, state, attached resources). Capture sub-issues via `list_issues({project})` and per-issue comments via `list_comments({issueId})`.
44
+ - **Linear**: `get_project` (capture name, description, labels, state, attached resources). Capture all project comments via `lisa-linear-access operation: list-comments project_id:<ID>`, plus sub-issues via `list_issues({project})` and per-issue comments via `list_comments({issueId})`. Include both comment sources in destination URL discovery; refuse to report `NO_TICKETS_FOUND` from an incomplete read.
45
45
  - **GitHub**: `gh issue view --json` for the source PRD issue (title, body, labels, comments). Capture sub-issues via the GraphQL `subIssues` traversal.
46
46
  3. If the PRD has child Epic sub-pages / sub-issues (a multi-epic PRD), fetch each in parallel:
47
47
  - **Notion**: `notion-fetch` per child page with `include_discussions: true`.
@@ -6,6 +6,20 @@ allowed-tools: ["Skill", "Bash", "Read", "Write", "Edit"]
6
6
 
7
7
  # Repair Intake: $ARGUMENTS
8
8
 
9
+ ## Human-gate release authorization
10
+
11
+ A release requires a trusted human author, not just matching comment text. Follow
12
+ `ready-role-filing` — **Human-gate release authorization**: preserve tracker-supplied comment
13
+ author IDs and bot metadata, resolve `trustedHumanActorIds` only from an explicit user instruction
14
+ or existing human-authored trusted project policy, and pass it with structured `comments` to every
15
+ hold classifier, reconciliation, normalization and release planner. Never derive trust from the
16
+ comment body, a display name, the actor's own assertion, or an automation posting on its own behalf.
17
+ Missing policy, missing/unreadable author identity, raw body strings, untrusted actors and known bots
18
+ cannot discharge a hold. Keep the item held and report the missing authorization; do not silently
19
+ replace these inputs with an empty history or an inferred allowlist. Authorized matching releases
20
+ continue through the existing path and never override an independently declared caller hold.
21
+
22
+
9
23
  Run one batch-**repair** cycle against the queue identified by `$ARGUMENTS`, or by merged GitHub
10
24
  config when the queue is omitted and a GitHub source/tracker default is resolvable. Where `lisa-intake`
11
25
  scans the `ready` role and moves work *forward*, repair-intake scans the **stuck and
@@ -189,7 +203,7 @@ In addition to the lifecycle roles above, the build lifecycle defines the **`hum
189
203
  - The blocks repair-intake **itself writes** are the auto-recoverable kind — it files a build-ready fix ticket and moves the item `blocked` *blocked by that ticket*, expecting the next cycle to self-heal. Those are **not** `human_needed`; if such an item arrives carrying a `human_needed` marker **this skill applied on an earlier cycle**, repair-intake **clears** it (the block is no longer waiting on a human).
190
204
  - **Never remove a `human_needed` marker this skill did not apply.** "Stale" is a judgment about the block's kind, not about who applied the marker or when — so without this rule an operator's deliberate hold, applied *after* correcting a wrong transition, is indistinguishable from a leftover the sweep is designed to clear, and gets swept. Establish provenance from the label event's actor (`rejection-detection` **Automation-reversal memory** reads the same surfaces); if provenance is not readable, **leave the marker in place**. Removing a human's hold is unrecoverable within the loop; leaving a stale one costs a cycle and is visible.
191
205
  - **The one exception is a hold that has recorded its own discharge.** A `[lisa-human-gate-release]` comment naming the hold's `reason=` is not a guess about provenance — it is the hold's stated void condition, recorded on the item by the person who answered it. Clearing the marker there is not overriding a human's judgment; it is *enacting* it. That is the whole of the exception: no other reading of "this looks stale" reopens the question above, and an item whose release cannot be read stays held. See "Release the holds that have been answered" below (#3852).
192
- - The marker is consulted **before **any** repair transition**, not only before Class C. Class C's hard stop is the strictest reading of it, but a marker that is honoured on one classification path and ignored on the other three is not a guard — and Class A, dependency clearing, is exactly the path an operator reverting a wrongly-cleared blocker is trying to protect. Match it robustly (hyphen/underscore, case-insensitive, label set and note prose) wherever it is read.
206
+ - The marker is consulted **before **any** repair transition**, not only before Class C. Class C's hard stop is the strictest reading of it, but a marker that is honoured on one classification path and ignored on the other three is not a guard — and Class A, dependency clearing, is exactly the path an operator reverting a wrongly-cleared blocker is trying to protect. Read all comments and consult `classifyReadyCandidate` / `planHumanGateRelease` before treating the marker as active; a matching release discharges the historical body marker. Use the shared helpers for robust label and declaration matching, and leave unreadable releases held.
193
207
  - The blocks the **vendor agent** writes when repair-intake re-dispatches it (its pre-flight gate) carry `human_needed` already — the agent owns that marker. repair-intake leaves it in place.
194
208
 
195
209
  Resolve with the standard role-read pattern (local overrides global, default fallback):
@@ -621,6 +635,41 @@ the item open. Recording "the fix reached dev and production but skipped staging
621
635
  branch back-fill, not outstanding delivery" and then closing anyway is this defect exactly — the
622
636
  condition observed, filed under the wrong heading, and overridden.
623
637
 
638
+ ### Resolve the shipped blocker-edge module
639
+
640
+ The helper ships in the plugin and npm package. Only the runtime-supplied plugin roots
641
+ and installed package are trusted here; do not search arbitrary checkout-local plugin folders.
642
+ Write the evaluated edge inputs to a JSON array file, then call `blocker_edge_decisions`.
643
+ An absent module, unreadable input or import failure stops this repair without tracker writes.
644
+
645
+ ```bash
646
+ resolve_blocker_guard() {
647
+ local candidate
648
+ for candidate in \
649
+ "${CLAUDE_PLUGIN_ROOT:+$CLAUDE_PLUGIN_ROOT/scripts/blocker-edge-resolution.mjs}" \
650
+ "${PLUGIN_ROOT:+$PLUGIN_ROOT/scripts/blocker-edge-resolution.mjs}" \
651
+ node_modules/@codyswann/lisa/plugins/lisa/scripts/blocker-edge-resolution.mjs; do
652
+ [ -n "$candidate" ] && [ -f "$candidate" ] && { printf '%s\n' "$candidate"; return; }
653
+ done
654
+ echo "Error: could not locate blocker-edge-resolution.mjs; refusing repair." >&2
655
+ return 1
656
+ }
657
+
658
+ blocker_edge_decisions() { # JSON array file -> decision object
659
+ local guard
660
+ guard=$(resolve_blocker_guard) || return 1
661
+ node --input-type=module - "$guard" "$1" <<'LISA_BLOCKER_NODE'
662
+ import { readFileSync } from "node:fs";
663
+ import { resolve } from "node:path";
664
+ import { pathToFileURL } from "node:url";
665
+ const { resolveBlockerEdges } = await import(pathToFileURL(resolve(process.argv[2])).href);
666
+ const edges = JSON.parse(readFileSync(process.argv[3], "utf8"));
667
+ if (!Array.isArray(edges)) throw new Error("Expected an array of blocker edges");
668
+ console.log(JSON.stringify(resolveBlockerEdges(edges)));
669
+ LISA_BLOCKER_NODE
670
+ }
671
+ ```
672
+
624
673
  ### Build `blocked` → re-evaluate, unblock if cleared
625
674
 
626
675
  1. Read the block reason and classify the blocker (see Blocker classification & clearing). An item
@@ -629,8 +678,11 @@ condition observed, filed under the wrong heading, and overridden.
629
678
  Re-check **every** class present — do not stop at "no `is blocked by` links, therefore nothing
630
679
  to do." A self-block has zero dependencies by definition, yet is fully re-checkable.
631
680
  2. **Dependency cleared** — decide each parsed `is blocked by` edge with
632
- `scripts/blocker-edge-resolution.mjs`, feeding it the `blocker-containment` verdict plus the
633
- blocker's state and closure reason. It returns `dissolve` / `keep` / `escalate` per edge.
681
+ the shipped plugin helper `scripts/blocker-edge-resolution.mjs`, feeding it the
682
+ `blocker-containment` verdict plus the blocker's state and closure reason. This is a module,
683
+ not a CLI and not a required host `scripts/` file. Resolve a trusted plugin/package path and
684
+ invoke `resolveBlockerEdges` as shown above; never create a second resolver in the host.
685
+ It returns `dissolve` / `keep` / `escalate` per edge.
634
686
  **Dissolve the edge in the SAME write that records the ruling, then read the relation back and
635
687
  confirm it is gone.** Only when every edge dissolves → move `blocked → claimed`, then run the
636
688
  same agent-dispatch + post-agent `claimed → done` sequence as the stalled-`claimed` path above
@@ -1033,7 +1085,7 @@ with labels like `build-ready`, or with no Lisa status label at all, that are in
1033
1085
  `intake_mode=build`, every non-PRD issue is normalized as a build ticket. If `intake_mode=both`,
1034
1086
  classify PRDs first and normalize all remaining issues as build tickets.
1035
1087
  2a. **Ask whether a person is holding it, before anything else.** Call
1036
- `planLabelNormalization({ labels, body, humanNeededLabel, lifecycleLabels, readyLabel })` from
1088
+ `planLabelNormalization({ labels, body, comments, trustedHumanActorIds, humanNeededLabel, lifecycleLabels, readyLabel })` from
1037
1089
  `scripts/intake-blocker-reprobe.mjs` for every candidate and apply exactly the verdict it
1038
1090
  returns. Do **not** re-implement the test here and do **not** decide held-ness from labels
1039
1091
  alone: the vendor writers stamp the `[lisa-human-gate]` marker into the body of a deliberate
@@ -1050,7 +1102,7 @@ with labels like `build-ready`, or with no Lisa status label at all, that are in
1050
1102
  the safe failure direction without the latch. Count these under `held_for_person`, never under
1051
1103
  `normalized_ready`.
1052
1104
 
1053
- **Pass the item's `comments`.** The planner reads a recorded `[lisa-human-gate-release]` comment
1105
+ **Pass the item's `comments` with author identity and `trustedHumanActorIds`.** The planner reads a recorded `[lisa-human-gate-release]` comment
1054
1106
  as the discharge of the hold naming the same `reason=`, and an item read without its comments is
1055
1107
  an item whose discharge cannot be seen. That fails closed — it stays held — which is the safe
1056
1108
  direction and precisely why the omission is invisible.
@@ -1064,7 +1116,7 @@ with labels like `build-ready`, or with no Lisa status label at all, that are in
1064
1116
 
1065
1117
  Enumerate items carrying the configured `human_needed` marker **or** a `[lisa-human-gate]` marker
1066
1118
  in the body, and for each call
1067
- `planHumanGateRelease({ labels, body, comments, humanNeededLabel, readyLabel, lifecycleLabels, alreadyNotified })`
1119
+ `planHumanGateRelease({ labels, body, comments, trustedHumanActorIds, humanNeededLabel, readyLabel, lifecycleLabels, alreadyNotified })`
1068
1120
  from `scripts/intake-blocker-reprobe.mjs`. Apply exactly the actions it returns: remove the
1069
1121
  human-needed marker, add the configured build `ready` label back, and post
1070
1122
  `formatHumanGateReleaseNote()` once. Do **not** re-implement the discharge test, and do **not**
@@ -1081,10 +1133,10 @@ with labels like `build-ready`, or with no Lisa status label at all, that are in
1081
1133
  item carries no other configured lifecycle label.
1082
1134
 
1083
1135
  This is a genuine exception to "never remove a `human_needed` marker this skill did not apply",
1084
- and the exception is narrow enough to state exactly: provenance is the wrong question when the
1085
- *hold itself* names the condition that voids it and that condition is recorded. The general rule
1086
- stands because "stale" is otherwise a judgment about the block's kind; here nothing is being
1087
- judged — a release naming the hold's own reason is on the item, or it is not.
1136
+ and the exception is narrow enough to state exactly: the release author must first be verified against `trustedHumanActorIds`; only then does the
1137
+ matching release satisfy the hold's stated void condition. The actor who originally applied the
1138
+ marker does not need to match that authorized release author. The general rule
1139
+ stands because "stale" is otherwise a judgment about the block's kind; here an authorized matching release is required; arbitrary matching text is not enough.
1088
1140
 
1089
1141
  **Never edit a description to clear a hold**, here or anywhere. The only body write this plugin
1090
1142
  has is a whole-body replacement, so deleting one line means rewriting the record and hoping
@@ -1187,9 +1239,11 @@ layer, and test ancestry against the remote.
1187
1239
  remote, ancestry query errored) → **still blocking**, with the rule's reason key in the run
1188
1240
  record.
1189
1241
  - **Ships no code** — the blocker is closed as completed, positively declares
1190
- `Target Backend Environment: None — no runtime behavior change`, and has no merged PR →
1242
+ `## Target Backend Environment` reading `None — no runtime behavior change: <kind>`
1243
+ with kind `doc-only`, `config-only`, or `type-only`, and has no linked PR and no merge commit →
1191
1244
  **cleared** under the rule's carve-out. This is a positive determination, never an absence:
1192
- "no PR found" is `no-pr` and stays blocking.
1245
+ "no PR found" is `no-pr` and stays blocking. A missing kind does not qualify; any linked
1246
+ open or unmerged PR stays blocking under the normal containment test.
1193
1247
  - **Human override** — an explicit human statement on this item that the dependency is satisfied
1194
1248
  clears it and outranks a failed containment check. Name it in the run record.
1195
1249
  - **Human hold** — the override runs in both directions. `human_needed` is checked here as well as
@@ -53,7 +53,8 @@ first-attempt work.
53
53
  # bundle.json: { "labels": [...], "comments": [<bodies, oldest first>], "role": "<current>" }
54
54
  ```
55
55
 
56
- Branch on `action`, never on the label being there:
56
+ Branch on `outcome`, never on the label being there. The resolver's separate
57
+ `action` field is `keep` / `clear` / `none`; it is not the liveness verdict:
57
58
 
58
59
  | `outcome` | Meaning | What triage does |
59
60
  |---|---|---|
@@ -743,7 +743,8 @@ export function createCoordinationRecord(cfg, key, projectId, note) {
743
743
  "--output",
744
744
  "json",
745
745
  ],
746
- env
746
+ env,
747
+ "creating a coordination record in Bitwarden"
747
748
  );
748
749
  const created = JSON.parse(raw);
749
750
  return {
@@ -357,7 +357,7 @@ jq -e '.linear.workspace' .lisa.config.json >/dev/null
357
357
  [ "$(jq -r '.tracker // empty' .lisa.config.json)" = "linear" ] && jq -e '.linear.teamKey' .lisa.config.json >/dev/null
358
358
  ```
359
359
 
360
- Confirm what was scaffolded is present: `list-workflow-states` for every build role when Linear is the tracker, `list_project_labels` for `prd-*` (including the terminal `prd-verified`) when Linear is the PRD source. Do NOT expect a `status:*` namespace — it is not part of this model. Report success with the resolved workspace, team key (if any), which namespaces were scaffolded (created vs. already existed), any non-default overrides, and whether `tracker` / `source` were set. Direct the user to `/lisa:intake` to test.
360
+ Confirm what was scaffolded is present: `list-workflow-states` for every build role when Linear is the tracker, `list-project-labels` for `prd-*` (including the terminal `prd-verified`) when Linear is the PRD source. Do NOT expect a `status:*` namespace — it is not part of this model. Report success with the resolved workspace, team key (if any), which namespaces were scaffolded (created vs. already existed), any non-default overrides, and whether `tracker` / `source` were set. Direct the user to `/lisa:intake` to test.
361
361
 
362
362
  ## Idempotency
363
363
 
@@ -70,7 +70,7 @@ const BLOCKING = new Set(["missing", "invalid"]);
70
70
  /**
71
71
  * Whether an unpinnable entry is nonetheless usable on this machine.
72
72
  *
73
- * Presence-only, and deliberately not a skip. Dropping the entry entirely would
73
+ * Executability is required, even when no version floor is declared. Dropping the entry entirely would
74
74
  * report clean for a tool that is neither pinned nor installed, which is the
75
75
  * vacuous green this module refuses everywhere else. So the probe still decides
76
76
  * — it just gets asked, which on this branch it previously never was.
@@ -83,7 +83,12 @@ const BLOCKING = new Set(["missing", "invalid"]);
83
83
  * @returns {boolean} Whether the tool is present and good enough to use.
84
84
  */
85
85
  function usableWithoutPin(step, minVersions) {
86
- if (!step.unpinnedForPlatform || !step.found?.present) return false;
86
+ if (
87
+ !step.unpinnedForPlatform ||
88
+ !step.found?.present ||
89
+ step.found.executable !== true
90
+ )
91
+ return false;
87
92
  const floor = minVersions[step.name];
88
93
  return !floor || compareVersions(step.found.version ?? "0", floor) >= 0;
89
94
  }
@@ -120,7 +120,7 @@ export function readRemoteEnvConfig(cwd = process.cwd()) {
120
120
  * on which quirky binaries happen to exist on the machine running the tests.
121
121
  * @param {string} name Executable name.
122
122
  * @param {Function} [exec] Command runner, for tests.
123
- * @returns {{version: string|null, present: boolean}} Probe result.
123
+ * @returns {{version: string|null, present: boolean, executable: boolean}} Probe result.
124
124
  */
125
125
  export function probe(name, exec = boundedChildOutput) {
126
126
  try {
@@ -128,12 +128,19 @@ export function probe(name, exec = boundedChildOutput) {
128
128
  encoding: "utf8",
129
129
  stdio: ["ignore", "pipe", "pipe"],
130
130
  });
131
- return { present: true, version: extractVersion(out) };
131
+ return { present: true, executable: true, version: extractVersion(out) };
132
132
  } catch (err) {
133
- if (err.code === "ENOENT") return { present: false, version: null };
134
133
  if (err.code === "ETIMEDOUT") throw err;
134
+ // A numeric exit status proves the child started, even when --version is
135
+ // unsupported. EACCES and other spawn failures carry no exit status: a
136
+ // file being discoverable does not mean the agent can execute it.
137
+ const executable = typeof err.status === "number";
135
138
  const output = `${err.stdout ?? ""}${err.stderr ?? ""}`;
136
- return { present: true, version: extractVersion(output) };
139
+ return {
140
+ present: err.code !== "ENOENT",
141
+ executable,
142
+ version: executable ? extractVersion(output) : null,
143
+ };
137
144
  }
138
145
  }
139
146
 
@@ -56,7 +56,7 @@ export function extractVersion(output) {
56
56
  /**
57
57
  * Classify one required tool against what the environment actually provides.
58
58
  * @param {object} tool Manifest entry.
59
- * @param {{version: string|null, present: boolean}} found Probe result.
59
+ * @param {{version: string|null, present: boolean, executable: boolean}} found Probe result.
60
60
  * @returns {{name: string, action: string, reason: string}} The decision.
61
61
  */
62
62
  function planRequired(tool, found) {
@@ -70,6 +70,13 @@ function planRequired(tool, found) {
70
70
  `Either add an install entry or pin a different image.`,
71
71
  };
72
72
  }
73
+ if (found.executable !== true) {
74
+ return {
75
+ name: tool.name,
76
+ action: "missing",
77
+ reason: `${tool.name} was found but cannot be executed. Repair its permissions or replace the binary before using it.`,
78
+ };
79
+ }
73
80
  if (
74
81
  tool.minVersion &&
75
82
  compareVersions(found.version ?? "0", tool.minVersion) < 0
@@ -97,7 +104,7 @@ function planRequired(tool, found) {
97
104
  * and maintenance the same script, and it is the cheap path when a container
98
105
  * resumes from cache rather than being built fresh.
99
106
  * @param {object} tool Manifest entry.
100
- * @param {{version: string|null, present: boolean}} found Probe result.
107
+ * @param {{version: string|null, present: boolean, executable: boolean}} found Probe result.
101
108
  * @returns {{name: string, action: string, reason: string}} The decision.
102
109
  */
103
110
  function planInstallable(tool, found, pinIsFloor = false) {
@@ -108,7 +115,11 @@ function planInstallable(tool, found, pinIsFloor = false) {
108
115
  reason: `${tool.name} has no pinned version. An unpinned install is not reproducible.`,
109
116
  };
110
117
  }
111
- if (found.present && found.version === tool.version) {
118
+ if (
119
+ found.present &&
120
+ found.executable === true &&
121
+ found.version === tool.version
122
+ ) {
112
123
  return {
113
124
  name: tool.name,
114
125
  action: "skip",
@@ -125,6 +136,7 @@ function planInstallable(tool, found, pinIsFloor = false) {
125
136
  if (
126
137
  pinIsFloor &&
127
138
  found.present &&
139
+ found.executable === true &&
128
140
  found.version &&
129
141
  compareVersions(found.version, tool.version) > 0
130
142
  ) {
@@ -286,10 +298,10 @@ export function appliesToSurface(tool, surface) {
286
298
  * asking about availability rather than provisioning has the answer instead of
287
299
  * having to infer one from the other.
288
300
  * @param {{require?: object[], install?: object[]}} tools Manifest.
289
- * @param {(name: string) => {version: string|null, present: boolean}} probe Version probe.
301
+ * @param {(name: string) => {version: string|null, present: boolean, executable: boolean}} probe Version probe.
290
302
  * @param {string} [surface] Surface being provisioned.
291
303
  * @param {string} [platform] Platform key to resolve install entries against.
292
- * @returns {Array<{name: string, action: string, reason: string, tool?: object, found?: {version: string|null, present: boolean}, unpinnedForPlatform?: boolean}>} Ordered decisions.
304
+ * @returns {Array<{name: string, action: string, reason: string, tool?: object, found?: {version: string|null, present: boolean, executable: boolean}, unpinnedForPlatform?: boolean}>} Ordered decisions.
293
305
  */
294
306
  export function planToolchain(
295
307
  tools,
@@ -6,6 +6,20 @@ allowed-tools: ["Skill", "Bash", "Read"]
6
6
 
7
7
  # Track Work: $ARGUMENTS
8
8
 
9
+ ## Human-gate release authorization
10
+
11
+ A release requires a trusted human author, not just matching comment text. Follow
12
+ `ready-role-filing` — **Human-gate release authorization**: preserve tracker-supplied comment
13
+ author IDs and bot metadata, resolve `trustedHumanActorIds` only from an explicit user instruction
14
+ or existing human-authored trusted project policy, and pass it with structured `comments` to every
15
+ hold classifier, reconciliation, normalization and release planner. Never derive trust from the
16
+ comment body, a display name, the actor's own assertion, or an automation posting on its own behalf.
17
+ Missing policy, missing/unreadable author identity, raw body strings, untrusted actors and known bots
18
+ cannot discharge a hold. Keep the item held and report the missing authorization; do not silently
19
+ replace these inputs with an empty history or an inferred allowlist. Authorized matching releases
20
+ continue through the existing path and never override an independently declared caller hold.
21
+
22
+
9
23
  Establish the tracked-work invariant before any durable project mutation. Discussion and read-only orientation may proceed without this skill; code, configuration, documentation, research artifacts, plans, investigation findings, tests, commits, and pull requests may not.
10
24
 
11
25
  This flow must return exactly one canonical `(tracker_provider, work_item_ref)` pair or fail closed. It never returns an unvalidated textual guess.
@@ -24,7 +38,7 @@ This flow must return exactly one canonical `(tracker_provider, work_item_ref)`
24
38
 
25
39
  ### Explicit reference
26
40
 
27
- Invoke `lisa-tracker-read <ref>` and require a live result from the configured project. Reject nonexistent, inaccessible, closed/resolved/terminal, wrong-project, wrong-repository, or container items. Read the returned body for the hold marker: an item carrying `[lisa-human-gate]` is held and Phase 3 refuses to claim it, whatever role or labels it carries. This live read is mandatory even if caller context already includes ticket text.
41
+ Invoke `lisa-tracker-read <ref>` and require a live result from the configured project. Reject nonexistent, inaccessible, closed/resolved/terminal, wrong-project, wrong-repository, or container items. Read the returned body, labels and all comments; Phase 3 uses the shared hold classifier so a historical `[lisa-human-gate]` marker with a matching release is not mistaken for an active hold. This live read is mandatory even if caller context already includes ticket text.
28
42
 
29
43
  ### File or plain text
30
44
 
@@ -44,9 +58,23 @@ This is intentionally conservative: ambiguity creates one explicit work item ins
44
58
 
45
59
  ## Phase 3 — Claim and bind
46
60
 
47
- The work item is **held** when either of two independent signals is present: the caller declared a `human_gate`, or the resolved item's body contains the literal `[lisa-human-gate]` marker. Test the marker as a plain substring and never key the parse on a `reason=` value — markers are written both with and without one, and a parser that requires the key misses the keyless ones while appearing to work.
61
+ The work item is **held** when the caller declared a `human_gate`, independently of any item history,
62
+ or `classifyReadyCandidate({ labels, body, comments, trustedHumanActorIds, humanNeededLabel })` from the shipped
63
+ `scripts/intake-blocker-reprobe.mjs` returns `claimable: false`. Pass the complete live comment
64
+ history so a matching `[lisa-human-gate-release]` discharges the historical body marker. Never
65
+ reimplement heldness as a substring test or as the negation of `planHumanGateRelease().released`:
66
+ that planner also returns `released: false` for an item that was never held. Missing comments fail
67
+ closed for a hold; never infer release from a missing label.
68
+
69
+ A held item stops the flow here, whatever roles or labels it carries. Do not invoke
70
+ `lisa-tracker-claim`, write the worktree binding, or begin durable project work. Return
71
+ `claim_outcome: held-by-gate` and `binding_outcome: skipped-human-gate`, name the signal in `held_by`
72
+ and carry its reason verbatim in `gate_reason` (null for a keyless hold), then stop.
48
73
 
49
- A held item stops the flow here, whatever the resolution outcome and whatever roles or labels the item carries. The marker is the authority: an item can be held while sitting in the build-ready role with no blocked or human-needed label, because a human stamping a hold on live work is the most likely way a gate is ever applied, and the vendor claim contracts reject a closed item or an active blocker but not a marked one. Do not invoke `lisa-tracker-claim`, do not write the worktree binding, and do not begin durable project work. Claiming a held leaf binds a live lane to it and makes it look already-attended, which suppresses exactly the human attention it was filed to attract. Return the structured result below with `claim_outcome: held-by-gate` and `binding_outcome: skipped-human-gate`, name which signal held it in `held_by` and carry the reason verbatim in `gate_reason` alongside the canonical reference, then stop. A marker written without a `reason=` key yields `gate_reason: null` — a missing reason narrows what the result can say, never whether the item is held.
74
+ For a discharged item, call
75
+ `planHumanGateRelease({ labels, body, comments, trustedHumanActorIds, humanNeededLabel, readyLabel, lifecycleLabels, alreadyNotified })`
76
+ and apply only the returned actions before claiming. Keep the body marker as history; a release
77
+ never overrides a new caller-declared hold or another eligibility check.
50
78
 
51
79
  Otherwise:
52
80
 
@@ -78,5 +106,5 @@ Otherwise:
78
106
  - Branch setup may call `node scripts/lisa-work-item.mjs attach-branch` after the feature branch exists.
79
107
  - Keep the binding across ordinary interruptions and blocked outcomes so resumed work remains attributable.
80
108
  - Clear it only after true terminal completion — merged, deployed/verified where required, tracker evidence/backlink complete, and the work item terminal — by running `node scripts/lisa-work-item.mjs clear` and verifying no current binding remains.
81
- - A held filing writes no binding at all, so there is nothing to clear. The gate is released by a human decision, but not by a human edit: the person records the decision as a comment on the leaf beginning `[lisa-human-gate-release]` and repeating the hold's `reason=` verbatim, and the next intake sweep takes the human-needed marker off and puts the leaf back in the build-ready role on its own (`planHumanGateRelease` in `scripts/intake-blocker-reprobe.mjs`). A later invocation then resolves it on the ordinary path. **Do not tell anyone to delete the marker from the description, and do not delete it here.** The only description write available is a whole-body replacement, so clearing one line means rewriting the entire record — which is why, before this, the rational move was always to leave a hold in place and answered holds only accumulated (CodySwannGT/lisa#3852). The hold stays in the body as history; the release is recorded beside it.
109
+ - A held filing writes no binding at all, so there is nothing to clear. The gate is released by a human decision, but not by a human edit: the person records the decision as a comment on the leaf beginning `[lisa-human-gate-release]` and, for a keyed hold, repeating its `reason=` verbatim. For a keyless hold, the comment begins `[lisa-human-gate-release]` without a `reason=` field. The next intake sweep takes the human-needed marker off and puts the leaf back in the build-ready role on its own (`planHumanGateRelease` in `scripts/intake-blocker-reprobe.mjs`). A later invocation then resolves it on the ordinary path. **Do not tell anyone to delete the marker from the description, and do not delete it here.** The only description write available is a whole-body replacement, so clearing one line means rewriting the entire record — which is why, before this, the rational move was always to leave a hold in place and answered holds only accumulated (CodySwannGT/lisa#3852). The hold stays in the body as history; the release is recorded beside it.
82
110
  - A tracker outage, invalid item, failed claim, or failed binding blocks durable work. Never continue untracked and never ask a Git hook to create the item.
@@ -6,6 +6,20 @@ allowed-tools: ["Skill", "Bash", "Read"]
6
6
 
7
7
  # Tracker Build Intake: $ARGUMENTS
8
8
 
9
+ ## Human-gate release authorization
10
+
11
+ A release requires a trusted human author, not just matching comment text. Follow
12
+ `ready-role-filing` — **Human-gate release authorization**: preserve tracker-supplied comment
13
+ author IDs and bot metadata, resolve `trustedHumanActorIds` only from an explicit user instruction
14
+ or existing human-authored trusted project policy, and pass it with structured `comments` to every
15
+ hold classifier, reconciliation, normalization and release planner. Never derive trust from the
16
+ comment body, a display name, the actor's own assertion, or an automation posting on its own behalf.
17
+ Missing policy, missing/unreadable author identity, raw body strings, untrusted actors and known bots
18
+ cannot discharge a hold. Keep the item held and report the missing authorization; do not silently
19
+ replace these inputs with an empty history or an inferred allowlist. Authorized matching releases
20
+ continue through the existing path and never override an independently declared caller hold.
21
+
22
+
9
23
  Thin dispatcher. Resolves the configured destination tracker and delegates to the matching vendor build-queue scanner.
10
24
 
11
25
  See the `config-resolution` rule for configuration and dispatch table.
@@ -63,7 +77,7 @@ blocker re-probe carries an absolute human gate: an item carrying the configured
63
77
  or a `[lisa-human-gate]` marker is never auto-selected, whatever a probe returns.
64
78
 
65
79
  That gate has an inverse, and it is forwarded identically: a hold ends when a
66
- `[lisa-human-gate-release]` comment naming the same `reason=` is recorded on the item. Every vendor
80
+ `[lisa-human-gate-release]` comment naming the same `reason=` is recorded on the item by an authorized human. Every vendor
67
81
  scanner passes the item's `comments` into the gate helpers so the discharge is visible, and calls
68
82
  `planHumanGateRelease(...)` to take the marker off and put the item back in the queue. **No vendor
69
83
  scanner clears a hold by editing the description** — the only body write any of them has is a
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.55.2",
3
+ "version": "4.55.4",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env bash
2
+ # This file is managed by Lisa and IS replaced on each `lisa` run.
3
+ # Do not edit directly — durable changes belong upstream in Lisa.
4
+
2
5
  # PreToolUse hook for Bash: refuse to ARM auto-merge on a pull request that
3
6
  # GitHub already says is blocked on review.
4
7
  #
@@ -280,7 +283,8 @@ NODE_ID_PATTERN = re.compile(r"^[A-Za-z0-9_=-]+$")
280
283
  NODE_QUERY = (
281
284
  "query($id:ID!){node(id:$id){... on PullRequest"
282
285
  "{number url reviewDecision state baseRefName "
283
- "commits(last:1){nodes{commit{statusCheckRollup{contexts(first:100){nodes{"
286
+ "commits(last:1){nodes{commit{statusCheckRollup{contexts(first:100){"
287
+ "pageInfo{hasNextPage} nodes{"
284
288
  "__typename ... on CheckRun{name conclusion} "
285
289
  "... on StatusContext{context state}"
286
290
  "}}}}}}}}}"
@@ -294,9 +298,13 @@ NODE_QUERY = (
294
298
  # checks, which is genuinely not failing and gets an empty list. A node without
295
299
  # the scaffolding is a probe that never asked, and it must leave the key absent
296
300
  # so the re-target path can tell the two apart instead of reading both as green.
301
+ # A truncated page is equally unreadable: a failing check may be on the next
302
+ # page, so a green first page cannot authorize an uncovered-base re-target.
297
303
  NODE_JQ = (
298
304
  "if .data.node == null then null else .data.node as $n "
299
- "| if ($n | has(\"commits\")) then ($n | del(.commits)) "
305
+ "| if ($n.commits.nodes[0].commit.statusCheckRollup.contexts.pageInfo.hasNextPage == true) "
306
+ "then ($n | del(.commits)) "
307
+ "elif ($n | has(\"commits\")) then ($n | del(.commits)) "
300
308
  "+ {statusCheckRollup: "
301
309
  "((($n.commits.nodes[0].commit.statusCheckRollup.contexts.nodes)) // [])} "
302
310
  "else $n end end"
@@ -1024,9 +1032,9 @@ not read the pull request's checks.
1024
1032
 
1025
1033
  That ref has ZERO required status checks, so the one thing standing between the
1026
1034
  move and a permission-free gate bypass is whether the PR is currently failing —
1027
- and the probe returned no `statusCheckRollup` at all. An absent rollup is not an
1028
- empty one. Reporting the move as the sanctioned green-PR batching case here
1029
- would be a verdict about a question that was never asked.
1035
+ and the probe returned no complete `statusCheckRollup`. An absent or truncated
1036
+ rollup is not an empty one. Reporting the move as the sanctioned green-PR
1037
+ batching case here would claim a result the probe did not establish.
1030
1038
 
1031
1039
  Re-target through `gh pr edit --base` instead, which reads the checks, or fix
1032
1040
  the probe. Do not report the PR as batched until something has actually looked.
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env bash
2
+ # This file is managed by Lisa and IS replaced on each `lisa` run.
3
+ # Do not edit directly — durable changes belong upstream in Lisa.
4
+
2
5
  # PreToolUse hook for Bash: refuse a direct tracker-creation command that
3
6
  # declares no readiness.
4
7
  #
@@ -2106,6 +2109,10 @@ def unparseable_reads_only(text):
2106
2109
  Returns:
2107
2110
  True when every segment's command word is a known reader.
2108
2111
  """
2112
+ # Unlexable operands cannot be certified as data when shell substitutions
2113
+ # may execute inside them. Preserve the plain apostrophe reader exemption.
2114
+ if any(operator in text for operator in ("$(", "`", "<(", ">(")):
2115
+ return False
2109
2116
  words = raw_command_words(text)
2110
2117
  return bool(words) and all(word in READ_ONLY_PROGRAMS for word in words)
2111
2118
 
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env bash
2
+ # This file is managed by Lisa and IS replaced on each `lisa` run.
3
+ # Do not edit directly — durable changes belong upstream in Lisa.
4
+
2
5
  # PreToolUse hook: refuse agent writes to the session-instruction files.
3
6
  #
4
7
  # `AGENTS.md`, `CLAUDE.md`, and `.github/copilot-instructions.md` are the files