@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,47 +1,37 @@
1
1
  /**
2
- * final-gate-fix — the bounded, model-driven fix pass offered when the FINAL
3
- * integration gate fails.
2
+ * final-gate-fix — the bounded, model-driven fix pass the FINAL integration
3
+ * gate's resolution picker offers as its second card.
4
4
  *
5
- * The failure this closes (mx5 run 7, validated): the final gate's first live
6
- * firing was a TRUE POSITIVE the project's own `test` command genuinely failed
7
- * whole-repo while every per-slice check was green but the resolution picker
8
- * offered only "Leave failed" / "Accept". There was NO automated path to fix a
9
- * defect the run itself shipped; the user had to leave the run failed, fix by
10
- * hand, and resume.
11
- *
12
- * This mirrors the per-task graduated-resolution shape (lint-fix.ts): a bounded
13
- * write-enabled child (read, edit, bash) is seeded with the gate's exact failure
14
- * (command + exit code + output tail), fixes the defect in place, and the gate
15
- * itself is re-run as the only arbiter — the child's self-report is never
16
- * trusted. The user always chooses this path from the picker ("Leave failed"
17
- * stays the recommended default), and attempts are capped so a non-converging
18
- * loop hands control back to a person.
5
+ * This mirrors the per-task graduated-resolution shape (lint-fix.ts) and shares
6
+ * its child ladder through `runFixChild`: a write-enabled child limited to
7
+ * `read,edit,bash` is seeded with the gate's own failure text, edits in place,
8
+ * and then the gate is RE-RUN. The child's self-report can only end an attempt
9
+ * early as BLOCKED; it can never produce a PASS. `run-final-gate.ts` keeps
10
+ * "Leave failed" as the recommended card and stops offering Autofix after
11
+ * MAX_FINAL_GATE_AUTOFIX attempts, so a non-converging loop hands control back
12
+ * to a person.
19
13
  *
20
14
  * CHEAT GUARD (deterministic): the cheapest way for a fix child to "converge" is
21
15
  * to remove the failing command itself — delete the `test` script, drop the
22
- * Makefile target — so the gate discovers nothing and vacuously passes. Both
23
- * live lint-fix validation runs cheated exactly this way (via git checkout)
24
- * until a guard existed. So the discovered gate commands are snapshotted before
25
- * the child runs; any previously-discovered command that is no longer
26
- * discoverable afterwards rejects the attempt and discards its edits. A fix may
27
- * change what a command DOES, never make it disappear.
16
+ * Makefile target — so the gate discovers nothing and vacuously passes. The
17
+ * discovered gate commands are therefore snapshotted before the child runs; a
18
+ * previously-discovered command that is no longer discoverable afterwards
19
+ * rejects the attempt and discards its edits, and so does one whose resolved
20
+ * BODY narrowed. A fix may change what a command DOES, never make it disappear
21
+ * or shrink what it covers.
28
22
  *
29
- * WRITE-GUARD STACK (mx5 run 11): this child was added after the run-8 guard
30
- * generation and inherited none of them it ran `rm` on a sibling task's
31
- * verified deliverable to satisfy a recorded debt claim and hand-copied a pinned
32
- * contract to green the lint, with free bash and no trace. Every attempt now
33
- * runs, deterministically and in order: frozen-path revert (when a freeze set is
34
- * wired see below) deletion guard (a tracked file deleted without relocation
35
- * rejects the attempt) → shrink guard (above) → probe-gaming scan over the added
36
- * lines (a fix that SAYS it games a check rejects the attempt). Diff capture for
37
- * every write-capable gate child lives at the gate-deps seam, keyed on the
38
- * child's TOOLS, so the next write-capable kind cannot run invisibly either.
23
+ * WRITE-GUARD STACK, in the order `runFinalGateAutofix` runs it: frozen-path
24
+ * revert (only when a freeze set is wired) deletion guard (a tracked file
25
+ * deleted without relocation rejects the attempt) shrink guard → scope-shrink
26
+ * guard probe-gaming scan over the added lines. Diff capture is NOT here: it
27
+ * lives at the gate-child seam, where a `/\b(?:edit|bash|write)\b/` test on the
28
+ * child's TOOLS decides it, so any future write-capable kind is logged too.
39
29
  *
40
- * The frozen-path deny is implemented but NOT wired by gate-deps: per-task
41
- * frozen fences are task-SCOPED (they fence a task off a sibling's territory),
42
- * and the measured union over the run-11 specs would have reverted the one
43
- * legitimate whole-repo fix that run needed (migrate.ts frozen by its own
44
- * producing task). It activates only when a run-GLOBAL freeze source exists.
30
+ * The frozen-path deny is implemented here but NOT wired by gate-deps — the
31
+ * `finalGateFix` wiring there passes every other dep and omits these two.
32
+ * Per-task frozen fences are task-SCOPED, so their union across a run's specs
33
+ * can fence off a file a legitimate whole-repo fix has to touch. It activates
34
+ * only when a run-GLOBAL freeze source exists.
45
35
  */
