@mjasnikovs/pi-task 0.38.29 → 0.38.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (373) hide show
  1. package/dist/config/config.d.ts +70 -70
  2. package/dist/config/config.js +26 -35
  3. package/dist/config/extension-list.d.ts +6 -5
  4. package/dist/config/extension-list.js +3 -2
  5. package/dist/config/reasoning-args.d.ts +9 -7
  6. package/dist/config/reasoning-args.js +12 -10
  7. package/dist/config/reasoning.d.ts +44 -105
  8. package/dist/config/reasoning.js +27 -704
  9. package/dist/config/register.d.ts +34 -48
  10. package/dist/config/register.js +41 -51
  11. package/dist/config/tool-list.d.ts +16 -16
  12. package/dist/config/tool-list.js +1 -1
  13. package/dist/index.js +2 -0
  14. package/dist/remote/bridge.d.ts +19 -10
  15. package/dist/remote/bridge.js +3 -2
  16. package/dist/remote/broadcast.js +3 -1
  17. package/dist/remote/events.js +12 -11
  18. package/dist/remote/history.d.ts +1 -1
  19. package/dist/remote/protocol.d.ts +6 -3
  20. package/dist/remote/protocol.js +2 -1
  21. package/dist/remote/push.d.ts +16 -16
  22. package/dist/remote/push.js +27 -27
  23. package/dist/remote/register.d.ts +3 -3
  24. package/dist/remote/register.js +17 -19
  25. package/dist/remote/server.d.ts +9 -8
  26. package/dist/remote/server.js +15 -14
  27. package/dist/remote/session-state.d.ts +5 -4
  28. package/dist/remote/session-state.js +8 -5
  29. package/dist/remote/sw.d.ts +7 -6
  30. package/dist/remote/sw.js +7 -6
  31. package/dist/remote/tailscale.d.ts +4 -2
  32. package/dist/remote/tailscale.js +4 -2
  33. package/dist/remote/ui-highlight.js +6 -5
  34. package/dist/remote/ui-render.js +4 -4
  35. package/dist/remote/ui-script.js +24 -24
  36. package/dist/remote/ui-styles.d.ts +1 -1
  37. package/dist/remote/ui-styles.js +10 -13
  38. package/dist/remote/ui-tools.js +9 -6
  39. package/dist/shared/child-extensions.d.ts +29 -17
  40. package/dist/shared/child-extensions.js +29 -17
  41. package/dist/shared/child-output.d.ts +30 -24
  42. package/dist/shared/child-output.js +25 -17
  43. package/dist/shared/child-process.d.ts +47 -40
  44. package/dist/shared/child-process.js +50 -59
  45. package/dist/shared/command-watchdog.d.ts +85 -16
  46. package/dist/shared/command-watchdog.js +115 -21
  47. package/dist/shared/fs-text.d.ts +16 -10
  48. package/dist/shared/fs-text.js +16 -10
  49. package/dist/shared/git-runner.d.ts +25 -25
  50. package/dist/shared/git-runner.js +25 -25
  51. package/dist/shared/leaked-tool-call.d.ts +17 -11
  52. package/dist/shared/leaked-tool-call.js +23 -15
  53. package/dist/shared/model-endpoint.d.ts +29 -16
  54. package/dist/shared/model-endpoint.js +33 -21
  55. package/dist/shared/pi-invocation.d.ts +7 -4
  56. package/dist/shared/pi-invocation.js +12 -7
  57. package/dist/shared/pkg-version.d.ts +13 -5
  58. package/dist/shared/pkg-version.js +13 -5
  59. package/dist/shared/reasoning-capability.d.ts +35 -24
  60. package/dist/shared/reasoning-capability.js +35 -24
  61. package/dist/shared/stream-watchdog.d.ts +60 -44
  62. package/dist/shared/stream-watchdog.js +62 -45
  63. package/dist/task/accept-debt.d.ts +41 -43
  64. package/dist/task/accept-debt.js +73 -65
  65. package/dist/task/api-synthesis.d.ts +24 -21
  66. package/dist/task/api-synthesis.js +32 -26
  67. package/dist/task/apis-contract.d.ts +32 -64
  68. package/dist/task/apis-contract.js +32 -64
  69. package/dist/task/artifact-closure.d.ts +27 -13
  70. package/dist/task/artifact-closure.js +95 -67
  71. package/dist/task/auto-commit.d.ts +46 -35
  72. package/dist/task/auto-commit.js +51 -38
  73. package/dist/task/auto-io.d.ts +45 -25
  74. package/dist/task/auto-io.js +57 -29
  75. package/dist/task/auto-orchestrator.d.ts +26 -24
  76. package/dist/task/auto-orchestrator.js +192 -165
  77. package/dist/task/auto-prompts.d.ts +36 -24
  78. package/dist/task/auto-prompts.js +40 -26
  79. package/dist/task/autofix-ledger.d.ts +27 -25
  80. package/dist/task/autofix-ledger.js +29 -26
  81. package/dist/task/batch-test-task.d.ts +20 -12
  82. package/dist/task/batch-test-task.js +67 -60
  83. package/dist/task/boot-probe.d.ts +60 -44
  84. package/dist/task/boot-probe.js +91 -72
  85. package/dist/task/cancel-input.d.ts +30 -16
  86. package/dist/task/cancel-input.js +20 -11
  87. package/dist/task/cancel-points.d.ts +27 -20
  88. package/dist/task/cancel-points.js +30 -22
  89. package/dist/task/child-runner.d.ts +124 -55
  90. package/dist/task/child-runner.js +298 -90
  91. package/dist/task/child-status.d.ts +23 -16
  92. package/dist/task/child-status.js +23 -16
  93. package/dist/task/clamp-output.js +12 -5
  94. package/dist/task/command-run.d.ts +31 -28
  95. package/dist/task/command-run.js +44 -35
  96. package/dist/task/command-shrink.d.ts +25 -18
  97. package/dist/task/command-shrink.js +37 -31
  98. package/dist/task/command-watchdog.d.ts +9 -6
  99. package/dist/task/command-watchdog.js +21 -15
  100. package/dist/task/context-attribution.d.ts +34 -26
  101. package/dist/task/context-attribution.js +34 -26
  102. package/dist/task/context-silence.d.ts +39 -29
  103. package/dist/task/context-silence.js +35 -25
  104. package/dist/task/context-usage.d.ts +16 -9
  105. package/dist/task/context-usage.js +16 -9
  106. package/dist/task/contracts.d.ts +8 -4
  107. package/dist/task/contracts.js +25 -17
  108. package/dist/task/coverage-loop.d.ts +22 -18
  109. package/dist/task/coverage-loop.js +35 -30
  110. package/dist/task/critique-probes.d.ts +13 -14
  111. package/dist/task/critique-probes.js +50 -39
  112. package/dist/task/debug-log.d.ts +13 -5
  113. package/dist/task/debug-log.js +32 -20
  114. package/dist/task/decompose-fidelity.d.ts +11 -9
  115. package/dist/task/decompose-fidelity.js +38 -33
  116. package/dist/task/decompose-granularity.d.ts +41 -38
  117. package/dist/task/decompose-granularity.js +41 -38
  118. package/dist/task/deep-render-check.d.ts +22 -14
  119. package/dist/task/deep-render-check.js +40 -31
  120. package/dist/task/dropped-input.d.ts +12 -7
  121. package/dist/task/dropped-input.js +5 -2
  122. package/dist/task/enforce-attribution.d.ts +38 -47
  123. package/dist/task/enforce-attribution.js +46 -52
  124. package/dist/task/enforce-guidelines.d.ts +31 -20
  125. package/dist/task/enforce-guidelines.js +32 -21
  126. package/dist/task/enrichment.d.ts +7 -2
  127. package/dist/task/enrichment.js +26 -14
  128. package/dist/task/env-notes.d.ts +16 -7
  129. package/dist/task/env-notes.js +48 -31
  130. package/dist/task/env-template-closure.d.ts +4 -4
  131. package/dist/task/env-template-closure.js +42 -34
  132. package/dist/task/external-context.d.ts +28 -21
  133. package/dist/task/external-context.js +17 -12
  134. package/dist/task/failure-classifier.d.ts +4 -5
  135. package/dist/task/failure-classifier.js +30 -8
  136. package/dist/task/file-inventory.d.ts +15 -11
  137. package/dist/task/file-inventory.js +25 -22
  138. package/dist/task/final-gate-fix.d.ts +74 -86
  139. package/dist/task/final-gate-fix.js +97 -116
  140. package/dist/task/final-gate-progress.d.ts +29 -46
  141. package/dist/task/final-gate-progress.js +40 -51
  142. package/dist/task/final-gate.d.ts +64 -97
  143. package/dist/task/final-gate.js +192 -199
  144. package/dist/task/fix-child.d.ts +21 -27
  145. package/dist/task/fix-child.js +21 -27
  146. package/dist/task/foreign-path.d.ts +6 -5
  147. package/dist/task/foreign-path.js +0 -0
  148. package/dist/task/frozen-conflict.d.ts +9 -10
  149. package/dist/task/frozen-conflict.js +61 -64
  150. package/dist/task/frozen-path-guard.d.ts +35 -14
  151. package/dist/task/frozen-path-guard.js +56 -39
  152. package/dist/task/gate-child.d.ts +27 -28
  153. package/dist/task/gate-child.js +36 -35
  154. package/dist/task/gate-deps.d.ts +34 -27
  155. package/dist/task/gate-deps.js +169 -159
  156. package/dist/task/gate-tally.d.ts +77 -80
  157. package/dist/task/gate-tally.js +65 -68
  158. package/dist/task/git-state-guard.d.ts +15 -11
  159. package/dist/task/git-state-guard.js +76 -66
  160. package/dist/task/impl-widget.d.ts +25 -16
  161. package/dist/task/impl-widget.js +27 -17
  162. package/dist/task/implementation-guards.d.ts +26 -0
  163. package/dist/task/implementation-guards.js +177 -0
  164. package/dist/task/implementation-thinking.d.ts +33 -31
  165. package/dist/task/implementation-thinking.js +5 -6
  166. package/dist/task/implementation-turn.d.ts +39 -31
  167. package/dist/task/implementation-turn.js +41 -28
  168. package/dist/task/inline-markdown.d.ts +20 -7
  169. package/dist/task/inline-markdown.js +15 -6
  170. package/dist/task/launch-config-gap.js +25 -39
  171. package/dist/task/launch-contract.d.ts +18 -21
  172. package/dist/task/launch-contract.js +28 -30
  173. package/dist/task/launch-manifest.d.ts +6 -2
  174. package/dist/task/launch-manifest.js +35 -34
  175. package/dist/task/ledger.js +16 -14
  176. package/dist/task/lint-fix.d.ts +6 -8
  177. package/dist/task/lint-fix.js +67 -69
  178. package/dist/task/loop-detector.d.ts +27 -8
  179. package/dist/task/loop-detector.js +38 -14
  180. package/dist/task/mid-run-input.d.ts +17 -15
  181. package/dist/task/mid-run-input.js +17 -15
  182. package/dist/task/orchestrator.d.ts +24 -28
  183. package/dist/task/orchestrator.js +89 -66
  184. package/dist/task/orientation.d.ts +18 -23
  185. package/dist/task/orientation.js +24 -31
  186. package/dist/task/owned-freeze-conflict.d.ts +21 -20
  187. package/dist/task/owned-freeze-conflict.js +52 -85
  188. package/dist/task/owned-freeze-reassign.d.ts +40 -60
  189. package/dist/task/owned-freeze-reassign.js +41 -61
  190. package/dist/task/parsers.d.ts +4 -2
  191. package/dist/task/parsers.js +4 -4
  192. package/dist/task/phases.d.ts +41 -48
  193. package/dist/task/phases.js +196 -252
  194. package/dist/task/plan-io.d.ts +6 -7
  195. package/dist/task/plan-io.js +6 -7
  196. package/dist/task/plan-orchestrator.d.ts +10 -8
  197. package/dist/task/plan-orchestrator.js +14 -10
  198. package/dist/task/plan-prompts.d.ts +6 -5
  199. package/dist/task/plan-prompts.js +6 -5
  200. package/dist/task/plan-readonly.d.ts +4 -5
  201. package/dist/task/plan-readonly.js +4 -5
  202. package/dist/task/plan-rounds.d.ts +17 -29
  203. package/dist/task/plan-rounds.js +21 -34
  204. package/dist/task/plan-session.d.ts +58 -72
  205. package/dist/task/plan-session.js +61 -83
  206. package/dist/task/probe-gaming.d.ts +28 -27
  207. package/dist/task/probe-gaming.js +0 -0
  208. package/dist/task/prohibition-probe.d.ts +14 -16
  209. package/dist/task/prompts.d.ts +3 -4
  210. package/dist/task/prompts.js +17 -26
  211. package/dist/task/qa-transcript.d.ts +15 -22
  212. package/dist/task/qa-transcript.js +15 -21
  213. package/dist/task/question-box.d.ts +17 -13
  214. package/dist/task/question-box.js +19 -15
  215. package/dist/task/question-dedup.d.ts +6 -7
  216. package/dist/task/question-dedup.js +13 -14
  217. package/dist/task/question-dialog.d.ts +22 -32
  218. package/dist/task/question-dialog.js +22 -32
  219. package/dist/task/question-source.d.ts +18 -44
  220. package/dist/task/question-source.js +22 -51
  221. package/dist/task/refuted-constraint.d.ts +11 -31
  222. package/dist/task/refuted-constraint.js +27 -51
  223. package/dist/task/regenerable-artifacts.d.ts +12 -31
  224. package/dist/task/regenerable-artifacts.js +12 -31
  225. package/dist/task/render-check.d.ts +11 -22
  226. package/dist/task/render-check.js +33 -46
  227. package/dist/task/repo-health-check.d.ts +10 -14
  228. package/dist/task/repo-health-check.js +17 -23
  229. package/dist/task/requirements.d.ts +38 -71
  230. package/dist/task/requirements.js +78 -126
  231. package/dist/task/research-fanout-budget.d.ts +51 -88
  232. package/dist/task/research-fanout-budget.js +51 -88
  233. package/dist/task/research-worker.d.ts +29 -39
  234. package/dist/task/research-worker.js +37 -61
  235. package/dist/task/resume-gap.d.ts +14 -15
  236. package/dist/task/root-cause-repair.d.ts +9 -9
  237. package/dist/task/root-cause-repair.js +28 -40
  238. package/dist/task/run-bracket.d.ts +10 -13
  239. package/dist/task/run-end.d.ts +12 -22
  240. package/dist/task/run-end.js +8 -16
  241. package/dist/task/run-final-gate.d.ts +19 -21
  242. package/dist/task/run-final-gate.js +62 -80
  243. package/dist/task/runner-globs.d.ts +12 -13
  244. package/dist/task/runner-globs.js +12 -13
  245. package/dist/task/runner-resolve.d.ts +9 -9
  246. package/dist/task/runner-resolve.js +22 -23
  247. package/dist/task/script-escape.d.ts +10 -12
  248. package/dist/task/script-escape.js +13 -14
  249. package/dist/task/serve-entry.d.ts +1 -1
  250. package/dist/task/serve-entry.js +22 -25
  251. package/dist/task/service-blocks.js +4 -2
  252. package/dist/task/shipped-source.d.ts +11 -29
  253. package/dist/task/shipped-source.js +11 -29
  254. package/dist/task/skip-escape.js +10 -14
  255. package/dist/task/spec-urls.d.ts +26 -65
  256. package/dist/task/spec-urls.js +26 -65
  257. package/dist/task/spec-validation.d.ts +17 -20
  258. package/dist/task/spec-validation.js +17 -20
  259. package/dist/task/stall-detector.d.ts +23 -30
  260. package/dist/task/stall-detector.js +23 -30
  261. package/dist/task/stream-watchdog.d.ts +14 -12
  262. package/dist/task/stream-watchdog.js +14 -12
  263. package/dist/task/substitution-probe.d.ts +17 -20
  264. package/dist/task/substitution-probe.js +17 -20
  265. package/dist/task/task-gates.d.ts +36 -41
  266. package/dist/task/task-gates.js +95 -106
  267. package/dist/task/task-io.d.ts +4 -4
  268. package/dist/task/task-io.js +4 -4
  269. package/dist/task/task-parsers.js +4 -3
  270. package/dist/task/task-provenance.d.ts +2 -2
  271. package/dist/task/task-provenance.js +11 -13
  272. package/dist/task/task-types.d.ts +4 -3
  273. package/dist/task/terminal-outcome.d.ts +14 -16
  274. package/dist/task/terminal-outcome.js +12 -14
  275. package/dist/task/test-assembly.d.ts +13 -20
  276. package/dist/task/test-assembly.js +13 -20
  277. package/dist/task/timings.d.ts +5 -3
  278. package/dist/task/timings.js +5 -3
  279. package/dist/task/title-label.d.ts +9 -4
  280. package/dist/task/title-label.js +9 -4
  281. package/dist/task/type-only-answer.d.ts +44 -52
  282. package/dist/task/type-only-answer.js +44 -52
  283. package/dist/task/unfailable-command.d.ts +18 -24
  284. package/dist/task/unfailable-command.js +21 -27
  285. package/dist/task/unknown-routing.d.ts +10 -4
  286. package/dist/task/unknown-routing.js +10 -4
  287. package/dist/task/user-directives.d.ts +5 -8
  288. package/dist/task/user-directives.js +5 -8
  289. package/dist/task/verify-quality.d.ts +18 -22
  290. package/dist/task/verify-quality.js +45 -46
  291. package/dist/task/verify-reconcile.d.ts +15 -10
  292. package/dist/task/verify-reconcile.js +45 -43
  293. package/dist/task/verify-resolution.d.ts +24 -20
  294. package/dist/task/verify-resolution.js +51 -50
  295. package/dist/task/verify-work.d.ts +59 -66
  296. package/dist/task/verify-work.js +101 -138
  297. package/dist/task/widget.d.ts +15 -14
  298. package/dist/task/widget.js +22 -17
  299. package/dist/task/wiring-claims.d.ts +25 -32
  300. package/dist/task/wiring-claims.js +30 -35
  301. package/dist/task/write-guard.d.ts +39 -39
  302. package/dist/task/write-guard.js +48 -51
  303. package/dist/task/yolo.d.ts +34 -30
  304. package/dist/task/yolo.js +42 -37
  305. package/dist/workers/abstention.d.ts +21 -41
  306. package/dist/workers/abstention.js +27 -48
  307. package/dist/workers/brave-search.d.ts +4 -3
  308. package/dist/workers/brave-search.js +5 -2
  309. package/dist/workers/brave-warning.d.ts +7 -4
  310. package/dist/workers/brave-warning.js +19 -7
  311. package/dist/workers/ddg-search.d.ts +6 -6
  312. package/dist/workers/ddg-search.js +18 -12
  313. package/dist/workers/docs-cache.js +5 -2
  314. package/dist/workers/docs-chunk.d.ts +30 -37
  315. package/dist/workers/docs-chunk.js +37 -41
  316. package/dist/workers/docs-core.d.ts +28 -44
  317. package/dist/workers/docs-core.js +25 -44
  318. package/dist/workers/docs-index.js +4 -3
  319. package/dist/workers/docs-lookup.d.ts +15 -22
  320. package/dist/workers/docs-lookup.js +12 -21
  321. package/dist/workers/docs-project.d.ts +15 -9
  322. package/dist/workers/docs-project.js +17 -10
  323. package/dist/workers/docs-resolve.d.ts +19 -20
  324. package/dist/workers/docs-resolve.js +35 -32
  325. package/dist/workers/docs-retrieve.d.ts +5 -6
  326. package/dist/workers/docs-retrieve.js +18 -15
  327. package/dist/workers/exa-search.d.ts +9 -6
  328. package/dist/workers/exa-search.js +23 -12
  329. package/dist/workers/fetch-core.d.ts +13 -16
  330. package/dist/workers/fetch-core.js +23 -23
  331. package/dist/workers/focused-extractor.d.ts +13 -12
  332. package/dist/workers/focused-extractor.js +27 -19
  333. package/dist/workers/html-clean.js +24 -14
  334. package/dist/workers/http-request.d.ts +28 -20
  335. package/dist/workers/http-request.js +22 -17
  336. package/dist/workers/npm-version.d.ts +28 -11
  337. package/dist/workers/npm-version.js +24 -15
  338. package/dist/workers/phantom-imports.d.ts +15 -12
  339. package/dist/workers/phantom-imports.js +30 -24
  340. package/dist/workers/pi-worker-core.d.ts +65 -96
  341. package/dist/workers/pi-worker-core.js +93 -181
  342. package/dist/workers/pi-worker-docs.d.ts +24 -19
  343. package/dist/workers/pi-worker-docs.js +67 -76
  344. package/dist/workers/pi-worker-fetch.d.ts +7 -3
  345. package/dist/workers/pi-worker-fetch.js +27 -19
  346. package/dist/workers/pi-worker-search.js +12 -8
  347. package/dist/workers/pi-worker.d.ts +9 -4
  348. package/dist/workers/pi-worker.js +21 -14
  349. package/dist/workers/reasoning-warning.d.ts +18 -17
  350. package/dist/workers/reasoning-warning.js +22 -20
  351. package/dist/workers/research-cache.js +50 -78
  352. package/dist/workers/search-core.js +7 -5
  353. package/dist/workers/search-types.d.ts +10 -9
  354. package/dist/workers/search-types.js +9 -8
  355. package/dist/workers/session-hint.d.ts +13 -14
  356. package/dist/workers/session-hint.js +8 -9
  357. package/dist/workers/shared.d.ts +21 -25
  358. package/dist/workers/shared.js +0 -0
  359. package/dist/workers/single-read-extension.d.ts +14 -7
  360. package/dist/workers/single-read-extension.js +14 -7
  361. package/dist/workers/single-read-guard.d.ts +27 -30
  362. package/dist/workers/single-read-guard.js +36 -36
  363. package/dist/workers/typeonly-log.d.ts +12 -9
  364. package/dist/workers/typeonly-log.js +29 -33
  365. package/dist/workers/worker-channels.d.ts +15 -23
  366. package/dist/workers/worker-channels.js +15 -23
  367. package/dist/workers/worker-failure.d.ts +38 -46
  368. package/dist/workers/worker-failure.js +31 -39
  369. package/dist/workers/worker-kill.d.ts +25 -26
  370. package/dist/workers/worker-kill.js +16 -19
  371. package/dist/workers/worker-profiles.d.ts +54 -56
  372. package/dist/workers/worker-profiles.js +63 -39
  373. package/package.json +10 -8
