@codyswann/lisa 4.86.0 → 4.87.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 (246) hide show
  1. package/all/copy-overwrite/scripts/lib/completion-proof-content.mjs +63 -22
  2. package/all/copy-overwrite/scripts/lib/npm-update-hosted-hook.mjs +6 -1
  3. package/all/copy-overwrite/scripts/lisa-hooks/parity-safety-net.sh +19 -3
  4. package/all/copy-overwrite/scripts/npm-updater-helper-graph.json +2 -2
  5. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  6. package/dist/core/lisa-owned-hash-ledger.js +16 -0
  7. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  8. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  9. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  10. package/dist/core/upstream-evidence-manifest.js +35 -28
  11. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  12. package/dist/opencode/plugin-templates/parity-safety-net.sh +19 -3
  13. package/package.json +4 -4
  14. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  15. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  16. package/plugins/lisa/.codex-plugin/skills/lisa-confluence-to-tracker/SKILL.md +5 -0
  17. package/plugins/lisa/.codex-plugin/skills/lisa-delivery-effectiveness/SKILL.md +7 -3
  18. package/plugins/lisa/.codex-plugin/skills/lisa-github-to-tracker/SKILL.md +5 -0
  19. package/plugins/lisa/.codex-plugin/skills/lisa-github-validate-issue/SKILL.md +2 -0
  20. package/plugins/lisa/.codex-plugin/skills/lisa-implement/SKILL.md +2 -0
  21. package/plugins/lisa/.codex-plugin/skills/lisa-jira-validate-ticket/SKILL.md +2 -0
  22. package/plugins/lisa/.codex-plugin/skills/lisa-learnings-audit/SKILL.md +9 -0
  23. package/plugins/lisa/.codex-plugin/skills/lisa-linear-to-tracker/SKILL.md +5 -0
  24. package/plugins/lisa/.codex-plugin/skills/lisa-linear-validate-issue/SKILL.md +2 -0
  25. package/plugins/lisa/.codex-plugin/skills/lisa-notion-to-tracker/SKILL.md +5 -0
  26. package/plugins/lisa/.codex-plugin/skills/lisa-parity-sentry-sdk-setup/SKILL.md +24 -17
  27. package/plugins/lisa/.codex-plugin/skills/lisa-persist-learning/SKILL.md +27 -8
  28. package/plugins/lisa/.codex-plugin/skills/lisa-plan/SKILL.md +2 -0
  29. package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/validate-config.mjs +39 -5
  30. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/SKILL.md +30 -5
  31. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-human.mjs +3 -1
  32. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-usage.mjs +11 -5
  33. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/human-needed.mjs +112 -5
  34. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/session-manager.mjs +5 -1
  35. package/plugins/lisa/.codex-plugin/skills/lisa-task-decomposition/SKILL.md +18 -0
  36. package/plugins/lisa/agents/learning-judge.md +34 -14
  37. package/plugins/lisa/hooks/parity-safety-net.sh +19 -3
  38. package/plugins/lisa/rules/reference/ready-role-filing.md +4 -0
  39. package/plugins/lisa/rules/reference/work-item-definition-of-ready.md +8 -0
  40. package/plugins/lisa/skills/lisa-confluence-to-tracker/SKILL.md +5 -0
  41. package/plugins/lisa/skills/lisa-delivery-effectiveness/SKILL.md +7 -3
  42. package/plugins/lisa/skills/lisa-delivery-effectiveness/agents/openai.yaml +2 -2
  43. package/plugins/lisa/skills/lisa-github-to-tracker/SKILL.md +5 -0
  44. package/plugins/lisa/skills/lisa-github-validate-issue/SKILL.md +2 -0
  45. package/plugins/lisa/skills/lisa-implement/SKILL.md +2 -0
  46. package/plugins/lisa/skills/lisa-jira-validate-ticket/SKILL.md +2 -0
  47. package/plugins/lisa/skills/lisa-learnings-audit/SKILL.md +9 -0
  48. package/plugins/lisa/skills/lisa-linear-to-tracker/SKILL.md +5 -0
  49. package/plugins/lisa/skills/lisa-linear-validate-issue/SKILL.md +2 -0
  50. package/plugins/lisa/skills/lisa-notion-to-tracker/SKILL.md +5 -0
  51. package/plugins/lisa/skills/lisa-parity-sentry-sdk-setup/SKILL.md +24 -17
  52. package/plugins/lisa/skills/lisa-persist-learning/SKILL.md +27 -8
  53. package/plugins/lisa/skills/lisa-plan/SKILL.md +2 -0
  54. package/plugins/lisa/skills/lisa-secrets-access/scripts/validate-config.mjs +39 -5
  55. package/plugins/lisa/skills/lisa-session-manager/SKILL.md +30 -5
  56. package/plugins/lisa/skills/lisa-session-manager/scripts/cli-human.mjs +3 -1
  57. package/plugins/lisa/skills/lisa-session-manager/scripts/cli-usage.mjs +11 -5
  58. package/plugins/lisa/skills/lisa-session-manager/scripts/human-needed.mjs +112 -5
  59. package/plugins/lisa/skills/lisa-session-manager/scripts/session-manager.mjs +5 -1
  60. package/plugins/lisa/skills/lisa-task-decomposition/SKILL.md +18 -0
  61. package/plugins/lisa-agy/agents/learning-judge.md +34 -14
  62. package/plugins/lisa-agy/hooks/parity-safety-net.sh +19 -3
  63. package/plugins/lisa-agy/plugin.json +1 -1
  64. package/plugins/lisa-agy/skills/lisa-confluence-to-tracker/SKILL.md +5 -0
  65. package/plugins/lisa-agy/skills/lisa-delivery-effectiveness/SKILL.md +7 -3
  66. package/plugins/lisa-agy/skills/lisa-github-to-tracker/SKILL.md +5 -0
  67. package/plugins/lisa-agy/skills/lisa-github-validate-issue/SKILL.md +2 -0
  68. package/plugins/lisa-agy/skills/lisa-implement/SKILL.md +2 -0
  69. package/plugins/lisa-agy/skills/lisa-jira-validate-ticket/SKILL.md +2 -0
  70. package/plugins/lisa-agy/skills/lisa-learnings-audit/SKILL.md +9 -0
  71. package/plugins/lisa-agy/skills/lisa-linear-to-tracker/SKILL.md +5 -0
  72. package/plugins/lisa-agy/skills/lisa-linear-validate-issue/SKILL.md +2 -0
  73. package/plugins/lisa-agy/skills/lisa-notion-to-tracker/SKILL.md +5 -0
  74. package/plugins/lisa-agy/skills/lisa-parity-sentry-sdk-setup/SKILL.md +24 -17
  75. package/plugins/lisa-agy/skills/lisa-persist-learning/SKILL.md +27 -8
  76. package/plugins/lisa-agy/skills/lisa-plan/SKILL.md +2 -0
  77. package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/validate-config.mjs +39 -5
  78. package/plugins/lisa-agy/skills/lisa-session-manager/SKILL.md +30 -5
  79. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-human.mjs +3 -1
  80. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-usage.mjs +11 -5
  81. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/human-needed.mjs +112 -5
  82. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/session-manager.mjs +5 -1
  83. package/plugins/lisa-agy/skills/lisa-task-decomposition/SKILL.md +18 -0
  84. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  85. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  86. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  87. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  88. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  89. package/plugins/lisa-cdk-devin/.claude-plugin/plugin.json +1 -1
  90. package/plugins/lisa-cdk-devin/.devin-plugin/plugin.json +1 -1
  91. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  92. package/plugins/lisa-copilot/agents/learning-judge.agent.md +34 -14
  93. package/plugins/lisa-copilot/hooks/parity-safety-net.sh +19 -3
  94. package/plugins/lisa-copilot/rules/reference/ready-role-filing.md +4 -0
  95. package/plugins/lisa-copilot/rules/reference/work-item-definition-of-ready.md +8 -0
  96. package/plugins/lisa-copilot/skills/lisa-confluence-to-tracker/SKILL.md +5 -0
  97. package/plugins/lisa-copilot/skills/lisa-delivery-effectiveness/SKILL.md +7 -3
  98. package/plugins/lisa-copilot/skills/lisa-github-to-tracker/SKILL.md +5 -0
  99. package/plugins/lisa-copilot/skills/lisa-github-validate-issue/SKILL.md +2 -0
  100. package/plugins/lisa-copilot/skills/lisa-implement/SKILL.md +2 -0
  101. package/plugins/lisa-copilot/skills/lisa-jira-validate-ticket/SKILL.md +2 -0
  102. package/plugins/lisa-copilot/skills/lisa-learnings-audit/SKILL.md +9 -0
  103. package/plugins/lisa-copilot/skills/lisa-linear-to-tracker/SKILL.md +5 -0
  104. package/plugins/lisa-copilot/skills/lisa-linear-validate-issue/SKILL.md +2 -0
  105. package/plugins/lisa-copilot/skills/lisa-notion-to-tracker/SKILL.md +5 -0
  106. package/plugins/lisa-copilot/skills/lisa-parity-sentry-sdk-setup/SKILL.md +24 -17
  107. package/plugins/lisa-copilot/skills/lisa-persist-learning/SKILL.md +27 -8
  108. package/plugins/lisa-copilot/skills/lisa-plan/SKILL.md +2 -0
  109. package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/validate-config.mjs +39 -5
  110. package/plugins/lisa-copilot/skills/lisa-session-manager/SKILL.md +30 -5
  111. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-human.mjs +3 -1
  112. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-usage.mjs +11 -5
  113. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/human-needed.mjs +112 -5
  114. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/session-manager.mjs +5 -1
  115. package/plugins/lisa-copilot/skills/lisa-task-decomposition/SKILL.md +18 -0
  116. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  117. package/plugins/lisa-cursor/agents/learning-judge.md +34 -14
  118. package/plugins/lisa-cursor/hooks/parity-safety-net.sh +19 -3
  119. package/plugins/lisa-cursor/rules/ready-role-filing-reference.mdc +4 -0
  120. package/plugins/lisa-cursor/rules/work-item-definition-of-ready-reference.mdc +8 -0
  121. package/plugins/lisa-cursor/skills/lisa-confluence-to-tracker/SKILL.md +5 -0
  122. package/plugins/lisa-cursor/skills/lisa-delivery-effectiveness/SKILL.md +7 -3
  123. package/plugins/lisa-cursor/skills/lisa-github-to-tracker/SKILL.md +5 -0
  124. package/plugins/lisa-cursor/skills/lisa-github-validate-issue/SKILL.md +2 -0
  125. package/plugins/lisa-cursor/skills/lisa-implement/SKILL.md +2 -0
  126. package/plugins/lisa-cursor/skills/lisa-jira-validate-ticket/SKILL.md +2 -0
  127. package/plugins/lisa-cursor/skills/lisa-learnings-audit/SKILL.md +9 -0
  128. package/plugins/lisa-cursor/skills/lisa-linear-to-tracker/SKILL.md +5 -0
  129. package/plugins/lisa-cursor/skills/lisa-linear-validate-issue/SKILL.md +2 -0
  130. package/plugins/lisa-cursor/skills/lisa-notion-to-tracker/SKILL.md +5 -0
  131. package/plugins/lisa-cursor/skills/lisa-parity-sentry-sdk-setup/SKILL.md +24 -17
  132. package/plugins/lisa-cursor/skills/lisa-persist-learning/SKILL.md +27 -8
  133. package/plugins/lisa-cursor/skills/lisa-plan/SKILL.md +2 -0
  134. package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/validate-config.mjs +39 -5
  135. package/plugins/lisa-cursor/skills/lisa-session-manager/SKILL.md +30 -5
  136. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-human.mjs +3 -1
  137. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-usage.mjs +11 -5
  138. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/human-needed.mjs +112 -5
  139. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/session-manager.mjs +5 -1
  140. package/plugins/lisa-cursor/skills/lisa-task-decomposition/SKILL.md +18 -0
  141. package/plugins/lisa-devin/.claude-plugin/plugin.json +1 -1
  142. package/plugins/lisa-devin/.devin-plugin/plugin.json +1 -1
  143. package/plugins/lisa-devin/agents/learning-judge.md +34 -14
  144. package/plugins/lisa-devin/hooks/parity-safety-net.sh +19 -3
  145. package/plugins/lisa-devin/rules/reference/ready-role-filing.md +4 -0
  146. package/plugins/lisa-devin/rules/reference/work-item-definition-of-ready.md +8 -0
  147. package/plugins/lisa-devin/skills/lisa-confluence-to-tracker/SKILL.md +5 -0
  148. package/plugins/lisa-devin/skills/lisa-delivery-effectiveness/SKILL.md +7 -3
  149. package/plugins/lisa-devin/skills/lisa-github-to-tracker/SKILL.md +5 -0
  150. package/plugins/lisa-devin/skills/lisa-github-validate-issue/SKILL.md +2 -0
  151. package/plugins/lisa-devin/skills/lisa-implement/SKILL.md +2 -0
  152. package/plugins/lisa-devin/skills/lisa-jira-validate-ticket/SKILL.md +2 -0
  153. package/plugins/lisa-devin/skills/lisa-learnings-audit/SKILL.md +9 -0
  154. package/plugins/lisa-devin/skills/lisa-linear-to-tracker/SKILL.md +5 -0
  155. package/plugins/lisa-devin/skills/lisa-linear-validate-issue/SKILL.md +2 -0
  156. package/plugins/lisa-devin/skills/lisa-notion-to-tracker/SKILL.md +5 -0
  157. package/plugins/lisa-devin/skills/lisa-parity-sentry-sdk-setup/SKILL.md +24 -17
  158. package/plugins/lisa-devin/skills/lisa-persist-learning/SKILL.md +27 -8
  159. package/plugins/lisa-devin/skills/lisa-plan/SKILL.md +2 -0
  160. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/validate-config.mjs +39 -5
  161. package/plugins/lisa-devin/skills/lisa-session-manager/SKILL.md +30 -5
  162. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-human.mjs +3 -1
  163. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-usage.mjs +11 -5
  164. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/human-needed.mjs +112 -5
  165. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/session-manager.mjs +5 -1
  166. package/plugins/lisa-devin/skills/lisa-task-decomposition/SKILL.md +18 -0
  167. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  168. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  169. package/plugins/lisa-expo-agy/plugin.json +1 -1
  170. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  171. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  172. package/plugins/lisa-expo-devin/.claude-plugin/plugin.json +1 -1
  173. package/plugins/lisa-expo-devin/.devin-plugin/plugin.json +1 -1
  174. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  175. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  176. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  177. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  178. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  179. package/plugins/lisa-harper-fabric-devin/.claude-plugin/plugin.json +1 -1
  180. package/plugins/lisa-harper-fabric-devin/.devin-plugin/plugin.json +1 -1
  181. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  182. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  183. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  184. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  185. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  186. package/plugins/lisa-nestjs-devin/.claude-plugin/plugin.json +1 -1
  187. package/plugins/lisa-nestjs-devin/.devin-plugin/plugin.json +1 -1
  188. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  189. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  190. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  191. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  192. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  193. package/plugins/lisa-openclaw-devin/.claude-plugin/plugin.json +1 -1
  194. package/plugins/lisa-openclaw-devin/.devin-plugin/plugin.json +1 -1
  195. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  196. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  197. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  198. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  199. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  200. package/plugins/lisa-phaser-devin/.claude-plugin/plugin.json +1 -1
  201. package/plugins/lisa-phaser-devin/.devin-plugin/plugin.json +1 -1
  202. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  203. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  204. package/plugins/lisa-rails-agy/plugin.json +1 -1
  205. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  206. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  207. package/plugins/lisa-rails-devin/.claude-plugin/plugin.json +1 -1
  208. package/plugins/lisa-rails-devin/.devin-plugin/plugin.json +1 -1
  209. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  210. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  211. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  212. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  213. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  214. package/plugins/lisa-typescript-devin/.claude-plugin/plugin.json +1 -1
  215. package/plugins/lisa-typescript-devin/.devin-plugin/plugin.json +1 -1
  216. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  217. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  218. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  219. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  220. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  221. package/plugins/lisa-wiki-devin/.claude-plugin/plugin.json +1 -1
  222. package/plugins/lisa-wiki-devin/.devin-plugin/plugin.json +1 -1
  223. package/plugins/src/base/agents/learning-judge.md +34 -14
  224. package/plugins/src/base/hooks/parity-safety-net.sh +19 -3
  225. package/plugins/src/base/rules/reference/ready-role-filing.md +4 -0
  226. package/plugins/src/base/rules/reference/work-item-definition-of-ready.md +8 -0
  227. package/plugins/src/base/skills/lisa-confluence-to-tracker/SKILL.md +5 -0
  228. package/plugins/src/base/skills/lisa-delivery-effectiveness/SKILL.md +7 -3
  229. package/plugins/src/base/skills/lisa-github-to-tracker/SKILL.md +5 -0
  230. package/plugins/src/base/skills/lisa-github-validate-issue/SKILL.md +2 -0
  231. package/plugins/src/base/skills/lisa-implement/SKILL.md +2 -0
  232. package/plugins/src/base/skills/lisa-jira-validate-ticket/SKILL.md +2 -0
  233. package/plugins/src/base/skills/lisa-learnings-audit/SKILL.md +9 -0
  234. package/plugins/src/base/skills/lisa-linear-to-tracker/SKILL.md +5 -0
  235. package/plugins/src/base/skills/lisa-linear-validate-issue/SKILL.md +2 -0
  236. package/plugins/src/base/skills/lisa-notion-to-tracker/SKILL.md +5 -0
  237. package/plugins/src/base/skills/lisa-parity-sentry-sdk-setup/SKILL.md +24 -17
  238. package/plugins/src/base/skills/lisa-persist-learning/SKILL.md +27 -8
  239. package/plugins/src/base/skills/lisa-plan/SKILL.md +2 -0
  240. package/plugins/src/base/skills/lisa-secrets-access/scripts/validate-config.mjs +39 -5
  241. package/plugins/src/base/skills/lisa-session-manager/SKILL.md +30 -5
  242. package/plugins/src/base/skills/lisa-session-manager/scripts/cli-human.mjs +3 -1
  243. package/plugins/src/base/skills/lisa-session-manager/scripts/cli-usage.mjs +11 -5
  244. package/plugins/src/base/skills/lisa-session-manager/scripts/human-needed.mjs +112 -5
  245. package/plugins/src/base/skills/lisa-session-manager/scripts/session-manager.mjs +5 -1
  246. package/plugins/src/base/skills/lisa-task-decomposition/SKILL.md +18 -0
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: learning-judge
3
- description: Skeptical judgment gate for candidate learnings. Classifies each candidate as durable-learning, one-off, misunderstanding/spec-gap, or lisa-upstream with mandatory evidence citation. Hostile default — most candidates are DROPPED; only durable-learning ever persists. Use whenever a failure signal or debrief produces a claimed learning that something wants to write to the project learnings surface.
3
+ description: Skeptical judgment gate for candidate learnings. Classifies each candidate as durable-learning, planning-miss, one-off, misunderstanding/spec-gap, or lisa-upstream with mandatory evidence citation. Hostile default — most candidates are DROPPED; only durable-learning and planning-miss (a dispatched item that needed a human because planning let a gap through) persist. Use whenever a failure signal or debrief produces a claimed learning that something wants to write to the project learnings surface.
4
4
  ---
