@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,13 +5,15 @@ import { type TreeChangeSummary, type IgnoredSnapshot } from './write-guard.js';
5
5
  export declare const FINAL_FIX_TOOLS = "read,edit,bash";
6
6
  /**
7
7
  * How many fix passes the user may launch from the picker before the option is
8
- * withdrawn (mirrors the per-task MAX_AUTO_AUTOFIX budget). Each attempt is a
9
- * full model child plus a full gate re-run — after this many that still FAIL,
10
- * only Leave-failed / Accept remain so a person breaks the loop.
8
+ * withdrawn. Same value as the per-task MAX_AUTO_AUTOFIX budget. Each attempt is
9
+ * a full model child plus a full gate re-run — after this many that still FAIL,
10
+ * `run-final-gate.ts` drops the Autofix card and only Leave-failed / Accept
11
+ * remain, so a person breaks the loop.
11
12
  */
12
13
  export declare const MAX_FINAL_GATE_AUTOFIX = 3;
13
- /** Picker labels/values. Classification accepts the value token, the label, or
14
- * free text (→ autofix guidance), same contract as the per-task resolution. */
14
+ /** Picker labels/values. Each label starts with its own value word, so
15
+ * `classifyFinalGateAnswer` accepts the value token and the label alike;
16
+ * anything else is free text and becomes autofix guidance. */
15
17
  export declare const FINAL_LEAVE_VALUE = "fail";
16
18
  export declare const FINAL_ACCEPT_VALUE = "accept";
17
19
  export declare const FINAL_AUTOFIX_VALUE = "autofix";
@@ -19,8 +21,8 @@ export declare const FINAL_LEAVE_LABEL = "Leave failed \u2014 I will fix and /ta
19
21
  export declare const FINAL_ACCEPT_LABEL = "Accept \u2014 complete the run anyway";
20
22
  export declare const FINAL_AUTOFIX_LABEL = "Autofix \u2014 run a bounded fix pass and re-run the gate";
