@nathapp/nax 0.27.1 → 0.29.0

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 (383) hide show
  1. package/CHANGELOG.md +13 -2
  2. package/dist/nax.js +72691 -0
  3. package/package.json +12 -4
  4. package/src/cli/config.ts +42 -1
  5. package/src/cli/prompts.ts +18 -6
  6. package/src/config/defaults.ts +2 -0
  7. package/src/config/schemas.ts +11 -0
  8. package/src/config/types.ts +8 -0
  9. package/src/context/builder.ts +10 -1
  10. package/src/pipeline/stages/execution.ts +5 -0
  11. package/src/pipeline/stages/prompt.ts +13 -4
  12. package/src/precheck/checks-warnings.ts +37 -0
  13. package/src/precheck/checks.ts +1 -0
  14. package/src/precheck/index.ts +14 -7
  15. package/src/prompts/builder.ts +178 -0
  16. package/src/prompts/index.ts +2 -0
  17. package/src/prompts/loader.ts +43 -0
  18. package/src/prompts/sections/conventions.ts +15 -0
  19. package/src/prompts/sections/index.ts +11 -0
  20. package/src/prompts/sections/isolation.ts +24 -0
  21. package/src/prompts/sections/role-task.ts +34 -0
  22. package/src/prompts/sections/story.ts +13 -0
  23. package/src/prompts/sections/verdict.ts +70 -0
  24. package/src/prompts/templates/implementer.ts +6 -0
  25. package/src/prompts/templates/single-session.ts +6 -0
  26. package/src/prompts/templates/test-writer.ts +6 -0
  27. package/src/prompts/templates/verifier.ts +6 -0
  28. package/src/prompts/types.ts +21 -0
  29. package/src/review/runner.ts +6 -1
  30. package/src/tdd/session-runner.ts +12 -12
  31. package/src/version.ts +2 -1
  32. package/.claude/rules/01-project-conventions.md +0 -34
  33. package/.claude/rules/02-test-architecture.md +0 -39
  34. package/.claude/rules/03-test-writing.md +0 -58
  35. package/.claude/rules/04-forbidden-patterns.md +0 -29
  36. package/.claude/settings.json +0 -15
  37. package/.githooks/pre-commit +0 -16
  38. package/.gitlab-ci.yml +0 -103
  39. package/.mcp.json +0 -8
  40. package/BRIEF.md +0 -140
  41. package/CLAUDE.md +0 -143
  42. package/US-007-IMPLEMENTATION.md +0 -139
  43. package/biome.json +0 -14
  44. package/bun.lock +0 -163
  45. package/bunfig.toml +0 -12
  46. package/docker-compose.test.yml +0 -15
  47. package/docs/20260216-fix-plan-context-review.md +0 -56
  48. package/docs/20260216-relentless-vs-ngent-comparison.md +0 -208
  49. package/docs/20260216-v02-plan.md +0 -136
  50. package/docs/20260216-v02-review.md +0 -685
  51. package/docs/20260217-dogfood-findings.md +0 -56
  52. package/docs/20260217-p2-plus-plan.md +0 -117
  53. package/docs/20260217-partial-fixes-plan.md +0 -62
  54. package/docs/20260217-plan-analyze-spec.md +0 -117
  55. package/docs/20260217-post-impl-review.md +0 -1137
  56. package/docs/20260217-quick-wins-plan.md +0 -66
  57. package/docs/20260217-split-runner-plan.md +0 -75
  58. package/docs/20260217-v03-impl-plan.md +0 -80
  59. package/docs/20260217-v03-post-impl-review.md +0 -589
  60. package/docs/20260217-v04-impl-plan.md +0 -86
  61. package/docs/20260217-v05-post-impl-review.md +0 -850
  62. package/docs/20260217-v06-post-impl-review.md +0 -817
  63. package/docs/20260218-adr003-port-plan.md +0 -151
  64. package/docs/20260218-review-adr003-verification.md +0 -175
  65. package/docs/20260219-fix-plan-bug16-19.md +0 -79
  66. package/docs/20260219-fix-plan-bug20-22.md +0 -114
  67. package/docs/20260219-plan-llm-routing.md +0 -116
  68. package/docs/20260219-review-bug20-22-fixes.md +0 -135
  69. package/docs/20260219-routing-baseline-keyword.md +0 -63
  70. package/docs/20260220-plan-structured-logging-p1.md +0 -80
  71. package/docs/20260220-plan-structured-logging-p2.md +0 -37
  72. package/docs/20260220-review-llm-routing.md +0 -180
  73. package/docs/20260220-review-post-fix-llm-routing.md +0 -70
  74. package/docs/20260221-fix-plan-relevantfiles-split.md +0 -101
  75. package/docs/20260221-fix-plan-routing-mode.md +0 -125
  76. package/docs/20260221-review-v0.9-implementation.md +0 -379
  77. package/docs/20260222-fix-plan-v091-routing-isolation.md +0 -197
  78. package/docs/20260223-fix-plan-prompt-audit.md +0 -62
  79. package/docs/20260224-nax-roadmap-phases.md +0 -189
  80. package/docs/20260225-phase2-llm-service-layer.md +0 -401
  81. package/docs/20260225-review-v0.10.1.md +0 -187
  82. package/docs/20260303-v010-implementation-plan.md +0 -165
  83. package/docs/20260304-review-nax.md +0 -492
  84. package/docs/CLAUDE.md.bak +0 -191
  85. package/docs/ROADMAP.md +0 -364
  86. package/docs/SPEC-rectification.md +0 -0
  87. package/docs/SPEC.md +0 -324
  88. package/docs/US-001-plugin-loading-verification.md +0 -152
  89. package/docs/adr/ADR-005-implementation-plan.md +0 -655
  90. package/docs/adr/ADR-005-pipeline-re-architecture.md +0 -464
  91. package/docs/architecture-analysis.md +0 -1076
  92. package/docs/bugs/BUG-21-escalation-null-attempts.md +0 -48
  93. package/docs/bugs-from-dogfood-run-c.md +0 -243
  94. package/docs/code-review-20260228.md +0 -612
  95. package/docs/code-review-v0.15.0.md +0 -629
  96. package/docs/hook-lifecycle-test-plan.md +0 -149
  97. package/docs/releases/v0.11.0-and-earlier.md +0 -20
  98. package/docs/releases/v0.12.0.md +0 -15
  99. package/docs/releases/v0.13.0.md +0 -14
  100. package/docs/releases/v0.14.0.md +0 -20
  101. package/docs/releases/v0.14.1.md +0 -36
  102. package/docs/releases/v0.14.2.md +0 -51
  103. package/docs/releases/v0.14.3.md +0 -174
  104. package/docs/releases/v0.14.4.md +0 -94
  105. package/docs/releases/v0.15.0.md +0 -502
  106. package/docs/releases/v0.15.1.md +0 -170
  107. package/docs/releases/v0.15.3.md +0 -193
  108. package/docs/specs/bug-039-orphan-processes.md +0 -131
  109. package/docs/specs/bug-040-review-rectification.md +0 -82
  110. package/docs/specs/bug-041-cross-story-test-isolation.md +0 -88
  111. package/docs/specs/bug-042-verifier-failure-capture.md +0 -117
  112. package/docs/specs/bun-pty-migration.md +0 -171
  113. package/docs/specs/central-run-registry.md +0 -116
  114. package/docs/specs/feat-010-smart-runner-git-history.md +0 -96
  115. package/docs/specs/feat-011-file-context-strategy.md +0 -73
  116. package/docs/specs/feat-012-tdd-writer-tier.md +0 -79
  117. package/docs/specs/feat-013-test-after-review.md +0 -89
  118. package/docs/specs/feat-014-heartbeat-observability.md +0 -127
  119. package/docs/specs/status-file-consolidation.md +0 -93
  120. package/docs/specs/status-file-v0.10.1.md +0 -812
  121. package/docs/specs/trigger-completion.md +0 -145
  122. package/docs/specs/verification-architecture-v2.md +0 -343
  123. package/docs/tdd/strategies.md +0 -97
  124. package/docs/v0.10-global-config.md +0 -206
  125. package/docs/v0.10-plugin-system.md +0 -415
  126. package/docs/v0.10-prompt-optimizer.md +0 -234
  127. package/docs/v0.3-spec.md +0 -244
  128. package/docs/v0.4-spec.md +0 -140
  129. package/docs/v0.5-spec.md +0 -237
  130. package/docs/v0.6-spec.md +0 -371
  131. package/docs/v0.7-spec.md +0 -177
  132. package/docs/v0.8-llm-routing.md +0 -206
  133. package/docs/v0.8-structured-logging.md +0 -132
  134. package/docs/v0.9.3-prompt-audit.md +0 -112
  135. package/examples/plugins/console-reporter/index.test.ts +0 -207
  136. package/examples/plugins/console-reporter/index.ts +0 -110
  137. package/memory/topic/feat-010-baseref.md +0 -28
  138. package/memory/topic/feat-013-test-after-deprecation.md +0 -22
  139. package/nax/config.json +0 -154
  140. package/nax/features/bug-039-medium/prd.json +0 -45
  141. package/nax/features/bugfix-v0171/prd.json +0 -52
  142. package/nax/features/central-run-registry/prd.json +0 -105
  143. package/nax/features/config-management/prd.json +0 -108
  144. package/nax/features/config-management/progress.txt +0 -5
  145. package/nax/features/diagnose/acceptance.test.ts +0 -414
  146. package/nax/features/diagnose/prd.json +0 -41
  147. package/nax/features/nax-compliance/prd.json +0 -52
  148. package/nax/features/nax-compliance/progress.txt +0 -1
  149. package/nax/features/orchestration-fixes/prd.json +0 -89
  150. package/nax/features/orchestration-fixes/progress.txt +0 -1
  151. package/nax/features/plugin-integration/US-007-VERIFICATION.md +0 -259
  152. package/nax/features/plugin-integration/prd.json +0 -208
  153. package/nax/features/plugin-integration/progress.txt +0 -5
  154. package/nax/features/post-rearch-bugfix/prd.json +0 -137
  155. package/nax/features/precheck/prd.json +0 -205
  156. package/nax/features/precheck/progress.txt +0 -15
  157. package/nax/features/review-quality/prd.json +0 -55
  158. package/nax/features/routing-persistence/prd.json +0 -104
  159. package/nax/features/routing-persistence/progress.txt +0 -1
  160. package/nax/features/smart-test-runner/plan.md +0 -7
  161. package/nax/features/smart-test-runner/prd.json +0 -203
  162. package/nax/features/smart-test-runner/progress.txt +0 -13
  163. package/nax/features/smart-test-runner/spec.md +0 -7
  164. package/nax/features/smart-test-runner/tasks.md +0 -8
  165. package/nax/features/status-file-consolidation/prd.json +0 -106
  166. package/nax/features/structured-logging/prd.json +0 -199
  167. package/nax/features/trigger-completion/prd.json +0 -150
  168. package/nax/features/trigger-completion/progress.txt +0 -7
  169. package/nax/features/unlock/prd.json +0 -36
  170. package/nax/features/v0.18.3-execution-reliability/prd.json +0 -80
  171. package/nax/features/v0.18.3-execution-reliability/progress.txt +0 -3
  172. package/nax/features/v0.19.0-hardening/plan.md +0 -7
  173. package/nax/features/v0.19.0-hardening/prd.json +0 -84
  174. package/nax/features/v0.19.0-hardening/progress.txt +0 -7
  175. package/nax/features/v0.19.0-hardening/spec.md +0 -18
  176. package/nax/features/v0.19.0-hardening/tasks.md +0 -8
  177. package/nax/features/verify-v2/prd.json +0 -79
  178. package/nax/features/verify-v2/progress.txt +0 -3
  179. package/nax/status.json +0 -36
  180. package/test/COVERAGE-GAPS.md +0 -333
  181. package/test/e2e/cm-003-default-view.test.ts +0 -195
  182. package/test/e2e/plan-analyze-run.test.ts +0 -902
  183. package/test/helpers/helpers.test.ts +0 -295
  184. package/test/helpers/timeout.ts +0 -42
  185. package/test/integration/US-002-TEST-SUMMARY.md +0 -107
  186. package/test/integration/US-003-TEST-SUMMARY.md +0 -149
  187. package/test/integration/US-004-TEST-SUMMARY.md +0 -106
  188. package/test/integration/US-005-TEST-SUMMARY.md +0 -138
  189. package/test/integration/US-007-TEST-SUMMARY.md +0 -100
  190. package/test/integration/cli/agent-validation.test.ts +0 -439
  191. package/test/integration/cli/cli-config-default-edge-cases.test.ts +0 -223
  192. package/test/integration/cli/cli-config-default-view.test.ts +0 -230
  193. package/test/integration/cli/cli-config-diff.test.ts +0 -461
  194. package/test/integration/cli/cli-config.test.ts +0 -737
  195. package/test/integration/cli/cli-diagnose.test.ts +0 -595
  196. package/test/integration/cli/cli-logs.test.ts +0 -346
  197. package/test/integration/cli/cli-plugins.test.ts +0 -679
  198. package/test/integration/cli/cli-precheck.test.ts +0 -372
  199. package/test/integration/cli/cli-run-headless.test.ts +0 -174
  200. package/test/integration/cli/cli.test.ts +0 -76
  201. package/test/integration/cli/precheck-integration.test.ts +0 -476
  202. package/test/integration/cli/precheck-orchestrator.test.ts +0 -247
  203. package/test/integration/cli/precheck.test.ts +0 -806
  204. package/test/integration/config/config-loader.test.ts +0 -266
  205. package/test/integration/config/config.test.ts +0 -444
  206. package/test/integration/config/merger.test.ts +0 -466
  207. package/test/integration/config/paths.test.ts +0 -52
  208. package/test/integration/config/security-loader.test.ts +0 -83
  209. package/test/integration/context/context-integration.test.ts +0 -703
  210. package/test/integration/context/context-path-security.test.ts +0 -173
  211. package/test/integration/context/context-provider-injection.test.ts +0 -507
  212. package/test/integration/context/context-verification-integration.test.ts +0 -296
  213. package/test/integration/context/s5-greenfield-fallback.test.ts +0 -298
  214. package/test/integration/execution/execution-isolation.test.ts +0 -143
  215. package/test/integration/execution/execution.test.ts +0 -634
  216. package/test/integration/execution/feature-status-write.test.ts +0 -302
  217. package/test/integration/execution/parallel.test.ts +0 -251
  218. package/test/integration/execution/prd-pause.test.ts +0 -205
  219. package/test/integration/execution/prd-resolvers.test.ts +0 -186
  220. package/test/integration/execution/progress.test.ts +0 -34
  221. package/test/integration/execution/runner-batching.test.ts +0 -682
  222. package/test/integration/execution/runner-config-plugins.test.ts +0 -462
  223. package/test/integration/execution/runner-escalation.test.ts +0 -561
  224. package/test/integration/execution/runner-fixes.test.ts +0 -400
  225. package/test/integration/execution/runner-plugin-integration.test.ts +0 -544
  226. package/test/integration/execution/runner-queue-and-attempts.test.ts +0 -476
  227. package/test/integration/execution/status-file-integration.test.ts +0 -289
  228. package/test/integration/execution/status-file.test.ts +0 -380
  229. package/test/integration/execution/status-writer.test.ts +0 -447
  230. package/test/integration/execution/story-id-in-events.test.ts +0 -274
  231. package/test/integration/interaction/interaction-chain-pipeline.test.ts +0 -476
  232. package/test/integration/pipeline/hooks.test.ts +0 -363
  233. package/test/integration/pipeline/pipeline-acceptance.test.ts +0 -303
  234. package/test/integration/pipeline/pipeline-events.test.ts +0 -476
  235. package/test/integration/pipeline/pipeline.test.ts +0 -660
  236. package/test/integration/pipeline/reporter-lifecycle.test.ts +0 -862
  237. package/test/integration/pipeline/verify-stage.test.ts +0 -286
  238. package/test/integration/plan/analyze-integration.test.ts +0 -262
  239. package/test/integration/plan/analyze-scanner.test.ts +0 -132
  240. package/test/integration/plan/logger.test.ts +0 -461
  241. package/test/integration/plan/plan.test.ts +0 -157
  242. package/test/integration/plugins/config-integration.test.ts +0 -173
  243. package/test/integration/plugins/config-resolution.test.ts +0 -523
  244. package/test/integration/plugins/loader.test.ts +0 -644
  245. package/test/integration/plugins/plugins-registry.test.ts +0 -747
  246. package/test/integration/plugins/validator.test.ts +0 -564
  247. package/test/integration/review/review-config-commands.test.ts +0 -320
  248. package/test/integration/review/review-config-schema.test.ts +0 -117
  249. package/test/integration/review/review-plugin-integration.test.ts +0 -729
  250. package/test/integration/review/review.test.ts +0 -150
  251. package/test/integration/routing/plugin-routing-advanced.test.ts +0 -461
  252. package/test/integration/routing/plugin-routing-core.test.ts +0 -527
  253. package/test/integration/routing/routing-stage-bug-021.test.ts +0 -275
  254. package/test/integration/routing/routing-stage-greenfield.test.ts +0 -287
  255. package/test/integration/tdd/tdd-cleanup.test.ts +0 -246
  256. package/test/integration/tdd/tdd-orchestrator-core.test.ts +0 -565
  257. package/test/integration/tdd/tdd-orchestrator-failureCategory.test.ts +0 -355
  258. package/test/integration/tdd/tdd-orchestrator-fallback.test.ts +0 -311
  259. package/test/integration/tdd/tdd-orchestrator-lite.test.ts +0 -289
  260. package/test/integration/tdd/tdd-orchestrator-prompts.test.ts +0 -260
  261. package/test/integration/tdd/tdd-orchestrator-verdict.test.ts +0 -536
  262. package/test/integration/tmp/headless-test/test.jsonl +0 -30
  263. package/test/integration/verification/test-scanner.test.ts +0 -403
  264. package/test/integration/verification/verification-asset-check.test.ts +0 -143
  265. package/test/integration/worktree/manager.test.ts +0 -218
  266. package/test/integration/worktree/worktree-merge.test.ts +0 -341
  267. package/test/manual/logging-formatter-demo.ts +0 -158
  268. package/test/ui/tui-agent-panel.test.tsx +0 -99
  269. package/test/ui/tui-pty-integration.test.tsx +0 -146
  270. package/test/unit/acceptance.test.ts +0 -187
  271. package/test/unit/agent-stderr-capture.test.ts +0 -147
  272. package/test/unit/agents/claude.test.ts +0 -107
  273. package/test/unit/analyze-classifier.test.ts +0 -216
  274. package/test/unit/analyze.test.ts +0 -224
  275. package/test/unit/auto-detect.test.ts +0 -250
  276. package/test/unit/cli-status-project-level.test.ts +0 -283
  277. package/test/unit/cli-status.test.ts +0 -418
  278. package/test/unit/commands/common.test.ts +0 -321
  279. package/test/unit/commands/logs.test.ts +0 -458
  280. package/test/unit/commands/runs.test.ts +0 -303
  281. package/test/unit/commands/unlock.test.ts +0 -320
  282. package/test/unit/config/defaults.test.ts +0 -70
  283. package/test/unit/config/quality-commands-schema.test.ts +0 -72
  284. package/test/unit/config/regression-gate-schema.test.ts +0 -160
  285. package/test/unit/config/smart-runner-flag.test.ts +0 -250
  286. package/test/unit/constitution-generators.test.ts +0 -161
  287. package/test/unit/constitution.test.ts +0 -210
  288. package/test/unit/context/context-autodetect.test.ts +0 -297
  289. package/test/unit/context/context-build.test.ts +0 -575
  290. package/test/unit/context/context-coverage.test.ts +0 -236
  291. package/test/unit/context/context-error.test.ts +0 -93
  292. package/test/unit/context/context-estimate-tokens.test.ts +0 -201
  293. package/test/unit/context/context-format.test.ts +0 -302
  294. package/test/unit/context/context-isolation.test.ts +0 -267
  295. package/test/unit/context/context-sort.test.ts +0 -93
  296. package/test/unit/context/context-story.test.ts +0 -108
  297. package/test/unit/context/prior-failures.test.ts +0 -463
  298. package/test/unit/context.test.ts +0 -1726
  299. package/test/unit/cost.test.ts +0 -231
  300. package/test/unit/crash-recovery.test.ts +0 -309
  301. package/test/unit/escalation.test.ts +0 -127
  302. package/test/unit/execution/lifecycle/run-completion.test.ts +0 -240
  303. package/test/unit/execution/lifecycle/run-regression.test.ts +0 -420
  304. package/test/unit/execution/pid-registry.test.ts +0 -241
  305. package/test/unit/execution/sequential-executor.test.ts +0 -235
  306. package/test/unit/execution/sfc-004-dead-code-cleanup.test.ts +0 -89
  307. package/test/unit/execution/structured-failure.test.ts +0 -415
  308. package/test/unit/execution-logging-stderr.test.ts +0 -157
  309. package/test/unit/execution-stage.test.ts +0 -123
  310. package/test/unit/fix-generator.test.ts +0 -276
  311. package/test/unit/formatters.test.ts +0 -468
  312. package/test/unit/greenfield.test.ts +0 -180
  313. package/test/unit/hooks/shell-security.test.ts +0 -40
  314. package/test/unit/interaction/auto-plugin.test.ts +0 -162
  315. package/test/unit/interaction/human-review-trigger.test.ts +0 -165
  316. package/test/unit/interaction-network-failures.test.ts +0 -390
  317. package/test/unit/interaction-plugins.test.ts +0 -472
  318. package/test/unit/logging/formatter.test.ts +0 -456
  319. package/test/unit/merge.test.ts +0 -269
  320. package/test/unit/metrics/aggregator.test.ts +0 -164
  321. package/test/unit/metrics/tracker.test.ts +0 -186
  322. package/test/unit/metrics.test.ts +0 -276
  323. package/test/unit/optimizer/noop.optimizer.test.ts +0 -125
  324. package/test/unit/optimizer/rule-based.optimizer.test.ts +0 -358
  325. package/test/unit/pipeline/event-bus.test.ts +0 -105
  326. package/test/unit/pipeline/routing-partial-override.test.ts +0 -121
  327. package/test/unit/pipeline/runner-retry.test.ts +0 -89
  328. package/test/unit/pipeline/stages/autofix.test.ts +0 -97
  329. package/test/unit/pipeline/stages/completion-review-gate.test.ts +0 -218
  330. package/test/unit/pipeline/stages/execution-ambiguity.test.ts +0 -311
  331. package/test/unit/pipeline/stages/execution-merge-conflict.test.ts +0 -218
  332. package/test/unit/pipeline/stages/rectify.test.ts +0 -101
  333. package/test/unit/pipeline/stages/regression-stage.test.ts +0 -69
  334. package/test/unit/pipeline/stages/review.test.ts +0 -201
  335. package/test/unit/pipeline/stages/routing-idempotence.test.ts +0 -139
  336. package/test/unit/pipeline/stages/routing-initial-complexity.test.ts +0 -321
  337. package/test/unit/pipeline/stages/routing-persistence.test.ts +0 -380
  338. package/test/unit/pipeline/stages/verify.test.ts +0 -267
  339. package/test/unit/pipeline/subscribers/events-writer.test.ts +0 -227
  340. package/test/unit/pipeline/subscribers/hooks.test.ts +0 -84
  341. package/test/unit/pipeline/subscribers/interaction.test.ts +0 -313
  342. package/test/unit/pipeline/subscribers/registry.test.ts +0 -149
  343. package/test/unit/pipeline/subscribers/reporters.test.ts +0 -90
  344. package/test/unit/pipeline/verify-smart-runner.test.ts +0 -345
  345. package/test/unit/prd-auto-default.test.ts +0 -291
  346. package/test/unit/prd-failure-category.test.ts +0 -177
  347. package/test/unit/prd-get-next-story.test.ts +0 -215
  348. package/test/unit/precheck-checks.test.ts +0 -841
  349. package/test/unit/precheck-story-size-gate.test.ts +0 -288
  350. package/test/unit/precheck-types.test.ts +0 -143
  351. package/test/unit/prompts.test.ts +0 -476
  352. package/test/unit/queue.test.ts +0 -237
  353. package/test/unit/rectification.test.ts +0 -285
  354. package/test/unit/registry.test.ts +0 -288
  355. package/test/unit/review/runner.test.ts +0 -117
  356. package/test/unit/routing/content-hash.test.ts +0 -99
  357. package/test/unit/routing/routing-stability.test.ts +0 -208
  358. package/test/unit/routing/strategies/llm.test.ts +0 -306
  359. package/test/unit/routing-advanced.test.ts +0 -313
  360. package/test/unit/routing-core.test.ts +0 -341
  361. package/test/unit/routing-strategies.test.ts +0 -440
  362. package/test/unit/storyid-events.test.ts +0 -213
  363. package/test/unit/tdd-verdict.test.ts +0 -492
  364. package/test/unit/test-output-parser.test.ts +0 -377
  365. package/test/unit/ui/tui-controls.test.ts +0 -335
  366. package/test/unit/ui/tui-cost-and-pty.test.ts +0 -190
  367. package/test/unit/ui/tui-layout.test.ts +0 -379
  368. package/test/unit/ui/tui-stories.test.ts +0 -333
  369. package/test/unit/unit-isolation.test.ts +0 -135
  370. package/test/unit/utils/git.test.ts +0 -50
  371. package/test/unit/utils/path-security.test.ts +0 -47
  372. package/test/unit/utils-helpers.test.ts +0 -318
  373. package/test/unit/verdict.test.ts +0 -325
  374. package/test/unit/verification/orchestrator-types.test.ts +0 -54
  375. package/test/unit/verification/orchestrator.test.ts +0 -66
  376. package/test/unit/verification/smart-runner-config.test.ts +0 -163
  377. package/test/unit/verification/smart-runner-discovery.test.ts +0 -354
  378. package/test/unit/verification/smart-runner.test.ts +0 -262
  379. package/test/unit/verification/strategies/acceptance.test.ts +0 -33
  380. package/test/unit/verification/strategies/regression.test.ts +0 -87
  381. package/test/unit/verification/strategies/scoped.test.ts +0 -100
  382. package/test/unit/worktree-manager.test.ts +0 -159
  383. package/tsconfig.json +0 -27
