@mjasnikovs/pi-task 0.38.29 → 0.38.30

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 (370) hide show
  1. package/dist/config/config.d.ts +70 -70
  2. package/dist/config/config.js +26 -35
  3. package/dist/config/extension-list.d.ts +6 -5
  4. package/dist/config/extension-list.js +3 -2
  5. package/dist/config/reasoning-args.d.ts +9 -7
  6. package/dist/config/reasoning-args.js +12 -10
  7. package/dist/config/reasoning.d.ts +44 -105
  8. package/dist/config/reasoning.js +27 -704
  9. package/dist/config/register.d.ts +34 -48
  10. package/dist/config/register.js +41 -51
  11. package/dist/config/tool-list.d.ts +16 -16
  12. package/dist/config/tool-list.js +1 -1
  13. package/dist/remote/bridge.d.ts +19 -10
  14. package/dist/remote/bridge.js +3 -2
  15. package/dist/remote/broadcast.js +3 -1
  16. package/dist/remote/events.js +12 -11
  17. package/dist/remote/history.d.ts +1 -1
  18. package/dist/remote/protocol.d.ts +6 -3
  19. package/dist/remote/protocol.js +2 -1
  20. package/dist/remote/push.d.ts +16 -16
  21. package/dist/remote/push.js +27 -27
  22. package/dist/remote/register.d.ts +3 -3
  23. package/dist/remote/register.js +17 -19
  24. package/dist/remote/server.d.ts +9 -8
  25. package/dist/remote/server.js +15 -14
  26. package/dist/remote/session-state.d.ts +5 -4
  27. package/dist/remote/session-state.js +8 -5
  28. package/dist/remote/sw.d.ts +7 -6
  29. package/dist/remote/sw.js +7 -6
  30. package/dist/remote/tailscale.d.ts +4 -2
  31. package/dist/remote/tailscale.js +4 -2
  32. package/dist/remote/ui-highlight.js +6 -5
  33. package/dist/remote/ui-render.js +4 -4
  34. package/dist/remote/ui-script.js +24 -24
  35. package/dist/remote/ui-styles.d.ts +1 -1
  36. package/dist/remote/ui-styles.js +10 -13
  37. package/dist/remote/ui-tools.js +9 -6
  38. package/dist/shared/child-extensions.d.ts +29 -17
  39. package/dist/shared/child-extensions.js +29 -17
  40. package/dist/shared/child-output.d.ts +30 -24
  41. package/dist/shared/child-output.js +25 -17
  42. package/dist/shared/child-process.d.ts +47 -40
  43. package/dist/shared/child-process.js +50 -59
  44. package/dist/shared/command-watchdog.d.ts +22 -16
  45. package/dist/shared/command-watchdog.js +28 -21
  46. package/dist/shared/fs-text.d.ts +16 -10
  47. package/dist/shared/fs-text.js +16 -10
  48. package/dist/shared/git-runner.d.ts +25 -25
  49. package/dist/shared/git-runner.js +25 -25
  50. package/dist/shared/leaked-tool-call.d.ts +17 -11
  51. package/dist/shared/leaked-tool-call.js +23 -15
  52. package/dist/shared/model-endpoint.d.ts +29 -16
  53. package/dist/shared/model-endpoint.js +33 -21
  54. package/dist/shared/pi-invocation.d.ts +7 -4
  55. package/dist/shared/pi-invocation.js +12 -7
  56. package/dist/shared/pkg-version.d.ts +13 -5
  57. package/dist/shared/pkg-version.js +13 -5
  58. package/dist/shared/reasoning-capability.d.ts +35 -24
  59. package/dist/shared/reasoning-capability.js +35 -24
  60. package/dist/shared/stream-watchdog.d.ts +60 -44
  61. package/dist/shared/stream-watchdog.js +62 -45
  62. package/dist/task/accept-debt.d.ts +41 -43
  63. package/dist/task/accept-debt.js +73 -65
  64. package/dist/task/api-synthesis.d.ts +24 -21
  65. package/dist/task/api-synthesis.js +32 -26
  66. package/dist/task/apis-contract.d.ts +32 -64
  67. package/dist/task/apis-contract.js +32 -64
  68. package/dist/task/artifact-closure.d.ts +27 -13
  69. package/dist/task/artifact-closure.js +95 -67
  70. package/dist/task/auto-commit.d.ts +46 -35
  71. package/dist/task/auto-commit.js +51 -38
  72. package/dist/task/auto-io.d.ts +45 -25
  73. package/dist/task/auto-io.js +57 -29
  74. package/dist/task/auto-orchestrator.d.ts +26 -24
  75. package/dist/task/auto-orchestrator.js +178 -162
  76. package/dist/task/auto-prompts.d.ts +36 -24
  77. package/dist/task/auto-prompts.js +40 -26
  78. package/dist/task/autofix-ledger.d.ts +27 -25
  79. package/dist/task/autofix-ledger.js +29 -26
  80. package/dist/task/batch-test-task.d.ts +20 -12
  81. package/dist/task/batch-test-task.js +67 -60
  82. package/dist/task/boot-probe.d.ts +60 -44
  83. package/dist/task/boot-probe.js +91 -72
  84. package/dist/task/cancel-input.d.ts +30 -16
  85. package/dist/task/cancel-input.js +20 -11
  86. package/dist/task/cancel-points.d.ts +27 -20
  87. package/dist/task/cancel-points.js +30 -22
  88. package/dist/task/child-runner.d.ts +46 -51
  89. package/dist/task/child-runner.js +48 -49
  90. package/dist/task/child-status.d.ts +23 -16
  91. package/dist/task/child-status.js +23 -16
  92. package/dist/task/clamp-output.js +12 -5
  93. package/dist/task/command-run.d.ts +31 -28
  94. package/dist/task/command-run.js +44 -35
  95. package/dist/task/command-shrink.d.ts +25 -18
  96. package/dist/task/command-shrink.js +37 -31
  97. package/dist/task/command-watchdog.d.ts +9 -6
  98. package/dist/task/command-watchdog.js +21 -15
  99. package/dist/task/context-attribution.d.ts +34 -26
  100. package/dist/task/context-attribution.js +34 -26
  101. package/dist/task/context-silence.d.ts +39 -29
  102. package/dist/task/context-silence.js +35 -25
  103. package/dist/task/context-usage.d.ts +16 -9
  104. package/dist/task/context-usage.js +16 -9
  105. package/dist/task/contracts.d.ts +8 -4
  106. package/dist/task/contracts.js +25 -17
  107. package/dist/task/coverage-loop.d.ts +22 -18
  108. package/dist/task/coverage-loop.js +35 -30
  109. package/dist/task/critique-probes.d.ts +13 -14
  110. package/dist/task/critique-probes.js +50 -39
  111. package/dist/task/debug-log.d.ts +13 -5
  112. package/dist/task/debug-log.js +32 -20
  113. package/dist/task/decompose-fidelity.d.ts +11 -9
  114. package/dist/task/decompose-fidelity.js +38 -33
  115. package/dist/task/decompose-granularity.d.ts +41 -38
  116. package/dist/task/decompose-granularity.js +41 -38
  117. package/dist/task/deep-render-check.d.ts +22 -14
  118. package/dist/task/deep-render-check.js +40 -31
  119. package/dist/task/dropped-input.d.ts +12 -7
  120. package/dist/task/dropped-input.js +5 -2
  121. package/dist/task/enforce-attribution.d.ts +38 -47
  122. package/dist/task/enforce-attribution.js +46 -52
  123. package/dist/task/enforce-guidelines.d.ts +31 -20
  124. package/dist/task/enforce-guidelines.js +32 -21
  125. package/dist/task/enrichment.d.ts +7 -2
  126. package/dist/task/enrichment.js +26 -14
  127. package/dist/task/env-notes.d.ts +16 -7
  128. package/dist/task/env-notes.js +48 -31
  129. package/dist/task/env-template-closure.d.ts +4 -4
  130. package/dist/task/env-template-closure.js +42 -34
  131. package/dist/task/external-context.d.ts +28 -21
  132. package/dist/task/external-context.js +17 -12
  133. package/dist/task/failure-classifier.d.ts +4 -5
  134. package/dist/task/failure-classifier.js +6 -7
  135. package/dist/task/file-inventory.d.ts +15 -11
  136. package/dist/task/file-inventory.js +25 -22
  137. package/dist/task/final-gate-fix.d.ts +74 -86
  138. package/dist/task/final-gate-fix.js +97 -116
  139. package/dist/task/final-gate-progress.d.ts +29 -46
  140. package/dist/task/final-gate-progress.js +40 -51
  141. package/dist/task/final-gate.d.ts +64 -97
  142. package/dist/task/final-gate.js +192 -199
  143. package/dist/task/fix-child.d.ts +21 -27
  144. package/dist/task/fix-child.js +21 -27
  145. package/dist/task/foreign-path.d.ts +6 -5
  146. package/dist/task/foreign-path.js +0 -0
  147. package/dist/task/frozen-conflict.d.ts +9 -10
  148. package/dist/task/frozen-conflict.js +61 -64
  149. package/dist/task/frozen-path-guard.d.ts +35 -14
  150. package/dist/task/frozen-path-guard.js +56 -39
  151. package/dist/task/gate-child.d.ts +27 -28
  152. package/dist/task/gate-child.js +36 -35
  153. package/dist/task/gate-deps.d.ts +34 -27
  154. package/dist/task/gate-deps.js +169 -159
  155. package/dist/task/gate-tally.d.ts +77 -80
  156. package/dist/task/gate-tally.js +65 -68
  157. package/dist/task/git-state-guard.d.ts +15 -11
  158. package/dist/task/git-state-guard.js +76 -66
  159. package/dist/task/impl-widget.d.ts +25 -16
  160. package/dist/task/impl-widget.js +27 -17
  161. package/dist/task/implementation-thinking.d.ts +33 -31
  162. package/dist/task/implementation-thinking.js +5 -6
  163. package/dist/task/implementation-turn.d.ts +34 -31
  164. package/dist/task/implementation-turn.js +29 -27
  165. package/dist/task/inline-markdown.d.ts +20 -7
  166. package/dist/task/inline-markdown.js +15 -6
  167. package/dist/task/launch-config-gap.js +25 -39
  168. package/dist/task/launch-contract.d.ts +18 -21
  169. package/dist/task/launch-contract.js +28 -30
  170. package/dist/task/launch-manifest.d.ts +6 -2
  171. package/dist/task/launch-manifest.js +35 -34
  172. package/dist/task/ledger.js +16 -14
  173. package/dist/task/lint-fix.d.ts +6 -8
  174. package/dist/task/lint-fix.js +67 -69
  175. package/dist/task/loop-detector.d.ts +9 -8
  176. package/dist/task/loop-detector.js +16 -12
  177. package/dist/task/mid-run-input.d.ts +17 -15
  178. package/dist/task/mid-run-input.js +17 -15
  179. package/dist/task/orchestrator.d.ts +24 -28
  180. package/dist/task/orchestrator.js +62 -64
  181. package/dist/task/orientation.d.ts +18 -23
  182. package/dist/task/orientation.js +24 -31
  183. package/dist/task/owned-freeze-conflict.d.ts +21 -20
  184. package/dist/task/owned-freeze-conflict.js +52 -85
  185. package/dist/task/owned-freeze-reassign.d.ts +40 -60
  186. package/dist/task/owned-freeze-reassign.js +41 -61
  187. package/dist/task/parsers.d.ts +4 -2
  188. package/dist/task/parsers.js +4 -4
  189. package/dist/task/phases.d.ts +41 -48
  190. package/dist/task/phases.js +179 -248
  191. package/dist/task/plan-io.d.ts +6 -7
  192. package/dist/task/plan-io.js +6 -7
  193. package/dist/task/plan-orchestrator.d.ts +10 -8
  194. package/dist/task/plan-orchestrator.js +14 -10
  195. package/dist/task/plan-prompts.d.ts +6 -5
  196. package/dist/task/plan-prompts.js +6 -5
  197. package/dist/task/plan-readonly.d.ts +4 -5
  198. package/dist/task/plan-readonly.js +4 -5
  199. package/dist/task/plan-rounds.d.ts +17 -29
  200. package/dist/task/plan-rounds.js +21 -34
  201. package/dist/task/plan-session.d.ts +58 -72
  202. package/dist/task/plan-session.js +61 -83
  203. package/dist/task/probe-gaming.d.ts +28 -27
  204. package/dist/task/probe-gaming.js +0 -0
  205. package/dist/task/prohibition-probe.d.ts +14 -16
  206. package/dist/task/prompts.d.ts +3 -4
  207. package/dist/task/prompts.js +17 -26
  208. package/dist/task/qa-transcript.d.ts +15 -22
  209. package/dist/task/qa-transcript.js +15 -21
  210. package/dist/task/question-box.d.ts +17 -13
  211. package/dist/task/question-box.js +19 -15
  212. package/dist/task/question-dedup.d.ts +6 -7
  213. package/dist/task/question-dedup.js +13 -14
  214. package/dist/task/question-dialog.d.ts +22 -32
  215. package/dist/task/question-dialog.js +22 -32
  216. package/dist/task/question-source.d.ts +18 -44
  217. package/dist/task/question-source.js +22 -51
  218. package/dist/task/refuted-constraint.d.ts +11 -31
  219. package/dist/task/refuted-constraint.js +27 -51
  220. package/dist/task/regenerable-artifacts.d.ts +12 -31
  221. package/dist/task/regenerable-artifacts.js +12 -31
  222. package/dist/task/render-check.d.ts +11 -22
  223. package/dist/task/render-check.js +33 -46
  224. package/dist/task/repo-health-check.d.ts +10 -14
  225. package/dist/task/repo-health-check.js +17 -23
  226. package/dist/task/requirements.d.ts +38 -71
  227. package/dist/task/requirements.js +78 -126
  228. package/dist/task/research-fanout-budget.d.ts +51 -88
  229. package/dist/task/research-fanout-budget.js +51 -88
  230. package/dist/task/research-worker.d.ts +29 -39
  231. package/dist/task/research-worker.js +37 -61
  232. package/dist/task/resume-gap.d.ts +14 -15
  233. package/dist/task/root-cause-repair.d.ts +9 -9
  234. package/dist/task/root-cause-repair.js +28 -40
  235. package/dist/task/run-bracket.d.ts +10 -13
  236. package/dist/task/run-end.d.ts +12 -22
  237. package/dist/task/run-end.js +8 -16
  238. package/dist/task/run-final-gate.d.ts +19 -21
  239. package/dist/task/run-final-gate.js +62 -80
  240. package/dist/task/runner-globs.d.ts +12 -13
  241. package/dist/task/runner-globs.js +12 -13
  242. package/dist/task/runner-resolve.d.ts +9 -9
  243. package/dist/task/runner-resolve.js +22 -23
  244. package/dist/task/script-escape.d.ts +10 -12
  245. package/dist/task/script-escape.js +13 -14
  246. package/dist/task/serve-entry.d.ts +1 -1
  247. package/dist/task/serve-entry.js +22 -25
  248. package/dist/task/service-blocks.js +4 -2
  249. package/dist/task/shipped-source.d.ts +11 -29
  250. package/dist/task/shipped-source.js +11 -29
  251. package/dist/task/skip-escape.js +10 -14
  252. package/dist/task/spec-urls.d.ts +26 -65
  253. package/dist/task/spec-urls.js +26 -65
  254. package/dist/task/spec-validation.d.ts +17 -20
  255. package/dist/task/spec-validation.js +17 -20
  256. package/dist/task/stall-detector.d.ts +23 -30
  257. package/dist/task/stall-detector.js +23 -30
  258. package/dist/task/stream-watchdog.d.ts +14 -12
  259. package/dist/task/stream-watchdog.js +14 -12
  260. package/dist/task/substitution-probe.d.ts +17 -20
  261. package/dist/task/substitution-probe.js +17 -20
  262. package/dist/task/task-gates.d.ts +36 -41
  263. package/dist/task/task-gates.js +95 -106
  264. package/dist/task/task-io.d.ts +4 -4
  265. package/dist/task/task-io.js +4 -4
  266. package/dist/task/task-parsers.js +4 -3
  267. package/dist/task/task-provenance.d.ts +2 -2
  268. package/dist/task/task-provenance.js +11 -13
  269. package/dist/task/task-types.d.ts +4 -3
  270. package/dist/task/terminal-outcome.d.ts +14 -16
  271. package/dist/task/terminal-outcome.js +12 -14
  272. package/dist/task/test-assembly.d.ts +13 -20
  273. package/dist/task/test-assembly.js +13 -20
  274. package/dist/task/timings.d.ts +5 -3
  275. package/dist/task/timings.js +5 -3
  276. package/dist/task/title-label.d.ts +9 -4
  277. package/dist/task/title-label.js +9 -4
  278. package/dist/task/type-only-answer.d.ts +44 -52
  279. package/dist/task/type-only-answer.js +44 -52
  280. package/dist/task/unfailable-command.d.ts +18 -24
  281. package/dist/task/unfailable-command.js +21 -27
  282. package/dist/task/unknown-routing.d.ts +10 -4
  283. package/dist/task/unknown-routing.js +10 -4
  284. package/dist/task/user-directives.d.ts +5 -8
  285. package/dist/task/user-directives.js +5 -8
  286. package/dist/task/verify-quality.d.ts +18 -22
  287. package/dist/task/verify-quality.js +45 -46
  288. package/dist/task/verify-reconcile.d.ts +15 -10
  289. package/dist/task/verify-reconcile.js +45 -43
  290. package/dist/task/verify-resolution.d.ts +24 -20
  291. package/dist/task/verify-resolution.js +51 -50
  292. package/dist/task/verify-work.d.ts +59 -66
  293. package/dist/task/verify-work.js +101 -138
  294. package/dist/task/widget.d.ts +15 -14
  295. package/dist/task/widget.js +22 -17
  296. package/dist/task/wiring-claims.d.ts +25 -32
  297. package/dist/task/wiring-claims.js +30 -35
  298. package/dist/task/write-guard.d.ts +39 -39
  299. package/dist/task/write-guard.js +48 -51
  300. package/dist/task/yolo.d.ts +34 -30
  301. package/dist/task/yolo.js +42 -37
  302. package/dist/workers/abstention.d.ts +21 -41
  303. package/dist/workers/abstention.js +27 -48
  304. package/dist/workers/brave-search.d.ts +4 -3
  305. package/dist/workers/brave-search.js +5 -2
  306. package/dist/workers/brave-warning.d.ts +7 -4
  307. package/dist/workers/brave-warning.js +19 -7
  308. package/dist/workers/ddg-search.d.ts +6 -6
  309. package/dist/workers/ddg-search.js +18 -12
  310. package/dist/workers/docs-cache.js +5 -2
  311. package/dist/workers/docs-chunk.d.ts +30 -37
  312. package/dist/workers/docs-chunk.js +37 -41
  313. package/dist/workers/docs-core.d.ts +28 -44
  314. package/dist/workers/docs-core.js +25 -44
  315. package/dist/workers/docs-index.js +4 -3
  316. package/dist/workers/docs-lookup.d.ts +15 -22
  317. package/dist/workers/docs-lookup.js +12 -21
  318. package/dist/workers/docs-project.d.ts +15 -9
  319. package/dist/workers/docs-project.js +17 -10
  320. package/dist/workers/docs-resolve.d.ts +19 -20
  321. package/dist/workers/docs-resolve.js +35 -32
  322. package/dist/workers/docs-retrieve.d.ts +5 -6
  323. package/dist/workers/docs-retrieve.js +18 -15
  324. package/dist/workers/exa-search.d.ts +9 -6
  325. package/dist/workers/exa-search.js +23 -12
  326. package/dist/workers/fetch-core.d.ts +13 -16
  327. package/dist/workers/fetch-core.js +23 -23
  328. package/dist/workers/focused-extractor.d.ts +12 -12
  329. package/dist/workers/focused-extractor.js +16 -19
  330. package/dist/workers/html-clean.js +24 -14
  331. package/dist/workers/http-request.d.ts +28 -20
  332. package/dist/workers/http-request.js +22 -17
  333. package/dist/workers/npm-version.d.ts +28 -11
  334. package/dist/workers/npm-version.js +24 -15
  335. package/dist/workers/phantom-imports.d.ts +15 -12
  336. package/dist/workers/phantom-imports.js +30 -24
  337. package/dist/workers/pi-worker-core.d.ts +69 -71
  338. package/dist/workers/pi-worker-core.js +100 -109
  339. package/dist/workers/pi-worker-docs.d.ts +24 -19
  340. package/dist/workers/pi-worker-docs.js +67 -76
  341. package/dist/workers/pi-worker-fetch.d.ts +7 -3
  342. package/dist/workers/pi-worker-fetch.js +27 -19
  343. package/dist/workers/pi-worker-search.js +12 -8
  344. package/dist/workers/pi-worker.d.ts +9 -4
  345. package/dist/workers/pi-worker.js +21 -14
  346. package/dist/workers/reasoning-warning.d.ts +18 -17
  347. package/dist/workers/reasoning-warning.js +22 -20
  348. package/dist/workers/research-cache.js +50 -78
  349. package/dist/workers/search-core.js +7 -5
  350. package/dist/workers/search-types.d.ts +10 -9
  351. package/dist/workers/search-types.js +9 -8
  352. package/dist/workers/session-hint.d.ts +13 -14
  353. package/dist/workers/session-hint.js +8 -9
  354. package/dist/workers/shared.d.ts +21 -25
  355. package/dist/workers/shared.js +0 -0
  356. package/dist/workers/single-read-extension.d.ts +14 -7
  357. package/dist/workers/single-read-extension.js +14 -7
  358. package/dist/workers/single-read-guard.d.ts +25 -28
  359. package/dist/workers/single-read-guard.js +32 -32
  360. package/dist/workers/typeonly-log.d.ts +12 -9
  361. package/dist/workers/typeonly-log.js +29 -33
  362. package/dist/workers/worker-channels.d.ts +15 -23
  363. package/dist/workers/worker-channels.js +15 -23
  364. package/dist/workers/worker-failure.d.ts +38 -46
  365. package/dist/workers/worker-failure.js +31 -39
  366. package/dist/workers/worker-kill.d.ts +25 -26
  367. package/dist/workers/worker-kill.js +16 -19
  368. package/dist/workers/worker-profiles.d.ts +43 -53
  369. package/dist/workers/worker-profiles.js +30 -38
  370. package/package.json +10 -8
