@mjasnikovs/pi-task 0.38.28 → 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 +25 -7
  104. package/dist/task/context-usage.js +21 -6
  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 +37 -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 +180 -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 +33 -36
  231. package/dist/task/research-worker.js +39 -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 +86 -54
  338. package/dist/workers/pi-worker-core.js +112 -112
  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 +23 -10
  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
@@ -5,25 +5,24 @@
5
5
  * Why this module exists. `RunWorkerResult` reports each kill cause as its own
6
6
  * optional field (`loopHit`, `timedOut`, `stalled`, `commandTimedOut`,
7
7
  * `streamStalled`, `leakedToolCall`, `aborted`, `exitCode`), and every kill path
8
- * ALSO sets `aborted` and a non-zero exit — killProc flips those on every route
9
- * out. So a consumer cannot read the fields in any order it likes: the specific
10
- * causes must be matched before the generic `aborted`/`exitCode` ones, or a dead
11
- * backend is reported to the user as "you cancelled".
8
+ * ALSO sets the two generic ones. `killProc` sets `aborted` on every route out,
9
+ * and pi's own print/json mode installs a SIGTERM handler that exits 143, so a
10
+ * terminated child carries a non-zero exit too. So a consumer cannot read the
11
+ * fields in any order it likes: the specific causes must be matched before the
12
+ * generic `aborted`/`exitCode` ones, or a dead backend is reported to the user as
13
+ * "you cancelled".
12
14
  *
13
- * That rule used to live as prose in three doc comments and as the source order
14
- * of three hand-written ladders (`classifyEnforceChildFailure`,
15
- * `classifyResearchWorker`, and the gate's own reading). Three copies of an
16
- * ordering is three chances to drift, and it had already drifted: `streamStalled`
17
- * was added to the result and to `finalAttemptFailed`, but the enforce ladder
18
- * never grew an arm for it, so an enforcement child killed for a hung model
19
- * stream fell all the way through to `if (aborted) return USER_CANCELLED` — the
20
- * exact mislabel the comment above that line warns against.
15
+ * Written as prose, or as the source order of each consumer's own hand-rolled
16
+ * ladder, that rule gets a fresh chance to drift per consumer — and the failure is
17
+ * silent: add a new kill cause to the result, forget one ladder's arm for it, and
18
+ * that consumer falls through to `if (aborted)` and reports a cancel.
21
19
  *
22
- * The fix is to make the order data. `FAILURE_RULES` is ordered, the first
23
- * matching row wins, and consumers `switch` on the resulting `kind` instead of
24
- * re-deriving the ladder. A new kill cause is one row here plus a compile error
25
- * in every consumer that has not handled it which is what makes the drift that
26
- * caused the bug impossible rather than merely fixed.
20
+ * So the order is DATA. `FAILURE_RULES` is ordered, the first matching row wins,
21
+ * and consumers `switch` on the resulting `kind` `classifyEnforceChildFailure`
22
+ * (enforce-guidelines.ts) and `classifyResearchWorker` (research-worker.ts) both
23
+ * call `classifyWorkerFailure` and say only what each cause means to THEM. A new
24
+ * kill cause is one row here plus a compile error in every consumer that has not
25
+ * handled it.
27
26
  */
28
27
  const _kindsAreKills = true;
29
28
  void _kindsAreKills;
@@ -45,9 +44,8 @@ void _kindsAreKills;
45
44
  * class of event: a watchdog, not the model, ended the attempt.
46
45
  * 4. `worker-timeout` — the wall-clock backstop.
47
46
  * 5. `loop` — killed for repeating one tool call past threshold. After the
48
- * timeouts, matching the enforce ladder this replaces; in practice the two
49
- * cannot both fire, since a loop kill stops the attempt before its own timer
50
- * can expire.
47
+ * timeouts: a loop kill ends the attempt, so its own timer does not go on to
48
+ * expire as well.
51
49
  * 6. `leaked-tool-call` — the model wrote a call as prose instead of invoking
52
50
  * it. Only ever set on an otherwise clean run.
53
51
  * 7. `aborted` — no specific cause survived, so this really is a cancel.
@@ -78,31 +76,20 @@ export const FAILURE_RULES = [
78
76
  { id: 'aborted', match: r => (r.aborted ? { kind: 'aborted' } : null) },
79
77
  { id: 'exit', match: r => (r.exitCode !== 0 ? { kind: 'exit', code: r.exitCode } : null) }
80
78
  ];
81
- /**
82
- * Classify a finished child. Returns `undefined` when nothing killed it —
83
- * which is not the same as "it answered": the text may still be empty, and that
84
- * judgement belongs to the caller.
85
- */
86
79
  /**
87
80
  * What a worker failure SAYS to the caller that asked for the work.
88
81
  *
89
- * WHY IT EXISTS. The ladder above already names the cause exactly, with its
90
- * detail — which tool hung, how long the stream was idle, which exit code. None
91
- * of that reached a human. `formatChildFailure` was handed a `ChildOutcome`
92
- * (`{aborted, exitCode, stderr}`) and answered `if (aborted) return
93
- * abortedMessage`, so a 240s wall-clock kill, a hung `bash`, a dead model
94
- * backend, a loop kill and a user pressing ESC all printed the SAME four words.
95
- * The discriminating value was computed a line later by `childFailureReason` and
96
- * put in the debug trail, which a user reading a tool result never sees.
97
- *
98
- * That is not only unhelpful; it is why the `pi-worker` tool's 240s cap has no
99
- * base rate. 53 recorded invocations across eight repos carry 14 failures, and
100
- * NOTHING in the transcript says which of them ran out of time — the honest
101
- * bound recoverable from timestamps alone is "somewhere between 0 and 8".
82
+ * WHY IT EXISTS. The ladder above already names the cause exactly, with its detail
83
+ * — which tool hung, how long the stream was idle, which exit code. Answering
84
+ * `if (aborted) return abortedMessage` instead throws all of it away: a wall-clock
85
+ * kill, a hung `bash`, a dead model backend, a loop kill and a user pressing ESC
86
+ * then print the SAME words, and the discriminating value only reaches a debug
87
+ * trail a user reading a tool result never sees. Every arm below returns a
88
+ * different message, and only `aborted` returns the caller's own.
102
89
  *
103
90
  * A switch, not a table: `WorkerFailure` is a discriminated union carrying a
104
91
  * different payload per arm, so the exhaustiveness check is the compiler's and a
105
- * ninth arm cannot be added without a message.
92
+ * new arm cannot be added without a message.
106
93
  */
107
94
  export function describeWorkerFailure(f,
108
95
  /** What a genuine user cancel says. The caller's wording — only this arm is theirs. */
@@ -137,6 +124,11 @@ stderr = '') {
137
124
  return `Worker exited ${f.code}.\n${stderr.trim().slice(-500) || '(no stderr)'}`;
138
125
  }
139
126
  }
