@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
@@ -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
 
@@ -343,7 +343,7 @@ Each sub-task MUST:
343
343
  2. **Include an Empirical Verification Plan** — real user-like verification, NOT unit tests, linting, or typechecking.
344
344
  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).
345
345
 
346
- **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.
346
+ **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.
347
347
 
348
348
  Sub-tasks inherit their parent Story's artifacts by reference (the parent link). Do not pass the same artifact list to every sub-task.
349
349
 
@@ -412,6 +412,7 @@ that downstream skills (triage, journey, evidence) cannot use.
412
412
 
413
413
  For each sub-task, invoke `lisa-tracker-write` with:
414
414
  - issue_type: "Sub-task"
415
+ - build_ready: true # explicit per `ready-role-filing`; omitted is NOT build-ready on any tracker
415
416
  - prd_source: [the originating PRD URL — mandatory; arms the S16 traceability gate]
416
417
  - parent_ref: the parent story ref
417
418
  - 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
@@ -253,12 +253,21 @@ For non-build-ready issues created fresh (Epics, Stories, and other containers),
253
253
 
254
254
  ### Build-ready control input (`build_ready`)
255
255
 
256
- `build_ready` is an optional write-control input (default: **omitted**). It governs whether a **leaf** work unit is stamped with the build-ready role on create. It never overrides `leaf-only-lifecycle` — a container is never stamped build-ready regardless of `build_ready`. "Not build-ready" is not a special status: it simply means the issue is created in its natural default (a plain open issue with **no `status:ready` label**), which a human can promote later.
256
+ `build_ready` is a write-control input governed by the `ready-role-filing` rule — cite that slug for the full contract; do not restate its per-vendor normalization table here. It decides whether a **leaf** work unit is stamped with the build-ready role on create. It never overrides `leaf-only-lifecycle` — a container is never stamped build-ready regardless of `build_ready`. "Not build-ready" is not a special status: it simply means the issue is created in its natural default (a plain open issue with **no `status:ready` label**), which a human can promote later.
257
257
 
258
- - **Omitted** → current behavior: a leaf work unit receives `status:ready`. Preserves what every existing caller (`lisa-plan`, the `*-to-tracker` skills) relies on.
258
+ - **Omitted** → **not build-ready**: the leaf is created without `status:ready`. Ready is an explicit claim, never a vendor default. **This is a breaking change** — GitHub previously applied `status:ready` on omission, so a caller that relied on that must now pass `build_ready: true`.
259
259
  - **`build_ready: false`** → create the leaf **without** `status:ready`, so it sits in the backlog for a human to review and promote into the queue.
260
260
  - **`build_ready: true`** → ensure the leaf carries `status:ready` so `lisa-intake` / `lisa-github-build-intake` auto-picks it up.
261
261
 
262
+ **A filing with neither is an incomplete handoff.** A leaf that is not build-ready must carry an explicit `human_gate: "<why a human must judge this first>"`; nothing in the ready lane means nothing ever claims it. When `human_gate` is supplied, stamp the hold on the issue so it is auditable — a visible line plus the verbatim marker:
263
+
264
+ ```text
265
+ Held for a human product call: <reason>.
266
+ <!-- [lisa-human-gate] reason=<short-slug> -->
267
+ ```
268
+
269
+ If a leaf arrives with `build_ready` omitted or `false` **and** no `human_gate`, do not create it: report the incomplete handoff and name both ways to resolve it (`build_ready: true`, or a `human_gate` reason). Containers are exempt — their state rolls up from children, so they need neither.
270
+
262
271
  ## Phase 5.5 — Validate (Pre-write Gate)
263
272
 
264
273
  Before any write, invoke `lisa-github-validate-issue` with the full proposed spec assembled from Phases 2 / 3 / 4 / 5. Pass it as a YAML block per the `lisa-github-validate-issue` schema, including `runtime_behavior_change`, `authenticated_surface`, and `artifacts_attached` flags so the right gates run.
@@ -271,9 +280,9 @@ If the validator reports `FAIL`, do NOT proceed to Phase 6. Fix the spec and re-
271
280
 
272
281
  ### CREATE
273
282
 