5
5
 
6
6
  # Learning Judge Agent
@@ -30,6 +30,7 @@ Each candidate you evaluate is a single object:
30
30
  | `evidence_links[]` | string[] | Concrete evidence URLs/refs available for citation (failure logs, rejection comments, prior incidents). |
31
31
  | `scope_hint` | `project` \| `upstream` | The submitter's guess at where the learning belongs. A hint only — attribution below decides. |
32
32
  | `triggering_issue` | string | The issue/work item whose failure produced this candidate. |
33
+ | `signal` | `planning-miss` \| absent | Set by a caller that saw a dispatched item stop for a human or file a new ticket mid-build (`lisa-session-manager`, `lisa-implement`). A hint only — Step 2.5 decides. |
33
34
  | `fingerprint` | string | Stable dedupe key for this candidate (computed by the caller, e.g. `lisa-persist-learning`). Echo it back unchanged. |
34
35
 
35
36
  A candidate missing `triggering_issue` or with an empty evidence set can still be evaluated — but it can never reach `durable-learning`, because the mandatory citations below would be impossible.
@@ -51,27 +52,41 @@ Determine what actually caused the failure. If the root cause is a Lisa-shipped
51
52
  Only candidates that survive Steps 0–1 continue. Answer both questions, each with **cited** concrete evidence (from `evidence_links`, `provenance`, or your own tracker/repo lookup):