21
23
  export interface FinalGateChoice {
22
- /** What the user decided. 'leave' = leave the run failed (also the dismissal
23
- * default identical to the pre-autofix behavior). */
24
+ /** What the user decided. 'leave' = leave the run failed, and also what a
25
+ * dismissed picker means. */
24
26
  action: 'leave' | 'accept' | 'autofix';
25
27
  /** Free-text guidance typed instead of picking a card; folded into the fix
26
28
  * child's failure seed. Only set with 'autofix'. */
@@ -28,63 +30,51 @@ export interface FinalGateChoice {
28
30
  }
29
31
  /**
30
32
  * Map a final-gate picker answer to an action. Dismissal (undefined/empty) and
31
- * an explicit leave stay "leave" exactly what the two-option picker did.
32
- * Free text becomes autofix guidance, mirroring classifyResolutionAnswer; the
33
- * caller demotes autofix back to "leave" when the option was not offered.
33
+ * an explicit leave both stay "leave". Free text becomes autofix guidance; the
34
+ * caller's `choice.action === 'autofix' && canAutofix` test demotes autofix back
35
+ * to leave when the card was not offered.
34
36
  */
35
37
  export declare function classifyFinalGateAnswer(answer: string | undefined): FinalGateChoice;
36
38
  /**
37
- * The gate's fail reason always carries the failing command in backticks
38
- * (`` `bun run test` exited 1 `` / ``static checks: `make lint` exited 2``).
39
- * Extract it for reporting; the shrink guard itself compares the FULL
40
- * discovered-command sets, so a reason this cannot parse still guards.
39
+ * The gate's fail reason carries the failing command in backticks — final-gate
40
+ * mints `` `<label>` exited <status><tail> ``, with a `lockfile check: ` or
41
+ * `launch script: ` prefix on two of the sections. Extract it for reporting
42
+ * only; the shrink guard compares the FULL discovered-command sets, so a reason
43
+ * this cannot parse still guards.
41
44
  */
42
45
  export declare function exitedCommandFromReason(reason: string): string | null;
43
46
  /**
44
47
  * Build the fix child's prompt. Generic by construction: the only project facts
45
- * in it are the gate's own failure text the command comes from the project's
46
- * discovered manifest, never from a hardcoded ecosystem. The seed may carry
47
- * SEVERAL failures (the gate aggregates every section since mx5 run 13, ranked
48
- * most load-bearing first); convergence means the WHOLE list is empty, so the
49
- * child is told to fix all of them.
48
+ * in it are the gate's own failure text, whose command labels come from the
49
+ * project's discovered manifest. The seed may carry SEVERAL failures the gate
50
+ * runs every section and aggregates, emitting "N failures (ranked, most
51
+ * load-bearing first)" and it reports `ok` only when that list is empty, so
52
+ * the child is told to fix all of them.
50
53
  */
51
54
  export declare function buildFinalFixPrompt(failReason: string): string;
52
- /**
53
- * Parse the child's final marker. Last match wins (the model reasons before
54
- * concluding and bash output can echo the words). No marker → treated as DONE:
55
- * the gate re-run is the arbiter either way, so a missing marker only skips the
56
- * early-out on a self-declared BLOCKED.
57
- */
55
+ /** This pass's marker word, parsed by the shared `parseFixMarker` (last match
56
+ * wins; no marker DONE). */
58
57
  export declare function parseFinalFixMarker(text: string): {
59
58
  blocked: boolean;
60
59
  note?: string;
61
60
  };
62
61
  /**
63
- * STRANDED SUB-FIXES (mx5 run 13, PROMPT 4 item 3).
64
- *
65
- * A fix attempt that does not converge keeps its edits: they are NOT discarded
66
- * (only a guard trip discards), and `deps.commit` runs only on `fix.ok`. So a
67
- * partial fix that genuinely repaired something sits in the working tree, uncommitted,
68
- * and if the user then ACCEPTs the FAIL the run completes around it — leaving HEAD
69
- * broken while the repair is invisible unless someone runs `git status`.
62
+ * STRANDED SUB-FIXES.
70
63
  *
71
- * That is exactly what run 13 shipped: the fix child's bunfig.toml change made
72
- * `bun run test` pass 116/116, attempt 1 did not converge overall, the user accepted
73
- * the FAIL, and the tree still shows the file modified while HEAD's `bun run test` is
74
- * broken. The repair and the breakage were BOTH real; only the repair was discarded
75
- * by default.
64
+ * An attempt that does not converge KEEPS its edits only a guard trip
65
+ * discards and the caller commits only on `fix.ok`. So a partial fix that
66
+ * genuinely repaired something sits uncommitted in the working tree while HEAD
67
+ * still carries the defect, invisible unless someone runs `git status`.
76
68
  *
77
- * The rule: a partial fix is either committed (its own commit, named in the trail) or
78
- * explicitly surfaced — never silently stranded.
69
+ * The rule: a partial fix is either committed as its own named commit or
70
+ * explicitly surfaced — never silently stranded. `run-final-gate.ts` calls
71
+ * `commitStranded` on BOTH terminal outcomes, accept and leave-failed, so an
72
+ * unattended run that ends on LEAVE does not leave real repairs one `git
73
+ * checkout` from gone.
79
74
  *
80
- * mx5 run 14 proved the committing half only ever ran on the ACCEPT path. The run
81
- * ended on LEAVE (YOLO, budget spent) and 13 real repairs the dev script, the
82
- * teardown bug, test serialization, the migrate script: the changes that make that
83
- * app work today — were left dirty in the tree, one `git checkout` from gone, after
84
- * an UNATTENDED run nobody was watching. So EVERY terminal non-converged outcome
85
- * commits them now, not just ACCEPT. Only guard-CLEAN edits qualify: an attempt a
86
- * write-guard rejected without discarding leaves REJECTED edits in the tree, and
87
- * those are never committed (the guard is not weakened to make committing easier).
75
+ * Only guard-CLEAN edits qualify. `AutofixLedger.mayCommitTree()` goes false
76
+ * once a guard has rejected an attempt whose edits could not be discarded, and
77
+ * never flips back: the guard is not weakened to make committing easier.
88
78
  */
89
79
  /** Commit subject for partial fixes committed alongside a terminal gate FAIL. */
90
80
  export declare const STRANDED_FIX_COMMIT: (runId: string, outcome?: "accepted" | "left-failed") => string;
@@ -99,38 +89,32 @@ export interface FinalFixResult {
99
89
  /** Human-readable outcome (converged gate reason, or why the attempt failed). */
100
90
  reason: string;
101
91
  /**
102
- * The re-run gate's OUTCOME, whole — present whenever the gate actually ran
103
- * (absent only when the fix child self-declared blocked and the re-run was
104
- * skipped).
105
- *
106
- * This used to be four flattened `gate*` mirrors, and the flattening lost
107
- * things. `openDebts` never crossed at all, so `runFinalGateStage` rebuilt
108
- * `fin` as a literal three times and each literal dropped it — the recorded
109
- * mx5 run-18 defect, fixed by RE-DERIVING the field (`reconcileDebts`) rather
110
- * than by keeping the value. Then 19A had to push `observedFailures` across the
111
- * same wall as a third parallel field and re-pair it downstream by
112
- * `gateObservedFailures?.includes(detail)` — a membership test that exists only
113
- * because the pairing was broken in transit.
92
+ * The re-run gate's OUTCOME, whole — present whenever the gate actually ran,
93
+ * absent only when the fix child self-declared BLOCKED and the re-run was
94
+ * skipped. The whole `FinalGateOutcome` crosses, not a hand-picked copy of
95
+ * some of its fields: a copy silently drops whatever it forgot, and the
96
+ * pairing between `failures` and `observedFailures` only holds inside it.
114
97
  */
115
98
  gate?: FinalGateOutcome;
116
99
  /** On a converged outcome: the UNOBSERVED note the CALLER should show. It is
117
100
  * the gate's own note plus any downgrade this fix pass added (see the
118
101
  * ignored-dependency probe below), so it is not simply `gate.unobserved`. */
119
102
  unobserved?: string;
120
- /** Gitignored path(s) this fix pass wrote, exempt classes already removed (see
121
- * write-guard.ts). Present whether or not the gate converged the caller
122
- * trails them either way; path names only, never contents. */
103
+ /** Gitignored path(s) this fix pass wrote, with the exempt classes already
104
+ * removed (task dir, `.git`, node_modules, build outputwrite-guard.ts).
105
+ * Present whether or not the gate converged; path names only, never
106
+ * contents. */
123
107
  ignoredWrites?: string[];
124
108
  /** …and the mechanical dependency probe found the converged gate does NOT pass
125
109
  * without them, so `unobserved` above carries the downgrade. Absent when the
126
- * probe could not answer (no probe wired, restore risk, too many paths). */
110
+ * probe could not answer: no probe wired, a path that would not move, or more
111
+ * paths than its bound allows. */
127
112
  ignoredDependent?: boolean;
128
113
  /** A write-guard rejected this attempt (deletion / shrink / probe-gaming). */
129
114
  guardTripped?: boolean;
130
- /** …and its edits were discarded. When a guard tripped and this is false, the
131
- * working tree still holds REJECTED edits, so the caller must NOT commit what
132
- * it finds there (mx5 run 14 item 2b: commit surviving fix-pass edits — but
133
- * only guard-CLEAN ones; the cheat guard is never weakened to ease committing). */
115
+ /** …and its edits were discarded. False here with `guardTripped` true means
116
+ * the tree still holds REJECTED edits, and the caller must not commit what it
117
+ * finds: that is what `AutofixLedger.mayCommitTree()` latches off. */
134
118
  editsDiscarded?: boolean;
135
119
  }
136
120
  export interface FinalFixDeps {
@@ -143,34 +127,37 @@ export interface FinalFixDeps {
143
127
  runChild: (tools: string, prompt: string, signal?: AbortSignal) => Promise<string>;
144
128
  /** Re-run the final integration gate — the only arbiter of convergence.
145
129
  * Converges only when the gate's FULL aggregated failure list is empty
146
- * (ok=true); `failures` rides through so the caller sees every entry. */
147
- /** Returns the gate's own outcome type, not a structural copy of five of its
148
- * fields — a re-declaration is how `openDebts` came to be silently absent. */
130
+ * (ok=true); `failures` rides through so the caller sees every entry.
131
+ * Typed as the gate's own outcome, not a structural copy of some fields. */
149
132
  gate: (cwd: string) => Promise<FinalGateOutcome>;
150
- /** Labels of every currently-discoverable gate command (static + integration),
151
- * for the shrink guard. Pure discovery nothing is executed. */
133
+ /** Labels of every currently-discoverable gate command health, lockfile,
134
+ * integration and boot — for the shrink guard. Pure discovery: nothing
135
+ * runs. */
152
136
  discoverLabels: (cwd: string) => string[];
153
137
  /** The same commands' RESOLVED BODIES (`label → scripts[name]` / Makefile
154
138
  * recipe), for the scope-shrink half of the guard. Absent → only the label
155
- * comparison runs, i.e. the pre-run-19 behaviour. */
139
+ * comparison runs. */
156
140
  discoverBodies?: (cwd: string) => Record<string, string>;
157
141
  /** Discard the fix child's working-tree edits (guard trips only). Absent
158
142
  * → the violation is still rejected, edits are left for inspection. */
159
143
  discard?: (cwd: string) => Promise<void>;
160
- /** The fix child's tree changes (`git status --porcelain` shape)diff capture
161
- * for the log and the deletion guard's input. The tree was clean before the
162
- * child ran (every task committed), so status IS the child's work. */
144
+ /** Tree changes in `git status --porcelain` shape — the deletion guard's input
145
+ * and the "created by this fix" set the scope-shrink guard consults. Every
146
+ * task is committed before this stage, so what status reports is fix-pass
147
+ * work; on a second attempt that includes the first attempt's kept edits,
148
+ * since a non-converged attempt is not discarded. */
163
149
  treeChanges?: () => Promise<TreeChangeSummary>;
164
150
  /** The union of every task spec's frozen (Do-NOT-modify) paths — the whole-run
165
151
  * write-deny set, since this child works across all slices at once. */
166
152
  frozenPaths?: () => Promise<string[]>;
167
- /** Restore the given frozen paths to HEAD; returns the files actually reverted
168
- * (same mechanical deny the enforce pass carries — see frozen-path-guard.ts). */
153
+ /** Restore the given frozen paths to HEAD; returns the files actually reverted.
154
+ * `frozen-path-guard.ts`'s `revertFrozenPaths`, the same one the per-task
155
+ * passes use. */
169
156
  revertFrozen?: (paths: string[]) => Promise<string[]>;
170
- /** Deterministic probe scan over the child's ADDED lines (probe-gaming, F6):
171
- * a fix written to game a check rather than meet it rejects the attempt —
172
- * run 11's autofix replaced the typed client with a hand-written contract
173
- * copy to green the lint. Findings are verbatim offending lines. */
157
+ /** Deterministic probe scan over the child's ADDED lines: a fix whose own
158
+ * added text says it is gaming a check rather than meeting it rejects the
159
+ * attempt. There is no verify child downstream of this pass to judge such a
160
+ * finding. Findings are the verbatim offending lines. */
174
161
  probeScan?: () => Promise<string[]>;
175
162
  /** Fingerprint of the ACTIONABLE ignored paths (build output and node_modules
176
163
  * already exempt). Called before and after the child; the difference is what
@@ -189,9 +176,10 @@ export interface FinalFixDeps {
189
176
  log?: (msg: string) => void;
190
177
  }
191
178
  /**
192
- * Run one bounded final-gate fix attempt: snapshot discovery child write-guard
193
- * stack (diff capture → frozen-path revert → deletion guard → shrink guard → probe
194
- * scan) → gate re-run. Never throws for an outcome; only a user cancel inside
195
- * runChild propagates (the caller's USER_CANCELLED path handles it).
179
+ * Run one bounded final-gate fix attempt: snapshot discovery and ignored paths
180
+ * child → frozen-path revert → deletion guard → shrink guard → scope-shrink
181
+ * guard → probe scan → gate re-run. Never throws for an outcome; only a user
182
+ * cancel inside runChild propagates, and the caller's USER_CANCELLED path
183
+ * handles that.
196
184
  */
197
185
  export declare function runFinalGateAutofix(deps: FinalFixDeps): Promise<FinalFixResult>;
@@ -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);