@nathapp/nax 0.18.1

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 (459) hide show
  1. package/.gitlab-ci.yml +96 -0
  2. package/BRIEF.md +140 -0
  3. package/CHANGELOG.md +60 -0
  4. package/CLAUDE.md +159 -0
  5. package/README.md +373 -0
  6. package/US-007-IMPLEMENTATION.md +139 -0
  7. package/bin/nax.ts +930 -0
  8. package/biome.json +14 -0
  9. package/bun.lock +168 -0
  10. package/bunfig.toml +11 -0
  11. package/docs/20260216-fix-plan-context-review.md +56 -0
  12. package/docs/20260216-relentless-vs-ngent-comparison.md +208 -0
  13. package/docs/20260216-v02-plan.md +136 -0
  14. package/docs/20260216-v02-review.md +685 -0
  15. package/docs/20260217-dogfood-findings.md +56 -0
  16. package/docs/20260217-p2-plus-plan.md +117 -0
  17. package/docs/20260217-partial-fixes-plan.md +62 -0
  18. package/docs/20260217-plan-analyze-spec.md +117 -0
  19. package/docs/20260217-post-impl-review.md +1137 -0
  20. package/docs/20260217-quick-wins-plan.md +66 -0
  21. package/docs/20260217-split-runner-plan.md +75 -0
  22. package/docs/20260217-v03-impl-plan.md +80 -0
  23. package/docs/20260217-v03-post-impl-review.md +589 -0
  24. package/docs/20260217-v04-impl-plan.md +86 -0
  25. package/docs/20260217-v05-post-impl-review.md +850 -0
  26. package/docs/20260217-v06-post-impl-review.md +817 -0
  27. package/docs/20260218-adr003-port-plan.md +151 -0
  28. package/docs/20260218-review-adr003-verification.md +175 -0
  29. package/docs/20260219-fix-plan-bug16-19.md +79 -0
  30. package/docs/20260219-fix-plan-bug20-22.md +114 -0
  31. package/docs/20260219-plan-llm-routing.md +116 -0
  32. package/docs/20260219-review-bug20-22-fixes.md +135 -0
  33. package/docs/20260219-routing-baseline-keyword.md +63 -0
  34. package/docs/20260220-plan-structured-logging-p1.md +80 -0
  35. package/docs/20260220-plan-structured-logging-p2.md +37 -0
  36. package/docs/20260220-review-llm-routing.md +180 -0
  37. package/docs/20260220-review-post-fix-llm-routing.md +70 -0
  38. package/docs/20260221-fix-plan-relevantfiles-split.md +101 -0
  39. package/docs/20260221-fix-plan-routing-mode.md +125 -0
  40. package/docs/20260221-review-v0.9-implementation.md +379 -0
  41. package/docs/20260222-fix-plan-v091-routing-isolation.md +197 -0
  42. package/docs/20260223-fix-plan-prompt-audit.md +62 -0
  43. package/docs/20260224-nax-roadmap-phases.md +189 -0
  44. package/docs/20260225-phase2-llm-service-layer.md +401 -0
  45. package/docs/20260225-review-v0.10.1.md +187 -0
  46. package/docs/20260303-v010-implementation-plan.md +165 -0
  47. package/docs/CLAUDE.md.bak +191 -0
  48. package/docs/ROADMAP.md +165 -0
  49. package/docs/SPEC-rectification.md +0 -0
  50. package/docs/SPEC.md +324 -0
  51. package/docs/US-001-plugin-loading-verification.md +152 -0
  52. package/docs/architecture-analysis.md +1076 -0
  53. package/docs/bugs/BUG-21-escalation-null-attempts.md +48 -0
  54. package/docs/bugs-from-dogfood-run-c.md +243 -0
  55. package/docs/code-review-20260228.md +612 -0
  56. package/docs/code-review-v0.15.0.md +629 -0
  57. package/docs/hook-lifecycle-test-plan.md +149 -0
  58. package/docs/releases/v0.11.0-and-earlier.md +20 -0
  59. package/docs/releases/v0.12.0.md +15 -0
  60. package/docs/releases/v0.13.0.md +14 -0
  61. package/docs/releases/v0.14.0.md +20 -0
  62. package/docs/releases/v0.14.1.md +36 -0
  63. package/docs/releases/v0.14.2.md +51 -0
  64. package/docs/releases/v0.14.3.md +174 -0
  65. package/docs/releases/v0.14.4.md +94 -0
  66. package/docs/releases/v0.15.0.md +502 -0
  67. package/docs/releases/v0.15.1.md +170 -0
  68. package/docs/releases/v0.15.3.md +193 -0
  69. package/docs/specs/status-file-v0.10.1.md +812 -0
  70. package/docs/v0.10-global-config.md +206 -0
  71. package/docs/v0.10-plugin-system.md +415 -0
  72. package/docs/v0.10-prompt-optimizer.md +234 -0
  73. package/docs/v0.3-spec.md +244 -0
  74. package/docs/v0.4-spec.md +140 -0
  75. package/docs/v0.5-spec.md +237 -0
  76. package/docs/v0.6-spec.md +371 -0
  77. package/docs/v0.7-spec.md +177 -0
  78. package/docs/v0.8-llm-routing.md +206 -0
  79. package/docs/v0.8-structured-logging.md +132 -0
  80. package/docs/v0.9.3-prompt-audit.md +112 -0
  81. package/examples/plugins/console-reporter/index.test.ts +207 -0
  82. package/examples/plugins/console-reporter/index.ts +110 -0
  83. package/nax/config.json +147 -0
  84. package/nax/features/bugfix-v0171/prd.json +52 -0
  85. package/nax/features/config-management/prd.json +108 -0
  86. package/nax/features/config-management/progress.txt +5 -0
  87. package/nax/features/diagnose/acceptance.test.ts +412 -0
  88. package/nax/features/diagnose/prd.json +41 -0
  89. package/nax/features/orchestration-fixes/prd.json +89 -0
  90. package/nax/features/orchestration-fixes/progress.txt +1 -0
  91. package/nax/features/plugin-integration/US-007-VERIFICATION.md +259 -0
  92. package/nax/features/plugin-integration/prd.json +208 -0
  93. package/nax/features/plugin-integration/progress.txt +5 -0
  94. package/nax/features/precheck/prd.json +205 -0
  95. package/nax/features/precheck/progress.txt +15 -0
  96. package/nax/features/structured-logging/prd.json +199 -0
  97. package/nax/features/unlock/prd.json +36 -0
  98. package/package.json +47 -0
  99. package/src/acceptance/fix-generator.ts +348 -0
  100. package/src/acceptance/generator.ts +282 -0
  101. package/src/acceptance/index.ts +30 -0
  102. package/src/acceptance/types.ts +79 -0
  103. package/src/agents/claude-decompose.ts +169 -0
  104. package/src/agents/claude-plan.ts +139 -0
  105. package/src/agents/claude.ts +324 -0
  106. package/src/agents/cost.ts +268 -0
  107. package/src/agents/index.ts +13 -0
  108. package/src/agents/registry.ts +48 -0
  109. package/src/agents/types-extended.ts +133 -0
  110. package/src/agents/types.ts +113 -0
  111. package/src/agents/validation.ts +69 -0
  112. package/src/analyze/classifier.ts +305 -0
  113. package/src/analyze/index.ts +16 -0
  114. package/src/analyze/scanner.ts +175 -0
  115. package/src/analyze/types.ts +51 -0
  116. package/src/cli/accept.ts +108 -0
  117. package/src/cli/analyze-parser.ts +284 -0
  118. package/src/cli/analyze.ts +207 -0
  119. package/src/cli/config.ts +561 -0
  120. package/src/cli/constitution.ts +109 -0
  121. package/src/cli/diagnose-analysis.ts +159 -0
  122. package/src/cli/diagnose-formatter.ts +87 -0
  123. package/src/cli/diagnose.ts +203 -0
  124. package/src/cli/generate.ts +127 -0
  125. package/src/cli/index.ts +37 -0
  126. package/src/cli/init.ts +188 -0
  127. package/src/cli/interact.ts +295 -0
  128. package/src/cli/plan.ts +198 -0
  129. package/src/cli/plugins.ts +111 -0
  130. package/src/cli/prompts.ts +295 -0
  131. package/src/cli/runs.ts +174 -0
  132. package/src/cli/status-cost.ts +151 -0
  133. package/src/cli/status-features.ts +338 -0
  134. package/src/cli/status.ts +13 -0
  135. package/src/commands/common.ts +171 -0
  136. package/src/commands/diagnose.ts +17 -0
  137. package/src/commands/index.ts +8 -0
  138. package/src/commands/logs.ts +384 -0
  139. package/src/commands/precheck.ts +86 -0
  140. package/src/commands/unlock.ts +96 -0
  141. package/src/config/defaults.ts +160 -0
  142. package/src/config/index.ts +22 -0
  143. package/src/config/loader.ts +121 -0
  144. package/src/config/merger.ts +147 -0
  145. package/src/config/path-security.ts +121 -0
  146. package/src/config/paths.ts +27 -0
  147. package/src/config/schema.ts +56 -0
  148. package/src/config/schemas.ts +286 -0
  149. package/src/config/types.ts +423 -0
  150. package/src/config/validate.ts +103 -0
  151. package/src/constitution/generator.ts +191 -0
  152. package/src/constitution/generators/aider.ts +41 -0
  153. package/src/constitution/generators/claude.ts +35 -0
  154. package/src/constitution/generators/cursor.ts +36 -0
  155. package/src/constitution/generators/opencode.ts +38 -0
  156. package/src/constitution/generators/types.ts +33 -0
  157. package/src/constitution/generators/windsurf.ts +36 -0
  158. package/src/constitution/index.ts +10 -0
  159. package/src/constitution/loader.ts +133 -0
  160. package/src/constitution/types.ts +31 -0
  161. package/src/context/auto-detect.ts +227 -0
  162. package/src/context/builder.ts +246 -0
  163. package/src/context/elements.ts +83 -0
  164. package/src/context/formatter.ts +107 -0
  165. package/src/context/generator.ts +129 -0
  166. package/src/context/generators/aider.ts +34 -0
  167. package/src/context/generators/claude.ts +28 -0
  168. package/src/context/generators/cursor.ts +28 -0
  169. package/src/context/generators/opencode.ts +30 -0
  170. package/src/context/generators/windsurf.ts +28 -0
  171. package/src/context/greenfield.ts +114 -0
  172. package/src/context/index.ts +33 -0
  173. package/src/context/injector.ts +279 -0
  174. package/src/context/test-scanner.ts +370 -0
  175. package/src/context/types.ts +98 -0
  176. package/src/errors.ts +67 -0
  177. package/src/execution/batching.ts +157 -0
  178. package/src/execution/crash-recovery.ts +373 -0
  179. package/src/execution/escalation/escalation.ts +44 -0
  180. package/src/execution/escalation/index.ts +13 -0
  181. package/src/execution/escalation/tier-escalation.ts +295 -0
  182. package/src/execution/escalation/tier-outcome.ts +158 -0
  183. package/src/execution/helpers.ts +38 -0
  184. package/src/execution/index.ts +45 -0
  185. package/src/execution/lifecycle/acceptance-loop.ts +272 -0
  186. package/src/execution/lifecycle/headless-formatter.ts +85 -0
  187. package/src/execution/lifecycle/index.ts +12 -0
  188. package/src/execution/lifecycle/parallel-lifecycle.ts +101 -0
  189. package/src/execution/lifecycle/precheck-runner.ts +140 -0
  190. package/src/execution/lifecycle/run-cleanup.ts +81 -0
  191. package/src/execution/lifecycle/run-completion.ts +129 -0
  192. package/src/execution/lifecycle/run-initialization.ts +141 -0
  193. package/src/execution/lifecycle/run-lifecycle.ts +312 -0
  194. package/src/execution/lifecycle/run-setup.ts +204 -0
  195. package/src/execution/lifecycle/story-hooks.ts +38 -0
  196. package/src/execution/lifecycle/story-size-prompts.ts +123 -0
  197. package/src/execution/lock.ts +115 -0
  198. package/src/execution/parallel-executor.ts +216 -0
  199. package/src/execution/parallel.ts +400 -0
  200. package/src/execution/pid-registry.ts +280 -0
  201. package/src/execution/pipeline-result-handler.ts +388 -0
  202. package/src/execution/post-verify-rectification.ts +188 -0
  203. package/src/execution/post-verify.ts +274 -0
  204. package/src/execution/progress.ts +25 -0
  205. package/src/execution/prompts.ts +127 -0
  206. package/src/execution/queue-handler.ts +109 -0
  207. package/src/execution/rectification.ts +13 -0
  208. package/src/execution/runner.ts +377 -0
  209. package/src/execution/sequential-executor.ts +388 -0
  210. package/src/execution/status-file.ts +264 -0
  211. package/src/execution/status-writer.ts +139 -0
  212. package/src/execution/story-context.ts +229 -0
  213. package/src/execution/test-output-parser.ts +14 -0
  214. package/src/execution/verification.ts +72 -0
  215. package/src/hooks/index.ts +2 -0
  216. package/src/hooks/runner.ts +286 -0
  217. package/src/hooks/types.ts +67 -0
  218. package/src/interaction/chain.ts +154 -0
  219. package/src/interaction/index.ts +60 -0
  220. package/src/interaction/init.ts +83 -0
  221. package/src/interaction/plugins/auto.ts +217 -0
  222. package/src/interaction/plugins/cli.ts +300 -0
  223. package/src/interaction/plugins/telegram.ts +384 -0
  224. package/src/interaction/plugins/webhook.ts +258 -0
  225. package/src/interaction/state.ts +171 -0
  226. package/src/interaction/triggers.ts +229 -0
  227. package/src/interaction/types.ts +163 -0
  228. package/src/logger/formatters.ts +84 -0
  229. package/src/logger/index.ts +16 -0
  230. package/src/logger/logger.ts +298 -0
  231. package/src/logger/types.ts +48 -0
  232. package/src/logging/formatter.ts +355 -0
  233. package/src/logging/index.ts +22 -0
  234. package/src/logging/types.ts +93 -0
  235. package/src/metrics/aggregator.ts +190 -0
  236. package/src/metrics/index.ts +14 -0
  237. package/src/metrics/tracker.ts +200 -0
  238. package/src/metrics/types.ts +109 -0
  239. package/src/optimizer/index.ts +62 -0
  240. package/src/optimizer/noop.optimizer.ts +24 -0
  241. package/src/optimizer/rule-based.optimizer.ts +248 -0
  242. package/src/optimizer/types.ts +53 -0
  243. package/src/pipeline/events.ts +130 -0
  244. package/src/pipeline/index.ts +19 -0
  245. package/src/pipeline/runner.ts +161 -0
  246. package/src/pipeline/stages/acceptance.ts +197 -0
  247. package/src/pipeline/stages/completion.ts +99 -0
  248. package/src/pipeline/stages/constitution.ts +63 -0
  249. package/src/pipeline/stages/context.ts +117 -0
  250. package/src/pipeline/stages/execution.ts +194 -0
  251. package/src/pipeline/stages/index.ts +62 -0
  252. package/src/pipeline/stages/optimizer.ts +74 -0
  253. package/src/pipeline/stages/prompt.ts +57 -0
  254. package/src/pipeline/stages/queue-check.ts +103 -0
  255. package/src/pipeline/stages/review.ts +181 -0
  256. package/src/pipeline/stages/routing.ts +81 -0
  257. package/src/pipeline/stages/verify.ts +100 -0
  258. package/src/pipeline/types.ts +167 -0
  259. package/src/plugins/index.ts +31 -0
  260. package/src/plugins/loader.ts +287 -0
  261. package/src/plugins/registry.ts +168 -0
  262. package/src/plugins/types.ts +327 -0
  263. package/src/plugins/validator.ts +352 -0
  264. package/src/prd/index.ts +172 -0
  265. package/src/prd/types.ts +202 -0
  266. package/src/precheck/checks-blockers.ts +391 -0
  267. package/src/precheck/checks-warnings.ts +142 -0
  268. package/src/precheck/checks.ts +30 -0
  269. package/src/precheck/index.ts +247 -0
  270. package/src/precheck/story-size-gate.ts +144 -0
  271. package/src/precheck/types.ts +31 -0
  272. package/src/queue/index.ts +2 -0
  273. package/src/queue/manager.ts +254 -0
  274. package/src/queue/types.ts +54 -0
  275. package/src/review/index.ts +8 -0
  276. package/src/review/runner.ts +172 -0
  277. package/src/review/types.ts +66 -0
  278. package/src/routing/builder.ts +81 -0
  279. package/src/routing/chain.ts +74 -0
  280. package/src/routing/index.ts +16 -0
  281. package/src/routing/loader.ts +58 -0
  282. package/src/routing/router.ts +303 -0
  283. package/src/routing/strategies/adaptive.ts +215 -0
  284. package/src/routing/strategies/index.ts +8 -0
  285. package/src/routing/strategies/keyword.ts +163 -0
  286. package/src/routing/strategies/llm-prompts.ts +209 -0
  287. package/src/routing/strategies/llm.ts +235 -0
  288. package/src/routing/strategies/manual.ts +50 -0
  289. package/src/routing/strategy.ts +99 -0
  290. package/src/tdd/cleanup.ts +111 -0
  291. package/src/tdd/index.ts +23 -0
  292. package/src/tdd/isolation.ts +123 -0
  293. package/src/tdd/orchestrator.ts +383 -0
  294. package/src/tdd/prompts.ts +270 -0
  295. package/src/tdd/rectification-gate.ts +183 -0
  296. package/src/tdd/session-runner.ts +179 -0
  297. package/src/tdd/types.ts +81 -0
  298. package/src/tdd/verdict.ts +271 -0
  299. package/src/tui/App.tsx +265 -0
  300. package/src/tui/components/AgentPanel.tsx +75 -0
  301. package/src/tui/components/CostOverlay.tsx +118 -0
  302. package/src/tui/components/HelpOverlay.tsx +107 -0
  303. package/src/tui/components/StatusBar.tsx +63 -0
  304. package/src/tui/components/StoriesPanel.tsx +177 -0
  305. package/src/tui/hooks/useKeyboard.ts +142 -0
  306. package/src/tui/hooks/useLayout.ts +137 -0
  307. package/src/tui/hooks/usePipelineEvents.ts +183 -0
  308. package/src/tui/hooks/usePty.ts +194 -0
  309. package/src/tui/index.tsx +38 -0
  310. package/src/tui/types.ts +76 -0
  311. package/src/utils/git.ts +83 -0
  312. package/src/utils/queue-writer.ts +54 -0
  313. package/src/verification/executor.ts +235 -0
  314. package/src/verification/gate.ts +207 -0
  315. package/src/verification/index.ts +12 -0
  316. package/src/verification/parser.ts +230 -0
  317. package/src/verification/rectification.ts +108 -0
  318. package/src/verification/types.ts +113 -0
  319. package/src/worktree/dispatcher.ts +65 -0
  320. package/src/worktree/index.ts +2 -0
  321. package/src/worktree/manager.ts +187 -0
  322. package/src/worktree/merge.ts +301 -0
  323. package/src/worktree/types.ts +4 -0
  324. package/test/TEST_COVERAGE_US001.md +217 -0
  325. package/test/TEST_COVERAGE_US003.md +84 -0
  326. package/test/TEST_COVERAGE_US005.md +86 -0
  327. package/test/US-002-orchestrator.test.ts +246 -0
  328. package/test/acceptance/cm-003-default-view.test.ts +194 -0
  329. package/test/execution/pid-registry.test.ts +240 -0
  330. package/test/execution/post-verify.test.ts +224 -0
  331. package/test/helpers/timeout.ts +42 -0
  332. package/test/integration/US-002-TEST-SUMMARY.md +107 -0
  333. package/test/integration/US-003-TEST-SUMMARY.md +149 -0
  334. package/test/integration/US-004-TEST-SUMMARY.md +106 -0
  335. package/test/integration/US-005-TEST-SUMMARY.md +138 -0
  336. package/test/integration/US-007-TEST-SUMMARY.md +100 -0
  337. package/test/integration/agent-validation.test.ts +439 -0
  338. package/test/integration/analyze-integration.test.ts +261 -0
  339. package/test/integration/analyze-scanner.test.ts +131 -0
  340. package/test/integration/cli-config-default-edge-cases.test.ts +222 -0
  341. package/test/integration/cli-config-default-view.test.ts +229 -0
  342. package/test/integration/cli-config-diff.test.ts +460 -0
  343. package/test/integration/cli-config.test.ts +736 -0
  344. package/test/integration/cli-diagnose.test.ts +592 -0
  345. package/test/integration/cli-logs.test.ts +314 -0
  346. package/test/integration/cli-plugins.test.ts +678 -0
  347. package/test/integration/cli-precheck.test.ts +371 -0
  348. package/test/integration/cli-run-headless.test.ts +173 -0
  349. package/test/integration/cli.test.ts +75 -0
  350. package/test/integration/config/merger.test.ts +465 -0
  351. package/test/integration/config/paths.test.ts +51 -0
  352. package/test/integration/config-loader.test.ts +265 -0
  353. package/test/integration/config.test.ts +444 -0
  354. package/test/integration/context-integration.test.ts +702 -0
  355. package/test/integration/context-provider-injection.test.ts +506 -0
  356. package/test/integration/context-verification-integration.test.ts +295 -0
  357. package/test/integration/e2e.test.ts +896 -0
  358. package/test/integration/execution.test.ts +625 -0
  359. package/test/integration/helpers.test.ts +295 -0
  360. package/test/integration/hooks.test.ts +361 -0
  361. package/test/integration/interaction-chain-pipeline.test.ts +464 -0
  362. package/test/integration/isolation.test.ts +143 -0
  363. package/test/integration/logger.test.ts +461 -0
  364. package/test/integration/parallel.test.ts +250 -0
  365. package/test/integration/path-security.test.ts +173 -0
  366. package/test/integration/pipeline-acceptance.test.ts +302 -0
  367. package/test/integration/pipeline-events.test.ts +475 -0
  368. package/test/integration/pipeline.test.ts +658 -0
  369. package/test/integration/plan.test.ts +157 -0
  370. package/test/integration/plugin-routing.test.ts +921 -0
  371. package/test/integration/plugins/config-integration.test.ts +172 -0
  372. package/test/integration/plugins/config-resolution.test.ts +522 -0
  373. package/test/integration/plugins/loader.test.ts +641 -0
  374. package/test/integration/plugins/registry.test.ts +746 -0
  375. package/test/integration/plugins/validator.test.ts +563 -0
  376. package/test/integration/prd-pause.test.ts +205 -0
  377. package/test/integration/prd-resolvers.test.ts +185 -0
  378. package/test/integration/precheck-integration.test.ts +468 -0
  379. package/test/integration/precheck.test.ts +805 -0
  380. package/test/integration/progress.test.ts +34 -0
  381. package/test/integration/rectification-flow.test.ts +512 -0
  382. package/test/integration/reporter-lifecycle.test.ts +860 -0
  383. package/test/integration/review-config-commands.test.ts +319 -0
  384. package/test/integration/review-config-schema.test.ts +116 -0
  385. package/test/integration/review-plugin-integration.test.ts +722 -0
  386. package/test/integration/review.test.ts +149 -0
  387. package/test/integration/routing-stage-bug-021.test.ts +274 -0
  388. package/test/integration/routing-stage-greenfield.test.ts +286 -0
  389. package/test/integration/runner-config-plugins.test.ts +461 -0
  390. package/test/integration/runner-fixes.test.ts +399 -0
  391. package/test/integration/runner-plugin-integration.test.ts +543 -0
  392. package/test/integration/runner.test.ts +1679 -0
  393. package/test/integration/s5-greenfield-fallback.test.ts +297 -0
  394. package/test/integration/status-file-integration.test.ts +325 -0
  395. package/test/integration/status-file.test.ts +379 -0
  396. package/test/integration/status-writer.test.ts +345 -0
  397. package/test/integration/story-id-in-events.test.ts +273 -0
  398. package/test/integration/tdd-cleanup.test.ts +246 -0
  399. package/test/integration/tdd-orchestrator.test.ts +1762 -0
  400. package/test/integration/test-scanner.test.ts +403 -0
  401. package/test/integration/verification-asset-check.test.ts +142 -0
  402. package/test/integration/verify-stage.test.ts +275 -0
  403. package/test/integration/worktree/manager.test.ts +218 -0
  404. package/test/integration/worktree/merge.test.ts +341 -0
  405. package/test/manual/logging-formatter-demo.ts +158 -0
  406. package/test/ui/tui-agent-panel.test.tsx +99 -0
  407. package/test/ui/tui-controls.test.ts +334 -0
  408. package/test/ui/tui-cost-and-pty.test.ts +189 -0
  409. package/test/ui/tui-layout.test.ts +378 -0
  410. package/test/ui/tui-pty-integration.test.tsx +159 -0
  411. package/test/ui/tui-stories.test.ts +332 -0
  412. package/test/unit/acceptance.test.ts +186 -0
  413. package/test/unit/agent-stderr-capture.test.ts +146 -0
  414. package/test/unit/analyze-classifier.test.ts +215 -0
  415. package/test/unit/analyze.test.ts +224 -0
  416. package/test/unit/auto-detect.test.ts +249 -0
  417. package/test/unit/cli-status.test.ts +417 -0
  418. package/test/unit/commands/common.test.ts +320 -0
  419. package/test/unit/commands/logs.test.ts +416 -0
  420. package/test/unit/commands/unlock.test.ts +319 -0
  421. package/test/unit/constitution-generators.test.ts +160 -0
  422. package/test/unit/constitution.test.ts +209 -0
  423. package/test/unit/context.test.ts +1722 -0
  424. package/test/unit/cost.test.ts +231 -0
  425. package/test/unit/crash-recovery.test.ts +308 -0
  426. package/test/unit/escalation.test.ts +126 -0
  427. package/test/unit/execution-logging-stderr.test.ts +156 -0
  428. package/test/unit/execution-stage.test.ts +122 -0
  429. package/test/unit/fix-generator.test.ts +275 -0
  430. package/test/unit/formatters.test.ts +469 -0
  431. package/test/unit/greenfield.test.ts +179 -0
  432. package/test/unit/helpers.test.ts +317 -0
  433. package/test/unit/interaction/human-review-trigger.test.ts +164 -0
  434. package/test/unit/interaction-network-failures.test.ts +389 -0
  435. package/test/unit/interaction-plugins.test.ts +164 -0
  436. package/test/unit/isolation.test.ts +134 -0
  437. package/test/unit/logging/formatter.test.ts +455 -0
  438. package/test/unit/merge.test.ts +268 -0
  439. package/test/unit/metrics.test.ts +276 -0
  440. package/test/unit/optimizer/noop.optimizer.test.ts +125 -0
  441. package/test/unit/optimizer/rule-based.optimizer.test.ts +358 -0
  442. package/test/unit/prd-auto-default.test.ts +290 -0
  443. package/test/unit/prd-failure-category.test.ts +176 -0
  444. package/test/unit/prd-get-next-story.test.ts +186 -0
  445. package/test/unit/precheck-checks.test.ts +840 -0
  446. package/test/unit/precheck-story-size-gate.test.ts +287 -0
  447. package/test/unit/precheck-types.test.ts +142 -0
  448. package/test/unit/prompts.test.ts +475 -0
  449. package/test/unit/queue.test.ts +237 -0
  450. package/test/unit/rectification.test.ts +284 -0
  451. package/test/unit/registry.test.ts +287 -0
  452. package/test/unit/routing.test.ts +937 -0
  453. package/test/unit/run-lifecycle.test.ts +140 -0
  454. package/test/unit/storyid-events.test.ts +224 -0
  455. package/test/unit/tdd-verdict.test.ts +492 -0
  456. package/test/unit/test-output-parser.test.ts +377 -0
  457. package/test/unit/verdict.test.ts +324 -0
  458. package/test/unit/worktree-manager.test.ts +158 -0
  459. package/tsconfig.json +27 -0