46
36
  import { parseFixMarker, runFixChild } from './fix-child.js';
47
37
  import { findForbiddenDeletions, diffIgnoredSnapshots, ignoredWriteTrailLine, ignoredWriteUnobservedNote } from './write-guard.js';
@@ -51,13 +41,15 @@ import { findNarrowedCommands, narrowingRejectionText } from './command-shrink.j
51
41
  export const FINAL_FIX_TOOLS = 'read,edit,bash';
52
42
  /**
53
43
  * How many fix passes the user may launch from the picker before the option is
54
- * withdrawn (mirrors the per-task MAX_AUTO_AUTOFIX budget). Each attempt is a
55
- * full model child plus a full gate re-run — after this many that still FAIL,
56
- * only Leave-failed / Accept remain so a person breaks the loop.
44
+ * withdrawn. Same value as the per-task MAX_AUTO_AUTOFIX budget. Each attempt is
45
+ * a full model child plus a full gate re-run — after this many that still FAIL,
46
+ * `run-final-gate.ts` drops the Autofix card and only Leave-failed / Accept
47
+ * remain, so a person breaks the loop.
57
48
  */
58
49
  export const MAX_FINAL_GATE_AUTOFIX = 3;
59
- /** Picker labels/values. Classification accepts the value token, the label, or
60
- * free text (→ autofix guidance), same contract as the per-task resolution. */
50
+ /** Picker labels/values. Each label starts with its own value word, so
51
+ * `classifyFinalGateAnswer` accepts the value token and the label alike;
52
+ * anything else is free text and becomes autofix guidance. */
61
53
  export const FINAL_LEAVE_VALUE = 'fail';
62
54
  export const FINAL_ACCEPT_VALUE = 'accept';
63
55
  export const FINAL_AUTOFIX_VALUE = 'autofix';
@@ -66,9 +58,9 @@ export const FINAL_ACCEPT_LABEL = 'Accept — complete the run anyway';
66
58
  export const FINAL_AUTOFIX_LABEL = 'Autofix — run a bounded fix pass and re-run the gate';
67
59
  /**
68
60
  * Map a final-gate picker answer to an action. Dismissal (undefined/empty) and
69
- * an explicit leave stay "leave" exactly what the two-option picker did.
70
- * Free text becomes autofix guidance, mirroring classifyResolutionAnswer; the
71
- * caller demotes autofix back to "leave" when the option was not offered.
61
+ * an explicit leave both stay "leave". Free text becomes autofix guidance; the
62
+ * caller's `choice.action === 'autofix' && canAutofix` test demotes autofix back
63
+ * to leave when the card was not offered.
72
64
  */