127
+ /**
128
+ * Classify a finished child against the ladder. Returns `undefined` when nothing
129
+ * killed it — which is not the same as "it answered": the text may still be empty,
130
+ * and that judgement belongs to the caller.
131
+ */
140
132
  export function classifyWorkerFailure(r) {
141
133
  for (const rule of FAILURE_RULES) {
142
134
  const hit = rule.match(r);
@@ -1,31 +1,28 @@
1
1
  /**
2
2
  * The ROSTER of ways a worker child can die, and what each one implies.
3
3
  *
4
- * WHY IT EXISTS. One kill cause was named in six unlinked places: a
4
+ * WHY IT EXISTS. Without it, one kill cause is named in six unlinked places: a
5
5
  * `RunWorkerInput` guard option, a `RunWorkerResult` field, the
6
- * `WorkerRestartReason` union, a `RESTART_RULES` row, the `CARRY_FORWARD_REASONS`
7
- * set, and a `FAILURE_RULES` row. Adding one meant six coordinated edits, and
8
- * only two of them failed to compile if you skipped one. That is not
9
- * hypothetical: `worker-failure.ts`'s own header records the bug it cost
10
- * *"`streamStalled` was added to the result and to `finalAttemptFailed`, but the
11
- * enforce ladder never grew an arm for it, so an enforcement child killed for a
12
- * hung model stream fell all the way through to `if (aborted) return
13
- * USER_CANCELLED`"*. That fix closed the READER side. This closes the author
14
- * side.
6
+ * `WorkerRestartReason` union, a `RESTART_RULES` row, the carry-forward set, and a
7
+ * `FAILURE_RULES` row. Adding a cause is six coordinated edits, and most of them
8
+ * still compile if one is skipped so the new cause simply does not exist on
9
+ * whichever path was missed. `worker-failure.ts` closes the READER side of that;
10
+ * this closes the AUTHOR side.
15
11
  *
16
12
  * WHAT IS AND IS NOT UNIFIED. The roster is one table. The two ORDERINGS stay
17
13
  * two, because they genuinely disagree and each says so in its own prose: the
18
14
  * restart ladder puts `loop` first (its hint is the most specific thing to tell a
19
- * re-spawn), and the failure ladder puts `stalled` first (the diagnosis most
20
- * easily lost behind the `aborted` every kill path sets). Folding two
21
- * precedences into one row type would need an escape hatch per row the same
22
- * objection that got a `WriteGuard` row table rejected. What the orderings gain
23
- * here is that neither can name a cause with no row, nor silently omit one.
15
+ * re-spawn), and the failure ladder puts `stalled` first (the diagnosis most easily
16
+ * lost behind the `aborted` every kill path sets). Folding two precedences into one
17
+ * row type would need an escape hatch per row. What the orderings gain here is that
18
+ * neither can name a cause with no row, nor silently omit one.
24
19
  *
25
- * Not every cause appears in both ladders, and that asymmetry is real:
26
- * `connection-error` is restartable but is reported as a `modelError`, never as a
27
- * kill; `stalled`, `aborted` and `exit` end an attempt outright and no hint would
28
- * help.
20
+ * Not every cause appears in both ladders, and that asymmetry is real. Six of the
21
+ * nine are `restartable` and those six are exactly RESTART_ORDER; eight are
22
+ * `reported` and those eight are exactly FAILURE_ORDER. `connection-error` is the
23
+ * one that restarts without ever being reported as a kill — it reaches the caller
24
+ * as a `modelError`. `stalled`, `aborted` and `exit` end an attempt outright, and
25
+ * no hint would help.
29
26
  */
30
27
  /** Every way a worker attempt can end other than by answering. */
31
28
  export type WorkerKillId = 'stalled' | 'command-timeout' | 'stream-stall' | 'worker-timeout' | 'connection-error' | 'loop' | 'leaked-tool-call' | 'aborted' | 'exit';
@@ -37,18 +34,20 @@ export interface WorkerKill {
37
34
  * (`connection-error` arrives as `modelError`; `aborted` and `exit` are the
38
35
  * generic fields every kill path also sets).
39
36
  *
40
- * A string rather than `keyof RunWorkerResult` so this module stays free of
41
- * pi-worker-core's import graph; `worker-kill.test.ts` checks it against the
42
- * real interface.
37
+ * Null for three rows: `connection-error`, `aborted` and `exit`. A string rather
38
+ * than `keyof RunWorkerResult` so this module stays out of pi-worker-core's
39
+ * import graph; worker-kill.test.ts checks every non-null one against a real
40
+ * result object.
43
41
  */
44
42
  resultField: string | null;
45
43
  /**
46
44
  * Is a killed attempt's partial output worth carrying into the next one?
47
45
  *
48
- * A clock kill, a hung tool, an idle stream and a dropped socket all discard
49
- * work the model genuinely did. A loop kill and a leaked tool call do not —
50
- * the first is by definition the same call repeated, the second is malformed
51
- * protocol text, and replaying either would feed the failure back to itself.
46
+ * True for exactly four: a clock kill, a hung tool, an idle stream and a dropped
47
+ * socket all discard work the model genuinely did. A loop kill and a leaked tool
48
+ * call do not — the first is by definition the same call repeated, the second is
49
+ * malformed protocol text, and replaying either would feed the failure back to
50
+ * itself.
52
51
  */
53
52
  carryForward: boolean;
54
53
  /** Does the restart ladder have a rule for this cause? */
@@ -1,31 +1,28 @@
1
1
  /**
2
2
  * The ROSTER of ways a worker child can die, and what each one implies.
3
3
  *
4
- * WHY IT EXISTS. One kill cause was named in six unlinked places: a
4
+ * WHY IT EXISTS. Without it, one kill cause is named in six unlinked places: a
5
5
  * `RunWorkerInput` guard option, a `RunWorkerResult` field, the
6
- * `WorkerRestartReason` union, a `RESTART_RULES` row, the `CARRY_FORWARD_REASONS`
7
- * set, and a `FAILURE_RULES` row. Adding one meant six coordinated edits, and
8
- * only two of them failed to compile if you skipped one. That is not
9
- * hypothetical: `worker-failure.ts`'s own header records the bug it cost
10
- * *"`streamStalled` was added to the result and to `finalAttemptFailed`, but the
11
- * enforce ladder never grew an arm for it, so an enforcement child killed for a
12
- * hung model stream fell all the way through to `if (aborted) return
13
- * USER_CANCELLED`"*. That fix closed the READER side. This closes the author
14
- * side.
6
+ * `WorkerRestartReason` union, a `RESTART_RULES` row, the carry-forward set, and a
7
+ * `FAILURE_RULES` row. Adding a cause is six coordinated edits, and most of them
8
+ * still compile if one is skipped so the new cause simply does not exist on
9
+ * whichever path was missed. `worker-failure.ts` closes the READER side of that;
10
+ * this closes the AUTHOR side.
15
11
  *
16
12
  * WHAT IS AND IS NOT UNIFIED. The roster is one table. The two ORDERINGS stay
17
13
  * two, because they genuinely disagree and each says so in its own prose: the
18
14
  * restart ladder puts `loop` first (its hint is the most specific thing to tell a
19
- * re-spawn), and the failure ladder puts `stalled` first (the diagnosis most
20
- * easily lost behind the `aborted` every kill path sets). Folding two
21
- * precedences into one row type would need an escape hatch per row the same
22
- * objection that got a `WriteGuard` row table rejected. What the orderings gain
23
- * here is that neither can name a cause with no row, nor silently omit one.
15
+ * re-spawn), and the failure ladder puts `stalled` first (the diagnosis most easily
16
+ * lost behind the `aborted` every kill path sets). Folding two precedences into one
17
+ * row type would need an escape hatch per row. What the orderings gain here is that
18
+ * neither can name a cause with no row, nor silently omit one.
24
19
  *
25
- * Not every cause appears in both ladders, and that asymmetry is real:
26
- * `connection-error` is restartable but is reported as a `modelError`, never as a
27
- * kill; `stalled`, `aborted` and `exit` end an attempt outright and no hint would
28
- * help.
20
+ * Not every cause appears in both ladders, and that asymmetry is real. Six of the
21
+ * nine are `restartable` and those six are exactly RESTART_ORDER; eight are
22
+ * `reported` and those eight are exactly FAILURE_ORDER. `connection-error` is the
23
+ * one that restarts without ever being reported as a kill — it reaches the caller
24
+ * as a `modelError`. `stalled`, `aborted` and `exit` end an attempt outright, and
25
+ * no hint would help.
29
26
  */
30
27
  export const WORKER_KILLS = [
31
28
  {
@@ -2,25 +2,14 @@
2
2
  * The GUARD POLICY each kind of worker child runs under, keyed on the ways it
3
3
  * can die.
4
4
  *
5
- * WHY IT EXISTS. `RunWorkerInput` carried ten guard knobs in four different
6
- * shapes two bare millisecond numbers, three `{...} | false` unions, an
7
- * optional object, a boolean and two counts and three production callers each
8
- * hand-picked a different subset of them:
9
- *
10
- * gate-child.ts timeoutMs 0, a per-command watchdog, a stream watchdog,
11
- * and the path rule disabled. Everything else default.
12
- * research-worker.ts a progress deadline and two off-by-default A/B levers.
13
- * NO command watchdog, NO stream watchdog. Everything else
14
- * default.
15
- * pi-worker.ts nothing at all — every default, silently.
16
- *
17
- * So "a gate child runs unbounded but with a per-command watchdog; a research
18
- * worker is the reverse" existed only as three option literals in three files,
19
- * and the reasoning was attached to whichever line happened to need defending.
20
- * `gate-child.ts` explained why it disables the path rule and said nothing about
21
- * why it takes no progress deadline. Nothing anywhere said that the ad-hoc
22
- * `pi-worker` tool is the strictest-clocked of the three. That was not a
23
- * decision; it was the residue of never having had a place to write one down.
5
+ * WHY IT EXISTS. As independent options on `RunWorkerInput`, ten guard knobs in
6
+ * four different shapes, each of the three production callers hand-picks its own
7
+ * subset and "a gate child runs unbounded but with a per-command watchdog; a
8
+ * research worker is the reverse" then exists only as three option literals in
9
+ * three files. The reasoning attaches to whichever line happened to need
10
+ * defending, a caller that names nothing gets a full policy silently, and no file
11
+ * is the place to say which child is the strictest-clocked of the three. That is
12
+ * not a decision; it is the residue of having nowhere to write one down.
24
13
  *
25
14
  * WHY IT IS KEYED ON `WorkerKillId`. A guard exists to prevent a specific way a
26
15
  * child can die, so the roster of deaths (`worker-kill.ts`) is the correct key —
@@ -55,8 +44,8 @@
55
44
  * silently re-level a gate child, which is the exact mistake
56
45
  * `RunWorkerInput.thinking`'s comment already records.
57
46
  *
58
- * `projectDocsBudget()` (the CAP arm, research-fanout-budget.ts) stays out. It
59
- * bounds what a worker ASKS FOR, via its prompt and its tool, not how it dies.
47
+ * `projectDocsBudget()` (research-fanout-budget.ts) stays out. It bounds what a
48
+ * worker ASKS FOR, via its prompt and its tool, not how it dies.
60
49
  *
61
50
  * `RESTART_ORDER` and `FAILURE_ORDER` are untouched. This is a third view of
62
51
  * the same key, not a merge of the two orderings.
@@ -67,18 +56,20 @@ import type { WorkerKillId } from './worker-kill.js';
67
56
  * LoopDetector only catches *identical* repeated tool calls; a model that
68
57
  * thrashes with slightly-varied calls (different grep patterns each time) slips
69
58
  * past it and would otherwise run unbounded. This is the backstop for that case:
70
- * after this long with no clean exit, abort and restart with a hint. Sized well
71
- * above a healthy worker's observed runtime (~25-130s on the local backend) so
72
- * it never trips a legitimately slow run.
59
+ * after this long with no clean exit, abort and restart with a hint.
60
+ *
61
+ * A fixed elapsed-time cap is a poor bound on a read-only worker — see the
62
+ * `adhoc` profile's `why`, which is why that profile disables it. The two
63
+ * profiles that keep it pair it with a progress ceiling or accept the trade.
73
64
  */
74
65
  export declare const RESEARCH_WORKER_TIMEOUT_MS = 240000;
75
66
  /**
76
- * Output-stall window before the dead-backend probe fires (mx5 run 7: model
77
- * server died mid-gate-child, the child hung MUTE for 64 minutes). This is NOT
78
- * a wall-clock cap — output progress resets it, and even a fully stalled child
79
- * is only killed when the model endpoint is actually unreachable. Sized so a
80
- * long local prompt-processing pass (minutes of legitimate silence, server
81
- * alive) just gets probed and waits on.
67
+ * Output-stall window before the dead-backend probe fires: a model server that
68
+ * dies mid-child leaves it hung MUTE with nothing else to notice. This is NOT a
69
+ * wall-clock cap — output progress resets it, and even a fully stalled child is
70
+ * killed only when the model endpoint is actually unreachable. Sized so a long
71
+ * local prompt-processing pass, which is minutes of legitimate silence from a
72
+ * live server, gets probed and then waited on.
82
73
  */
83
74
  export declare const STALL_AFTER_MS = 180000;
84
75
  /**
@@ -111,8 +102,8 @@ export interface StalledGuard {
111
102
  * bigger file — and must not cost the user their answer; the second is a real
112
103
  * fault, and one the dead-backend probe already catches on its own terms.
113
104
  *
114
- * `fanout` is the SCALE arm of nexttask 5B and is OFF unless both its env vars
115
- * are set see task/research-fanout-budget.ts for why it was not the fix.
105
+ * `fanout` is off unless BOTH of its env vars are set `fanoutTimeoutPolicy`
106
+ * returns null when either the per-lookup or the ceiling value is missing.
116
107
  */
117
108
  export interface WorkerTimeoutGuard {
118
109
  /** 0 disables the wall clock entirely: the child runs until it exits. */
@@ -138,15 +129,13 @@ export interface WorkerTimeoutGuard {
138
129
  *
139
130
  * `detector` judges ARGUMENTS over a 20-call window, so a child that rotates
140
131
  * through MORE DISTINCT CALLS THAN THE WINDOW HOLDS is invisible to it — every
141
- * key occurs once per window and the count never reaches the threshold.
142
- * Measured: mx5-n 2026-08-27, worker:tooling made 550 calls over exactly 20
143
- * distinct files, ~36 reads each, and neither the exact rule nor the path rule
144
- * ever tripped. It died 20 minutes later on the absolute progress ceiling,
145
- * having done 25s of useful work.
132
+ * key occurs once per window and the count never reaches the threshold. A worker
133
+ * rotating over as many distinct files as the window holds can re-read every one
134
+ * of them repeatedly without either the exact rule or the path rule tripping, and
135
+ * then die on the absolute deadline having produced almost nothing.
146
136
  *
147
- * `progress` judges RESULTS, which a rotating reader cannot vary. It was written
148
- * for exactly that class and was wired only into phase children until
149
- * `runWorker` grew an option for it.
137
+ * `progress` judges RESULTS, which a rotating reader cannot vary. It is the rule
138
+ * written for exactly that class.
150
139
  *
151
140
  * Either can be `false` independently — a pass that legitimately revisits one
152
141
  * file raises `pathThreshold`; a harness isolating one rule turns the other off.
@@ -192,20 +181,19 @@ interface WorkerGuardShapes {
192
181
  /**
193
182
  * Stream-inactivity ceiling, ms (shared/stream-watchdog.ts). 0 = off.
194
183
  *
195
- * The dead-backend probe cannot catch a HUNG stream on a HEALTHY backend
196
- * it reads a reachable endpoint as proof of life, which is exactly what run
197
- * 14's three hangs looked like. This one asks nothing of the backend: no
198
- * output for this long, tool executions excluded, means kill and restart the
199
- * attempt with `streamStallHint`, inside the same shared restart budget.
184
+ * The dead-backend probe cannot catch a HUNG stream on a HEALTHY backend: it
185
+ * reads a reachable endpoint as proof of life, which a hung stream leaves
186
+ * intact. This one asks nothing of the backend no output for this long, tool
187
+ * executions excluded, means kill and restart the attempt with
188
+ * `streamStallHint`, inside the same shared restart budget.
200
189
  */
201
190
  'stream-stall': number;
202
191
  'worker-timeout': WorkerTimeoutGuard;
203
192
  /**
204
193
  * Connection-error restart budget. The SHARED restart counter is what
205
- * actually binds — a worker that already spent the budget looping does not
206
- * get extra lives here. 0 turns the retry off, which is how
207
- * `scripts/connection-retry-ab.ts` gets a baseline arm out of a build that
208
- * already ships the retry.
194
+ * actually binds — a worker that already spent the budget looping does not get
195
+ * extra lives here. 0 turns the retry off entirely, which is how a harness
196
+ * obtains a no-retry arm from a build that ships the retry.
209
197
  */
210
198
  'connection-error': number;
211
199
  loop: LoopGuard;
@@ -266,7 +254,8 @@ export interface WorkerPolicyInputs {
266
254
  streamInactivityMs?: number;
267
255
  /** research: only `worker:apis` fans out, so only it can be scaled. */
268
256
  fanoutBounded?: boolean;
269
- /** research: the A/B levers' env reader. Injectable for tests. */
257
+ /** research: the env reader the fanout and progress-ceiling levers use.
258
+ * Injectable so a test does not depend on the machine's environment. */
270
259
  env?: (key: string) => string | undefined;
271
260
  }
272
261
  export interface WorkerProfile {
@@ -306,9 +295,10 @@ export declare function workerPolicy(id: WorkerProfileId, inputs?: WorkerPolicyI
306
295
  /**
307
296
  * Lay whole rows over a resolved policy.
308
297
  *
309
- * For tests and A/B harnesses ONLY. Production code names a profile: an override
310
- * at a production call site is the exact "hand-pick a subset" this module exists
311
- * to stop, and `worker-profiles.test.ts` fails the build if one appears.
298
+ * For tests and harnesses ONLY. Production code names a profile: an override at a
299
+ * production call site is the exact "hand-pick a subset" this module exists to
300
+ * stop, and worker-profiles.test.ts scans src/ for a leading `override:` and fails
301
+ * on any hit.
312
302
  */
313
303
  export declare function applyOverride(policy: WorkerGuardPolicy, override: WorkerGuardOverride | undefined): WorkerGuardPolicy;
314
304
  export {};
@@ -2,25 +2,14 @@
2
2
  * The GUARD POLICY each kind of worker child runs under, keyed on the ways it
3
3
  * can die.
4
4
  *
5
- * WHY IT EXISTS. `RunWorkerInput` carried ten guard knobs in four different
6
- * shapes two bare millisecond numbers, three `{...} | false` unions, an
7
- * optional object, a boolean and two counts and three production callers each
8
- * hand-picked a different subset of them:
9
- *
10
- * gate-child.ts timeoutMs 0, a per-command watchdog, a stream watchdog,
11
- * and the path rule disabled. Everything else default.
12
- * research-worker.ts a progress deadline and two off-by-default A/B levers.
13
- * NO command watchdog, NO stream watchdog. Everything else
14
- * default.
15
- * pi-worker.ts nothing at all — every default, silently.
16
- *
17
- * So "a gate child runs unbounded but with a per-command watchdog; a research
18
- * worker is the reverse" existed only as three option literals in three files,
19
- * and the reasoning was attached to whichever line happened to need defending.
20
- * `gate-child.ts` explained why it disables the path rule and said nothing about
21
- * why it takes no progress deadline. Nothing anywhere said that the ad-hoc
22
- * `pi-worker` tool is the strictest-clocked of the three. That was not a
23
- * decision; it was the residue of never having had a place to write one down.
5
+ * WHY IT EXISTS. As independent options on `RunWorkerInput`, ten guard knobs in
6
+ * four different shapes, each of the three production callers hand-picks its own
7
+ * subset and "a gate child runs unbounded but with a per-command watchdog; a
8
+ * research worker is the reverse" then exists only as three option literals in
9
+ * three files. The reasoning attaches to whichever line happened to need
10
+ * defending, a caller that names nothing gets a full policy silently, and no file
11
+ * is the place to say which child is the strictest-clocked of the three. That is
12
+ * not a decision; it is the residue of having nowhere to write one down.
24
13
  *
25
14
  * WHY IT IS KEYED ON `WorkerKillId`. A guard exists to prevent a specific way a
26
15
  * child can die, so the roster of deaths (`worker-kill.ts`) is the correct key —
@@ -55,8 +44,8 @@
55
44
  * silently re-level a gate child, which is the exact mistake
56
45
  * `RunWorkerInput.thinking`'s comment already records.
57
46
  *
58
- * `projectDocsBudget()` (the CAP arm, research-fanout-budget.ts) stays out. It
59
- * bounds what a worker ASKS FOR, via its prompt and its tool, not how it dies.
47
+ * `projectDocsBudget()` (research-fanout-budget.ts) stays out. It bounds what a
48
+ * worker ASKS FOR, via its prompt and its tool, not how it dies.
60
49
  *
61
50
  * `RESTART_ORDER` and `FAILURE_ORDER` are untouched. This is a third view of
62
51
  * the same key, not a merge of the two orderings.
@@ -69,18 +58,20 @@ import { fanoutTimeoutPolicy, workerCarryForward, workerProgressCeilingMs } from
69
58
  * LoopDetector only catches *identical* repeated tool calls; a model that
70
59
  * thrashes with slightly-varied calls (different grep patterns each time) slips
71
60
  * past it and would otherwise run unbounded. This is the backstop for that case:
72
- * after this long with no clean exit, abort and restart with a hint. Sized well
73
- * above a healthy worker's observed runtime (~25-130s on the local backend) so
74
- * it never trips a legitimately slow run.
61
+ * after this long with no clean exit, abort and restart with a hint.
62
+ *
63
+ * A fixed elapsed-time cap is a poor bound on a read-only worker — see the
64
+ * `adhoc` profile's `why`, which is why that profile disables it. The two
65
+ * profiles that keep it pair it with a progress ceiling or accept the trade.
75
66
  */
76
67
  export const RESEARCH_WORKER_TIMEOUT_MS = 240_000;
77
68
  /**
78
- * Output-stall window before the dead-backend probe fires (mx5 run 7: model
79
- * server died mid-gate-child, the child hung MUTE for 64 minutes). This is NOT
80
- * a wall-clock cap — output progress resets it, and even a fully stalled child
81
- * is only killed when the model endpoint is actually unreachable. Sized so a
82
- * long local prompt-processing pass (minutes of legitimate silence, server
83
- * alive) just gets probed and waits on.
69
+ * Output-stall window before the dead-backend probe fires: a model server that
70
+ * dies mid-child leaves it hung MUTE with nothing else to notice. This is NOT a
71
+ * wall-clock cap — output progress resets it, and even a fully stalled child is
72
+ * killed only when the model endpoint is actually unreachable. Sized so a long
73
+ * local prompt-processing pass, which is minutes of legitimate silence from a
74
+ * live server, gets probed and then waited on.
84
75
  */
85
76
  export const STALL_AFTER_MS = 180_000;
86
77
  /** The shipped `detector` half of the `loop` row: the read-only research/impl guard. */
@@ -219,19 +210,20 @@ export function workerPolicy(id, inputs = {}) {
219
210
  /**
220
211
  * Lay whole rows over a resolved policy.
221
212
  *
222
- * For tests and A/B harnesses ONLY. Production code names a profile: an override
223
- * at a production call site is the exact "hand-pick a subset" this module exists
224
- * to stop, and `worker-profiles.test.ts` fails the build if one appears.
213
+ * For tests and harnesses ONLY. Production code names a profile: an override at a
214
+ * production call site is the exact "hand-pick a subset" this module exists to
215
+ * stop, and worker-profiles.test.ts scans src/ for a leading `override:` and fails
216
+ * on any hit.
225
217
  */
226
218
  export function applyOverride(policy, override) {
227
219
  if (override === undefined)
228
220
  return policy;
229
221
  const { carryForward, ...rows } = override;
230
- // Present-but-`undefined` is DROPPED, not laid down. A conditional row is
231
- // the natural way to write a swept arm — `{'command-timeout': on ? ms :
232
- // undefined}` — and a plain spread would put `undefined` into the policy,
233
- // which either disarms the guard silently or throws on `clock.timeoutMs`.
234
- // The repo has no `exactOptionalPropertyTypes`, so the compiler allows it.
222
+ // Present-but-`undefined` is DROPPED, not laid down. A conditional row is the
223
+ // natural way to write one — `{'command-timeout': on ? ms : undefined}` — and a
224
+ // plain spread would put `undefined` into the policy, which either disarms the
225
+ // guard silently or throws on `clock.timeoutMs`. This tsconfig does not set
226
+ // `exactOptionalPropertyTypes`, so the compiler allows it through.
235
227
  const set = Object.fromEntries(Object.entries(rows).filter(([, v]) => v !== undefined));
236
228
  return {
237
229
  guards: { ...policy.guards, ...set },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mjasnikovs/pi-task",
3
- "version": "0.38.28",
3
+ "version": "0.38.30",
4
4
  "description": "Deterministic task planning and spec-orchestration for local models — crash-safe /task pipelines with verify/enforce gates, a real-time remote web view, and web/docs/fetch/worker subagent tools.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -13,8 +13,9 @@
13
13
  ],
14
14
  "scripts": {
15
15
  "build": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.build.json",
16
- "lint": "prettier --log-level warn --write 'src/**/*.ts' && eslint --fix . && tsc --noEmit && tsc -p scripts/tsconfig.json --noEmit",
17
- "test": "cross-env AGENT=1 bun test --isolate src/ scripts/",
16
+ "lint": "prettier --log-level warn --write '{src,test}/**/*.ts' && eslint --fix . && tsc --noEmit",
17
+ "lint:check": "prettier --check '{src,test}/**/*.ts' && eslint . --max-warnings 0 && tsc --noEmit",
18
+ "test": "cross-env AGENT=1 bun test --isolate test/ scripts/",
18
19
  "prepublishOnly": "bun run build"
19
20
  },
20
21
  "peerDependencies": {
@@ -41,12 +42,13 @@
41
42
  "@types/turndown": "5.0.6",
42
43
  "@types/web-push": "3.6.4",
43
44
  "@types/ws": "8.18.1",
44
- "cross-env": "^10.1.0",
45
- "eslint": "10.2.1",
46
- "globals": "17.5.0",
47
- "prettier": "3.8.3",
45
+ "cross-env": "10.1.0",
46
+ "eslint": "10.9.1",
47
+ "eslint-config-prettier": "10.1.8",
48
+ "globals": "17.11.0",
49
+ "prettier": "3.9.6",
48
50
  "typescript": "6.0.3",
49
- "typescript-eslint": "8.58.2"
51
+ "typescript-eslint": "8.68.0"
50
52
  },
51
53
  "keywords": [
52
54
  "pi-package",