274
- 1. Compose the body markdown from Phases 2/3/4 in a temp file (avoid quoting hell). Apply `status:ready` **only for a leaf work unit** per the Phase 5 leaf-only rule (`leaf-only-lifecycle`) — omit it for `Epic` / `Story` / `Spike` and any issue that has child work, **and** only when `build_ready` is not `false` (a leaf with `build_ready: false` is created without `status:ready`; see the Build-ready control input):
283
+ 1. Compose the body markdown from Phases 2/3/4 in a temp file (avoid quoting hell). Apply `status:ready` **only for a leaf work unit** per the Phase 5 leaf-only rule (`leaf-only-lifecycle`) — omit it for `Epic` / `Story` / `Spike` and any issue that has child work, **and** only when `build_ready` is explicitly `true` (a leaf with `build_ready` omitted or `false` is created without `status:ready`; see the Build-ready control input):
275
284
  ```bash
276
- # Leaf work unit (Bug / Task / Sub-task / Improvement with no children), build_ready not false:
285
+ # Leaf work unit (Bug / Task / Sub-task / Improvement with no children), build_ready: true:
277
286
  gh issue create \
278
287
  --repo <org>/<repo> \
279
288
  --title "<summary>" \
@@ -282,9 +291,10 @@ If the validator reports `FAIL`, do NOT proceed to Phase 6. Fix the spec and re-
282
291
  [--label "component:<name>" ...] [--milestone "<milestone>"] \
283
292
  [--assignee "<login>"]
284
293
 
285
- # Container (Epic / Story / Spike / any issue with child work), OR a leaf with build_ready: false:
294
+ # Container (Epic / Story / Spike / any issue with child work), OR a leaf whose build_ready is
295
+ # omitted or false (and which therefore carries an explicit human_gate):
286
296
  # identical, but WITHOUT --label "status:ready" — a container's state rolls up from children;
287
- # a build_ready: false leaf waits in the backlog for a human to promote it.
297
+ # a human-gated leaf waits in the backlog for a human to promote it.
288
298
  gh issue create \
289
299
  --repo <org>/<repo> \
290
300
  --title "<summary>" \
@@ -191,7 +191,7 @@ authority — if any of these hold:
191
191
  **On any of those: file a proposed-intervention ticket via `lisa-tracker-write` and STOP.** The
192
192
  ticket carries the job contract, the earliest failed handoff, the gap classification with
193
193
  evidence, and the proposed change with its expected mechanism; labels `type:harness`,
194
- `status:blocked` (human-flipped to `status:ready` when approved). Post the result record with
194
+ `status:blocked` plus an explicit `human_gate: "a human approves the proposed harness intervention"` per `ready-role-filing` (human-flipped to `status:ready` when approved). Post the result record with
195
195
  `Verdict: bounded-authority-stop`, `Decision: n/a (proposed-intervention, <url>)`, and
196
196
  terminate. Implementing it anyway is the failure mode this phase exists to prevent.
197
197
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: lisa-jam-access
3
- description: "Vendor-neutral access layer for Jam. Jam triage rules and skills MUST delegate through this skill rather than calling Jam MCP tools directly. Resolves Jam MCP first when available, then falls back to the JAM_PAT-authenticated Jam CLI for headless routines."
3
+ description: "Vendor-neutral access layer for Jam. Jam triage rules and skills MUST delegate through this skill rather than calling Jam MCP tools directly. Per the credential-substrate-precedence contract, resolves the JAM_PAT-authenticated Jam CLI first when the PAT is present and identity-matched, then falls back to the Jam MCP."
4
4
  allowed-tools: ["Bash", "Read", "Skill"]
5
5
  ---
6
6
 
@@ -21,13 +21,20 @@ Return parsed JSON or a concise structured summary in a `<result>` block.
21
21
 
22
22
  ## Substrate Selection
23
23
 
24
- Probe in order:
24
+ Probe in order — the ordering is the shared `credential-substrate-precedence`
25
+ contract, not a Jam-local choice. The first tier that is ready **and**
26
+ identity-matches the configured Jam account is used; one authenticated elsewhere
27
+ is skipped, never used.
25
28
 
26
- 1. Jam MCP, if the tool is available and authenticated.
27
- 2. Jam CLI authenticated with `JAM_PAT`.
29
+ 1. **Tier 1 configured-provider substrate: Jam CLI authenticated with `JAM_PAT`**,
30
+ resolved through `lisa-secrets-access`.
31
+ 2. **Tier 2 — interactive MCP fallback: Jam MCP**, if the tool is available and
32
+ authenticated. Used when tier 1 is genuinely unavailable: no `JAM_PAT`, no CLI
33
+ adapter for the operation, or a Jam outage.
28
34
 
29
35
  Jam documents a PAT-authenticated CLI that is cleaner for remote routines than
30
- editing `.mcp.json` headers. The headless tier uses:
36
+ editing `.mcp.json` headers, and it is the same substrate interactively and
37
+ headlessly — which is why it leads. The CLI tier uses:
31
38
 
32
39
  ```bash
33
40
  curl -fsSL https://native.jam.dev/install | bash
@@ -44,7 +51,8 @@ Error: no Jam access substrate available. Authenticate the Jam MCP or set JAM_PA
44
51
 
45
52
  ## Invariants
46
53
 
47
- - Fallback is gated on `JAM_PAT`; do not retry Jam MCP failures blindly.
54
+ - Tier order is `credential-substrate-precedence`: `JAM_PAT` CLI first, Jam MCP as
55
+ a preserved first-class fallback. Do not retry a failed tier blindly.
48
56
  - Never commit a Jam PAT into `.mcp.json` or any generated setup artifact.
49
57
  - Headless Jam access requires `native.jam.dev` for the installer and
50
58
  `api.jam.dev` for CLI/API calls in any custom remote network allowlist.
@@ -202,6 +202,11 @@ This gate never blocks a legitimate flat Task/Bug: those have no open children a
202
202
 
203
203
  **Claim-time archaeology runs second — after rejection detection, still before the transition below.** Classify this ticket 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. JIRA wiring only: the typed relations are already in the read bundle; text-similarity searches run through `lisa-atlassian-access operation: search-issues jql:` over recently-closed tickets; the fallback candidate comment is posted via `lisa-atlassian-access operation: comment`.
204
204
 
205
+ **The two `claim-time-guards` run third and fourth — still before the transition below.** Both semantics live in that one vendor-neutral slug; do not restate them here. JIRA wiring only:
206
+
207
+ 1. **`two-failed-attempts` valve.** Count `[lisa-build-attempt]` markers on the ticket from the read bundle's comments (match on the marker, never the summary). With two or more, do **not** claim: transition to the configured blocked status (`lisa-atlassian-access operation: transition to: "$BLOCKED"`, resolved from `jira.workflow.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.
208
+ 2. **`already-implemented` check.** Probe for this ticket's own key — `git log --all --grep "<TICKET>"` and the merged/open PRs referencing `<TICKET>` (`gh pr list --state all --search "<TICKET>"` in the bound repo). On a hit, claim as normal but route 3c to **verify-and-close** instead of `lisa-implement`: verify what shipped against the ticket's acceptance criteria, post evidence via `lisa-jira-evidence` naming the shipping PR/commit, then run the ordinary 3d transition and 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 ticket) and not `claim-archaeology` (a *different* ancestor ticket); it is this ticket's own work already having shipped without a transition.
209
+
205
210
  Transition the ticket from `$READY` to `$CLAIMED` by invoking `lisa-atlassian-access` `operation: transition key: <TICKET> to: "$CLAIMED"`.