@@ -1,13 +1,13 @@
1
1
  /**
2
- * decompose-fidelity — verbatim fidelity of plan derivations (mx5 run 11, goal B).
2
+ * decompose-fidelity — verbatim fidelity of plan derivations.
3
3
  *
4
- * The failure this closes: the design's §12 milestone lines 2 and 4 end in
5
- * "guards + tests" / "contact + tests"; the decomposed titles carried everything
4
+ * The failure this closes: a design's milestone line ends in an additive
5
+ * constraint — "guards + tests" and the decomposed title carries everything
6
6
  * BUT the "+ tests" suffix. A title is ALL a per-task pipeline ever sees, so a
7
- * silently dropped constraint fragment vanishes from the whole run the dropped
8
- * tests were exactly the instrument that would have caught the shipped 404 bug.
9
- * Decompose paraphrases freely and NOTHING compared a title to the spec line it
10
- * derives from.
7
+ * silently dropped fragment vanishes from the whole run, and the dropped thing is
8
+ * disproportionately the instrument that would have caught the bug. Decompose
9
+ * paraphrases freely, and without this nothing compares a title to the spec line
10
+ * it derives from.
11
11
  *
12
12
  * Mechanism (contracts.ts pattern, applied to decompose itself): the decompose
13
13
  * prompt asks each task line to cite its origin as a trailing
@@ -20,9 +20,11 @@
20
20
  * 3. RE-ATTACHES the missing fragments to the title verbatim.
21
21
  *
22
22
  * Scope is deliberately the additive-suffix class (`+`-joined fragments): those
23
- * are constraints by construction, so re-attachment can never inject noise that
24
- * the cited line doesn't demand — worst case is redundancy with what the title
25
- * already says, never fabrication. Whole-line paraphrase drift is NOT judged here
23
+ * are constraints by construction, so re-attachment can never inject noise the
24
+ * cited line does not demand — worst case is redundancy with what the title
25
+ * already says, never fabrication. In practice not even that: a title that
26
+ * already carries the fragment restores nothing, and the singular/plural
27
+ * allowance means "a test" counts as covering "tests". Whole-line paraphrase drift is NOT judged here
26
28
  * (a title is a paraphrase by design); requirement-level coverage owns that.
27
29
  * No similarity thresholds anywhere: grounding is exact normalised substring,
28
30
  * presence is exact word membership (with a singular/plural `s` allowance).
@@ -45,17 +47,15 @@ const SOURCE_RE = /^\[source:\s*"([\s\S]*)"\s*\]$/i;
45
47
  *
46
48
  * BACKTICKS ARE THE SAME CLASS and were the larger half. A code span renders as
47
49
  * bare text, so `3. **Invites** — create/validate/redeem, \`/join/:token\` page.`
48
- * comes back as `Invites — create/validate/redeem, /join/:token page.` Measured
49
- * on the mx5 fixture, screening every spec line in its RENDERED form:
50
- * 107/216 grounded with backticks kept, 216/216 with them dropped.
50
+ * comes back as `Invites — create/validate/redeem, /join/:token page.` Screening
51
+ * every spec line in its RENDERED form is what makes those quotes match at all.
51
52
  *
52
- * MEASURED 2026-08-27 over the 20 recorded decompose runs in
53
- * ab-grouplab/ledger-planning.jsonl, and screened both ways first:
54
- * FLOOR real spec lines with ONE content word altered: 0/216 pass.
55
- * CEILING real spec lines quoted without their markup: 209/257 = 81.3% passed
56
- * before, 257/257 after. 48 genuine lines were being rejected.
57
- * Re-screened by scripts/decompose-fidelity-screen.ts, which is the standing
58
- * check: CEILING raw 216/216, CEILING rendered 216/216, FLOOR 0/216.
53
+ * The two directions this has to hold in, both run:
54
+ * FLOOR a real spec line with ONE content word altered must NOT be grounded —
55
+ * changing `sessions` to `tokens`, or `redeem` to `revoke`, drops it.
56
+ * CEILING a real spec line quoted without its markup MUST be grounded — both the
57
+ * `2. **Auth** —` numbering-and-bold case and the backticked
58
+ * `` `/join/:token` `` case still match.
59
59
  */