52
53
 
53
54
  1. **Prevention** — Would this exact rule, had it existed, have prevented the triggering failure? Re-walk the failure with the rule in force. If the failure would have happened anyway, the rule is a superstition: not durable.
54
- 2. **Recurrence** — Does the failure **class** recur? Cite concrete references: a prior issue, PR, revert, rejection comment, or incident showing the same class of mistake on a different occasion. **No recurrence evidence ⇒ never `durable-learning`.** A single occurrence, however painful, is `one-off` — the class may prove itself later, and the candidate can return with evidence.
55
+ 2. **Recurrence** — Does the failure **class** recur? Cite concrete references: a prior issue, PR, revert, rejection comment, or incident showing the same class of mistake on a different occasion. **No recurrence evidence ⇒ never `durable-learning`.** A single occurrence, however painful, is `one-off` — the class may prove itself later, and the candidate can return with evidence. The one exception is a requirement gap that reached a dispatched worker: judge it under Step 2.5 before concluding `one-off`.
55
56
 
56
57
  Do not accept the candidate's own `why` as evidence — it is the claim under test.
57
58
 
58
- ### Step 3: Classify (4-way taxonomy)
59
+ ### Step 2.5: Planning miss (a gap planning let through)
60
+
61
+ A missing, ambiguous, contradictory or undecided requirement is not always a one-ticket problem. PRD intake, decomposition and the ready gate (`work-item-definition-of-ready`, the S18 stateless-pickup dry-run) exist so a dispatched worker never needs a human. When one does, the item's own question gets answered on the item, but the process that let it through is unchanged — dropping the signal guarantees the next PRD repeats it. So a requirement gap is a `planning-miss`, not a drop, when **all** of these hold, each established by cited evidence rather than the candidate's word. (The planning skills are Lisa-shipped, but that alone does not make the miss `lisa-upstream` in Step 1: a check about this project's domain — its report formats, its repos, its integrations — belongs here. Only a domain-free check every project's planning would miss is a Lisa gate defect.)
62
+
63
+ 1. **It was dispatched.** The item had passed the ready gate — it was in the ready role and was picked up for dispatch — claimed by a worker, or held by the dispatcher while routing it to a repository (a `repo-route` hold: the item is past the ready gate and mid-dispatch, and `repo-scope-split` at decomposition should have made the route unambiguous) — before the gap surfaced. Cite the claim, the dispatch, or the ready-role history. A gap found at PRD intake, during validation, or before the ready flip is the gate **working**: that is `misunderstanding/spec-gap`.
64
+ 2. **The information really was missing.** Quote what the worker could not find, and confirm it is absent from the item and the links it resolves. If the answer was on the item and the worker misread it, it is `misunderstanding/spec-gap` (the worker's defect, not planning's).
65
+ 3. **It is not environmental or planned.** An outage, an expired credential, a flaky tool, missing tool access (`tool-access-gate`), or a decision planning **flagged as a human gate** on the item (`human_gate`, `[lisa-human-gate]`) is not a planning miss: asking there was the plan working. Neither is an item that exhausted its attempts.
66
+ 4. **A planning check would have caught it.** This is Step 2's prevention question, asked of planning instead of the build. Name the stage that should have caught it — `prd` (the requirement was never decided), `decomposition` (the work was mis-scoped, mis-split, or depended on something nobody filed, including a leaf the router could not place in one repo per `repo-scope-split`), or `ready-gate` (the item looked ready but S18 should have asked the question) — and re-walk it: with the check in force, the item would not have reached Ready with this gap.
67
+
68
+ **The rule is the check planning should have run, never the answer.** Rewrite the candidate's `rule` as `Planning (<stage>): <check>` — e.g. `Planning (decomposition): an export ticket must name its report format before it is Ready.` — never `Exports use CSV.`, which only answers the one ticket and belongs on the item. A rule that only makes sense for this one item is not a check: drop it as `misunderstanding/spec-gap`. The `why` names the stage that let it through and quotes what the worker could not find. The prefix is load-bearing: planning skills select these entries from the bounded projection by it (`lisa-task-decomposition` step 0).
69
+
70
+ **Recurrence never blocks a first occurrence.** A first-occurrence planning miss persists at `low` confidence, so its persistence PR waits for a human to merge it. That is a deliberate, bounded exception to Step 2's recurrence requirement. The hostile default exists because a plausible-but-wrong rule would reach every future session unattended; a `low` rule never does, because a human reads it at the gate first. Meanwhile the signal is unusually strong and unusually rare: each occurrence already cost the human interruption the gate exists to prevent, so waiting for a second occurrence costs a second interruption and teaches nothing new. And the rule only adds a check to planning — a wrong one costs a planning question, not changed build behaviour. With recurrence evidence (another dispatched item that stopped on the same class of gap), Step 4 may grant `high`.
71
+
72
+ ### Step 3: Classify (5-way taxonomy)
59
73
 
60
74
  Exactly one of:
61
75
 
62
- - **`durable-learning`** — both falsification questions pass with cited evidence. The only classification that persists. Disposition `persist`.
76
+ - **`durable-learning`** — both falsification questions pass with cited evidence. Disposition `persist`.
77
+ - **`planning-miss`** — every Step 2.5 condition holds: the item was dispatched past the ready gate, the information really was missing, the cause is not an outage, an expired credential, a flaky tool or a decision flagged as a human gate, and a named planning check would have caught it. Disposition `persist`, with `planning_stage` set and `rule` rewritten as the check.
63
78
  - **`one-off`** — a genuine typo, transient fluke, or single-occurrence mistake with no recurrence evidence. Disposition `drop`.
64
- - **`misunderstanding/spec-gap`** — the failure traces to an ambiguous or missing requirement, not an agent defect. The fix is a better spec (raise it on the work item), not a rule. Disposition `drop`.
79
+ - **`misunderstanding/spec-gap`** — the failure traces to an ambiguous or missing requirement caught **before** the item was dispatched (the gate worked), or to information the item did hold that was misread. The fix is a better spec (raise it on the work item), not a rule. Disposition `drop`.
65
80
  - **`lisa-upstream`** — set in Step 1. Disposition `handoff-upstream`; never persisted locally.
66
81
 
67
- When multiple classifications seem defensible, choose the one that does **not** persist — the hostile default.
82
+ When multiple classifications seem defensible, choose the one that does **not** persist — the hostile default. Dispatch is a fact, not a judgement call: if you cannot cite that the item passed the ready gate and was dispatched, it is not `planning-miss`.
68
83
 
69
- ### Step 4: Confidence (durable-learning only)
84
+ ### Step 4: Confidence (durable-learning and planning-miss)
70
85
 