206
211
  - **Assign to the authenticated user when the ticket is unassigned.** A claim must be attributable. If the ticket has no assignee, assign it to the authenticated account — prefer acli `--assignee @me` (resolves server-side to the authenticated user, which avoids the federated-`accountId` mis-assignment), or `write-ticket` with the `accountId` from the `/rest/api/3/myself` identity probe the access skill already documents. Leave an already-assigned ticket's assignee untouched — never reassign work that already has an owner.
207
212
  - Post a `[claude-build-intake]` comment via `lisa-atlassian-access` `operation: comment key: <TICKET> body: "Claimed by Claude. Starting build."`
@@ -125,6 +125,8 @@ Exclude unless requested: migration plans, performance tests
125
125
  - Sign-in account and target environment recorded in description
126
126
  - Post-create verification
127
127
 
128
+ **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-jira-write-ticket` rejects it.
129
+
128
130
  ### Invocation order
129
131
 
130
132
  Tickets must be created in parent-before-child order so each child can be passed its parent key:
@@ -238,11 +238,21 @@ Before create/update, verify each field is populated where applicable:
238
238
 
239
239
  ### Build-ready control input (`build_ready`)
240
240
 
241
- `build_ready` is an optional write-control input (default: **omitted**). It governs whether a **leaf** work unit is promoted to the build-ready role on create. It never overrides `leaf-only-lifecycle` — a container is never promoted regardless of `build_ready`. Unlike the label-based trackers, JIRA tickets are **already created not-ready** (in the project's default initial status, e.g. `TODO`/`Backlog`); the build-ready role is the configured `ready` status (`jira.workflow.ready`, default `Ready`), reached by an explicit transition.
241
+ `build_ready` is a write-control input governed by the `ready-role-filing` rule — cite that slug for the full contract; do not restate its per-vendor normalization table here. It decides whether a **leaf** work unit is promoted to the build-ready role on create. It never overrides `leaf-only-lifecycle` — a container is never promoted regardless of `build_ready`. Unlike the label-based trackers, JIRA tickets are **already created not-ready** (in the project's default initial status, e.g. `TODO`/`Backlog`); the build-ready role is the configured `ready` status (`jira.workflow.ready`, default `Ready`), reached by an explicit transition. JIRA is the vendor whose behavior the other two converged onto — this arm is unchanged by that normalization.
242
242
 
243
- - **Omitted** or **`build_ready: false`** current behavior: leave the ticket in the project's default created status. No transition. A human (or `build_ready: true`) promotes it to the `ready` status later.
243
+ - **Omitted** → **not build-ready**: leave the ticket in the project's default created status. No transition. Ready is an explicit claim, never a vendor default.
244
+ - **`build_ready: false`** → same outcome as omitted, stated deliberately: the ticket waits in the project's default status for a human to promote it.
244
245
  - **`build_ready: true`** → after create, transition the **leaf** to the resolved `ready` role so `lisa-intake` / `lisa-jira-build-intake` auto-picks it up (see Phase 6 CREATE step). Resolve the role name with the standard pattern (`.jira.workflow.ready` // `Ready`, local overrides global). Best-effort: if the transition is unreachable, record it and leave the ticket in its default status rather than failing the write.
245
246
 
247
+ **A filing with neither is an incomplete handoff.** A leaf that is not build-ready must carry an explicit `human_gate: "<why a human must judge this first>"`; nothing in the ready status means nothing ever claims it. When `human_gate` is supplied, stamp the hold on the ticket so it is auditable — a visible line plus the verbatim marker:
248
+
249
+ ```text
250
+ Held for a human product call: <reason>.
251
+ <!-- [lisa-human-gate] reason=<short-slug> -->
252
+ ```
253
+
254
+ If a leaf arrives with `build_ready` omitted or `false` **and** no `human_gate`, do not create it: report the incomplete handoff and name both ways to resolve it (`build_ready: true`, or a `human_gate` reason). Containers are exempt — their status rolls up from children, so they need neither.
255
+
246
256
  ## Phase 5.5 — Validate (Pre-write Gate)
247
257
 
248
258
  Before any write, invoke `lisa-jira-validate-ticket` with the full proposed spec assembled from Phases 2 / 3 / 4 / 5. Pass it as a YAML block per the `lisa-jira-validate-ticket` schema, including `runtime_behavior_change`, `authenticated_surface`, and `artifacts_attached` flags so the right gates run.
@@ -172,7 +172,12 @@ audits the auditor without re-running it.
172
172
 
173
173
  All project-tracker writes go through **`lisa-tracker-write`** so gardener
174
174
  tickets pass the same validation gates as all factory work. Nothing is created
175
- `status:ready` — the human flips.
175
+ `status:ready` — the human flips. Per `ready-role-filing` that hold is
176
+ **declared, not implied**: every gardener ticket passes
177
+ `human_gate: "a human decides whether this knowledge is promoted, demoted, or
178
+ retired"` so the writer stamps the auditable `[lisa-human-gate]` marker. An
179
+ omitted flag would be indistinguishable from the accidental non-ready filing
180
+ the rule exists to catch.
176
181
 
177
182
  **Per-item tickets — PROMOTE / DEMOTE** (`issue_type: Task`; GitHub trackers
178
183
  carry the `type:Task` label) — one ticket per recommendation, capped by
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: lisa-linear-access
3
- description: "Vendor-neutral access layer for Linear. Linear skills MUST delegate through this skill rather than calling Linear MCP tools or Linear GraphQL directly. Resolves Linear MCP first when authenticated, then falls back to LINEAR_API_KEY + Linear GraphQL in headless environments."
3
+ description: "Vendor-neutral access layer for Linear. Linear skills MUST delegate through this skill rather than calling Linear MCP tools or Linear GraphQL directly. Per the credential-substrate-precedence contract, resolves LINEAR_API_KEY + Linear GraphQL first ahead of the Linear MCP — whenever the key is present and identity-matches the configured workspace/team, and falls back to the Linear MCP when the token path is unavailable. Identity-match is mandatory on both substrates."
4
4
  allowed-tools: ["Bash", "Read", "Skill"]
