@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: ["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-cdk",
3
- "version": "4.55.2",
3
+ "version": "4.55.4",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "4.55.2",
3
+ "version": "4.55.4",
4
4
  "description": "AWS CDK-specific Lisa plugin.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "4.55.2",
3
+ "version": "4.55.4",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "4.55.2",
3
+ "version": "4.55.4",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "4.55.2",
3
+ "version": "4.55.4",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -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
@@ -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 files Lisa overwrites on every apply.
3
6
  #
4
7
  # Lisa ships templates in three modes, and only one of them is unsafe to edit:
@@ -566,6 +569,7 @@ EOF
566
569
  import os
567
570
  import re
568
571
  import shlex
572
+ import sys
569
573
 
570
574
  command = os.environ.get("MANAGED_EDIT_COMMAND", "")
571
575
  project = os.environ.get("MANAGED_EDIT_PROJECT", "") or os.getcwd()
@@ -576,6 +580,7 @@ project = os.environ.get("MANAGED_EDIT_PROJECT", "") or os.getcwd()
576
580
  FOLLOW_MAX_BYTES = 262144
577
581
  FOLLOW_MAX_FILES = 8
578
582
  FOLLOW_MAX_DEPTH = 3
583
+ ENV_SPLIT_UNRESOLVED = 42
579
584
 
580
585
  # Spelled with chr() rather than backslash escapes on purpose. This source is
581
586
  # embedded in a shell heredoc and copied verbatim through several generators
@@ -607,7 +612,7 @@ FOLLOW_WRAPPERS = {
607
612
  # positional count: the walk below re-enters its assignment skip on the
608
613
  # next iteration and steps over as many as are present.
609
614
  "env": (
610
- frozenset({"-C", "--chdir", "-P", "-S", "--split-string", "-u", "--unset"}),
615
+ frozenset({"-C", "--chdir", "-P", "-u", "--unset"}),
611
616
  0,
612
617
  ),
613
618
  "exec": (frozenset({"-a"}), 0),
@@ -741,6 +746,31 @@ def statements(tokens):
741
746
  return grouped
742
747
 
743
748
 
749
+ class UnresolvedEnvSplit(ValueError):
750
+ """Split-string syntax whose executed arguments cannot be proven here."""
751
+
752
+
753
+ def parse_env_split(split_string):
754
+ """Parse only the env -S subset shared with ordinary quoted arguments.
755
+
756
+ GNU env has its own escapes, comments and environment interpolation. Do
757
+ not pretend shlex implements those, or invent environment values in a
758
+ pre-execution guard. The operator can spell the resulting command directly.
759
+
760
+ Args:
761
+ split_string: The literal argument supplied to env's split option.
762
+
763
+ Returns:
764
+ Arguments for the supported subset; otherwise raises UnresolvedEnvSplit.
765
+ """
766
+ if any(marker in split_string for marker in (BACKSLASH, "#", "$", chr(96), chr(11), chr(12))):
767
+ raise UnresolvedEnvSplit("escapes, comments, shell substitution, variable expansion or control whitespace")
768
+ try:
769
+ return shlex.split(split_string, comments=False, posix=True)
770
+ except ValueError as error:
771
+ raise UnresolvedEnvSplit("unbalanced quoting") from error
772
+
773
+
744
774
  def command_word(statement):
745
775
  """The program a statement runs, and the tokens after it.
746
776
 
@@ -757,6 +787,7 @@ def command_word(statement):
757
787
  its command word is itself the executed script.
758
788
  """
759
789
  index = 0
790
+ split_expansions = 0
760
791
  while index < len(statement):
761
792
  token = statement[index]
762
793
  if "=" in token and not token.startswith(("=", "-")):
@@ -772,6 +803,36 @@ def command_word(statement):
772
803
  if option == "--":
773
804
  index += 1
774
805
  break
806
+ # env -S inserts the split string back into env's argument list;
807
+ # it is executable input, not an option value to discard. Keep
808
+ # shell -c's quoted operand intact while expanding the env layer.
809
+ # The known no-operand flags can be combined before S (-vS/-ivS).
810
+ # Stop at S: the rest belongs to its argument, not more flags.
811
+ short_split = re.match(r"^-[iv0]*S(.*)$", option)
812
+ if program == "env" and (
813
+ option == "--split-string"
814
+ or option.startswith("--split-string=")
815
+ or short_split is not None
816
+ ):
817
+ consumed = 1
818
+ if option == "--split-string" or (
819
+ short_split is not None and not short_split.group(1)
820
+ ):
821
+ if index + 1 >= len(statement):
822
+ raise UnresolvedEnvSplit("missing split-string operand")
823
+ split_string = statement[index + 1]
824
+ consumed = 2
825
+ elif option.startswith("--split-string="):
826
+ split_string = option.split("=", 1)[1]
827
+ else:
828
+ split_string = short_split.group(1)
829
+ if split_expansions >= 64:
830
+ raise UnresolvedEnvSplit("nested split-string limit")
831
+ expanded = parse_env_split(split_string)
832
+ statement = [token] + expanded + statement[index + consumed :]
833
+ split_expansions += 1
834
+ index = 0
835
+ break
775
836
  index += 2 if option in separate else 1
776
837
  index += positional
777
838
  return (None, None, [])
@@ -985,7 +1046,11 @@ def collect(text, depth, seen, out):
985
1046
 
986
1047
 
987
1048
  targets = []
988
- collect(command, 0, set(), targets)
1049
+ try:
1050
+ collect(command, 0, set(), targets)
1051
+ except UnresolvedEnvSplit as error:
1052
+ sys.stderr.write(str(error) + NEWLINE)
1053
+ sys.exit(ENV_SPLIT_UNRESOLVED)
989
1054
  for target in targets:
990
1055
  cleaned = target.strip().strip("'\"")
991
1056
  if cleaned:
@@ -1003,6 +1068,15 @@ PY
1003
1068
  else
1004
1069
  analyzer_status=$?
1005
1070
  fi
1071
+ if [ "$analyzer_status" -eq 42 ]; then
1072
+ printf 'Blocked: cannot resolve env --split-string for managed-file protection.\n' >&2
1073
+ printf 'Use an explicit command without split-string escapes, comments or variable expansion.\n' >&2
1074
+ while IFS= read -r analyzer_line; do
1075
+ [ -n "$analyzer_line" ] && printf ' %s\n' "$analyzer_line" >&2
1076
+ done <"$analyzer_stderr"
1077
+ rm -f "$analyzer_stderr"
1078
+ exit 2
1079
+ fi
1006
1080
  if [ "$analyzer_status" -ne 0 ]; then
1007
1081
  printf 'block-managed-file-edits: Bash analyzer failed (exit %s); Bash write protection is NOT active\n' "$analyzer_status" >&2
1008
1082
  while IFS= read -r analyzer_line; do
@@ -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: blocks commands that bypass git's verification hooks.
3
6
  # Bypassing pre-commit/pre-push hooks (which exist for a reason) is blocked in
4
7
  # all of its forms; the fix is to address the underlying issue, not silence the
@@ -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: blocks structural JSON parsing with text tools.
3
6
  # Text tools (grep/sed/cut/awk) break on valid JSON — multiline values, escaped
4
7
  # quotes, reordered keys, nested objects — producing silently wrong output
@@ -1,3 +1,6 @@
1
+ # This file is managed by Lisa and IS replaced on each `lisa` run.
2
+ # Do not edit directly — durable changes belong upstream in Lisa.
3
+
1
4
  # shellcheck shell=bash
2
5
  # Evaluate a dual-channel guard once per tool call, without de-registering it.
3
6
  #
@@ -51,12 +54,9 @@
51
54
  # refusal reaching the agent without the message that explains it. On a
52
55
  # refusal every channel evaluates and speaks exactly as it does today.
53
56
  #
54
- # COST ON THE PATH THAT GETS NO BENEFIT. A host with one channel must not pay
55
- # for a mechanism it cannot use. The channel check is builtins only — one small
56
- # file read, no subshell, no fork — and returns before the digest is computed
57
- # unless a second channel has actually been seen. The digest, and the one `stat`
58
- # that feeds it the per-call discriminator, are reached only where a second
59
- # channel is live, which is exactly where they are repaid.
57
+ # State ownership, modes and ancestry are verified before channel discovery.
58
+ # After that validation the channel check uses only builtins, and returns
59
+ # before digesting code or sizing the transcript unless another channel is live.
60
60
 
61
61
  # Key this guard would memoise under, once computed. Empty means "record
62
62
  # nothing on exit".
@@ -74,14 +74,25 @@ lisa_guard_memo_ready=0
74
74
  # Digest tool for the memo key, resolved once. Empty disables the memo.
75
75
  lisa_guard_memo_digest_tool=""
76
76
 
77
- # Whether a directory is a real directory this user owns, and not a symlink —
78
- # builtins only, so this costs no process.
79
- #
80
- # `-O` is the load-bearing test: a memo planted by another user would suppress a
81
- # refusal, so a directory this user does not own is never used. The dispatcher
82
- # validates the whole parent chain before exporting `LISA_GUARD_MEMO_DIR`; this
83
- # re-checks the leaf rather than trusting the environment variable, because an
84
- # exported path is an input like any other.
77
+ # Read ownership and all permission bits without accepting output from a
78
+ # failed platform-specific stat invocation.
79
+ # $1 - directory; sets lisa_guard_memo_owner and lisa_guard_memo_mode
80
+ lisa_guard_memo_stat() {
81
+ local facts=""
82
+ facts="$(stat -c '%u %a' "$1" 2>/dev/null)" ||
83
+ facts="$(stat -f '%u %p' "$1" 2>/dev/null)" || return 1
84
+ lisa_guard_memo_owner="${facts%% *}"
85
+ lisa_guard_memo_mode="${facts#* }"
86
+ case "$lisa_guard_memo_owner:$lisa_guard_memo_mode" in
87
+ *[!0-9:]* | :* | *:) return 1 ;;
88
+ esac
89
+ case "$lisa_guard_memo_mode" in *[!0-7]*) return 1 ;; esac
90
+ lisa_guard_memo_mode=$((8#$lisa_guard_memo_mode & 8#7777))
91
+ }
92
+
93
+ # Memo leaves must be private even when a sticky shared temp ancestor is safe.
94
+ # Ownership alone allows another local account to plant a session/allow file
95
+ # in an owned but group- or world-writable directory.
85
96
  #
86
97
  # $1 - candidate directory
87
98
  lisa_guard_memo_dir_usable() {
@@ -89,23 +100,42 @@ lisa_guard_memo_dir_usable() {
89
100
  [ -d "$1" ] || return 1
90
101
  [ ! -L "$1" ] || return 1
91
102
  [ -O "$1" ] || return 1
103
+ lisa_guard_memo_stat "$1" || return 1
104
+ [ $((lisa_guard_memo_mode & 8#0022)) -eq 0 ]
105
+ }
106
+
107
+ # Resolve parents physically and verify every ancestor. Plugin hooks do not
108
+ # inherit the dispatcher's trust walk, and exported paths are still inputs.
109
+ # $1 - candidate memo base; sets lisa_guard_memo_base only on success
110
+ lisa_guard_memo_trust_base() {
111
+ lisa_guard_memo_dir_usable "$1" || return 1
112
+ local physical=""
113
+ physical="$(cd "$1" 2>/dev/null && pwd -P)" || return 1
114
+ local current="$physical"
115
+ while :; do
116
+ lisa_guard_memo_stat "$current" || return 1
117
+ [ "$lisa_guard_memo_owner" = 0 ] || [ -O "$current" ] || return 1
118
+ if [ $((lisa_guard_memo_mode & 8#0022)) -ne 0 ] &&
119
+ [ $((lisa_guard_memo_mode & 8#1000)) -eq 0 ]; then
120
+ return 1
121
+ fi
122
+ [ "$current" != / ] || break
123
+ current="${current%/*}"
124
+ [ -n "$current" ] || current=/
125
+ done
126
+ lisa_guard_memo_base="$physical"
92
127
  }
93
128
 
94
129
  # Establish the memo base directory.
95
130
  #
96
- # Preferred source is `LISA_GUARD_MEMO_DIR`, exported by the dispatcher, which
97
- # has already resolved `TMPDIR` physically and walked every parent for ownership
98
- # and mode. Guards it spawns therefore pay nothing for that walk. A guard
99
- # reached by the plugin channel has no such parent, so it creates the directory
100
- # itself under `TMPDIR` — private by umask, and used only when this user owns
101
- # it. If neither works the memo is unavailable and every guard evaluates, which
102
- # is today's behaviour.
131
+ # Preferred source is `LISA_GUARD_MEMO_DIR`, exported by the dispatcher. Both
132
+ # this input and the plugin channel's TMPDIR fallback receive the same trust
133
+ # checks. Missing state is created privately; untrusted state disables memo use.
103
134
  lisa_guard_memo_resolve_base() {
104
135
  [ -z "$lisa_guard_memo_base" ] || return 0
105
136
 
106
137
  local candidate="${LISA_GUARD_MEMO_DIR:-}"
107
- if lisa_guard_memo_dir_usable "$candidate"; then
108
- lisa_guard_memo_base="$candidate"
138
+ if lisa_guard_memo_trust_base "$candidate"; then
109
139
  return 0
110
140
  fi
111
141
 
@@ -118,8 +148,7 @@ lisa_guard_memo_resolve_base() {
118
148
  if [ ! -e "$candidate" ] && [ ! -L "$candidate" ]; then
119
149
  (umask 077 && mkdir -p "$candidate") 2>/dev/null || true
120
150
  fi
121
- if lisa_guard_memo_dir_usable "$candidate"; then
122
- lisa_guard_memo_base="$candidate"
151
+ if lisa_guard_memo_trust_base "$candidate"; then
123
152
  return 0
124
153
  fi
125
154
  return 1
@@ -165,6 +194,7 @@ lisa_guard_memo_sweep() {
165
194
  #
166
195
  # $1 - guard name, used only to name the memo file
167
196
  # $2 - the raw tool payload this guard was handed on stdin
197
+ # Remaining arguments - files containing delegated verdict code
168
198
  lisa_guard_dedupe() {
169
199
  local guard_name="${1:-}"
170
200
  local payload="${2:-}"
@@ -194,8 +224,7 @@ lisa_guard_dedupe() {
194
224
  fresh_session=1
195
225
  fi
196
226
  fi
197
- [ -d "$session_dir" ] || return 0
198
- [ ! -L "$session_dir" ] || return 0
227
+ lisa_guard_memo_dir_usable "$session_dir" || return 0
199
228
 
200
229
  # Swept once, by the process that created the session directory, so a
201
230
  # long-lived machine does not accumulate memo state. Off the hot path by
@@ -278,11 +307,18 @@ lisa_guard_dedupe() {
278
307
  case "$transcript_size" in "" | *[!0-9]*) return 0 ;; esac
279
308
 
280
309
  # One command substitution, covering everything the verdict depends on: the
281
- # guard's own bytes, this library's bytes, the payload, and which call it is.
310
+ # guard's own bytes, this library, delegated code, payload, and call identity.
311
+ # Keep literal bytes (including trailing newlines), and propagate every read
312
+ # failure. A successful digest of a partial stream is not proof of identity.
282
313
  local key=""
283
314
  key="$(
315
+ set -o pipefail
284
316
  {
285
- cat "$self_script" "${BASH_SOURCE[0]}" 2>/dev/null
317
+ local source_file=""
318
+ for source_file in "$self_script" "${BASH_SOURCE[0]}" "${@:3}"; do
319
+ cat "$source_file" 2>/dev/null || exit 1
320
+ printf '\0'
321
+ done
286
322
  printf '\n%s\n' "$payload"
287
323
  printf '%s\n' "$transcript_size"
288
324
  } | if [ "$lisa_guard_memo_digest_tool" = "shasum" ]; then
@@ -293,6 +329,7 @@ lisa_guard_dedupe() {
293
329
  )" || key=""
294
330
  key="${key%% *}"
295
331
  case "$key" in "" | *[!0-9a-f]*) return 0 ;; esac
332
+ [ "${#key}" -eq 64 ] || return 0
296
333
 
297
334
  # One memo file per guard per session, rewritten as the call moves on, so the
298
335
  # state directory stays a fixed size however long a session runs. A saturated
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env python3
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
  """Classify the only heredoc forms whose payload is non-executable text.
3
6
 
4
7
  SCOPE — read this before hardening anything here (issue #1993).
@@ -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: a safety net that blocks destructive shell commands
3
6
  # before they run. Lisa-native reimplementation of the upstream
4
7
  # `safety-net@cc-marketplace` plugin's PreToolUse Bash-guard (parity work,
@@ -136,7 +139,8 @@ if [ -r "$lisa_guard_dedupe_lib" ]; then
136
139
  # shellcheck source=guard-dedupe.bash
137
140
  . "$lisa_guard_dedupe_lib"
138
141
  trap 'lisa_guard_dedupe_record $?' EXIT
139
- lisa_guard_dedupe parity-safety-net "$input"
142
+ lisa_guard_dedupe parity-safety-net "$input" \
143
+ "$lisa_guard_hook_dir/parity-safety-net-heredoc.py"
140
144
  fi
141
145
 
142
146
  tool_name="$(printf '%s' "$input" | jq -r '.tool_name // empty')"
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
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
  /**
3
6
  * Reconcile the worktree a session was TOLD it is in against the one it is
4
7
  * ACTUALLY operating in, and refuse to act while the two disagree.
@@ -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 guard for Bash/Write/Edit/MultiEdit, and PostToolUse recorder for
3
6
  # EnterWorktree: refuse to act while the worktree the session was told it is in
4
7
  # disagrees with the one it is measurably in (CodySwannGT/lisa#3864).
@@ -54,7 +57,8 @@ if [ -r "$lisa_guard_dedupe_lib" ]; then
54
57
  # shellcheck source=guard-dedupe.bash
55
58
  . "$lisa_guard_dedupe_lib"
56
59
  trap 'lisa_guard_dedupe_record $?' EXIT
57
- lisa_guard_dedupe worktree-binding-guard "$input"
60
+ lisa_guard_dedupe worktree-binding-guard "$input" \
61
+ "$lisa_guard_hook_dir/worktree-binding-guard.mjs"
58
62
  fi
59
63
 
60
64
  if ! command -v node >/dev/null 2>&1; then
@@ -68,6 +68,7 @@ Paths are relative to this file.
68
68
 
69
69
  | Slug | Read it when | Body |
70
70
  |---|---|---|
71
+ | `operational-hazards` | looking up or publishing an active operational hazard that other sessions must see | [../reference/operational-hazards.md](../reference/operational-hazards.md) |
71
72
  | `automation-runbook-contract` | registering a loop, or ending any flow with its run outcome | [../reference/automation-runbook-contract.md](../reference/automation-runbook-contract.md) |
72
73
  | `convergent-review` | reviewing a PR or resolving review findings | [../reference/convergent-review.md](../reference/convergent-review.md) |
73
74
  | `credential-substrate-precedence` | writing or editing an `*-access` skill | [../reference/credential-substrate-precedence.md](../reference/credential-substrate-precedence.md) |
@@ -7,7 +7,7 @@ These are mandatory disciplines that apply to every session. Full prose, JIRA de
7
7
  You are factory machinery, not a chat assistant. Three consequences bind every session:
8
8
 
9
9
  - **Do not pause mid-flow to ask a human whether to proceed.** Handoff happens at the gates — the ready-role flips and intake's adversarial validation — never in the middle of a flow.
10
- - **Every flow must work headless**: no interactive prompts, idempotent re-runs, clean exits on empty queues. Flows run under native schedulers as often as under a human.
10
+ - **Every admitted flow must work headless**: no interactive prompts after admission, idempotent re-runs, clean exits on empty queues. Resolve required input before admission: interactive requests may need clarification; unattended requests with missing input return `recovery-required` without guessing or applying side effects. Flows run under native schedulers as often as under a human.
11
11
  - **Never weaken a gate to get work through it — fix the work.**
12
12
 
13
13
  The model these follow from (the four factories, the gate, the loops, the brownfield on-ramp) is [reference/factory-model.md](../reference/factory-model.md); read it when you need the shape rather than the obligations.
@@ -16,6 +16,8 @@ The model these follow from (the four factories, the gate, the loops, the brownf
16
16
 
17
17
  Treat every request as potentially underspecified. Before starting any work:
18
18
 
19
+ **Unattended: override stop-and-ask below.** Missing input means `recovery-required`: no guessing, prompts or side effects. Ask only before interactive admission.
20
+
19
21
  1. Identify ambiguities that would prevent completion. If any exist, stop and ask.
20
22
  2. Identify open questions whose answers would change your approach. If any exist, stop and ask.
21
23
  3. Define how you will empirically verify the work is complete by USING the resulting software, not just running tests. If you cannot define this, stop and ask.