@@ -1,69 +1,60 @@
1
1
  /**
2
2
  * enforce-attribution — decide whether an enforce-pass re-verify FAIL can possibly
3
- * be the ENFORCE COMMIT's fault (mx5 run 18, nexttask 4).
3
+ * be the ENFORCE COMMIT's fault.
4
4
  *
5
- * The failure class, measured. Run 18's TASK_0024 enforce commit `ee65661` was, in
6
- * full, one line:
5
+ * THE FAILURE CLASS. An enforce commit can be one line:
7
6
  *
8
7
  * - setApiError((usersData).error ?? 'Failed to load users')
9
8
  * + setApiError(usersData.error ?? 'Failed to load users')
10
9
  *
11
- * The differential re-verify then FAILed on `MyListings.spec.tsx:186`, a Playwright
12
- * CT file `Admin.tsx` cannot reach (CT bundles per story; the import graph never
13
- * touches it), and the differential reverted the enforce commit anyway. The defect
14
- * was real and PRE-EXISTING `getByText('SOLD')` matched two elements because
15
- * MOCK_LISTINGS already carries a sold row and the final gate fixed it five
16
- * minutes later, in the same commit that RE-MADE the identical paren change. Cost:
17
- * one correct change destroyed, one permanent false verify-FAIL debt written
18
- * against work that was fine, and the change re-made anyway.
10
+ * and the differential re-verify can still FAIL — on a test in a file that change
11
+ * cannot reach, because the runner bundles per story and the import graph never
12
+ * touches it. The differential reverts the enforce commit anyway. The defect was
13
+ * real and PRE-EXISTING, a later pass fixes it and re-makes the identical change,
14
+ * and the cost is one correct edit destroyed plus a false verify-FAIL debt written
15
+ * against work that was fine.
19
16
  *
20
- * The mechanism was not broken; it was asked the wrong question. The root-cause
21
- * channel (root-cause-repair.ts) attributed against `scope: 'committed'` — the
22
- * TASK's own commit, which touched `MyListings.tsx` concluded "this task touched
23
- * the file", and fell through to the conservative revert. But at THIS seam the
24
- * differential is deciding whether to discard the ENFORCE COMMIT. The causal
25
- * question is therefore *"could the enforce diff have caused this?"*, never *"could
26
- * the task have?"*: reverting the enforce commit can only ever repair damage the
27
- * enforce commit did.
17
+ * The mechanism is not broken; it is asked the wrong question. The root-cause
18
+ * channel (root-cause-repair.ts) attributes against `scope: 'committed'` — the
19
+ * TASK's own commit — concludes "this task touched the file", and falls through to
20
+ * the conservative revert. But at THIS seam the differential is deciding whether to
21
+ * discard the ENFORCE COMMIT. The causal question is therefore *"could the enforce
22
+ * diff have caused this?"*, never *"could the task have?"*: reverting the enforce
23
+ * commit can only ever repair damage the enforce commit did.
28
24
  *
29
25
  * So the filter here is mechanical and one-sided:
30
26
  *
31
- * - the files the FAIL text NAMES are extracted (paths AND bare basenames — run
32
- * 18's reason named `MyListings.spec.tsx:186`, which carries no separator and
33
- * is invisible to root-cause-repair.ts's path-token regex, a second reason
34
- * that incident could not be attributed);
27
+ * - the files the FAIL text NAMES are extracted, paths AND bare basenames. This
28
+ * is not belt-and-braces: run against root-cause-repair.ts's own
29
+ * `PATH_TOKEN_RE`, a reason naming `MyListings.spec.tsx:186` matches NOTHING,
30
+ * because that pattern needs a `/`. Basenames are not optional here;
35
31
  * - each is compared against the enforce commit's own file set, by path suffix
36
32
  * and by RELATED STEM (`Admin.tsx` ~ `Admin.spec.tsx` ~ `Admin.stories.tsx`),
37
33
  * so a regression in a touched file's own test still counts as overlap;
38
34
  * - DISJOINT ⇒ keep the edits and route the defect. Anything else — an unknown
39
- * enforce diff, a FAIL text naming no file at all, any overlap — reverts,
40
- * which is exactly the pre-existing behaviour. Never keep on ignorance.
35
+ * or empty enforce diff, a FAIL text naming no file at all, any overlap —
36
+ * reverts. Never keep on ignorance.
41
37
  *
42
- * Keeping the edits must not mean losing the finding: the caller still records the
43
- * debt and still queues the repair. Losing the finding was mx5 run 5's mistake.
38
+ * Run across every branch: a disjoint reason KEEPs and names the file to blame;
39
+ * an overlap by path and an overlap by related stem (`Admin.spec.tsx` against a
40
+ * touched `src/client/pages/Admin.tsx`) both REVERT with the overlap recorded;
41
+ * and a reason naming no file, a null enforce diff and an empty one all REVERT.
42
+ * Exactly one branch keeps, and it requires positive evidence.
44
43
  *
45
- * MEASURED COVERAGE, and it is the honest weakness of this filter. Live, 40 trials
46
- * against the run-18 tree with a real verify child
47
- * (`scripts/live-enforce-attribution-ab.ts`):
44
+ * Keeping the edits must not mean losing the finding: the caller still records the
45
+ * debt and still queues the repair.
48
46
  *
49
- * reachable arm (the enforce edit itself breaks `Admin.tsx`, ground truth REVERT)
50
- * 20/20 FAILs named a resolvable file, 20/20 decided correctlytsc prints the
51
- * path, so the regression case is fully covered.
52
- * disjoint arm (a deterministic failure in `MyListings.spec.tsx`, ground truth KEEP)
53
- * only 9/20 FAILs named a file at all. The other 11 named the UNIT — "The
54
- * MyListings component test \"edit link navigates…\" fails … expects 4 Edit links"
55
- * — with no path and no `.tsx` anywhere. Those 11 fall through to the revert.
47
+ * THE HONEST WEAKNESS. This only fires when the FAIL text names a file. A type
48
+ * error does the compiler prints the pathbut a failing unit test often names
49
+ * the UNIT instead ("The MyListings component test fails"), with no path and no
50
+ * extension anywhere. Confirmed: that reason extracts nothing and REVERTs with
51
+ * `no-file-named`, which is exactly the behaviour that shipped before this filter
52
+ * existed.
56
53
  *
57
- * So this fires on roughly half of live disjoint failures and on the recorded run-18
58
- * verdict (which did name `MyListings.spec.tsx:186`), and it was NEVER wrong: 29 of
59
- * 29 extractable decisions matched ground truth across both arms. The arm-level
60
- * verdict is still FAIL against the pre-registered ≥80%-extractable bar, and the
61
- * shipped rule is deliberately the conservative half of that trade: a miss costs
62
- * exactly the behaviour that shipped before, while a false KEEP would ship a real
63
- * regression. A stem-widened extractor (accept a bare identifier matching a tracked
64
- * file's stem) reaches 40/40 with 0 errors in the same data and is NOT wired — see
65
- * VALIDATION-DEBT.md, it resolves prose nouns to files and its FP mode was never
66
- * exercised.
54
+ * That is the deliberate half of the trade: a miss changes nothing, while a false
55
+ * KEEP would ship a real regression. Widening the extractor to accept a bare
56
+ * identifier matching a tracked file's stem would catch more, and is NOT wired: it
57
+ * resolves prose nouns to files, and its false-positive mode is unexercised.
67
58
  */