5
5
  ---
6
6
 
@@ -46,15 +46,27 @@ WORKSPACE=$(jq -r '.linear.workspace // empty' .lisa.config.json 2>/dev/null)
46
46
  TEAM_KEY=$(jq -r '.linear.teamKey // empty' .lisa.config.json 2>/dev/null)
47
47
  ```
48
48
 
49
- Probe in order:
50
-
51
- 1. Linear MCP, if `mcp__linear-server__list_teams` is available and can list the
52
- configured workspace/team.
53
- 2. `LINEAR_API_KEY` with Linear GraphQL (`https://api.linear.app/graphql`).
49
+ Probe in order — the ordering is the shared `credential-substrate-precedence`
50
+ contract, not a Linear-local choice. The first tier that is ready **and**
51
+ identity-matches wins; a substrate authenticated against a different
52
+ workspace/team is **skipped, never used**, at either tier.
53
+
54
+ 1. **Tier 1 — configured-provider substrate: `LINEAR_API_KEY` with Linear GraphQL**
55
+ (`https://api.linear.app/graphql`), resolved through `lisa-secrets-access`.
56
+ Identity-match by querying `viewer { organization { urlKey } }` (plus
57
+ `teams` when `linear.teamKey` is configured) and comparing to
58
+ `.lisa.config.json`. A key that resolves to a different organization fails the
59
+ gate — warn, skip the tier, and continue down the ladder.
60
+ 2. **Tier 2 — interactive MCP fallback: Linear MCP**, if
61
+ `mcp__linear-server__list_teams` is available and can list the configured
62
+ workspace/team (that listing *is* the identity match). Used when tier 1 is
63
+ genuinely unavailable: no `LINEAR_API_KEY`, no GraphQL adapter for the
64
+ operation, or a Linear API outage.
54
65
 
55
66
  The Linear GraphQL docs support personal API keys for scripts and authenticate
56
- with an `Authorization: <API_KEY>` header. Treat `LINEAR_API_KEY` as the
57
- headless substrate. If neither tier works, fail with:
67
+ with an `Authorization: <API_KEY>` header, so the token tier works identically on
68
+ a developer laptop, in CI, in a cloud routine, and in a subagent — which is why it
69
+ leads. If neither tier works, fail with:
58
70
 
59
71
  ```text
60
72
  Error: no Linear access substrate available. Authenticate the Linear MCP or set LINEAR_API_KEY.
@@ -204,8 +216,16 @@ query($id:String!){
204
216
 
205
217
  ## Invariants
206
218
 
207
- - MCP is preferred when it is present and already authenticated.
208
- - GraphQL fallback runs only when `LINEAR_API_KEY` is present.
209
- - Missing MCP plus missing token is a hard failure naming `LINEAR_API_KEY`.
219
+ - Tier order is the shared `credential-substrate-precedence` contract:
220
+ `LINEAR_API_KEY` + GraphQL first when present and identity-matched, then the
221
+ Linear MCP. Do not restate or locally override the ordering here.
222
+ - The Linear MCP remains a first-class **fallback**, not a removed tier: it stays
223
+ the substrate whenever `LINEAR_API_KEY` is absent, the operation has no GraphQL
224
+ adapter, or the token path is failing.
225
+ - Identity-match is mandatory on **both** substrates. A substrate authenticated
226
+ against a different Linear organization or team is skipped, never used — that
227
+ includes a present-but-wrong `LINEAR_API_KEY`, which fails the gate loudly
228
+ instead of silently deferring to an authenticated MCP.
229
+ - Missing token plus missing MCP is a hard failure naming `LINEAR_API_KEY`.
210
230
  - Mutations send only the fields being changed, matching existing Linear skill
211
231
  guidance that `save_*` style updates should not clobber unrelated fields.
@@ -203,6 +203,11 @@ This gate never blocks a legitimate flat Task/Bug: those have no open children a
203
203
 
204
204
  **Claim-time archaeology runs second — after rejection detection, still before the transition below.** Classify this Issue 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. Linear wiring only: the native relations are already in the read bundle; text-similarity searches run through `lisa-linear-access operation: list-issues` filtered to recently-closed Issues; the fallback candidate comment is posted via `lisa-linear-access operation: save-comment`.
205
205
 
206
+ **The two `claim-time-guards` run third and fourth — still before the transition below.** Both semantics live in that one vendor-neutral slug; do not restate them here. Linear wiring only:
207
+
208
+ 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: set `stateId` to the configured blocked state via `lisa-linear-access operation: save-issue` (resolved from `linear.workflow.blocked` per `config-resolution`), post the operator-readable comment naming both attempts via `save-comment`, 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.
209
+ 2. **`already-implemented` check.** Probe for this Issue's own key — `git log --all --grep "<IDENTIFIER>"` and the merged/open PRs referencing `<IDENTIFIER>` (`gh pr list --state all --search "<IDENTIFIER>"` in the bound repo; Linear's own GitHub attachments in the read bundle are the cheaper first look). 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-linear-evidence` naming the shipping PR/commit, then run the ordinary 3d transition and 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.
210
+
206
211
  Transition the Issue via `lisa-linear-access operation: save-issue` by setting `stateId` to the `$CLAIMED` state. Resolve state IDs via `list-workflow-states`; a missing `$CLAIMED` state is a setup defect (see the pre-flight check) — never create one here.
207
212
 