71
86
  - **`high`** — the causal story is unambiguous and the recurrence citations are directly on point. The persistence PR may merge through the project's normal gates unattended.
72
87
  - **`low`** — durable on the evidence, but the causal chain has an inferential step or the recurrence evidence is indirect. The persistence PR must wait for a human (auto-merge off + triage label).
73
88
 
74
- If you cannot justify `high` in one sentence a non-engineer would accept, it is `low`.
89
+ If you cannot justify `high` in one sentence a non-engineer would accept, it is `low`. A `planning-miss` with no recurrence citation is always `low`.
75
90
 
76
91
  ## Verdict Output Schema
77
92
 
@@ -79,11 +94,13 @@ Return exactly one verdict object per candidate:
79
94
 
80
95
  | Field | Type | Meaning |
81
96
  |-------|------|---------|
82
- | `classification` | `durable-learning` \| `one-off` \| `misunderstanding/spec-gap` \| `lisa-upstream` | The Step 3 outcome. |
97
+ | `classification` | `durable-learning` \| `planning-miss` \| `one-off` \| `misunderstanding/spec-gap` \| `lisa-upstream` | The Step 3 outcome. |
83
98
  | `cited_evidence[]` | string[] | The concrete refs you actually relied on for this call — prevention and recurrence citations for durable; attribution citations for upstream; the decisive absence/counter-evidence for drops. Never empty. This is what makes a wrong call auditable. |
84
99
  | `rationale` | string | 1–3 sentences readable by product, engineering, and QA alike (a non-technical operator stands at the gate). |
85
- | `confidence` | `high` \| `low` | Present **only** when `classification` is `durable-learning`. |
86
- | `disposition` | `persist` \| `drop` \| `handoff-upstream` | `persist` iff durable-learning; `handoff-upstream` iff lisa-upstream; otherwise `drop`. |
100
+ | `confidence` | `high` \| `low` | Present **only** when `classification` is `durable-learning` or `planning-miss`. |
101
+ | `planning_stage` | `prd` \| `decomposition` \| `ready-gate` | Present **only** when `classification` is `planning-miss`: the stage that let the gap through. |
102
+ | `rule` | string | Present **only** when `classification` is `planning-miss`: the candidate's rule rewritten as the `Planning (<stage>): <check>` check, within the contract's caps. The caller persists this text, not the submitted one. |
103
+ | `disposition` | `persist` \| `drop` \| `handoff-upstream` | `persist` iff durable-learning or planning-miss; `handoff-upstream` iff lisa-upstream; otherwise `drop`. |
87
104
 
88
105
  Also echo back the candidate's `fingerprint` and `triggering_issue` so the caller can route without re-deriving them.
89
106
 
@@ -102,9 +119,12 @@ Also echo back the candidate's `fingerprint` and `triggering_issue` so the calle
102
119
  | Attribution (Lisa vs project) | project/lisa-upstream | [refs] |
103
120
  | Prevention (would the rule have prevented it?) | yes/no | [refs] |
104
121
  | Recurrence (does the class recur?) | yes/no | [refs] |
122
+ | Planning miss (dispatched, really missing, not environmental or a flagged gate, planning check named) | yes/no/n-a | [refs] |
105
123
 
106
- **Classification**: durable-learning | one-off | misunderstanding/spec-gap | lisa-upstream
107
- **Confidence**: high | low (durable-learning only)
124
+ **Classification**: durable-learning | planning-miss | one-off | misunderstanding/spec-gap | lisa-upstream
125
+ **Planning stage**: prd | decomposition | ready-gate (planning-miss only)
126
+ **Rule**: Planning (<stage>): <check> (planning-miss only — the rewritten rule the caller persists)
127
+ **Confidence**: high | low (durable-learning and planning-miss only)
108
128
  **Disposition**: persist | drop | handoff-upstream
109
129
  **Rationale**: [1–3 plain-language sentences]
