@mjasnikovs/pi-task 0.38.29 → 0.38.31

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 (373) 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/index.js +2 -0
  14. package/dist/remote/bridge.d.ts +19 -10
  15. package/dist/remote/bridge.js +3 -2
  16. package/dist/remote/broadcast.js +3 -1
  17. package/dist/remote/events.js +12 -11
  18. package/dist/remote/history.d.ts +1 -1
  19. package/dist/remote/protocol.d.ts +6 -3
  20. package/dist/remote/protocol.js +2 -1
  21. package/dist/remote/push.d.ts +16 -16
  22. package/dist/remote/push.js +27 -27
  23. package/dist/remote/register.d.ts +3 -3
  24. package/dist/remote/register.js +17 -19
  25. package/dist/remote/server.d.ts +9 -8
  26. package/dist/remote/server.js +15 -14
  27. package/dist/remote/session-state.d.ts +5 -4
  28. package/dist/remote/session-state.js +8 -5
  29. package/dist/remote/sw.d.ts +7 -6
  30. package/dist/remote/sw.js +7 -6
  31. package/dist/remote/tailscale.d.ts +4 -2
  32. package/dist/remote/tailscale.js +4 -2
  33. package/dist/remote/ui-highlight.js +6 -5
  34. package/dist/remote/ui-render.js +4 -4
  35. package/dist/remote/ui-script.js +24 -24
  36. package/dist/remote/ui-styles.d.ts +1 -1
  37. package/dist/remote/ui-styles.js +10 -13
  38. package/dist/remote/ui-tools.js +9 -6
  39. package/dist/shared/child-extensions.d.ts +29 -17
  40. package/dist/shared/child-extensions.js +29 -17
  41. package/dist/shared/child-output.d.ts +30 -24
  42. package/dist/shared/child-output.js +25 -17
  43. package/dist/shared/child-process.d.ts +47 -40
  44. package/dist/shared/child-process.js +50 -59
  45. package/dist/shared/command-watchdog.d.ts +85 -16
  46. package/dist/shared/command-watchdog.js +115 -21
  47. package/dist/shared/fs-text.d.ts +16 -10
  48. package/dist/shared/fs-text.js +16 -10
  49. package/dist/shared/git-runner.d.ts +25 -25
  50. package/dist/shared/git-runner.js +25 -25
  51. package/dist/shared/leaked-tool-call.d.ts +17 -11
  52. package/dist/shared/leaked-tool-call.js +23 -15
  53. package/dist/shared/model-endpoint.d.ts +29 -16
  54. package/dist/shared/model-endpoint.js +33 -21
  55. package/dist/shared/pi-invocation.d.ts +7 -4
  56. package/dist/shared/pi-invocation.js +12 -7
  57. package/dist/shared/pkg-version.d.ts +13 -5
  58. package/dist/shared/pkg-version.js +13 -5
  59. package/dist/shared/reasoning-capability.d.ts +35 -24
  60. package/dist/shared/reasoning-capability.js +35 -24
  61. package/dist/shared/stream-watchdog.d.ts +60 -44
  62. package/dist/shared/stream-watchdog.js +62 -45
  63. package/dist/task/accept-debt.d.ts +41 -43
  64. package/dist/task/accept-debt.js +73 -65
  65. package/dist/task/api-synthesis.d.ts +24 -21
  66. package/dist/task/api-synthesis.js +32 -26
  67. package/dist/task/apis-contract.d.ts +32 -64
  68. package/dist/task/apis-contract.js +32 -64
  69. package/dist/task/artifact-closure.d.ts +27 -13
  70. package/dist/task/artifact-closure.js +95 -67
  71. package/dist/task/auto-commit.d.ts +46 -35
  72. package/dist/task/auto-commit.js +51 -38
  73. package/dist/task/auto-io.d.ts +45 -25
  74. package/dist/task/auto-io.js +57 -29
  75. package/dist/task/auto-orchestrator.d.ts +26 -24
  76. package/dist/task/auto-orchestrator.js +192 -165
  77. package/dist/task/auto-prompts.d.ts +36 -24
  78. package/dist/task/auto-prompts.js +40 -26
  79. package/dist/task/autofix-ledger.d.ts +27 -25
  80. package/dist/task/autofix-ledger.js +29 -26
  81. package/dist/task/batch-test-task.d.ts +20 -12
  82. package/dist/task/batch-test-task.js +67 -60
  83. package/dist/task/boot-probe.d.ts +60 -44
  84. package/dist/task/boot-probe.js +91 -72
  85. package/dist/task/cancel-input.d.ts +30 -16
  86. package/dist/task/cancel-input.js +20 -11
  87. package/dist/task/cancel-points.d.ts +27 -20
  88. package/dist/task/cancel-points.js +30 -22
  89. package/dist/task/child-runner.d.ts +124 -55
  90. package/dist/task/child-runner.js +298 -90
  91. package/dist/task/child-status.d.ts +23 -16
  92. package/dist/task/child-status.js +23 -16
  93. package/dist/task/clamp-output.js +12 -5
  94. package/dist/task/command-run.d.ts +31 -28
  95. package/dist/task/command-run.js +44 -35
  96. package/dist/task/command-shrink.d.ts +25 -18
  97. package/dist/task/command-shrink.js +37 -31
  98. package/dist/task/command-watchdog.d.ts +9 -6
  99. package/dist/task/command-watchdog.js +21 -15
  100. package/dist/task/context-attribution.d.ts +34 -26
  101. package/dist/task/context-attribution.js +34 -26
  102. package/dist/task/context-silence.d.ts +39 -29
  103. package/dist/task/context-silence.js +35 -25
  104. package/dist/task/context-usage.d.ts +16 -9
  105. package/dist/task/context-usage.js +16 -9
  106. package/dist/task/contracts.d.ts +8 -4
  107. package/dist/task/contracts.js +25 -17
  108. package/dist/task/coverage-loop.d.ts +22 -18
  109. package/dist/task/coverage-loop.js +35 -30
  110. package/dist/task/critique-probes.d.ts +13 -14
  111. package/dist/task/critique-probes.js +50 -39
  112. package/dist/task/debug-log.d.ts +13 -5
  113. package/dist/task/debug-log.js +32 -20
  114. package/dist/task/decompose-fidelity.d.ts +11 -9
  115. package/dist/task/decompose-fidelity.js +38 -33
  116. package/dist/task/decompose-granularity.d.ts +41 -38
  117. package/dist/task/decompose-granularity.js +41 -38
  118. package/dist/task/deep-render-check.d.ts +22 -14
  119. package/dist/task/deep-render-check.js +40 -31
  120. package/dist/task/dropped-input.d.ts +12 -7
  121. package/dist/task/dropped-input.js +5 -2
  122. package/dist/task/enforce-attribution.d.ts +38 -47
  123. package/dist/task/enforce-attribution.js +46 -52
  124. package/dist/task/enforce-guidelines.d.ts +31 -20
  125. package/dist/task/enforce-guidelines.js +32 -21
  126. package/dist/task/enrichment.d.ts +7 -2
  127. package/dist/task/enrichment.js +26 -14
  128. package/dist/task/env-notes.d.ts +16 -7
  129. package/dist/task/env-notes.js +48 -31
  130. package/dist/task/env-template-closure.d.ts +4 -4
  131. package/dist/task/env-template-closure.js +42 -34
  132. package/dist/task/external-context.d.ts +28 -21
  133. package/dist/task/external-context.js +17 -12
  134. package/dist/task/failure-classifier.d.ts +4 -5
  135. package/dist/task/failure-classifier.js +30 -8
  136. package/dist/task/file-inventory.d.ts +15 -11
  137. package/dist/task/file-inventory.js +25 -22
  138. package/dist/task/final-gate-fix.d.ts +74 -86
  139. package/dist/task/final-gate-fix.js +97 -116
  140. package/dist/task/final-gate-progress.d.ts +29 -46
  141. package/dist/task/final-gate-progress.js +40 -51
  142. package/dist/task/final-gate.d.ts +64 -97
  143. package/dist/task/final-gate.js +192 -199
  144. package/dist/task/fix-child.d.ts +21 -27
  145. package/dist/task/fix-child.js +21 -27
  146. package/dist/task/foreign-path.d.ts +6 -5
  147. package/dist/task/foreign-path.js +0 -0
  148. package/dist/task/frozen-conflict.d.ts +9 -10
  149. package/dist/task/frozen-conflict.js +61 -64
  150. package/dist/task/frozen-path-guard.d.ts +35 -14
  151. package/dist/task/frozen-path-guard.js +56 -39
  152. package/dist/task/gate-child.d.ts +27 -28
  153. package/dist/task/gate-child.js +36 -35
  154. package/dist/task/gate-deps.d.ts +34 -27
  155. package/dist/task/gate-deps.js +169 -159
  156. package/dist/task/gate-tally.d.ts +77 -80
  157. package/dist/task/gate-tally.js +65 -68
  158. package/dist/task/git-state-guard.d.ts +15 -11
  159. package/dist/task/git-state-guard.js +76 -66
  160. package/dist/task/impl-widget.d.ts +25 -16
  161. package/dist/task/impl-widget.js +27 -17
  162. package/dist/task/implementation-guards.d.ts +26 -0
  163. package/dist/task/implementation-guards.js +177 -0
  164. package/dist/task/implementation-thinking.d.ts +33 -31
  165. package/dist/task/implementation-thinking.js +5 -6
  166. package/dist/task/implementation-turn.d.ts +39 -31
  167. package/dist/task/implementation-turn.js +41 -28
  168. package/dist/task/inline-markdown.d.ts +20 -7
  169. package/dist/task/inline-markdown.js +15 -6
  170. package/dist/task/launch-config-gap.js +25 -39
  171. package/dist/task/launch-contract.d.ts +18 -21
  172. package/dist/task/launch-contract.js +28 -30
  173. package/dist/task/launch-manifest.d.ts +6 -2
  174. package/dist/task/launch-manifest.js +35 -34
  175. package/dist/task/ledger.js +16 -14
  176. package/dist/task/lint-fix.d.ts +6 -8
  177. package/dist/task/lint-fix.js +67 -69
  178. package/dist/task/loop-detector.d.ts +27 -8
  179. package/dist/task/loop-detector.js +38 -14
  180. package/dist/task/mid-run-input.d.ts +17 -15
  181. package/dist/task/mid-run-input.js +17 -15
  182. package/dist/task/orchestrator.d.ts +24 -28
  183. package/dist/task/orchestrator.js +89 -66
  184. package/dist/task/orientation.d.ts +18 -23
  185. package/dist/task/orientation.js +24 -31
  186. package/dist/task/owned-freeze-conflict.d.ts +21 -20
  187. package/dist/task/owned-freeze-conflict.js +52 -85
  188. package/dist/task/owned-freeze-reassign.d.ts +40 -60
  189. package/dist/task/owned-freeze-reassign.js +41 -61
  190. package/dist/task/parsers.d.ts +4 -2
  191. package/dist/task/parsers.js +4 -4
  192. package/dist/task/phases.d.ts +41 -48
  193. package/dist/task/phases.js +196 -252
  194. package/dist/task/plan-io.d.ts +6 -7
  195. package/dist/task/plan-io.js +6 -7
  196. package/dist/task/plan-orchestrator.d.ts +10 -8
  197. package/dist/task/plan-orchestrator.js +14 -10
  198. package/dist/task/plan-prompts.d.ts +6 -5
  199. package/dist/task/plan-prompts.js +6 -5
  200. package/dist/task/plan-readonly.d.ts +4 -5
  201. package/dist/task/plan-readonly.js +4 -5
  202. package/dist/task/plan-rounds.d.ts +17 -29
  203. package/dist/task/plan-rounds.js +21 -34
  204. package/dist/task/plan-session.d.ts +58 -72
  205. package/dist/task/plan-session.js +61 -83
  206. package/dist/task/probe-gaming.d.ts +28 -27
  207. package/dist/task/probe-gaming.js +0 -0
  208. package/dist/task/prohibition-probe.d.ts +14 -16
  209. package/dist/task/prompts.d.ts +3 -4
  210. package/dist/task/prompts.js +17 -26
  211. package/dist/task/qa-transcript.d.ts +15 -22
  212. package/dist/task/qa-transcript.js +15 -21
  213. package/dist/task/question-box.d.ts +17 -13
  214. package/dist/task/question-box.js +19 -15
  215. package/dist/task/question-dedup.d.ts +6 -7
  216. package/dist/task/question-dedup.js +13 -14
  217. package/dist/task/question-dialog.d.ts +22 -32
  218. package/dist/task/question-dialog.js +22 -32
  219. package/dist/task/question-source.d.ts +18 -44
  220. package/dist/task/question-source.js +22 -51
  221. package/dist/task/refuted-constraint.d.ts +11 -31
  222. package/dist/task/refuted-constraint.js +27 -51
  223. package/dist/task/regenerable-artifacts.d.ts +12 -31
  224. package/dist/task/regenerable-artifacts.js +12 -31
  225. package/dist/task/render-check.d.ts +11 -22
  226. package/dist/task/render-check.js +33 -46
  227. package/dist/task/repo-health-check.d.ts +10 -14
  228. package/dist/task/repo-health-check.js +17 -23
  229. package/dist/task/requirements.d.ts +38 -71
  230. package/dist/task/requirements.js +78 -126
  231. package/dist/task/research-fanout-budget.d.ts +51 -88
  232. package/dist/task/research-fanout-budget.js +51 -88
  233. package/dist/task/research-worker.d.ts +29 -39
  234. package/dist/task/research-worker.js +37 -61
  235. package/dist/task/resume-gap.d.ts +14 -15
  236. package/dist/task/root-cause-repair.d.ts +9 -9
  237. package/dist/task/root-cause-repair.js +28 -40
  238. package/dist/task/run-bracket.d.ts +10 -13
  239. package/dist/task/run-end.d.ts +12 -22
  240. package/dist/task/run-end.js +8 -16
  241. package/dist/task/run-final-gate.d.ts +19 -21
  242. package/dist/task/run-final-gate.js +62 -80
  243. package/dist/task/runner-globs.d.ts +12 -13
  244. package/dist/task/runner-globs.js +12 -13
  245. package/dist/task/runner-resolve.d.ts +9 -9
  246. package/dist/task/runner-resolve.js +22 -23
  247. package/dist/task/script-escape.d.ts +10 -12
  248. package/dist/task/script-escape.js +13 -14
  249. package/dist/task/serve-entry.d.ts +1 -1
  250. package/dist/task/serve-entry.js +22 -25
  251. package/dist/task/service-blocks.js +4 -2
  252. package/dist/task/shipped-source.d.ts +11 -29
  253. package/dist/task/shipped-source.js +11 -29
  254. package/dist/task/skip-escape.js +10 -14
  255. package/dist/task/spec-urls.d.ts +26 -65
  256. package/dist/task/spec-urls.js +26 -65
  257. package/dist/task/spec-validation.d.ts +17 -20
  258. package/dist/task/spec-validation.js +17 -20
  259. package/dist/task/stall-detector.d.ts +23 -30
  260. package/dist/task/stall-detector.js +23 -30
  261. package/dist/task/stream-watchdog.d.ts +14 -12
  262. package/dist/task/stream-watchdog.js +14 -12
  263. package/dist/task/substitution-probe.d.ts +17 -20
  264. package/dist/task/substitution-probe.js +17 -20
  265. package/dist/task/task-gates.d.ts +36 -41
  266. package/dist/task/task-gates.js +95 -106
  267. package/dist/task/task-io.d.ts +4 -4
  268. package/dist/task/task-io.js +4 -4
  269. package/dist/task/task-parsers.js +4 -3
  270. package/dist/task/task-provenance.d.ts +2 -2
  271. package/dist/task/task-provenance.js +11 -13
  272. package/dist/task/task-types.d.ts +4 -3
  273. package/dist/task/terminal-outcome.d.ts +14 -16
  274. package/dist/task/terminal-outcome.js +12 -14
  275. package/dist/task/test-assembly.d.ts +13 -20
  276. package/dist/task/test-assembly.js +13 -20
  277. package/dist/task/timings.d.ts +5 -3
  278. package/dist/task/timings.js +5 -3
  279. package/dist/task/title-label.d.ts +9 -4
  280. package/dist/task/title-label.js +9 -4
  281. package/dist/task/type-only-answer.d.ts +44 -52
  282. package/dist/task/type-only-answer.js +44 -52
  283. package/dist/task/unfailable-command.d.ts +18 -24
  284. package/dist/task/unfailable-command.js +21 -27
  285. package/dist/task/unknown-routing.d.ts +10 -4
  286. package/dist/task/unknown-routing.js +10 -4
  287. package/dist/task/user-directives.d.ts +5 -8
  288. package/dist/task/user-directives.js +5 -8
  289. package/dist/task/verify-quality.d.ts +18 -22
  290. package/dist/task/verify-quality.js +45 -46
  291. package/dist/task/verify-reconcile.d.ts +15 -10
  292. package/dist/task/verify-reconcile.js +45 -43
  293. package/dist/task/verify-resolution.d.ts +24 -20
  294. package/dist/task/verify-resolution.js +51 -50
  295. package/dist/task/verify-work.d.ts +59 -66
  296. package/dist/task/verify-work.js +101 -138
  297. package/dist/task/widget.d.ts +15 -14
  298. package/dist/task/widget.js +22 -17
  299. package/dist/task/wiring-claims.d.ts +25 -32
  300. package/dist/task/wiring-claims.js +30 -35
  301. package/dist/task/write-guard.d.ts +39 -39
  302. package/dist/task/write-guard.js +48 -51
  303. package/dist/task/yolo.d.ts +34 -30
  304. package/dist/task/yolo.js +42 -37
  305. package/dist/workers/abstention.d.ts +21 -41
  306. package/dist/workers/abstention.js +27 -48
  307. package/dist/workers/brave-search.d.ts +4 -3
  308. package/dist/workers/brave-search.js +5 -2
  309. package/dist/workers/brave-warning.d.ts +7 -4
  310. package/dist/workers/brave-warning.js +19 -7
  311. package/dist/workers/ddg-search.d.ts +6 -6
  312. package/dist/workers/ddg-search.js +18 -12
  313. package/dist/workers/docs-cache.js +5 -2
  314. package/dist/workers/docs-chunk.d.ts +30 -37
  315. package/dist/workers/docs-chunk.js +37 -41
  316. package/dist/workers/docs-core.d.ts +28 -44
  317. package/dist/workers/docs-core.js +25 -44
  318. package/dist/workers/docs-index.js +4 -3
  319. package/dist/workers/docs-lookup.d.ts +15 -22
  320. package/dist/workers/docs-lookup.js +12 -21
  321. package/dist/workers/docs-project.d.ts +15 -9
  322. package/dist/workers/docs-project.js +17 -10
  323. package/dist/workers/docs-resolve.d.ts +19 -20
  324. package/dist/workers/docs-resolve.js +35 -32
  325. package/dist/workers/docs-retrieve.d.ts +5 -6
  326. package/dist/workers/docs-retrieve.js +18 -15
  327. package/dist/workers/exa-search.d.ts +9 -6
  328. package/dist/workers/exa-search.js +23 -12
  329. package/dist/workers/fetch-core.d.ts +13 -16
  330. package/dist/workers/fetch-core.js +23 -23
  331. package/dist/workers/focused-extractor.d.ts +13 -12
  332. package/dist/workers/focused-extractor.js +27 -19
  333. package/dist/workers/html-clean.js +24 -14
  334. package/dist/workers/http-request.d.ts +28 -20
  335. package/dist/workers/http-request.js +22 -17
  336. package/dist/workers/npm-version.d.ts +28 -11
  337. package/dist/workers/npm-version.js +24 -15
  338. package/dist/workers/phantom-imports.d.ts +15 -12
  339. package/dist/workers/phantom-imports.js +30 -24
  340. package/dist/workers/pi-worker-core.d.ts +65 -96
  341. package/dist/workers/pi-worker-core.js +93 -181
  342. package/dist/workers/pi-worker-docs.d.ts +24 -19
  343. package/dist/workers/pi-worker-docs.js +67 -76
  344. package/dist/workers/pi-worker-fetch.d.ts +7 -3
  345. package/dist/workers/pi-worker-fetch.js +27 -19
  346. package/dist/workers/pi-worker-search.js +12 -8
  347. package/dist/workers/pi-worker.d.ts +9 -4
  348. package/dist/workers/pi-worker.js +21 -14
  349. package/dist/workers/reasoning-warning.d.ts +18 -17
  350. package/dist/workers/reasoning-warning.js +22 -20
  351. package/dist/workers/research-cache.js +50 -78
  352. package/dist/workers/search-core.js +7 -5
  353. package/dist/workers/search-types.d.ts +10 -9
  354. package/dist/workers/search-types.js +9 -8
  355. package/dist/workers/session-hint.d.ts +13 -14
  356. package/dist/workers/session-hint.js +8 -9
  357. package/dist/workers/shared.d.ts +21 -25
  358. package/dist/workers/shared.js +0 -0
  359. package/dist/workers/single-read-extension.d.ts +14 -7
  360. package/dist/workers/single-read-extension.js +14 -7
  361. package/dist/workers/single-read-guard.d.ts +27 -30
  362. package/dist/workers/single-read-guard.js +36 -36
  363. package/dist/workers/typeonly-log.d.ts +12 -9
  364. package/dist/workers/typeonly-log.js +29 -33
  365. package/dist/workers/worker-channels.d.ts +15 -23
  366. package/dist/workers/worker-channels.js +15 -23
  367. package/dist/workers/worker-failure.d.ts +38 -46
  368. package/dist/workers/worker-failure.js +31 -39
  369. package/dist/workers/worker-kill.d.ts +25 -26
  370. package/dist/workers/worker-kill.js +16 -19
  371. package/dist/workers/worker-profiles.d.ts +54 -56
  372. package/dist/workers/worker-profiles.js +63 -39
  373. package/package.json +10 -8