208
213
  **Assign to the authenticated user when the Issue is unassigned.** A claim must be attributable. If the Issue has no assignee, set its `assigneeId` to the authenticated viewer (resolve the viewer's id via the Linear MCP identity — e.g. `get_user` for the current actor) through `lisa-linear-access operation: save-issue`. Leave an already-assigned Issue's assignee untouched — never reassign work that already has an owner.
@@ -124,7 +124,9 @@ Items must be created in parent-before-child order so each child can be passed i
124
124
 
125
125
  1. Invoke `lisa-linear-write-issue` for the Epic (Project). Capture the returned Project ID.
126
126
  2. For each Story, invoke `lisa-linear-write-issue` with the Project ID as `parent_project_id`. Capture each Issue identifier.
127
- 3. For each Sub-task, invoke `lisa-linear-write-issue` with the Story Issue ID as `parent_issue_id`.
127
+ 3. For each Sub-task, invoke `lisa-linear-write-issue` with the Story Issue ID as `parent_issue_id` and explicit `build_ready: true`.
128
+
129
+ - **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-linear-write-issue` rejects it.
128
130
 
129
131
  ### What to pass to each invocation
130
132
 
@@ -340,7 +340,7 @@ Each sub-task MUST:
340
340
  2. **Include an Empirical Verification Plan** — real user-like verification, NOT unit tests, linting, or typechecking
341
341
  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).
342
342
 
343
- **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.
343
+ **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.
344
344
 
345
345
  Sub-tasks inherit their parent story's artifacts by reference (the parent link). Do not pass the same artifact list to every sub-task.
346
346
 
@@ -408,6 +408,7 @@ produces broken tickets that downstream skills (triage, journey, evidence) canno
408
408
 
409
409
  For each sub-task, invoke `lisa-tracker-write` with:
410
410
  - issue_type: "Sub-task"
411
+ - build_ready: true # explicit per `ready-role-filing`; omitted is NOT build-ready on any tracker
411
412
  - prd_source: [the originating PRD URL — mandatory; arms the S16 traceability gate]
412
413
  - parent: the parent story key
413
414
  - project_key: [PROJECT]
@@ -31,7 +31,7 @@ Linear's data model maps Epic / Story / Sub-task to **different entity types**.
31
31
  | `Bug` | **Issue** | `lisa-linear-access operation: save-issue` | `projectId` if part of an Epic; else top-level |
32
32
  | `Spike` | **Issue** | `lisa-linear-access operation: save-issue` | `projectId` if part of an Epic; else top-level |
33
33
 
34
- The build lifecycle uses native **workflow states** (`Ready`, `In Progress`, `In Review`, `Blocked`, `On Dev`, `On Stg`, `Done`), resolved per role from `linear.workflow` — see "Why Linear uses states, not labels" in `config-resolution`. A new **leaf** work unit is created in the configured `ready` state by default; `build_ready: false` leaves it in the team's default backlog state instead, and a container is never put in `ready` at all (see the Build-ready control input below).
34
+ The build lifecycle uses native **workflow states** (`Ready`, `In Progress`, `In Review`, `Blocked`, `On Dev`, `On Stg`, `Done`), resolved per role from `linear.workflow` — see "Why Linear uses states, not labels" in `config-resolution`. A new **leaf** work unit is created in the configured `ready` state only on explicit `build_ready: true`; omitted or `false` leaves it in the team's default backlog state, and a container is never put in `ready` at all (see the Build-ready control input below).
35
35
 
36
36
  ## Phase 1 — Resolve Intent
37
37
 
@@ -242,7 +242,7 @@ If the item modifies an existing user-facing surface, a `lisa-product-walkthroug
242
242
 
243
243
  Before create/update, verify each field is populated where applicable:
244
244
 
245
- - **Workflow state**: set the resolved `ready` state (`linear.workflow.ready`, default `Ready`) on a new **leaf** work unit (Bug / Task / Sub-task / Improvement with no child work) per `leaf-only-lifecycle`, **unless `build_ready: false`** (see the Build-ready control input below). A container (Epic Project / Story with sub-issues / Spike) is never put in the build-ready state.
245
+ - **Workflow state**: set the resolved `ready` state (`linear.workflow.ready`, default `Ready`) on a new **leaf** work unit (Bug / Task / Sub-task / Improvement with no child work) per `leaf-only-lifecycle`, **only on explicit `build_ready: true`** (see the Build-ready control input below). A container (Epic Project / Story with sub-issues / Spike) is never put in the build-ready state.
246
246
  - **Labels**: taxonomy only — `type:<Kind>`, `repo:<name>`, `component:<name>`, and the `prd-intake-feedback` sentinel. Lifecycle is **not** a label on Linear; do not add `status:*` labels.
247
247
  - **Native priority field**: 0–4 per Linear's scale; explicit, not "unset".
248
248
  - **Native estimate**: per Linear's team-configured estimate scale (often 0–8 Fibonacci); skip for Epic / Spike.
@@ -254,12 +254,21 @@ For Bug / Task / Sub-task, ensure the summary is prefixed with `[<repo-name>]`.
254
254
 
255
255
  ### Build-ready control input (`build_ready`)
256
256
 
257
- `build_ready` is an optional write-control input (default: **omitted**). It governs whether a **leaf** work unit is created **in the resolved `ready` workflow state**. It never overrides `leaf-only-lifecycle` — a container is never stamped build-ready regardless of `build_ready`. "Not build-ready" is not a special state: the Issue is simply left in the team's default backlog/unstarted state, which a human can promote later. This mirrors `lisa-jira-write-ticket`, because Linear is a state-driven tracker like JIRA, not a label-driven one like GitHub.
257
+ `build_ready` is a write-control input governed by the `ready-role-filing` rule — cite that slug for the full contract; do not restate its per-vendor normalization table here. It decides whether a **leaf** work unit is created **in the resolved `ready` workflow state**. It never overrides `leaf-only-lifecycle` — a container is never stamped build-ready regardless of `build_ready`. "Not build-ready" is not a special state: the Issue is simply left in the team's default backlog/unstarted state, which a human can promote later. This mirrors `lisa-jira-write-ticket`, because Linear is a state-driven tracker like JIRA, not a label-driven one like GitHub.
258
258
 
259
- - **Omitted** → current behavior: a leaf work unit is created in the resolved `ready` state. Preserves what every existing caller (`lisa-plan`, the `*-to-tracker` skills) relies on.
259
+ - **Omitted** → **not build-ready**: the leaf is left in the team's default backlog state. Ready is an explicit claim, never a vendor default. **This is a breaking change** — Linear previously created a leaf directly in the `ready` state on omission, so a caller that relied on that must now pass `build_ready: true`.
260
260
  - **`build_ready: false`** → create the leaf **without** the `ready` state, leaving it in the team's default backlog state so it waits for a human to review and promote it into the queue.
261
261
  - **`build_ready: true`** → transition the **leaf** to the resolved `ready` state (`.linear.workflow.ready`) so `lisa-intake` / `lisa-linear-build-intake` auto-picks it up. Best-effort: if the state cannot be resolved or the transition is rejected, do not fail the write — leave the Issue in its default state and record the reason.
262
262
 
263
+ **A filing with neither is an incomplete handoff.** A leaf that is not build-ready must carry an explicit `human_gate: "<why a human must judge this first>"`; nothing in the ready lane means nothing ever claims it. When `human_gate` is supplied, stamp the hold on the Issue so it is auditable — a visible line plus the verbatim marker:
264
+
265
+ ```text
266
+ Held for a human product call: <reason>.
267
+ <!-- [lisa-human-gate] reason=<short-slug> -->
268
+ ```
269
+
270
+ If a leaf arrives with `build_ready` omitted or `false` **and** no `human_gate`, do not create it: report the incomplete handoff and name both ways to resolve it (`build_ready: true`, or a `human_gate` reason). Containers are exempt — their state rolls up from children, so they need neither.
271
+
263
272
  ## Phase 5.5 — Validate (Pre-write Gate)
264
273
 
265
274
  Before any write, invoke `lisa-linear-validate-issue` with the full proposed spec assembled from Phases 2 / 3 / 4 / 5. Pass it as a YAML block per the `lisa-linear-validate-issue` schema, including `runtime_behavior_change`, `authenticated_surface`, and `artifacts_attached` flags so the right gates run.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: lisa-notion-access
3
- description: "Vendor-neutral access layer for Notion. Every notion-* skill MUST delegate through this skill rather than invoking the Notion REST API or any Notion MCP directly. Resolves a substrate per operation in this order: (1) Notion MCP if authenticated and the configured prdDatabaseId is fetchable through it (identity-match), (2) curl + Bearer auth + internal-integration token. Verifies the active connection matches `.lisa.config.json` before every operation — substrates authenticated as a different Notion workspace are skipped, not used."
3
+ description: "Vendor-neutral access layer for Notion. Every notion-* skill MUST delegate through this skill rather than invoking the Notion REST API or any Notion MCP directly. Per the credential-substrate-precedence contract, resolves a substrate per operation in this order: (1) curl + Bearer auth + internal-integration token when the token is present and identity-matches the configured workspace, (2) Notion MCP as fallback if authenticated and the configured prdDatabaseId is fetchable through it. Verifies the active connection matches `.lisa.config.json` before every operation — substrates authenticated as a different Notion workspace are skipped, not used."
4
4
  allowed-tools: ["Bash", "Read", "Skill"]
5
5
  ---
6
6
 
@@ -38,20 +38,15 @@ DB_ID=$(jq -r '.notion.prdDatabaseId // empty' .lisa.config.json)
38
38
  [ -z "$DB_ID" ] && { echo "Error: notion.prdDatabaseId not set. Run /lisa:setup:notion." >&2; exit 1; }
39
39
  ```
40
40
 
41
- 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 workspace are skipped, not used.
41
+ 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, the interactive MCP is the fallback — not a Notion-local choice. Identity-match is verified before any operation; substrates authenticated as a different workspace are skipped, not used, at **every** tier.
42
42
 
43
43
  ```bash
44
44
  substrate=""
45
45
 
46
- # Tier 1: Notion MCP (identity-matched by fetching the configured PRD database)
47
- # Pseudo-code; actual call is the MCP tool invocation.
48
- # Try to fetch DB_ID through the MCP. Success MCP is authed to the right workspace.
49
- # 404 / object_not_found MCP is authed elsewhere (or unauthenticated). Skip.
50
- if mcp_notion_can_fetch_database "$DB_ID"; then
51
- substrate="mcp"
52
- fi
53
-
54
- # Tier 2: curl + API token
46
+ # Tier 1: curl + API token the configured-provider substrate, resolved through
47
+ # lisa-secrets-access. Leads because it is identical on a laptop, in CI, in a cloud
48
+ # routine, and in a subagent, and because its workspace binding travels with the
49
+ # request instead of coming from ambient browser-session state.
55
50
  read_notion_token() {
56
51
  local workspace="$1"
57
52
  [ -n "$NOTION_API_TOKEN" ] && { echo "$NOTION_API_TOKEN"; return; }
@@ -120,12 +115,28 @@ if [ -n "$TOKEN" ]; then
120
115
  "https://api.notion.com/v1/users/me")
121
116
  me_workspace=$(echo "$me" | jq -r '.bot.workspace_name // .bot.workspace_id // empty')
122
117
  if [ -n "$me_workspace" ] && [ "$me_workspace" = "$WORKSPACE" ]; then
123
- : ${substrate:=curl}
118
+ substrate="curl"
124
119
  elif [ -n "$me_workspace" ]; then
120
+ # A present-but-wrong token fails the gate rather than deferring to the MCP.
121
+ # Silently succeeding through an MCP authenticated elsewhere is the exact bug
122
+ # the precedence contract exists to surface.
125
123
  echo "Warning: Notion token belongs to workspace '$me_workspace' but config declares '$WORKSPACE'. Skipping curl tier." >&2
126
124
  fi
127
125
  fi
128
126
 
127
+ # Tier 2: Notion MCP — first-class fallback, used when tier 1 is genuinely
128
+ # unavailable (no token, no curl adapter for the operation, or Notion API outage).
129
+ # Identity-matched by fetching the configured PRD database.
130
+ # Pseudo-code; actual call is the MCP tool invocation.
131
+ # Try to fetch DB_ID through the MCP. Success → MCP is authed to the right workspace.
132
+ # 404 / object_not_found → MCP is authed elsewhere (or unauthenticated). Skip.
133
+ if mcp_notion_can_fetch_database "$DB_ID"; then
134
+ : ${substrate:=mcp}
135
+ # Mark the MCP available even when curl already won tier 1 — the dispatch table
136
+ # falls through to it for operations curl has no adapter for.
137
+ mcp_available=true
138
+ fi
139
+
129
140
  # Fail loudly with actionable remediation if nothing works.
130
141
  if [ -z "$substrate" ]; then
131
142
  # Detect plugin enablement state for the suggestion.
@@ -136,14 +147,19 @@ if [ -z "$substrate" ]; then
136
147
  cat >&2 <<EOF
137
148
  Error: no Notion access substrate available for workspace '$WORKSPACE'.
138
149
 
139
- Attempted:
140
- MCP — $([ "$plugin_enabled_global" = "true" ] || [ "$plugin_enabled_project" = "true" ] || [ "$plugin_enabled_local" = "true" ] && echo "plugin enabled but not authenticated or cannot fetch configured prdDatabaseId" || echo "plugin not enabled in any settings.json scope")
150
+ Attempted (in credential-substrate-precedence order):
141
151
  curl — no NOTION_API_TOKEN found for $WORKSPACE (env, slug-suffixed env, or keychain) OR token belongs to a different workspace
152
+ MCP — $([ "$plugin_enabled_global" = "true" ] || [ "$plugin_enabled_project" = "true" ] || [ "$plugin_enabled_local" = "true" ] && echo "plugin enabled but not authenticated or cannot fetch configured prdDatabaseId" || echo "plugin not enabled in any settings.json scope")
153
+
154
+ Remediation paths (the first is the contract's primary path):
142
155
 
143
- Remediation paths (pick one):
156
+ 1. Provision an internal-integration API token — works headless, in CI, and in
157
+ multi-workspace setups, and is the substrate this project resolves first.
144
158
 
145
- 1. Install the Notion MCP plugin (local scope — per-developer, gitignored).
146
- This is the simplest path for single-workspace developers.
159
+ Run /lisa:setup:notion guided flow with clipboard-piped keychain store.
160
+
161
+ 2. Install the Notion MCP plugin (local scope — per-developer, gitignored).
162
+ The supported fallback when no credentials provider is configured.
147
163
 
148
164
  Run in your terminal:
149
165
 
@@ -157,10 +173,6 @@ Remediation paths (pick one):
157
173
  Also share the configured prdDatabaseId with the integration via
158
174
  the page's '•••' menu → Connections.
159
175
 
160
- 2. Provision an internal-integration API token (headless / CI / multi-workspace).
161
-
162
- Run /lisa:setup:notion — guided flow with clipboard-piped keychain store.
163
-
164
176
  EOF
165
177
  exit 1
166
178
  fi
@@ -225,14 +237,15 @@ exec_op() {
225
237
  ## Invariants
226
238
 
227
239
  - Caller skills never call `curl https://api.notion.com/...` or any `mcp__*notion*` tool directly. They invoke this skill via the Skill tool with an operation name and arguments.
228
- - Substrate is selected per skill invocation following the tier ladder. The first tier that's available AND identity-matches `notion.workspaceId` wins.
229
- - The connection-match check is mandatory at every tier. Skipping it (because "the user obviously meant this workspace") is forbidden silent cross-workspace operations are exactly the multi-account hazard this design exists to prevent.
240
+ - Substrate is selected per skill invocation following the tier ladder defined by the shared `credential-substrate-precedence` contract — internal-integration token first, Notion MCP as fallback. The first tier that's available AND identity-matches `notion.workspaceId` wins. Do not restate or locally override the ordering here.
241
+ - The Notion MCP stays a first-class fallback, not a removed tier: it is the substrate whenever no token is configured, the operation has no curl adapter, or the Notion API is failing.
242
+ - The connection-match check is mandatory at every tier. Skipping it (because "the user obviously meant this workspace") is forbidden — silent cross-workspace operations are exactly the multi-account hazard this design exists to prevent. A present-but-wrong token fails the gate rather than deferring to an MCP authenticated somewhere else.
230
243
  - API tokens never mutate. If the configured workspace's token is wrong or missing, fail loudly and tell the user to run `/lisa:setup:notion`.
231
244
  - `Notion-Version` is pinned to `2022-06-28` — the version every existing notion-* skill targets. Bumping it is a coordinated change across the access skill and all callers.
232
245
 
233
246
  ## Headless behavior
234
247
 
235
- In a headless / non-interactive context (no TTY, `CI=true`, or `-p` mode), the MCP tier is unavailable (its OAuth flow needs a browser). The ladder collapses to curl + `NOTION_API_TOKEN`. Same skill code runs identically; only the substrate changes.
248
+ In a headless / non-interactive context (no TTY, `CI=true`, or `-p` mode), the MCP tier is unavailable (its OAuth flow needs a browser) and the ladder collapses to curl + `NOTION_API_TOKEN` — which is already tier 1 interactively. That is the point of the ordering: headless and interactive sessions take the **same primary path**, so a credential problem reproduces on a laptop instead of only in cron (`credential-substrate-precedence`, "headless parity"). Same skill code runs identically; only the availability of the fallback changes.
236
249
 
237
250
  ## Per-page sharing prerequisite
238
251
 
@@ -342,7 +342,7 @@ Each sub-task MUST:
342
342
  2. **Include an Empirical Verification Plan** — real user-like verification, NOT unit tests, linting, or typechecking
343
343
  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).
344
344
 
345
- **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.
345
+ **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.
346
346
 
347
347
  **Verification plan examples by stack:**
348
348
  - **Backend APIs**: curl GraphQL/REST calls with auth token, database queries, checking audit entries
@@ -426,6 +426,7 @@ produces broken tickets that downstream skills (triage, journey, evidence) canno
426
426
 
427
427
  For each sub-task, invoke `lisa-tracker-write` with:
428
428
  - issue_type: "Sub-task"
429
+ - build_ready: true # explicit per `ready-role-filing`; omitted is NOT build-ready on any tracker
429
430
  - parent: the parent story key
430
431
  - project_key: [PROJECT]
431
432
  - prd_source: [the originating PRD URL — mandatory; arms the S16 traceability gate]
@@ -112,7 +112,7 @@ This disposition completes the SLL-5 loop (#1583): on a Lisa-attributed failure
112
112
 
113
113
  Resolve the upstream repo from `.lisa.config.json` `hardening.upstreamRepo` (default `CodySwannGT/lisa`). Search **all issue states** for an existing issue carrying the marker — a closed marker-bearing ticket still owns this root cause, and searching only open issues would mint a duplicate the moment the original closes. Match on the **MARKER, never the title** — with the same eventual-consistency guard as above (`gh issue list -R <upstream> --state all --search '"<marker>" in:body' --json number,state,url`, and when the search index returns nothing, also `gh issue list -R <upstream> --state all --json number,state,body` and grep the bodies for the marker before concluding no ticket exists).
114
114
 
115
- - **No existing ticket** → compose the body EXCLUSIVELY through the executable builder, then file its stdout verbatim via `lisa-github-write-issue` targeting the upstream repo with the `self-hardening` label:
115
+ - **No existing ticket** → compose the body EXCLUSIVELY through the executable builder, then file its stdout verbatim via `lisa-github-write-issue` targeting the upstream repo with the `self-hardening` label and explicit `build_ready: true` (per `ready-role-filing`; the upstream repo runs its own build queue off the ready role, and an omitted flag would strand the hardening ticket there):
116
116
 
117
117
  ```bash
118
118
  bunx @codyswann/lisa file-upstream --input filing-event.json # or pipe the JSON on stdin
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: lisa-posthog-access
3
- description: "Vendor-neutral access layer for PostHog. PostHog skills and observability rules MUST delegate through this skill rather than calling PostHog MCP tools or REST directly. Resolves PostHog MCP first when available, then falls back to POSTHOG_PERSONAL_API_KEY bearer auth."
3
+ description: "Vendor-neutral access layer for PostHog. PostHog skills and observability rules MUST delegate through this skill rather than calling PostHog MCP tools or REST directly. Per the credential-substrate-precedence contract, resolves POSTHOG_PERSONAL_API_KEY bearer auth first when present and identity-matched to the configured project, then falls back to the PostHog MCP."
4
4
  allowed-tools: ["Bash", "Read", "Skill"]
5
5
  ---
6
6
 
@@ -22,13 +22,21 @@ Return parsed JSON in a `<result>` block.
22
22
 
23
23
  ## Substrate Selection
24
24
 
25
- Probe in order:
25
+ Probe in order — the ordering is the shared `credential-substrate-precedence`
26
+ contract, not a PostHog-local choice. The first tier that is ready **and**
27
+ identity-matches the configured project is used; a substrate authenticated against
28
+ a different project is skipped, never used.
26
29
 
27
- 1. PostHog MCP, if available and authenticated.
28
- 2. `POSTHOG_PERSONAL_API_KEY` bearer token against the configured PostHog host.
30
+ 1. **Tier 1 configured-provider substrate: `POSTHOG_PERSONAL_API_KEY`** bearer
31
+ token against the configured PostHog host, resolved through
32
+ `lisa-secrets-access`.
33
+ 2. **Tier 2 — interactive MCP fallback: PostHog MCP**, if available and
34
+ authenticated. Used when tier 1 is genuinely unavailable: no
35
+ `POSTHOG_PERSONAL_API_KEY`, no REST adapter for the operation, or a PostHog
36
+ outage.
29
37
 
30
- PostHog documents personal API keys and bearer authentication. The headless REST
31
- tier uses:
38
+ PostHog documents personal API keys and bearer authentication, and the same key
39
+ works interactively and headlessly — which is why it leads. The REST tier uses:
32
40
 
33
41
  ```bash
34
42
  POSTHOG_HOST=${POSTHOG_HOST:-https://app.posthog.com}
@@ -54,7 +62,9 @@ Error: no PostHog access substrate available. Authenticate the PostHog MCP or se
54
62
 
55
63
  ## Invariants
56
64
 
57
- - Fallback is gated on `POSTHOG_PERSONAL_API_KEY`.
65
+ - Tier order is `credential-substrate-precedence`: `POSTHOG_PERSONAL_API_KEY`
66
+ first, the PostHog MCP as a preserved first-class fallback. Identity-match
67
+ against the configured project is mandatory on every tier.
58
68
  - `POSTHOG_HOST` defaults to PostHog Cloud but can point at a self-hosted
59
69
  deployment.
60
70
  - Consumer skills do not embed PostHog REST paths.