110
130
  ```
@@ -112,7 +132,7 @@ Also echo back the candidate's `fingerprint` and `triggering_issue` so the calle
112
132
  ## Important Reminders
113
133
 
114
134
  1. **Most candidates DROP** — a session where you persist everything you saw is a failed gate, not a productive one.
115
- 2. **No recurrence citation, no durable-learning** — this is absolute; there are no exceptions for "obviously true" rules.
135
+ 2. **No recurrence citation, no durable-learning** — this is absolute; there are no exceptions for "obviously true" rules. A `planning-miss` is not a durable-learning: without recurrence it persists only at `low`, behind a human merge, and the recurrence requirement never blocks a first occurrence of it.
116
136
  3. **Cite what you relied on** — a verdict without `cited_evidence` is invalid; re-run the evaluation.
117
137
  4. **`lisa-upstream` never becomes a local rule** — classify and hand off; filing the upstream ticket is the caller's flow, not yours.
118
138
  5. **You classify; you do not write** — never touch the learnings surface, post comments, or open PRs. The caller (`lisa-persist-learning`) owns all side effects.
@@ -3475,12 +3475,28 @@ if [ -f "$rules_file" ]; then
3475
3475
  # here — before the remaining rules ran, and with an exit status that is
3476
3476
  # not a refusal. The `||` puts the pipeline in a condition context, where
3477
3477
  # a non-zero status is expected rather than fatal.
3478
- # Consume the whole input: grep -q can close an early match while printf
3479
- # is still writing, making pipefail report SIGPIPE instead of the match.
3478
+ # A here-string, never a pipe. With `printf | grep` under pipefail, a grep
3479
+ # that stops at its first match (`-q`, and GNU grep whose stdout is
3480
+ # /dev/null, which it treats as `-q`) closes the pipe while printf is still
3481
+ # writing; printf takes SIGPIPE and the pipeline reports 141 instead of
3482
+ # grep's 0. 141 lands in the `*)` arm below and a rule that MATCHED was
3483
+ # reported as an invalid regex and not enforced (CodySwannGT/lisa#4564).
3484
+ # A here-string has no writer process, so the status is grep's alone.
3485
+ #
3486
+ # The here-string is staged by the shell (a pipe, or a temp file for a
3487
+ # large body or on Bash 3.2), and that staging can fail: no temp space,
3488
+ # a file-size limit. A failed redirection on a bare `grep … <<<` returns
3489
+ # 1, the same status as "no match", so the rule would silently pass. The
3490
+ # brace group separates the two: grep's own status is captured INSIDE it,
3491
+ # so the group itself only fails when the redirection could not be set up.
3480
3492
  rule_status=0
3481
- printf '%s' "$custom_command_str" | grep -Ei -- "$rule" >/dev/null || rule_status=$?
3493
+ { grep -qEi -- "$rule" || rule_status=$?; } <<<"$custom_command_str" \
3494
+ || rule_status=unstaged
3482
3495
  case "$rule_status" in
3483
3496
  0) block "matched a project custom safety rule (${rules_file##*/}): $rule" ;;
3497
+ # Fail closed: the rule could not be evaluated at all, which is not the
3498
+ # same thing as the rule not matching.
3499
+ unstaged) block "could not stage the command to check project custom safety rule (${rules_file##*/}): $rule" ;;
3484
3500
  1) ;; # no match
3485
3501
  # grep exits 2 on a malformed ERE. Treated as no-match before, so a typo
3486
3502
  # in a project's rules file silently disabled that rule — a guard the
@@ -105,6 +105,10 @@ Any defect discovered while doing something else, which is complete enough to bu
105
105
 
106
106
  The same explicitness applies in the other direction. A filing that is genuinely a human product call declares `human_gate`; it does not simply omit the flag and hope the tracker default is the merciful one.
107
107
 
108
+ ## Mid-build filings are a planning signal
109
+
110
+ A ticket a worker has to file **while building** a dispatched item, because that item was mis-scoped, mis-split, or depends on work nobody filed, is filed exactly as above. It is also evidence that planning let a gap through, and it is routed as such: the filer sends one `planning-miss` candidate through `lisa-persist-learning`, with the item being built (never the new ticket) as `triggering_issue` and the check planning should have run as the rule. `lisa-implement` owns the step and its exclusions (outages, credentials, tool access, flaky tools, and decisions planning flagged as human gates); the judge decides whether it really was a miss. The signal never delays or changes the filing.
111
+
108
112
  ## The named exception: `lisa-exploratory-qa`
109
113
 
110
114
  `lisa-exploratory-qa` files its findings **not** build-ready by default, and that is **correct** — it is the named human-gate exception under this rule, not drift to be repaired.
@@ -167,6 +167,14 @@ the caller posts to the source. This is the enforcement of the intake
167
167
  contract's core promise, and of TASC AC8.6: *ready means zero-clarification
168
168
  executable.*
169
169
 
170
+ The dry-run also asks the **learned planning checks**: `planning-miss`
171
+ learnings, the check planning should have run, persisted by `learning-judge`
172
+ each time a dispatched worker still had to stop for a human or file a ticket
173
+ mid-build (CodySwannGT/lisa#4569). They are read through the learnings
174
+ contract's bounded projection (`lisa-task-decomposition` step 0), never the raw
175
+ ledger. A worker that stops anyway is the signal this gate missed something,
176
+ and the loop turns that stop into the next item's question.
177
+
170
178
  ## Relationship to the lifecycle
171
179
 
172
180
  - **Write time** — `*-write-*` runs the applicable pre-write gates; a spec
@@ -240,6 +240,11 @@ planning proceeds. Per atom:
240
240
  requirement.
241
241
  - **Pattern shape (SHOULD)** — an EARS pattern (ubiquitous / When / While / If-then / Where) or an
242
242
  equivalent single-behavior sentence; conforming shapes decompose into Gherkin mechanically.
243
+ - **Learned planning checks** — load the `Planning (...)` checks through the bounded projection
244
+ (`lisa-task-decomposition` step 0). Test the register against every `Planning (prd)` check; an
245
+ atom or a missing atom that fails one is a `product-clarity` item quoting the check, exactly
246
+ like the failures above. Carry the `Planning (decomposition)` checks into Phases 3–5. Each is
247
+ a gap a dispatched worker once had to stop and ask about, so catching it here is the point.
243
248
 
244
249
  Failures here are **requirement-level product clarifications**, not internal errors: report each in
245
250
  the dry-run report as a `product-clarity` item quoting the atom verbatim, naming the defect, and
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: lisa-delivery-effectiveness
3
- description: "Measure whether the work the factory delivers was worth shipping — gate rejection, rework, escape, first-pass yield and cost per delivered item — so autonomy rate cannot stand alone as a success measure."
3
+ description: "Measure whether the work the factory delivers was worth shipping — gate rejection, rework, escape, first-pass yield, cost per delivered item and planning-miss rate — so autonomy rate cannot stand alone as a success measure."
4
4
  allowed-tools: ["Read", "Grep", "Glob", "Bash"]
5
5
  ---
6
6
 
@@ -8,7 +8,7 @@ allowed-tools: ["Read", "Grep", "Glob", "Bash"]
8
8
 
9
9
  Autonomy rate answers how much ran without a human. It says nothing about whether any of it should have shipped, and on its own it rewards exactly the wrong thing: a factory that produces rejected work faster scores better.
10
10
 
11
- ## The five measures
11
+ ## The six measures
12
12
 
13
13
  Each needs a stated numerator, denominator and window, or it is a number-shaped opinion.
14
14
 
@@ -19,8 +19,11 @@ Each needs a stated numerator, denominator and window, or it is a number-shaped
19
19
  | **Escape rate** | Defects reaching production, over items released | What the gates did not catch |
20
20
  | **First-pass yield** | Items reaching terminal state with no rework, over items started | The one number that moves only when the whole line works |
21
21
  | **Cost per delivered item** | Metered spend, over items reaching terminal state | What a unit of accepted output actually costs |
22
+ | **Planning-miss rate** | Items carrying a `[lisa-planning-miss]` note, over items picked up for dispatch (entered the claimed role, or were held by the dispatcher at repository routing) | How often planning let through work a worker could not finish without a human |
22
23
 
23
- First-pass yield is the summary measure worth watching, because every other failure shows up in it. The other four exist to tell you *where* it went.
24
+ First-pass yield is the summary measure worth watching, because every other failure shows up in it. The other five exist to tell you *where* it went.
25
+
26
+ The planning-miss rate is the one that points upstream of the build. Its numerator is the `[lisa-planning-miss]` note `lisa-persist-learning` leaves on an item when `learning-judge` confirms that a dispatched worker had to stop for a human, or file a new ticket mid-build, because planning let a gap through. Count distinct items, not notes. The note is posted only on a confirmed miss, so outages, expired credentials, flaky tools and decisions planning flagged as human gates are already out of it. Both halves come from the tracker. Each persisted miss also becomes a planning check that PRD intake, decomposition and the ready gate read back, so better planning shows up as this number falling.
24
27
 
25
28
  ## Where the numbers come from
26
29
 
@@ -55,6 +58,7 @@ Report both, together, always. The pairing is the point:
55
58
  | Escape rate | | | | | |
56
59
  | First-pass yield | | | | | |
57
60
  | Cost per delivered item | | | | | |
61
+ | Planning-miss rate | | | | | |
58
62
 
59
63
  **Reading:** which of the four autonomy/yield quadrants this window sits in
60
64
  **Uncollected:** any measure not gathered, and why — never an estimate in its place
@@ -227,6 +227,11 @@ planning proceeds. Per atom:
227
227
  requirement.
228
228
  - **Pattern shape (SHOULD)** — an EARS pattern (ubiquitous / When / While / If-then / Where) or an
229
229
  equivalent single-behavior sentence; conforming shapes decompose into Gherkin mechanically.
230
+ - **Learned planning checks** — load the `Planning (...)` checks through the bounded projection
231
+ (`lisa-task-decomposition` step 0). Test the register against every `Planning (prd)` check; an
232
+ atom or a missing atom that fails one is a `product-clarity` item quoting the check, exactly
233
+ like the failures above. Carry the `Planning (decomposition)` checks into Phases 3–5. Each is
234
+ a gap a dispatched worker once had to stop and ask about, so catching it here is the point.
230
235
 
231
236
  Failures here are **requirement-level product clarifications**, not internal errors: report each in
232
237
  the dry-run report as a `product-clarity` item quoting the atom verbatim, naming the defect, and
@@ -345,6 +345,8 @@ Without a baseline and a target an Improvement has no verifiable terminal state
345
345
 
346
346
  The autonomy gate, run last, on every build-ready leaf (use the S15 classification; `N/A` for containers and non-build-ready items). Simulate a stateless agent reading only this item and the links it can resolve — session knowledge about the codebase does not count, because the next claimant will not have it. List every question that agent would have to ask a human before starting work, before choosing between materially different implementations, or before declaring the work done.
347
347
 
348
+ **Learned planning checks.** Questions that past dispatched workers actually had to stop and ask are the best predictor of the next one. Load the `Planning (...)` checks through the bounded projection exactly as `lisa-task-decomposition` step 0 does, and add each one that applies to this item as a question the simulated agent must be able to answer from the item and the links it can resolve, the same reach S18 already allows. One it cannot answer is a FAIL question like any other, quoting the check's rule. No ledger, or a malformed one, adds nothing and never fails this gate.
349
+
348
350
  Zero questions → PASS. Any question → FAIL, with each question listed verbatim as its own remediation line — these are exactly the clarifying comments the caller posts to the source. The structure gates are proxies; this gate checks the readiness property itself: `ready` means a stateless agent can drive this item to its terminal state with zero human clarification (see `work-item-definition-of-ready`).
349
351
 
350
352
  #### S19 — Branch Plan derivation
@@ -345,6 +345,8 @@ Before shutting down the team, execute the Verify flow:
345
345
  - **Actionable blocker** — an unresolved dependency or fixable technical gap that some team or repository could build (a missing or changed schema field, an unbuilt sibling work item, a required upstream fix), **including cross-repo dependencies**. Before writing the blocked verdict you MUST (1) file a build-ready fix/dependency ticket capturing the diagnosis — in the dependency's own repository/tracker when it is cross-repo (e.g. a `[<repo>] …` ticket in the shared project, or the sibling tracker) — and (2) link the current work item to it as `is blocked by`. Only then write the verdict. This is the same discipline as the regression-spec blocker and the remote-verification-fail exits above, and it is what makes the block machine-recoverable: `repair-intake` re-dispatches a blocked item once its linked `is blocked by` dependency closes, but it cannot act on a prose-only comment. Recommending the ticket "as a human follow-up" without filing and linking it is **not** a permitted exit.
346
346
  - **Human-only blocker** — an input the agent genuinely cannot obtain or produce no matter what it does: credentials, secrets, or **tool access** it does not have (AWS/CloudWatch, Figma, Jam, Sentry, SonarCloud, a database, a protected deploy target, …), or a product/design decision only a human can make. For missing tool access, follow the `tool-access-gate` rule's break-out protocol: post the "Access Needed" comment naming the exact credential/role/env var to grant and the probe that must pass — never work around the gap by substituting weaker verification, mocking the inaccessible system, or narrowing scope. Record the blocked verdict, mark it `human_needed` (the marker `repair-intake` recognizes, so it won't churn re-dispatching it), and surface or reassign to a human; do **not** fabricate a build-ready ticket, because there is no build-ready work.
347
347
 
348
+ **Planning-miss signal.** Either exit can mean planning let a gap through, and that signal is worth more than the one ticket (CodySwannGT/lisa#4569). It is a planning miss when you file a new ticket mid-build because this item was mis-scoped, mis-split, or depends on work nobody filed, or when you mark it `human_needed` because a requirement was missing, unclear, contradictory or undecided. It is **not** one when the cause is an outage, an expired credential, missing tool access, a flaky tool, or a decision the item itself flagged as a human gate. For a planning miss, route one candidate through `lisa-persist-learning` with `signal: planning-miss`, `triggering_issue` = **this** item (never the new ticket), `rule` = the check planning should have run, as `Planning (<prd|decomposition|ready-gate>): <check>` (not this item's answer), `why` = the stage that let it through plus a quote of what you could not find, and `evidence_links` = the new ticket or the blocked-verdict comment. Run it as a background subagent where the runtime has one, otherwise after the blocked verdict is recorded; it is headless-safe, never blocks the exit, and its failure is one line in the final summary. Under `managedBy=`, the manager routes a human-needed stop itself when it marks the item, so route only the mid-build ticket case there; routing both would double-count one miss.
349
+
348
350
  **Harnesses that do not fire a Stop hook enforce the same discipline by convention.** The
349
351
  `enforce-verification-gate.sh` Stop hook is a **Claude-only** surface — Codex, Cursor, Antigravity,
350
352
  Copilot, and OpenCode carry the skills, agents, and (where the runtime has a rules surface) the
@@ -347,6 +347,8 @@ Without a baseline and a target an Improvement has no verifiable terminal state
347
347
 
348
348
  The autonomy gate, run last, on every build-ready leaf (use the S15 classification; `N/A` for containers and non-build-ready items). Simulate a stateless agent reading only this item and the links it can resolve — session knowledge about the codebase does not count, because the next claimant will not have it. List every question that agent would have to ask a human before starting work, before choosing between materially different implementations, or before declaring the work done.
349
349
 
350
+ **Learned planning checks.** Questions that past dispatched workers actually had to stop and ask are the best predictor of the next one. Load the `Planning (...)` checks through the bounded projection exactly as `lisa-task-decomposition` step 0 does, and add each one that applies to this item as a question the simulated agent must be able to answer from the item and the links it can resolve, the same reach S18 already allows. One it cannot answer is a FAIL question like any other, quoting the check's rule. No ledger, or a malformed one, adds nothing and never fails this gate.
351
+
350
352
  Zero questions → PASS. Any question → FAIL, with each question listed verbatim as its own remediation line — these are exactly the clarifying comments the caller posts to the source. The structure gates are proxies; this gate checks the readiness property itself: `ready` means a stateless agent can drive this item to its terminal state with zero human clarification (see `work-item-definition-of-ready`).
351
353
 
352
354
  #### S19 — Branch Plan derivation
@@ -83,6 +83,15 @@ a `last_confirmed` bump), **RETIRE** (provably redundant/stale — proof, not
83
83
  vibes), or leave alone. No evidence ⇒ no candidate; the gardener never files
84
84
  a recommendation it cannot evidence.
85
85
 
86
+ **Learned planning checks.** A ledger entry whose rule begins
87
+ `Planning (prd|decomposition|ready-gate):` is a `planning-miss` learning: the
88
+ check planning should have run before a dispatched worker had to stop for a
89
+ human (CodySwannGT/lisa#4569). When Recurrence shows the same class of gap
90
+ stopping workers on more than one item, it is a PROMOTE candidate into the
91
+ ready gate itself — the `work-item-definition-of-ready` rule or the validators'
92
+ S18 dry-run — rather than one more ledger entry competing for the projection.
93
+ A recurring miss counts once per `[lisa-planning-miss]` note on distinct items.
94
+
86
95
  **The eager tier is audited every run** — including
87
96
  **Lisa's own shipped eager rules**, not just host additions. Admission is demotion-biased and
88
97
  earned only by repeated-miss evidence (see the `promotion-contract` rule);
@@ -224,6 +224,11 @@ planning proceeds. Per atom:
224
224
  requirement.
225
225
  - **Pattern shape (SHOULD)** — an EARS pattern (ubiquitous / When / While / If-then / Where) or an
226
226
  equivalent single-behavior sentence; conforming shapes decompose into Gherkin mechanically.
227
+ - **Learned planning checks** — load the `Planning (...)` checks through the bounded projection
228
+ (`lisa-task-decomposition` step 0). Test the register against every `Planning (prd)` check; an
229
+ atom or a missing atom that fails one is a `product-clarity` item quoting the check, exactly
230
+ like the failures above. Carry the `Planning (decomposition)` checks into Phases 3–5. Each is
231
+ a gap a dispatched worker once had to stop and ask about, so catching it here is the point.
227
232
 
228
233
  Failures here are **requirement-level product clarifications**, not internal errors: report each in
229
234
  the dry-run report as a `product-clarity` item quoting the atom verbatim, naming the defect, and
@@ -332,6 +332,8 @@ Without a baseline and a target an Improvement has no verifiable terminal state
332
332
 
333
333
  The autonomy gate, run last, on every build-ready leaf (use the S15 classification; `N/A` for containers and non-build-ready items). Simulate a stateless agent reading only this item and the links it can resolve — session knowledge about the codebase does not count, because the next claimant will not have it. List every question that agent would have to ask a human before starting work, before choosing between materially different implementations, or before declaring the work done.
334
334
 
335
+ **Learned planning checks.** Questions that past dispatched workers actually had to stop and ask are the best predictor of the next one. Load the `Planning (...)` checks through the bounded projection exactly as `lisa-task-decomposition` step 0 does, and add each one that applies to this item as a question the simulated agent must be able to answer from the item and the links it can resolve, the same reach S18 already allows. One it cannot answer is a FAIL question like any other, quoting the check's rule. No ledger, or a malformed one, adds nothing and never fails this gate.
336
+
335
337
  Zero questions → PASS. Any question → FAIL, with each question listed verbatim as its own remediation line — these are exactly the clarifying comments the caller posts to the source. The structure gates are proxies; this gate checks the readiness property itself: `ready` means a stateless agent can drive this item to its terminal state with zero human clarification (see `work-item-definition-of-ready`).
336
338
 
337
339
  #### S19 — Branch Plan derivation
@@ -206,6 +206,11 @@ planning proceeds. Per atom:
206
206
  requirement.
207
207
  - **Pattern shape (SHOULD)** — an EARS pattern (ubiquitous / When / While / If-then / Where) or an
208
208
  equivalent single-behavior sentence; conforming shapes decompose into Gherkin mechanically.
209
+ - **Learned planning checks** — load the `Planning (...)` checks through the bounded projection
210
+ (`lisa-task-decomposition` step 0). Test the register against every `Planning (prd)` check; an
211
+ atom or a missing atom that fails one is a `product-clarity` item quoting the check, exactly
212
+ like the failures above. Carry the `Planning (decomposition)` checks into Phases 3–5. Each is
213
+ a gap a dispatched worker once had to stop and ask about, so catching it here is the point.
209
214
 
210
215
  Failures here are **requirement-level product clarifications**, not internal errors: report each in
211
216
  the dry-run report as a `product-clarity` item quoting the atom verbatim, naming the defect, and
@@ -177,8 +177,11 @@ once at module startup with the DSN from the environment. Await a finite positiv
177
177
  flush budget on both success and original-error paths. A false flush result or
178
178
  rejection must not turn successful queue work into a retry or replace its real
179
179
  error. Keep diagnostics local and non-throwing, and preserve the client for warm
180
- invocations: `close()` disables it. The following helper wraps the host's existing
181
- business operation; it neither mutates context nor adds a Lambda callback.
180
+ invocations: `close()` disables it. A warm container reuses the same process, so
181
+ run each invocation inside `Sentry.withIsolationScope()`: tags, user and
182
+ breadcrumbs that one invocation sets then stay with that invocation instead of
183
+ leaking into the next one's events. The following helper wraps the host's existing
184
+ business operation; it neither mutates the Lambda context nor adds a Lambda callback.
182
185
 
183
186
  <!-- lisa-node24-unwrapped-example:start -->
184
187
  ```ts