@@ -1,23 +1,27 @@
1
1
  /**
2
2
  * coverage-loop — the MONOTONIC replacement rule for /task-auto's decompose
3
- * coverage gate (mx5 run 12).
3
+ * coverage gate.
4
4
  *
5
- * The failure this closes: the coverage-retry loop regenerated the whole plan on
6
- * every INCOMPLETE verdict, and adopted the regeneration on nothing but a size
7
- * floor (`retry.length * 2 >= current.length`). A regeneration is a fresh
8
- * stochastic roll of the ENTIRE plan, so one that DROPPED a previously-covered
9
- * feature-area but kept the title count replaced the better plan anyway — and,
10
- * because the loop shipped whatever the LAST round produced, the dropped area was
11
- * gone with only a toast. Live: a complete full-stack plan (31 requirements
12
- * mapped, frontend pages present) was overwritten by a backend-only one and
13
- * shipped, driven by 3 NEGATIVE requirements no task could ever "own" that kept
14
- * the verdict INCOMPLETE forever.
5
+ * The failure this closes: a coverage retry regenerates the WHOLE plan, so it is a
6
+ * fresh stochastic roll rather than an edit. Adopt it on a size floor alone and a
7
+ * retry that DROPPED a previously-covered area but kept the title count replaces
8
+ * the better plan — and since the loop ships whatever the last round produced, the
9
+ * dropped area is gone with only a toast.
10
+ *
11
+ * The shape that makes this bite: a requirement no task can ever "own" — a
12
+ * prohibition, say keeps the verdict INCOMPLETE forever, so the loop keeps
13
+ * rolling until a worse plan happens to come up last.
15
14
  *
16
15
  * The rule here makes replacement monotone: coverage can only hold or grow across
17
16
  * rounds. A retry is adopted ONLY when it drops no requirement the current plan
18
- * already owns (its owned-set is a superset). Because adoption is monotone, the
19
- * working plan at exhaustion is the best-covered one seen so "ship the working
20
- * plan" is automatically "ship the best", never "ship the last".
17
+ * already owns its owned-set must be a superset. Because adoption is monotone,
18
+ * the working plan at exhaustion is the best-covered one seen, so "ship the
19
+ * working plan" is automatically "ship the best" and never "ship the last".
20
+ *
21
+ * Each rule was run. A retry dropping one owned requirement is rejected naming
22
+ * it; a strict superset is adopted; a retry that grows while covering nothing new
23
+ * is rejected as "no coverage gain"; and with no requirement signal at all, a
24
+ * retry leaving MORE areas uncovered is rejected while one leaving fewer is taken.
21
25
  *
22
26
  * Spec-shape-agnostic: the only inputs are title counts and the set of
23
27
  * requirement INDICES a task owns (from the host-side coverage map). No feature
@@ -47,13 +51,13 @@ export interface CoveragePlan {
47
51
  * DETERMINISTIC owned-set for the monotonic guard — grounded in requirement↔title
48
52
  * token overlap, NOT the coverage-map model's `TASK n` verdict.
49
53
  *
50
- * Why this exists (live A/B, Qwen3.6-27B, mx5-shaped CLI spec): the model
54
+ * Why this exists: the model
51
55
  * over-credits ownership — it mapped a "--json output" requirement to a generic
52
56
  * "scaffold + argument parser" task, so a plan with NO --json task still reported
53
57
  * owning it. A guard that trusts those numbers is blind to the very drop it must
54
- * catch (treatment held only 1/5 trials). Grounding coverage in whether a task
58
+ * catch. Grounding coverage in whether a task
55
59
  * TITLE actually shares a distinctive token with the requirement makes the
56
- * drop-signal independent of the model's rubber-stamp (treatment → 5/5).
60
+ * drop-signal independent of the model's rubber-stamp.
57
61
  *
58
62
  * A requirement is "covered" when some title shares a DISTINCTIVE token with it —
59
63
  * distinctive meaning the token is not shared across more than half the ownable
@@ -103,7 +107,7 @@ export declare function decideAdoption(current: CoveragePlan, retry: CoveragePla
103
107
  * title list the coverage-map child was prompted with. Hold the two apart and the
104
108
  * index silently addresses the wrong plan.
105
109
  *
106
- * That is not hypothetical. The coverage loop used to keep `best` (the scored plan)
110
+ * That is not hypothetical: a loop that keeps `best` (the scored plan)
107
111
  * and a separate `let accounting`, updated on adoption as
108
112
  * `accounting = cand.accounting ?? accounting`. `cand.accounting` is null whenever
109
113
  * the coverage-map child throws or its output fails to parse — a fault that is
@@ -1,23 +1,27 @@
1
1
  /**
2
2
  * coverage-loop — the MONOTONIC replacement rule for /task-auto's decompose
3
- * coverage gate (mx5 run 12).
3
+ * coverage gate.
4
4
  *
5
- * The failure this closes: the coverage-retry loop regenerated the whole plan on
6
- * every INCOMPLETE verdict, and adopted the regeneration on nothing but a size
7
- * floor (`retry.length * 2 >= current.length`). A regeneration is a fresh
8
- * stochastic roll of the ENTIRE plan, so one that DROPPED a previously-covered
9
- * feature-area but kept the title count replaced the better plan anyway — and,
10
- * because the loop shipped whatever the LAST round produced, the dropped area was
11
- * gone with only a toast. Live: a complete full-stack plan (31 requirements
12
- * mapped, frontend pages present) was overwritten by a backend-only one and
13
- * shipped, driven by 3 NEGATIVE requirements no task could ever "own" that kept
14
- * the verdict INCOMPLETE forever.
5
+ * The failure this closes: a coverage retry regenerates the WHOLE plan, so it is a
6
+ * fresh stochastic roll rather than an edit. Adopt it on a size floor alone and a
7
+ * retry that DROPPED a previously-covered area but kept the title count replaces
8
+ * the better plan — and since the loop ships whatever the last round produced, the
9
+ * dropped area is gone with only a toast.
10
+ *
11
+ * The shape that makes this bite: a requirement no task can ever "own" — a
12
+ * prohibition, say keeps the verdict INCOMPLETE forever, so the loop keeps
13
+ * rolling until a worse plan happens to come up last.
15
14
  *
16
15
  * The rule here makes replacement monotone: coverage can only hold or grow across
17
16
  * rounds. A retry is adopted ONLY when it drops no requirement the current plan
18
- * already owns (its owned-set is a superset). Because adoption is monotone, the
19
- * working plan at exhaustion is the best-covered one seen so "ship the working
20
- * plan" is automatically "ship the best", never "ship the last".
17
+ * already owns its owned-set must be a superset. Because adoption is monotone,
18
+ * the working plan at exhaustion is the best-covered one seen, so "ship the
19
+ * working plan" is automatically "ship the best" and never "ship the last".
20
+ *
21
+ * Each rule was run. A retry dropping one owned requirement is rejected naming
22
+ * it; a strict superset is adopted; a retry that grows while covering nothing new
23
+ * is rejected as "no coverage gain"; and with no requirement signal at all, a
24
+ * retry leaving MORE areas uncovered is rejected while one leaving fewer is taken.
21
25
  *
22
26
  * Spec-shape-agnostic: the only inputs are title counts and the set of
23
27
  * requirement INDICES a task owns (from the host-side coverage map). No feature
@@ -28,8 +32,12 @@
28
32
  // titles and requirement quotes, so overlap on them would falsely connect a
29
33
  // requirement to any plan. Stopped so grounding keys on the DISTINCTIVE nouns
30
34
  // (json, dead-letter, serialize, symlink…) that actually name a deliverable.
35
+ //
36
+ // Confirmed: titles built only from these words own NOTHING, while titles naming
37
+ // `JSON output` and `dead-letter queue` own the matching requirements.
38
+ //
31
39
  // English function words + generic task verbs + generic project nouns — all
32
- // domain-agnostic (no mx5/web vocabulary).
40
+ // domain-agnostic.
33
41
  const COVERAGE_STOPWORDS = new Set([
34
42
  // function words
35
43
  'the',
@@ -151,13 +159,13 @@ function contentTokens(s) {
151
159
  * DETERMINISTIC owned-set for the monotonic guard — grounded in requirement↔title
152
160
  * token overlap, NOT the coverage-map model's `TASK n` verdict.
153
161
  *
154
- * Why this exists (live A/B, Qwen3.6-27B, mx5-shaped CLI spec): the model
162
+ * Why this exists: the model
155
163
  * over-credits ownership — it mapped a "--json output" requirement to a generic
156
164
  * "scaffold + argument parser" task, so a plan with NO --json task still reported
157
165
  * owning it. A guard that trusts those numbers is blind to the very drop it must
158
- * catch (treatment held only 1/5 trials). Grounding coverage in whether a task
166
+ * catch. Grounding coverage in whether a task
159
167
  * TITLE actually shares a distinctive token with the requirement makes the
160
- * drop-signal independent of the model's rubber-stamp (treatment → 5/5).
168
+ * drop-signal independent of the model's rubber-stamp.
161
169
  *
162
170
  * A requirement is "covered" when some title shares a DISTINCTIVE token with it —
163
171
  * distinctive meaning the token is not shared across more than half the ownable
@@ -244,31 +252,28 @@ export function decideAdoption(current, retry, hasRequirements) {
244
252
  }
245
253
  // Growth must PAY FOR ITSELF. Past this point the retry's owned-set is a
246
254
  // superset, so an equal size means the sets are IDENTICAL — the retry
247
- // covers nothing new. Adopting it anyway is how mx5 (2026-07-28) went
248
- // 26 → 32 → 60 titles with the owned-set pinned at 27 in all three rounds,
249
- // both retries logged as "preserves owned coverage".
255
+ // covers nothing new. Adopting it anyway lets a plan inflate round after
256
+ // round with the owned-set pinned, every step logged as "preserves owned
257
+ // coverage".
250
258
  //
251
259
  // The old rule could not object, by construction: groundedCoverage is
252
260
  // monotone in the title set (titleTokens is a union over titles; df/maxDF
253
261
  // depend only on the quotes), and coverageRepromptHint asks the model for
254
262
  // "every task your previous list already had ... PLUS" — a superset. So
255
263
  // `dropped` is structurally empty whenever the model obeys the hint and the
256
- // guard adopted unconditionally (measured: 2000/2000 superset retries
257
- // adopted; 563/2000 independently-sampled ones rejected — the guard has
264
+ // guard adopted unconditionally. A retry that is a strict superset is
265
+ // always adopted; an independently-sampled one often is not — the guard has
258
266
  // power, just not against the shape the prompt requests).
259
267
  //
260
268
  // REJECT, never break. Rejection keeps the smaller plan and lets the loop
261
269
  // reprompt again; breaking here forfeits a later round that would have
262
- // gained (live: 19t/24c 38t/24c 40t/25c, where stopping at the tie
263
- // loses the 25th requirement). "No gain this round" is not "no gain ever".
270
+ // gained: a later round can add the requirement a tied round did not. "No gain this round" is not "no gain ever".
264
271
  //
265
272
  // Safety is structural, not statistical: this branch is reachable only when
266
273
  // the retry covers NO MORE than the current plan, so it can never decline a
267
- // strictly better one. Live A/B (Qwen3.6-27B, mx5 20KB spec, 24 reps,
268
- // precondition 24/24): inflated plans 7/24 0/24, Fisher two-sided
269
- // p=0.0094; coverage mean 24.58 → 24.79 (higher in 6 reps, lower in 1, and
270
- // that one rep never fired this clause); plan size 41.8 → 38.8, which is
271
- // NOT significant (sign 15/8, p=0.21) — the win is removing pathological
274
+ // strictly better one. It removes plans inflated by a retry that added
275
+ // titles without adding coverage, and leaves coverage itself alone — the
276
+ // win is removing pathological
272
277
  // inflation, not shrinking plans generally.
273
278
  if (retry.covered.size <= current.covered.size
274
279
  && retry.titles.length > current.titles.length) {
@@ -6,21 +6,20 @@
6
6
  * the deterministic half of critique: the triage child judges taste, these decide
7
7
  * facts.
8
8
  *
9
- * Why a table. Every probe used to be written out three times inside
10
- * `phaseCritique` — once as a four-line detect/format/log ritual, once as a term
11
- * in the seven-way conjunction that lets a CLEAN triage short-circuit, and once
12
- * as an element of the array merged into the rewrite. Adding a probe meant three
13
- * coordinated edits, and forgetting the SECOND one is silent and severe: a CLEAN
14
- * triage would then ship a spec carrying a defect the scanner had already found —
15
- * which is precisely the failure each probe exists to prevent. No test would
16
- * notice, because the wiring, unlike the scanners, was almost entirely untested
17
- * (1 of 6).
9
+ * Why a table. Longhand, a probe has to appear three times in `phaseCritique`:
10
+ * once as a detect/format/log ritual, once as a term in the conjunction that lets
11
+ * a CLEAN triage short-circuit, and once in the array merged into the rewrite.
12
+ * Adding one then means three coordinated edits, and forgetting the SECOND is
13
+ * silent and severe a CLEAN triage ships a spec carrying a defect the scanner
14
+ * already found, which is precisely what each probe exists to prevent. Wiring like
15
+ * that is also the part tests rarely cover, because the scanners are the
16
+ * interesting half.
18
17
  *
19
- * With a table the override and the merge are DERIVED from the rows, so "every
20
- * probe blocks a CLEAN short-circuit" is structurally true rather than something
21
- * a reviewer must check. This is the same move `PROBE_ADAPTERS` (verify-work.ts)
22
- * and `CLOSURE_SCANS` (final-gate.ts) already made; critique is the one place
23
- * that never got it.
18
+ * As a table the override and the merge are DERIVED from the rows:
19
+ * `collectCritiqueDefects` returns `forced: blocks.length > 0`, so "every probe
20
+ * blocks a CLEAN short-circuit" is structurally true rather than something a
21
+ * reviewer must check. Same move as `PROBE_ADAPTERS` (verify-work.ts) and
22
+ * `CLOSURE_SCANS` (final-gate.ts).
24
23
  */