@@ -1,125 +0,0 @@
1
- # Fix Plan: Configurable LLM Routing Mode
2
-
3
- **Date:** 2026-02-21
4
- **Branch:** `feat/v0.9-routing-mode`
5
- **Issue:** #2
6
- **Base:** `master` (`b459e9f`)
7
-
8
- ## Context
9
-
10
- Current `batchMode: boolean` is a binary on/off. Issue #2 replaces it with
11
- `mode: "one-shot" | "per-story" | "hybrid"` for fine-grained control.
12
-
13
- **Mode semantics:**
14
- - `one-shot`: batch-route ALL pending stories once at run start. If a story
15
- is missing from cache at execution time, use keyword fallback (no new LLM call).
16
- Minimises Claude sessions spawned (1 total). Eliminates hook noise.
17
- - `per-story`: route each story individually just before execution.
18
- Current behaviour when `batchMode: false`. Max LLM calls = N stories.
19
- - `hybrid` (DEFAULT): batch-route upfront like one-shot, but on story
20
- retry/failure, re-route that story individually. Best quality + cost balance.
21
-
22
- **Problem solved:** With LLM routing, Run H spawned 9+ separate Claude sessions
23
- for routing (one per story) causing hook noise and extra cost. One-shot or hybrid
24
- reduces this to 1 batch call.
25
-
26
- ## Phase 1: Config Schema
27
-
28
- ### Fix 1.1: Replace batchMode with mode enum
29
- **File:** `src/config/schema.ts`
30
- **Change:**
31
- - In `LlmRoutingConfig` interface: remove `batchMode?: boolean`, add `mode?: "one-shot" | "per-story" | "hybrid"`
32
- - In Zod schema: replace `batchMode: z.boolean().optional()` with
33
- `mode: z.enum(["one-shot", "per-story", "hybrid"]).optional()`
34
- - Default value: `"hybrid"` (applied in defaults/config resolver)
35
-
36
- ### Fix 1.2: Update config defaults
37
- **File:** `src/config/defaults.ts` (or wherever defaults are set)
38
- **Change:** Set `routing.llm.mode` default to `"hybrid"`.
39
-
40
- ### Fix 1.3: Backward compat shim
41
- **File:** `src/config/resolver.ts` (or schema.ts transform)
42
- **Change:** If old `batchMode: true` is present, map to `mode: "one-shot"`.
43
- If `batchMode: false`, map to `mode: "per-story"`. Log deprecation warning.
44
-
45
- **Commit:** `feat(config): replace routing.llm.batchMode with routing.llm.mode enum`
46
-
47
- ## Phase 2: LLM Strategy — One-Shot Strict Cache
48
-
49
- ### Fix 2.1: Add one-shot cache-miss behaviour
50
- **File:** `src/routing/strategies/llm.ts`
51
- **Change:** In `llmStrategy.route()` (the per-story routing call), check if mode
52
- is `one-shot`. If so and the story is NOT in cache → return keyword fallback
53
- result immediately without making a new LLM call.
54
-
55
- ```typescript
56
- // In llmStrategy.route()
57
- if (config.routing.llm?.mode === "one-shot" && cachedDecisions.has(story.id)) {
58
- return cachedDecisions.get(story.id)!;
59
- }
60
- if (config.routing.llm?.mode === "one-shot") {
61
- // Cache miss in one-shot mode — fall back to keyword, no new LLM call
62
- return keywordStrategy.route(context);
63
- }
64
- ```
65
-
66
- ### Fix 2.2: Export mode helper
67
- **File:** `src/routing/strategies/llm.ts`
68
- **Change:** Add `getCacheSize(): number` export for test verification.
69
-
70
- **Commit:** `feat(routing): one-shot mode skips per-story LLM calls on cache miss`
71
-
72
- ## Phase 3: Runner — Wire Mode to Batch Trigger
73
-
74
- ### Fix 3.1: Update tryLlmBatchRoute guard
75
- **File:** `src/execution/runner.ts`
76
- **Change:** Replace the `batchMode` guard with mode check:
77
- ```typescript
78
- // OLD:
79
- if (config.routing.strategy !== "llm" || !config.routing.llm?.batchMode ...) return;
80
- // NEW:
81
- const mode = config.routing.llm?.mode ?? "hybrid";
82
- if (config.routing.strategy !== "llm" || mode === "per-story" ...) return;
83
- ```
84
-
85
- ### Fix 3.2: Hybrid re-route on failure
86
- **File:** `src/execution/runner.ts`
87
- **Change:** In story retry logic, when mode is `hybrid` and story failed:
88
- - Call `llmRouteBatch([story], ...)` to re-route just that story
89
- - This invalidates and refreshes its cache entry before the next attempt
90
- Look for where stories are retried (error handling after agent run) and inject the re-route call.
91
-
92
- ### Fix 3.3: Log mode at run start
93
- **File:** `src/execution/runner.ts`
94
- **Change:** In the run-start logging block, include `routingMode` in the log entry.
95
-
96
- **Commit:** `feat(runner): wire routing mode to batch trigger and hybrid re-route`
97
-
98
- ## Phase 4: Tests
99
-
100
- ### Fix 4.1: Config schema tests
101
- **Change:** Test `mode` enum is accepted (`one-shot`, `per-story`, `hybrid`).
102
- Test backward compat: `batchMode: true` → `mode: "one-shot"`.
103
- Test default is `"hybrid"`.
104
-
105
- ### Fix 4.2: LLM strategy tests
106
- **Change:** Test one-shot mode: after `routeBatch()`, a cache-miss story returns
107
- keyword fallback without making another LLM call.
108
- Test per-story mode: each story triggers individual LLM call.
109
- Test hybrid: upfront batch + per-story call on cache miss.
110
-
111
- ### Fix 4.3: Runner integration tests (if any)
112
- **Change:** Verify `tryLlmBatchRoute` is called on `one-shot`/`hybrid` but not `per-story`.
113
-
114
- **Commit:** `test: add tests for routing mode config and one-shot/hybrid behaviour`
115
-
116
- ## Test Strategy
117
- - Mode: test-after
118
- - Run `bun test` after each phase
119
- - Backward compat: existing configs with `batchMode: true` must still work
120
-
121
- ## Commits
122
- 1. `feat(config): replace routing.llm.batchMode with routing.llm.mode enum`
123
- 2. `feat(routing): one-shot mode skips per-story LLM calls on cache miss`
124
- 3. `feat(runner): wire routing mode to batch trigger and hybrid re-route`
125
- 4. `test: add tests for routing mode config and one-shot/hybrid behaviour`
@@ -1,379 +0,0 @@
1
- # v0.9 Implementation Review
2
-
3
- **Date:** 2026-02-21
4
- **Reviewer:** code-reviewer agent (Opus 4.6)
5
- **Branches:** `feat/v0.9-relevantfiles-split` (Issue #1), `feat/v0.9-routing-mode` (Issue #2)
6
- **Test Status:** 710 pass, 2 skip, 6 fail (out of 718). All failures are pre-existing.
7
-
8
- ---
9
-
10
- ## Overall Grade: B+ (84/100)
11
-
12
- | Category | Score | Max | Notes |
13
- |--------------------|-------|-----|--------------------------------------------------|
14
- | Security | 18 | 20 | No injection risks. Minor: mutation of raw config object in compat shim. |
15
- | Reliability | 16 | 20 | Global config compat shim missing. Edge case with empty array fallback well-handled. |
16
- | API Design | 18 | 20 | Clean resolver pattern. `LlmRoutingMode` enum well-designed. Minor JSDoc gap in `classifier.ts` bridge. |
17
- | Code Quality | 16 | 20 | Good test coverage. `runner.ts` at 921 lines (exceeds 800 guideline). Mutation in `applyCachedRouting`. |
18
- | Best Practices | 16 | 20 | Bun-native APIs used throughout. Immutability violated in 2 places. LLM prompt not updated in classifier. |
19
-
20
- ---
21
-
22
- ## Findings
23
-
24
- ### CRITICAL
25
-
26
- None.
27
-
28
- ### HIGH
29
-
30
- #### [HIGH-1] `applyBatchModeCompat` not applied to global config
31
- **File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/config/loader.ts:99-102`
32
- **Branch:** `feat/v0.9-routing-mode`
33
-
34
- The backward compatibility shim `applyBatchModeCompat()` is called on `projConf` (line 111) but NOT on `globalConf` (line 100-101). If a user has `routing.llm.batchMode: true` in their global config (`~/.nax/config.json`) but no project config, the shim never runs.
35
-
36
- After `deepMerge` with defaults (which now set `mode: "hybrid"`), the `"mode" in llm` guard in `applyBatchModeCompat` would prevent mapping even if the shim were called later. But the root issue is that global-only users with `batchMode` will silently get `mode: "hybrid"` from defaults instead of the expected `mode: "one-shot"`.
37
-
38
- **Impact:** Users with global-only config using deprecated `batchMode: true` will get unexpected routing behavior. Silent behavior change with no deprecation warning.
39
-
40
- **Fix:**
41
- ```typescript
42
- // In loadConfig(), after loading global config:
43
- const globalConf = await loadJsonFile<Record<string, unknown>>(globalConfigPath());
44
- if (globalConf) {
45
- applyBatchModeCompat(globalConf); // <-- Add this line
46
- rawConfig = deepMerge(rawConfig, globalConf);
47
- }
48
- ```
49
-
50
- ---
51
-
52
- #### [HIGH-2] `applyBatchModeCompat` mutates its argument
53
- **File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/config/loader.ts:76-91`
54
- **Branch:** `feat/v0.9-routing-mode`
55
-
56
- The function mutates the `conf` object in-place (`llm.mode = ...`). While this works because the caller does not reuse the raw config, it violates the project's immutability guideline (from CLAUDE.md: "Immutable patterns -- avoid mutation"). The `deepMerge` function correctly uses spread operators; the compat shim should follow the same pattern.
57
-
58
- **Impact:** Low immediate risk (caller does not reuse), but sets a bad precedent and makes the code harder to reason about. Could cause subtle bugs if `loadConfig` is refactored to reuse partial configs.
59
-
60
- **Fix:**
61
- Return a new object instead of mutating, or document the intentional mutation:
62
- ```typescript
63
- function applyBatchModeCompat(conf: Record<string, unknown>): Record<string, unknown> {
64
- const routing = conf.routing as Record<string, unknown> | undefined;
65
- const llm = routing?.llm as Record<string, unknown> | undefined;
66
- if (llm && "batchMode" in llm && !("mode" in llm)) {
67
- const batchMode = llm.batchMode;
68
- if (typeof batchMode === "boolean") {
69
- return {
70
- ...conf,
71
- routing: {
72
- ...routing,
73
- llm: {
74
- ...llm,
75
- mode: batchMode ? "one-shot" : "per-story",
76
- },
77
- },
78
- };
79
- }
80
- }
81
- return conf;
82
- }
83
- ```
84
-
85
- ---
86
-
87
- #### [HIGH-3] `applyCachedRouting` mutates the routing object
88
- **File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts:77-86`
89
- **Branch:** `feat/v0.9-routing-mode` (pre-existing, but worsened by new code paths)
90
-
91
- The function directly mutates `routing.complexity`, `routing.modelTier`, and `routing.testStrategy`. This is called from the main loop and the routing object is reused as `pipelineContext.routing`. If any downstream code assumes the routing object is the original from `routeTask()`, it will get incorrect values.
92
-
93
- **Impact:** The mutation is currently "safe" because the routing object is scoped to a single iteration, but it makes the code fragile. The new hybrid re-route call at line 340 uses the `story` object (not the routing), so no immediate bug, but the pattern is error-prone.
94
-
95
- **Fix:**
96
- ```typescript
97
- function applyCachedRouting(
98
- routing: ReturnType<typeof routeTask>,
99
- story: UserStory,
100
- config: NaxConfig
101
- ): ReturnType<typeof routeTask> {
102
- if (!story.routing) return routing;
103
- return {
104
- ...routing,
105
- ...(story.routing.complexity && {
106
- complexity: story.routing.complexity,
107
- modelTier: config.autoMode.complexityRouting[story.routing.complexity] ?? "balanced",
108
- }),
109
- ...(story.routing.testStrategy && {
110
- testStrategy: story.routing.testStrategy,
111
- }),
112
- };
113
- }
114
- ```
115
-
116
- ---
117
-
118
- ### MEDIUM
119
-
120
- #### [MED-1] `runner.ts` exceeds 800-line file size limit (921 lines)
121
- **File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts`
122
- **Branch:** `feat/v0.9-routing-mode` (pre-existing, worsened by +12 lines)
123
-
124
- The file was already at 909 lines before this change. The new routing mode code adds 12 more lines (two `tryLlmBatchRoute` calls and `routingMode` variable). The CLAUDE.md guidelines state "200-400 lines typical, 800 max per file." This file is now 15% over limit.
125
-
126
- **Impact:** Reduced readability and maintainability. The acceptance retry loop (lines 669-853) alone is ~184 lines and could be extracted.
127
-
128
- **Fix:** Extract the acceptance retry loop into `src/execution/acceptance-runner.ts`. This is already identified as STYLE-1 in the project backlog.
129
-
130
- ---
131
-
132
- #### [MED-2] LLM prompt in classifier still uses `relevantFiles` instead of `contextFiles`
133
- **File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/analyze/classifier.ts:217`
134
- **Branch:** `feat/v0.9-relevantfiles-split`
135
-
136
- The LLM prompt template still instructs the model to output `"relevantFiles"` in its JSON response. The parser correctly maps `rawItem.relevantFiles` to `contextFiles`, creating an implicit bridge. However:
137
- 1. This bridge is undocumented -- a future developer may update the prompt without updating the parser or vice versa.
138
- 2. The raw JSON type at line 21 still declares `relevantFiles: unknown`, not `contextFiles`.
139
-
140
- **Impact:** Confusion for future maintainers. If someone updates the prompt to use `contextFiles`, the parser will break (it reads `rawItem.relevantFiles`).
141
-
142
- **Fix:** Either:
143
- - (a) Update the prompt to output `contextFiles` and update the parser accordingly.
144
- - (b) Add a code comment documenting the intentional bridge: `// BRIDGE: LLM prompt outputs "relevantFiles", mapped to contextFiles here. Update both together.`
145
-
146
- ---
147
-
148
- #### [MED-3] LLM prompt in `claude.ts` agent updated but no backward compat for existing LLM outputs
149
- **File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/agents/claude.ts:538-541`
150
- **Branch:** `feat/v0.9-relevantfiles-split`
151
-
152
- The `decompose()` method now reads `item.contextFiles` from the LLM response. If an older cached LLM response or a different LLM version outputs `relevantFiles`, the parser will set `contextFiles: []` (empty array from the `Array.isArray` fallback). The `getContextFiles()` resolver would then return `[]` instead of falling back to `relevantFiles`.
153
-
154
- **Impact:** Context injection silently breaks for any LLM response that uses the old field name. The probability is low since decompose is called interactively, but if responses are cached or replayed, context will be lost.
155
-
156
- **Fix:** Parse both fields with fallback:
157
- ```typescript
158
- contextFiles: Array.isArray(item.contextFiles)
159
- ? item.contextFiles
160
- : Array.isArray(item.relevantFiles)
161
- ? item.relevantFiles
162
- : [],
163
- ```
164
-
165
- ---
166
-
167
- #### [MED-4] Module-level mutable cache (`cachedDecisions`) with no eviction policy
168
- **File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/routing/strategies/llm.ts:16`
169
- **Branch:** `feat/v0.9-routing-mode` (pre-existing, now more relevant due to one-shot mode reliance on cache)
170
-
171
- The `cachedDecisions` Map grows without bound during a run. For one-shot mode, the cache is the primary data store -- if it is cleared unexpectedly (e.g., module reload in watch mode), all subsequent stories fall back to keyword routing.
172
-
173
- **Impact:** Memory accumulation for very large PRDs. More importantly, one-shot mode's correctness depends on cache integrity.
174
-
175
- **Fix:** Add a `maxCacheSize` guard or LRU eviction. Document the cache's role in one-shot mode.
176
-
177
- ---
178
-
179
- #### [MED-5] `batchMode: false` + `mode: "one-shot"` conflict not validated
180
- **File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/config/schema.ts:458-465`
181
- **Branch:** `feat/v0.9-routing-mode`
182
-
183
- A user can set both `batchMode: false` and `mode: "one-shot"` in their config. The compat shim only maps `batchMode` when `mode` is absent (guard: `!("mode" in llm)`), so when both are set, `mode` wins. But there is no validation warning for the contradictory combination. This can confuse users during migration.
184
-
185
- **Impact:** User confusion. `batchMode: false` semantically means "don't batch" but `mode: "one-shot"` means "batch everything once." No error or warning.
186
-
187
- **Fix:** Add a Zod `.refine()` to warn when both fields are set with contradictory values:
188
- ```typescript
189
- const LlmRoutingConfigSchema = z.object({
190
- // ...existing fields
191
- }).refine((data) => {
192
- if (data.batchMode !== undefined && data.mode !== undefined) {
193
- // Both set - check for contradiction
194
- const implied = data.batchMode ? "one-shot" : "per-story";
195
- if (implied !== data.mode) {
196
- // Could log warning here
197
- }
198
- }
199
- return true;
200
- });
201
- ```
202
-
203
- ---
204
-
205
- #### [MED-6] Duplicate log lines in iteration start
206
- **File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts:385-403`
207
- **Branch:** `feat/v0.9-routing-mode` (pre-existing)
208
-
209
- Lines 385-392 log `"Starting iteration N"` with event name `"execution"`, and lines 395-403 log the same message with event name `"iteration.start"`. Both contain overlapping data. This was pre-existing but is worth noting as it inflates structured log output.
210
-
211
- **Impact:** Log noise. JSONL log files contain two near-identical entries per iteration.
212
-
213
- ---
214
-
215
- ### LOW
216
-
217
- #### [LOW-1] `getCacheSize()` exposed for testing only
218
- **File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/routing/strategies/llm.ts:24-26`
219
- **Branch:** `feat/v0.9-routing-mode`
220
-
221
- The function is exported solely for testing (`/** Get the current cache size (for testing) */`). While harmless, it widens the public API surface for a test utility. Consider using Bun's test mocking or accessing the cache through the module's test exports pattern instead.
222
-
223
- **Impact:** Negligible. Minor API surface bloat.
224
-
225
- ---
226
-
227
- #### [LOW-2] `fix-generator.ts` uses `contextFiles: []` instead of leaving field undefined
228
- **File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/acceptance/fix-generator.ts:361`
229
- **Branch:** `feat/v0.9-relevantfiles-split`
230
-
231
- Setting `contextFiles: []` explicitly means `getContextFiles()` returns `[]` even if a parent process later sets `relevantFiles` on the story. This is technically correct (fix stories should not inherit context from parent stories), but the behavior depends on `[]` being truthy for `??` -- which is correct in JavaScript but could confuse developers unfamiliar with nullish coalescing semantics.
232
-
233
- **Impact:** Negligible. Behavior is correct.
234
-
235
- ---
236
-
237
- #### [LOW-3] Missing JSDoc on `LlmRoutingMode` type
238
- **File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/config/schema.ts:233-234`
239
- **Branch:** `feat/v0.9-routing-mode`
240
-
241
- The type has a one-line comment (`/** LLM routing mode */`) but no documentation of what each enum value means. The detailed documentation is on the `mode` field in `LlmRoutingConfig`, but the type itself should also document its values for consumers who import it directly.
242
-
243
- **Impact:** Minor developer experience issue.
244
-
245
- ---
246
-
247
- #### [LOW-4] Test file backs up and restores global config
248
- **File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/test/config-loader.test.ts:30-39`
249
- **Branch:** `feat/v0.9-routing-mode`
250
-
251
- The test manipulates the real global config at `~/.nax/config.json` using rename+restore. While the cleanup is in `afterEach`, a crash between backup and restore could leave the user's config in a broken state. Consider using a mock or environment variable to redirect the config path during tests.
252
-
253
- **Impact:** Test safety. If test runner crashes, user's global config is a backup file.
254
-
255
- ---
256
-
257
- #### [LOW-5] Two empty lines between `deepMerge` and `applyBatchModeCompat`
258
- **File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/config/loader.ts:73-74`
259
- **Branch:** `feat/v0.9-routing-mode`
260
-
261
- Minor formatting inconsistency -- double blank line where the rest of the file uses single blank lines between functions.
262
-
263
- **Impact:** Cosmetic.
264
-
265
- ---
266
-
267
- ## Backward Compatibility Assessment
268
-
269
- ### Branch 1: `feat/v0.9-relevantfiles-split`
270
-
271
- | Scenario | Behavior | Correct? |
272
- |----------|----------|----------|
273
- | `contextFiles` set, `relevantFiles` unset | Uses `contextFiles` for context | Yes |
274
- | `contextFiles` unset, `relevantFiles` set | Falls back to `relevantFiles` for context | Yes |
275
- | Both `contextFiles` and `relevantFiles` set | Prefers `contextFiles` (nullish coalescing) | Yes |
276
- | Neither set | Returns empty array | Yes |
277
- | `expectedFiles` set | Uses for asset verification | Yes |
278
- | `expectedFiles` unset, `relevantFiles` set | Returns empty array (no fallback) | Yes, by design |
279
- | `expectedFiles: []` | Returns empty array (skips verification) | Yes |
280
- | LLM outputs `relevantFiles` in classify response | Mapped to `contextFiles` via bridge | Yes, but undocumented (MED-2) |
281
- | LLM outputs `relevantFiles` in decompose response | **Silently drops data** | No (MED-3) |
282
-
283
- ### Branch 2: `feat/v0.9-routing-mode`
284
-
285
- | Scenario | Behavior | Correct? |
286
- |----------|----------|----------|
287
- | `mode: "one-shot"` | Batch upfront, keyword fallback on miss | Yes |
288
- | `mode: "per-story"` | Individual LLM call per story | Yes |
289
- | `mode: "hybrid"` | Batch upfront + re-route on escalation | Yes |
290
- | `mode` unset | Defaults to `"hybrid"` | Yes |
291
- | `batchMode: true`, `mode` unset (project config) | Maps to `mode: "one-shot"` | Yes |
292
- | `batchMode: false`, `mode` unset (project config) | Maps to `mode: "per-story"` | Yes |
293
- | `batchMode: true`, `mode: "per-story"` | `mode` wins (explicit takes precedence) | Yes |
294
- | `batchMode: true`, `mode` unset (global config only) | **Silently ignored, gets "hybrid"** | No (HIGH-1) |
295
- | `batchMode: "yes"` (invalid type) | Zod validation rejects | Yes |
296
- | `mode: "ultra-batch"` (invalid value) | Zod validation rejects | Yes |
297
-
298
- ---
299
-
300
- ## Test Coverage Assessment
301
-
302
- ### Branch 1: `feat/v0.9-relevantfiles-split`
303
-
304
- | Test File | Tests Added | Coverage |
305
- |-----------|-------------|----------|
306
- | `test/prd-resolvers.test.ts` | 12 tests | Excellent: covers all fallback/precedence combinations |
307
- | `test/verification-asset-check.test.ts` | 9 tests | Excellent: covers opt-in semantics, legacy compat, dogfood scenarios |
308
- | `test/context-verification-integration.test.ts` | 6 tests | Good: end-to-end with temp files |
309
- | `test/context-integration.test.ts` | 3 tests added | Good: contextFiles, relevantFiles fallback, no-files |
310
- | `test/context.test.ts` | 3 tests added, 6 updated | Good: preference, fallback, limits |
311
- | `test/analyze-classifier.test.ts` | 1 updated | Adequate |
312
-
313
- **Missing coverage:**
314
- - No test for the `classifier.ts` bridge pattern where LLM outputs `relevantFiles` and it maps to `contextFiles`
315
- - No test for `claude.ts` decompose response with old `relevantFiles` field name
316
-
317
- ### Branch 2: `feat/v0.9-routing-mode`
318
-
319
- | Test File | Tests Added | Coverage |
320
- |-----------|-------------|----------|
321
- | `test/config.test.ts` | 6 tests | Good: all three modes + invalid + deprecated |
322
- | `test/config-loader.test.ts` | 4 tests | Good: compat shim, precedence, invalid type, defaults |
323
- | `test/routing/llm-strategy.test.ts` | 5 tests | Good: one-shot miss, one-shot hit, per-story, hybrid, default |
324
-
325
- **Missing coverage:**
326
- - No test for `batchMode` in global config (HIGH-1)
327
- - No test for hybrid re-route in `runner.ts` (lines 339-341, 591-593) -- these are integration paths
328
- - No test for `batchMode: false` mapping to `mode: "per-story"` in isolation (the loader test only covers `batchMode: true`)
329
-
330
- ---
331
-
332
- ## Logic Correctness
333
-
334
- ### `getContextFiles()` and `getExpectedFiles()` (Branch 1)
335
-
336
- The semantic split is correct and well-reasoned:
337
- - **contextFiles** = input to the agent (pre-execution context injection). Falls back to `relevantFiles` because existing PRDs should continue to provide context.
338
- - **expectedFiles** = output verification gate (post-execution asset check). Does NOT fall back because the old `relevantFiles` field was LLM-generated and unreliable for asset verification (documented in dogfood Run F findings).
339
-
340
- The `??` (nullish coalescing) operator is the correct choice here. An empty array `[]` is an explicit "no files" signal and should not trigger fallback. This is tested in `test/prd-resolvers.test.ts`.
341
-
342
- ### Routing Mode Logic (Branch 2)
343
-
344
- The three-mode design is correct:
345
-
346
- 1. **one-shot**: `tryLlmBatchRoute` runs at startup (line 208). On individual `route()`, cache hit returns cached decision; cache miss falls back to `keywordStrategy.route()` without an LLM call (line 380-386). This is cost-optimal for stable PRDs.
347
-
348
- 2. **per-story**: `tryLlmBatchRoute` returns early when `mode === "per-story"` (line 60). Each `route()` call triggers an individual LLM call (lines 388-409). This is quality-optimal for dynamic PRDs.
349
-
350
- 3. **hybrid**: `tryLlmBatchRoute` runs at startup (same as one-shot). On cache miss during `route()`, an individual LLM call is made (same as per-story). On escalation, `tryLlmBatchRoute` is called again for the escalated story (lines 339-341, 591-593). This combines upfront batching with retry precision.
351
-
352
- The `mode ?? "hybrid"` default is applied consistently in all three locations: `tryLlmBatchRoute` (line 59), `llmStrategy.route` (line 364), and `run()` (line 144).
353
-
354
- ---
355
-
356
- ## Priority Fix Order
357
-
358
- 1. **HIGH-1**: Apply `applyBatchModeCompat` to global config -- prevents silent behavior regression for global-config-only users.
359
- 2. **MED-3**: Add fallback for `relevantFiles` in `claude.ts` decompose parser -- prevents data loss from older LLM responses.
360
- 3. **HIGH-2**: Refactor `applyBatchModeCompat` to return new object -- aligns with project immutability guidelines.
361
- 4. **HIGH-3**: Refactor `applyCachedRouting` to return new object -- same rationale.
362
- 5. **MED-2**: Document or fix the classifier bridge pattern -- prevents future maintainer confusion.
363
- 6. **MED-5**: Add validation for contradictory `batchMode` + `mode` combinations.
364
- 7. **MED-1**: Extract acceptance retry loop from `runner.ts` -- file size reduction.
365
- 8. **LOW-4**: Mock global config path in tests instead of manipulating real file.
366
-
367
- ---
368
-
369
- ## Verdict
370
-
371
- **Approve with conditions (HIGH issues must be fixed before merge)**
372
-
373
- The v0.9 changes are well-structured with clear semantics, comprehensive test coverage, and proper backward compatibility design. The resolver function pattern (`getContextFiles`, `getExpectedFiles`) is clean and the three-mode routing enum is well-thought-out.
374
-
375
- However, three HIGH-priority issues need resolution before merge:
376
- 1. Global config compat shim gap (HIGH-1) is a user-facing regression risk
377
- 2. Two mutation patterns (HIGH-2, HIGH-3) violate project guidelines
378
-
379
- Once these are fixed, the changes are ready for v0.9.0 release.