@@ -200,24 +203,28 @@ export async function withSentryFlush<T>(
200
203
  if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
201
204
  throw new RangeError("Choose a finite positive Sentry flush budget");
202
205
  }
203
- try {
204
- return await work();
205
- } catch (originalError) {
206
- try {
207
- Sentry.captureException(originalError);
208
- } catch {
209
- // Preserve the original handler error even if capture fails.
210
- }
211
- throw originalError;
212
- } finally {
206
+ // A fresh isolation scope per invocation: scope data set by one warm
207
+ // invocation must not be attached to the next invocation's events.
208
+ return Sentry.withIsolationScope(async () => {
213
209
  try {
214
- if (!(await Sentry.flush(timeoutMs))) {
215
- reportFlushProblem("Sentry flush did not finish in time");
210
+ return await work();
211
+ } catch (originalError) {
212
+ try {
213
+ Sentry.captureException(originalError);
214
+ } catch {
215
+ // Preserve the original handler error even if capture fails.
216
+ }
217
+ throw originalError;
218
+ } finally {
219
+ try {
220
+ if (!(await Sentry.flush(timeoutMs))) {
221
+ reportFlushProblem("Sentry flush did not finish in time");
222
+ }
223
+ } catch {
224
+ reportFlushProblem("Sentry flush rejected");
216
225
  }
217
- } catch {
218
- reportFlushProblem("Sentry flush rejected");
219
226
  }
220
- }
227
+ });
221
228
  }