73
65
  export function classifyFinalGateAnswer(answer) {
74
66
  if (answer === undefined)
@@ -85,10 +77,11 @@ export function classifyFinalGateAnswer(answer) {
85
77
  return { action: 'autofix', guidance: t };
86
78
  }
87
79
  /**
88
- * The gate's fail reason always carries the failing command in backticks
89
- * (`` `bun run test` exited 1 `` / ``static checks: `make lint` exited 2``).
90
- * Extract it for reporting; the shrink guard itself compares the FULL
91
- * discovered-command sets, so a reason this cannot parse still guards.
80
+ * The gate's fail reason carries the failing command in backticks — final-gate
81
+ * mints `` `<label>` exited <status><tail> ``, with a `lockfile check: ` or
82
+ * `launch script: ` prefix on two of the sections. Extract it for reporting
83
+ * only; the shrink guard compares the FULL discovered-command sets, so a reason
84
+ * this cannot parse still guards.
92
85
  */
93
86
  export function exitedCommandFromReason(reason) {
94
87
  const m = /`([^`]+)`\s+exited\b/.exec(reason);
@@ -96,11 +89,11 @@ export function exitedCommandFromReason(reason) {
96
89
  }
97
90
  /**
98
91
  * Build the fix child's prompt. Generic by construction: the only project facts
99
- * in it are the gate's own failure text the command comes from the project's
100
- * discovered manifest, never from a hardcoded ecosystem. The seed may carry
101
- * SEVERAL failures (the gate aggregates every section since mx5 run 13, ranked
102
- * most load-bearing first); convergence means the WHOLE list is empty, so the
103
- * child is told to fix all of them.
92
+ * in it are the gate's own failure text, whose command labels come from the
93
+ * project's discovered manifest. The seed may carry SEVERAL failures the gate
94
+ * runs every section and aggregates, emitting "N failures (ranked, most
95
+ * load-bearing first)" and it reports `ok` only when that list is empty, so
96
+ * the child is told to fix all of them.
104
97
  */
105
98
  export function buildFinalFixPrompt(failReason) {
106
99
  return [
@@ -144,41 +137,28 @@ export function buildFinalFixPrompt(failReason) {
144
137
  ' FINAL-GATE-FIX: BLOCKED <why you could not fix it>'
145
138
  ].join('\n');
146
139
  }
147
- /**
148
- * Parse the child's final marker. Last match wins (the model reasons before
149
- * concluding and bash output can echo the words). No marker → treated as DONE:
150
- * the gate re-run is the arbiter either way, so a missing marker only skips the
151
- * early-out on a self-declared BLOCKED.
152
- */
140
+ /** This pass's marker word, parsed by the shared `parseFixMarker` (last match
141
+ * wins; no marker DONE). */
153
142
  export function parseFinalFixMarker(text) {
154
143
  return parseFixMarker('FINAL-GATE-FIX', text);
155
144
  }
156
145
  /**
157
- * STRANDED SUB-FIXES (mx5 run 13, PROMPT 4 item 3).
158
- *
159
- * A fix attempt that does not converge keeps its edits: they are NOT discarded
160
- * (only a guard trip discards), and `deps.commit` runs only on `fix.ok`. So a
161
- * partial fix that genuinely repaired something sits in the working tree, uncommitted,
162
- * and if the user then ACCEPTs the FAIL the run completes around it — leaving HEAD
163
- * broken while the repair is invisible unless someone runs `git status`.
146
+ * STRANDED SUB-FIXES.
164
147
  *
165
- * That is exactly what run 13 shipped: the fix child's bunfig.toml change made
166
- * `bun run test` pass 116/116, attempt 1 did not converge overall, the user accepted
167
- * the FAIL, and the tree still shows the file modified while HEAD's `bun run test` is
168
- * broken. The repair and the breakage were BOTH real; only the repair was discarded
169
- * by default.
148
+ * An attempt that does not converge KEEPS its edits only a guard trip
149
+ * discards and the caller commits only on `fix.ok`. So a partial fix that
150
+ * genuinely repaired something sits uncommitted in the working tree while HEAD
151
+ * still carries the defect, invisible unless someone runs `git status`.
170
152
  *
171
- * The rule: a partial fix is either committed (its own commit, named in the trail) or
172
- * explicitly surfaced — never silently stranded.
153
+ * The rule: a partial fix is either committed as its own named commit or
154
+ * explicitly surfaced — never silently stranded. `run-final-gate.ts` calls
155
+ * `commitStranded` on BOTH terminal outcomes, accept and leave-failed, so an
156
+ * unattended run that ends on LEAVE does not leave real repairs one `git
157
+ * checkout` from gone.
173
158
  *
174
- * mx5 run 14 proved the committing half only ever ran on the ACCEPT path. The run
175
- * ended on LEAVE (YOLO, budget spent) and 13 real repairs the dev script, the
176
- * teardown bug, test serialization, the migrate script: the changes that make that
177
- * app work today — were left dirty in the tree, one `git checkout` from gone, after
178
- * an UNATTENDED run nobody was watching. So EVERY terminal non-converged outcome
179
- * commits them now, not just ACCEPT. Only guard-CLEAN edits qualify: an attempt a
180
- * write-guard rejected without discarding leaves REJECTED edits in the tree, and
181
- * those are never committed (the guard is not weakened to make committing easier).
159
+ * Only guard-CLEAN edits qualify. `AutofixLedger.mayCommitTree()` goes false
160
+ * once a guard has rejected an attempt whose edits could not be discarded, and
161
+ * never flips back: the guard is not weakened to make committing easier.
182
162
  */
183
163
  /** Commit subject for partial fixes committed alongside a terminal gate FAIL. */
184
164
  export const STRANDED_FIX_COMMIT = (runId, outcome = 'accepted') => `FINAL GATE PARTIAL FIX (${runId}) — ${outcome === 'accepted' ?
@@ -198,10 +178,11 @@ export function strandedFixNote(paths) {
198
178
  + `checkout — the run's outcome is recorded in the gate trail either way.`);
199
179
  }