25
24
  /** Everything the probes read. Assembled once by the critique phase. */
26
25
  export interface CritiqueProbeContext {
@@ -6,21 +6,20 @@
6
6
  * the deterministic half of critique: the triage child judges taste, these decide
7
7
  * facts.
8
8
  *
9
- * Why a table. Every probe used to be written out three times inside
10
- * `phaseCritique` — once as a four-line detect/format/log ritual, once as a term
11
- * in the seven-way conjunction that lets a CLEAN triage short-circuit, and once
12
- * as an element of the array merged into the rewrite. Adding a probe meant three
13
- * coordinated edits, and forgetting the SECOND one is silent and severe: a CLEAN
14
- * triage would then ship a spec carrying a defect the scanner had already found —
15
- * which is precisely the failure each probe exists to prevent. No test would
16
- * notice, because the wiring, unlike the scanners, was almost entirely untested
17
- * (1 of 6).
9
+ * Why a table. Longhand, a probe has to appear three times in `phaseCritique`:
10
+ * once as a detect/format/log ritual, once as a term in the conjunction that lets
11
+ * a CLEAN triage short-circuit, and once in the array merged into the rewrite.
12
+ * Adding one then means three coordinated edits, and forgetting the SECOND is
13
+ * silent and severe a CLEAN triage ships a spec carrying a defect the scanner
14
+ * already found, which is precisely what each probe exists to prevent. Wiring like
15
+ * that is also the part tests rarely cover, because the scanners are the
16
+ * interesting half.
18
17
  *
19
- * With a table the override and the merge are DERIVED from the rows, so "every
20
- * probe blocks a CLEAN short-circuit" is structurally true rather than something
21
- * a reviewer must check. This is the same move `PROBE_ADAPTERS` (verify-work.ts)
22
- * and `CLOSURE_SCANS` (final-gate.ts) already made; critique is the one place
23
- * that never got it.
18
+ * As a table the override and the merge are DERIVED from the rows:
19
+ * `collectCritiqueDefects` returns `forced: blocks.length > 0`, so "every probe
20
+ * blocks a CLEAN short-circuit" is structurally true rather than something a
21
+ * reviewer must check. Same move as `PROBE_ADAPTERS` (verify-work.ts) and
22
+ * `CLOSURE_SCANS` (final-gate.ts).
24
23
  */
25
24
  import { existsSync } from 'node:fs';
26
25
  import { resolve } from 'node:path';
@@ -40,22 +39,28 @@ function probe(row) {
40
39
  */
41
40
  export const CRITIQUE_PROBES = [
42
41
  probe({
43
- // run-8 F2: a required VERIFY check wrapped in a skip-announcing `||`
44
- // fallback (`… || echo "skipping (tool absent)"`) lets the check pass
45
- // while never running. FP-measured 0/20 on the historical specs.
42
+ // A required VERIFY check wrapped in a skip-announcing `||` fallback
43
+ // (`… || echo "skipping (tool absent)"`) lets the check pass while never
44
+ // running. Confirmed: that exact line makes the collector force a rewrite.
46
45
  id: 'skip-escape',
47
46
  detect: ctx => findSkipEscapes(ctx.spec),
48
47
  text: f => skipEscapeDefectText(f),
49
48
  log: f => `skip-escape flagged in VERIFY: ${f.length} line(s)`
50
49
  }),
51
50
  probe({
52
- // run-8 F3, generation side. The registry alone is a WEAK catcher (live
53
- // A/B: prompt+registry ~1/8) the model's attention goes to the obvious
54
- // VERIFY weakness and it rarely does the path-composition reasoning. The
55
- // scanner NAMES the inferred mount mappings and juxtaposes the verbatim
56
- // pinned facts, forcing focused reconciliation. FP-clean (1/18 files on
57
- // the run-8 trees). Grounding = the registry any design doc the
58
- // spec/refined @-reference. No registry nothing to contradict.
51
+ // The generation-side complement of the verify-side boundary check: a spec
52
+ // that INFERS a wiring specific (a tidy mount table) the design never
53
+ // pinned.
54
+ //
55
+ // Handing the registry to the model alone is a weak catcher, because its
56
+ // attention goes to the obvious VERIFY weakness rather than to
57
+ // path-composition reasoning. So this scanner NAMES the inferred mount
58
+ // mappings and juxtaposes the verbatim pinned facts, forcing a focused
59
+ // reconciliation.
60
+ //
61
+ // Grounding is the registry plus any design doc the spec or refined text
62
+ // @-references. No registry means nothing to contradict, and the row
63
+ // returns no findings at all.
59
64
  id: 'synthesized-wiring',
60
65
  detect: ctx => ctx.registryRaw.trim().length > 0 ?
61
66
  findSynthesizedWiring(ctx.spec, ctx.registryRaw + '\n' + readReferencedDocs(ctx.cwd, ctx.refined, ctx.spec), ctx.registryRaw)
@@ -64,11 +69,11 @@ export const CRITIQUE_PROBES = [
64
69
  log: f => `synthesized wiring flagged in spec: ${f.map(w => w.line).join(' | ')}`
65
70
  }),
66
71
  probe({
67
- // mx5 run 11, goal D: a VERIFY line asserting the ABSENCE of an artifact
72
+ // A VERIFY line asserting the ABSENCE of an artifact
68
73
  // the plan pins elsewhere — a path a prior task already shipped, a sibling
69
- // title's deliverable, a contract-pinned boundary. Run 11: the scope fence
70
- // leaked into TASK_0009's verify as "the admin page must NOT exist"
71
- // (TASK_0008's deliverable); the guaranteed FAIL became an accepted debt
74
+ // title's deliverable, a contract-pinned boundary. A scope fence can
75
+ // leak into a sibling's verify as "the admin page must NOT exist"
76
+ //; the guaranteed FAIL became an accepted debt
72
77
  // that the final-gate autofix then "fixed" by deleting the sibling's work.
73
78
  // It must die here, at spec time. Delete-tasks keep their check by
74
79
  // declaring the delete.
@@ -83,14 +88,20 @@ export const CRITIQUE_PROBES = [
83
88
  + f.map(c => `${c.assertion.target} (${c.against})`).join(' | ')
84
89
  }),
85
90
  probe({
86
- // mx5 run 12 root cause: a blanket frozen path ("Do NOT modify
87
- // `tsconfig.json` handled in steps 12") whose registration edit the
88
- // spec's OWN body or the task's RESEARCH the spec was composed from
89
- // (live drafts sometimes drop the nuance while shipping the freeze and the
90
- // creation) says the deliverable requires. Shipped as-is, the created
91
- // files turn the repo-wide static check permanently red and no task is
92
- // allowed to fix it: every later task burns its AUTOFIX rounds on it. The
93
- // rewrite must grant scoped ownership or drop the creation.
91
+ // An unsatisfiable pair: the spec FREEZES a path outright ("Do NOT modify
92
+ // `tsconfig.json` handled in steps 1-2") while something also says the
93
+ // deliverable requires editing that same path. The freeze always comes from
94
+ // the spec; the requirement may come from the spec's own body OR from the
95
+ // RESEARCH it was composed from, since compose can drop the nuance while
96
+ // keeping both the freeze and the file creation.
97
+ //
98
+ // Shipped as-is, the created files turn the repo-wide static check
99
+ // permanently red and no task is allowed to fix it — every later task burns
100
+ // its AUTOFIX rounds on it. The rewrite must grant scoped ownership or drop
101
+ // the creation.
102
+ //
103
+ // Confirmed: a freeze alone yields nothing; a freeze plus a
104
+ // requires-edit statement in the same spec yields one conflict.
94
105
  id: 'frozen-conflict',
95
106
  detect: ctx => findFrozenPathConflicts(ctx.spec, ctx.research),
96
107
  text: f => frozenConflictProbeText(f),
@@ -98,7 +109,7 @@ export const CRITIQUE_PROBES = [
98
109
  + f.map(c => c.path).join(' | ')
99
110
  }),
100
111
  probe({
101
- // mx5 run 13, Bug B: a VERIFY block that grep-asserts the SOURCE of a
112
+ // A VERIFY block that grep-asserts the SOURCE of a
102
113
  // runnable deliverable while every command in the block is static
103
114
  // inspection — the build script "verified" by three greps that was never
104
115
  // run, shipping broken for 14 tasks. VERIFY must EXECUTE the artifact and
@@ -107,7 +118,7 @@ export const CRITIQUE_PROBES = [
107
118
  detect: ctx => findGrepOnlyVerify(ctx.spec),
108
119
  text: f => grepOnlyVerifyDefectText(f),
109
120
  log: f => `grep-theater VERIFY flagged in spec: ${f.map(x => x.target).join(' | ')}`,
110
- // Detector-backed closure: live A/B, 1/5 rewrites ignored the injected
121
+ // Detector-backed closure: a rewrite can ignore the injected
111
122
  // defect and re-shipped the grep-only block.
112
123
  unresolvedProblem: {
113
124
  name: 'verify_grep_theater',
@@ -115,7 +126,7 @@ export const CRITIQUE_PROBES = [
115
126
  }
116
127
  }),
117
128
  probe({
118
- // mx5 run 13, PROMPT 4 item 4: a spec that DICTATES a check script which
129
+ // A spec that DICTATES a check script which
119
130
  // cannot fail — `"lint": "… || true"`, or a checker laundered through an
120
131
  // inverted grep. Whatever task implements that spec writes the disarmed
121
132
  // script into package.json, and from then on every gate that runs it
@@ -1,10 +1,13 @@
1
1
  import { type DebugLogLevel } from '../config/config.js';
2
2
  /**
3
3
  * Escape hatch for reproducing a user's bug without walking them through
4
- * /task-config. Follows the existing `PI_TASK_*` instrumentation convention
5
- * (`PI_TASK_TYPEONLY_LOG`, `PI_REMOTE_PUSH_DEBUG`). An unrecognised value is
6
- * ignored rather than treated as `off` — a typo in an env var must not silently
7
- * throw the trail away.
4
+ * /task-config. Follows the `PI_TASK_*` instrumentation convention this codebase
5
+ * already uses in nine places, `PI_TASK_TYPEONLY_LOG` among them.
6
+ *
7
+ * An unrecognised value is IGNORED rather than treated as `off` — a typo in an env
8
+ * var must not silently throw the trail away. Run: `full` and `off` both take
9
+ * effect, surrounding whitespace is tolerated, and `verbose` falls through to the
10
+ * saved config instead of resolving to anything.
8
11
  */
9
12
  export declare const DEBUG_LOG_ENV = "PI_TASK_DEBUG_LOG";
10
13
  /** A trail line's kind — see the module note. Producers default to `'event'`. */
@@ -15,7 +18,9 @@ export type DebugLine = 'event' | 'stream';
15
18
  * line instead of at the next restart.
16
19
  */
17
20
  export declare function debugLogLevel(getEnv?: (k: string) => string | undefined): DebugLogLevel;
18
- /** Whether a line of this kind should be written at `level`. */
21
+ /** Whether a line of this kind should be written at `level`. The whole matrix:
22
+ * `off` writes nothing, `full` writes both kinds, `events` writes events and
23
+ * drops stream. */
19
24
  export declare function shouldLogDebug(kind: DebugLine, level: DebugLogLevel): boolean;
20
25
  /**
21
26
  * A timestamped fire-and-forget appender for one trail file, level-gated.
@@ -30,5 +35,8 @@ export declare function makeDebugAppender(logPath: string, appendFile?: (p: stri
30
35
  * Wrap a raw append in the level gate. Returns `undefined` when the level is
31
36
  * `off`, so callers that hold an OPTIONAL `logDebug` leave it unset and every
32
37
  * `logDebug?.(…)` in the pipeline short-circuits before it formats a string.
38
+ *
39
+ * Run: undefined at `off`, a function otherwise, and at `events` it writes an
40
+ * event line while dropping a stream one.
33
41
  */
34
42
  export declare function gateDebugWriter(write: (msg: string) => void, getEnv?: (k: string) => string | undefined): ((msg: string, kind?: DebugLine) => void) | undefined;
@@ -1,38 +1,45 @@
1
1
  /**
2
2
  * One place that decides whether a `.pi-tasks/*-debug.log` line gets written.
3
3
  *
4
- * THE TRAIL IS WRITE-ONLY. Nothing in pi-task reads these files back: `task-io.ts`
5
- * globs `TASK_NNNN.md` and skips everything else, and auto-commit's `snapshotTrail`
6
- * copies the bytes across a `reset --hard` without ever parsing them. Every producer
7
- * is a `logDebug?.(…)` / `log(…)` side effect whose return value is discarded. So
8
- * this gate cannot change what a run DOES — only what it can explain afterwards.
4
+ * THE TRAIL IS WRITE-ONLY in production. Nothing under src/ reads these files
5
+ * back: `task-io.ts` globs `TASK_NNNN.md` and skips everything else, and
6
+ * auto-commit's `snapshotTrail` copies the bytes across a `reset --hard` without
7
+ * ever parsing them. Every producer is a `logDebug?.(…)` / `log(…)` side effect
8
+ * whose return value is discarded. So this gate cannot change what a run DOES —
9
+ * only what it can explain afterwards. (Tests do read the trail back, which is why
10
+ * `flushPlanDebug` exists.)
9
11
  *
10
12
  * TWO KINDS OF LINE, and the distinction is the whole point of having three levels
11
13
  * rather than a boolean:
12
14
  *
13
- * 'stream' — what the child model said, and what its tools returned. Reproducible
14
- * by re-running, useful while you are actively debugging, and 85% of the
15
- * bytes (measured: a 247 KB IAR1 `verify-debug.log` is 1315 lines, of
16
- * which 521 are `↳` tool dumps and most of the rest is raw model text).
15
+ * 'stream' — what the child model said, and what its tools returned. It is the
16
+ * bulk of the bytes by a wide margin, and it is REPRODUCIBLE: re-run
17
+ * the child and you get it again. Useful while actively debugging,
18
+ * worthless as a record.
17
19
  *
18
20
  * 'event' — a decision or a guard action: which phase started, why a worker was
19
21
  * retried or degraded, what the git-state guard restored, what a
20
- * write-capable child changed on disk, why a gate returned FAIL. Ten-ish
21
- * lines per task, and NOT reproducible — it is the only record that the
22
- * guard fired at all. mx5 run 11's final-fix child deleted a source file
23
- * and the `tree changes:` line is the reason anyone could tell.
22
+ * write-capable child changed on disk, why a gate returned FAIL. A
23
+ * handful of lines per task, and NOT reproducible — it is the only
24
+ * record that the guard fired at all. If a final-fix child deletes a
25
+ * source file, the `tree changes:` line is the only way anyone can
26
+ * tell.
24
27
  *
25
- * Hence the default is `events`, not `off`: the quiet default users want costs the
26
- * chatter, not the audit trail.
28
+ * Hence the shipped default is `events`, not `off` (DEFAULT_DEBUG_LOGS in
29
+ * config.ts): the quiet default users want costs the chatter, not the audit trail.
30
+ * A machine-local `"debugLogs": "off"` still wins — this is a default, not a floor.
27
31
  */
28
32
  import * as fsp from 'node:fs/promises';
29
33
  import { getConfig, sanitizeDebugLogs } from '../config/config.js';
30
34
  /**
31
35
  * Escape hatch for reproducing a user's bug without walking them through
32
- * /task-config. Follows the existing `PI_TASK_*` instrumentation convention
33
- * (`PI_TASK_TYPEONLY_LOG`, `PI_REMOTE_PUSH_DEBUG`). An unrecognised value is
34
- * ignored rather than treated as `off` — a typo in an env var must not silently
35
- * throw the trail away.
36
+ * /task-config. Follows the `PI_TASK_*` instrumentation convention this codebase
37
+ * already uses in nine places, `PI_TASK_TYPEONLY_LOG` among them.
38
+ *
39
+ * An unrecognised value is IGNORED rather than treated as `off` — a typo in an env
40
+ * var must not silently throw the trail away. Run: `full` and `off` both take
41
+ * effect, surrounding whitespace is tolerated, and `verbose` falls through to the
42
+ * saved config instead of resolving to anything.
36
43
  */
37
44
  export const DEBUG_LOG_ENV = 'PI_TASK_DEBUG_LOG';
38
45
  /**
@@ -49,7 +56,9 @@ export function debugLogLevel(getEnv = k => process.env[k]) {
49
56
  return raw;
50
57
  return getConfig().debugLogs;
51
58
  }
52
- /** Whether a line of this kind should be written at `level`. */
59
+ /** Whether a line of this kind should be written at `level`. The whole matrix:
60
+ * `off` writes nothing, `full` writes both kinds, `events` writes events and
61
+ * drops stream. */
53
62
  export function shouldLogDebug(kind, level) {
54
63
  if (level === 'off')
55
64
  return false;
@@ -76,6 +85,9 @@ export function makeDebugAppender(logPath, appendFile = (p, data) => fsp.appendF
76
85
  * Wrap a raw append in the level gate. Returns `undefined` when the level is
77
86
  * `off`, so callers that hold an OPTIONAL `logDebug` leave it unset and every
78
87
  * `logDebug?.(…)` in the pipeline short-circuits before it formats a string.
88
+ *
89
+ * Run: undefined at `off`, a function otherwise, and at `events` it writes an
90
+ * event line while dropping a stream one.
79
91
  */
80
92
  export function gateDebugWriter(write, getEnv) {
81
93
  if (debugLogLevel(getEnv) === 'off')
@@ -7,15 +7,17 @@ export interface SourcedTitle {
7
7
  /**
8
8
  * Split a decompose title into its base and its GROUNDED source citations.
9
9
  *
10
- * PLURAL, because the model emits plural. The prompt asks for one trailing
11
- * citation and a quarter of real titles carry more 62 of 244 across the 20
12
- * recorded runs. The old pattern was `\[source:\s*"(.+)"\]$`: greedy `.+`
13
- * against an end anchor, so on `[source: "A"] [source: "B"]` it matched from the
14
- * FIRST clause to the LAST quote and produced the superstring `A"] [source: "B`,
15
- * which of course is not in the document. Two real citations became one
16
- * fabricated one, and both were discarded. Peeling from the end with
17
- * lastIndexOf is the fix; a lazy quantifier is NOT, because leftmost-first
18
- * matching plus the `$` anchor expands it across the later clauses just the same.
10
+ * PLURAL, because the model emits plural: the prompt asks for one trailing
11
+ * citation and a real share of titles carry more than one.
12
+ *
13
+ * A single anchored pattern cannot read them. Run on `[source: "A"] [source: "B"]`,
14
+ * `\[source:\s*"(.+)"\]$` captures the superstring `A"] [source: "B` — from the
15
+ * FIRST clause to the LAST quote — which is of course not in the document, so two
16
+ * real citations become one fabricated one and both are discarded. Making the
17
+ * quantifier LAZY changes nothing: `(.+?)` against the same input captures the
18
+ * identical superstring, because leftmost-first matching plus the `$` anchor
19
+ * expands it across the later clauses just the same. Peeling from the end with
20
+ * lastIndexOf is what actually works — confirmed, both citations come back.
19
21
  *
20
22
  * An absent clause yields no sources; a fabricated (ungrounded) one is dropped
21
23
  * — exactly like keepGroundedContracts rejects a paraphrased quote.