@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,224 @@
1
+ /**
2
+ * Unit tests for post-verify regression gate (BUG-009)
3
+ *
4
+ * Tests the logic for:
5
+ * - Running regression gate after scoped verification passes
6
+ * - Skipping regression gate when scoped verification already ran full suite
7
+ * - Feeding regression failures into rectification loop
8
+ */
9
+
10
+ import { describe, expect, test } from "bun:test";
11
+ import type { RegressionGateConfig } from "../../src/config/schema";
12
+
13
+ describe("RegressionGateConfig", () => {
14
+ test("should have correct default values", () => {
15
+ const defaultConfig: RegressionGateConfig = {
16
+ enabled: true,
17
+ timeoutSeconds: 120,
18
+ };
19
+
20
+ expect(defaultConfig.enabled).toBe(true);
21
+ expect(defaultConfig.timeoutSeconds).toBe(120);
22
+ });
23
+
24
+ test("should allow disabling regression gate", () => {
25
+ const config: RegressionGateConfig = {
26
+ enabled: false,
27
+ timeoutSeconds: 120,
28
+ };
29
+
30
+ expect(config.enabled).toBe(false);
31
+ });
32
+
33
+ test("should allow custom timeout", () => {
34
+ const config: RegressionGateConfig = {
35
+ enabled: true,
36
+ timeoutSeconds: 180,
37
+ };
38
+
39
+ expect(config.timeoutSeconds).toBe(180);
40
+ });
41
+ });
42
+
43
+ describe("Regression Gate Logic", () => {
44
+ test("should run regression gate when scoped tests were run (changed files > 0)", () => {
45
+ const changedTestFiles = ["test/foo.test.ts", "test/bar.test.ts"];
46
+ const regressionGateEnabled = true;
47
+ const scopedTestsWereRun = changedTestFiles.length > 0;
48
+
49
+ // Logic: regression gate should run
50
+ const shouldRunRegressionGate = regressionGateEnabled && scopedTestsWereRun;
51
+ expect(shouldRunRegressionGate).toBe(true);
52
+ });
53
+
54
+ test("should skip regression gate when scoped tests ran full suite (changed files = 0)", () => {
55
+ const changedTestFiles: string[] = [];
56
+ const regressionGateEnabled = true;
57
+ const scopedTestsWereRun = changedTestFiles.length > 0;
58
+
59
+ // Logic: regression gate should NOT run (full suite already ran)
60
+ const shouldRunRegressionGate = regressionGateEnabled && scopedTestsWereRun;
61
+ expect(shouldRunRegressionGate).toBe(false);
62
+ });
63
+
64
+ test("should skip regression gate when disabled in config", () => {
65
+ const changedTestFiles = ["test/foo.test.ts"];
66
+ const regressionGateEnabled = false;
67
+ const scopedTestsWereRun = changedTestFiles.length > 0;
68
+
69
+ // Logic: regression gate should NOT run (disabled)
70
+ const shouldRunRegressionGate = regressionGateEnabled && scopedTestsWereRun;
71
+ expect(shouldRunRegressionGate).toBe(false);
72
+ });
73
+
74
+ test("should skip regression gate when both disabled AND no changed files", () => {
75
+ const changedTestFiles: string[] = [];
76
+ const regressionGateEnabled = false;
77
+ const scopedTestsWereRun = changedTestFiles.length > 0;
78
+
79
+ // Logic: regression gate should NOT run
80
+ const shouldRunRegressionGate = regressionGateEnabled && scopedTestsWereRun;
81
+ expect(shouldRunRegressionGate).toBe(false);
82
+ });
83
+ });
84
+
85
+ describe("Regression Failure Handling", () => {
86
+ test("should prefix regression errors with REGRESSION:", () => {
87
+ const regressionStatus = "TEST_FAILURE";
88
+ const diagnosticContext = `REGRESSION: ${regressionStatus}`;
89
+
90
+ expect(diagnosticContext).toBe("REGRESSION: TEST_FAILURE");
91
+ expect(diagnosticContext).toContain("REGRESSION:");
92
+ });
93
+
94
+ test("should handle different regression failure statuses", () => {
95
+ const statuses = ["TEST_FAILURE", "TIMEOUT", "ENVIRONMENTAL_FAILURE", "ASSET_CHECK_FAILED"];
96
+
97
+ for (const status of statuses) {
98
+ const diagnosticContext = `REGRESSION: ${status}`;
99
+ expect(diagnosticContext).toContain("REGRESSION:");
100
+ expect(diagnosticContext).toContain(status);
101
+ }
102
+ });
103
+ });
104
+
105
+ describe("Rectification Prompt for Regression", () => {
106
+ test("should include REGRESSION prefix in rectification prompt", () => {
107
+ const basePrompt = `# Rectification Required
108
+
109
+ Your changes caused test regressions. Fix these without breaking existing logic.`;
110
+
111
+ const regressionPrompt = `# REGRESSION: Cross-Story Test Failures
112
+
113
+ Your changes passed scoped tests but broke unrelated tests. Fix these regressions.
114
+
115
+ ${basePrompt}`;
116
+
117
+ expect(regressionPrompt).toContain("# REGRESSION:");
118
+ expect(regressionPrompt).toContain("passed scoped tests but broke unrelated tests");
119
+ expect(regressionPrompt).toContain(basePrompt);
120
+ });
121
+
122
+ test("regression prompt should emphasize cross-story nature", () => {
123
+ const regressionPrompt =
124
+ "# REGRESSION: Cross-Story Test Failures\n\nYour changes passed scoped tests but broke unrelated tests.";
125
+
126
+ expect(regressionPrompt).toContain("Cross-Story");
127
+ expect(regressionPrompt).toContain("unrelated tests");
128
+ });
129
+ });
130
+
131
+ describe("Regression Gate Timeout", () => {
132
+ test("should use config.execution.regressionGate.timeoutSeconds", () => {
133
+ const regressionGateConfig: RegressionGateConfig = {
134
+ enabled: true,
135
+ timeoutSeconds: 120,
136
+ };
137
+
138
+ expect(regressionGateConfig.timeoutSeconds).toBe(120);
139
+ });
140
+
141
+ test("should allow different timeout from verification timeout", () => {
142
+ const verificationTimeoutSeconds = 300;
143
+ const regressionGateTimeoutSeconds = 120;
144
+
145
+ // Regression gate can have different timeout (usually shorter)
146
+ expect(regressionGateTimeoutSeconds).not.toBe(verificationTimeoutSeconds);
147
+ expect(regressionGateTimeoutSeconds).toBeLessThan(verificationTimeoutSeconds);
148
+ });
149
+ });
150
+
151
+ describe("Story State After Regression Failure", () => {
152
+ test("should revert story to pending status", () => {
153
+ const story = {
154
+ id: "US-001",
155
+ status: "passed" as const,
156
+ passes: true,
157
+ priorErrors: [] as string[],
158
+ attempts: 0,
159
+ };
160
+
161
+ // After regression failure
162
+ const updatedStory = {
163
+ ...story,
164
+ status: "pending" as const,
165
+ passes: false,
166
+ priorErrors: [...story.priorErrors, "REGRESSION: TEST_FAILURE"],
167
+ };
168
+
169
+ expect(updatedStory.status).toBe("pending");
170
+ expect(updatedStory.passes).toBe(false);
171
+ expect(updatedStory.priorErrors).toContain("REGRESSION: TEST_FAILURE");
172
+ });
173
+
174
+ test("should increment attempts when countsTowardEscalation is true", () => {
175
+ const story = { id: "US-001", attempts: 0 };
176
+ const countsTowardEscalation = true;
177
+
178
+ // After regression failure that counts toward escalation
179
+ const updatedAttempts = countsTowardEscalation ? story.attempts + 1 : story.attempts;
180
+
181
+ expect(updatedAttempts).toBe(1);
182
+ });
183
+
184
+ test("should NOT increment attempts when countsTowardEscalation is false", () => {
185
+ const story = { id: "US-001", attempts: 0 };
186
+ const countsTowardEscalation = false;
187
+
188
+ // After regression failure that doesn't count toward escalation (e.g., timeout)
189
+ const updatedAttempts = countsTowardEscalation ? story.attempts + 1 : story.attempts;
190
+
191
+ expect(updatedAttempts).toBe(0);
192
+ });
193
+ });
194
+
195
+ describe("Story Metrics Removal", () => {
196
+ test("should remove story metrics on regression failure", () => {
197
+ const allStoryMetrics = [
198
+ { storyId: "US-001", cost: 0.5 },
199
+ { storyId: "US-002", cost: 0.3 },
200
+ ];
201
+ const failedStoryIds = new Set(["US-001"]);
202
+
203
+ // Remove metrics for failed stories
204
+ const remainingMetrics = allStoryMetrics.filter((m) => !failedStoryIds.has(m.storyId));
205
+
206
+ expect(remainingMetrics.length).toBe(1);
207
+ expect(remainingMetrics[0].storyId).toBe("US-002");
208
+ });
209
+
210
+ test("should remove metrics for all stories in batch", () => {
211
+ const allStoryMetrics = [
212
+ { storyId: "US-001", cost: 0.5 },
213
+ { storyId: "US-002", cost: 0.3 },
214
+ { storyId: "US-003", cost: 0.2 },
215
+ ];
216
+ const storyIds = new Set(["US-001", "US-002"]);
217
+
218
+ // Remove metrics for entire batch
219
+ const remainingMetrics = allStoryMetrics.filter((m) => !storyIds.has(m.storyId));
220
+
221
+ expect(remainingMetrics.length).toBe(1);
222
+ expect(remainingMetrics[0].storyId).toBe("US-003");
223
+ });
224
+ });
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Test Timeout Helpers
3
+ *
4
+ * Utilities to prevent tests from hanging indefinitely.
5
+ */
6
+
7
+ /**
8
+ * Wraps a promise with a hard timeout.
9
+ * If the promise doesn't resolve within the timeout, rejects with a timeout error.
10
+ *
11
+ * @param promise The promise to wrap
12
+ * @param timeoutMs Timeout in milliseconds
13
+ * @param operation Description of the operation (for error messages)
14
+ * @returns The promise result if it completes in time
15
+ * @throws TimeoutError if the timeout is exceeded
16
+ */
17
+ export async function withTimeout<T>(promise: Promise<T>, timeoutMs: number, operation = "Operation"): Promise<T> {
18
+ return Promise.race([
19
+ promise,
20
+ new Promise<T>((_, reject) =>
21
+ setTimeout(() => reject(new Error(`${operation} timed out after ${timeoutMs}ms`)), timeoutMs),
22
+ ),
23
+ ]);
24
+ }
25
+
26
+ /**
27
+ * Wraps a function call with a hard timeout.
28
+ * Useful for wrapping synchronous or async functions that might hang.
29
+ *
30
+ * @param fn The function to execute
31
+ * @param timeoutMs Timeout in milliseconds
32
+ * @param operation Description of the operation (for error messages)
33
+ * @returns The function result if it completes in time
34
+ * @throws TimeoutError if the timeout is exceeded
35
+ */
36
+ export async function executeWithTimeout<T>(
37
+ fn: () => Promise<T> | T,
38
+ timeoutMs: number,
39
+ operation = "Operation",
40
+ ): Promise<T> {
41
+ return withTimeout(Promise.resolve(fn()), timeoutMs, operation);
42
+ }
@@ -0,0 +1,107 @@
1
+ # US-002 Test Summary: Context Provider Injection
2
+
3
+ ## Overview
4
+ Created comprehensive test suite for US-002 that verifies context providers inject external data into agent prompts with proper token budget management.
5
+
6
+ ## Test File
7
+ - **Location**: `test/integration/context-provider-injection.test.ts`
8
+ - **Total Tests**: 20
9
+ - **Passing**: 14 (features already implemented)
10
+ - **Failing**: 6 (features not yet implemented)
11
+
12
+ ## Test Coverage by Acceptance Criteria
13
+
14
+ ### ✅ AC1: All registered context providers are called before agent execution
15
+ **Status**: All tests passing (feature implemented)
16
+ - ✓ Calls all registered context providers
17
+ - ✓ Providers receive the current story
18
+ - ✓ Works with no providers registered
19
+
20
+ ### ✅ AC2: Provider content appended under markdown section with label
21
+ **Status**: All tests passing (feature implemented)
22
+ - ✓ Appends provider content under labeled markdown section
23
+ - ✓ Multiple providers create separate labeled sections
24
+ - ✓ Provider content appended to existing context markdown
25
+
26
+ ### ❌ AC3: Total injected tokens respect token budget
27
+ **Status**: 4 tests failing (feature NOT implemented correctly)
28
+
29
+ **Issue**: Current implementation uses hardcoded `PLUGIN_CONTEXT_MAX_TOKENS = 20_000` instead of reading from `config.execution.contextProviderTokenBudget`
30
+
31
+ Failing tests:
32
+ - ✗ Respects default token budget of 2000 tokens when not configured
33
+ - ✗ Respects custom token budget from config
34
+ - ✗ Providers added in order until budget exhausted
35
+ - ✗ Single provider exceeding budget is skipped
36
+
37
+ ### ✅ AC4: Provider errors caught, logged, and skipped
38
+ **Status**: All tests passing (feature implemented)
39
+ - ✓ Continues when a provider throws error
40
+ - ✓ Handles all providers failing gracefully
41
+ - ✓ Error in one provider doesn't affect others
42
+
43
+ ### ❌ AC5: Token budget configurable via execution.contextProviderTokenBudget
44
+ **Status**: 2 tests failing (feature NOT implemented)
45
+
46
+ **Issue**:
47
+ 1. `ExecutionConfig` type doesn't include `contextProviderTokenBudget` field
48
+ 2. `DEFAULT_CONFIG` doesn't set default value of 2000 tokens
49
+ 3. Context stage uses hardcoded value instead of reading from config
50
+
51
+ Failing tests:
52
+ - ✗ Default config includes contextProviderTokenBudget with default of 2000
53
+ - ✗ Different projects can have different token budgets
54
+
55
+ ## Implementation Gaps
56
+
57
+ ### 1. Config Schema Missing Field
58
+ **File**: `src/config/schema.ts`
59
+ - Add `contextProviderTokenBudget: number` to `ExecutionConfig` interface
60
+ - Add validation in `ExecutionConfigSchema` (Zod)
61
+ - Set default value of 2000 in `DEFAULT_CONFIG.execution`
62
+
63
+ ### 2. Context Stage Uses Hardcoded Value
64
+ **File**: `src/pipeline/stages/context.ts`
65
+ - Line 32: `const PLUGIN_CONTEXT_MAX_TOKENS = 20_000;` (hardcoded)
66
+ - Should read from: `ctx.config.execution.contextProviderTokenBudget`
67
+ - Lines 62, 72: Replace `PLUGIN_CONTEXT_MAX_TOKENS` with config value
68
+
69
+ ## Test Execution
70
+
71
+ ```bash
72
+ # Run US-002 tests only
73
+ bun test ./test/integration/context-provider-injection.test.ts
74
+
75
+ # Current results:
76
+ # 14 pass, 6 fail, 46 expect() calls
77
+ ```
78
+
79
+ ## Next Steps for Implementer
80
+
81
+ 1. **Update ExecutionConfig interface** (src/config/schema.ts):
82
+ - Add `contextProviderTokenBudget: number` field
83
+ - Add Zod validation: `z.number().int().min(100).max(100000).default(2000)`
84
+ - Add to DEFAULT_CONFIG: `contextProviderTokenBudget: 2000`
85
+
86
+ 2. **Update context stage** (src/pipeline/stages/context.ts):
87
+ - Remove hardcoded `PLUGIN_CONTEXT_MAX_TOKENS` constant
88
+ - Read budget from `ctx.config.execution.contextProviderTokenBudget`
89
+ - Use configured value in budget checks (lines 62, 72)
90
+
91
+ 3. **Verify all tests pass**:
92
+ ```bash
93
+ bun test ./test/integration/context-provider-injection.test.ts
94
+ ```
95
+
96
+ ## Coverage Notes
97
+
98
+ The test suite covers:
99
+ - ✓ Provider registration and invocation
100
+ - ✓ Markdown formatting with labels
101
+ - ✓ Error handling and soft failures
102
+ - ✓ Token budget enforcement (with config)
103
+ - ✓ Multi-provider orchestration
104
+ - ✓ Integration with existing PRD context
105
+ - ✓ Built context element tracking
106
+
107
+ All edge cases are covered per acceptance criteria.
@@ -0,0 +1,149 @@
1
+ # US-003 Test Summary: Review Plugins Run After Built-in Verification
2
+
3
+ **Story ID:** US-003
4
+ **Date:** 2026-02-27
5
+ **Status:** ✅ PASSED
6
+ **Test File:** `test/integration/review-plugin-integration.test.ts`
7
+
8
+ ## Overview
9
+
10
+ This test suite verifies that plugin reviewers are correctly integrated into the review pipeline stage, running after built-in checks and triggering appropriate retry/escalation on failure.
11
+
12
+ ## Test Results
13
+
14
+ **Total Tests:** 19
15
+ **Passed:** 19
16
+ **Failed:** 0
17
+ **Success Rate:** 100%
18
+
19
+ ## Acceptance Criteria Coverage
20
+
21
+ ### ✅ AC1: Plugin reviewers run after built-in checks pass
22
+
23
+ | Test | Status |
24
+ |------|--------|
25
+ | Plugin reviewers execute when built-in checks pass | ✅ PASS |
26
+ | Plugin reviewers do not run if built-in checks fail | ✅ PASS |
27
+ | No plugin reviewers registered - continues normally | ✅ PASS |
28
+
29
+ **Verification:** Plugin reviewers only execute after built-in checks succeed, preventing unnecessary work when code quality gates fail.
30
+
31
+ ### ✅ AC2: Each reviewer receives workdir and changed files
32
+
33
+ | Test | Status |
34
+ |------|--------|
35
+ | Reviewer receives correct workdir | ✅ PASS |
36
+ | Reviewer receives list of changed files | ✅ PASS |
37
+ | Reviewer receives empty array when no files changed | ✅ PASS |
38
+
39
+ **Verification:** Reviewers receive accurate context about the working directory and which files were modified, enabling targeted analysis.
40
+
41
+ ### ✅ AC3: Reviewer failure triggers retry/escalation
42
+
43
+ | Test | Status |
44
+ |------|--------|
45
+ | Failing reviewer returns fail action | ✅ PASS |
46
+ | Reviewer failure includes plugin name in reason | ✅ PASS |
47
+
48
+ **Verification:** When a plugin reviewer fails, the pipeline returns a `fail` action with the plugin name in the failure reason, triggering the same retry/escalation logic as built-in check failures.
49
+
50
+ ### ✅ AC4: Reviewer output included in story result
51
+
52
+ | Test | Status |
53
+ |------|--------|
54
+ | Passing reviewer output is captured | ✅ PASS |
55
+ | Failing reviewer output is captured | ✅ PASS |
56
+
57
+ **Verification:** All reviewer outputs (success and failure) are stored in `ctx.reviewResult.pluginReviewers`, providing debugging information and audit trail.
58
+
59
+ ### ✅ AC5: Exceptions count as failures
60
+
61
+ | Test | Status |
62
+ |------|--------|
63
+ | Reviewer throwing exception counts as failure | ✅ PASS |
64
+ | Exception message captured in output | ✅ PASS |
65
+ | Non-Error exception converted to string | ✅ PASS |
66
+
67
+ **Verification:** When a reviewer throws an exception, it's treated as a failure with the error message captured for debugging. The pipeline correctly handles both Error objects and primitive throws.
68
+
69
+ ### ✅ AC6: Multiple reviewers run sequentially with short-circuiting
70
+
71
+ | Test | Status |
72
+ |------|--------|
73
+ | Multiple reviewers run in order when all pass | ✅ PASS |
74
+ | First failure short-circuits remaining reviewers | ✅ PASS |
75
+ | Exception short-circuits remaining reviewers | ✅ PASS |
76
+
77
+ **Verification:** Reviewers execute sequentially in registration order. When one fails (or throws), subsequent reviewers are skipped, providing fail-fast behavior.
78
+
79
+ ### ✅ Edge Cases
80
+
81
+ | Test | Status |
82
+ |------|--------|
83
+ | No plugins context - continues normally | ✅ PASS |
84
+ | Reviewer returns empty output | ✅ PASS |
85
+ | Reviewer without exitCode works | ✅ PASS |
86
+
87
+ **Verification:** The implementation handles edge cases gracefully: missing plugin context, empty output strings, and optional exitCode field.
88
+
89
+ ## Implementation Verification
90
+
91
+ ### Key Files Modified
92
+
93
+ 1. **`src/pipeline/stages/review.ts`**
94
+ - Lines 77-155: Plugin reviewer execution logic
95
+ - Lines 35-53: `getChangedFiles()` helper function
96
+ - Correctly integrates plugin reviewers after built-in checks
97
+
98
+ 2. **`src/review/types.ts`**
99
+ - Lines 26-38: `PluginReviewerResult` interface
100
+ - Line 51: Extended `ReviewResult` with `pluginReviewers` field
101
+
102
+ 3. **`test/integration/review-plugin-integration.test.ts`**
103
+ - 722 lines of comprehensive test coverage
104
+ - Mock plugins and reviewers for isolated testing
105
+ - Git repository setup for realistic changed file detection
106
+
107
+ ### Type Safety
108
+
109
+ - ✅ All TypeScript types correctly defined
110
+ - ✅ No type errors (`bun run typecheck` passes)
111
+ - ✅ Proper type guards and assertions
112
+
113
+ ### Error Handling
114
+
115
+ - ✅ Exceptions caught and converted to failures
116
+ - ✅ Error messages preserved for debugging
117
+ - ✅ Non-Error throws handled correctly
118
+ - ✅ Missing optional fields handled safely
119
+
120
+ ### Integration Points
121
+
122
+ - ✅ Integrates with `PluginRegistry.getReviewers()`
123
+ - ✅ Uses existing pipeline context structure
124
+ - ✅ Follows established patterns from built-in checks
125
+ - ✅ Compatible with retry/escalation logic
126
+
127
+ ## Performance Considerations
128
+
129
+ - Reviewers run sequentially (not parallel) to prevent resource contention
130
+ - Fail-fast behavior minimizes wasted computation
131
+ - Changed files retrieved once and reused for all reviewers
132
+ - No unnecessary git operations or file system scans
133
+
134
+ ## Conclusion
135
+
136
+ **US-003 is fully implemented and verified.** All acceptance criteria are met with comprehensive test coverage. The implementation follows the codebase patterns, handles edge cases gracefully, and integrates seamlessly with the existing plugin system architecture.
137
+
138
+ ## Test Execution
139
+
140
+ ```bash
141
+ $ bun test test/integration/review-plugin-integration.test.ts
142
+
143
+ 19 pass
144
+ 0 fail
145
+ 51 expect() calls
146
+ Ran 19 tests across 1 file. [1.71s]
147
+ ```
148
+
149
+ **Final Status:** ✅ READY FOR PRODUCTION
@@ -0,0 +1,106 @@
1
+ # US-004: Reporter plugins receive lifecycle events — Test Summary
2
+
3
+ **Status:** ✅ PASSED
4
+ **Date:** 2026-02-27
5
+ **Commit:** 26181a1
6
+
7
+ ## Overview
8
+
9
+ This story implements reporter lifecycle events that fire at appropriate points in the runner loop. All reporter calls are fire-and-forget (errors logged, never block pipeline).
10
+
11
+ ## Implementation Summary
12
+
13
+ ### Changes Made
14
+
15
+ 1. **Moved PRD initialization** (runner.ts:205)
16
+ - Moved `prd` declaration before try block to make it accessible in finally block
17
+ - Ensures `prd` is available for onRunEnd event even on failure/abort
18
+
19
+ 2. **Consolidated onRunEnd calls** (runner.ts:1417-1439)
20
+ - Moved onRunEnd reporter events to finally block
21
+ - Removed duplicate calls from success paths (parallel and sequential)
22
+ - Guarantees onRunEnd fires even when run fails or is aborted
23
+
24
+ 3. **Added dry-run onStoryComplete events** (runner.ts:666-684)
25
+ - Added missing onStoryComplete events for dry-run mode
26
+ - Ensures reporters receive events consistently across all execution modes
27
+
28
+ ### Key Design Decisions
29
+
30
+ - **Finally block placement**: onRunEnd must fire even on exceptions, so it's placed in the finally block before teardown and lock release
31
+ - **Error isolation**: Each reporter call is wrapped in try/catch to prevent one reporter's failure from affecting others
32
+ - **Event ordering**: onRunEnd fires before plugin teardown to ensure reporters can still access plugin state
33
+
34
+ ## Test Results
35
+
36
+ All 9 tests in `test/integration/reporter-lifecycle.test.ts` pass:
37
+
38
+ ### AC1: onRunStart fires once at run start ✅
39
+ - Verified event contains: runId, feature, totalStories, startTime
40
+ - Verified event fires exactly once per run
41
+
42
+ ### AC2: onStoryComplete fires after each story ✅
43
+ - Verified event contains: runId, storyId, status, durationMs, cost, tier, testStrategy
44
+ - Verified event fires for each story execution (including dry-run)
45
+ - Verified correct status values (completed, failed, skipped, paused)
46
+
47
+ ### AC3: onRunEnd fires once at run end ✅
48
+ - Verified event contains: runId, totalDurationMs, totalCost, storySummary
49
+ - Verified storySummary contains: completed, failed, skipped, paused counts
50
+ - Verified correct counts match PRD state
51
+
52
+ ### AC4: Reporter errors never block execution ✅
53
+ - Verified failing reporter doesn't abort run
54
+ - Verified run completes successfully despite reporter errors
55
+ - Verified errors are logged (not thrown)
56
+
57
+ ### AC5: Multiple reporters all receive events ✅
58
+ - Verified two reporters both receive onRunStart, onStoryComplete, onRunEnd
59
+ - Verified second reporter receives events even if first reporter fails
60
+ - Verified no short-circuiting on error (all reporters always execute)
61
+
62
+ ### AC6: Events fire even when run fails or is aborted ✅
63
+ - Verified onRunStart and onRunEnd fire when stories are pre-failed
64
+ - Verified onRunEnd fires in finally block (even on exception)
65
+ - Verified storySummary reflects actual failure state
66
+
67
+ ## Additional Test Coverage
68
+
69
+ - **onStoryComplete for different outcomes**: Verified events for completed, failed, skipped, paused stories
70
+ - **Multiple stories**: Verified consistent runId across all events in same run
71
+ - **Dry-run mode**: Verified reporters receive events in dry-run mode
72
+
73
+ ## Verification Command
74
+
75
+ ```bash
76
+ bun test test/integration/reporter-lifecycle.test.ts
77
+ ```
78
+
79
+ **Result:** 9 pass, 0 fail, 48 expect() calls
80
+
81
+ ## Integration with Existing Code
82
+
83
+ - **US-001 (Plugin loading)**: Uses pluginRegistry.getReporters() to retrieve all loaded reporters
84
+ - **US-002 (Context provider injection)**: No conflicts, reporters operate independently
85
+ - **US-003 (Review plugins)**: No conflicts, different lifecycle hooks
86
+
87
+ ## Notes
88
+
89
+ - Reporter events are fire-and-forget by design
90
+ - All reporter methods are optional (IReporter interface)
91
+ - Reporter errors are logged at WARN level (not ERROR) since they're non-critical
92
+ - onRunEnd always fires in finally block, even if try block throws
93
+ - PRD must be accessible in finally block, so it's initialized before try
94
+
95
+ ## Acceptance Criteria Status
96
+
97
+ | AC | Description | Status |
98
+ |----|-------------|--------|
99
+ | 1 | onRunStart fires once at run start with runId, feature, totalStories, startTime | ✅ |
100
+ | 2 | onStoryComplete fires after each story with storyId, status, durationMs, cost, tier, testStrategy | ✅ |
101
+ | 3 | onRunEnd fires once at run end with runId, totalDurationMs, totalCost, storySummary counts | ✅ |
102
+ | 4 | Reporter errors are caught and logged but never block execution | ✅ |
103
+ | 5 | Multiple reporters all receive events (not short-circuited on error) | ✅ |
104
+ | 6 | Events fire even when the run fails or is aborted (onRunEnd still fires) | ✅ |
105
+
106
+ **Overall Status:** ✅ ALL ACCEPTANCE CRITERIA MET