@mjasnikovs/pi-task 0.38.29 → 0.38.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (370) hide show
  1. package/dist/config/config.d.ts +70 -70
  2. package/dist/config/config.js +26 -35
  3. package/dist/config/extension-list.d.ts +6 -5
  4. package/dist/config/extension-list.js +3 -2
  5. package/dist/config/reasoning-args.d.ts +9 -7
  6. package/dist/config/reasoning-args.js +12 -10
  7. package/dist/config/reasoning.d.ts +44 -105
  8. package/dist/config/reasoning.js +27 -704
  9. package/dist/config/register.d.ts +34 -48
  10. package/dist/config/register.js +41 -51
  11. package/dist/config/tool-list.d.ts +16 -16
  12. package/dist/config/tool-list.js +1 -1
  13. package/dist/remote/bridge.d.ts +19 -10
  14. package/dist/remote/bridge.js +3 -2
  15. package/dist/remote/broadcast.js +3 -1
  16. package/dist/remote/events.js +12 -11
  17. package/dist/remote/history.d.ts +1 -1
  18. package/dist/remote/protocol.d.ts +6 -3
  19. package/dist/remote/protocol.js +2 -1
  20. package/dist/remote/push.d.ts +16 -16
  21. package/dist/remote/push.js +27 -27
  22. package/dist/remote/register.d.ts +3 -3
  23. package/dist/remote/register.js +17 -19
  24. package/dist/remote/server.d.ts +9 -8
  25. package/dist/remote/server.js +15 -14
  26. package/dist/remote/session-state.d.ts +5 -4
  27. package/dist/remote/session-state.js +8 -5
  28. package/dist/remote/sw.d.ts +7 -6
  29. package/dist/remote/sw.js +7 -6
  30. package/dist/remote/tailscale.d.ts +4 -2
  31. package/dist/remote/tailscale.js +4 -2
  32. package/dist/remote/ui-highlight.js +6 -5
  33. package/dist/remote/ui-render.js +4 -4
  34. package/dist/remote/ui-script.js +24 -24
  35. package/dist/remote/ui-styles.d.ts +1 -1
  36. package/dist/remote/ui-styles.js +10 -13
  37. package/dist/remote/ui-tools.js +9 -6
  38. package/dist/shared/child-extensions.d.ts +29 -17
  39. package/dist/shared/child-extensions.js +29 -17
  40. package/dist/shared/child-output.d.ts +30 -24
  41. package/dist/shared/child-output.js +25 -17
  42. package/dist/shared/child-process.d.ts +47 -40
  43. package/dist/shared/child-process.js +50 -59
  44. package/dist/shared/command-watchdog.d.ts +22 -16
  45. package/dist/shared/command-watchdog.js +28 -21
  46. package/dist/shared/fs-text.d.ts +16 -10
  47. package/dist/shared/fs-text.js +16 -10
  48. package/dist/shared/git-runner.d.ts +25 -25
  49. package/dist/shared/git-runner.js +25 -25
  50. package/dist/shared/leaked-tool-call.d.ts +17 -11
  51. package/dist/shared/leaked-tool-call.js +23 -15
  52. package/dist/shared/model-endpoint.d.ts +29 -16
  53. package/dist/shared/model-endpoint.js +33 -21
  54. package/dist/shared/pi-invocation.d.ts +7 -4
  55. package/dist/shared/pi-invocation.js +12 -7
  56. package/dist/shared/pkg-version.d.ts +13 -5
  57. package/dist/shared/pkg-version.js +13 -5
  58. package/dist/shared/reasoning-capability.d.ts +35 -24
  59. package/dist/shared/reasoning-capability.js +35 -24
  60. package/dist/shared/stream-watchdog.d.ts +60 -44
  61. package/dist/shared/stream-watchdog.js +62 -45
  62. package/dist/task/accept-debt.d.ts +41 -43
  63. package/dist/task/accept-debt.js +73 -65
  64. package/dist/task/api-synthesis.d.ts +24 -21
  65. package/dist/task/api-synthesis.js +32 -26
  66. package/dist/task/apis-contract.d.ts +32 -64
  67. package/dist/task/apis-contract.js +32 -64
  68. package/dist/task/artifact-closure.d.ts +27 -13
  69. package/dist/task/artifact-closure.js +95 -67
  70. package/dist/task/auto-commit.d.ts +46 -35
  71. package/dist/task/auto-commit.js +51 -38
  72. package/dist/task/auto-io.d.ts +45 -25
  73. package/dist/task/auto-io.js +57 -29
  74. package/dist/task/auto-orchestrator.d.ts +26 -24
  75. package/dist/task/auto-orchestrator.js +178 -162
  76. package/dist/task/auto-prompts.d.ts +36 -24
  77. package/dist/task/auto-prompts.js +40 -26
  78. package/dist/task/autofix-ledger.d.ts +27 -25
  79. package/dist/task/autofix-ledger.js +29 -26
  80. package/dist/task/batch-test-task.d.ts +20 -12
  81. package/dist/task/batch-test-task.js +67 -60
  82. package/dist/task/boot-probe.d.ts +60 -44
  83. package/dist/task/boot-probe.js +91 -72
  84. package/dist/task/cancel-input.d.ts +30 -16
  85. package/dist/task/cancel-input.js +20 -11
  86. package/dist/task/cancel-points.d.ts +27 -20
  87. package/dist/task/cancel-points.js +30 -22
  88. package/dist/task/child-runner.d.ts +46 -51
  89. package/dist/task/child-runner.js +48 -49
  90. package/dist/task/child-status.d.ts +23 -16
  91. package/dist/task/child-status.js +23 -16
  92. package/dist/task/clamp-output.js +12 -5
  93. package/dist/task/command-run.d.ts +31 -28
  94. package/dist/task/command-run.js +44 -35
  95. package/dist/task/command-shrink.d.ts +25 -18
  96. package/dist/task/command-shrink.js +37 -31
  97. package/dist/task/command-watchdog.d.ts +9 -6
  98. package/dist/task/command-watchdog.js +21 -15
  99. package/dist/task/context-attribution.d.ts +34 -26
  100. package/dist/task/context-attribution.js +34 -26
  101. package/dist/task/context-silence.d.ts +39 -29
  102. package/dist/task/context-silence.js +35 -25
  103. package/dist/task/context-usage.d.ts +16 -9
  104. package/dist/task/context-usage.js +16 -9
  105. package/dist/task/contracts.d.ts +8 -4
  106. package/dist/task/contracts.js +25 -17
  107. package/dist/task/coverage-loop.d.ts +22 -18
  108. package/dist/task/coverage-loop.js +35 -30
  109. package/dist/task/critique-probes.d.ts +13 -14
  110. package/dist/task/critique-probes.js +50 -39
  111. package/dist/task/debug-log.d.ts +13 -5
  112. package/dist/task/debug-log.js +32 -20
  113. package/dist/task/decompose-fidelity.d.ts +11 -9
  114. package/dist/task/decompose-fidelity.js +38 -33
  115. package/dist/task/decompose-granularity.d.ts +41 -38
  116. package/dist/task/decompose-granularity.js +41 -38
  117. package/dist/task/deep-render-check.d.ts +22 -14
  118. package/dist/task/deep-render-check.js +40 -31
  119. package/dist/task/dropped-input.d.ts +12 -7
  120. package/dist/task/dropped-input.js +5 -2
  121. package/dist/task/enforce-attribution.d.ts +38 -47
  122. package/dist/task/enforce-attribution.js +46 -52
  123. package/dist/task/enforce-guidelines.d.ts +31 -20
  124. package/dist/task/enforce-guidelines.js +32 -21
  125. package/dist/task/enrichment.d.ts +7 -2
  126. package/dist/task/enrichment.js +26 -14
  127. package/dist/task/env-notes.d.ts +16 -7
  128. package/dist/task/env-notes.js +48 -31
  129. package/dist/task/env-template-closure.d.ts +4 -4
  130. package/dist/task/env-template-closure.js +42 -34
  131. package/dist/task/external-context.d.ts +28 -21
  132. package/dist/task/external-context.js +17 -12
  133. package/dist/task/failure-classifier.d.ts +4 -5
  134. package/dist/task/failure-classifier.js +6 -7
  135. package/dist/task/file-inventory.d.ts +15 -11
  136. package/dist/task/file-inventory.js +25 -22
  137. package/dist/task/final-gate-fix.d.ts +74 -86
  138. package/dist/task/final-gate-fix.js +97 -116
  139. package/dist/task/final-gate-progress.d.ts +29 -46
  140. package/dist/task/final-gate-progress.js +40 -51
  141. package/dist/task/final-gate.d.ts +64 -97
  142. package/dist/task/final-gate.js +192 -199
  143. package/dist/task/fix-child.d.ts +21 -27
  144. package/dist/task/fix-child.js +21 -27
  145. package/dist/task/foreign-path.d.ts +6 -5
  146. package/dist/task/foreign-path.js +0 -0
  147. package/dist/task/frozen-conflict.d.ts +9 -10
  148. package/dist/task/frozen-conflict.js +61 -64
  149. package/dist/task/frozen-path-guard.d.ts +35 -14
  150. package/dist/task/frozen-path-guard.js +56 -39
  151. package/dist/task/gate-child.d.ts +27 -28
  152. package/dist/task/gate-child.js +36 -35
  153. package/dist/task/gate-deps.d.ts +34 -27
  154. package/dist/task/gate-deps.js +169 -159
  155. package/dist/task/gate-tally.d.ts +77 -80
  156. package/dist/task/gate-tally.js +65 -68
  157. package/dist/task/git-state-guard.d.ts +15 -11
  158. package/dist/task/git-state-guard.js +76 -66
  159. package/dist/task/impl-widget.d.ts +25 -16
  160. package/dist/task/impl-widget.js +27 -17
  161. package/dist/task/implementation-thinking.d.ts +33 -31
  162. package/dist/task/implementation-thinking.js +5 -6
  163. package/dist/task/implementation-turn.d.ts +34 -31
  164. package/dist/task/implementation-turn.js +29 -27
  165. package/dist/task/inline-markdown.d.ts +20 -7
  166. package/dist/task/inline-markdown.js +15 -6
  167. package/dist/task/launch-config-gap.js +25 -39
  168. package/dist/task/launch-contract.d.ts +18 -21
  169. package/dist/task/launch-contract.js +28 -30
  170. package/dist/task/launch-manifest.d.ts +6 -2
  171. package/dist/task/launch-manifest.js +35 -34
  172. package/dist/task/ledger.js +16 -14
  173. package/dist/task/lint-fix.d.ts +6 -8
  174. package/dist/task/lint-fix.js +67 -69
  175. package/dist/task/loop-detector.d.ts +9 -8
  176. package/dist/task/loop-detector.js +16 -12
  177. package/dist/task/mid-run-input.d.ts +17 -15
  178. package/dist/task/mid-run-input.js +17 -15
  179. package/dist/task/orchestrator.d.ts +24 -28
  180. package/dist/task/orchestrator.js +62 -64
  181. package/dist/task/orientation.d.ts +18 -23
  182. package/dist/task/orientation.js +24 -31
  183. package/dist/task/owned-freeze-conflict.d.ts +21 -20
  184. package/dist/task/owned-freeze-conflict.js +52 -85
  185. package/dist/task/owned-freeze-reassign.d.ts +40 -60
  186. package/dist/task/owned-freeze-reassign.js +41 -61
  187. package/dist/task/parsers.d.ts +4 -2
  188. package/dist/task/parsers.js +4 -4
  189. package/dist/task/phases.d.ts +41 -48
  190. package/dist/task/phases.js +179 -248
  191. package/dist/task/plan-io.d.ts +6 -7
  192. package/dist/task/plan-io.js +6 -7
  193. package/dist/task/plan-orchestrator.d.ts +10 -8
  194. package/dist/task/plan-orchestrator.js +14 -10
  195. package/dist/task/plan-prompts.d.ts +6 -5
  196. package/dist/task/plan-prompts.js +6 -5
  197. package/dist/task/plan-readonly.d.ts +4 -5
  198. package/dist/task/plan-readonly.js +4 -5
  199. package/dist/task/plan-rounds.d.ts +17 -29
  200. package/dist/task/plan-rounds.js +21 -34
  201. package/dist/task/plan-session.d.ts +58 -72
  202. package/dist/task/plan-session.js +61 -83
  203. package/dist/task/probe-gaming.d.ts +28 -27
  204. package/dist/task/probe-gaming.js +0 -0
  205. package/dist/task/prohibition-probe.d.ts +14 -16
  206. package/dist/task/prompts.d.ts +3 -4
  207. package/dist/task/prompts.js +17 -26
  208. package/dist/task/qa-transcript.d.ts +15 -22
  209. package/dist/task/qa-transcript.js +15 -21
  210. package/dist/task/question-box.d.ts +17 -13
  211. package/dist/task/question-box.js +19 -15
  212. package/dist/task/question-dedup.d.ts +6 -7
  213. package/dist/task/question-dedup.js +13 -14
  214. package/dist/task/question-dialog.d.ts +22 -32
  215. package/dist/task/question-dialog.js +22 -32
  216. package/dist/task/question-source.d.ts +18 -44
  217. package/dist/task/question-source.js +22 -51
  218. package/dist/task/refuted-constraint.d.ts +11 -31
  219. package/dist/task/refuted-constraint.js +27 -51
  220. package/dist/task/regenerable-artifacts.d.ts +12 -31
  221. package/dist/task/regenerable-artifacts.js +12 -31
  222. package/dist/task/render-check.d.ts +11 -22
  223. package/dist/task/render-check.js +33 -46
  224. package/dist/task/repo-health-check.d.ts +10 -14
  225. package/dist/task/repo-health-check.js +17 -23
  226. package/dist/task/requirements.d.ts +38 -71
  227. package/dist/task/requirements.js +78 -126
  228. package/dist/task/research-fanout-budget.d.ts +51 -88
  229. package/dist/task/research-fanout-budget.js +51 -88
  230. package/dist/task/research-worker.d.ts +29 -39
  231. package/dist/task/research-worker.js +37 -61
  232. package/dist/task/resume-gap.d.ts +14 -15
  233. package/dist/task/root-cause-repair.d.ts +9 -9
  234. package/dist/task/root-cause-repair.js +28 -40
  235. package/dist/task/run-bracket.d.ts +10 -13
  236. package/dist/task/run-end.d.ts +12 -22
  237. package/dist/task/run-end.js +8 -16
  238. package/dist/task/run-final-gate.d.ts +19 -21
  239. package/dist/task/run-final-gate.js +62 -80
  240. package/dist/task/runner-globs.d.ts +12 -13
  241. package/dist/task/runner-globs.js +12 -13
  242. package/dist/task/runner-resolve.d.ts +9 -9
  243. package/dist/task/runner-resolve.js +22 -23
  244. package/dist/task/script-escape.d.ts +10 -12
  245. package/dist/task/script-escape.js +13 -14
  246. package/dist/task/serve-entry.d.ts +1 -1
  247. package/dist/task/serve-entry.js +22 -25
  248. package/dist/task/service-blocks.js +4 -2
  249. package/dist/task/shipped-source.d.ts +11 -29
  250. package/dist/task/shipped-source.js +11 -29
  251. package/dist/task/skip-escape.js +10 -14
  252. package/dist/task/spec-urls.d.ts +26 -65
  253. package/dist/task/spec-urls.js +26 -65
  254. package/dist/task/spec-validation.d.ts +17 -20
  255. package/dist/task/spec-validation.js +17 -20
  256. package/dist/task/stall-detector.d.ts +23 -30
  257. package/dist/task/stall-detector.js +23 -30
  258. package/dist/task/stream-watchdog.d.ts +14 -12
  259. package/dist/task/stream-watchdog.js +14 -12
  260. package/dist/task/substitution-probe.d.ts +17 -20
  261. package/dist/task/substitution-probe.js +17 -20
  262. package/dist/task/task-gates.d.ts +36 -41
  263. package/dist/task/task-gates.js +95 -106
  264. package/dist/task/task-io.d.ts +4 -4
  265. package/dist/task/task-io.js +4 -4
  266. package/dist/task/task-parsers.js +4 -3
  267. package/dist/task/task-provenance.d.ts +2 -2
  268. package/dist/task/task-provenance.js +11 -13
  269. package/dist/task/task-types.d.ts +4 -3
  270. package/dist/task/terminal-outcome.d.ts +14 -16
  271. package/dist/task/terminal-outcome.js +12 -14
  272. package/dist/task/test-assembly.d.ts +13 -20
  273. package/dist/task/test-assembly.js +13 -20
  274. package/dist/task/timings.d.ts +5 -3
  275. package/dist/task/timings.js +5 -3
  276. package/dist/task/title-label.d.ts +9 -4
  277. package/dist/task/title-label.js +9 -4
  278. package/dist/task/type-only-answer.d.ts +44 -52
  279. package/dist/task/type-only-answer.js +44 -52
  280. package/dist/task/unfailable-command.d.ts +18 -24
  281. package/dist/task/unfailable-command.js +21 -27
  282. package/dist/task/unknown-routing.d.ts +10 -4
  283. package/dist/task/unknown-routing.js +10 -4
  284. package/dist/task/user-directives.d.ts +5 -8
  285. package/dist/task/user-directives.js +5 -8
  286. package/dist/task/verify-quality.d.ts +18 -22
  287. package/dist/task/verify-quality.js +45 -46
  288. package/dist/task/verify-reconcile.d.ts +15 -10
  289. package/dist/task/verify-reconcile.js +45 -43
  290. package/dist/task/verify-resolution.d.ts +24 -20
  291. package/dist/task/verify-resolution.js +51 -50
  292. package/dist/task/verify-work.d.ts +59 -66
  293. package/dist/task/verify-work.js +101 -138
  294. package/dist/task/widget.d.ts +15 -14
  295. package/dist/task/widget.js +22 -17
  296. package/dist/task/wiring-claims.d.ts +25 -32
  297. package/dist/task/wiring-claims.js +30 -35
  298. package/dist/task/write-guard.d.ts +39 -39
  299. package/dist/task/write-guard.js +48 -51
  300. package/dist/task/yolo.d.ts +34 -30
  301. package/dist/task/yolo.js +42 -37
  302. package/dist/workers/abstention.d.ts +21 -41
  303. package/dist/workers/abstention.js +27 -48
  304. package/dist/workers/brave-search.d.ts +4 -3
  305. package/dist/workers/brave-search.js +5 -2
  306. package/dist/workers/brave-warning.d.ts +7 -4
  307. package/dist/workers/brave-warning.js +19 -7
  308. package/dist/workers/ddg-search.d.ts +6 -6
  309. package/dist/workers/ddg-search.js +18 -12
  310. package/dist/workers/docs-cache.js +5 -2
  311. package/dist/workers/docs-chunk.d.ts +30 -37
  312. package/dist/workers/docs-chunk.js +37 -41
  313. package/dist/workers/docs-core.d.ts +28 -44
  314. package/dist/workers/docs-core.js +25 -44
  315. package/dist/workers/docs-index.js +4 -3
  316. package/dist/workers/docs-lookup.d.ts +15 -22
  317. package/dist/workers/docs-lookup.js +12 -21
  318. package/dist/workers/docs-project.d.ts +15 -9
  319. package/dist/workers/docs-project.js +17 -10
  320. package/dist/workers/docs-resolve.d.ts +19 -20
  321. package/dist/workers/docs-resolve.js +35 -32
  322. package/dist/workers/docs-retrieve.d.ts +5 -6
  323. package/dist/workers/docs-retrieve.js +18 -15
  324. package/dist/workers/exa-search.d.ts +9 -6
  325. package/dist/workers/exa-search.js +23 -12
  326. package/dist/workers/fetch-core.d.ts +13 -16
  327. package/dist/workers/fetch-core.js +23 -23
  328. package/dist/workers/focused-extractor.d.ts +12 -12
  329. package/dist/workers/focused-extractor.js +16 -19
  330. package/dist/workers/html-clean.js +24 -14
  331. package/dist/workers/http-request.d.ts +28 -20
  332. package/dist/workers/http-request.js +22 -17
  333. package/dist/workers/npm-version.d.ts +28 -11
  334. package/dist/workers/npm-version.js +24 -15
  335. package/dist/workers/phantom-imports.d.ts +15 -12
  336. package/dist/workers/phantom-imports.js +30 -24
  337. package/dist/workers/pi-worker-core.d.ts +69 -71
  338. package/dist/workers/pi-worker-core.js +100 -109
  339. package/dist/workers/pi-worker-docs.d.ts +24 -19
  340. package/dist/workers/pi-worker-docs.js +67 -76
  341. package/dist/workers/pi-worker-fetch.d.ts +7 -3
  342. package/dist/workers/pi-worker-fetch.js +27 -19
  343. package/dist/workers/pi-worker-search.js +12 -8
  344. package/dist/workers/pi-worker.d.ts +9 -4
  345. package/dist/workers/pi-worker.js +21 -14
  346. package/dist/workers/reasoning-warning.d.ts +18 -17
  347. package/dist/workers/reasoning-warning.js +22 -20
  348. package/dist/workers/research-cache.js +50 -78
  349. package/dist/workers/search-core.js +7 -5
  350. package/dist/workers/search-types.d.ts +10 -9
  351. package/dist/workers/search-types.js +9 -8
  352. package/dist/workers/session-hint.d.ts +13 -14
  353. package/dist/workers/session-hint.js +8 -9
  354. package/dist/workers/shared.d.ts +21 -25
  355. package/dist/workers/shared.js +0 -0
  356. package/dist/workers/single-read-extension.d.ts +14 -7
  357. package/dist/workers/single-read-extension.js +14 -7
  358. package/dist/workers/single-read-guard.d.ts +25 -28
  359. package/dist/workers/single-read-guard.js +32 -32
  360. package/dist/workers/typeonly-log.d.ts +12 -9
  361. package/dist/workers/typeonly-log.js +29 -33
  362. package/dist/workers/worker-channels.d.ts +15 -23
  363. package/dist/workers/worker-channels.js +15 -23
  364. package/dist/workers/worker-failure.d.ts +38 -46
  365. package/dist/workers/worker-failure.js +31 -39
  366. package/dist/workers/worker-kill.d.ts +25 -26
  367. package/dist/workers/worker-kill.js +16 -19
  368. package/dist/workers/worker-profiles.d.ts +43 -53
  369. package/dist/workers/worker-profiles.js +30 -38
  370. package/package.json +10 -8