60
60
  function demark(s) {
61
61
  return s
@@ -69,10 +69,13 @@ function demark(s) {
69
69
  * Undo the backslash-escaping a model applies to a quote it is putting INSIDE a
70
70
  * double-quoted clause. `[source: "… \`import { sql } from \\"bun\\"\` gotcha …"]`
71
71
  * is a faithful copy of a line the document stores with plain quotes; the
72
- * backslashes are an artefact of the delimiter, not content. Measured live: 4 of
73
- * the 19 ungrounded clauses in the n=30/arm planning run were this and nothing
74
- * else. Only `\"` is undone — no other escape sequence is interpreted, so this
75
- * cannot rewrite a quote into something the document happens to contain.
72
+ * backslashes are an artefact of the delimiter, not content, so without this an
73
+ * otherwise-faithful quote fails to match for that reason alone.
74
+ *
75
+ * Only `\"` is undone no other escape sequence is interpreted, so this cannot
76
+ * rewrite a quote into something the document happens to contain. Confirmed both
77
+ * ways: the escaped-quote citation grounds, and a citation carrying a literal
78
+ * `\n` does not.
76
79
  */
77
80
  function unescapeQuotes(s) {
78
81
  return s.replace(/\\"/g, '"');
@@ -80,15 +83,17 @@ function unescapeQuotes(s) {
80
83
  /**
81
84
  * Split a decompose title into its base and its GROUNDED source citations.
82
85
  *
83
- * PLURAL, because the model emits plural. The prompt asks for one trailing
84
- * citation and a quarter of real titles carry more 62 of 244 across the 20
85
- * recorded runs. The old pattern was `\[source:\s*"(.+)"\]$`: greedy `.+`
86
- * against an end anchor, so on `[source: "A"] [source: "B"]` it matched from the
87
- * FIRST clause to the LAST quote and produced the superstring `A"] [source: "B`,
88
- * which of course is not in the document. Two real citations became one
89
- * fabricated one, and both were discarded. Peeling from the end with
90
- * lastIndexOf is the fix; a lazy quantifier is NOT, because leftmost-first
91
- * matching plus the `$` anchor expands it across the later clauses just the same.
86
+ * PLURAL, because the model emits plural: the prompt asks for one trailing
87
+ * citation and a real share of titles carry more than one.
88
+ *
89
+ * A single anchored pattern cannot read them. Run on `[source: "A"] [source: "B"]`,
90
+ * `\[source:\s*"(.+)"\]$` captures the superstring `A"] [source: "B` — from the
91
+ * FIRST clause to the LAST quote — which is of course not in the document, so two
92
+ * real citations become one fabricated one and both are discarded. Making the
93
+ * quantifier LAZY changes nothing: `(.+?)` against the same input captures the
94
+ * identical superstring, because leftmost-first matching plus the `$` anchor
95
+ * expands it across the later clauses just the same. Peeling from the end with
96
+ * lastIndexOf is what actually works — confirmed, both citations come back.
92
97
  *
93
98
  * An absent clause yields no sources; a fabricated (ungrounded) one is dropped
94
99
  * — exactly like keepGroundedContracts rejects a paraphrased quote.
@@ -2,18 +2,15 @@
2
2
  * decompose-granularity — the deterministic FLOOR on how finely /task-auto cuts
3
3
  * a feature into tasks.
4
4
  *
5
- * The failure this closes (mx5, Jul 25 vs Jul 27): the SAME design doc, from the
6
- * SAME base commit, with a byte-identical planning path, planned once into 41
7
- * tasks and once into 11. The whole 4x difference is one line of clarify text.
8
- * /task-auto's clarify head asks a plan-shape question first ("one task per
9
- * milestone, or split smaller?" 8/8 live reps), the answer-side triage
10
- * auto-resolves it 8/8 and stamps it "already settled by the spec", so the user
11
- * never sees the fork; and the answer decides the whole plan. Live A/B, run 18's
12
- * transcript with ONLY that line swapped (n=8/arm): coarse mean 11.4 titles vs
13
- * fine mean 28.6, 63.5/64 pairwise wins, p<0.001.
5
+ * The failure this closes: the SAME design doc, from the SAME base commit, with a
6
+ * byte-identical planning path, plans several times coarser or finer depending on
7
+ * ONE line of clarify text. /task-auto's clarify head asks a plan-shape question
8
+ * first ("one task per milestone, or split smaller?"), the answer-side triage
9
+ * auto-resolves it and stamps it "already settled by the spec", so the user never
10
+ * sees the fork and that answer decides the whole plan.
14
11
  *
15
- * The spec does NOT settle it. mx5's §12 is titled "Build order (milestones)"
16
- * an ORDER, 9 items, not a task breakdown. So the plan's granularity, the single
12
+ * The spec does NOT settle it. A section titled "Build order (milestones)" is an
13
+ * ORDER, not a task breakdown. So the plan's granularity, the single
17
14
  * highest-leverage decision in a run (each title is handed to its own pipeline
18
15
  * that researches and specs it alone), was being decided by a coin flip nobody
19
16
  * could see, review, or reproduce.
@@ -25,10 +22,10 @@
25
22
  *
26
23
  * floor = ceil(ownable requirements / MAX_REQUIREMENTS_PER_TASK)
27
24
  *
28
- * MAX_REQUIREMENTS_PER_TASK = 2 is anchored on the two real mx5 plans, not on
29
- * taste: the 41-task plan carried 0.8 ownable requirements per task, the collapsed
30
- * 11-task plan carried 2.8. A ceiling of 2 sits between them — it rejects the
31
- * collapse without demanding the finest plan ever observed.
25
+ * MAX_REQUIREMENTS_PER_TASK = 2 sits deliberately between the two shapes: a plan
26
+ * cut fine enough to work carries roughly one ownable requirement per task, and a
27
+ * collapsed one bundles several. A ceiling of 2 rejects the collapse without
28
+ * demanding the finest possible plan.
32
29
  *
33
30
  * Spec-shape-agnostic: the only inputs are two integers. A CLI, a library, a
34
31
  * refactor, a docs job all flow through the same arithmetic, and a feature with
@@ -37,7 +34,7 @@
37
34
  */
38
35
  /**
39
36
  * The most distinct grounded requirements one task may carry before the plan is
40
- * judged too coarse. See the module docstring for the mx5 anchoring.
37
+ * judged too coarse. See the module docstring for where the number comes from.
41
38
  */
42
39
  export declare const MAX_REQUIREMENTS_PER_TASK = 2;
43
40
  /**
@@ -47,14 +44,14 @@ export declare const MAX_REQUIREMENTS_PER_TASK = 2;
47
44
  * Also zero below MIN_REQUIREMENTS_FOR_PLAN_SHAPE, for the reason that constant
48
45
  * already documents: under a handful of requirements the plan is one or two tasks
49
46
  * either way, and the requirement COUNT at that scale is an artifact of extraction
50
- * granularity rather than real breadth. Measured (2026-07-28 size smoke): the
51
- * 78-char feature "Add a `--version` flag to the CLI that prints the package
52
- * version and exits 0" extracted THREE ownable requirements the flag, the
53
- * print, the exit code yielding a floor of 2 for what is unambiguously one
54
- * task. Both arms correctly shipped 1 title, so the floor bought nothing and cost
55
- * a split-retry child; had anything ever made it binding it would have forced a
56
- * bad split. The same cut governs both because it is the same judgement: the
57
- * requirement channel is not load-bearing for shape until a feature has real breadth.
47
+ * granularity rather than real breadth. A one-line feature request — "add a
48
+ * --version flag that prints the version and exits 0" extracts three ownable
49
+ * requirements (the flag, the print, the exit code) for what is unambiguously one
50
+ * task, and an ungated floor would demand two. The same cut governs both checks
51
+ * because it is the same judgement.
52
+ *
53
+ * Run: the floor is 0 for 0-4 ownable requirements, then ceil(n/2) 5 gives 3,
54
+ * 10 gives 5, 21 gives 11.
58
55
  */
59
56
  export declare function granularityFloor(ownable: number): number;
60
57
  /** Is this plan too coarse for the requirements it has to carry? */
@@ -76,25 +73,31 @@ export declare function planShapeIsHostsToAnswer(ownable: number): boolean;
76
73
  /**
77
74
  * Does this clarify question decide how finely the feature is CUT into tasks?
78
75
  *
79
- * Deterministic and narrow on purpose. It must fire on the fork the triage keeps
80
- * answering for itself ("follow the milestones as-is, or split more granularly?")
81
- * and stay off ordinary scope questions an over-eager classifier would replace
82
- * a real user decision with the host's. Matched against the plain-text question.
76
+ * Deterministic and narrow on purpose: it must fire on the fork the triage keeps
77
+ * answering for itself and stay off ordinary scope questions, because an
78
+ * over-eager classifier would replace a real user decision with the host's.
79
+ * Matched against the plain-text question.
80
+ *
81
+ * BOTH halves must hold — a breakdown phrase AND a plan-unit noun — and the unit
82
+ * list is SINGULAR except for tasks. Measured across the units it names:
83
+ * milestone / section / step / phase / task / tasks fire
84
+ * milestones / sections / steps / phases do NOT
85
+ * So "one task per milestone, or split smaller?" fires, while the same fork
86
+ * phrased "follow the milestones as-is, or split more granularly?" does not —
87
+ * the breakdown half matches, the plural unit does not.
83
88
  */
84
89
  export declare function isPlanShapeQuestion(question: string): boolean;
85
90
  /**
86
91
  * BELT — the host's own answer to that fork, recorded in the clarify transcript in
87
92
  * place of the triage's.
88
93
  *
89
- * WHY A CLARIFICATION AND NOT A DECOMPOSE RULE. Both were measured live. As a
90
- * RULES line replacing "prefer a handful of substantial tasks", the same directive
91
- * removed the collapse but destroyed plan-size control: 66, then 81 and 85 titles
92
- * for a spec whose healthy plan is ~30, plus one decompose child that blew the
93
- * model's 120k context window and killed the planning phase (the baseline produced
94
- * no such failure in 27 reps). Naming a target count made it worse, not better.
95
- * In the CLARIFICATIONS block, with the "prefer a handful" counterweight left
96
- * intact, the identical directive held 20–39 titles across 16 reps. The channel is
97
- * part of the lever, not a detail.
94
+ * WHY A CLARIFICATION AND NOT A DECOMPOSE RULE. The identical directive behaves
95
+ * very differently depending on where it lands. As a RULES line REPLACING "prefer
96
+ * a handful of substantial tasks", it removes the collapse but takes the
97
+ * counterweight with it, and plan size runs away far enough that a decompose
98
+ * child can exhaust its context window and kill the planning phase outright. In
99
+ * the CLARIFICATIONS block, with that counterweight left intact, the same words
100
+ * land as one input among several. The channel is part of the lever, not a detail.
98
101
  *
99
102
  * Deliberately count-free: the spec-derived floor stays host-side, where it is
100
103
  * enforced silently and cannot be chased.
@@ -105,6 +108,6 @@ export declare const PLAN_SHAPE_ANSWER: string;
105
108
  * BRACES — the reprompt when the returned plan lands under the floor. Also
106
109
  * countless, for the reason above: it asks for a SPLIT of the plan in hand rather
107
110
  * than a fresh roll (a regeneration is a new stochastic draw over the whole plan
108
- * and can drop an area the current one covers — mx5 run 12).
111
+ * and can drop an area the current one covers).
109
112
  */
110
113
  export declare function granularitySplitHint(titles: number, ownable: number): string;
@@ -2,18 +2,15 @@
2
2
  * decompose-granularity — the deterministic FLOOR on how finely /task-auto cuts
3
3
  * a feature into tasks.
4
4
  *
5
- * The failure this closes (mx5, Jul 25 vs Jul 27): the SAME design doc, from the
6
- * SAME base commit, with a byte-identical planning path, planned once into 41
7
- * tasks and once into 11. The whole 4x difference is one line of clarify text.
8
- * /task-auto's clarify head asks a plan-shape question first ("one task per
9
- * milestone, or split smaller?" 8/8 live reps), the answer-side triage
10
- * auto-resolves it 8/8 and stamps it "already settled by the spec", so the user
11
- * never sees the fork; and the answer decides the whole plan. Live A/B, run 18's
12
- * transcript with ONLY that line swapped (n=8/arm): coarse mean 11.4 titles vs
13
- * fine mean 28.6, 63.5/64 pairwise wins, p<0.001.
5
+ * The failure this closes: the SAME design doc, from the SAME base commit, with a
6
+ * byte-identical planning path, plans several times coarser or finer depending on
7
+ * ONE line of clarify text. /task-auto's clarify head asks a plan-shape question
8
+ * first ("one task per milestone, or split smaller?"), the answer-side triage
9
+ * auto-resolves it and stamps it "already settled by the spec", so the user never
10
+ * sees the fork and that answer decides the whole plan.
14
11
  *
15
- * The spec does NOT settle it. mx5's §12 is titled "Build order (milestones)"
16
- * an ORDER, 9 items, not a task breakdown. So the plan's granularity, the single
12
+ * The spec does NOT settle it. A section titled "Build order (milestones)" is an
13
+ * ORDER, not a task breakdown. So the plan's granularity, the single
17
14
  * highest-leverage decision in a run (each title is handed to its own pipeline
18
15
  * that researches and specs it alone), was being decided by a coin flip nobody
19
16
  * could see, review, or reproduce.
@@ -25,10 +22,10 @@
25
22
  *
26
23
  * floor = ceil(ownable requirements / MAX_REQUIREMENTS_PER_TASK)
27
24
  *
28
- * MAX_REQUIREMENTS_PER_TASK = 2 is anchored on the two real mx5 plans, not on
29
- * taste: the 41-task plan carried 0.8 ownable requirements per task, the collapsed
30
- * 11-task plan carried 2.8. A ceiling of 2 sits between them — it rejects the
31
- * collapse without demanding the finest plan ever observed.
25
+ * MAX_REQUIREMENTS_PER_TASK = 2 sits deliberately between the two shapes: a plan
26
+ * cut fine enough to work carries roughly one ownable requirement per task, and a
27
+ * collapsed one bundles several. A ceiling of 2 rejects the collapse without
28
+ * demanding the finest possible plan.
32
29
  *
33
30
  * Spec-shape-agnostic: the only inputs are two integers. A CLI, a library, a
34
31
  * refactor, a docs job all flow through the same arithmetic, and a feature with
@@ -37,7 +34,7 @@
37
34
  */
38
35
  /**
39
36
  * The most distinct grounded requirements one task may carry before the plan is
40
- * judged too coarse. See the module docstring for the mx5 anchoring.
37
+ * judged too coarse. See the module docstring for where the number comes from.
41
38
  */
42
39
  export const MAX_REQUIREMENTS_PER_TASK = 2;
43
40
  /**
@@ -47,14 +44,14 @@ export const MAX_REQUIREMENTS_PER_TASK = 2;
47
44
  * Also zero below MIN_REQUIREMENTS_FOR_PLAN_SHAPE, for the reason that constant
48
45
  * already documents: under a handful of requirements the plan is one or two tasks
49
46
  * either way, and the requirement COUNT at that scale is an artifact of extraction
50
- * granularity rather than real breadth. Measured (2026-07-28 size smoke): the
51
- * 78-char feature "Add a `--version` flag to the CLI that prints the package
52
- * version and exits 0" extracted THREE ownable requirements the flag, the
53
- * print, the exit code yielding a floor of 2 for what is unambiguously one
54
- * task. Both arms correctly shipped 1 title, so the floor bought nothing and cost
55
- * a split-retry child; had anything ever made it binding it would have forced a
56
- * bad split. The same cut governs both because it is the same judgement: the
57
- * requirement channel is not load-bearing for shape until a feature has real breadth.
47
+ * granularity rather than real breadth. A one-line feature request — "add a
48
+ * --version flag that prints the version and exits 0" extracts three ownable
49
+ * requirements (the flag, the print, the exit code) for what is unambiguously one
50
+ * task, and an ungated floor would demand two. The same cut governs both checks
51
+ * because it is the same judgement.
52
+ *
53
+ * Run: the floor is 0 for 0-4 ownable requirements, then ceil(n/2) 5 gives 3,
54
+ * 10 gives 5, 21 gives 11.
58
55
  */
59
56
  export function granularityFloor(ownable) {
60
57
  if (ownable < MIN_REQUIREMENTS_FOR_PLAN_SHAPE)
@@ -84,10 +81,18 @@ export function planShapeIsHostsToAnswer(ownable) {
84
81
  /**
85
82
  * Does this clarify question decide how finely the feature is CUT into tasks?
86
83
  *
87
- * Deterministic and narrow on purpose. It must fire on the fork the triage keeps
88
- * answering for itself ("follow the milestones as-is, or split more granularly?")
89
- * and stay off ordinary scope questions an over-eager classifier would replace
90
- * a real user decision with the host's. Matched against the plain-text question.
84
+ * Deterministic and narrow on purpose: it must fire on the fork the triage keeps
85
+ * answering for itself and stay off ordinary scope questions, because an
86
+ * over-eager classifier would replace a real user decision with the host's.
87
+ * Matched against the plain-text question.
88
+ *
89
+ * BOTH halves must hold — a breakdown phrase AND a plan-unit noun — and the unit
90
+ * list is SINGULAR except for tasks. Measured across the units it names:
91
+ * milestone / section / step / phase / task / tasks fire
92
+ * milestones / sections / steps / phases do NOT
93
+ * So "one task per milestone, or split smaller?" fires, while the same fork
94
+ * phrased "follow the milestones as-is, or split more granularly?" does not —
95
+ * the breakdown half matches, the plural unit does not.
91
96
  */
92
97
  export function isPlanShapeQuestion(question) {
93
98
  const q = question.toLowerCase();
@@ -102,15 +107,13 @@ export function isPlanShapeQuestion(question) {
102
107
  * BELT — the host's own answer to that fork, recorded in the clarify transcript in
103
108
  * place of the triage's.
104
109
  *
105
- * WHY A CLARIFICATION AND NOT A DECOMPOSE RULE. Both were measured live. As a
106
- * RULES line replacing "prefer a handful of substantial tasks", the same directive
107
- * removed the collapse but destroyed plan-size control: 66, then 81 and 85 titles
108
- * for a spec whose healthy plan is ~30, plus one decompose child that blew the
109
- * model's 120k context window and killed the planning phase (the baseline produced
110
- * no such failure in 27 reps). Naming a target count made it worse, not better.
111
- * In the CLARIFICATIONS block, with the "prefer a handful" counterweight left
112
- * intact, the identical directive held 20–39 titles across 16 reps. The channel is
113
- * part of the lever, not a detail.
110
+ * WHY A CLARIFICATION AND NOT A DECOMPOSE RULE. The identical directive behaves
111
+ * very differently depending on where it lands. As a RULES line REPLACING "prefer
112
+ * a handful of substantial tasks", it removes the collapse but takes the
113
+ * counterweight with it, and plan size runs away far enough that a decompose
114
+ * child can exhaust its context window and kill the planning phase outright. In
115
+ * the CLARIFICATIONS block, with that counterweight left intact, the same words
116
+ * land as one input among several. The channel is part of the lever, not a detail.
114
117
  *
115
118
  * Deliberately count-free: the spec-derived floor stays host-side, where it is
116
119
  * enforced silently and cannot be chased.
@@ -125,7 +128,7 @@ export const PLAN_SHAPE_ANSWER = 'subdivide into smaller per-deliverable tasks
125
128
  * BRACES — the reprompt when the returned plan lands under the floor. Also
126
129
  * countless, for the reason above: it asks for a SPLIT of the plan in hand rather
127
130
  * than a fresh roll (a regeneration is a new stochastic draw over the whole plan
128
- * and can drop an area the current one covers — mx5 run 12).
131
+ * and can drop an area the current one covers).
129
132
  */
130
133
  export function granularitySplitHint(titles, ownable) {
131
134
  return (`[SYSTEM NOTE: your plan of ${titles} task(s) is too coarse for the`
@@ -12,15 +12,18 @@ export type DeepRenderOutcome = {
12
12
  export interface LoginCredentials {
13
13
  identifier: string;
14
14
  password: string;
15
- /** Key names only the value is never logged or surfaced anywhere. */
15
+ /** Key NAMES only. The values are read from the project's own dotenv and typed
16
+ * into the page; neither ever reaches a log line, a skip note or a failure
17
+ * detail — those quote the key names and the request paths only. */
16
18
  identifierKey: string;
17
19
  passwordKey: string;
18
20
  }
19
21
  /**
20
- * Parse a dotenv-style file into a plain record. Deliberately minimal (KEY=VALUE,
21
- * `export ` prefix, # comments, optional matching quotes) this reads the same
22
- * file the app's own runtime reads, and anything it cannot parse simply yields no
23
- * credentials, which is a SKIP.
22
+ * Parse a dotenv-style file into a plain record. Deliberately minimal KEY=VALUE,
23
+ * an optional `export ` prefix, `#` comments, and matching quotes that preserve
24
+ * inner spaces while an unquoted value drops a trailing ` #` comment. This reads
25
+ * the same file the app's own runtime reads, and anything it cannot parse simply
26
+ * yields no credentials, which is a SKIP rather than a failure.
24
27
  */
25
28
  export declare function parseEnvFile(text: string): Record<string, string>;
26
29
  /** The variables the booted app itself sees: its dotenv files, overlaid by the real
@@ -37,7 +40,7 @@ export declare function findLoginCredentials(vars: Record<string, string>): Logi
37
40
  * The LOCAL port the project's own client was built to call, when its dotenv pins
38
41
  * one (`APP_URL=http://localhost:3000`, `VITE_API_URL=…`), else null.
39
42
  *
40
- * Why the boot check wants it (measured on mx5@373e88d, both directions): a bundler
43
+ * Why the boot check wants it: a bundler
41
44
  * bakes that base URL into the client at BUILD time, so a client served on the
42
45
  * gate's freshly-reserved private port calls an origin nothing is listening on. The
43
46
  * app is then unusable for reasons that have nothing to do with the code, and the
@@ -45,7 +48,7 @@ export declare function findLoginCredentials(vars: Record<string, string>): Logi
45
48
  * origin and never reaches the server we booted. Serving on the app's own declared
46
49
  * port makes the session same-origin and the evidence real.
47
50
  *
48
- * This deliberately narrows the private-port ownership evidence of run 14, so it
51
+ * This deliberately narrows the private-port ownership evidence, so it
49
52
  * only applies when the port is LOCAL, DECLARED by the project itself, and CURRENTLY
50
53
  * FREE — the caller checks freeness and falls back to a reserved port otherwise.
51
54
  */
@@ -117,18 +120,23 @@ export declare function deriveLegacyFacts(log: SessionRequest[]): Pick<DeepSessi
117
120
  * Judge a recorded session. The ONE thing that may FAIL is a session the SERVER
118
121
  * authenticated (2xx on the sign-in request) whose client then could not use it:
119
122
  *
120
- * - never left the wall → the run-17 signature exactly;
123
+ * - never left the wall → the signature exactly;
121
124
  * - data calls attempted, none 2xx → the same class one page deeper;
122
- * - post-sign-in page renders blank → the run-16 class behind the wall.
125
+ * - post-sign-in page renders blank → the class behind the wall.
123
126
  *
124
127
  * Everything else is an environment or shape gap and SKIPs. Note what is NOT a
125
128
  * failure: zero data calls attempted after sign-in. A server-rendered app that
126
129
  * redirects to a fresh document legitimately issues no XHR at all, so the missing
127
- * half is reported UNOBSERVED in the detail instead. (The task text asked for
128
- * "≥1 same-origin /api/* 2xx during the session" as a hard assertion; STEP 0
129
- * refuted that wording the BROKEN mx5 build satisfies it with the probe's own
130
- * login POST so the assertion is registered post-auth and excludes the sign-in
131
- * request. See the scratch REGISTERED-METRIC record quoted in the commit.)
130
+ * half is reported UNOBSERVED in the detail instead.
131
+ *
132
+ * The data assertion is deliberately POST-AUTH and EXCLUDES the sign-in request.
133
+ * A plain "at least one same-origin 2xx during the session" would be satisfied by
134
+ * the probe's own login POST and nothing else a broken build passes it.
135
+ *
136
+ * Run across every branch: only those three FAIL. No wall PASSes; no credentials,
137
+ * an undriveable form, no sign-in request, a server that REJECTED the credentials,
138
+ * and a client pinned to a foreign origin all SKIP; and zero post-auth data calls
139
+ * PASSes with the gap noted.
132
140
  */
133
141
  export declare function judgeDeepSession(f: DeepSessionFacts): DeepRenderOutcome;
134
142
  /** Whole-session wall-clock cap, including browser launch (I4). */
@@ -1,19 +1,20 @@
1
1
  /**
2
2
  * deep-render-check — sign in on the booted app and prove the AUTHENTICATED half
3
- * of it is alive (mx5 run 17).
3
+ * of it is alive.
4
4
  *
5
5
  * The failure class this closes: the shallow render check (render-check.ts) loads
6
- * ONE url and judges the rendered DOM. mx5 run 17 satisfies it completely while
6
+ * ONE url and judges the rendered DOM. An app can satisfy it completely while
7
7
  * being unusable — GET / redirects to /login, the login page renders fully, and
8
- * that is the whole check. Behind it, src/client/hooks/useAuth.ts called
9
- * `typedClient.api.auth.me.get()`; hono RPC methods are `$get`/`$post`, so a bare
10
- * `.get` is just another path segment in hono's createProxy and the call returns a
11
- * request BUILDER that never issues a request. Login POSTs 200 and sets the
12
- * session cookie, zero /api/auth/me requests are ever made, and the app bounces to
13
- * /login forever. Seven call sites were dead the same way, mixed in the same files
14
- * with correct `$get` ones the signature of code no runtime ever executed. The
15
- * server was healthy throughout: 134/134 tests, tsc clean, login 200, me-with-
16
- * cookie 200. Nothing static could see it.
8
+ * that is the whole check.
9
+ *
10
+ * Behind that wall lives the DEAD CLIENT CALL. A typed RPC client whose method
11
+ * names are proxied (hono's `$get`/`$post`, say) turns a wrong-but-plausible
12
+ * spelling into just another path segment: the call returns a request BUILDER and
13
+ * never issues a request. Login POSTs 200 and sets the session cookie, the
14
+ * follow-up data call is never made at all, and the app bounces back to the wall
15
+ * forever. The dead spellings sit in the same files as correct ones, which is the
16
+ * signature of code no runtime ever executed — and everything static stays green:
17
+ * the suite passes, tsc is clean, and both endpoints answer 200 to curl.
17
18
  *
18
19
  * The generic instrument is a NETWORK FACT: after a real sign-in, did the client
19
20
  * actually leave the wall, and did its data calls actually reach the server. No
@@ -24,8 +25,8 @@
24
25
  *
25
26
  * SCOPE HONESTY: this is WEB-ONLY. It runs only behind detectsServedApp() and does
26
27
  * nothing for C++, Godot, CLI or library projects, which are most of the fleet. It
27
- * is here because the class is the most expensive one observed it ended run 16
28
- * (blank page) and run 17 (dead login) outright.
28
+ * is here because the class is the most expensive one observed: a blank page, or
29
+ * a login that does not work, ends a run outright.
29
30
  *
30
31
  * Mechanism, dependency-free: the same discovered Chrome-family binary the shallow
31
32
  * check uses, driven over the DevTools protocol through the `ws` dependency the
@@ -47,7 +48,9 @@ import { findHeadlessBrowser, judgeRenderedDom } from './render-check.js';
47
48
  const IDENTIFIER_SUFFIXES = ['PHONE', 'EMAIL', 'USERNAME', 'USER', 'LOGIN', 'IDENTIFIER'];
48
49
  const PASSWORD_SUFFIXES = ['PASSWORD', 'PASSWD', 'PASS'];
49
50
  /** Prefixes whose `_PASSWORD` belongs to infrastructure, not to an app account.
50
- * `DB_USER`/`DB_PASSWORD` pair perfectly and would otherwise be tried as a login. */
51
+ * `DB_USER`/`DB_PASSWORD` pair perfectly and would otherwise be tried as a login.
52
+ * Confirmed: that pair alone yields no credentials, and so does POSTGRES_*, while
53
+ * an ADMIN pair in the same file is chosen over both. */
51
54
  const INFRA_PREFIX_RE = /^(DATABASE|DB|POSTGRES|POSTGRESQL|PG|MYSQL|MARIADB|MONGO|MONGODB|REDIS|RABBIT|RABBITMQ|AMQP|KAFKA|SMTP|IMAP|MAIL|MAILER|S3|MINIO|AWS|GCP|AZURE|DOCKER|REGISTRY|NPM|GITHUB|GITLAB|PROXY|LDAP|VAULT|GRAFANA|SENTRY)$/i;
52
55
  /** Prefixes that name a seeded APP account, tried before any other pair. */
53
56
  const ACCOUNT_PREFIX_ORDER = ['ADMIN', 'TEST', 'E2E', 'SEED', 'DEV', 'DEFAULT', 'USER', 'LOGIN'];
@@ -65,10 +68,11 @@ function splitKey(key, suffixes) {
65
68
  return null;
66
69
  }
67
70
  /**
68
- * Parse a dotenv-style file into a plain record. Deliberately minimal (KEY=VALUE,
69
- * `export ` prefix, # comments, optional matching quotes) this reads the same
70
- * file the app's own runtime reads, and anything it cannot parse simply yields no
71
- * credentials, which is a SKIP.
71
+ * Parse a dotenv-style file into a plain record. Deliberately minimal KEY=VALUE,
72
+ * an optional `export ` prefix, `#` comments, and matching quotes that preserve
73
+ * inner spaces while an unquoted value drops a trailing ` #` comment. This reads
74
+ * the same file the app's own runtime reads, and anything it cannot parse simply
75
+ * yields no credentials, which is a SKIP rather than a failure.
72
76
  */
73
77
  export function parseEnvFile(text) {
74
78
  const out = {};
@@ -166,7 +170,7 @@ export function findLoginCredentials(vars) {
166
170
  * The LOCAL port the project's own client was built to call, when its dotenv pins
167
171
  * one (`APP_URL=http://localhost:3000`, `VITE_API_URL=…`), else null.
168
172
  *
169
- * Why the boot check wants it (measured on mx5@373e88d, both directions): a bundler
173
+ * Why the boot check wants it: a bundler
170
174
  * bakes that base URL into the client at BUILD time, so a client served on the
171
175
  * gate's freshly-reserved private port calls an origin nothing is listening on. The
172
176
  * app is then unusable for reasons that have nothing to do with the code, and the
@@ -174,7 +178,7 @@ export function findLoginCredentials(vars) {
174
178
  * origin and never reaches the server we booted. Serving on the app's own declared
175
179
  * port makes the session same-origin and the evidence real.
176
180
  *
177
- * This deliberately narrows the private-port ownership evidence of run 14, so it
181
+ * This deliberately narrows the private-port ownership evidence, so it
178
182
  * only applies when the port is LOCAL, DECLARED by the project itself, and CURRENTLY
179
183
  * FREE — the caller checks freeness and falls back to a reserved port otherwise.
180
184
  */
@@ -219,18 +223,23 @@ const MISSING_ROUTE_STATUS = new Set([404, 405, 501]);
219
223
  * Judge a recorded session. The ONE thing that may FAIL is a session the SERVER
220
224
  * authenticated (2xx on the sign-in request) whose client then could not use it:
221
225
  *
222
- * - never left the wall → the run-17 signature exactly;
226
+ * - never left the wall → the signature exactly;
223
227
  * - data calls attempted, none 2xx → the same class one page deeper;
224
- * - post-sign-in page renders blank → the run-16 class behind the wall.
228
+ * - post-sign-in page renders blank → the class behind the wall.
225
229
  *
226
230
  * Everything else is an environment or shape gap and SKIPs. Note what is NOT a
227
231
  * failure: zero data calls attempted after sign-in. A server-rendered app that
228
232
  * redirects to a fresh document legitimately issues no XHR at all, so the missing
229
- * half is reported UNOBSERVED in the detail instead. (The task text asked for
230
- * "≥1 same-origin /api/* 2xx during the session" as a hard assertion; STEP 0
231
- * refuted that wording the BROKEN mx5 build satisfies it with the probe's own
232
- * login POST so the assertion is registered post-auth and excludes the sign-in
233
- * request. See the scratch REGISTERED-METRIC record quoted in the commit.)
233
+ * half is reported UNOBSERVED in the detail instead.
234
+ *
235
+ * The data assertion is deliberately POST-AUTH and EXCLUDES the sign-in request.
236
+ * A plain "at least one same-origin 2xx during the session" would be satisfied by
237
+ * the probe's own login POST and nothing else a broken build passes it.
238
+ *
239
+ * Run across every branch: only those three FAIL. No wall PASSes; no credentials,
240
+ * an undriveable form, no sign-in request, a server that REJECTED the credentials,
241
+ * and a client pinned to a foreign origin all SKIP; and zero post-auth data calls
242
+ * PASSes with the gap noted.
234
243
  */
235
244
  export function judgeDeepSession(f) {
236
245
  if (!f.landingHadAuthWall) {
@@ -753,9 +762,9 @@ export async function driveSession(cdp, { url, credentials, judge, quietMs }) {
753
762
  lastActivity = Date.now();
754
763
  await settle(() => lastActivity, POST_SUBMIT_CAP_MS, quietMs);
755
764
  // The sign-in request: the first same-origin non-GET issued by the submit. Its
756
- // own 2xx is the precondition for judging anything, and it is excluded from the
757
- // data evidence (STEP 0: the broken build satisfies "≥1 same-origin 2xx" with
758
- // exactly this request and nothing else).
765
+ // own 2xx is the precondition for judging anything, and it is EXCLUDED from the
766
+ // data evidence a broken build satisfies "at least one same-origin 2xx" with
767
+ // exactly this request and nothing else.
759
768
  const after = new Map([...requests].filter(([, r]) => r.at >= submitMark));
760
769
  let authId = null;
761
770
  for (const [id, r] of after) {
@@ -770,7 +779,7 @@ export async function driveSession(cdp, { url, credentials, judge, quietMs }) {
770
779
  const domJudgment = judgeRenderedDom(now?.html ?? '');
771
780
  const leftAuthWall = !(now?.hasPassword ?? false) || (now?.pathname ?? '') !== before.pathname;
772
781
  // Exercise the authenticated app once. A sign-in page that ends on a success
773
- // card mx5's does — issues NOTHING after the login POST, so the authenticated
782
+ // card can issue NOTHING after the login POST, so the authenticated
774
783
  // data path is never observed at all and every request-shaped fact below is a
775
784
  // fact about the login form. Re-entering the landing URL with the session cookie
776
785
  // is the cheapest way to make the app fetch its own data. Deliberately gated on