222
229
  ```
223
230
  <!-- lisa-node24-unwrapped-example:end -->
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: lisa-persist-learning
3
- description: This skill should be used when a candidate learning (from a failure signal, rejection, or debrief) needs to be judged and routed. It computes a stable fingerprint, runs the candidate through the hostile-default learning-judge gate, and performs exactly the verdict's side effects — a dropped-with-reason note on the triggering issue (drop), an automatically filed upstream Lisa ticket with marker dedupe, evidence, and a per-run cap (lisa-upstream), or a confidence-routed pull request that touches only the learnings surface (durable-learning). Idempotent via marker dedupe; headless-safe; never blocks the primary build flow.
3
+ description: This skill should be used when a candidate learning (from a failure signal, rejection, or debrief) needs to be judged and routed. It computes a stable fingerprint, runs the candidate through the hostile-default learning-judge gate, and performs exactly the verdict's side effects — a dropped-with-reason note on the triggering issue (drop), an automatically filed upstream Lisa ticket with marker dedupe, evidence, and a per-run cap (lisa-upstream), or a confidence-routed pull request that touches only the learnings surface (durable-learning, or planning-miss — a dispatched item that needed a human because planning let a gap through, which also leaves a countable planning-miss note on the item). Idempotent via marker dedupe; headless-safe; never blocks the primary build flow.
4
4
  ---
5
5
 
6
6
  # Persist Learning
@@ -21,6 +21,7 @@ Accept the candidate as JSON or `key=value` fields:
21
21
  - `evidence_links` — concrete evidence refs available for citation
22
22
  - `scope_hint` — `project` | `upstream` (a hint; the judge decides)
23
23
  - `triggering_issue` — the issue/work item whose failure produced this candidate (required)
24
+ - `signal` — optional; `planning-miss` when a dispatched item stopped for a human or filed a new ticket mid-build (from `lisa-session-manager` or `lisa-implement`). A hint for the judge, never a verdict
24
25
  - `fingerprint` — optional; computed below when absent
25
26
 
26
27
  ## Phase 0 — Fingerprint (stable dedupe key)
@@ -41,9 +42,9 @@ FP="sll4-$(printf '%s\n%s' "$NORM" "$TRIGGERING_ISSUE" | shasum -a 1 | cut -c1-1
41
42
 
42
43
  ## Phase 1 — Judge (mandatory, never skipped)
43
44
 
44
- Invoke the `learning-judge` agent (via the Agent/Task tool with `subagent_type: "learning-judge"` — the same invoke pattern the gardener uses for the `skill-evaluator` ladder router) with the full candidate including the fingerprint. It returns a verdict: `classification`, `cited_evidence[]`, `rationale`, `confidence` (durable only), `disposition`.
45
+ Invoke the `learning-judge` agent (via the Agent/Task tool with `subagent_type: "learning-judge"` — the same invoke pattern the gardener uses for the `skill-evaluator` ladder router) with the full candidate including the fingerprint. It returns a verdict: `classification`, `cited_evidence[]`, `rationale`, `confidence` (durable-learning and planning-miss only), `planning_stage` and the rewritten `rule` (planning-miss only), `disposition`.
45
46
 
46
- **Respect the verdict — do not override it.** Never re-run the judge hoping for a different answer, and never persist anything the judge did not classify `durable-learning`.
47
+ **Respect the verdict — do not override it.** Never re-run the judge hoping for a different answer, and never persist anything the judge did not classify `durable-learning` or `planning-miss`. For a `planning-miss`, persist the judge's rewritten `Planning (<stage>): <check>` rule, never the submitted text: the check is what planning reads back, and the submitted text is often just the one ticket's answer.
47
48
 
48
49
  ## Phase 2 — Route by disposition
49
50
 
@@ -68,6 +69,8 @@ The note is one line naming the classification (with its fixed plain-language gl
68
69
 
69
70
  (A `lisa-upstream` classification never produces a drop note — it routes through the `handoff-upstream` flow below, whose step-1 note uses this pre-attribution wording because filing only happens after attribution confirms the Lisa surface.) Dedupe before posting: if any comment on the triggering issue already carries `[lisa-learning-drop] key=<fingerprint>`, do not post again — report the existing note.
70
71
 
72
+ On a tracker that strips HTML comments from comment bodies (Linear does), the hidden marker line is lost, so also begin the visible line with the bracketed marker (`[lisa-learning-drop] key=<fingerprint> Dropped (…)`). Dedupe still finds it, and so does every machine-comment filter that reads the item — the session manager's `item-answer` would otherwise read a markerless note on a held item as a human's answer.
73
+
71
74
  ### `handoff-upstream` (classification `lisa-upstream`)
72
75
 
73
76
  This disposition completes the SLL-5 loop (#1583): on an accepted worthwhile Lisa-attributed failure the upstream Lisa ticket is filed **automatically**. Filing lives here — not in `lisa-attribute-failure` — because that skill is deliberately read-only (doctor delegates to it inside its own read-only contract), while this skill already owns exactly the verdict's side effects and the marker-dedupe discipline. Never persist a local rule for a Lisa-attributed failure; the host project's only durable trace is the brief linking note in step 6.
@@ -159,15 +162,24 @@ First apply `do-it-now`'s **Worth doing** guidance. Attribution establishes owne
159
162
  Upstream filing did not complete — nothing was filed upstream and nothing was persisted locally; a later run retries.
160
163
  ```
161
164
 
162
- ### `persist` (classification `durable-learning`)
165
+ ### `persist` (classification `durable-learning` or `planning-miss`)
166
+
167
+ For a `planning-miss`, first post **one** note on the triggering issue, marker-deduped like the drop note, so the miss is visible on the item and countable from the tracker (`lisa-delivery-effectiveness` reads it for the planning-miss rate). The marker is in the visible text, not only an HTML comment, because some trackers strip those:
168
+
169
+ ```markdown
170
+ [lisa-planning-miss] key=<fingerprint> Planning miss (<planning_stage>): <what the worker could not find>. Recorded as the planning check "<rewritten rule>"; the learning pull request names this item.
171
+ ```
172
+
173
+ Post it even when Phase 3 then finds the rule already captured, or fails: the occurrence is still a miss, and the rate counts occurrences, not new rules. The `[lisa-planning-miss]` marker sits outside the `[lisa-learning-*]` namespace on purpose: it is a measurement of planning, and must not make the item look like learning machinery to `rejection-detection` or the judge's Step 0 guard.
163
174
 
164
- Continue to Phase 3.
175
+ Then continue to Phase 3.
165
176
 
166
- ## Phase 3 — Persist via PR (durable-learning only)
177
+ ## Phase 3 — Persist via PR (durable-learning and planning-miss)
167
178
 
168
179
  No learning content is ever committed without a PR — there is no other write path, and the PR must touch **only** the learnings surface (any other changed file is a bug).
169
180
 
170
181
  1. **PR dedupe.** Search all PRs for the marker `[lisa-learning-pr] key=<fingerprint>` in the body (`gh pr list --state all --search '"<marker>" in:body' --json number,url`), with the stale-index guard above. If one exists, reference it and stop — never open a duplicate.
182
+ Then create (or reuse) branch `learning/<fingerprint>` in an **isolated worktree** off the default branch, never the caller's checkout, and run every step below from that worktree's root — `projectRoot` in each writer call is that root. A caller such as the session manager or an implement worker has its own branch and files in flight in its checkout; a writer run there would put the ledger change on the wrong branch and leave the learning branch empty.
171
183
  2. **Resolve the learnings surface path — never hardcode it.** The canonical path is `resolveProjectLearningsFile` from `@codyswann/lisa/learnings`: the machine-managed ledger resolved from `.lisa.config.json` (the `learnings.file` override, else the default `.lisa/PROJECT_LEARNINGS.md` — a cold path, never an auto-loaded rules tree):
172
184
 