68
59
  /**
69
60
  * The comparable stem of a file name: the base name with its extension and any
@@ -1,84 +1,78 @@
1
1
  /**
2
2
  * enforce-attribution — decide whether an enforce-pass re-verify FAIL can possibly
3
- * be the ENFORCE COMMIT's fault (mx5 run 18, nexttask 4).
3
+ * be the ENFORCE COMMIT's fault.
4
4
  *
5
- * The failure class, measured. Run 18's TASK_0024 enforce commit `ee65661` was, in
6
- * full, one line:
5
+ * THE FAILURE CLASS. An enforce commit can be one line:
7
6
  *
8
7
  * - setApiError((usersData).error ?? 'Failed to load users')
9
8
  * + setApiError(usersData.error ?? 'Failed to load users')
10
9
  *
11
- * The differential re-verify then FAILed on `MyListings.spec.tsx:186`, a Playwright
12
- * CT file `Admin.tsx` cannot reach (CT bundles per story; the import graph never
13
- * touches it), and the differential reverted the enforce commit anyway. The defect
14
- * was real and PRE-EXISTING `getByText('SOLD')` matched two elements because
15
- * MOCK_LISTINGS already carries a sold row and the final gate fixed it five
16
- * minutes later, in the same commit that RE-MADE the identical paren change. Cost:
17
- * one correct change destroyed, one permanent false verify-FAIL debt written
18
- * against work that was fine, and the change re-made anyway.
10
+ * and the differential re-verify can still FAIL — on a test in a file that change
11
+ * cannot reach, because the runner bundles per story and the import graph never
12
+ * touches it. The differential reverts the enforce commit anyway. The defect was
13
+ * real and PRE-EXISTING, a later pass fixes it and re-makes the identical change,
14
+ * and the cost is one correct edit destroyed plus a false verify-FAIL debt written
15
+ * against work that was fine.
19
16
  *
20
- * The mechanism was not broken; it was asked the wrong question. The root-cause
21
- * channel (root-cause-repair.ts) attributed against `scope: 'committed'` — the
22
- * TASK's own commit, which touched `MyListings.tsx` concluded "this task touched
23
- * the file", and fell through to the conservative revert. But at THIS seam the
24
- * differential is deciding whether to discard the ENFORCE COMMIT. The causal
25
- * question is therefore *"could the enforce diff have caused this?"*, never *"could
26
- * the task have?"*: reverting the enforce commit can only ever repair damage the
27
- * enforce commit did.
17
+ * The mechanism is not broken; it is asked the wrong question. The root-cause
18
+ * channel (root-cause-repair.ts) attributes against `scope: 'committed'` — the
19
+ * TASK's own commit — concludes "this task touched the file", and falls through to
20
+ * the conservative revert. But at THIS seam the differential is deciding whether to
21
+ * discard the ENFORCE COMMIT. The causal question is therefore *"could the enforce
22
+ * diff have caused this?"*, never *"could the task have?"*: reverting the enforce
23
+ * commit can only ever repair damage the enforce commit did.
28
24
  *
29
25
  * So the filter here is mechanical and one-sided:
30
26
  *
31
- * - the files the FAIL text NAMES are extracted (paths AND bare basenames — run
32
- * 18's reason named `MyListings.spec.tsx:186`, which carries no separator and
33
- * is invisible to root-cause-repair.ts's path-token regex, a second reason
34
- * that incident could not be attributed);
27
+ * - the files the FAIL text NAMES are extracted, paths AND bare basenames. This
28
+ * is not belt-and-braces: run against root-cause-repair.ts's own
29
+ * `PATH_TOKEN_RE`, a reason naming `MyListings.spec.tsx:186` matches NOTHING,
30
+ * because that pattern needs a `/`. Basenames are not optional here;
35
31
  * - each is compared against the enforce commit's own file set, by path suffix
36
32
  * and by RELATED STEM (`Admin.tsx` ~ `Admin.spec.tsx` ~ `Admin.stories.tsx`),
37
33
  * so a regression in a touched file's own test still counts as overlap;
38
34
  * - DISJOINT ⇒ keep the edits and route the defect. Anything else — an unknown
39
- * enforce diff, a FAIL text naming no file at all, any overlap — reverts,
40
- * which is exactly the pre-existing behaviour. Never keep on ignorance.
35
+ * or empty enforce diff, a FAIL text naming no file at all, any overlap —
36
+ * reverts. Never keep on ignorance.
41
37
  *
42
- * Keeping the edits must not mean losing the finding: the caller still records the
43
- * debt and still queues the repair. Losing the finding was mx5 run 5's mistake.
38
+ * Run across every branch: a disjoint reason KEEPs and names the file to blame;
39
+ * an overlap by path and an overlap by related stem (`Admin.spec.tsx` against a
40
+ * touched `src/client/pages/Admin.tsx`) both REVERT with the overlap recorded;
41
+ * and a reason naming no file, a null enforce diff and an empty one all REVERT.
42
+ * Exactly one branch keeps, and it requires positive evidence.
44
43
  *
45
- * MEASURED COVERAGE, and it is the honest weakness of this filter. Live, 40 trials
46
- * against the run-18 tree with a real verify child
47
- * (`scripts/live-enforce-attribution-ab.ts`):
44
+ * Keeping the edits must not mean losing the finding: the caller still records the
45
+ * debt and still queues the repair.
48
46
  *
49
- * reachable arm (the enforce edit itself breaks `Admin.tsx`, ground truth REVERT)
50
- * 20/20 FAILs named a resolvable file, 20/20 decided correctlytsc prints the
51
- * path, so the regression case is fully covered.
52
- * disjoint arm (a deterministic failure in `MyListings.spec.tsx`, ground truth KEEP)
53
- * only 9/20 FAILs named a file at all. The other 11 named the UNIT — "The
54
- * MyListings component test \"edit link navigates…\" fails … expects 4 Edit links"
55
- * — with no path and no `.tsx` anywhere. Those 11 fall through to the revert.
47
+ * THE HONEST WEAKNESS. This only fires when the FAIL text names a file. A type
48
+ * error does the compiler prints the pathbut a failing unit test often names
49
+ * the UNIT instead ("The MyListings component test fails"), with no path and no
50
+ * extension anywhere. Confirmed: that reason extracts nothing and REVERTs with
51
+ * `no-file-named`, which is exactly the behaviour that shipped before this filter
52
+ * existed.
56
53
  *
57
- * So this fires on roughly half of live disjoint failures and on the recorded run-18
58
- * verdict (which did name `MyListings.spec.tsx:186`), and it was NEVER wrong: 29 of
59
- * 29 extractable decisions matched ground truth across both arms. The arm-level
60
- * verdict is still FAIL against the pre-registered ≥80%-extractable bar, and the
61
- * shipped rule is deliberately the conservative half of that trade: a miss costs
62
- * exactly the behaviour that shipped before, while a false KEEP would ship a real
63
- * regression. A stem-widened extractor (accept a bare identifier matching a tracked
64
- * file's stem) reaches 40/40 with 0 errors in the same data and is NOT wired — see
65
- * VALIDATION-DEBT.md, it resolves prose nouns to files and its FP mode was never
66
- * exercised.
54
+ * That is the deliberate half of the trade: a miss changes nothing, while a false
55
+ * KEEP would ship a real regression. Widening the extractor to accept a bare
56
+ * identifier matching a tracked file's stem would catch more, and is NOT wired: it
57
+ * resolves prose nouns to files, and its false-positive mode is unexercised.
67
58
  */
