@codyswann/lisa 2.353.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (318) hide show
  1. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  2. package/dist/core/upstream-evidence-manifest.js +83 -47
  3. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  4. package/expo/copy-overwrite/scripts/bdd/discover.mjs +502 -0
  5. package/expo/copy-overwrite/scripts/bdd/envelope.mjs +10 -1
  6. package/expo/copy-overwrite/scripts/bdd/render.mjs +53 -0
  7. package/expo/copy-overwrite/scripts/bdd/report.mjs +46 -0
  8. package/expo/copy-overwrite/scripts/check-bdd-coverage.mjs +39 -4
  9. package/expo/create-only/.github/workflows/nightly-e2e-report.yml +71 -0
  10. package/expo/create-only/bdd/coverage-map.json +16 -0
  11. package/package.json +1 -1
  12. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  13. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  14. package/plugins/lisa/.codex-plugin/skills/lisa-agent-ready/SKILL.md +5 -3
  15. package/plugins/lisa/.codex-plugin/skills/lisa-atlassian-access/SKILL.md +75 -64
  16. package/plugins/lisa/.codex-plugin/skills/lisa-confluence-to-tracker/SKILL.md +2 -1
  17. package/plugins/lisa/.codex-plugin/skills/lisa-debrief-apply/SKILL.md +2 -2
  18. package/plugins/lisa/.codex-plugin/skills/lisa-exploratory-qa/SKILL.md +7 -1
  19. package/plugins/lisa/.codex-plugin/skills/lisa-github-build-intake/SKILL.md +5 -0
  20. package/plugins/lisa/.codex-plugin/skills/lisa-github-create/SKILL.md +3 -1
  21. package/plugins/lisa/.codex-plugin/skills/lisa-github-to-tracker/SKILL.md +2 -1
  22. package/plugins/lisa/.codex-plugin/skills/lisa-github-validate-issue/SKILL.md +7 -3
  23. package/plugins/lisa/.codex-plugin/skills/lisa-github-write-issue/SKILL.md +16 -6
  24. package/plugins/lisa/.codex-plugin/skills/lisa-improve-harness/SKILL.md +1 -1
  25. package/plugins/lisa/.codex-plugin/skills/lisa-jam-access/SKILL.md +13 -5
  26. package/plugins/lisa/.codex-plugin/skills/lisa-jira-build-intake/SKILL.md +5 -0
  27. package/plugins/lisa/.codex-plugin/skills/lisa-jira-create/SKILL.md +2 -0
  28. package/plugins/lisa/.codex-plugin/skills/lisa-jira-write-ticket/SKILL.md +12 -2
  29. package/plugins/lisa/.codex-plugin/skills/lisa-learnings-audit/SKILL.md +6 -1
  30. package/plugins/lisa/.codex-plugin/skills/lisa-linear-access/SKILL.md +30 -10
  31. package/plugins/lisa/.codex-plugin/skills/lisa-linear-build-intake/SKILL.md +5 -0
  32. package/plugins/lisa/.codex-plugin/skills/lisa-linear-create/SKILL.md +3 -1
  33. package/plugins/lisa/.codex-plugin/skills/lisa-linear-to-tracker/SKILL.md +2 -1
  34. package/plugins/lisa/.codex-plugin/skills/lisa-linear-write-issue/SKILL.md +13 -4
  35. package/plugins/lisa/.codex-plugin/skills/lisa-notion-access/SKILL.md +36 -23
  36. package/plugins/lisa/.codex-plugin/skills/lisa-notion-to-tracker/SKILL.md +2 -1
  37. package/plugins/lisa/.codex-plugin/skills/lisa-persist-learning/SKILL.md +1 -1
  38. package/plugins/lisa/.codex-plugin/skills/lisa-posthog-access/SKILL.md +16 -6
  39. package/plugins/lisa/.codex-plugin/skills/lisa-prd-source-write/SKILL.md +4 -2
  40. package/plugins/lisa/.codex-plugin/skills/lisa-qa-fail/SKILL.md +3 -1
  41. package/plugins/lisa/.codex-plugin/skills/lisa-repair-intake/SKILL.md +28 -0
  42. package/plugins/lisa/.codex-plugin/skills/lisa-rework-triage/SKILL.md +2 -2
  43. package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/SKILL.md +8 -0
  44. package/plugins/lisa/.codex-plugin/skills/lisa-sentry-access/SKILL.md +16 -6
  45. package/plugins/lisa/.codex-plugin/skills/lisa-sonarcloud-access/SKILL.md +7 -1
  46. package/plugins/lisa/.codex-plugin/skills/lisa-tracker-build-intake/SKILL.md +1 -0
  47. package/plugins/lisa/.codex-plugin/skills/lisa-tracker-create/SKILL.md +1 -0
  48. package/plugins/lisa/.codex-plugin/skills/lisa-tracker-write/SKILL.md +1 -0
  49. package/plugins/lisa/.codex-plugin/skills/lisa-verify/SKILL.md +1 -1
  50. package/plugins/lisa/rules/eager/bdd-e2e-coverage.md +3 -1
  51. package/plugins/lisa/rules/eager/claim-time-guards.md +30 -0
  52. package/plugins/lisa/rules/eager/integration-access-layer.md +7 -3
  53. package/plugins/lisa/rules/eager/ready-role-filing.md +22 -0
  54. package/plugins/lisa/rules/reference/automation-runbook-contract.md +8 -1
  55. package/plugins/lisa/rules/reference/bdd-e2e-coverage.md +42 -6
  56. package/plugins/lisa/rules/reference/claim-time-guards.md +69 -0
  57. package/plugins/lisa/rules/reference/credential-substrate-precedence.md +166 -0
  58. package/plugins/lisa/rules/reference/integration-access-layer.md +27 -15
  59. package/plugins/lisa/rules/reference/ready-role-filing.md +66 -0
  60. package/plugins/lisa/skills/lisa-agent-ready/SKILL.md +5 -3
  61. package/plugins/lisa/skills/lisa-atlassian-access/SKILL.md +76 -65
  62. package/plugins/lisa/skills/lisa-confluence-to-tracker/SKILL.md +2 -1
  63. package/plugins/lisa/skills/lisa-debrief-apply/SKILL.md +2 -2
  64. package/plugins/lisa/skills/lisa-exploratory-qa/SKILL.md +7 -1
  65. package/plugins/lisa/skills/lisa-github-build-intake/SKILL.md +5 -0
  66. package/plugins/lisa/skills/lisa-github-create/SKILL.md +3 -1
  67. package/plugins/lisa/skills/lisa-github-to-tracker/SKILL.md +2 -1
  68. package/plugins/lisa/skills/lisa-github-validate-issue/SKILL.md +7 -3
  69. package/plugins/lisa/skills/lisa-github-write-issue/SKILL.md +16 -6
  70. package/plugins/lisa/skills/lisa-improve-harness/SKILL.md +1 -1
  71. package/plugins/lisa/skills/lisa-jam-access/SKILL.md +14 -6
  72. package/plugins/lisa/skills/lisa-jira-build-intake/SKILL.md +5 -0
  73. package/plugins/lisa/skills/lisa-jira-create/SKILL.md +2 -0
  74. package/plugins/lisa/skills/lisa-jira-write-ticket/SKILL.md +12 -2
  75. package/plugins/lisa/skills/lisa-learnings-audit/SKILL.md +6 -1
  76. package/plugins/lisa/skills/lisa-linear-access/SKILL.md +31 -11
  77. package/plugins/lisa/skills/lisa-linear-build-intake/SKILL.md +5 -0
  78. package/plugins/lisa/skills/lisa-linear-create/SKILL.md +3 -1
  79. package/plugins/lisa/skills/lisa-linear-to-tracker/SKILL.md +2 -1
  80. package/plugins/lisa/skills/lisa-linear-write-issue/SKILL.md +13 -4
  81. package/plugins/lisa/skills/lisa-notion-access/SKILL.md +37 -24
  82. package/plugins/lisa/skills/lisa-notion-to-tracker/SKILL.md +2 -1
  83. package/plugins/lisa/skills/lisa-persist-learning/SKILL.md +1 -1
  84. package/plugins/lisa/skills/lisa-posthog-access/SKILL.md +17 -7
  85. package/plugins/lisa/skills/lisa-prd-source-write/SKILL.md +4 -2
  86. package/plugins/lisa/skills/lisa-qa-fail/SKILL.md +3 -1
  87. package/plugins/lisa/skills/lisa-repair-intake/SKILL.md +28 -0
  88. package/plugins/lisa/skills/lisa-rework-triage/SKILL.md +2 -2
  89. package/plugins/lisa/skills/lisa-secrets-access/SKILL.md +8 -0
  90. package/plugins/lisa/skills/lisa-sentry-access/SKILL.md +17 -7
  91. package/plugins/lisa/skills/lisa-sonarcloud-access/SKILL.md +7 -1
  92. package/plugins/lisa/skills/lisa-tracker-build-intake/SKILL.md +1 -0
  93. package/plugins/lisa/skills/lisa-tracker-create/SKILL.md +1 -0
  94. package/plugins/lisa/skills/lisa-tracker-write/SKILL.md +1 -0
  95. package/plugins/lisa/skills/lisa-verify/SKILL.md +1 -1
  96. package/plugins/lisa-agy/plugin.json +1 -1
  97. package/plugins/lisa-agy/skills/lisa-agent-ready/SKILL.md +5 -3
  98. package/plugins/lisa-agy/skills/lisa-atlassian-access/SKILL.md +76 -65
  99. package/plugins/lisa-agy/skills/lisa-confluence-to-tracker/SKILL.md +2 -1
  100. package/plugins/lisa-agy/skills/lisa-debrief-apply/SKILL.md +2 -2
  101. package/plugins/lisa-agy/skills/lisa-exploratory-qa/SKILL.md +7 -1
  102. package/plugins/lisa-agy/skills/lisa-github-build-intake/SKILL.md +5 -0
  103. package/plugins/lisa-agy/skills/lisa-github-create/SKILL.md +3 -1
  104. package/plugins/lisa-agy/skills/lisa-github-to-tracker/SKILL.md +2 -1
  105. package/plugins/lisa-agy/skills/lisa-github-validate-issue/SKILL.md +7 -3
  106. package/plugins/lisa-agy/skills/lisa-github-write-issue/SKILL.md +16 -6
  107. package/plugins/lisa-agy/skills/lisa-improve-harness/SKILL.md +1 -1
  108. package/plugins/lisa-agy/skills/lisa-jam-access/SKILL.md +14 -6
  109. package/plugins/lisa-agy/skills/lisa-jira-build-intake/SKILL.md +5 -0
  110. package/plugins/lisa-agy/skills/lisa-jira-create/SKILL.md +2 -0
  111. package/plugins/lisa-agy/skills/lisa-jira-write-ticket/SKILL.md +12 -2
  112. package/plugins/lisa-agy/skills/lisa-learnings-audit/SKILL.md +6 -1
  113. package/plugins/lisa-agy/skills/lisa-linear-access/SKILL.md +31 -11
  114. package/plugins/lisa-agy/skills/lisa-linear-build-intake/SKILL.md +5 -0
  115. package/plugins/lisa-agy/skills/lisa-linear-create/SKILL.md +3 -1
  116. package/plugins/lisa-agy/skills/lisa-linear-to-tracker/SKILL.md +2 -1
  117. package/plugins/lisa-agy/skills/lisa-linear-write-issue/SKILL.md +13 -4
  118. package/plugins/lisa-agy/skills/lisa-notion-access/SKILL.md +37 -24
  119. package/plugins/lisa-agy/skills/lisa-notion-to-tracker/SKILL.md +2 -1
  120. package/plugins/lisa-agy/skills/lisa-persist-learning/SKILL.md +1 -1
  121. package/plugins/lisa-agy/skills/lisa-posthog-access/SKILL.md +17 -7
  122. package/plugins/lisa-agy/skills/lisa-prd-source-write/SKILL.md +4 -2
  123. package/plugins/lisa-agy/skills/lisa-qa-fail/SKILL.md +3 -1
  124. package/plugins/lisa-agy/skills/lisa-repair-intake/SKILL.md +28 -0
  125. package/plugins/lisa-agy/skills/lisa-rework-triage/SKILL.md +2 -2
  126. package/plugins/lisa-agy/skills/lisa-secrets-access/SKILL.md +8 -0
  127. package/plugins/lisa-agy/skills/lisa-sentry-access/SKILL.md +17 -7
  128. package/plugins/lisa-agy/skills/lisa-sonarcloud-access/SKILL.md +7 -1
  129. package/plugins/lisa-agy/skills/lisa-tracker-build-intake/SKILL.md +1 -0
  130. package/plugins/lisa-agy/skills/lisa-tracker-create/SKILL.md +1 -0
  131. package/plugins/lisa-agy/skills/lisa-tracker-write/SKILL.md +1 -0
  132. package/plugins/lisa-agy/skills/lisa-verify/SKILL.md +1 -1
  133. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  134. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  135. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  136. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  137. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  138. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  139. package/plugins/lisa-copilot/rules/eager/bdd-e2e-coverage.md +3 -1
  140. package/plugins/lisa-copilot/rules/eager/claim-time-guards.md +30 -0
  141. package/plugins/lisa-copilot/rules/eager/integration-access-layer.md +7 -3
  142. package/plugins/lisa-copilot/rules/eager/ready-role-filing.md +22 -0
  143. package/plugins/lisa-copilot/rules/reference/automation-runbook-contract.md +8 -1
  144. package/plugins/lisa-copilot/rules/reference/bdd-e2e-coverage.md +42 -6
  145. package/plugins/lisa-copilot/rules/reference/claim-time-guards.md +69 -0
  146. package/plugins/lisa-copilot/rules/reference/credential-substrate-precedence.md +166 -0
  147. package/plugins/lisa-copilot/rules/reference/integration-access-layer.md +27 -15
  148. package/plugins/lisa-copilot/rules/reference/ready-role-filing.md +66 -0
  149. package/plugins/lisa-copilot/skills/lisa-agent-ready/SKILL.md +5 -3
  150. package/plugins/lisa-copilot/skills/lisa-atlassian-access/SKILL.md +76 -65
  151. package/plugins/lisa-copilot/skills/lisa-confluence-to-tracker/SKILL.md +2 -1
  152. package/plugins/lisa-copilot/skills/lisa-debrief-apply/SKILL.md +2 -2
  153. package/plugins/lisa-copilot/skills/lisa-exploratory-qa/SKILL.md +7 -1
  154. package/plugins/lisa-copilot/skills/lisa-github-build-intake/SKILL.md +5 -0
  155. package/plugins/lisa-copilot/skills/lisa-github-create/SKILL.md +3 -1
  156. package/plugins/lisa-copilot/skills/lisa-github-to-tracker/SKILL.md +2 -1
  157. package/plugins/lisa-copilot/skills/lisa-github-validate-issue/SKILL.md +7 -3
  158. package/plugins/lisa-copilot/skills/lisa-github-write-issue/SKILL.md +16 -6
  159. package/plugins/lisa-copilot/skills/lisa-improve-harness/SKILL.md +1 -1
  160. package/plugins/lisa-copilot/skills/lisa-jam-access/SKILL.md +14 -6
  161. package/plugins/lisa-copilot/skills/lisa-jira-build-intake/SKILL.md +5 -0
  162. package/plugins/lisa-copilot/skills/lisa-jira-create/SKILL.md +2 -0
  163. package/plugins/lisa-copilot/skills/lisa-jira-write-ticket/SKILL.md +12 -2
  164. package/plugins/lisa-copilot/skills/lisa-learnings-audit/SKILL.md +6 -1
  165. package/plugins/lisa-copilot/skills/lisa-linear-access/SKILL.md +31 -11
  166. package/plugins/lisa-copilot/skills/lisa-linear-build-intake/SKILL.md +5 -0
  167. package/plugins/lisa-copilot/skills/lisa-linear-create/SKILL.md +3 -1
  168. package/plugins/lisa-copilot/skills/lisa-linear-to-tracker/SKILL.md +2 -1
  169. package/plugins/lisa-copilot/skills/lisa-linear-write-issue/SKILL.md +13 -4
  170. package/plugins/lisa-copilot/skills/lisa-notion-access/SKILL.md +37 -24
  171. package/plugins/lisa-copilot/skills/lisa-notion-to-tracker/SKILL.md +2 -1
  172. package/plugins/lisa-copilot/skills/lisa-persist-learning/SKILL.md +1 -1
  173. package/plugins/lisa-copilot/skills/lisa-posthog-access/SKILL.md +17 -7
  174. package/plugins/lisa-copilot/skills/lisa-prd-source-write/SKILL.md +4 -2
  175. package/plugins/lisa-copilot/skills/lisa-qa-fail/SKILL.md +3 -1
  176. package/plugins/lisa-copilot/skills/lisa-repair-intake/SKILL.md +28 -0
  177. package/plugins/lisa-copilot/skills/lisa-rework-triage/SKILL.md +2 -2
  178. package/plugins/lisa-copilot/skills/lisa-secrets-access/SKILL.md +8 -0
  179. package/plugins/lisa-copilot/skills/lisa-sentry-access/SKILL.md +17 -7
  180. package/plugins/lisa-copilot/skills/lisa-sonarcloud-access/SKILL.md +7 -1
  181. package/plugins/lisa-copilot/skills/lisa-tracker-build-intake/SKILL.md +1 -0
  182. package/plugins/lisa-copilot/skills/lisa-tracker-create/SKILL.md +1 -0
  183. package/plugins/lisa-copilot/skills/lisa-tracker-write/SKILL.md +1 -0
  184. package/plugins/lisa-copilot/skills/lisa-verify/SKILL.md +1 -1
  185. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  186. package/plugins/lisa-cursor/rules/automation-runbook-contract-reference.mdc +8 -1
  187. package/plugins/lisa-cursor/rules/bdd-e2e-coverage-reference.mdc +42 -6
  188. package/plugins/lisa-cursor/rules/bdd-e2e-coverage.mdc +3 -1
  189. package/plugins/lisa-cursor/rules/claim-time-guards-reference.mdc +74 -0
  190. package/plugins/lisa-cursor/rules/claim-time-guards.mdc +35 -0
  191. package/plugins/lisa-cursor/rules/credential-substrate-precedence-reference.mdc +171 -0
  192. package/plugins/lisa-cursor/rules/integration-access-layer-reference.mdc +27 -15
  193. package/plugins/lisa-cursor/rules/integration-access-layer.mdc +7 -3
  194. package/plugins/lisa-cursor/rules/ready-role-filing-reference.mdc +71 -0
  195. package/plugins/lisa-cursor/rules/ready-role-filing.mdc +27 -0
  196. package/plugins/lisa-cursor/skills/lisa-agent-ready/SKILL.md +5 -3
  197. package/plugins/lisa-cursor/skills/lisa-atlassian-access/SKILL.md +76 -65
  198. package/plugins/lisa-cursor/skills/lisa-confluence-to-tracker/SKILL.md +2 -1
  199. package/plugins/lisa-cursor/skills/lisa-debrief-apply/SKILL.md +2 -2
  200. package/plugins/lisa-cursor/skills/lisa-exploratory-qa/SKILL.md +7 -1
  201. package/plugins/lisa-cursor/skills/lisa-github-build-intake/SKILL.md +5 -0
  202. package/plugins/lisa-cursor/skills/lisa-github-create/SKILL.md +3 -1
  203. package/plugins/lisa-cursor/skills/lisa-github-to-tracker/SKILL.md +2 -1
  204. package/plugins/lisa-cursor/skills/lisa-github-validate-issue/SKILL.md +7 -3
  205. package/plugins/lisa-cursor/skills/lisa-github-write-issue/SKILL.md +16 -6
  206. package/plugins/lisa-cursor/skills/lisa-improve-harness/SKILL.md +1 -1
  207. package/plugins/lisa-cursor/skills/lisa-jam-access/SKILL.md +14 -6
  208. package/plugins/lisa-cursor/skills/lisa-jira-build-intake/SKILL.md +5 -0
  209. package/plugins/lisa-cursor/skills/lisa-jira-create/SKILL.md +2 -0
  210. package/plugins/lisa-cursor/skills/lisa-jira-write-ticket/SKILL.md +12 -2
  211. package/plugins/lisa-cursor/skills/lisa-learnings-audit/SKILL.md +6 -1
  212. package/plugins/lisa-cursor/skills/lisa-linear-access/SKILL.md +31 -11
  213. package/plugins/lisa-cursor/skills/lisa-linear-build-intake/SKILL.md +5 -0
  214. package/plugins/lisa-cursor/skills/lisa-linear-create/SKILL.md +3 -1
  215. package/plugins/lisa-cursor/skills/lisa-linear-to-tracker/SKILL.md +2 -1
  216. package/plugins/lisa-cursor/skills/lisa-linear-write-issue/SKILL.md +13 -4
  217. package/plugins/lisa-cursor/skills/lisa-notion-access/SKILL.md +37 -24
  218. package/plugins/lisa-cursor/skills/lisa-notion-to-tracker/SKILL.md +2 -1
  219. package/plugins/lisa-cursor/skills/lisa-persist-learning/SKILL.md +1 -1
  220. package/plugins/lisa-cursor/skills/lisa-posthog-access/SKILL.md +17 -7
  221. package/plugins/lisa-cursor/skills/lisa-prd-source-write/SKILL.md +4 -2
  222. package/plugins/lisa-cursor/skills/lisa-qa-fail/SKILL.md +3 -1
  223. package/plugins/lisa-cursor/skills/lisa-repair-intake/SKILL.md +28 -0
  224. package/plugins/lisa-cursor/skills/lisa-rework-triage/SKILL.md +2 -2
  225. package/plugins/lisa-cursor/skills/lisa-secrets-access/SKILL.md +8 -0
  226. package/plugins/lisa-cursor/skills/lisa-sentry-access/SKILL.md +17 -7
  227. package/plugins/lisa-cursor/skills/lisa-sonarcloud-access/SKILL.md +7 -1
  228. package/plugins/lisa-cursor/skills/lisa-tracker-build-intake/SKILL.md +1 -0
  229. package/plugins/lisa-cursor/skills/lisa-tracker-create/SKILL.md +1 -0
  230. package/plugins/lisa-cursor/skills/lisa-tracker-write/SKILL.md +1 -0
  231. package/plugins/lisa-cursor/skills/lisa-verify/SKILL.md +1 -1
  232. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  233. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  234. package/plugins/lisa-expo-agy/plugin.json +1 -1
  235. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  236. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  237. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  238. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  239. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  240. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  241. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  242. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  243. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  244. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  245. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  246. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  247. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  248. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  249. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  250. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  251. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  252. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  253. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  254. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  255. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  256. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  257. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  258. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  259. package/plugins/lisa-rails-agy/plugin.json +1 -1
  260. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  261. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  262. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  263. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  264. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  265. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  266. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  267. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  268. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  269. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  270. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  271. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  272. package/plugins/src/base/rules/eager/bdd-e2e-coverage.md +3 -1
  273. package/plugins/src/base/rules/eager/claim-time-guards.md +30 -0
  274. package/plugins/src/base/rules/eager/integration-access-layer.md +7 -3
  275. package/plugins/src/base/rules/eager/ready-role-filing.md +22 -0
  276. package/plugins/src/base/rules/reference/automation-runbook-contract.md +8 -1
  277. package/plugins/src/base/rules/reference/bdd-e2e-coverage.md +42 -6
  278. package/plugins/src/base/rules/reference/claim-time-guards.md +69 -0
  279. package/plugins/src/base/rules/reference/credential-substrate-precedence.md +166 -0
  280. package/plugins/src/base/rules/reference/integration-access-layer.md +27 -15
  281. package/plugins/src/base/rules/reference/ready-role-filing.md +66 -0
  282. package/plugins/src/base/skills/lisa-agent-ready/SKILL.md +5 -3
  283. package/plugins/src/base/skills/lisa-atlassian-access/SKILL.md +76 -65
  284. package/plugins/src/base/skills/lisa-confluence-to-tracker/SKILL.md +2 -1
  285. package/plugins/src/base/skills/lisa-debrief-apply/SKILL.md +2 -2
  286. package/plugins/src/base/skills/lisa-exploratory-qa/SKILL.md +7 -1
  287. package/plugins/src/base/skills/lisa-github-build-intake/SKILL.md +5 -0
  288. package/plugins/src/base/skills/lisa-github-create/SKILL.md +3 -1
  289. package/plugins/src/base/skills/lisa-github-to-tracker/SKILL.md +2 -1
  290. package/plugins/src/base/skills/lisa-github-validate-issue/SKILL.md +7 -3
  291. package/plugins/src/base/skills/lisa-github-write-issue/SKILL.md +16 -6
  292. package/plugins/src/base/skills/lisa-improve-harness/SKILL.md +1 -1
  293. package/plugins/src/base/skills/lisa-jam-access/SKILL.md +14 -6
  294. package/plugins/src/base/skills/lisa-jira-build-intake/SKILL.md +5 -0
  295. package/plugins/src/base/skills/lisa-jira-create/SKILL.md +2 -0
  296. package/plugins/src/base/skills/lisa-jira-write-ticket/SKILL.md +12 -2
  297. package/plugins/src/base/skills/lisa-learnings-audit/SKILL.md +6 -1
  298. package/plugins/src/base/skills/lisa-linear-access/SKILL.md +31 -11
  299. package/plugins/src/base/skills/lisa-linear-build-intake/SKILL.md +5 -0
  300. package/plugins/src/base/skills/lisa-linear-create/SKILL.md +3 -1
  301. package/plugins/src/base/skills/lisa-linear-to-tracker/SKILL.md +2 -1
  302. package/plugins/src/base/skills/lisa-linear-write-issue/SKILL.md +13 -4
  303. package/plugins/src/base/skills/lisa-notion-access/SKILL.md +37 -24
  304. package/plugins/src/base/skills/lisa-notion-to-tracker/SKILL.md +2 -1
  305. package/plugins/src/base/skills/lisa-persist-learning/SKILL.md +1 -1
  306. package/plugins/src/base/skills/lisa-posthog-access/SKILL.md +17 -7
  307. package/plugins/src/base/skills/lisa-prd-source-write/SKILL.md +4 -2
  308. package/plugins/src/base/skills/lisa-qa-fail/SKILL.md +3 -1
  309. package/plugins/src/base/skills/lisa-repair-intake/SKILL.md +28 -0
  310. package/plugins/src/base/skills/lisa-rework-triage/SKILL.md +2 -2
  311. package/plugins/src/base/skills/lisa-secrets-access/SKILL.md +8 -0
  312. package/plugins/src/base/skills/lisa-sentry-access/SKILL.md +17 -7
  313. package/plugins/src/base/skills/lisa-sonarcloud-access/SKILL.md +7 -1
  314. package/plugins/src/base/skills/lisa-tracker-build-intake/SKILL.md +1 -0
  315. package/plugins/src/base/skills/lisa-tracker-create/SKILL.md +1 -0
  316. package/plugins/src/base/skills/lisa-tracker-write/SKILL.md +1 -0
  317. package/plugins/src/base/skills/lisa-verify/SKILL.md +1 -1
  318. package/typescript/copy-overwrite/scripts/check-nightly-e2e-health.mjs +631 -5