@@ -0,0 +1,135 @@
1
+ # Post-Fix Code Review: BUG-20, BUG-21, BUG-22
2
+
3
+ **Date:** 2026-02-19
4
+ **Reviewer:** Subrina (AI)
5
+ **Scope:** `fix/bug-20-22-tdd-orchestrator` branch (3 commits, 7 files)
6
+ **Depth:** Standard (post-fix verification)
7
+ **Files:** 7 (lib: ~170 LOC added, test: ~470 LOC added)
8
+ **Baseline:** 21 new tests, 67 assertions — all passing
9
+
10
+ ---
11
+
12
+ ## Overall Grade: B+ (82/100)
13
+
14
+ Solid bug fixes with good test coverage and clean separation. The `cleanup.ts` module is well-structured with proper JSDoc and graceful error handling. The orchestrator changes address the root causes correctly. However, there are a few issues around race conditions, missing type narrowing, and a potential security concern in the BUG-22 fix that should be addressed before merge.
15
+
16
+ ---
17
+
18
+ ## Scoring
19
+
20
+ | Dimension | Score | Notes |
21
+ |:---|:---|:---|
22
+ | Security | 16/20 | `executeWithTimeout` called with config-derived command — acceptable but no sanitization |
23
+ | Reliability | 15/20 | SIGTERM→SIGKILL race window; no PGID validation; `reviewReason` type narrowing |
24
+ | API Design | 18/20 | Clean module boundary; `pid` optional on `AgentResult` is correct |
25
+ | Code Quality | 17/20 | Good JSDoc; test mocking pattern is verbose but thorough |
26
+ | Best Practices | 16/20 | Bun.sleep mock in tests is fragile; `@ts-ignore` used for mocking |
27
+
28
+ ---
29
+
30
+ ## Findings
31
+
32
+ ### 🟡 MEDIUM
33
+
34
+ #### BUG-1: Race condition in SIGTERM→SIGKILL cleanup
35
+ **Severity:** MEDIUM | **Category:** Bug
36
+ ```typescript
37
+ // src/tdd/cleanup.ts:73-76
38
+ process.kill(-pgid, "SIGTERM");
39
+ await Bun.sleep(3000); // ← Fixed 3s delay
40
+ process.kill(-pgid, "SIGKILL");
41
+ ```
42
+ **Risk:** If the process group exits cleanly in <3s and the PGID is reassigned to a new process group (unlikely but possible on busy systems), SIGKILL hits the wrong group. Also, 3s is hardcoded with no configurability.
43
+ **Fix:** Check if processes still exist before SIGKILL:
44
+ ```typescript
45
+ const stillAlive = await getPgid(pid);
46
+ if (stillAlive === pgid) {
47
+ process.kill(-pgid, "SIGKILL");
48
+ }
49
+ ```
50
+
51
+ #### BUG-2: BUG-22 post-verification runs `bun test` without workdir context
52
+ **Severity:** MEDIUM | **Category:** Bug
53
+ ```typescript
54
+ // src/tdd/orchestrator.ts:430-432
55
+ const testCmd = config.quality?.commands?.test ?? "bun test";
56
+ const timeoutSeconds = config.quality?.verificationTimeoutSeconds ?? 120;
57
+ const postVerify = await executeWithTimeout(testCmd, timeoutSeconds);
58
+ ```
59
+ **Risk:** `executeWithTimeout` may not inherit the correct working directory. If the orchestrator's cwd differs from the project workdir, post-verification runs tests against the wrong codebase or fails with "no tests found."
60
+ **Fix:** Pass `workdir` to `executeWithTimeout`:
61
+ ```typescript
62
+ const postVerify = await executeWithTimeout(testCmd, timeoutSeconds, { cwd: workdir });
63
+ ```
64
+ *(Verify `executeWithTimeout` accepts cwd option — if not, needs a small change.)*
65
+
66
+ #### ENH-1: `reviewReason` type could be `undefined | string` but is set via `let`
67
+ **Severity:** MEDIUM | **Category:** Type Safety
68
+ ```typescript
69
+ // src/tdd/orchestrator.ts:441
70
+ reviewReason = undefined; // ← assignment to undefined in success path
71
+ ```
72
+ **Risk:** The `reviewReason` variable is declared with `let` higher up. The `undefined` assignment works but the type should be explicit to avoid accidental string checks downstream.
73
+ **Fix:** Declare as `let reviewReason: string | undefined;` if not already.
74
+
75
+ ### 🟢 LOW
76
+
77
+ #### STYLE-1: `@ts-ignore` comments in tests instead of proper typing
78
+ **Severity:** LOW | **Category:** Style
79
+ ```typescript
80
+ // test/tdd-cleanup.test.ts:24
81
+ // @ts-ignore — mocking global
82
+ Bun.spawn = mock((cmd: string[], spawnOpts?: any) => {
83
+ ```
84
+ **Risk:** If `Bun.spawn` signature changes, tests won't catch the type mismatch at compile time.
85
+ **Fix:** Consider a wrapper function pattern:
86
+ ```typescript
87
+ const mockSpawn = mock((...args: Parameters<typeof Bun.spawn>) => { ... });
88
+ Object.defineProperty(Bun, 'spawn', { value: mockSpawn, writable: true });
89
+ ```
90
+
91
+ #### STYLE-2: Verbose mock setup repeated across tests
92
+ **Severity:** LOW | **Category:** Style
93
+ The `Bun.spawn` mock setup for git commands is duplicated across `tdd-cleanup.test.ts` and `tdd-orchestrator.test.ts` with slightly different patterns.
94
+ **Fix:** Extract a `createGitMock()` helper into a shared test utility (e.g., `test/helpers/git-mock.ts`).
95
+
96
+ #### ENH-2: `cleanupProcessTree` hardcoded 3s grace period
97
+ **Severity:** LOW | **Category:** Enhancement
98
+ ```typescript
99
+ await Bun.sleep(3000);
100
+ ```
101
+ **Fix:** Accept optional `gracePeriodMs` parameter with 3000 default:
102
+ ```typescript
103
+ export async function cleanupProcessTree(pid: number, gracePeriodMs = 3000): Promise<void> {
104
+ ```
105
+
106
+ #### PERF-1: BUG-20 test file detection uses regex on every file per session
107
+ **Severity:** LOW | **Category:** Performance
108
+ ```typescript
109
+ const testFilePatterns = /\.(test|spec)\.(ts|js|tsx|jsx)$/;
110
+ const testFilesCreated = session1.filesChanged.filter((f) => testFilePatterns.test(f));
111
+ ```
112
+ **Risk:** Negligible perf impact (typically <50 files), but the regex is recompiled each call.
113
+ **Fix:** Move `testFilePatterns` to module scope as a constant. Minor.
114
+
115
+ ---
116
+
117
+ ## Priority Fix Order
118
+
119
+ | Priority | ID | Effort | Description |
120
+ |:---|:---|:---|:---|
121
+ | P1 | BUG-2 | S | Pass workdir to post-TDD verification `executeWithTimeout` |
122
+ | P2 | BUG-1 | S | Verify process still alive before SIGKILL |
123
+ | P3 | ENH-1 | S | Explicit type for `reviewReason` |
124
+ | P3 | ENH-2 | S | Configurable grace period in `cleanupProcessTree` |
125
+ | P4 | STYLE-1 | M | Replace `@ts-ignore` with proper mock typing |
126
+ | P4 | STYLE-2 | M | Extract shared git mock helper |
127
+ | P5 | PERF-1 | S | Move test file regex to module scope |
128
+
129
+ ---
130
+
131
+ ## Verdict
132
+
133
+ **Ship with P1 fix.** BUG-2 (missing workdir in post-verification) is the only functional risk. The SIGKILL race (BUG-1) is theoretical on macOS but worth a quick fix. Everything else is polish.
134
+
135
+ The test coverage is thorough — 21 tests covering happy path, failure modes, isolation violations, dry-run, and all 3 bug-specific scenarios. The `cleanup.ts` module is clean, well-documented, and properly handles edge cases (dead processes, ESRCH, unexpected errors).
@@ -0,0 +1,63 @@
1
+ # Keyword Routing Baseline — Config-Loader Dogfood
2
+
3
+ > Recorded from Run D + Run D2 (2026-02-19) for comparison with LLM routing.
4
+
5
+ ## Run D (US-001 to US-007)
6
+
7
+ | Story | Title | Classified | Model | Test Strategy | Routing Reason | Cost | Status |
8
+ |:---|:---|:---|:---|:---|:---|:---|:---|
9
+ | US-001 | Define core types and error handling | simple | balanced | test-after | simple task (medium) | ~$0.08 | ✅ |
10
+ | US-002 | Implement environment variable interpolation | medium | balanced | test-after | simple task (medium) | ~$0.08 | ✅ |
11
+ | US-003 | Implement deep merge utility | medium | balanced | test-after | simple task (medium) | ~$0.08 | ✅ |
12
+ | US-004 | Implement config file discovery | simple | balanced | test-after | simple task (medium) | ~$0.08 | ✅ |
13
+ | US-005 | Implement synchronous config loader | medium | balanced | test-after | simple task (medium) | ~$0.10 | ✅ |
14
+ | US-006 | Implement async config loader | medium | balanced | test-after | simple task (medium) | ~$0.10 | ✅ |
15
+ | US-007 | Implement config file watcher | complex | powerful | three-session-tdd | complexity:expert | — | ❌ TDD failure (BUG-20) |
16
+
17
+ **Run D total: $0.65, 6/9 passed, 174 tests, 9.8 min**
18
+
19
+ ## Run D2 (US-007 to US-009, resumed)
20
+
21
+ | Story | Title | Classified | Model | Test Strategy | Routing Reason | Cost | Status |
22
+ |:---|:---|:---|:---|:---|:---|:---|:---|
23
+ | US-007 | Implement config file watcher | complex | powerful | three-session-tdd | complexity:expert | $1.74 | ✅ |
24
+ | US-008 (attempt 1) | Export public API and create barrel exports | simple | powerful | three-session-tdd | public-api, complexity:complex | $1.26 | ✅ but ASSET_CHECK failed |
25
+ | US-008 (attempt 2) | Export public API and create barrel exports | simple | powerful | three-session-tdd | public-api, complexity:complex | $1.21 | ✅ |
26
+ | US-009 | Comprehensive integration tests and documentation | medium | powerful | three-session-tdd | complexity:complex | $4.95 | ⏸ Human review (verifier issues) |
27
+
28
+ **Run D2 total: $4.20 (completed) + $4.95 (US-009 paused) = ~$9.15, 41.4 min**
29
+
30
+ ## Misroute Analysis
31
+
32
+ | Story | Keyword Route | Ideal Route | Wasted Cost |
33
+ |:---|:---|:---|:---|
34
+ | US-008 | powerful + three-session-tdd ($2.47 over 2 attempts) | fast + test-after (~$0.10) | **~$2.37** |
35
+ | US-009 | powerful + three-session-tdd ($4.95) | balanced + test-after (~$0.20) | **~$4.75** |
36
+
37
+ **Total misroute waste: ~$7.12** (77% of Run D2 spend)
38
+
39
+ ### Why Keyword Routing Failed
40
+
41
+ **US-008:** Title "Export **public API** and create barrel exports" matches `PUBLIC_API_KEYWORDS` → forces TDD. But this is just creating `index.ts` barrel files — no logic, no contracts, no breaking changes. A 2-minute task got 3-session TDD with Opus.
42
+
43
+ **US-009:** "Comprehensive **integration tests** and documentation" — classified as medium by AC count, but routing reason says `complexity:complex`. The word "comprehensive" + AC count likely pushed it. Also got TDD despite the story literally being "write tests" — TDD for writing tests is circular.
44
+
45
+ ### Expected LLM Routing (to validate later)
46
+
47
+ | Story | Expected LLM Route | Expected Cost |
48
+ |:---|:---|:---|
49
+ | US-001 | fast / test-after | ~$0.05 |
50
+ | US-002 | fast / test-after | ~$0.05 |
51
+ | US-003 | fast / test-after | ~$0.05 |
52
+ | US-004 | fast / test-after | ~$0.05 |
53
+ | US-005 | balanced / test-after | ~$0.10 |
54
+ | US-006 | balanced / test-after | ~$0.10 |
55
+ | US-007 | powerful / three-session-tdd | ~$1.50 |
56
+ | US-008 | fast / test-after | ~$0.05 |
57
+ | US-009 | balanced / test-after | ~$0.15 |
58
+
59
+ **Expected total with LLM routing: ~$2.10** vs actual $9.80 (Run D + D2)
60
+
61
+ ---
62
+
63
+ *Recorded 2026-02-19 for A/B comparison with v0.8 LLM routing.*
@@ -0,0 +1,80 @@
1
+ # Fix Plan: nax v0.8 Structured Logging — Phase 1
2
+ **Date:** 2026-02-20
3
+ **Branch:** `feat/v0.8-structured-logging`
4
+
5
+ ## Scope
6
+ Phase 1: Logger core, CLI flags, JSONL file output, debug mode.
7
+ Covers AC-1, AC-2, AC-3, AC-4, AC-5, AC-8.
8
+ Does NOT touch existing console.log calls (Phase 2).
9
+
10
+ ## Phase 1A: Logger Core
11
+ **Commit:** `feat(logger): implement structured Logger with level gating and JSONL output`
12
+
13
+ ### File: `src/logger/index.ts` (NEW)
14
+ Export barrel.
15
+
16
+ ### File: `src/logger/logger.ts` (NEW)
17
+ - `Logger` class with `error`, `warn`, `info`, `debug` methods
18
+ - Each method signature: `(stage: string, message: string, data?: Record<string, unknown>)`
19
+ - `withStory(storyId: string)` returns a `StoryLogger` with storyId auto-injected
20
+ - Constructor: `{ level: LogLevel, filePath?: string, useChalk?: boolean }`
21
+ - Console output: chalk-formatted, filtered by level
22
+ - File output: JSON Lines, all levels written regardless of console level
23
+ - Singleton pattern: `getLogger()` / `initLogger(opts)`
24
+
25
+ ### File: `src/logger/types.ts` (NEW)
26
+ - `LogLevel` type: `"error" | "warn" | "info" | "debug"`
27
+ - `LogEntry` interface: `{ timestamp, level, stage, storyId?, message, data? }`
28
+ - `LoggerOptions` interface
29
+
30
+ ### File: `src/logger/formatters.ts` (NEW)
31
+ - `formatConsole(entry: LogEntry): string` — chalk-formatted human-readable
32
+ - `formatJsonl(entry: LogEntry): string` — JSON.stringify one-liner
33
+
34
+ ## Phase 1B: CLI Integration
35
+ **Commit:** `feat(cli): add --verbose, --quiet, --silent flags and run directory`
36
+
37
+ ### File: `bin/nax.ts`
38
+ - Add `--verbose` flag → sets log level to `debug`
39
+ - Add `--quiet` flag → sets log level to `warn`
40
+ - Add `--silent` flag → sets log level to `error`
41
+ - Add `NAX_LOG_LEVEL` env var support (overrides flags)
42
+ - Create run directory: `nax/features/<name>/runs/`
43
+ - Generate run ID: ISO timestamp `YYYY-MM-DDTHH-mm-ssZ`
44
+ - Pass `filePath` to logger init: `nax/features/<name>/runs/<run-id>.jsonl`
45
+ - After run, create/update `latest.jsonl` symlink
46
+
47
+ ### File: `src/config/schema.ts`
48
+ - Add `logging` section to NaxConfig: `{ level: LogLevel, verbose: boolean }`
49
+
50
+ ## Phase 1C: Stage Events
51
+ **Commit:** `feat(logger): emit structured stage lifecycle events`
52
+
53
+ ### File: `src/execution/runner.ts`
54
+ - Add logger calls at key lifecycle points (alongside existing console.log, not replacing):
55
+ - `run.start`, `iteration.start`, `context.built`
56
+ - `agent.start`, `agent.complete`
57
+ - `story.complete`, `run.complete`
58
+ - These write to JSONL file even at `info` level
59
+
60
+ ### File: `src/pipeline/stages/routing.ts`
61
+ - Add logger call for routing decision
62
+
63
+ ## Phase 1D: Tests
64
+ **Commit:** `test(logger): add unit tests for Logger, formatters, and JSONL output`
65
+
66
+ ### Test targets:
67
+ - `test/logger.test.ts` — Logger class, level gating, withStory, file output
68
+ - `test/formatters.test.ts` — console and JSONL formatters
69
+ - Verify: JSONL lines are valid JSON with required fields
70
+ - Verify: level gating (debug hidden at info level, etc.)
71
+ - Verify: file always gets all levels regardless of console setting
72
+
73
+ ## Test Strategy
74
+ - Mode: test-after (implementing against spec)
75
+ - Run: `bun test`
76
+
77
+ ## Notes
78
+ - Do NOT replace any existing `console.log` calls (Phase 2)
79
+ - Logger runs alongside existing output in Phase 1
80
+ - Console formatter should closely match current chalk output style
@@ -0,0 +1,37 @@
1
+ # Fix Plan: nax v0.8 Structured Logging — Phase 2
2
+ **Date:** 2026-02-20
3
+ **Covers:** AC-6 (runs list/show), AC-7 (per-story metrics), AC-9 (console.log migration)
4
+
5
+ ## Migration Rules
6
+ 1. Import `getLogger` from `../logger` (adjust path as needed)
7
+ 2. Get logger instance: `const logger = getLogger()`
8
+ 3. Replace `console.log(chalk.X(...))` → `logger.info(stage, message, data?)`
9
+ 4. Replace `console.warn(...)` → `logger.warn(stage, message, data?)`
10
+ 5. Replace `console.error(...)` → `logger.error(stage, message, data?)`
11
+ 6. Replace verbose/debug output → `logger.debug(stage, message, data?)`
12
+ 7. `stage` should be the module/concern: "routing", "context", "agent", "tdd", "pipeline", "config", "cli", etc.
13
+ 8. Keep chalk formatting in the logger's console formatter — do NOT use chalk in the migrated calls
14
+ 9. For `data` objects, include structured fields (storyId, cost, duration, etc.) not string interpolation
15
+ 10. Do NOT change test files — only src/ files
16
+
17
+ ## Phase 2A: Core execution pipeline (highest impact)
18
+ **Files:** src/execution/runner.ts, src/execution/helpers.ts, src/execution/post-verify.ts, src/execution/queue-handler.ts
19
+ **Commit:** `refactor(execution): migrate console.log to structured logger`
20
+
21
+ ## Phase 2B: Pipeline stages
22
+ **Files:** src/pipeline/runner.ts, src/pipeline/events.ts, src/pipeline/stages/*.ts (acceptance, completion, constitution, execution, prompt, review, routing, verification)
23
+ **Commit:** `refactor(pipeline): migrate console.log to structured logger`
24
+
25
+ ## Phase 2C: Agents, routing, context, config
26
+ **Files:** src/agents/claude.ts, src/agents/cost.ts, src/agents/validation.ts, src/routing/strategies/*.ts, src/context/builder.ts, src/config/loader.ts, src/analyze/*.ts
27
+ **Commit:** `refactor(agents): migrate console.log to structured logger`
28
+
29
+ ## Phase 2D: CLI, TDD, hooks, metrics + runs list/show commands
30
+ **Files:** src/cli/*.ts, src/tdd/*.ts, src/hooks/*.ts, src/metrics/*.ts, src/review/*.ts, src/acceptance/*.ts
31
+ **Also:** Implement `nax runs list -f <feature>` and `nax runs show <run-id> -f <feature>` commands in bin/nax.ts
32
+ **Also:** Add per-story metrics summary table to run.complete event
33
+ **Commit:** `feat(cli): add nax runs commands and migrate remaining console.log`
34
+
35
+ ## Verification
36
+ After all phases: `grep -rn "console\.\(log\|warn\|error\)" src/ | grep -v "logger\.ts\|formatters\.ts" | wc -l` should be 0
37
+ Run: `bun test` — all tests must pass
@@ -0,0 +1,180 @@
1
+ # Code Review: nax v0.8 LLM-Enhanced Routing
2
+
3
+ **Date:** 2026-02-20
4
+ **Reviewer:** Subrina (AI)
5
+ **Branch:** `feat/v0.8-llm-routing` (7 commits, LLM routing scope)
6
+ **Files:** 12 changed (src: ~450 LOC, test: ~700 LOC)
7
+ **Baseline:** 633 pass, 0 fail, 2 skip
8
+
9
+ ---
10
+
11
+ ## Overall Grade: B+ (83/100)
12
+
13
+ Solid implementation of LLM-based routing with good test coverage (532-line test file), clean separation from keyword strategy, proper fallback chain, and batch mode support. Two notable issues: a **process leak on timeout** (P1) and **duplicate batch routing code** (P2). The async strategy refactor is clean and non-breaking.
14
+
15
+ | Dimension | Score | Notes |
16
+ |:---|:---|:---|
17
+ | Security | 16/20 | Process leak on timeout; prompt injection surface (low risk — internal tool) |
18
+ | Reliability | 15/20 | Timeout doesn't kill process; no retry on transient failures |
19
+ | API Design | 18/20 | Clean strategy interface, good batch/cache separation |
20
+ | Code Quality | 17/20 | Well-documented, good JSDoc. Some duplication in runner.ts |
21
+ | Best Practices | 17/20 | Proper fallback chain, zod validation, backward compat via `routeTask` |
22
+
23
+ ---
24
+
25
+ ## Findings
26
+
27
+ ### 🔴 CRITICAL
28
+
29
+ *(none)*
30
+
31
+ ### 🟠 HIGH
32
+
33
+ #### BUG-1: Process leak on LLM timeout
34
+ **Severity:** HIGH | **Category:** Memory/Resource
35
+ **File:** `src/routing/strategies/llm.ts:131-149`
36
+
37
+ ```typescript
38
+ const timeoutPromise = new Promise<never>((_, reject) => {
39
+ setTimeout(() => reject(new Error(`LLM call timeout after ${timeoutMs}ms`)), timeoutMs);
40
+ });
41
+ // ...
42
+ return await Promise.race([outputPromise, timeoutPromise]);
43
+ ```
44
+
45
+ When the timeout fires, `Promise.race` rejects but the spawned `claude` process continues running. There's no `proc.kill()` on timeout. This leaks a process that could run for minutes.
46
+
47
+ **Risk:** Orphaned `claude` processes accumulating on Mac01, consuming memory and API credits.
48
+
49
+ **Fix:**
50
+ ```typescript
51
+ const controller = new AbortController();
52
+ const timeoutId = setTimeout(() => {
53
+ proc.kill();
54
+ controller.abort();
55
+ }, timeoutMs);
56
+
57
+ try {
58
+ const output = await outputPromise;
59
+ clearTimeout(timeoutId);
60
+ return output;
61
+ } catch (err) {
62
+ proc.kill();
63
+ clearTimeout(timeoutId);
64
+ throw err;
65
+ }
66
+ ```
67
+
68
+ #### BUG-2: `setTimeout` in `timeoutPromise` is never cleared on success
69
+ **Severity:** HIGH | **Category:** Bug
70
+ **File:** `src/routing/strategies/llm.ts:135`
71
+
72
+ Even when the LLM responds quickly, the `setTimeout` callback still fires after `timeoutMs`, creating a rejected promise with no handler (unhandled rejection in some runtimes). In Bun this is silently swallowed, but it's undefined behavior.
73
+
74
+ **Fix:** Use `clearTimeout` pattern (see BUG-1 fix above).
75
+
76
+ ---
77
+
78
+ ### 🟡 MEDIUM
79
+
80
+ #### ENH-1: Duplicate batch routing logic in `runner.ts`
81
+ **Severity:** MEDIUM | **Category:** Enhancement
82
+ **File:** `src/execution/runner.ts:140-154` and `src/execution/runner.ts:183-193`
83
+
84
+ The LLM batch routing block (check strategy, call `llmRouteBatch`, catch and warn) is duplicated verbatim for initial routing and re-routing after dependency resolution. Extract to a helper.
85
+
86
+ **Fix:**
87
+ ```typescript
88
+ async function tryBatchRoute(config: NaxConfig, stories: UserStory[]): Promise<void> {
89
+ if (config.routing.strategy !== "llm" || !config.routing.llm?.batchMode || stories.length === 0) return;
90
+ try {
91
+ console.log(chalk.dim(` LLM batch routing: routing ${stories.length} stories...`));
92
+ await llmRouteBatch(stories, { config });
93
+ } catch (err) {
94
+ console.warn(chalk.yellow(` LLM batch routing failed: ${(err as Error).message}`));
95
+ }
96
+ }
97
+ ```
98
+
99
+ #### ENH-2: Duplicate cached-routing override blocks in `runner.ts`
100
+ **Severity:** MEDIUM | **Category:** Enhancement
101
+ **File:** `src/execution/runner.ts:228-237` and `src/execution/runner.ts:258-267`
102
+
103
+ The `if (story.routing)` override block (complexity + modelTier + testStrategy) is duplicated for batch vs single-story paths. Same fix: extract helper.
104
+
105
+ #### PERF-1: `buildStrategyChain` called per-story in `routeStory`
106
+ **Severity:** MEDIUM | **Category:** Performance
107
+ **File:** `src/routing/router.ts`
108
+
109
+ ```typescript
110
+ export async function routeStory(...): Promise<RoutingDecision> {
111
+ const chain = await buildStrategyChain(context.config, workdir);
112
+ return await chain.route(story, context);
113
+ }
114
+ ```
115
+
116
+ The chain is rebuilt for every story call from the pipeline routing stage. For keyword/manual strategies this is cheap, but `buildStrategyChain` could load a custom strategy file each time. Consider caching the chain per-run.
117
+
118
+ **Risk:** Low for current usage (pipeline already uses batch routing for LLM). But `routeStory` is the public API.
119
+
120
+ #### TYPE-1: `parseBatchResponse` re-serializes then re-parses each entry
121
+ **Severity:** MEDIUM | **Category:** Performance/Style
122
+ **File:** `src/routing/strategies/llm.ts:239`
123
+
124
+ ```typescript
125
+ const decision = parseRoutingResponse(JSON.stringify(entry), story, config);
126
+ ```
127
+
128
+ Each batch entry is `JSON.stringify`'d then immediately `JSON.parse`'d inside `parseRoutingResponse`. This works but is wasteful. Consider extracting validation into a shared function that accepts an object.
129
+
130
+ ---
131
+
132
+ ### 🟢 LOW
133
+
134
+ #### ENH-3: `maxInputTokens` config field is unused
135
+ **Severity:** LOW | **Category:** Enhancement
136
+ **File:** `src/config/schema.ts` (LlmRoutingConfig)
137
+
138
+ `maxInputTokens` is defined in the schema and has a default of 2000, but nothing in `llm.ts` reads or enforces it. Either implement truncation of story context or remove the field to avoid config confusion.
139
+
140
+ #### STYLE-1: `console.log`/`console.warn` for routing logs
141
+ **Severity:** LOW | **Category:** Style
142
+ **File:** `src/routing/strategies/llm.ts` (multiple)
143
+
144
+ Uses raw `console.log`/`console.warn` with `[routing]` prefix. This will be addressed by the v0.8 structured logging feature, so noting for tracking only.
145
+
146
+ #### ENH-4: No validation that `strategy: "llm"` has `routing.llm` config
147
+ **Severity:** LOW | **Category:** Enhancement
148
+ **File:** `src/config/schema.ts`
149
+
150
+ When `strategy` is `"llm"`, there's a zod refinement for `customStrategyPath` on `"custom"` but no refinement requiring `llm` config when `strategy` is `"llm"`. The runtime handles it gracefully (falls through to keyword), but a config validation error would be more user-friendly.
151
+
152
+ #### STYLE-2: Adaptive strategy now has unnecessary null guards
153
+ **Severity:** LOW | **Category:** Style
154
+ **File:** `src/routing/strategies/adaptive.ts:170,193`
155
+
156
+ ```typescript
157
+ const decision = await keywordStrategy.route(story, context);
158
+ if (!decision) return null; // keyword never returns null
159
+ ```
160
+
161
+ The keyword strategy **never** returns null (it always produces a decision). The null guard is defensive but misleading — it suggests keyword might return null when it can't.
162
+
163
+ ---
164
+
165
+ ## Priority Fix Order
166
+
167
+ | Priority | ID | Effort | Description |
168
+ |:---|:---|:---|:---|
169
+ | P1 | BUG-1 + BUG-2 | S | Kill process on timeout, clear setTimeout on success |
170
+ | P2 | ENH-1 + ENH-2 | S | Extract duplicate batch routing + override helpers in runner.ts |
171
+ | P3 | TYPE-1 | S | Avoid re-serializing batch entries for validation |
172
+ | P4 | PERF-1 | M | Cache strategy chain per-run (optional) |
173
+ | P5 | ENH-3 | S | Remove or implement `maxInputTokens` |
174
+ | — | ENH-4, STYLE-1, STYLE-2 | S | Low priority / deferred to structured logging |
175
+
176
+ ---
177
+
178
+ ## Verdict
179
+
180
+ **Ship after P1 fix.** The process leak on timeout is the only blocker — it could accumulate orphaned `claude` processes costing real API credits. P2-P5 are quality improvements that can land in a follow-up.
@@ -0,0 +1,70 @@
1
+ Code Review Report — Post-fix LLM routing
2
+ Date: 2026-02-20
3
+ Branch: feat/v0.8-llm-routing
4
+ Commit: a70d4f61d29ce1e528fd1e3d82ec9987b4737a79
5
+
6
+ Summary
7
+ - Reviewed only the latest commit (the P1–P5 fix commit).
8
+ - Verified code changes for P1, P2, P3, P5 and test mock updates in the diff between HEAD~1 and HEAD.
9
+ - Could not complete test run: 'bun test' appeared to hang in this environment within the allotted time. (See note at the end.)
10
+
11
+ What I accomplished / found
12
+ 1) P1 (BUG-1+2): callLlm timeout, process kill and clearTimeout
13
+ - Changes made in src/routing/strategies/llm.ts:
14
+ - Introduced timeoutId variable, setTimeout now kills the spawned process (proc.kill()) and rejects on timeout.
15
+ - Promise.race is wrapped in try/catch and both success and error paths clearTimeout(timeoutId) and ensure proc.kill() is called on the error path.
16
+ - Assessment: Good improvements. This addresses the resource leak (leftover child) on timeout and ensures the timer is cleared on both success and failure.
17
+ - Notes / minor suggestions:
18
+ - clearTimeout is called with timeoutId which is possibly undefined in the narrow window before setTimeout assigned it; that's safe because clearTimeout(undefined) is benign in Node.
19
+ - proc.kill() is invoked both inside the timeout handler and again in catch — double-kill is usually safe but could be redundant; acceptable.
20
+ - If proc.exited already resolved, kill() is a no-op. No dangling promises observed in this snippet.
21
+
22
+ 2) P2 (ENH-1+2): tryLlmBatchRoute and applyCachedRouting
23
+ - Changes made in src/execution/runner.ts:
24
+ - Extracted the LLM batch routing logic into tryLlmBatchRoute that logs and swallows errors and returns early when not applicable.
25
+ - Extracted cached-routing override into applyCachedRouting(routing, story, config) and replaced inline blocks with the helper.
26
+ - Assessment: Behavior preserved. The helpers are straightforward extractions with identical logic (I compared the code before/after in the diff). applyCachedRouting reproduces the previous override logic for complexity -> modelTier mapping and testStrategy.
27
+ - Minor suggestion: applyCachedRouting accepts routing produced by routeTask; that function's return type is used via ReturnType<> which is OK. Consider adding a narrow explicit type alias for clarity in future.
28
+
29
+ 3) P3 (TYPE-1): validateRoutingDecision and stripCodeFences
30
+ - Changes made in src/routing/strategies/llm.ts:
31
+ - Extracted validateRoutingDecision(parsed, config) which validates parsed object fields and returns typed RoutingDecision.
32
+ - Extracted stripCodeFences(text) to remove markdown/json code fences.
33
+ - parseRoutingResponse now strips fences, JSON.parse once, and validates via validateRoutingDecision.
34
+ - parseBatchResponse uses validateRoutingDecision(entry, config) directly instead of re-serializing entry->string->parse again.
35
+ - Assessment: Correct and type-safer.
36
+ - validateRoutingDecision uses type assertions (as Complexity/TestStrategy/ModelTier) before returning typed fields — appropriate.
37
+ - Using direct validation on batch entries avoids unnecessary serialization/parsing and fixes the prior issue where batch entries were re-serialized.
38
+ - Minor caution: validateRoutingDecision checks `if (!parsed.complexity || !parsed.modelTier || ...)` — if any field is present but falsy (empty string) it will still be caught; that likely matches intended validation.
39
+
40
+ 4) P5 (ENH-3): Removed maxInputTokens from config schema
41
+ - Changes made in src/config/schema.ts: removed maxInputTokens from LlmRoutingConfig interface, schema and DEFAULT_CONFIG.
42
+ - Assessment: Removal in the three spots shown in diff is correct. I searched the diff for remaining references and did not see other references in the commit diff. (A full repo-wide search was not performed in this review scope.)
43
+
44
+ 5) Test mocks: mock spawn kill handlers
45
+ - Changes made in test/routing/llm-strategy.test.ts: added kill: () => {} to all 9 mock spawn objects.
46
+ - Assessment: Matches the code changes in callLlm that call proc.kill() on timeout and in catch — tests needed mocks to provide a kill function to avoid runtime errors. Good.
47
+
48
+ Tests
49
+ - I attempted to run tests with `bun test` but the runner in this environment did not complete within the quick-review time window (process appeared to hang). I aborted attempts to repeatedly poll.
50
+ - Because tests did not finish here, I could not validate runtime behavior across the suite. Local/CI test run is recommended.
51
+
52
+ Grade (per requested areas)
53
+ - P1 (BUG-1+2): PASS — timeout handling and process cleanup implemented; no obvious resource leaks or dangling timers.
54
+ - P2 (ENH-1+2): PASS — helpers extracted; logic preserved.
55
+ - P3 (TYPE-1): PASS — validation and fence-stripping extracted; batch entry validation fixed to avoid re-serialization.
56
+ - P5 (ENH-3): PASS (within commit diff) — removed config field; no remaining references in diff.
57
+ - Test mocks: PASS — all mocked spawns in the tested file now include kill() handler.
58
+
59
+ Recommendations / Follow-ups
60
+ - Run the full test suite in CI or locally to confirm all tests pass. The new timeout/process kill behavior and the added kill mocks should make tests stable, but I couldn't confirm here.
61
+ - Optional: avoid double-kill redundancy by checking proc.killed/exited state before calling kill() if platform provides it — not required.
62
+ - Optional: add unit tests for validateRoutingDecision and stripCodeFences to assert correct behavior on edge cases (fenced JSON, invalid fields, batch entries).
63
+
64
+ Note about test run
65
+ - The environment's `bun test` invocation did not complete in this review session; please run tests in CI or locally and paste the last 20 lines of output if you want me to re-check test failures (if any).
66
+
67
+ Artifacts
68
+ - Saved report at: docs/20260220-review-post-fix-llm-routing.md
69
+
70
+ End of report.
@@ -0,0 +1,101 @@
1
+ # Fix Plan: Split relevantFiles into contextFiles + expectedFiles
2
+
3
+ **Date:** 2026-02-21
4
+ **Branch:** `feat/v0.9-relevantfiles-split`
5
+ **Issue:** #1
6
+ **Base:** `master` (`b459e9f`)
7
+
8
+ ## Context
9
+
10
+ `relevantFiles` conflates two purposes:
11
+ 1. **Context injection** — files loaded into agent prompt before execution
12
+ 2. **Asset verification** — files that must exist after execution (pre-flight gate)
13
+
14
+ This causes false negatives: LLM-predicted filenames fail asset check even when code is correct and tests pass. Observed in dogfood Runs F and H.
15
+
16
+ ## Phase 1: Type Changes + Resolver Functions
17
+
18
+ ### Fix 1.1: Add new fields to UserStory type
19
+ **File:** `src/prd/types.ts`
20
+ **Change:** Add `contextFiles?: string[]` and `expectedFiles?: string[]` to `UserStory` interface. Keep `relevantFiles?: string[]` as deprecated.
21
+
22
+ ### Fix 1.2: Add resolver functions
23
+ **File:** `src/prd/types.ts` (or new `src/prd/helpers.ts`)
24
+ **Change:** Create two helper functions:
25
+ ```typescript
26
+ export function getContextFiles(story: UserStory): string[] {
27
+ return story.contextFiles ?? story.relevantFiles ?? [];
28
+ }
29
+ export function getExpectedFiles(story: UserStory): string[] {
30
+ return story.expectedFiles ?? [];
31
+ }
32
+ ```
33
+ **Key:** `getExpectedFiles` does NOT fall back to `relevantFiles`. Asset check is opt-in only.
34
+
35
+ ### Fix 1.3: Export helpers from prd index
36
+ **File:** `src/prd/index.ts`
37
+ **Change:** Export `getContextFiles` and `getExpectedFiles`.
38
+
39
+ **Commit:** `refactor(prd): add contextFiles + expectedFiles types and resolvers`
40
+
41
+ ## Phase 2: Wire Context Builder
42
+
43
+ ### Fix 2.1: Use getContextFiles in context builder
44
+ **File:** `src/context/builder.ts`
45
+ **Change:** Replace `currentStory.relevantFiles` with `getContextFiles(currentStory)` at line ~296. Import from prd.
46
+
47
+ **Commit:** `refactor(context): use getContextFiles for prompt injection`
48
+
49
+ ## Phase 3: Wire Verification
50
+
51
+ ### Fix 3.1: Use getExpectedFiles in post-verify
52
+ **File:** `src/execution/post-verify.ts`
53
+ **Change:** Replace `story.relevantFiles` (line ~73) with `getExpectedFiles(story)`. Import from prd.
54
+
55
+ ### Fix 3.2: Update verification function signature
56
+ **File:** `src/execution/verification.ts`
57
+ **Change:** Rename parameter `relevantFiles` to `expectedFiles` in `runVerification()` and `verifyAssets()` for clarity.
58
+
59
+ **Commit:** `refactor(verification): use getExpectedFiles for asset check (opt-in only)`
60
+
61
+ ## Phase 4: Wire Analyze + Decompose Output
62
+
63
+ ### Fix 4.1: Update classifier output
64
+ **File:** `src/analyze/classifier.ts`
65
+ **Change:** Map LLM output `relevantFiles` -> `contextFiles` in parsed result.
66
+
67
+ ### Fix 4.2: Update analyze types
68
+ **File:** `src/analyze/types.ts`
69
+ **Change:** Add `contextFiles` field alongside `relevantFiles`.
70
+
71
+ ### Fix 4.3: Update decompose prompt
72
+ **File:** `src/agents/claude.ts`
73
+ **Change:** In decompose prompt (~line 455), rename field 8 from `relevantFiles` to `contextFiles`.
74
+
75
+ ### Fix 4.4: Update CLI analyze output
76
+ **File:** `src/cli/analyze.ts`
77
+ **Change:** Map `relevantFiles` -> `contextFiles` in feature creation output.
78
+
79
+ ### Fix 4.5: Update acceptance fix-generator
80
+ **File:** `src/acceptance/fix-generator.ts`
81
+ **Change:** Replace `relevantFiles: []` with `contextFiles: []`.
82
+
83
+ **Commit:** `refactor(analyze): output contextFiles instead of relevantFiles`
84
+
85
+ ## Phase 5: Tests
86
+
87
+ ### Fix 5.1: Update verification tests
88
+ **Change:** Add test: story with `relevantFiles` but no `expectedFiles` -> asset check PASSES. Add test: story with `expectedFiles` set -> asset check verifies those files.
89
+
90
+ ### Fix 5.2: Update context builder tests
91
+ **Change:** Test `contextFiles` used when present. Test `relevantFiles` fallback. Test empty when neither set.
92
+
93
+ ### Fix 5.3: Update classifier/analyze tests
94
+ **Change:** Verify output uses `contextFiles` field.
95
+
96
+ **Commit:** `test: update tests for contextFiles/expectedFiles split`
97
+
98
+ ## Test Strategy
99
+ - Mode: test-after
100
+ - Run `bun test` after each phase
101
+ - All existing test files should continue passing (backward compat)