68
59
  /** A path-like token: at least one separator, ending in a file name. */
69
60
  const PATH_TOKEN_RE = /(?:[\w.@~-]+\/)+[\w.@-]+\.\w+/g;
70
61
  /**
71
- * A bare file name with a code-ish extension. Deliberately extension-gated: an
72
- * ungated `\w+\.\w+` matches prose ("e.g.", "v1.2"), object access (`usersData.error`
73
- * which run 18's own enforce diff contains) and assertion chains
74
- * (`toBeVisible()`), and every one of those would be a phantom "named file".
62
+ * A bare file name with a code-ish extension. Deliberately extension-gated, and
63
+ * the gate does real work: run against an ungated `\w+\.\w+`, the prose "e.g.", a
64
+ * version "v1.2", the object access `usersData.error` and method chains like
65
+ * `page.locator` or `cy.get` ALL match, and every one would be a phantom "named
66
+ * file". Through this pattern none of them extract anything, while
67
+ * `MyListings.spec.tsx:186` and `src/server/routes/photos.ts` both do.
75
68
  */
76
69
  const BARE_FILE_RE = /\b[\w@-]+(?:\.[\w@-]+)*\.(?:tsx?|jsx?|mtsx?|ctsx?|mjs|cjs|vue|svelte|astro|py|go|rs|rb|java|kt|kts|cs|php|swift|scala|c|h|cc|cpp|hpp|css|scss|sass|less|html?|json|jsonc|ya?ml|toml|sql|sh|bash|zsh|md|mdx|prisma|graphql|gql|proto|lock)\b/g;