@@ -50,6 +50,11 @@ import {
50
50
  subjectFor,
51
51
  } from "./bdd/envelope.mjs";
52
52
  import { checkDeletions, checkRatchet, loadBaseline } from "./bdd/baseline.mjs";
53
+ import {
54
+ disclosureDefects,
55
+ discoverSpecs,
56
+ missingDiscoveryDefects,
57
+ } from "./bdd/discover.mjs";
53
58
  import { loadScenarios } from "./bdd/parse.mjs";
54
59
  import { buildReport } from "./bdd/report.mjs";
55
60
  import { renderBurndown } from "./bdd/render.mjs";
@@ -236,12 +241,22 @@ export function loadExecutionResults(root, files) {
236
241
  * @param {object} input - Root, contract, scenarios, platforms, and options.
237
242
  * @returns {object[]} Defects found.
238
243
  */
239
- function validateAll({ root, contract, scenarios, platforms, options, cache }) {
244
+ function validateAll({
245
+ root,
246
+ contract,
247
+ scenarios,
248
+ platforms,
249
+ options,
250
+ cache,
251
+ discovery,
252
+ }) {
240
253
  const defects = [
241
254
  ...validateScenarios(scenarios, platforms),
242
255
  ...validateTrackerTags(scenarios, contract.trackers),
243
256
  ...validateMappings({ root, scenarios, contract, cache }),
244
257
  ...validateWaivers({ scenarios, contract, today: options.today }),
258
+ ...discovery.defects,
259
+ ...disclosureDefects({ root, contract, discovery }),
245
260
  ];
246
261
  if (!options.baseSha) return defects;
247
262
  const baseline = loadBaseline(root, options.baseSha);
@@ -294,7 +309,13 @@ function floorIntegrityDefects(report) {
294
309
  * @param {object} input - Contract, scenarios, report, and platforms.
295
310
  * @returns {object[]} Defects found.
296
311
  */
297
- function enforcedDefects({ contract, scenarios, report, platforms }) {
312
+ function enforcedDefects({
313
+ contract,
314
+ scenarios,
315
+ report,
316
+ platforms,
317
+ discovery,
318
+ }) {
298
319
  const defects = [];
299
320
  if (scenarios.length === 0) {
300
321
  defects.push(
@@ -320,6 +341,7 @@ function enforcedDefects({ contract, scenarios, report, platforms }) {
320
341
  )
321
342
  );
322
343
  }
344
+ defects.push(...missingDiscoveryDefects(contract, discovery));
323
345
  for (const platform of report.floor.unset) {
324
346
  defects.push(
325
347
  defect(
@@ -366,21 +388,34 @@ export function run(root, options) {
366
388
  // so each mapped file is read once no matter how large the manifest.
367
389
  const cache = new Map();
368
390
  const unresolved = unresolvedEvidenceKeys({ root, contract, cache });
391
+ // Discovery answers the question the declared half cannot: which tests exist
392
+ // that the manifest never mentions. It runs before the report so the report
393
+ // can carry the inventory it produced.
394
+ const discovery = discoverSpecs({ root, contract });
369
395
  const report = buildReport({
370
396
  scenarios,
371
397
  contract,
372
398
  runs: execution.runs,
373
399
  platforms,
374
400
  unresolved,
401
+ discovery,
375
402
  });
376
403
  const defects = [
377
404
  ...(versionDefect ? [versionDefect] : []),
378
405
  ...validateAdoption(contract, mode, options.today),
379
406
  ...execution.defects,
380
407
  ...floorIntegrityDefects(report),
381
- ...validateAll({ root, contract, scenarios, platforms, options, cache }),
408
+ ...validateAll({
409
+ root,
410
+ contract,
411
+ scenarios,
412
+ platforms,
413
+ options,
414
+ cache,
415
+ discovery,
416
+ }),
382
417
  ...(mode === "enforced"
383
- ? enforcedDefects({ contract, scenarios, report, platforms })
418
+ ? enforcedDefects({ contract, scenarios, report, platforms, discovery })
384
419
  : []),
385
420
  ];
386
421
  return result({ mode, defects, report, contract });
@@ -0,0 +1,71 @@
1
+ name: 🌙 Nightly E2E Report
2
+
3
+ # The REPORTING half of the nightly e2e standard, and the companion to
4
+ # `nightly-e2e-health.yml`.
5
+ #
6
+ # The gate tells whoever opened a pull request that the nightly is red. It tells
7
+ # nobody else. A red suite with no open pull requests is invisible, there is
8
+ # nothing to assign, and there is no record that it came back. This workflow
9
+ # keeps exactly ONE open tracking issue per suite: filed the first red night,
10
+ # refreshed every night it is still red, closed automatically the night a full
11
+ # green run lands.
12
+ #
13
+ # ## This is NOT a gate — never make it a required check
14
+ #
15
+ # Its status answers "did reporting work", not "is the suite green". A red
16
+ # nightly reported correctly is a successful report. Requiring this context would
17
+ # hand an issues-API outage the power to block every pull request, which is
18
+ # exactly the coupling the two-workflow split exists to prevent: the gate
19
+ # workflow does not request `issues:` scope at all, so it cannot file, and this
20
+ # one is not required, so it cannot block.
21
+ #
22
+ # ## Wiring this up
23
+ #
24
+ # 1. Keep `suites` and `branch` IDENTICAL to your `nightly-e2e-health.yml`
25
+ # caller. Two different tables means the issues describe a different set of
26
+ # suites than the one blocking merges.
27
+ # 2. Schedule it AFTER your nightly suites finish, not before. It reports on
28
+ # the runs they produced; running it first reports on yesterday's.
29
+ # 3. Leave the `nightly-e2e` label alone once issues exist under it — the label
30
+ # is how this job finds the issue it already owns.
31
+ #
32
+ # ## Concurrency
33
+ #
34
+ # Deliberately absent here. The non-cancelling group lives in Lisa's reusable
35
+ # workflow, on the job that writes, so an adopter cannot forget it — a forgotten
36
+ # group lets two overlapping reports both read "no open issue" and both file one.
37
+
38
+ on:
39
+ schedule:
40
+ # ~90 minutes after a midnight-UTC nightly, so the suites it reports on have
41
+ # finished. Move it if yours run at another hour; reporting on a suite that
42
+ # is still running produces "no completed run" every night.
43
+ - cron: '30 1 * * *'
44
+ workflow_dispatch:
45
+
46
+ permissions:
47
+ contents: read
48
+ # Reading the nightly run history — the same read the gate does.
49
+ actions: read
50
+ # The one scope the GATE deliberately does not have. Filing lives here so an
51
+ # issues outage can never redden a required check.
52
+ issues: write
53
+
54
+ jobs:
55
+ report:
56
+ name: 🌙 Nightly E2E Report
57
+ # PIN AN IMMUTABLE REF, for the same reason the gate caller does: the two
58
+ # halves must speak the same contract major, and `@main` can change between
59
+ # a report and the gate reading the same night.
60
+ uses: CodySwannGT/lisa/.github/workflows/nightly-e2e-report.yml@v2.345.1
61
+ with:
62
+ branch: dev
63
+ # KEEP THIS IDENTICAL to the `suites` value in nightly-e2e-health.yml.
64
+ suites: |
65
+ [
66
+ {
67
+ "label": "Maestro native e2e",
68
+ "workflow": "maestro-e2e.yml",
69
+ "match": { "mode": "run" }
70
+ }
71
+ ]
@@ -13,6 +13,21 @@
13
13
  "playwright": ["web"],
14
14
  "maestro": ["ios", "android"]
15
15
  },
16
+ "testDiscovery": {
17
+ "_comment": "Where each runner's tests live, so the gate can find a test NOBODY DECLARED. Keys must be runners declared in runnerPlatforms. `roots` are repo-relative directories (list every one — a subflow or helper directory omitted here is structurally invisible to the gate), `extensions` are filename suffixes, optional `ignore` holds repo-relative path prefixes to skip, and `evidence` says how a test is titled: {\"kind\": \"call-title\", \"functions\": [...]} reads test(\"...\") style declarations, {\"kind\": \"line-field\", \"field\": \"name\"} reads a leading document field. Edit these to match this project; a malformed block is refused rather than ignored, because silently discovering nothing looks exactly like a clean repo.",
18
+ "playwright": {
19
+ "roots": ["e2e"],
20
+ "extensions": [".spec.ts", ".spec.tsx", ".spec.js", ".spec.jsx"],
21
+ "ignore": [],
22
+ "evidence": { "kind": "call-title", "functions": ["test", "it"] }
23
+ },
24
+ "maestro": {
25
+ "roots": [".maestro/flows", ".maestro/subflows"],
26
+ "extensions": [".yaml", ".yml"],
27
+ "ignore": [],
28
+ "evidence": { "kind": "line-field", "field": "name" }
29
+ }
30
+ },
16
31
  "coverageFloor": {
17
32
  "_comment": "Committed traceability floor per platform. A ratchet: may rise, may never fall. Seeded at 0 so adopting on a brownfield app never red-gates CI before any scenario exists. Lowering one requires a coverageFloorBaseline record naming the exact change AND the maintainer-applied `bdd-floor-baseline` pull-request label.",
18
33
  "web": 0,
@@ -34,5 +49,6 @@
34
49
  },
35
50
  "platformWaivers": [],
36
51
  "mappings": [],
52
+ "_exclusionsComment": "A discovered test must be named by a mapping or by an exclusion. Each entry is {\"file\": \"<path>\", \"evidence\": \"<optional exact title; omit to excuse the whole file>\", \"reason\": \"<why this test aligns to no product behavior>\"} — an exclusion whose file is gone, whose title was renamed, or that no discovery root covers is a defect, never a permanent excuse.",
37
53
  "exclusions": []
38
54
  }
package/package.json CHANGED
@@ -120,7 +120,7 @@
120
120
  }
121
121
  },
122
122
  "name": "@codyswann/lisa",
123
- "version": "2.353.0",
123
+ "version": "3.1.0",
124
124
  "description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
125
125
  "main": "dist/index.js",
126
126
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.353.0",
3
+ "version": "3.1.0",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.353.0",
3
+ "version": "3.1.0",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -217,9 +217,11 @@ vocabulary; it consumes it.
217
217
 
218
218
  3. **File each standing blocker as a tracker work item — never an in-session question.** For every
219
219
  standing ship blocker, create **one** Lisa work item through the vendor-neutral `lisa-tracker-write`
220
- skill (never a vendor write skill directly), carrying the five finding fields in the body. Label it
221
- **build-ready** when the correction is mechanical; mark it **human-needed** when it is a genuine
222
- human decision. This is the skill's **only tracker write**, and it creates Lisa's *own* work item —
220
+ skill (never a vendor write skill directly), carrying the five finding fields in the body. Per the `ready-role-filing` rule each
221
+ create declares its readiness explicitly: pass **`build_ready: true`** when the correction is
222
+ mechanical (an omitted flag is NOT build-ready on any tracker, so the mechanical branch would
223
+ otherwise file work nothing ever claims), and pass **`human_gate: "<the decision only a human can
224
+ make>"`** plus the `human-needed` marker when it is a genuine human decision. This is the skill's **only tracker write**, and it creates Lisa's *own* work item —
223
225
  it **never edits, comments on, transitions, or otherwise mutates any ingested source** (see the
224
226
  connected-source safety boundary above). The shipped never-ask posture is preserved: a blocker
225
227
  becomes a filed ticket, **never** a prompt, and the session **never pauses to ask a human anything**,
@@ -35,46 +35,17 @@ EMAIL=$(jq -r '.atlassian.email // empty' .lisa.config.local.json 2>/dev/null)
35
35
  [ -z "$CLOUDID" ] && { echo "Error: atlassian.cloudId not set. Run /lisa:setup:atlassian." >&2; exit 1; }
36
36
  ```
37
37
 
38
- Probe each tier in order; the first that's ready AND identity-matches is the substrate for this operation. Identity-match is verified before any operation; substrates authenticated as a different Atlassian account are switched to the configured profile when one exists, then skipped only if the switch fails or re-verification still mismatches.
38
+ Probe each tier in order; the first that's ready AND identity-matches is the substrate for this operation. The ordering is the shared `credential-substrate-precedence` contract — the configured-provider token substrate leads for **reads and writes alike**, with acli and the MCP as identity-matched fallbacks — not an Atlassian-local choice. Identity-match is verified before any operation; substrates authenticated as a different Atlassian account are switched to the configured profile when one exists, then skipped only if the switch fails or re-verification still mismatches.
39
39
 
40
40
  ```bash
41
41
  substrate=""
42
42
 
43
- # Tier 1: acli for reads and non-write operations only.
44
- #
45
- # Do not choose acli for JIRA writes when curl/token auth is available. acli stores
46
- # one machine-global active account and workitem writes cannot pin a cloudId per
47
- # invocation, so switch-then-write is a TOCTOU risk in multi-account or concurrent
48
- # sessions. Write operations prefer the cloudId-scoped REST URL below.
49
- if [ "$OP_KIND" != "jira-write" ] && command -v acli >/dev/null 2>&1 && acli auth status >/dev/null 2>&1; then
50
- current_site=$(acli auth status 2>/dev/null | awk '/^ Site:/{print $2}')
51
- if [ "$current_site" != "$SITE" ]; then
52
- # acli installed but pointing at a different site. Try switching profiles.
53
- acli auth switch --site "$SITE" ${EMAIL:+--email "$EMAIL"} >/dev/null 2>&1 || true
54
- current_site=$(acli auth status 2>/dev/null | awk '/^ Site:/{print $2}')
55
- fi
56
- if [ "$current_site" = "$SITE" ]; then
57
- substrate="acli"
58
- fi
59
- fi
60
-
61
- # Tier 2: Atlassian MCP (if acli not ready OR the operation isn't acli-covered)
62
- # $OP_REQUIRES is a conceptual variable set by the dispatch table to "non-acli" for
63
- # operations that have no acli adapter (e.g. read-page-descendants). It is not a real
64
- # shell variable initialized here — the condition is illustrative pseudo-code.
65
- if [ -z "$substrate" ] || [ "$OP_REQUIRES" = "non-acli" ]; then
66
- # Probe via mcp__plugin_atlassian_atlassian__getAccessibleAtlassianResources.
67
- # (Pseudo-code; actual call is the MCP tool invocation, not a bash command.)
68
- # If the MCP returns a list and $CLOUDID is in it, MCP is identity-matched.
69
- # If the MCP is unauthenticated or $CLOUDID is NOT in the list, MCP is skipped.
70
- if mcp_atlassian_authenticated_and_matches_cloudid "$CLOUDID"; then
71
- : ${substrate:=mcp}
72
- # Mark MCP as available even if acli already won tier 1 — used for ops acli can't do.
73
- mcp_available=true
74
- fi
75
- fi
76
-
77
- # Tier 3: curl + API token (headless / multi-account / scoped-token path)
43
+ # Tier 1: curl + API token — the configured-provider substrate, resolved through
44
+ # lisa-secrets-access. Leads for every operation because it is per-invocation-bound:
45
+ # the cloudId-scoped gateway URL and the token's own account carry the tenant inside
46
+ # the request, so no ambient machine-global state can redirect it. acli (one global
47
+ # active account) and the MCP (browser OAuth session) are ambient-bound and therefore
48
+ # TOCTOU-exposed see credential-substrate-precedence, "tenant safety".
78
49
  read_atlassian_token() {
79
50
  local email="$1"
80
51
  [ -n "$ATLASSIAN_API_TOKEN" ] && { echo "$ATLASSIAN_API_TOKEN"; return; }
@@ -136,13 +107,50 @@ public static class LisaCred {
136
107
  esac
137
108
  }
138
109
  TOKEN=$(read_atlassian_token "$EMAIL")
139
- [ -n "$TOKEN" ] && curl_available=true && {
140
- if [ "$OP_KIND" = "jira-write" ]; then
110
+ if [ -n "$TOKEN" ]; then
111
+ # Identity-match before use: /rest/api/3/myself must report the configured account
112
+ # (Step 2). A present-but-wrong token fails the gate loudly instead of quietly
113
+ # deferring to an acli profile or MCP session authenticated somewhere else — that
114
+ # silent success is the bug class the precedence contract exists to surface.
115
+ if atlassian_token_matches_config "$TOKEN" "$EMAIL" "$CLOUDID"; then
116
+ curl_available=true
141
117
  substrate="curl"
142
118
  else
143
- : ${substrate:=curl}
119
+ echo "Warning: ATLASSIAN_API_TOKEN does not match the configured account/site. Skipping curl tier." >&2
144
120
  fi
145
- }
121
+ fi
122
+
123
+ # Tier 2: acli — identity-matched fallback. Used when no token is available, or for
124
+ # operations with no curl adapter. Never the primary path for JIRA writes when token
125
+ # auth is available: acli stores one machine-global active account and workitem writes
126
+ # cannot pin a cloudId per invocation, so switch-then-write is a TOCTOU risk in
127
+ # multi-account or concurrent sessions. When a write does land here it is the *guarded*
128
+ # fallback documented in the dispatch table (assert, write, re-read, assert, roll back).
129
+ if command -v acli >/dev/null 2>&1 && acli auth status >/dev/null 2>&1; then
130
+ current_site=$(acli auth status 2>/dev/null | awk '/^ Site:/{print $2}')
131
+ if [ "$current_site" != "$SITE" ]; then
132
+ # acli installed but pointing at a different site. Try switching profiles.
133
+ acli auth switch --site "$SITE" ${EMAIL:+--email "$EMAIL"} >/dev/null 2>&1 || true
134
+ current_site=$(acli auth status 2>/dev/null | awk '/^ Site:/{print $2}')
135
+ fi
136
+ if [ "$current_site" = "$SITE" ]; then
137
+ acli_available=true
138
+ # Mark acli available even if curl already won tier 1 — used for ops curl can't do.
139
+ : ${substrate:=acli}
140
+ fi
141
+ fi
142
+
143
+ # Tier 3: Atlassian MCP — first-class interactive fallback, for when neither tier above
144
+ # is available or covers the operation (e.g. an op with no curl and no acli adapter).
145
+ # Probe via mcp__plugin_atlassian_atlassian__getAccessibleAtlassianResources.
146
+ # (Pseudo-code; actual call is the MCP tool invocation, not a bash command.)
147
+ # If the MCP returns a list and $CLOUDID is in it, MCP is identity-matched.
148
+ # If the MCP is unauthenticated or $CLOUDID is NOT in the list, MCP is skipped.
149
+ if mcp_atlassian_authenticated_and_matches_cloudid "$CLOUDID"; then
150
+ : ${substrate:=mcp}
151
+ # Mark MCP as available even if an earlier tier won — used for ops they can't do.
152
+ mcp_available=true
153
+ fi
146
154
 
147
155
  # Fail loudly with actionable remediation if nothing works.
148
156
  if [ -z "$substrate" ]; then
@@ -154,15 +162,25 @@ if [ -z "$substrate" ]; then
154
162
  cat >&2 <<EOF
155
163
  Error: no Atlassian access substrate available for site $SITE.
156
164
 
157
- Attempted:
165
+ Attempted (in credential-substrate-precedence order):
166
+ curl — no ATLASSIAN_API_TOKEN found for $EMAIL (env, slug-suffixed env, or keychain) OR the token does not match the configured account/site
158
167
  acli — $(command -v acli >/dev/null && echo "installed but identity mismatch or unauthenticated" || echo "not installed")
159
168
  MCP — $([ "$plugin_enabled_global" = "true" ] || [ "$plugin_enabled_project" = "true" ] || [ "$plugin_enabled_local" = "true" ] && echo "plugin enabled but not authenticated or cloudId $CLOUDID not in accessible resources" || echo "plugin not enabled in any settings.json scope")
160
- curl — no ATLASSIAN_API_TOKEN found for $EMAIL (env, slug-suffixed env, or keychain)
161
169
 
162
- Remediation paths (pick one):
170
+ Remediation paths (the first is the contract's primary path):
171
+
172
+ 1. Provision an API token — works headless, in CI, in subagents, and in
173
+ multi-account setups, and is the substrate this project resolves first.
174
+
175
+ Run /lisa:setup:atlassian — guided flow with clipboard-piped keychain store.
176
+
177
+ 2. Install acli and authenticate (identity-matched fallback for multi-account developers).
163
178
 
164
- 1. Install the Atlassian MCP plugin (local scope — per-developer, gitignored).
165
- This is the simplest path for single-account developers.
179
+ brew tap atlassian/homebrew-acli && brew install acli
180
+ acli auth login # OAuth as the account matching $EMAIL
181
+
182
+ 3. Install the Atlassian MCP plugin (local scope — per-developer, gitignored).
183
+ The supported fallback when no credentials provider is configured.
166
184
 
167
185
  Run in your terminal:
168
186
 
@@ -174,25 +192,16 @@ Remediation paths (pick one):
174
192
  Then restart Claude Code (or run /restart-mcp) to load the plugin, and
175
193
  invoke 'mcp__plugin_atlassian_atlassian__authenticate' to complete OAuth.
176
194
 
177
- 2. Install acli and authenticate (best for multi-account developers).
178
-
179
- brew tap atlassian/homebrew-acli && brew install acli
180
- acli auth login # OAuth as the account matching $EMAIL
181
-
182
- 3. Provision an API token (headless / CI / scoped-token environments).
183
-
184
- Run /lisa:setup:atlassian — guided flow with clipboard-piped keychain store.
185
-
186
195
  EOF
187
196
  exit 1
188
197
  fi
189
198
  ```
190
199
 
191
- Operation dispatch then uses `$substrate` for the primary route. If the operation has no `acli` adapter and `$substrate=acli`, fall through to `$mcp_available` then `$curl_available` for the actual call. The fall-through stops at the first available tier that can perform the operation.
200
+ Operation dispatch then uses `$substrate` for the primary route. If the operation has no adapter for the selected substrate, fall through in contract order — `$curl_available`, then `$acli_available`, then `$mcp_available` skipping the tier already tried. The fall-through stops at the first available tier that can perform the operation. A tier that failed identity-match is never in the fall-through set.
192
201
 
193
202
  ### Step 2 — Connection-match check
194
203
 
195
- The active connection MUST point at the cloudId/site declared in `.lisa.config.json`. Step 1's substrate selection already tries to switch mismatched acli profiles and verifies the result before selection. This step repeats the assertion before any operation runs — defensive in case the substrate state changed since selection.
204
+ The active connection MUST point at the cloudId/site declared in `.lisa.config.json`. Identity-match is mandatory on **every** substrate, tier 1 included (`credential-substrate-precedence`); the "curl mode check" below *is* the tier-1 gate referenced as `atlassian_token_matches_config` in Step 1. Step 1's substrate selection already validates the token account and tries to switch mismatched acli profiles before selection. This step repeats the assertion before any operation runs — defensive in case the substrate state changed since selection.
196
205
 
197
206
  Read configured site:
198
207
 
@@ -291,12 +300,12 @@ Rules:
291
300
 
292
301
  ### Step 3 — Operation dispatch
293
302
 
294
- Substrate column meanings:
303
+ Substrate column meanings (ordering per `credential-substrate-precedence`):
295
304
 
296
- - **`acli`**: routes through `acli`. Preferred when available and identity-matched.
297
- - **`MCP`**: routes through the Atlassian MCP. Preferred when acli can't do the op and the MCP is identity-matched (cloudId in `getAccessibleAtlassianResources`).
298
- - **`curl`**: routes through curl + Basic auth + `ATLASSIAN_API_TOKEN`. Used when neither acli nor MCP is available.
299
- - Multiple cells filled means tier ordering applies — try acli, then MCP, then curl, taking the first that has an adapter for the op AND is identity-matched.
305
+ - **`curl`**: routes through curl + Basic auth + `ATLASSIAN_API_TOKEN` — the configured-provider substrate. Preferred for every operation, read or write, whenever the token is present and identity-matched.
306
+ - **`acli`**: routes through `acli`. Identity-matched fallback used when no token is available or the op has no curl adapter. For JIRA writes it is the *guarded* fallback (see the tenant-safety rule below).
307
+ - **`MCP`**: routes through the Atlassian MCP. First-class fallback for ops neither tier above covers, when identity-matched (cloudId in `getAccessibleAtlassianResources`).
308
+ - Multiple cells filled means tier ordering applies — try curl, then acli, then MCP, taking the first that has an adapter for the op AND is identity-matched.
300
309
  - One cell means only that substrate can perform the op.
301
310
 
302
311
  `<SITE>` = `.atlassian.site` (e.g. `acme.atlassian.net`). `<CLOUDID>` = `.atlassian.cloudId`. `<AUTH>` = `Basic $(printf '%s:%s' "$email" "$ATLASSIAN_API_TOKEN" | base64)`. JIRA curl writes use the cloudId-bound Atlassian gateway `https://api.atlassian.com/ex/jira/<CLOUDID>/rest/api/3/...`; JIRA curl reads may use either that gateway or `https://<SITE>/rest/api/3/...` after the token account check. Confluence uses `/wiki/rest/api/...` (v1) or `/api/v2/...` (v2).
@@ -334,7 +343,7 @@ Substrate column meanings:
334
343
 
335
344
  **acli flag note:** acli's `--output` flag does not exist; the correct flag is `--json`. List commands require `--paginate` or `--limit` (no implicit fetch-all). `acli jira workitem view` defaults to a restricted field set (`key,issuetype,summary,status,assignee,description`), so `read-ticket` MUST pass `--fields '*all'` or an explicit equivalent that includes every downstream dependency: parent, subtasks, issue links, components, labels, priority, status, issue type, summary, description, fix versions, affected versions, attachments, comments, estimates, sprint/story-point fields, and project-required custom fields. Never rely on the default view fields; they hide parent/components/labels and corrupt leaf-only, relationship-search, build-ready, and required-custom-field gates. Several documented adapters are nominal — verify against `acli <subcmd> --help` before relying on them. When acli's adapter is broken or missing for a specific op, fall through to MCP (if identity-matched) then curl per the tier ordering.
336
345
 
337
- **JIRA write tenant-safety rule:** create, edit, transition, comment, and link are write operations. They MUST prefer the curl adapter whenever token auth is available because the URL includes `<CLOUDID>` and cannot be redirected by the user-global acli active account. If the flow must fall back to acli for a write, it is a guarded fallback, not the normal path:
346
+ **JIRA write tenant-safety rule** — the Atlassian instance of the shared guarded-fallback protocol in `credential-substrate-precedence` (which states the general rule: prefer the per-invocation-bound substrate over the ambient-bound one, for reads and writes alike; the rationale is not restated here). Create, edit, transition, comment, and link are write operations. They MUST use the curl adapter whenever token auth is available because the URL includes `<CLOUDID>` and cannot be redirected by the user-global acli active account. If the flow must fall back to acli for a write, it is a guarded fallback, not the normal path:
338
347
 
339
348
  1. Switch and assert the active `acli auth status` site/email matches config immediately before the write.
340
349
  2. Execute the write.
@@ -378,15 +387,17 @@ Do not paraphrase substrate output beyond JSON normalization.
378
387
  ## Invariants
379
388
 
380
389
  - Caller skills never invoke `acli` or `curl` against Atlassian directly. They only invoke this skill.
390
+ - Tier order is the shared `credential-substrate-precedence` contract — token curl first (reads **and** writes), then acli, then the Atlassian MCP. Do not restate or locally override the ordering here.
391
+ - acli and the Atlassian MCP remain first-class **fallbacks**, not removed tiers: every adapter stays in the dispatch table, and a project with no credentials provider is fully functional on them.
381
392
  - Substrate is decided once per skill invocation and never switches mid-operation.
382
- - Connection match is mandatory. Operations that bypass it (because "the user obviously meant the configured site") are forbidden.
393
+ - Connection match is mandatory on every tier, including the token tier. Operations that bypass it (because "the user obviously meant the configured site") are forbidden. A present-but-wrong token fails the gate rather than deferring to another substrate.
383
394
  - Profile mutations (`acli auth switch`) are allowed when acli is the active substrate. The curl substrate never mutates the token — if `ATLASSIAN_API_TOKEN` doesn't match the configured account, fail loud rather than silently substituting.
384
395
  - JIRA writes are cloudId-bound by default. `acli` write adapters are fallback-only and must perform post-write tenant assertions plus safe rollback on mismatch.
385
396
  - `.lisa.config.local.json` overrides `.lisa.config.json` per-key — the same precedence rule as every other consumer of project config.
386
397
 
387
398
  ## Headless behavior
388
399
 
389
- In a headless / non-interactive context, the MCP tier is unavailable (its OAuth flow needs a browser). The substrate ladder collapses to: acli (if pre-authenticated, e.g., a CI image baked with a service-account token) curl + `ATLASSIAN_API_TOKEN`. Never block on interactive prompts. If both fail readiness checks, exit non-zero with a deterministic error.
400
+ In a headless / non-interactive context, the MCP tier is unavailable (its OAuth flow needs a browser). The ladder collapses to: curl + `ATLASSIAN_API_TOKEN` → acli (if pre-authenticated, e.g., a CI image baked with a service-account token). Because curl is already tier 1 interactively, headless and interactive sessions take the **same primary path** — that is the "headless parity" arm of `credential-substrate-precedence`, and it is why a credential problem reproduces on a laptop instead of only in cron. Never block on interactive prompts. If both fail readiness checks, exit non-zero with a deterministic error.
390
401
 
391
402
  Treat all four of these as headless:
392
403
 
@@ -350,7 +350,7 @@ Each sub-task MUST:
350
350
  2. **Include an Empirical Verification Plan** — real user-like verification, NOT unit tests, linting, or typechecking
351
351
  3. **Carry its own `## Source Requirement` section** (shared format above) with the full verbatim quote(s) from the Phase 1.4 register — a leaf claimed by build-intake in isolation must be self-explanatory. When a sub-task is split per-repo, every split child inherits the same requirement quote(s).
352
352
 
353
- **Leaf-only build-ready (`leaf-only-lifecycle`)**: Sub-tasks are the **leaf work units** of the decomposition — they are the ONLY items in the hierarchy that receive the build-ready role. `lisa-tracker-write` applies the build-ready role here so downstream build intake (`lisa-tracker-build-intake`) claims the leaves and never the Epic or Stories. Apply the build-ready role to each Sub-task; never to its parent Story or Epic (Phases 3–4). `lisa-tracker-write` enforces the same invariant on the write side, so a Sub-task split into per-repo children (the cross-repo case above) carries build-ready on the children, not on any intermediate parent that gains child work.
353
+ **Leaf-only build-ready (`leaf-only-lifecycle`)**: Sub-tasks are the **leaf work units** of the decomposition — they are the ONLY items in the hierarchy that receive the build-ready role. `lisa-tracker-write` applies the build-ready role here so downstream build intake (`lisa-tracker-build-intake`) claims the leaves and never the Epic or Stories. **Pass `build_ready: true` explicitly on every Sub-task create** — per the `ready-role-filing` rule an omitted `build_ready` is NOT build-ready on any tracker, so a decomposition that relies on a vendor default silently produces a queue nothing ever claims. Apply the build-ready role to each Sub-task; never to its parent Story or Epic (Phases 3–4). `lisa-tracker-write` enforces the same invariant on the write side, so a Sub-task split into per-repo children (the cross-repo case above) carries build-ready on the children, not on any intermediate parent that gains child work.
354
354
 
355
355
  Sub-tasks inherit their parent story's artifacts by reference (the parent link). Do not pass the same artifact list to every sub-task.
356
356
 
@@ -419,6 +419,7 @@ tickets that downstream skills (triage, journey, evidence) cannot use.
419
419
 
420
420
  For each sub-task, invoke `lisa-tracker-write` with:
421
421
  - issue_type: "Sub-task"
422
+ - build_ready: true # explicit per `ready-role-filing`; omitted is NOT build-ready on any tracker
422
423
  - prd_source: [the originating PRD URL — mandatory; arms the S16 traceability gate]
423
424
  - parent: the parent story key
424
425
  - project_key: [PROJECT]
@@ -29,11 +29,11 @@ For every row marked **Accept**:
29
29
  | Edge case | Edge Case Brainstorm checklist in `intent-routing.md` | Append the new pattern + question to the matching group (Navigation, Data, Failure, Input, Auth, or a new group if none fit). Use the row's `Summary` and `Evidence` link as a citation comment. |
30
30
  | Recurring gotcha | Committed learnings ledger (via contract) | Persist a ledger entry per [Ledger persistence](#ledger-persistence-knowledge-categories). The `rule` is the recurring gotcha and the guard against it; `why` is the causal claim. |
31
31
  | Process friction | Committed learnings ledger (via contract) | Persist a ledger entry per [Ledger persistence](#ledger-persistence-knowledge-categories). The `rule` is the friction-avoiding guideline; `why` names the friction it prevents. |
32
- | Tooling gap | Configured tracker — or upstream Lisa when harness-level | **Split by level.** Project-level (a missing project script, hook, or automation) → create a ticket via `lisa-tracker-write` with `issue_type: Task`, summary derived from the row's `Summary`, description citing the evidence and the originating debrief doc, labeled `type:tooling` / `lifecycle-improvement`. Harness-level (a Lisa skill/gate/agent that should have caught the issue but didn't) → file an upstream Lisa issue exactly per the "Filing upstream" procedure in `lisa-rework-triage` (dedupe search first, three-audience description, evidence chain, `self-hardening` label; repo from `.lisa.config.json` `hardening.upstreamRepo`, default `CodySwannGT/lisa`). |
32
+ | Tooling gap | Configured tracker — or upstream Lisa when harness-level | **Split by level.** Project-level (a missing project script, hook, or automation) → create a ticket via `lisa-tracker-write` with `issue_type: Task`, summary derived from the row's `Summary`, description citing the evidence and the originating debrief doc, labeled `type:tooling` / `lifecycle-improvement`, and explicit `build_ready: true` per `ready-role-filing` (a tooling gap the factory can close itself is queue work, and an omitted flag is NOT build-ready on any tracker). Harness-level (a Lisa skill/gate/agent that should have caught the issue but didn't) → file an upstream Lisa issue exactly per the "Filing upstream" procedure in `lisa-rework-triage` (dedupe search first, three-audience description, evidence chain, `self-hardening` label; repo from `.lisa.config.json` `hardening.upstreamRepo`, default `CodySwannGT/lisa`). |
33
33
  | Convention drift | Committed learnings ledger (via contract) | Persist a ledger entry per [Ledger persistence](#ledger-persistence-knowledge-categories). The `rule` is the correct convention; `why` records the drift it corrects. |
34
34
  | Decomposition infidelity | Upstream Lisa repo | File an upstream Lisa issue per the "Filing upstream" procedure in `lisa-rework-triage`, citing the PRD text vs. the distorted ticket AC and naming the gate that passed it. |
35
35
  | PRD defect | Source PRD | Comment on the PRD via the `lisa-prd-backlink` lineage quoting the defective requirement and the failure it missed; flag for product review. Never silently edit the spec. |
36
- | Missing tool access | Configured tracker | Create a provisioning ticket via `lisa-tracker-write` (`issue_type: Task`, `type:tooling`) describing the missing tool/credential/environment and which flow needs it. |
36
+ | Missing tool access | Configured tracker | Create a provisioning ticket via `lisa-tracker-write` (`issue_type: Task`, `type:tooling`) describing the missing tool/credential/environment and which flow needs it. Pass `human_gate: "a human must grant the missing access"` per `ready-role-filing` — the factory cannot provision its own credentials. |
37
37
  | Uncategorized | **No route — requires reclassification** | `Uncategorized` records that the synthesizer could not fit the finding to a category; it is not itself a destination. Do NOT guess a route and do NOT silently skip the row. Leave the row unapplied, mark it `[!] Needs reclassification — <the synthesizer's "why no category fit" note>`, and list it under its own heading in the run summary so the human can retag it to one of the eight and re-run `apply`. A row that stays `Uncategorized` across runs is a signal the category set itself is missing a case — worth an upstream Lisa issue, not a forced fit. |
38
38
 
39
39
  For every row marked **Reject** or **Defer**: no action. Defer is a no-op for `apply` but worth surfacing in the run summary — the human may want to revisit at the next debrief.
@@ -70,7 +70,13 @@ Kane never files the work item itself. Even when it marks a failure as a confirm
70
70
  | User-visible **bug** (broken behavior) | `Bug` | the `ready` flag (default `false`) |
71
71
  | **Usability / UX / clarity issue** | `Improvement` | the `ready` flag (default `false`) |
72
72
 
73
- Each finding is a flat leaf, so `build_ready` applies directly — pass it explicitly on every create. Each ticket MUST be a complete spec (the validator rejects thin tickets): a **three-audience description**; for a **bug**, exact reproduction steps, observed-vs-expected, the env / account / interface it occurred at, and evidence; for a **usability issue**, the observed friction, who it affects, **where**, and the proposed improvement; and **Gherkin acceptance criteria** for the fixed behavior.
73
+ Each finding is a flat leaf, so `build_ready` applies directly — pass it explicitly on every create.
74
+
75
+ **This skill is the named human-gate exception under `ready-role-filing`.** Everywhere else in Lisa, a complete defect found during other work is filed with explicit `build_ready: true` so build-intake claims it next cycle. Exploratory QA is deliberately different, and that difference is ratified rather than drift: its findings are *candidate* defects and usability observations whose **product significance is a human call**, so auto-readying them would push judgment work into the build queue — precisely the failure the gate model exists to prevent. Its default `ready=false` is therefore an **explicit human-gate marker, never a bare omission**: every not-ready create passes `human_gate: "exploratory finding — product significance is a human product call"` alongside `build_ready: false`, and the writer stamps the auditable `[lisa-human-gate]` marker. An operator who wants a pass to feed the queue directly opts in with `ready=true`.
76
+
77
+ (The sibling `e2e-coverage-gaps` skills are the contrast: a missing automated test is not a product question, so they file `build_ready: true` by default.)
78
+
79
+ Each ticket MUST be a complete spec (the validator rejects thin tickets): a **three-audience description**; for a **bug**, exact reproduction steps, observed-vs-expected, the env / account / interface it occurred at, and evidence; for a **usability issue**, the observed friction, who it affects, **where**, and the proposed improvement; and **Gherkin acceptance criteria** for the fixed behavior.
74
80
 
75
81
  ### Idempotency — don't spam duplicates
76
82
 
@@ -258,6 +258,11 @@ A blocker is active if it is open and has no cleared status label. Treat `status
258
258
 
259
259
  **Claim-time archaeology runs second — after rejection detection, still before the relabel below.** Classify this item per the vendor-neutral `claim-archaeology` rule, with the rejection classification above as its input. All shared semantics — ancestry signals, classification, learning-loop exclusion, cost budget, candidate derivation, marker dedupe, and the never-block degrade — live in that one slug; change them there, never here. GitHub wiring only: the typed relations and `closingIssuesReferences` are already in the read bundle; text-similarity searches use `gh search issues` over recently-closed issues; the fallback candidate comment is posted with `gh issue comment`.
260
260
 
261
+ **The two `claim-time-guards` run third and fourth — still before the relabel below.** Both semantics live in that one vendor-neutral slug; do not restate them here. GitHub wiring only:
262
+
263
+ 1. **`two-failed-attempts` valve.** Count `[lisa-build-attempt]` markers on the issue from the read bundle's comments (match on the marker, never the title). With two or more, do **not** claim: relabel to the configured blocked role (`gh issue edit <number> --repo <org>/<repo> --remove-label "$READY" --add-label "$BLOCKED"`, resolved from `github.labels.build.blocked` per `config-resolution`), post the operator-readable comment naming both attempts, and **stop the cycle** at Phase 3e. Every non-success terminal outcome recorded in 3c/3d also appends a fresh `<!-- [lisa-build-attempt] n=<N> outcome=<outcome> -->` marker so the next cycle can count it.
264
+ 2. **`already-implemented` check.** Probe for this issue's own key — `git log --all --grep "<org>/<repo>#<number>"` and `gh pr list --repo <org>/<repo> --state all --search "<org>/<repo>#<number>" --json number,state,mergedAt,url`. On a hit, claim as normal but route 3c to **verify-and-close** instead of `lisa-implement`: verify what shipped against the issue's acceptance criteria, post evidence via `lisa-github-evidence` naming the shipping PR/commit, then run the ordinary 3d transition and 3d.1 rollup. A partial hit implements only the remaining gap. An unreadable history degrades to "no hit" and the ordinary path proceeds — the guard never blocks the claim. This is not `DUPLICATE_ALREADY_FIXED` (a *different* canonical issue) and not `claim-archaeology` (a *different* ancestor issue); it is this issue's own work already having shipped without a transition.
265
+
261
266
  ```bash
262
267
  gh issue edit <number> --repo <org>/<repo> --remove-label "$READY" --add-label "$CLAIMED"
263
268
  # Assign to the authenticated user ONLY when the issue is currently unassigned (attributable claim;
@@ -80,7 +80,9 @@ Issues must be created in parent-before-child order:
80
80
 
81
81
  1. Invoke `lisa-github-write-issue` for the Epic. Capture the returned issue number.
82
82
  2. For each Story, invoke `lisa-github-write-issue` with the Epic ref as `parent_ref`. Capture each Story number.
83
- 3. For each Sub-task, invoke `lisa-github-write-issue` with the Story ref as `parent_ref`.
83
+ 3. For each Sub-task, invoke `lisa-github-write-issue` with the Story ref as `parent_ref` and explicit `build_ready: true`.
84
+
85
+ - **Declare readiness on every leaf write.** Per the `ready-role-filing` rule an omitted `build_ready` is **not build-ready** on any tracker, so pass `build_ready: true` on each Sub-task (the leaf work units this skill plans) and never on the Epic or Stories, which are containers per `leaf-only-lifecycle`. A leaf that is deliberately held instead passes `human_gate: "<why a human must judge this first>"`. Filing a leaf with neither is an incomplete handoff and `lisa-github-write-issue` rejects it.
84
86
 
85
87
  ### What to pass to each invocation
86
88
 
@@ -335,7 +335,7 @@ Each sub-task MUST:
335
335
  2. **Include an Empirical Verification Plan** — real user-like verification, NOT unit tests, linting, or typechecking.
336
336
  3. **Carry its own `## Source Requirement` section** (shared format above) with the full verbatim quote(s) from the Phase 1.4 register — a leaf claimed by build-intake in isolation must be self-explanatory. When a sub-task is split per-repo, every split child inherits the same requirement quote(s).
337
337
 
338
- **Leaf-only build-ready (`leaf-only-lifecycle`)**: Sub-tasks are the **leaf work units** of the decomposition — they are the ONLY items in the hierarchy that receive the build-ready label. `lisa-tracker-write` applies `status:ready` here so downstream build intake (`lisa-github-build-intake`) claims the leaves and never the Epic or Stories. Apply `status:ready` to each Sub-task; never to its parent Story or Epic (Phases 3–4). `lisa-github-write-issue` enforces the same invariant on the write side, so a Sub-task split into per-repo children (the cross-repo case above) carries build-ready on the children, not on any intermediate parent that gains child work.
338
+ **Leaf-only build-ready (`leaf-only-lifecycle`)**: Sub-tasks are the **leaf work units** of the decomposition — they are the ONLY items in the hierarchy that receive the build-ready label. `lisa-tracker-write` applies `status:ready` here so downstream build intake (`lisa-github-build-intake`) claims the leaves and never the Epic or Stories. **Pass `build_ready: true` explicitly on every Sub-task create** — per the `ready-role-filing` rule an omitted `build_ready` is NOT build-ready on any tracker, so a decomposition that relies on a vendor default silently produces a queue nothing ever claims. Apply `status:ready` to each Sub-task; never to its parent Story or Epic (Phases 3–4). `lisa-github-write-issue` enforces the same invariant on the write side, so a Sub-task split into per-repo children (the cross-repo case above) carries build-ready on the children, not on any intermediate parent that gains child work.
339
339
 
340
340
  Sub-tasks inherit their parent Story's artifacts by reference (the parent link). Do not pass the same artifact list to every sub-task.
341
341
 
@@ -404,6 +404,7 @@ that downstream skills (triage, journey, evidence) cannot use.
404
404
 
405
405
  For each sub-task, invoke `lisa-tracker-write` with:
406
406
  - issue_type: "Sub-task"
407
+ - build_ready: true # explicit per `ready-role-filing`; omitted is NOT build-ready on any tracker
407
408
  - prd_source: [the originating PRD URL — mandatory; arms the S16 traceability gate]
408
409
  - parent_ref: the parent story ref
409
410
  - summary: prefixed with the repo in brackets, e.g. "[backend-api] Add audit log table"
@@ -382,13 +382,17 @@ Per `Phase 5` of `lisa-github-write-issue`, every issue MUST carry
382
382
  missing from the proposed spec or live issue, FAIL with the missing label name.
383
383
 
384
384
  The `status:*` requirement uses this validator's S15 leaf/container classification while preserving
385
- the writer's documented `build_ready` control-input defaults:
385
+ the writer's documented `build_ready` control-input defaults, which the `ready-role-filing` rule
386
+ fixes at "omitted is NOT build-ready" for every vendor:
386
387
 
387
388
  1. Classify the issue structurally using the S15 child-resolution rules. A container (any issue
388
389
  with child work, plus a childless `Epic`) may omit `status:*`; its state rolls up rather than
389
390
  being assigned directly.
390
- 2. For a proposed leaf spec, normalize omitted `build_ready` to `true`, preserving the writer's
391
- backward-compatible default-ready behavior. Explicit `build_ready: false` means backlog mode.
391
+ 2. For a proposed leaf spec, normalize omitted `build_ready` to `false`, per `ready-role-filing`:
392
+ ready is an explicit claim, so only `build_ready: true` asserts it. Explicit `build_ready: false`
393
+ means the same backlog mode. (This validator previously normalized omitted → `true` to mirror
394
+ GitHub's implicit-ready writer default; both were removed together, and re-introducing either
395
+ here would just move the leak.)
392
396
  3. For a live issue ref, derive `build_ready` from the labels (`true` exactly when the S15-resolved
393
397
  `READY_ROLE` from `github.labels.build.ready`, default `status:ready`, is present). A live backlog leaf without a status label
394
398
  therefore validates as `build_ready: false`; live data cannot distinguish an explicit false from