173
185
  ```bash
@@ -177,7 +189,7 @@ No learning content is ever committed without a PR — there is no other write p
177
189
  3. **Consolidation check (mandatory before writing).** Parse the existing entries (`parseLearningsFile` from `@codyswann/lisa/learnings`). First compare `learningFingerprint(existing.rule)` with `learningFingerprint(candidate.rule)`: an equal rule is already captured, even if its legacy id or fingerprint has another prefix. Preserve the stored values, report the existing id, and stop without writing that candidate. Shared evidence alone never makes two rules duplicates. Only otherwise look for related entries (same failure class, overlapping topic, or near-duplicate wording) and write through the executable contract — **never hand-edit the markdown**:
178
190
  - **Related entry found** → consolidate with the exact versions returned by the parser: `persistConsolidatedLearning(projectRoot, entry, { supersede: [{ id: <related id>, fingerprint: <related fingerprint> }], onStaleSupersede: targets => report(targets) })`. The writer checks every stamp together inside the lock. If any target is absent or its fingerprint changed, the whole supersede is stale: it removes nothing, safely appends the new fingerprint, and reports the mismatch. Never append a near-duplicate sibling by choice — a sibling is a bug that fails review; the writer's stale append is the deliberate race-safe preservation path.
179
191
  - **No related entry** → append via `persistLearningEntry(projectRoot, entry)` and state in the PR body why appending was correct.
180
- - Entry mapping (eight fields): `fingerprint` = `learningFingerprint(rule)` and initial `id = fingerprint`; `rule`/`why`/`provenance` from the candidate; `first_learned` = `last_confirmed` = today (ISO date; on consolidation keep the superseded entry's earliest `first_learned`); `confidence` = the judge's `high`/`low`. On an exact stamped consolidation the writer carries forward the deterministic primary target id while persisting the new fingerprint as the version token. Use exact parsed legacy stamps in `supersede`; never rewrite old ids or fingerprints just to adopt the helper. A duplicate fingerprint fails before mutation. The writer re-asserts the entry and token budgets — an over-budget failure means consolidate harder or drop, never truncate by hand.
192
+ - Entry mapping (eight fields): `fingerprint` = `learningFingerprint(rule)` and initial `id = fingerprint`; `rule`/`why`/`provenance` from the candidate (for a `planning-miss`, `rule` is the judge's rewritten check); `first_learned` = `last_confirmed` = today (ISO date; on consolidation keep the superseded entry's earliest `first_learned`); `confidence` = the judge's `high`/`low`. On an exact stamped consolidation the writer carries forward the deterministic primary target id while persisting the new fingerprint as the version token. Use exact parsed legacy stamps in `supersede`; never rewrite old ids or fingerprints just to adopt the helper. A duplicate fingerprint fails before mutation. The writer re-asserts the entry and token budgets — an over-budget failure means consolidate harder or drop, never truncate by hand.
181
193
  - **On a budget-forced drop, signal saturation once (never silent).** When the writer's budget re-assertion cannot fit the entry even after consolidating harder — a durable capture has to be DROPPED for budget — the ledger is saturated, and that pressure must be visible to an operator instead of swallowed. Emit **exactly one** tracker signal via `lisa-tracker-write` (`issue_type: Task`; GitHub trackers carry the `type:Task` label), then continue — dropping the capture never blocks the build. Follow the same marker-dedupe discipline as every other comment here (match on the **marker, never the title**; **exactly one marker per body**; the eventual-consistency guard when the search index is stale), with **one deliberate difference: dedupe against OPEN signals only.** A *closed* saturation ticket means room was already reclaimed, so a fresh saturation is a new actionable event — searching closed tickets too (as the drop/upstream markers do) would permanently suppress every later saturation.
182
194
 
183
195
  The saturation fingerprint keys on the **ledger, not the candidate**, so the signal fires once per saturation episode — never once per capture:
@@ -197,7 +209,7 @@ No learning content is ever committed without a PR — there is no other write p
197
209
  The overflow is git-tracked and bound to the same union merge driver as the ledger, so **still open the pull request on a budget-forced drop** — carrying the overflow file instead of the ledger. That is the whole point of preserving it: a capture that reaches only a disposable `learning/<fingerprint>` worktree is durable in name only, and the gardener draining `main` would never see it. Never hand-edit the overflow, and never delete an entry from it to make room; the gardener drains it.
198
210
 
199
211
  So a budget-forced drop produces **both** halves and neither substitutes for the other: the `[lisa-ledger-saturated]` ticket (the signal that room must be reclaimed) and a pull request carrying the overflow file (the content itself). Report both in the run summary.
200
- 4. **Branch + commit.** Work on branch `learning/<fingerprint>`. Commit only the learnings surface — the ledger, or the overflow buffer on a budget-forced drop; verify with `git diff --name-only` that the diff touches nothing else.
212
+ 4. **Commit.** In the step-1 worktree, on branch `learning/<fingerprint>`, commit only the learnings surface — the ledger, or the overflow buffer on a budget-forced drop; verify with `git diff --name-only` that the diff touches nothing else.
201
213
  5. **PR body.** Exactly one marker line plus the reviewable story:
202
214
 
203
215
  ```markdown
@@ -216,6 +228,13 @@ No learning content is ever committed without a PR — there is no other write p
216
228
  <"Superseded entry id(s) X, Y: <why they merged>" | "Appended: no related entry exists — <one-line search summary>">
217
229
  ```
218
230
 
231
+ For a **planning-miss** PR, add one section after `## Learning`, so the reviewer sees which stage let the gap through and that the rule is a check rather than the ticket's answer:
232
+
233
+ ```markdown
234
+ ## Planning miss
235
+ Stage: <planning_stage>. The worker could not find: "<quoted>". Planning skills read this rule back through the bounded projection (`lisa-task-decomposition` step 0).
236
+ ```
237
+
219
238
  For a **low-confidence** PR, the body must additionally end with this fixed decision-framing line so the human at the gate knows exactly what merging means:
220
239
 
221
240
  ```markdown
@@ -59,6 +59,8 @@ If no PRD or specification exists, suggest running the `lisa-research` skill fir
59
59
 
60
60
  Execute the **Plan** flow as defined in the `intent-routing` rule (loaded via the lisa plugin). The rule contains the canonical step sequence (gates, sub-flows, output structure). This skill does NOT restate flow steps — change them in the rule, propagate everywhere.
61
61
 
62
+ **Learned planning checks.** Whichever source skill runs the decomposition, it runs `lisa-task-decomposition` step 0 first: the `Planning (prd|decomposition|ready-gate)` checks that `learning-judge` persisted each time a dispatched worker still had to stop for a human or file a ticket mid-build, loaded through the learnings contract's bounded projection. For a file or plain-text spec, run that step yourself before decomposing. Planning that ignores them repeats the gap that stopped the last worker.
63
+
62
64
  ## Output
63
65
 
64
66
  Work items in the configured tracker (JIRA, GitHub Issues, or Linear, per `.lisa.config.json` `tracker`) with acceptance criteria, dependencies, and recommended skills/agents per item. Ordered by dependency. Before finishing, route usage writes through `lisa-usage-accounting`: record the Plan run as a direct entry on the source PRD/spec artifact, attach a plan usage entry (or an explicit `source: unavailable` entry with nullable token/cost fields) to each created work item, and refresh the PRD rollup after `lisa-prd-backlink` regenerates the `## Tickets` child refs. Do not invent plan-specific ledger formats or omit missing usage silently. If the specification cannot be decomposed without further clarification, stop and report what is missing.
@@ -712,6 +712,31 @@ function validateNotify(notify) {
712
712
  ];
713
713
  }
714
714
 
715
+ /**
716
+ * Maps under `sessionManager` whose KEYS are names chosen by the project, not
717
+ * config field names. `repos.entries` is keyed by child repository directory,
718
+ * so a repo called `token-service` or `secrets-manager` is a name, not a
719
+ * credential field; testing it against CREDENTIAL_KEY made `init-config
720
+ * --write` emit a block that `validate` then refused (CodySwannGT/lisa#4564).
721
+ * Their VALUES are still walked, so a token placed inside an entry is caught.
722
+ */
723
+ const NAME_KEYED_MAPS = [["repos", "entries"]];
724
+
725
+ /**
726
+ * Whether a key trail below `sessionManager` is exactly a name-keyed map.
727
+ * Compared segment by segment, never as a dotted string: a literal key
728
+ * `"repos.entries"` would otherwise borrow the exemption.
729
+ * @param {readonly string[]} segments Object keys from the block root.
730
+ * @returns {boolean} True for a map whose keys are names.
731
+ */
732
+ function isNameKeyedMap(segments) {
733
+ return NAME_KEYED_MAPS.some(
734
+ map =>
735
+ map.length === segments.length &&
736
+ map.every((segment, i) => segment === segments[i])
737
+ );
738
+ }
739
+
715
740
  /**
716
741
  * Walk the block for anything that looks like a credential.
717
742
  *
@@ -721,10 +746,12 @@ function validateNotify(notify) {
721
746
  * configured), so a token here is both leaked and unused. The value is never
722
747
  * echoed.
723
748
  * @param {unknown} value Subtree.
724
- * @param {string} path Dotted path so far.
749
+ * @param {string} path Dotted path so far, for messages.
750
+ * @param {readonly string[] | null} [segments] Object keys from the block root;
751
+ * `null` once an array is crossed, since no name-keyed map lives there.
725
752
  * @returns {string[]} Problems found.
726
753
  */
727
- function findCredentials(value, path) {
754
+ function findCredentials(value, path, segments = []) {
728
755
  if (typeof value === "string") {
729
756
  return TOKEN_VALUE.test(value.trim())
730
757
  ? [
@@ -736,18 +763,25 @@ function findCredentials(value, path) {
736
763
  : [];
737
764
  }
738
765
  if (Array.isArray(value)) {
739
- return value.flatMap((item, i) => findCredentials(item, `${path}[${i}]`));
766
+ return value.flatMap((item, i) =>
767
+ findCredentials(item, `${path}[${i}]`, null)
768
+ );
740
769
  }
741
770
  if (!isPlainObject(value)) return [];
771
+ const keysAreNames = segments !== null && isNameKeyedMap(segments);
742
772
  return Object.entries(value).flatMap(([key, child]) =>
743
- CREDENTIAL_KEY.test(key)
773
+ !keysAreNames && CREDENTIAL_KEY.test(key)
744
774
  ? [
745
775
  `${path}.${key} names a credential. Tokens and secrets never go in ` +
746
776
  `config: remove it, and keep the bot token in the project's ` +
747
777
  `secrets provider (session-manager.mjs store-token, run by ` +
748
778
  `/lisa:setup:session-manager).`,
749
779
  ]
750
- : findCredentials(child, `${path}.${key}`)
780
+ : findCredentials(
781
+ child,
782
+ `${path}.${key}`,
783
+ segments === null ? null : [...segments, key]
784
+ )
751
785
  );
752
786
  }
753
787