@@ -1,79 +1,43 @@
1
1
  /**
2
- * owned-freeze-conflict — the FIFTH unsatisfiable-pair family (nexttask 7):
3
- * an AUTHORITATIVE owned requirement whose file falls inside a CATEGORY freeze
4
- * written by the same spec.
2
+ * owned-freeze-conflict — an unsatisfiable spec pair: an AUTHORITATIVE owned
3
+ * requirement whose file falls inside a CATEGORY freeze written by the same spec.
5
4
  *
6
- * WHY frozen-conflict.ts does not see it (mx5 run 18, TASK_0023). The owned
7
- * channel worked: `.pi-tasks/requirements-owned.md` carried the design clause
8
- * "**Server:** `bun run --watch src/server/index.ts` serves `/api` + static
9
- * `dist/`." and the composed spec carried it verbatim under CONSTRAINTS, marked
10
- * AUTHORITATIVE. The same CONSTRAINTS block then said "Do not modify
11
- * `docker-compose.dev.yml`, …, or any source files outside of `package.json`",
12
- * and the spec's ACCEPTANCE/VERIFY converted the behavioural half of the clause
13
- * ("serves `/api` + static `dist/`") into a string-match on `package.json`. The
14
- * only file that could implement it — `src/server/index.ts` — was frozen. The
15
- * requirement was structurally unsatisfiable inside its owning task, VERIFY
16
- * PASSed honestly, and the app shipped with no static route.
5
+ * THE SHAPE. A spec carries a design clause verbatim under CONSTRAINTS, marked
6
+ * AUTHORITATIVE, whose behavioural half can only be satisfied inside one file —
7
+ * and the same spec freezes a category of files that covers that file. The task's
8
+ * own VERIFY can then only assert strings in the files it is allowed to touch, so
9
+ * it PASSes honestly while the requirement is never met.
17
10
  *
18
- * The existing detector misses this shape twice over (both visible in its own
19
- * header): its freeze side needs a NAMED path (`pathNamedIn`), and run 18's
20
- * freeze names a CATEGORY ("any source files outside of `package.json`"); its
21
- * statement side must match one of four measured phrasing families, and a plain
22
- * behavioural claim matches none of them.
11
+ * WHY frozen-conflict.ts does not see it. Its freeze side needs a NAMED path
12
+ * (`pathNamedIn`), and a category freeze names a CLASS instead. Its statement side
13
+ * must match one of a fixed set of registration phrasings, and a plain behavioural
14
+ * claim matches none of them.
23
15
  *
24
16
  * HIGH-PRECISION BY CONSTRUCTION — the statement side needs no NLP:
25
17
  * - owned requirement lines are MACHINE-MARKED. `appendOwnedConstraints`
26
- * stamps every one it appends with "owned requirement from the source
27
- * design (AUTHORITATIVE; …)"; when compose folded the quote in by itself
28
- * the marker is absent, so the caller may also pass the run's ledger
29
- * entries and the quote is matched verbatim against the spec text.
18
+ * (requirements.ts) stamps every bullet it appends with "owned requirement
19
+ * from the source design (AUTHORITATIVE; satisfy it in this task, do not
20
+ * narrow it)". When compose folded the quote in by itself the marker is
21
+ * absent, so the caller may also pass the run's ledger entries and the quote
22
+ * is matched verbatim against the spec text.
30
23
  * - the requirement names its path literally, so the intersection is lexical.
31
- * - category freezes are a small closed lexical set ("any source files
32
- * outside of X", "any files other than X", "only X may be modified",
33
- * "no files outside X").
24
+ * - category freezes are a small closed lexical set ("any source files outside
25
+ * of X", "any files other than X", "only X may be modified", "no files
26
+ * outside X").
34
27
  *
35
- * ── STATUS, 2026-08-05: WIRED but as a DETACH, not as a rewrite. ──────────
36
- *
37
- * `owned-freeze-reassign.ts` consumes this detector at the last spec-producing
38
- * step (`phases.ts`, right after `appendOwnedConstraints`) and resolves a finding
28
+ * WHERE IT RUNS, AND WHY IT CANNOT RUN EARLIER. `owned-freeze-reassign.ts`
29
+ * consumes this detector inside `critiquePhase`, immediately after
30
+ * `appendOwnedConstraints` the last spec-producing step. It resolves a finding
39
31
  * by BOOKKEEPING: the requirement leaves the task that cannot satisfy it and is
40
32
  * claimed later by the task whose refined prompt says it writes the frozen file.
41
- * The quote is never edited, so the deletion failure below cannot recur. A/B-1
42
- * (scripts/owned-freeze-reassign-ab.ts) PASSes on the corpus with five
43
- * invariants. The rewrite lever recorded below stays REFUTED and unwired.
44
- *
45
- * ── The critique-REWRITE seam FAILED its A/B, 2026-08-04. ────────────────────
46
- *
47
- * The detector is precise — 1 finding over 58 real composed specs, and it is the
48
- * true positive (scripts/owned-freeze-conflict-fp-suite.ts, PASS; STEP 0 in
49
- * scripts/owned-vs-freeze-baserate.ts). What failed is the LEVER built on it,
50
- * for two independent reasons, both measured:
33
+ * The quote itself is never edited.
51
34
  *
52
- * 1. THE SEAM IS BLIND IN PRODUCTION. `appendOwnedConstraints` — the BRACES that
53
- * stamp the machine-marked owned bullet this detector keys on — runs AFTER
54
- * `critiqueWithFallback`, inside the `critique` step (phases.ts). When
55
- * critique runs, the stamped line does not exist yet; compose's own folding
56
- * is a PARAPHRASE ("The server watch command must match the contract exactly:
57
- * `…` — serves `/api` + static `dist/`"), so neither the stamp nor the
58
- * verbatim quote is there to match. Live: 0/40 compose drafts carried a
59
- * detectable pair while 11/40 carried the clause semantically. A critique-
60
- * time probe cannot see the shape it was designed for.
61
- * 2. THE REWRITE RESOLVES IT BY DELETING THE REQUIREMENT. Forced through the
62
- * controlled critique seam on run 18's real TASK_0023 draft (n=20/arm):
63
- * pair-present 8/20 → 0/20, but the resolution was scoped ownership in only
64
- * 9/20 — the other 11/20 removed the AUTHORITATIVE clause outright and
65
- * rationalised it ("this references an existing file; no edits are required
66
- * or permitted"), with 0 of the 11 reassigning it to the task that owns the
67
- * file. VERIFY behaviour-observation was 6/20 in BOTH arms: the delivered
68
- * spec still verifies the requirement by grepping `package.json`.
35
+ * A critique-time probe cannot work, because `critiquePhase` calls
36
+ * `critiqueWithFallback` BEFORE `appendOwnedConstraints`: when critique runs, the
37
+ * stamped line does not exist yet, and compose's own folding is a paraphrase, so
38
+ * neither the stamp nor a verbatim quote is there to match.
69
39
  *
70
- * Removal of the pair is not satisfaction of the requirement the same lesson
71
- * as the run-16 lever's delivery metric, one level down. Anything built here
72
- * next has to act AFTER the braces, where the pair actually exists, and cannot
73
- * be a model rewrite: the braces are the last spec-producing step.
74
- *
75
- * It is a pure text function so the base rate, the FP suite and the live A/B all
76
- * measure the same object.
40
+ * It is a pure text function, so a test measures the same object production does.
77
41
  */