77
70
  /** Line/column suffixes and decoration a reason wraps a file name in. */
78
71
  const TRAILING_POSITION_RE = /:(\d+)(?::(\d+))?$/;
79
72
  /** Suffixes that make a file a sibling of another (test/story/type companions). */
80
73
  const COMPANION_SUFFIXES = ['.spec', '.test', '.stories', '.story', '.d', '.min'];
81
- /** A pathological reason cannot make this scan unbounded. */
74
+ /** A pathological reason cannot make this scan unbounded — 60 names in yields 24
75
+ * out. */
82
76
  const MAX_NAMED = 24;
83
77
  /** Strip `./`, leading slashes and surrounding whitespace. */
84
78
  function normalisePath(p) {
@@ -6,20 +6,25 @@ export declare const GUIDELINE_FILENAMES: readonly ["AGENTS.md", "CLAUDE.md"];
6
6
  * The fix pass gets exactly two tools: `read` and `edit`. Deliberately no
7
7
  * `write`, `grep`, `find`, or `ls`.
8
8
  *
9
- * - No `write` (and `edit` ENOENTs on a missing path) the pass cannot create
10
- * new files. Without this the local model, unable to run lint/tsc/tests, wrote
11
- * hundreds of scratch "runner" scripts hoping to execute them 864 junk files
12
- * in one real run (see enforce-debug.log analysis). This is the load-bearing
13
- * removal: dropping `write` is what stops the runaway file creation.
9
+ * - No `write`, and `edit` cannot substitute for it: pi's edit tool calls
10
+ * `access(absolutePath)` FIRST and throws `Could not edit file: <path>. Error
11
+ * code: ENOENT.` before it ever reads. So the pass cannot create a new file at
12
+ * all. This is the load-bearing removal — a model that cannot run lint, tsc or
13
+ * tests will otherwise write scratch "runner" scripts by the hundred hoping to
14
+ * execute them, and dropping `write` is what stops that.
14
15
  * - No `grep`/`find`/`ls` → the pass cannot enumerate or roam the tree; it is
15
16
  * handed the explicit, closed list of changed files (see captureCommitDiff) and is
16
17
  * told to edit only those.
17
18
  * - `read` IS allowed: the model genuinely needs it — to re-read a file after
18
19
  * editing to confirm the fix landed, and to read a neighbouring file for the
19
- * correct import/type when bringing the change into compliance (without it the
20
- * model fabricates imports — validated against the local model). `read` has no
21
- * per-path sandbox in pi, so "only the changed files" is enforced for EDITS
22
- * (the prompt scopes them) but is a soft instruction for READS.
20
+ * correct import or type when bringing the change into compliance. Denied that,
21
+ * it fabricates imports instead.
22
+ *
23
+ * But `read` has NO per-path sandbox in pi. Its resolver only joins the path to
24
+ * cwd and tries filename variants — checked, `/etc/hostname` resolves to
25
+ * `/etc/hostname` and `../../../` escapes upward, with no confinement test
26
+ * anywhere. So "only the changed files" is ENFORCED for edits, by the closed
27
+ * file list the prompt scopes them to, and is a soft instruction for reads.
23
28
  */
24
29
  declare const ENFORCE_TOOLS = "read,edit";
25
30
  /**
@@ -27,13 +32,15 @@ declare const ENFORCE_TOOLS = "read,edit";
27
32
  * files and report violations but CANNOT edit, create, or run anything.
28
33
  *
29
34
  * This is the "no signal ⇒ no license to rewrite logic" half of the gate. When a
30
- * task ships no behavioral verification to guard a destructive edit (no runnable
31
- * VERIFY, or the verify gate did not produce a genuine clean pass), letting the
32
- * weak model rewrite working code is exactly what trashes the build A/B-proven:
33
- * with `read,edit` and no guard the model degraded a clean tree in 4/5 runs while
34
- * declaring CLEAN. Demoted to `read`, it cannot trash anything (5/5 clean) and
35
- * still names the real violation (5/5). So with no signal to revert against, the
36
- * pass reports the violation as a warning instead of editing.
35
+ * task ships no behavioural verification to guard a destructive edit no runnable
36
+ * VERIFY, or a verify gate that never produced a genuine clean pass there is
37
+ * nothing to revert against if the fix pass makes things worse. A weak model handed
38
+ * `read,edit` in that state can degrade a working tree and still report CLEAN,
39
+ * because nothing is able to contradict it.
40
+ *
41
+ * Demoted to `read` alone it cannot change anything, and still names the real
42
+ * violation. So with no signal to check against, the pass reports the violation as
43
+ * a warning instead of editing.
37
44
  */
38
45
  declare const ENFORCE_FLAG_TOOLS = "read";
39
46
  export interface GuidelineDoc {
@@ -52,9 +59,13 @@ export interface EnforceOutcome {
52
59
  reason?: string;
53
60
  }
54
61
  /**
55
- * Read the guideline files that live directly in `cwd` (AGENTS.md, CLAUDE.md).
56
- * Returns null when none exist or all are empty — the caller treats that as a
57
- * pass. cwd-only by design: no walk up to the git root.
62
+ * Read the guideline files that live directly in `cwd` (AGENTS.md, CLAUDE.md),
63
+ * concatenated under a `## <name>` header each, in that order.
64
+ *
65
+ * Returns null when none exist OR all are empty — the caller treats either as a
66
+ * pass. cwd-only by design, with no walk up to the git root: run from a
67
+ * subdirectory holding only its own AGENTS.md, a CLAUDE.md one level up is not
68
+ * picked up.
58
69
  */
59
70
  export declare function discoverGuidelines(cwd: string, readFile?: (p: string) => Promise<string>): Promise<GuidelineDoc | null>;
60
71
  /**
@@ -143,7 +154,7 @@ export interface EnforcementDeps {
143
154
  * - `'edit'` (default): `read,edit` — the model fixes violations in place. The
144
155
  * caller is responsible for guarding those edits with a differential
145
156
  * verification check (revert on regression), because a bare edit pass
146
- * trashes working code (A/B: 4/5).
157
+ * trashes working code.
147
158
  * - `'flag'`: `read` only — the model reports violations but cannot touch the
148
159
  * tree. Used when there is no verification signal to guard an edit against.
149
160
  */
@@ -34,20 +34,25 @@ export const GUIDELINE_FILENAMES = ['AGENTS.md', 'CLAUDE.md'];
34
34
  * The fix pass gets exactly two tools: `read` and `edit`. Deliberately no
35
35
  * `write`, `grep`, `find`, or `ls`.
36
36
  *
37
- * - No `write` (and `edit` ENOENTs on a missing path) the pass cannot create
38
- * new files. Without this the local model, unable to run lint/tsc/tests, wrote
39
- * hundreds of scratch "runner" scripts hoping to execute them 864 junk files
40
- * in one real run (see enforce-debug.log analysis). This is the load-bearing
41
- * removal: dropping `write` is what stops the runaway file creation.
37
+ * - No `write`, and `edit` cannot substitute for it: pi's edit tool calls
38
+ * `access(absolutePath)` FIRST and throws `Could not edit file: <path>. Error
39
+ * code: ENOENT.` before it ever reads. So the pass cannot create a new file at
40
+ * all. This is the load-bearing removal — a model that cannot run lint, tsc or
41
+ * tests will otherwise write scratch "runner" scripts by the hundred hoping to
42
+ * execute them, and dropping `write` is what stops that.
42
43
  * - No `grep`/`find`/`ls` → the pass cannot enumerate or roam the tree; it is
43
44
  * handed the explicit, closed list of changed files (see captureCommitDiff) and is
44
45
  * told to edit only those.
45
46
  * - `read` IS allowed: the model genuinely needs it — to re-read a file after
46
47
  * editing to confirm the fix landed, and to read a neighbouring file for the
47
- * correct import/type when bringing the change into compliance (without it the
48
- * model fabricates imports — validated against the local model). `read` has no
49
- * per-path sandbox in pi, so "only the changed files" is enforced for EDITS
50
- * (the prompt scopes them) but is a soft instruction for READS.
48
+ * correct import or type when bringing the change into compliance. Denied that,
49
+ * it fabricates imports instead.
50
+ *
51
+ * But `read` has NO per-path sandbox in pi. Its resolver only joins the path to
52
+ * cwd and tries filename variants — checked, `/etc/hostname` resolves to
53
+ * `/etc/hostname` and `../../../` escapes upward, with no confinement test
54
+ * anywhere. So "only the changed files" is ENFORCED for edits, by the closed
55
+ * file list the prompt scopes them to, and is a soft instruction for reads.
51
56
  */
52
57
  const ENFORCE_TOOLS = 'read,edit';
53
58
  /**
@@ -55,19 +60,25 @@ const ENFORCE_TOOLS = 'read,edit';
55
60
  * files and report violations but CANNOT edit, create, or run anything.
56
61
  *
57
62
  * This is the "no signal ⇒ no license to rewrite logic" half of the gate. When a
58
- * task ships no behavioral verification to guard a destructive edit (no runnable
59
- * VERIFY, or the verify gate did not produce a genuine clean pass), letting the
60
- * weak model rewrite working code is exactly what trashes the build A/B-proven:
61
- * with `read,edit` and no guard the model degraded a clean tree in 4/5 runs while
62
- * declaring CLEAN. Demoted to `read`, it cannot trash anything (5/5 clean) and
63
- * still names the real violation (5/5). So with no signal to revert against, the
64
- * pass reports the violation as a warning instead of editing.
63
+ * task ships no behavioural verification to guard a destructive edit no runnable
64
+ * VERIFY, or a verify gate that never produced a genuine clean pass there is
65
+ * nothing to revert against if the fix pass makes things worse. A weak model handed
66
+ * `read,edit` in that state can degrade a working tree and still report CLEAN,
67
+ * because nothing is able to contradict it.
68
+ *
69
+ * Demoted to `read` alone it cannot change anything, and still names the real
70
+ * violation. So with no signal to check against, the pass reports the violation as
71
+ * a warning instead of editing.
65
72
  */
66
73
  const ENFORCE_FLAG_TOOLS = 'read';
67
74
  /**
68
- * Read the guideline files that live directly in `cwd` (AGENTS.md, CLAUDE.md).
69
- * Returns null when none exist or all are empty — the caller treats that as a
70
- * pass. cwd-only by design: no walk up to the git root.
75
+ * Read the guideline files that live directly in `cwd` (AGENTS.md, CLAUDE.md),
76
+ * concatenated under a `## <name>` header each, in that order.
77
+ *
78
+ * Returns null when none exist OR all are empty — the caller treats either as a
79
+ * pass. cwd-only by design, with no walk up to the git root: run from a
80
+ * subdirectory holding only its own AGENTS.md, a CLAUDE.md one level up is not
81
+ * picked up.
71
82
  */
72
83
  export async function discoverGuidelines(cwd, readFile = p => fsp.readFile(p, 'utf8')) {
73
84
  const files = [];
@@ -90,7 +101,7 @@ export async function discoverGuidelines(cwd, readFile = p => fsp.readFile(p, 'u
90
101
  return { files, text: sections.join('\n\n') };
91
102
  }
92
103
  /**
93
- * Render the deterministic probe-gaming findings (run-8 F6) as a prompt block, or
104
+ * Render the deterministic probe-gaming findings as a prompt block, or
94
105
  * an empty array when there are none. Shared by the edit and flag prompts: the
95
106
  * finding is a concrete diff line whose stated purpose is to make a check pass
96
107
  * rather than meet the requirement — the reliable lever the prompt rule leans on.
@@ -230,7 +241,7 @@ export function classifyEnforceChildFailure(r) {
230
241
  return null;
231
242
  switch (failure.kind) {
232
243
  case 'stalled':
233
- // mx5 run 7: 64 minutes of silence reported as a user cancel.
244
+ // Otherwise a long silence is reported as a user cancel.
234
245
  return 'model server unreachable — the child produced no output and the model endpoint did not respond';
235
246
  case 'command-timeout': {
236
247
  // Its text is truncated mid-run — the verdict in it is partial and
@@ -1,6 +1,11 @@
1
1
  /**
2
- * Research enrichment — extract package names and URLs from text so the
3
- * orchestrator can fan out docs/URL lookups before the research phase.
2
+ * Research enrichment — extract package names, URLs and named external services
3
+ * from text so the orchestrator can fan out lookups before the research phase.
4
+ *
5
+ * Everything here is order-preserving and deduped. Run on a mixed input: the
6
+ * denylisted shell names are dropped, a URL's trailing sentence punctuation is
7
+ * stripped, docs targets stop at ENRICH_CAP while version targets continue to
8
+ * ENRICH_VERSION_CAP, and the version list is a strict superset of the docs list.
4
9
  */
5
10
  export declare function extractEnrichTargets(text: string): {
6
11
  /** Packages that get a (heavy) docs fetch — capped at ENRICH_CAP. */
@@ -1,6 +1,11 @@
1
1
  /**
2
- * Research enrichment — extract package names and URLs from text so the
3
- * orchestrator can fan out docs/URL lookups before the research phase.
2
+ * Research enrichment — extract package names, URLs and named external services
3
+ * from text so the orchestrator can fan out lookups before the research phase.
4
+ *
5
+ * Everything here is order-preserving and deduped. Run on a mixed input: the
6
+ * denylisted shell names are dropped, a URL's trailing sentence punctuation is
7
+ * stripped, docs targets stop at ENRICH_CAP while version targets continue to
8
+ * ENRICH_VERSION_CAP, and the version list is a strict superset of the docs list.
4
9
  */
5
10
  const ENRICH_PKG_RE = /`((?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*)`/g;
6
11
  const ENRICH_URL_RE = /https?:\/\/[^\s)`>]+/g;
@@ -21,12 +26,15 @@ const ENRICH_DENYLIST = new Set([
21
26
  'rm'
22
27
  ]);
23
28
  const ENRICH_CAP = 3;
24
- // Heavy docs/url fetches stay capped at ENRICH_CAP (each is a worker spawn +
25
- // page fetch). A live npm VERSION lookup is just one cheap registry GET, so it
26
- // can cover far more packages every dependency a task explicitly names should
27
- // get a grounded latest-version block, not just the first ENRICH_CAP of them. A
28
- // task that named 6 runtime deps used to leave the 4th–6th (e.g. tailwindcss)
29
- // with NO live version, so a version question fell back to stale training data.
29
+ // Two different caps because the two lookups cost very different things. A docs
30
+ // or URL fetch is a worker spawn plus a page fetch, so those stay at ENRICH_CAP.
31
+ // A live npm VERSION lookup is one cheap registry GET, so it can cover far more:
32
+ // every dependency a task explicitly names should get a grounded latest-version
33
+ // block, not just the first ENRICH_CAP of them.
34
+ //
35
+ // With a single cap, a task naming several runtime deps leaves the later ones with
36
+ // no live version at all, and a question about one of them falls back to whatever
37
+ // the model remembers.
30
38
  const ENRICH_VERSION_CAP = 12;
31
39
  const ENRICH_SERVICE_HEADER = 'EXTERNAL-DEPENDENCIES';
32
40
  const ENRICH_HEADER_LINE_RE = /^[A-Z][A-Z0-9 -]+$/;
@@ -43,10 +51,11 @@ function parseServices(text) {
43
51
  const trimmed = line.trim();
44
52
  if (trimmed === '')
45
53
  break;
46
- // The refine model sometimes emits the section header twice in a row.
47
- // A repeated EXTERNAL-DEPENDENCIES line is not a section terminator
48
- // skip it and keep reading bullets. Any *other* all-caps header still
49
- // ends the section.
54
+ // A repeated EXTERNAL-DEPENDENCIES line is not a section terminator: the
55
+ // model sometimes emits the header twice in a row, and treating the second
56
+ // one as the end would drop every bullet under it. Skip it and keep
57
+ // reading. Any OTHER all-caps header still ends the section, and so does a
58
+ // blank line — both confirmed.
50
59
  if (trimmed === ENRICH_SERVICE_HEADER)
51
60
  continue;
52
61
  if (ENRICH_HEADER_LINE_RE.test(trimmed))
@@ -55,8 +64,11 @@ function parseServices(text) {
55
64
  if (!m)
56
65
  continue;
57
66
  const name = m[1].trim();
58
- // Dedupe by name (case-insensitive); the model also duplicates bullets.
59
- // Keep the first occurrence's query and count uniques against the cap.
67
+ // Dedupe by name, case-insensitively, because the model duplicates bullets
68
+ // as well as headers. The FIRST occurrence's query is kept, and only
69
+ // uniques count against the cap — so a duplicate cannot crowd out a real
70
+ // service. Confirmed: `Stripe` and a later `stripe` collapse to one entry
71
+ // carrying the first query.
60
72
  const key = name.toLowerCase();
61
73
  if (seen.has(key))
62
74
  continue;
@@ -4,16 +4,20 @@ export interface EnvNote {
4
4
  origin: string;
5
5
  }
6
6
  /**
7
- * Parse the stored file into fact+origin records. Legacy lines written before
8
- * provenance (no separator) parse with an empty origin, so old caches still read.
7
+ * Parse the stored file into fact+origin records. A line with no separator parses
8
+ * with an empty origin rather than being dropped, so a cache written before
9
+ * provenance existed still reads — and `buildEnvNotesBlock` renders those as
10
+ * "origin unrecorded" instead of silently claiming an author.
9
11
  */
10
12
  export declare function parseEnvNotes(raw: string): EnvNote[];
11
13
  export declare function envNotesFile(cwd: string): string;
12
14
  /** The raw stored file ('' when none were recorded yet). Parse with parseEnvNotes. */
13
15
  export declare function readEnvNotes(cwd: string): Promise<string>;
14
16
  /**
15
- * Pull `ENV-NOTE: <fact>` lines out of a child's answer text. Deduplicated,
16
- * length-capped; verdict markers can never match (different prefix).
17
+ * Pull `ENV-NOTE: <fact>` lines out of a child's answer text: trimmed,
18
+ * deduplicated case-insensitively, and dropped when empty or over
19
+ * MAX_NOTE_LENGTH. Run: a `VERDICT:` line and even a near-miss `ENV-NOTES:` line
20
+ * match nothing, so a verdict cannot leak into the fact cache.
17
21
  */
18
22
  export declare function extractEnvNotes(text: string): string[];
19
23
  /** True when a fact reads like a standing excuse (see EXCUSE_PATTERNS). */
@@ -21,9 +25,14 @@ export declare function isExcuseNote(fact: string): boolean;
21
25
  /**
22
26
  * Append newly discovered facts to the cache, deduplicated against what is
23
27
  * already there (case-insensitive fact match), keeping the newest MAX_NOTES.
24
- * Each new fact is stamped with the `origin` task that recorded it; a fact
25
- * already present keeps its ORIGINAL origin (provenance traces to who first
26
- * established it). Failures are swallowed the cache is a sharpener, never a
28
+ * Each new fact is stamped with the `origin` task that recorded it; a fact already
29
+ * present keeps its ORIGINAL origin, so provenance traces to whoever first
30
+ * established it. Confirmed by re-appending the same fact under a different task:
31
+ * one entry survives, still carrying the first writer.
32
+ *
33
+ * Tabs in an emitted fact are normalised to spaces before storage, which is what
34
+ * keeps the separator unambiguous. The cap holds too — sixty further facts leave
35
+ * MAX_NOTES stored. Failures are swallowed: the cache is a sharpener, never a
27
36
  * blocker.
28
37
  */
29
38
  export declare function appendEnvNotes(cwd: string, notes: string[], origin?: string): Promise<void>;