200
180
  /**
201
- * Run one bounded final-gate fix attempt: snapshot discovery child write-guard
202
- * stack (diff capture → frozen-path revert → deletion guard → shrink guard → probe
203
- * scan) → gate re-run. Never throws for an outcome; only a user cancel inside
204
- * runChild propagates (the caller's USER_CANCELLED path handles it).
181
+ * Run one bounded final-gate fix attempt: snapshot discovery and ignored paths
182
+ * child → frozen-path revert → deletion guard → shrink guard → scope-shrink
183
+ * guard → probe scan → gate re-run. Never throws for an outcome; only a user
184
+ * cancel inside runChild propagates, and the caller's USER_CANCELLED path
185
+ * handles that.
205
186
  */
206
187
  export async function runFinalGateAutofix(deps) {
207
188
  const before = deps.discoverLabels(deps.cwd);
@@ -210,7 +191,7 @@ export async function runFinalGateAutofix(deps) {
210
191
  // ignored files are untracked, so git alone cannot tell a file this pass wrote
211
192
  // from one that was already sitting in the worktree.
212
193
  const ignoredBefore = deps.ignoredSnapshot ? await deps.ignoredSnapshot() : null;
213
- // The four-rung ladder is task/fix-child.ts, shared with the per-task pass.
194
+ // The child ladder is task/fix-child.ts, shared with the per-task pass.
214
195
  const end = await runFixChild({
215
196
  runChild: deps.runChild,
216
197
  tools: FINAL_FIX_TOOLS,
@@ -241,12 +222,13 @@ export async function runFinalGateAutofix(deps) {
241
222
  guardTripped: true,
242
223
  editsDiscarded: deps.discard !== undefined
243
224
  });
244
- // (Diff capture — what the pass changed, durably — happens at the gate-deps
245
- // seam for every write-capable child; here only the guards act on it.)
246
- // FROZEN-PATH WRITE-DENY: undo the child's edits to any path a task spec
247
- // froze, before anything downstream can act on them same mechanical deny
248
- // the enforce pass carries (prompt framing is A/B-proven insufficient).
249
- // Non-fatal: the rest of the fix survives, only the frozen edits are undone.
225
+ // (Diff capture — what the pass changed, durably — happens in gate-child.ts,
226
+ // which logs the tree changes of any child whose TOOLS include edit/bash/
227
+ // write; here only the guards act on them.)
228
+ // FROZEN-PATH WRITE-DENY: undo the child's edits to any path a task's spec
229
+ // froze, before anything downstream can act on them — the same mechanical
230
+ // revert the per-task passes carry, not prompt framing. Non-fatal: the rest
231
+ // of the fix survives, only the frozen edits are undone.
250
232
  if (deps.frozenPaths && deps.revertFrozen) {
251
233
  const frozen = await deps.frozenPaths();
252
234
  if (frozen.length > 0) {
@@ -256,8 +238,10 @@ export async function runFinalGateAutofix(deps) {
256
238
  }
257
239
  }
258
240
  }
259
- // DELETION GUARD (post-revert state): a tracked file the pass deleted without
260
- // relocating it is a committed deliverable destroyed — reject the attempt.
241
+ // DELETION GUARD (post-revert state): a tracked file the pass deleted is a
242
+ // completed task's committed deliverable destroyed — reject the attempt. A
243
+ // deletion paired with an added file of the SAME BASENAME is a relocation and
244
+ // passes, as do the regenerable artifacts write-guard.ts exempts.
261
245
  const changes = deps.treeChanges ? await deps.treeChanges() : null;
262
246
  if (changes) {
263
247
  const gone = findForbiddenDeletions(changes);
@@ -280,14 +264,12 @@ export async function runFinalGateAutofix(deps) {
280
264
  await deps.discard(deps.cwd);
281
265
  return rejected(`fix pass removed the gate's own command(s) (${vanished.join(', ')})`);
282
266
  }
283
- // SCOPE-SHRINK GUARD (mx5 run 19): the label surviving is not enough. The
284
- // autofix kept `bun run test` and rewrote its BODY from `AGENT=1 bun test`
285
- // to `AGENT=1 bun test ./test`, so the set difference above was empty while
286
- // the suite stopped covering the repository and the gate re-ran, went
287
- // green, and reported "converged". Compare the resolved bodies and reject a
288
- // fix that shrinks what the gate measures (command-shrink.ts: four
289
- // mechanical shapes, measured at 3 hits in 274 manifest-touching corpus
290
- // commits, all three read by hand as real narrowings).
267
+ // SCOPE-SHRINK GUARD: the label surviving is not enough. A child can keep
268
+ // `bun run test` and rewrite its BODY to run a subdirectory instead of the
269
+ // repository the set difference above stays empty while the suite stops
270
+ // covering what the gate is meant to measure, and the re-run then goes green
271
+ // and reports "converged". So compare the resolved bodies too
272
+ // (command-shrink.ts holds the mechanical narrowing shapes).
291
273
  if (deps.discoverBodies) {
292
274
  const addedByFix = new Set((changes?.added ?? []).map(p => p.replace(/^\.\//, '')));
293
275
  const narrowed = findNarrowedCommands(bodiesBefore, deps.discoverBodies(deps.cwd), {
@@ -304,10 +286,10 @@ export async function runFinalGateAutofix(deps) {
304
286
  return r;
305
287
  }
306
288
  }
307
- // PROBE SCAN (F6): added lines whose stated purpose is to make a check pass
308
- // rather than meet the requirement reject the attempt there is no verify
309
- // child downstream of this pass to judge the finding, and the probe is
310
- // FP-measured at 1 true hit in 50,735 added lines on the real corpus.
289
+ // PROBE SCAN: added lines whose own stated purpose is to make a check pass
290
+ // rather than meet the requirement reject the attempt. Nothing downstream of
291
+ // this pass would judge such a finding the gate re-run only sees exit
292
+ // codes.
311
293
  if (deps.probeScan) {
312
294
  const findings = await deps.probeScan();
313
295
  if (findings.length > 0) {
@@ -326,15 +308,14 @@ export async function runFinalGateAutofix(deps) {
326
308
  if (!fin.ok) {
327
309
  return withIgnored({ ok: false, reason: `did not converge: ${fin.reason}`, gate: fin });
328
310
  }
329
- // IGNORED-DEPENDENCY DOWNGRADE (mx5 run 19). The gate says PASS; the question
330
- // this answers is whether that PASS belongs to the REPOSITORY or only to this
331
- // worktree. Decided mechanically, never by judgement: move the ignored files
332
- // the pass wrote aside, re-run the gate once, put them back. Still passing ⇒
333
- // they were incidental and the PASS stands. Failing the checks were passing
334
- // on state no fresh clone has, which is the definition of UNOBSERVED (see
335
- // final-gate.ts unobservedVerdict) not a FAIL: the fix is real, it just did
336
- // not ship. The probe runs only here, so a run with no ignored writes (the
337
- // overwhelming majority — 1 of 68 recorded child logs) pays nothing.
311
+ // IGNORED-DEPENDENCY DOWNGRADE. The gate says PASS; this decides whether the
312
+ // PASS belongs to the REPOSITORY or only to this worktree. Mechanical, never
313
+ // judgement: move the ignored files the pass wrote aside, re-run the gate
314
+ // once, put them back. Still passing ⇒ incidental, the PASS stands. Failing ⇒
315
+ // the checks were passing on state no fresh clone has, which is UNOBSERVED
316
+ // (final-gate.ts unobservedVerdict), not a FAIL the fix is real, it just
317
+ // did not ship. Guarded on a non-empty `ignoredWrites`, so a pass that wrote
318
+ // no ignored paths runs no extra gate.
338
319
  let ignoredDependent;
339
320
  if (ignoredWrites.length > 0 && deps.gateWithoutIgnored) {
340
321
  const passesWithout = await deps.gateWithoutIgnored(ignoredWrites);
@@ -1,33 +1,23 @@
1
1
  /**
2
- * final-gate-progress — the non-progress classifier for the final-gate autofix loop.
2
+ * final-gate-progress — the non-progress classifier for the final-gate autofix
3
+ * loop. `AutofixLedger.judge` is its only caller.
3
4
  *
4
- * The failure this closes (mx5 run 14, validated from TASK_AUTO_0001.md's gates
5
- * trail): the gate's boot check asserted "the app never opened a listening socket"
6
- * in a sandbox where NO tool the probe knows (`ss`, `lsof`) exists the check was
7
- * UNFALSIFIABLE there. Three autofix attempts each edited real files, re-ran, and
8
- * came back with a byte-identical ranked-first failure; the budget was spent on a
9
- * check no edit could ever move, the two checks that WERE fixable had converged by
10
- * attempt 2, and the run ended `failed` with 13 genuinely repaired files sitting
11
- * uncommitted in the working tree.
12
- *
13
- * The rule this encodes: an attempt that CHANGED the tree and re-ran the gate, and
14
- * got the same first failure back as the previous attempt, is evidence about the
15
- * CHECK, not about the fix. Two identical post-fix results ⇒ the check is
16
- * env-shaped/unfalsifiable in this environment ⇒ stop paying for it: demote that
17
- * one check to UNOBSERVED-with-debt (durable, so the NEXT run's gate re-checks it)
18
- * and let the REMAINING checks decide whether the gate converged. Run 14 replay:
19
- * checks 2 and 3 were fixed by attempts 1–2, so the run converges with the boot
20
- * check carried as debt instead of failing with the repairs stranded.
5
+ * The rule: an attempt that CHANGED the tree and re-ran the gate, and got the
6
+ * same ranked-first failure back as the previous attempt, is evidence about the
7
+ * CHECK, not about the fix. A check that survives two post-fix results
8
+ * identically is unfalsifiable in this environment, so stop paying for it —
9
+ * demote that ONE check to UNOBSERVED-with-debt and let the remaining checks
10
+ * decide whether the gate converged. The debt is appended to the ledger file
11
+ * under `.pi-tasks/`, so it outlives the run and the next gate re-checks it.
21
12
  *
22
13
  * Deliberately conservative:
23
- * - It never fires on attempt 1. The first repeat can be an ordinary
24
- * didn't-fix-it-yet; only a SECOND identical post-fix result is evidence.
25
- * - It never fires when the attempt changed nothing (a BLOCKED child, a
26
- * guard-discarded attempt): with no edit there is nothing to conclude about
27
- * falsifiability.
28
- * - It demotes exactly the one repeated check. Every other failure still has to
29
- * pass for real; the debt keeps the demoted one visible at run end and in the
30
- * next run's gate.
14
+ * - It never fires on attempt 1: `previousSignature` is null until an attempt
15
+ * has produced one, and null returns false.
16
+ * - It never fires when the attempt changed nothing. The caller passes
17
+ * `edited` as "the gate re-ran AND the tree is dirty", and a guard-rejected
18
+ * attempt returns before the re-run, so its `gate` is undefined.
19
+ * - It demotes exactly the one repeated signature. Every other failure still
20
+ * has to pass for real.
31
21
  */
32
22
  /**
33
23
  * Comparison key for a gate failure entry: lowercased, volatile substrings erased,
@@ -51,7 +41,7 @@ export interface NonProgressInput {
51
41
  * attempt that edited and re-tested says anything about falsifiability. */
52
42
  edited: boolean;
53
43
  /**
54
- * Did a PROBE return this failure after OBSERVING? (nexttask 19A.) Read off
44
+ * Did a PROBE return this failure after OBSERVING? Read off
55
45
  * `FinalGateOutcome.observedFailures` by exact text identity — never re-derived
56
46
  * from the failure string.
57
47
  *
@@ -64,24 +54,17 @@ export interface NonProgressInput {
64
54
  * here: it edited the tree, the gate re-ran, and returned the same first failure
65
55
  * as the previous attempt.
66
56
  *
67
- * …EXCEPT when the probe OBSERVED the failure (nexttask 19A). This rule was built
68
- * as a blind compensator for a probe limitation run 14's boot check "could not
69
- * observe a listener in that sandbox at all" and that limitation was fixed
70
- * upstream ELEVEN MINUTES BEFORE this rule landed (`b0f90a7` 23:34:05, `dd3b0c3`
71
- * 23:45:09, both 2026-07-19). Every probe now reports "I could not look" as its
72
- * own outcome, with the reason. What was left was a second, blind judgment of the
73
- * same question, made DOWNSTREAM from the evidence — and its only reachable effect
74
- * was to overrule a probe that DID look.
75
- *
76
- * It has to be overruled, because a deterministic un-fixed defect emits an
77
- * IDENTICAL failure by definition. String equality therefore reads reproducibility
78
- * as evidence against the instrument, which is backwards for every project type: a
79
- * CLI that exits 2 twice, a build that fails on the same symbol twice, a C++ plugin
80
- * missing the same export twice. mx5 run 21 is the one recorded instance and it
81
- * released a product whose every page was blank as a `completed` run.
57
+ * …EXCEPT when a probe OBSERVED the failure, which is checked FIRST and wins
58
+ * outright. A probe that looked and saw the defect has already answered the
59
+ * question this rule guesses at, and it answered it where the evidence is. A
60
+ * probe that could NOT look reports that as its own outcome instead, so it never
61
+ * reaches `observedFailures`.
82
62
  *
83
- * The fix is NOT a better string pattern the bug is that the decision was made
84
- * downstream from the evidence, not that the pattern was too coarse.
63
+ * The observed guard has to win, because a deterministic un-fixed defect emits an
64
+ * IDENTICAL failure by definition. Without it, string equality reads
65
+ * reproducibility as evidence against the instrument — a CLI that exits 2 twice,
66
+ * a build that fails on the same symbol twice — and demotes a real, still-broken
67
+ * check to debt.
85
68
  */
86
69
  export declare function isNonProgress(input: NonProgressInput): boolean;
87
70
  /**
@@ -89,6 +72,6 @@ export declare function isNonProgress(input: NonProgressInput): boolean;
89
72
  * what still has to pass for the gate to converge; empty ⇒ converged-with-debt.
90
73
  */
91
74
  export declare function applyDemotions(failures: string[], demoted: ReadonlySet<string>): string[];
92
- /** The debt reason recorded for a demoted check, and the gate-trail wording. Kept
93
- * in one place so the ledger line and the trail line cannot drift apart. */
75
+ /** The debt reason recorded for a demoted check. One function so the ledger entry
76
+ * and the wording the user reads cannot drift apart. */
94
77
  export declare function unobservedDebtReason(detail: string): string;
@@ -1,33 +1,23 @@
1
1
  /**
2
- * final-gate-progress — the non-progress classifier for the final-gate autofix loop.
2
+ * final-gate-progress — the non-progress classifier for the final-gate autofix
3
+ * loop. `AutofixLedger.judge` is its only caller.
3
4
  *
4
- * The failure this closes (mx5 run 14, validated from TASK_AUTO_0001.md's gates
5
- * trail): the gate's boot check asserted "the app never opened a listening socket"
6
- * in a sandbox where NO tool the probe knows (`ss`, `lsof`) exists the check was
7
- * UNFALSIFIABLE there. Three autofix attempts each edited real files, re-ran, and
8
- * came back with a byte-identical ranked-first failure; the budget was spent on a
9
- * check no edit could ever move, the two checks that WERE fixable had converged by
10
- * attempt 2, and the run ended `failed` with 13 genuinely repaired files sitting
11
- * uncommitted in the working tree.
12
- *
13
- * The rule this encodes: an attempt that CHANGED the tree and re-ran the gate, and
14
- * got the same first failure back as the previous attempt, is evidence about the
15
- * CHECK, not about the fix. Two identical post-fix results ⇒ the check is
16
- * env-shaped/unfalsifiable in this environment ⇒ stop paying for it: demote that
17
- * one check to UNOBSERVED-with-debt (durable, so the NEXT run's gate re-checks it)
18
- * and let the REMAINING checks decide whether the gate converged. Run 14 replay:
19
- * checks 2 and 3 were fixed by attempts 1–2, so the run converges with the boot
20
- * check carried as debt instead of failing with the repairs stranded.
5
+ * The rule: an attempt that CHANGED the tree and re-ran the gate, and got the
6
+ * same ranked-first failure back as the previous attempt, is evidence about the
7
+ * CHECK, not about the fix. A check that survives two post-fix results
8
+ * identically is unfalsifiable in this environment, so stop paying for it —
9
+ * demote that ONE check to UNOBSERVED-with-debt and let the remaining checks
10
+ * decide whether the gate converged. The debt is appended to the ledger file
11
+ * under `.pi-tasks/`, so it outlives the run and the next gate re-checks it.
21
12
  *
22
13
  * Deliberately conservative:
23
- * - It never fires on attempt 1. The first repeat can be an ordinary
24
- * didn't-fix-it-yet; only a SECOND identical post-fix result is evidence.
25
- * - It never fires when the attempt changed nothing (a BLOCKED child, a
26
- * guard-discarded attempt): with no edit there is nothing to conclude about
27
- * falsifiability.
28
- * - It demotes exactly the one repeated check. Every other failure still has to
29
- * pass for real; the debt keeps the demoted one visible at run end and in the
30
- * next run's gate.
14
+ * - It never fires on attempt 1: `previousSignature` is null until an attempt
15
+ * has produced one, and null returns false.
16
+ * - It never fires when the attempt changed nothing. The caller passes
17
+ * `edited` as "the gate re-ran AND the tree is dirty", and a guard-rejected
18
+ * attempt returns before the re-run, so its `gate` is undefined.
19
+ * - It demotes exactly the one repeated signature. Every other failure still
20
+ * has to pass for real.
31
21
  */
32
22
  /**
33
23
  * Volatile substrings that differ between two runs of the SAME failing check —
@@ -60,12 +50,18 @@ const VOLATILE = [
60
50
  * A bare `:NNNN` port, which the localhost/`port N` rules above do not reach (a
61
51
  * failure that just says "no listener on :3000").
62
52
  *
63
- * NOT applied when the colon follows a SOURCE LOCATION `src/db.ts:41`,
64
- * `Cart.tsx:88:12`. A failure detail embeds the failing command's output tail
65
- * verbatim (final-gate.ts `r.tail`), and tsc/eslint/bun-test tails are mostly
66
- * file:line. Collapsing those made two DIFFERENT defects in one file the second
67
- * uncovered by fixing the first compare equal, which reads as non-progress and
68
- * demotes a genuinely fixable check to UNOBSERVED debt. A moved error is progress.
53
+ * NOT applied when the colon follows a SOURCE LOCATION. A failure detail embeds
54
+ * the failing command's output tail verbatim (final-gate.ts interpolates
55
+ * `r.tail`), and tsc/eslint/bun-test tails are mostly `file:line`. Collapsing
56
+ * those would make two DIFFERENT defects in one file compare equal, which reads
57
+ * as non-progress and demotes a genuinely fixable check. A moved error is
58
+ * progress.
59
+ *
60
+ * The exemption covers the FILE:LINE colon only. Measured: `src/db.ts:41` and
61
+ * `src/db.ts:88` keep their line numbers and stay different, but the COLUMN in
62
+ * `Cart.tsx:88:12` normalises to `cart.tsx:88:<port>` — the prefix at that colon
63
+ * is the bare `88`, which is neither a path nor a filename. Two defects that
64
+ * differ only in column therefore compare equal.
69
65
  */
70
66
  const BARE_PORT = /(\S*?):(\d{2,5})\b/g;
71
67
  /** A path (has a separator) or a filename with an extension ⇒ a source location. */
@@ -97,24 +93,17 @@ export function rankedFirstFailure(outcome) {
97
93
  * here: it edited the tree, the gate re-ran, and returned the same first failure
98
94
  * as the previous attempt.
99
95
  *
100
- * …EXCEPT when the probe OBSERVED the failure (nexttask 19A). This rule was built
101
- * as a blind compensator for a probe limitation run 14's boot check "could not
102
- * observe a listener in that sandbox at all" and that limitation was fixed
103
- * upstream ELEVEN MINUTES BEFORE this rule landed (`b0f90a7` 23:34:05, `dd3b0c3`
104
- * 23:45:09, both 2026-07-19). Every probe now reports "I could not look" as its
105
- * own outcome, with the reason. What was left was a second, blind judgment of the
106
- * same question, made DOWNSTREAM from the evidence — and its only reachable effect
107
- * was to overrule a probe that DID look.
108
- *
109
- * It has to be overruled, because a deterministic un-fixed defect emits an
110
- * IDENTICAL failure by definition. String equality therefore reads reproducibility
111
- * as evidence against the instrument, which is backwards for every project type: a
112
- * CLI that exits 2 twice, a build that fails on the same symbol twice, a C++ plugin
113
- * missing the same export twice. mx5 run 21 is the one recorded instance and it
114
- * released a product whose every page was blank as a `completed` run.
96
+ * …EXCEPT when a probe OBSERVED the failure, which is checked FIRST and wins
97
+ * outright. A probe that looked and saw the defect has already answered the
98
+ * question this rule guesses at, and it answered it where the evidence is. A
99
+ * probe that could NOT look reports that as its own outcome instead, so it never
100
+ * reaches `observedFailures`.
115
101
  *
116
- * The fix is NOT a better string pattern the bug is that the decision was made
117
- * downstream from the evidence, not that the pattern was too coarse.
102
+ * The observed guard has to win, because a deterministic un-fixed defect emits an
103
+ * IDENTICAL failure by definition. Without it, string equality reads
104
+ * reproducibility as evidence against the instrument — a CLI that exits 2 twice,
105
+ * a build that fails on the same symbol twice — and demotes a real, still-broken
106
+ * check to debt.
118
107
  */
119
108
  export function isNonProgress(input) {
120
109
  if (input.observed === true)
@@ -134,8 +123,8 @@ export function applyDemotions(failures, demoted) {
134
123
  return [...failures];
135
124
  return failures.filter(f => !demoted.has(normalizeFailureDetail(f)));
136
125
  }
137
- /** The debt reason recorded for a demoted check, and the gate-trail wording. Kept
138
- * in one place so the ledger line and the trail line cannot drift apart. */
126
+ /** The debt reason recorded for a demoted check. One function so the ledger entry
127
+ * and the wording the user reads cannot drift apart. */
139
128
  export function unobservedDebtReason(detail) {
140
129
  return (`final gate check UNOBSERVED — ${detail.trim().slice(0, 200)} — `
141
130
  + 'repeated identically across two fix attempts that both changed the tree and '