78
42
  import { PROHIBITION_RE } from './prohibition-probe.js';
79
43
  import { pathNamedIn } from './frozen-path-guard.js';
@@ -87,14 +51,14 @@ const OWNED_MARKER_RE = /owned\s+requirement\s+from\s+the\s+source\s+design/i;
87
51
  * Modification verbs, shared by the active and passive freeze families. Scoped
88
52
  * to modification exactly as `PROHIBITION_RE` is: a "do not CREATE any files
89
53
  * other than X" line is a creation ban and freezes no existing file, so it must
90
- * never be read as a category freeze (mx5 run 18 TASK_0009 ships that line).
54
+ * never be read as a category freeze.
91
55
  */
92
56
  const MOD_VERB = 'modif|touch|edit|chang|alter|rewrit|overwrit';
93
57
  /**
94
58
  * A category noun phrase with an exception: "any source files outside of X",
95
- * "any existing file other than X", "no files except X". `\w+` slots absorb the
96
- * qualifiers seen in the corpora (source/existing/other), bounded so the phrase
97
- * cannot span a whole paragraph.
59
+ * "any existing file other than X", "no files except X". The `\w+` slots absorb
60
+ * qualifiers like source/existing/other, and are bounded so the phrase cannot
61
+ * span a whole paragraph.
98
62
  */
99
63
  const CATEGORY_NOUN = String.raw `(?:any|no)\s+(?:\w+\s+){0,3}?files?\b`;
100
64
  const EXCEPT_KEYWORD = String.raw `(?:outside(?:\s+of)?|other\s+than|except(?:\s+for)?|besides|apart\s+from|beyond)`;
@@ -108,8 +72,8 @@ const ACTIVE_CATEGORY_RE = new RegExp(String.raw `\b(?:do\s+not|do\s+NOT|don'?t|
108
72
  + String.raw `(?:(?!\b(?:creat|add|introduc|generat)\w*\b)[\s\S]){0,200}?`
109
73
  + String.raw `\b${CATEGORY_NOUN}[^\n]{0,40}?\b${EXCEPT_KEYWORD}\b`, 'i');
110
74
  /**
111
- * Passive family: "No files other than `package.json` are modified." — run 18's
112
- * ACCEPTANCE line, identical in force to the CONSTRAINTS freeze above it.
75
+ * Passive family: "No files other than `package.json` are modified." — the shape
76
+ * an ACCEPTANCE line takes, identical in force to a CONSTRAINTS freeze.
113
77
  */
114
78
  const PASSIVE_CATEGORY_RE = new RegExp(String.raw `\b${CATEGORY_NOUN}[^\n]{0,40}?\b${EXCEPT_KEYWORD}\b`
115
79
  + String.raw `[^\n]{0,120}?\b(?:are|is|may|must|should|can|will)\s+(?:be\s+|been\s+)?(?:${MOD_VERB})\w*`, 'i');
@@ -147,8 +111,8 @@ function tokensWithOrigin(text) {
147
111
  continue;
148
112
  }
149
113
  // A leading `/` is a route literal or an absolute path — never a
150
- // repo-relative source file, and `/api` is named by the very clause
151
- // that is the true positive, so this one is not hypothetical.
114
+ // repo-relative source file. Behavioural clauses routinely name routes
115
+ // (`/api`) beside the file that serves them.
152
116
  if (token.startsWith('/'))
153
117
  continue;
154
118
  const n = token.replace(/^\.\//, '').replace(/\/+$/, '');
@@ -164,8 +128,7 @@ function tokensWithOrigin(text) {
164
128
  * Does the requirement claim anything about the files it names BEYOND quoting a
165
129
  * command that mentions them?
166
130
  *
167
- * This is what separates the two build-contract clauses of mx5 run 18's
168
- * TASK_0023, which are otherwise the same shape:
131
+ * This is what separates two build-contract clauses of the same shape:
169
132
  *
170
133
  * "**Client CSS:** `bunx @tailwindcss/cli -i src/client/index.css -o dist/app.css`"
171
134
  * "**Server:** `bun run --watch src/server/index.ts` — serves `/api` + static `dist/`."
@@ -191,7 +154,7 @@ function hasClaimOutsideCommand(requirement) {
191
154
  * The clause the exception keyword governs: from the keyword to the first
192
155
  * clause break (an em dash, a semicolon, or a sentence end). Everything else on
193
156
  * the line — notably the "— all engine modules (`document.ts`, …) must remain
194
- * untouched" tail of gofer-pixel's freeze — is NOT an exemption.
157
+ * untouched" tail of a freeze — is NOT an exemption.
195
158
  */
196
159
  function exemptClause(line) {
197
160
  const m = new RegExp(String.raw `\b${EXCEPT_KEYWORD}\b`, 'i').exec(line);
@@ -231,8 +194,8 @@ const basename = (p) => p.slice(p.lastIndexOf('/') + 1);
231
194
  * Is `p` inside the freeze — i.e. NOT one of the exempted paths, a file under
232
195
  * an exempted directory, or the same file spelled shorter?
233
196
  *
234
- * The last clause is load-bearing. gofer-pixel TASK_0011 exempts
235
- * `src/components/Canvas.tsx` while its owned requirement quotes the design's
197
+ * The last clause is load-bearing. A spec can exempt
198
+ * `src/components/Canvas.tsx` while its owned requirement quotes a design's
236
199
  * table cell, which says just `Canvas.tsx` — the same file, and the spec is
237
200
  * correctly formed. A bare basename is matched against the exempted paths'
238
201
  * basenames; a path WITH a directory must match exactly or by prefix, so
@@ -300,8 +263,8 @@ export function findOwnedFreezeConflicts(spec, opts = {}) {
300
263
  if (named.length === 0)
301
264
  continue;
302
265
  // One finding per requirement: the FIRST freeze that covers any of its
303
- // files. A spec that restates the same freeze under ACCEPTANCE (run 18
304
- // does) must not double the rewrite's work.
266
+ // files. A spec that restates the same freeze under ACCEPTANCE must not
267
+ // double the rewrite's work.
305
268
  for (const f of freezes) {
306
269
  const paths = named.filter(p => insideFreeze(p, [...f.exempt, ...granted]));
307
270
  if (paths.length === 0)
@@ -313,7 +276,7 @@ export function findOwnedFreezeConflicts(spec, opts = {}) {
313
276
  return out;
314
277
  }
315
278
  /**
316
- * The measured `isSource` oracle: a token counts only when git tracks it in
279
+ * The production `isSource` oracle: a token counts only when git tracks it in
317
280
  * `cwd`. Tracked ⇒ it exists, it is not a build output, and it is not ignored —
318
281
  * exactly the "source file" the category freezes talk about. `git` missing or
319
282
  * the tree not a repo ⇒ every token counts (the broad reading), so the detector
@@ -332,11 +295,15 @@ export function trackedSourceOracle(lsFiles) {
332
295
  };
333
296
  }
334
297
  /**
335
- * The forced critique-rewrite defect text, in the shape the existing four
336
- * families use: MANDATORY, self-contained, naming the exact resolutions. Prose
337
- * surrender and silently dropping the requirement are called out as
338
- * non-resolutions because narrowing the clause is precisely what run 16 did and
339
- * freezing its file is precisely what run 18 did.
298
+ * A forced-rewrite defect block in the shape the CRITIQUE_PROBES entries use:
299
+ * MANDATORY, self-contained, naming the exact resolutions. Prose surrender and
300
+ * silently dropping the requirement are called out as non-resolutions — narrowing
301
+ * the clause and freezing its file are both ways a rewrite makes the
302
+ * contradiction disappear without satisfying the requirement.
303
+ *
304
+ * UNWIRED. Nothing in src/ or test/ calls this. The shipped resolution is the
305
+ * DETACH in `owned-freeze-reassign.ts`, which needs no model rewrite; this text
306
+ * is what a rewrite-based resolution would say if one were ever added.
340
307
  */
341
308
  export function ownedFreezeConflictProbeText(conflicts) {
342
309
  const items = conflicts.map(c => `- the spec carries the AUTHORITATIVE owned requirement `
@@ -1,69 +1,49 @@
1
1
  /**
2
2
  * owned-freeze-reassign — the DETERMINISTIC resolution for the owned/freeze
3
- * unsatisfiable pair (nexttask 2): an AUTHORITATIVE owned requirement whose only
4
- * implementing file the same spec FREEZES. No model, no prose edit. The
5
- * requirement text is never altered — only which task's ledger entry carries it,
6
- * so "resolution by deletion" is structurally impossible.
7
- *
8
- * WHY NOT A REWRITE. Measured on mx5 run 18 (scripts/live-owned-freeze-conflict
9
- * -ab.ts, 20 trials/arm): forcing the pair through the critique seam drives
10
- * pair-present 8/20 → 0/20, but 11 of the 20 resolutions DELETE the
11
- * AUTHORITATIVE clause instead of moving it, and the delivered VERIFY still
12
- * greps `package.json` in both arms (6/20). Removal of the pair is not
13
- * satisfaction of the requirement.
3
+ * unsatisfiable pair: an AUTHORITATIVE owned requirement whose only implementing
4
+ * file the same spec FREEZES. No model, no prose edit. The requirement text is
5
+ * never altered — only which task's ledger entry carries it, so "resolution by
6
+ * deletion" is structurally impossible. That is the whole point: a model asked to
7
+ * remove a contradiction can satisfy the request by deleting the requirement, and
8
+ * removal of the pair is not satisfaction of the requirement.
14
9
  *
15
10
  * ── THE MECHANISM: DETACH, then CLAIM ───────────────────────────────────────
16
11
  *
17
12
  * Two steps, each run where the information it needs actually exists:
18
13
  *
19
- * DETACH at the conflicting task's own critique (right after the braces
20
- * stamp the bullet, which is the first moment the pair exists): the
21
- * entry is marked `pending: [frozen paths]` in the ledger and its
22
- * stamped bullet is dropped from this spec. It is now owned by
23
- * nobody; `ownedForTitle` skips it; the quote is still there, byte for
24
- * byte.
25
- * CLAIM at every LATER task's compose, before the belt block is built: if
26
- * that task's REFINED PROMPT shows a write intent on one of the
27
- * pending paths, the entry becomes that task's own — belt into its
28
- * compose, braces onto its spec.
29
- *
30
- * ── WHY NOT "PICK THE TARGET AT DETACH TIME", WHICH IS WHAT nexttask2.md ASKS ─
31
- *
32
- * nexttask2.md's branch 1 is "if exactly one OTHER task in the plan names path
33
- * `P` — its title or its spec's file list contains `P` — move the requirement
34
- * there". Measured over all 60 recorded composed specs on disk
35
- * (scripts/owned-freeze-reassign-baserate.ts), on the one conflict the corpus
36
- * contains (mx5 run 19 TASK_0015, path `src/server/index.ts`):
14
+ * DETACH at the conflicting task's own critique (`critiquePhase`, right after
15
+ * `appendOwnedConstraints` stamps the bullet, which is the first moment
16
+ * the pair exists): the entry is marked `pending: [frozen paths]` in the
17
+ * ledger and its stamped bullet is dropped from this spec. It is now
18
+ * owned by nobody; `ownedForTitle` skips it; the quote is still there,
19
+ * byte for byte.
20
+ * CLAIM at every LATER task's compose, before the belt block is built: if that
21
+ * task's REFINED PROMPT shows a write intent on one of the pending
22
+ * paths, the entry becomes that task's own — belt into its compose,
23
+ * braces onto its spec. First claimant wins.
37
24
  *
38
- * title-only 3 candidates TASK_0014 TASK_0016 TASK_0017
39
- * FILES-only 7 candidates TASK_0016 … TASK_0025
40
- * either 8 candidates → "exactly one" NEVER holds
25
+ * ── WHY NOT "PICK THE TARGET AT DETACH TIME" ─────────────────────────────────
41
26
  *
42
- * and, decisively, that measurement is against RECORDED SPECS, which production
43
- * does not have: at the conflicting task's compose the later tasks are still
44
- * bare plan titles. None of run 19's 26 plan titles contains the string
45
- * `src/server/index.ts` TASK_0017's reads "Client API layer typed
46
- * hono/client hc<AppType> in api.ts, small fetch/mutation hooks, SPA fallback
47
- * route on server". A path-lexical target rule at detach time is therefore
48
- * BLIND IN PRODUCTION (0 candidates), the same way the run-18 critique probe was.
27
+ * The obvious rule is "if exactly one OTHER task in the plan names path `P`, move
28
+ * the requirement there". It needs COMPOSED SPECS, and at the conflicting task's
29
+ * compose the later tasks are still bare plan titles. A plan title describes a
30
+ * slice of behaviour, not a file list, so a path-lexical target rule at detach
31
+ * time finds nothing to point at.
49
32
  *
50
- * The claimant knows what the planner did not. By its own compose, TASK_0017 has
51
- * a refined prompt that says "add an SPA fallback route to the existing server
52
- * `src/server/index.ts`". Over run 19's 26 refined prompts, `writeIntent` on that
53
- * path fires on exactly two: TASK_0014 (which created the file, already run) and
54
- * TASK_0017. Nothing else in the plan claims it — six other specs mention the
55
- * path, all of them to fence themselves off it.
33
+ * The claimant knows what the planner did not. By its own compose the later task
34
+ * has a REFINED prompt, which does say which files it will write and
35
+ * `writeIntent` reads exactly that, while its negation fence keeps every sibling
36
+ * that merely mentions the path in order to fence itself off it.
56
37
  *
57
- * ── WHY NOT nexttask2.md's BRANCH 2 (CARRY EVERYTHING CROSS-CUTTING) ────────
38
+ * ── WHY NOT CARRY IT AS CROSS-CUTTING ────────────────────────────────────────
58
39
  *
59
40
  * The cross-cutting channel is for prohibitions and product-wide rules
60
- * (`isCrossCuttingRequirement`; `accountCoverage` only routes those there). The
61
- * corpus conflict is a task-specific deliverable clause carrying it would push
62
- * "the server serves static `dist/`" into the 11 tasks that had not yet run,
63
- * none of which owns the server file. That is spec inflation dressed as a fix.
64
- * An entry nobody claims stays `pending` and is surfaced at the end of the run
65
- * (`unclaimedPendingRequirements`), which is a debt the run can see rather than
66
- * an obligation that quietly evaporated.
41
+ * (`isCrossCuttingRequirement`; `accountCoverage` only routes those there). A
42
+ * task-specific deliverable clause carried that way lands in every task that has
43
+ * not run yet, none of which owns the file spec inflation dressed as a fix. An
44
+ * entry nobody claims stays `pending` and `unclaimedPendingRequirements` surfaces
45
+ * it at the end of the run (run-final-gate.ts), so it becomes a debt the run can
46
+ * see rather than an obligation that quietly evaporated.
67
47
  */
68
48
  import { type OwnedFreezeOptions } from './owned-freeze-conflict.js';
69
49
  import { type OwnedRequirement } from './requirements.js';
@@ -96,11 +76,10 @@ export interface DetachResult {
96
76
  * Does this text CLAIM a write on `p` — a create/modify verb reaching a mention
97
77
  * of the path, not fenced by a negation?
98
78
  *
99
- * The negation half is not decoration. Every sibling task's refined prompt names
100
- * the files it must not touch ("Do not create or modify any other files outside
101
- * this slice (e.g., no changes to `src/server/index.ts`, …)" — mx5 run 19
102
- * TASK_0008). Without the fence check that spec claims the server file; with it,
103
- * run 19's 26 refined prompts yield exactly the two tasks that do write it.
79
+ * The negation half is not decoration. A refined prompt routinely names the files
80
+ * its task must NOT touch, in the same sentence as a write verb — "Do not create
81
+ * or modify any other files outside this slice (e.g. no changes to `X`)". Without
82
+ * the fence check, every such sibling claims `X`.
104
83
  */
105
84
  export declare function writeIntent(text: string, p: string): boolean;
106
85
  /**
@@ -124,8 +103,9 @@ export interface ClaimResult {
124
103
  * pending paths its refined prompt writes. Run at the START of compose, so the
125
104
  * claimed obligation rides the same belt block every owned requirement does.
126
105
  *
127
- * First claimant wins (`inv-single-owner`): the entry stops being pending the
128
- * moment it is claimed, so a later task cannot take it as well.
106
+ * First claimant wins: `delete entry.pending` runs before the entry is retitled,
107
+ * so a later task finds nothing pending to take. The test named
108
+ * `inv-single-owner` pins that.
129
109
  */
130
110
  export declare function claimPendingRequirements(args: {
131
111
  /** The claiming task's refined prompt — the text that says what it will write. */
@@ -1,69 +1,49 @@
1
1
  /**
2
2
  * owned-freeze-reassign — the DETERMINISTIC resolution for the owned/freeze
3
- * unsatisfiable pair (nexttask 2): an AUTHORITATIVE owned requirement whose only
4
- * implementing file the same spec FREEZES. No model, no prose edit. The
5
- * requirement text is never altered — only which task's ledger entry carries it,
6
- * so "resolution by deletion" is structurally impossible.
7
- *
8
- * WHY NOT A REWRITE. Measured on mx5 run 18 (scripts/live-owned-freeze-conflict
9
- * -ab.ts, 20 trials/arm): forcing the pair through the critique seam drives
10
- * pair-present 8/20 → 0/20, but 11 of the 20 resolutions DELETE the
11
- * AUTHORITATIVE clause instead of moving it, and the delivered VERIFY still
12
- * greps `package.json` in both arms (6/20). Removal of the pair is not
13
- * satisfaction of the requirement.
3
+ * unsatisfiable pair: an AUTHORITATIVE owned requirement whose only implementing
4
+ * file the same spec FREEZES. No model, no prose edit. The requirement text is
5
+ * never altered — only which task's ledger entry carries it, so "resolution by
6
+ * deletion" is structurally impossible. That is the whole point: a model asked to
7
+ * remove a contradiction can satisfy the request by deleting the requirement, and
8
+ * removal of the pair is not satisfaction of the requirement.
14
9
  *
15
10
  * ── THE MECHANISM: DETACH, then CLAIM ───────────────────────────────────────
16
11
  *
17
12
  * Two steps, each run where the information it needs actually exists:
18
13
  *
19
- * DETACH at the conflicting task's own critique (right after the braces
20
- * stamp the bullet, which is the first moment the pair exists): the
21
- * entry is marked `pending: [frozen paths]` in the ledger and its
22
- * stamped bullet is dropped from this spec. It is now owned by
23
- * nobody; `ownedForTitle` skips it; the quote is still there, byte for
24
- * byte.
25
- * CLAIM at every LATER task's compose, before the belt block is built: if
26
- * that task's REFINED PROMPT shows a write intent on one of the
27
- * pending paths, the entry becomes that task's own — belt into its
28
- * compose, braces onto its spec.
29
- *
30
- * ── WHY NOT "PICK THE TARGET AT DETACH TIME", WHICH IS WHAT nexttask2.md ASKS ─
31
- *
32
- * nexttask2.md's branch 1 is "if exactly one OTHER task in the plan names path
33
- * `P` — its title or its spec's file list contains `P` — move the requirement
34
- * there". Measured over all 60 recorded composed specs on disk
35
- * (scripts/owned-freeze-reassign-baserate.ts), on the one conflict the corpus
36
- * contains (mx5 run 19 TASK_0015, path `src/server/index.ts`):
14
+ * DETACH at the conflicting task's own critique (`critiquePhase`, right after
15
+ * `appendOwnedConstraints` stamps the bullet, which is the first moment
16
+ * the pair exists): the entry is marked `pending: [frozen paths]` in the
17
+ * ledger and its stamped bullet is dropped from this spec. It is now
18
+ * owned by nobody; `ownedForTitle` skips it; the quote is still there,
19
+ * byte for byte.
20
+ * CLAIM at every LATER task's compose, before the belt block is built: if that
21
+ * task's REFINED PROMPT shows a write intent on one of the pending
22
+ * paths, the entry becomes that task's own — belt into its compose,
23
+ * braces onto its spec. First claimant wins.
37
24
  *
38
- * title-only 3 candidates TASK_0014 TASK_0016 TASK_0017
39
- * FILES-only 7 candidates TASK_0016 … TASK_0025
40
- * either 8 candidates → "exactly one" NEVER holds
25
+ * ── WHY NOT "PICK THE TARGET AT DETACH TIME" ─────────────────────────────────
41
26
  *
42
- * and, decisively, that measurement is against RECORDED SPECS, which production
43
- * does not have: at the conflicting task's compose the later tasks are still
44
- * bare plan titles. None of run 19's 26 plan titles contains the string
45
- * `src/server/index.ts` TASK_0017's reads "Client API layer typed
46
- * hono/client hc<AppType> in api.ts, small fetch/mutation hooks, SPA fallback
47
- * route on server". A path-lexical target rule at detach time is therefore
48
- * BLIND IN PRODUCTION (0 candidates), the same way the run-18 critique probe was.
27
+ * The obvious rule is "if exactly one OTHER task in the plan names path `P`, move
28
+ * the requirement there". It needs COMPOSED SPECS, and at the conflicting task's
29
+ * compose the later tasks are still bare plan titles. A plan title describes a
30
+ * slice of behaviour, not a file list, so a path-lexical target rule at detach
31
+ * time finds nothing to point at.
49
32
  *
50
- * The claimant knows what the planner did not. By its own compose, TASK_0017 has
51
- * a refined prompt that says "add an SPA fallback route to the existing server
52
- * `src/server/index.ts`". Over run 19's 26 refined prompts, `writeIntent` on that
53
- * path fires on exactly two: TASK_0014 (which created the file, already run) and
54
- * TASK_0017. Nothing else in the plan claims it — six other specs mention the
55
- * path, all of them to fence themselves off it.
33
+ * The claimant knows what the planner did not. By its own compose the later task
34
+ * has a REFINED prompt, which does say which files it will write and
35
+ * `writeIntent` reads exactly that, while its negation fence keeps every sibling
36
+ * that merely mentions the path in order to fence itself off it.
56
37
  *
57
- * ── WHY NOT nexttask2.md's BRANCH 2 (CARRY EVERYTHING CROSS-CUTTING) ────────
38
+ * ── WHY NOT CARRY IT AS CROSS-CUTTING ────────────────────────────────────────
58
39
  *
59
40
  * The cross-cutting channel is for prohibitions and product-wide rules
60
- * (`isCrossCuttingRequirement`; `accountCoverage` only routes those there). The
61
- * corpus conflict is a task-specific deliverable clause carrying it would push
62
- * "the server serves static `dist/`" into the 11 tasks that had not yet run,
63
- * none of which owns the server file. That is spec inflation dressed as a fix.
64
- * An entry nobody claims stays `pending` and is surfaced at the end of the run
65
- * (`unclaimedPendingRequirements`), which is a debt the run can see rather than
66
- * an obligation that quietly evaporated.
41
+ * (`isCrossCuttingRequirement`; `accountCoverage` only routes those there). A
42
+ * task-specific deliverable clause carried that way lands in every task that has
43
+ * not run yet, none of which owns the file spec inflation dressed as a fix. An
44
+ * entry nobody claims stays `pending` and `unclaimedPendingRequirements` surfaces
45
+ * it at the end of the run (run-final-gate.ts), so it becomes a debt the run can
46
+ * see rather than an obligation that quietly evaporated.
67
47
  */
68
48
  import { findOwnedFreezeConflicts } from './owned-freeze-conflict.js';
69
49
  import { ownedForTitle } from './requirements.js';
@@ -72,11 +52,10 @@ import { PROHIBITION_RE } from './prohibition-probe.js';
72
52
  * Does this text CLAIM a write on `p` — a create/modify verb reaching a mention
73
53
  * of the path, not fenced by a negation?
74
54
  *
75
- * The negation half is not decoration. Every sibling task's refined prompt names
76
- * the files it must not touch ("Do not create or modify any other files outside
77
- * this slice (e.g., no changes to `src/server/index.ts`, …)" — mx5 run 19
78
- * TASK_0008). Without the fence check that spec claims the server file; with it,
79
- * run 19's 26 refined prompts yield exactly the two tasks that do write it.
55
+ * The negation half is not decoration. A refined prompt routinely names the files
56
+ * its task must NOT touch, in the same sentence as a write verb — "Do not create
57
+ * or modify any other files outside this slice (e.g. no changes to `X`)". Without
58
+ * the fence check, every such sibling claims `X`.
80
59
  */
81
60
  export function writeIntent(text, p) {
82
61
  const re = new RegExp(String.raw `\b(?:creat|add|implement|modif|updat|extend|wir|writ|mount|chang)\w*\b`
@@ -84,7 +63,7 @@ export function writeIntent(text, p) {
84
63
  + p.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi');
85
64
  for (const m of text.matchAll(re)) {
86
65
  // The negation usually sits BEFORE the verb, so the window reaches back
87
- // past it — matching only the verb→path span misses TASK_0008 entirely.
66
+ // past it — matching only the verb→path span misses a fenced spec entirely.
88
67
  const from = Math.max(0, (m.index ?? 0) - 90);
89
68
  const window = text.slice(from, (m.index ?? 0) + m[0].length);
90
69
  if (NEGATED_RE.test(window) || PROHIBITION_RE.test(window))
@@ -171,8 +150,9 @@ export function detachUnsatisfiableRequirements(args) {
171
150
  * pending paths its refined prompt writes. Run at the START of compose, so the
172
151
  * claimed obligation rides the same belt block every owned requirement does.
173
152
  *
174
- * First claimant wins (`inv-single-owner`): the entry stops being pending the
175
- * moment it is claimed, so a later task cannot take it as well.
153
+ * First claimant wins: `delete entry.pending` runs before the entry is retitled,
154
+ * so a later task finds nothing pending to take. The test named
155
+ * `inv-single-owner` pins that.
176
156
  */
177
157
  export function claimPendingRequirements(args) {
178
158
  const out = { ledger: args.ledger.map(o => ({ ...o })), actions: [] };
@@ -12,8 +12,10 @@
12
12
  * bare recommendation): a genuine open fork carrying a best-effort suggestion.
13
13
  * - 'api-synthesis' — the answer was ANSWERED, then DEMOTED because it names an
14
14
  * API identifier absent from the research and the question, in a namespace the
15
- * research covers (mx5 run 13: an invented `Bun.mkdirSync` reached requirements
16
- * AND the VERIFY block). The suggestion rides along for a HUMAN to judge.
15
+ * research covers. `Bun.mkdirSync` is the shape: bun-types declares no such
16
+ * member, but an answer naming it reads as authoritative and can reach both
17
+ * requirements and the VERIFY block. The suggestion rides along for a HUMAN
18
+ * to judge.
17
19
  * - 'integration' — an integration/build-wiring unknown no fetched doc grounded;
18
20
  * a wrong guess is a structural landmine, so the model's answer is offered as
19
21
  * a recommendation instead of being taken silently.
@@ -224,10 +224,10 @@ export function deriveTitle(refined) {
224
224
  }
225
225
  // ─── Display label ───────────────────────────────────────────────────────────
226
226
  //
227
- // `title` is stored in full (a refine GOAL paragraph can be 1000+ chars — see
228
- // the "no truncation at storage" contract in deriveTitle). These helpers shrink
229
- // it for status surfaces (widget head, /task list) WITHOUT touching what's
230
- // stored: the pipeline always reads the full title. A model-compressed `label`
227
+ // `title` is stored in full: `deriveTitle` returns the GOAL line whole, however
228
+ // long it is, and nothing clamps it on the way to disk. These helpers shrink it
229
+ // for status surfaces (widget head, /task list) WITHOUT touching what is stored —
230
+ // the pipeline always reads the full title. A model-compressed `label`
231
231
  // is preferred when present (see title-label.ts); otherwise we fall back to a
232
232
  // deterministic, word-boundary truncation so a label-less task still reads
233
233
  // cleanly.