@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.
- package/.gitlab-ci.yml +96 -0
- package/BRIEF.md +140 -0
- package/CHANGELOG.md +60 -0
- package/CLAUDE.md +159 -0
- package/README.md +373 -0
- package/US-007-IMPLEMENTATION.md +139 -0
- package/bin/nax.ts +930 -0
- package/biome.json +14 -0
- package/bun.lock +168 -0
- package/bunfig.toml +11 -0
- package/docs/20260216-fix-plan-context-review.md +56 -0
- package/docs/20260216-relentless-vs-ngent-comparison.md +208 -0
- package/docs/20260216-v02-plan.md +136 -0
- package/docs/20260216-v02-review.md +685 -0
- package/docs/20260217-dogfood-findings.md +56 -0
- package/docs/20260217-p2-plus-plan.md +117 -0
- package/docs/20260217-partial-fixes-plan.md +62 -0
- package/docs/20260217-plan-analyze-spec.md +117 -0
- package/docs/20260217-post-impl-review.md +1137 -0
- package/docs/20260217-quick-wins-plan.md +66 -0
- package/docs/20260217-split-runner-plan.md +75 -0
- package/docs/20260217-v03-impl-plan.md +80 -0
- package/docs/20260217-v03-post-impl-review.md +589 -0
- package/docs/20260217-v04-impl-plan.md +86 -0
- package/docs/20260217-v05-post-impl-review.md +850 -0
- package/docs/20260217-v06-post-impl-review.md +817 -0
- package/docs/20260218-adr003-port-plan.md +151 -0
- package/docs/20260218-review-adr003-verification.md +175 -0
- package/docs/20260219-fix-plan-bug16-19.md +79 -0
- package/docs/20260219-fix-plan-bug20-22.md +114 -0
- package/docs/20260219-plan-llm-routing.md +116 -0
- package/docs/20260219-review-bug20-22-fixes.md +135 -0
- package/docs/20260219-routing-baseline-keyword.md +63 -0
- package/docs/20260220-plan-structured-logging-p1.md +80 -0
- package/docs/20260220-plan-structured-logging-p2.md +37 -0
- package/docs/20260220-review-llm-routing.md +180 -0
- package/docs/20260220-review-post-fix-llm-routing.md +70 -0
- package/docs/20260221-fix-plan-relevantfiles-split.md +101 -0
- package/docs/20260221-fix-plan-routing-mode.md +125 -0
- package/docs/20260221-review-v0.9-implementation.md +379 -0
- package/docs/20260222-fix-plan-v091-routing-isolation.md +197 -0
- package/docs/20260223-fix-plan-prompt-audit.md +62 -0
- package/docs/20260224-nax-roadmap-phases.md +189 -0
- package/docs/20260225-phase2-llm-service-layer.md +401 -0
- package/docs/20260225-review-v0.10.1.md +187 -0
- package/docs/20260303-v010-implementation-plan.md +165 -0
- package/docs/CLAUDE.md.bak +191 -0
- package/docs/ROADMAP.md +165 -0
- package/docs/SPEC-rectification.md +0 -0
- package/docs/SPEC.md +324 -0
- package/docs/US-001-plugin-loading-verification.md +152 -0
- package/docs/architecture-analysis.md +1076 -0
- package/docs/bugs/BUG-21-escalation-null-attempts.md +48 -0
- package/docs/bugs-from-dogfood-run-c.md +243 -0
- package/docs/code-review-20260228.md +612 -0
- package/docs/code-review-v0.15.0.md +629 -0
- package/docs/hook-lifecycle-test-plan.md +149 -0
- package/docs/releases/v0.11.0-and-earlier.md +20 -0
- package/docs/releases/v0.12.0.md +15 -0
- package/docs/releases/v0.13.0.md +14 -0
- package/docs/releases/v0.14.0.md +20 -0
- package/docs/releases/v0.14.1.md +36 -0
- package/docs/releases/v0.14.2.md +51 -0
- package/docs/releases/v0.14.3.md +174 -0
- package/docs/releases/v0.14.4.md +94 -0
- package/docs/releases/v0.15.0.md +502 -0
- package/docs/releases/v0.15.1.md +170 -0
- package/docs/releases/v0.15.3.md +193 -0
- package/docs/specs/status-file-v0.10.1.md +812 -0
- package/docs/v0.10-global-config.md +206 -0
- package/docs/v0.10-plugin-system.md +415 -0
- package/docs/v0.10-prompt-optimizer.md +234 -0
- package/docs/v0.3-spec.md +244 -0
- package/docs/v0.4-spec.md +140 -0
- package/docs/v0.5-spec.md +237 -0
- package/docs/v0.6-spec.md +371 -0
- package/docs/v0.7-spec.md +177 -0
- package/docs/v0.8-llm-routing.md +206 -0
- package/docs/v0.8-structured-logging.md +132 -0
- package/docs/v0.9.3-prompt-audit.md +112 -0
- package/examples/plugins/console-reporter/index.test.ts +207 -0
- package/examples/plugins/console-reporter/index.ts +110 -0
- package/nax/config.json +147 -0
- package/nax/features/bugfix-v0171/prd.json +52 -0
- package/nax/features/config-management/prd.json +108 -0
- package/nax/features/config-management/progress.txt +5 -0
- package/nax/features/diagnose/acceptance.test.ts +412 -0
- package/nax/features/diagnose/prd.json +41 -0
- package/nax/features/orchestration-fixes/prd.json +89 -0
- package/nax/features/orchestration-fixes/progress.txt +1 -0
- package/nax/features/plugin-integration/US-007-VERIFICATION.md +259 -0
- package/nax/features/plugin-integration/prd.json +208 -0
- package/nax/features/plugin-integration/progress.txt +5 -0
- package/nax/features/precheck/prd.json +205 -0
- package/nax/features/precheck/progress.txt +15 -0
- package/nax/features/structured-logging/prd.json +199 -0
- package/nax/features/unlock/prd.json +36 -0
- package/package.json +47 -0
- package/src/acceptance/fix-generator.ts +348 -0
- package/src/acceptance/generator.ts +282 -0
- package/src/acceptance/index.ts +30 -0
- package/src/acceptance/types.ts +79 -0
- package/src/agents/claude-decompose.ts +169 -0
- package/src/agents/claude-plan.ts +139 -0
- package/src/agents/claude.ts +324 -0
- package/src/agents/cost.ts +268 -0
- package/src/agents/index.ts +13 -0
- package/src/agents/registry.ts +48 -0
- package/src/agents/types-extended.ts +133 -0
- package/src/agents/types.ts +113 -0
- package/src/agents/validation.ts +69 -0
- package/src/analyze/classifier.ts +305 -0
- package/src/analyze/index.ts +16 -0
- package/src/analyze/scanner.ts +175 -0
- package/src/analyze/types.ts +51 -0
- package/src/cli/accept.ts +108 -0
- package/src/cli/analyze-parser.ts +284 -0
- package/src/cli/analyze.ts +207 -0
- package/src/cli/config.ts +561 -0
- package/src/cli/constitution.ts +109 -0
- package/src/cli/diagnose-analysis.ts +159 -0
- package/src/cli/diagnose-formatter.ts +87 -0
- package/src/cli/diagnose.ts +203 -0
- package/src/cli/generate.ts +127 -0
- package/src/cli/index.ts +37 -0
- package/src/cli/init.ts +188 -0
- package/src/cli/interact.ts +295 -0
- package/src/cli/plan.ts +198 -0
- package/src/cli/plugins.ts +111 -0
- package/src/cli/prompts.ts +295 -0
- package/src/cli/runs.ts +174 -0
- package/src/cli/status-cost.ts +151 -0
- package/src/cli/status-features.ts +338 -0
- package/src/cli/status.ts +13 -0
- package/src/commands/common.ts +171 -0
- package/src/commands/diagnose.ts +17 -0
- package/src/commands/index.ts +8 -0
- package/src/commands/logs.ts +384 -0
- package/src/commands/precheck.ts +86 -0
- package/src/commands/unlock.ts +96 -0
- package/src/config/defaults.ts +160 -0
- package/src/config/index.ts +22 -0
- package/src/config/loader.ts +121 -0
- package/src/config/merger.ts +147 -0
- package/src/config/path-security.ts +121 -0
- package/src/config/paths.ts +27 -0
- package/src/config/schema.ts +56 -0
- package/src/config/schemas.ts +286 -0
- package/src/config/types.ts +423 -0
- package/src/config/validate.ts +103 -0
- package/src/constitution/generator.ts +191 -0
- package/src/constitution/generators/aider.ts +41 -0
- package/src/constitution/generators/claude.ts +35 -0
- package/src/constitution/generators/cursor.ts +36 -0
- package/src/constitution/generators/opencode.ts +38 -0
- package/src/constitution/generators/types.ts +33 -0
- package/src/constitution/generators/windsurf.ts +36 -0
- package/src/constitution/index.ts +10 -0
- package/src/constitution/loader.ts +133 -0
- package/src/constitution/types.ts +31 -0
- package/src/context/auto-detect.ts +227 -0
- package/src/context/builder.ts +246 -0
- package/src/context/elements.ts +83 -0
- package/src/context/formatter.ts +107 -0
- package/src/context/generator.ts +129 -0
- package/src/context/generators/aider.ts +34 -0
- package/src/context/generators/claude.ts +28 -0
- package/src/context/generators/cursor.ts +28 -0
- package/src/context/generators/opencode.ts +30 -0
- package/src/context/generators/windsurf.ts +28 -0
- package/src/context/greenfield.ts +114 -0
- package/src/context/index.ts +33 -0
- package/src/context/injector.ts +279 -0
- package/src/context/test-scanner.ts +370 -0
- package/src/context/types.ts +98 -0
- package/src/errors.ts +67 -0
- package/src/execution/batching.ts +157 -0
- package/src/execution/crash-recovery.ts +373 -0
- package/src/execution/escalation/escalation.ts +44 -0
- package/src/execution/escalation/index.ts +13 -0
- package/src/execution/escalation/tier-escalation.ts +295 -0
- package/src/execution/escalation/tier-outcome.ts +158 -0
- package/src/execution/helpers.ts +38 -0
- package/src/execution/index.ts +45 -0
- package/src/execution/lifecycle/acceptance-loop.ts +272 -0
- package/src/execution/lifecycle/headless-formatter.ts +85 -0
- package/src/execution/lifecycle/index.ts +12 -0
- package/src/execution/lifecycle/parallel-lifecycle.ts +101 -0
- package/src/execution/lifecycle/precheck-runner.ts +140 -0
- package/src/execution/lifecycle/run-cleanup.ts +81 -0
- package/src/execution/lifecycle/run-completion.ts +129 -0
- package/src/execution/lifecycle/run-initialization.ts +141 -0
- package/src/execution/lifecycle/run-lifecycle.ts +312 -0
- package/src/execution/lifecycle/run-setup.ts +204 -0
- package/src/execution/lifecycle/story-hooks.ts +38 -0
- package/src/execution/lifecycle/story-size-prompts.ts +123 -0
- package/src/execution/lock.ts +115 -0
- package/src/execution/parallel-executor.ts +216 -0
- package/src/execution/parallel.ts +400 -0
- package/src/execution/pid-registry.ts +280 -0
- package/src/execution/pipeline-result-handler.ts +388 -0
- package/src/execution/post-verify-rectification.ts +188 -0
- package/src/execution/post-verify.ts +274 -0
- package/src/execution/progress.ts +25 -0
- package/src/execution/prompts.ts +127 -0
- package/src/execution/queue-handler.ts +109 -0
- package/src/execution/rectification.ts +13 -0
- package/src/execution/runner.ts +377 -0
- package/src/execution/sequential-executor.ts +388 -0
- package/src/execution/status-file.ts +264 -0
- package/src/execution/status-writer.ts +139 -0
- package/src/execution/story-context.ts +229 -0
- package/src/execution/test-output-parser.ts +14 -0
- package/src/execution/verification.ts +72 -0
- package/src/hooks/index.ts +2 -0
- package/src/hooks/runner.ts +286 -0
- package/src/hooks/types.ts +67 -0
- package/src/interaction/chain.ts +154 -0
- package/src/interaction/index.ts +60 -0
- package/src/interaction/init.ts +83 -0
- package/src/interaction/plugins/auto.ts +217 -0
- package/src/interaction/plugins/cli.ts +300 -0
- package/src/interaction/plugins/telegram.ts +384 -0
- package/src/interaction/plugins/webhook.ts +258 -0
- package/src/interaction/state.ts +171 -0
- package/src/interaction/triggers.ts +229 -0
- package/src/interaction/types.ts +163 -0
- package/src/logger/formatters.ts +84 -0
- package/src/logger/index.ts +16 -0
- package/src/logger/logger.ts +298 -0
- package/src/logger/types.ts +48 -0
- package/src/logging/formatter.ts +355 -0
- package/src/logging/index.ts +22 -0
- package/src/logging/types.ts +93 -0
- package/src/metrics/aggregator.ts +190 -0
- package/src/metrics/index.ts +14 -0
- package/src/metrics/tracker.ts +200 -0
- package/src/metrics/types.ts +109 -0
- package/src/optimizer/index.ts +62 -0
- package/src/optimizer/noop.optimizer.ts +24 -0
- package/src/optimizer/rule-based.optimizer.ts +248 -0
- package/src/optimizer/types.ts +53 -0
- package/src/pipeline/events.ts +130 -0
- package/src/pipeline/index.ts +19 -0
- package/src/pipeline/runner.ts +161 -0
- package/src/pipeline/stages/acceptance.ts +197 -0
- package/src/pipeline/stages/completion.ts +99 -0
- package/src/pipeline/stages/constitution.ts +63 -0
- package/src/pipeline/stages/context.ts +117 -0
- package/src/pipeline/stages/execution.ts +194 -0
- package/src/pipeline/stages/index.ts +62 -0
- package/src/pipeline/stages/optimizer.ts +74 -0
- package/src/pipeline/stages/prompt.ts +57 -0
- package/src/pipeline/stages/queue-check.ts +103 -0
- package/src/pipeline/stages/review.ts +181 -0
- package/src/pipeline/stages/routing.ts +81 -0
- package/src/pipeline/stages/verify.ts +100 -0
- package/src/pipeline/types.ts +167 -0
- package/src/plugins/index.ts +31 -0
- package/src/plugins/loader.ts +287 -0
- package/src/plugins/registry.ts +168 -0
- package/src/plugins/types.ts +327 -0
- package/src/plugins/validator.ts +352 -0
- package/src/prd/index.ts +172 -0
- package/src/prd/types.ts +202 -0
- package/src/precheck/checks-blockers.ts +391 -0
- package/src/precheck/checks-warnings.ts +142 -0
- package/src/precheck/checks.ts +30 -0
- package/src/precheck/index.ts +247 -0
- package/src/precheck/story-size-gate.ts +144 -0
- package/src/precheck/types.ts +31 -0
- package/src/queue/index.ts +2 -0
- package/src/queue/manager.ts +254 -0
- package/src/queue/types.ts +54 -0
- package/src/review/index.ts +8 -0
- package/src/review/runner.ts +172 -0
- package/src/review/types.ts +66 -0
- package/src/routing/builder.ts +81 -0
- package/src/routing/chain.ts +74 -0
- package/src/routing/index.ts +16 -0
- package/src/routing/loader.ts +58 -0
- package/src/routing/router.ts +303 -0
- package/src/routing/strategies/adaptive.ts +215 -0
- package/src/routing/strategies/index.ts +8 -0
- package/src/routing/strategies/keyword.ts +163 -0
- package/src/routing/strategies/llm-prompts.ts +209 -0
- package/src/routing/strategies/llm.ts +235 -0
- package/src/routing/strategies/manual.ts +50 -0
- package/src/routing/strategy.ts +99 -0
- package/src/tdd/cleanup.ts +111 -0
- package/src/tdd/index.ts +23 -0
- package/src/tdd/isolation.ts +123 -0
- package/src/tdd/orchestrator.ts +383 -0
- package/src/tdd/prompts.ts +270 -0
- package/src/tdd/rectification-gate.ts +183 -0
- package/src/tdd/session-runner.ts +179 -0
- package/src/tdd/types.ts +81 -0
- package/src/tdd/verdict.ts +271 -0
- package/src/tui/App.tsx +265 -0
- package/src/tui/components/AgentPanel.tsx +75 -0
- package/src/tui/components/CostOverlay.tsx +118 -0
- package/src/tui/components/HelpOverlay.tsx +107 -0
- package/src/tui/components/StatusBar.tsx +63 -0
- package/src/tui/components/StoriesPanel.tsx +177 -0
- package/src/tui/hooks/useKeyboard.ts +142 -0
- package/src/tui/hooks/useLayout.ts +137 -0
- package/src/tui/hooks/usePipelineEvents.ts +183 -0
- package/src/tui/hooks/usePty.ts +194 -0
- package/src/tui/index.tsx +38 -0
- package/src/tui/types.ts +76 -0
- package/src/utils/git.ts +83 -0
- package/src/utils/queue-writer.ts +54 -0
- package/src/verification/executor.ts +235 -0
- package/src/verification/gate.ts +207 -0
- package/src/verification/index.ts +12 -0
- package/src/verification/parser.ts +230 -0
- package/src/verification/rectification.ts +108 -0
- package/src/verification/types.ts +113 -0
- package/src/worktree/dispatcher.ts +65 -0
- package/src/worktree/index.ts +2 -0
- package/src/worktree/manager.ts +187 -0
- package/src/worktree/merge.ts +301 -0
- package/src/worktree/types.ts +4 -0
- package/test/TEST_COVERAGE_US001.md +217 -0
- package/test/TEST_COVERAGE_US003.md +84 -0
- package/test/TEST_COVERAGE_US005.md +86 -0
- package/test/US-002-orchestrator.test.ts +246 -0
- package/test/acceptance/cm-003-default-view.test.ts +194 -0
- package/test/execution/pid-registry.test.ts +240 -0
- package/test/execution/post-verify.test.ts +224 -0
- package/test/helpers/timeout.ts +42 -0
- package/test/integration/US-002-TEST-SUMMARY.md +107 -0
- package/test/integration/US-003-TEST-SUMMARY.md +149 -0
- package/test/integration/US-004-TEST-SUMMARY.md +106 -0
- package/test/integration/US-005-TEST-SUMMARY.md +138 -0
- package/test/integration/US-007-TEST-SUMMARY.md +100 -0
- package/test/integration/agent-validation.test.ts +439 -0
- package/test/integration/analyze-integration.test.ts +261 -0
- package/test/integration/analyze-scanner.test.ts +131 -0
- package/test/integration/cli-config-default-edge-cases.test.ts +222 -0
- package/test/integration/cli-config-default-view.test.ts +229 -0
- package/test/integration/cli-config-diff.test.ts +460 -0
- package/test/integration/cli-config.test.ts +736 -0
- package/test/integration/cli-diagnose.test.ts +592 -0
- package/test/integration/cli-logs.test.ts +314 -0
- package/test/integration/cli-plugins.test.ts +678 -0
- package/test/integration/cli-precheck.test.ts +371 -0
- package/test/integration/cli-run-headless.test.ts +173 -0
- package/test/integration/cli.test.ts +75 -0
- package/test/integration/config/merger.test.ts +465 -0
- package/test/integration/config/paths.test.ts +51 -0
- package/test/integration/config-loader.test.ts +265 -0
- package/test/integration/config.test.ts +444 -0
- package/test/integration/context-integration.test.ts +702 -0
- package/test/integration/context-provider-injection.test.ts +506 -0
- package/test/integration/context-verification-integration.test.ts +295 -0
- package/test/integration/e2e.test.ts +896 -0
- package/test/integration/execution.test.ts +625 -0
- package/test/integration/helpers.test.ts +295 -0
- package/test/integration/hooks.test.ts +361 -0
- package/test/integration/interaction-chain-pipeline.test.ts +464 -0
- package/test/integration/isolation.test.ts +143 -0
- package/test/integration/logger.test.ts +461 -0
- package/test/integration/parallel.test.ts +250 -0
- package/test/integration/path-security.test.ts +173 -0
- package/test/integration/pipeline-acceptance.test.ts +302 -0
- package/test/integration/pipeline-events.test.ts +475 -0
- package/test/integration/pipeline.test.ts +658 -0
- package/test/integration/plan.test.ts +157 -0
- package/test/integration/plugin-routing.test.ts +921 -0
- package/test/integration/plugins/config-integration.test.ts +172 -0
- package/test/integration/plugins/config-resolution.test.ts +522 -0
- package/test/integration/plugins/loader.test.ts +641 -0
- package/test/integration/plugins/registry.test.ts +746 -0
- package/test/integration/plugins/validator.test.ts +563 -0
- package/test/integration/prd-pause.test.ts +205 -0
- package/test/integration/prd-resolvers.test.ts +185 -0
- package/test/integration/precheck-integration.test.ts +468 -0
- package/test/integration/precheck.test.ts +805 -0
- package/test/integration/progress.test.ts +34 -0
- package/test/integration/rectification-flow.test.ts +512 -0
- package/test/integration/reporter-lifecycle.test.ts +860 -0
- package/test/integration/review-config-commands.test.ts +319 -0
- package/test/integration/review-config-schema.test.ts +116 -0
- package/test/integration/review-plugin-integration.test.ts +722 -0
- package/test/integration/review.test.ts +149 -0
- package/test/integration/routing-stage-bug-021.test.ts +274 -0
- package/test/integration/routing-stage-greenfield.test.ts +286 -0
- package/test/integration/runner-config-plugins.test.ts +461 -0
- package/test/integration/runner-fixes.test.ts +399 -0
- package/test/integration/runner-plugin-integration.test.ts +543 -0
- package/test/integration/runner.test.ts +1679 -0
- package/test/integration/s5-greenfield-fallback.test.ts +297 -0
- package/test/integration/status-file-integration.test.ts +325 -0
- package/test/integration/status-file.test.ts +379 -0
- package/test/integration/status-writer.test.ts +345 -0
- package/test/integration/story-id-in-events.test.ts +273 -0
- package/test/integration/tdd-cleanup.test.ts +246 -0
- package/test/integration/tdd-orchestrator.test.ts +1762 -0
- package/test/integration/test-scanner.test.ts +403 -0
- package/test/integration/verification-asset-check.test.ts +142 -0
- package/test/integration/verify-stage.test.ts +275 -0
- package/test/integration/worktree/manager.test.ts +218 -0
- package/test/integration/worktree/merge.test.ts +341 -0
- package/test/manual/logging-formatter-demo.ts +158 -0
- package/test/ui/tui-agent-panel.test.tsx +99 -0
- package/test/ui/tui-controls.test.ts +334 -0
- package/test/ui/tui-cost-and-pty.test.ts +189 -0
- package/test/ui/tui-layout.test.ts +378 -0
- package/test/ui/tui-pty-integration.test.tsx +159 -0
- package/test/ui/tui-stories.test.ts +332 -0
- package/test/unit/acceptance.test.ts +186 -0
- package/test/unit/agent-stderr-capture.test.ts +146 -0
- package/test/unit/analyze-classifier.test.ts +215 -0
- package/test/unit/analyze.test.ts +224 -0
- package/test/unit/auto-detect.test.ts +249 -0
- package/test/unit/cli-status.test.ts +417 -0
- package/test/unit/commands/common.test.ts +320 -0
- package/test/unit/commands/logs.test.ts +416 -0
- package/test/unit/commands/unlock.test.ts +319 -0
- package/test/unit/constitution-generators.test.ts +160 -0
- package/test/unit/constitution.test.ts +209 -0
- package/test/unit/context.test.ts +1722 -0
- package/test/unit/cost.test.ts +231 -0
- package/test/unit/crash-recovery.test.ts +308 -0
- package/test/unit/escalation.test.ts +126 -0
- package/test/unit/execution-logging-stderr.test.ts +156 -0
- package/test/unit/execution-stage.test.ts +122 -0
- package/test/unit/fix-generator.test.ts +275 -0
- package/test/unit/formatters.test.ts +469 -0
- package/test/unit/greenfield.test.ts +179 -0
- package/test/unit/helpers.test.ts +317 -0
- package/test/unit/interaction/human-review-trigger.test.ts +164 -0
- package/test/unit/interaction-network-failures.test.ts +389 -0
- package/test/unit/interaction-plugins.test.ts +164 -0
- package/test/unit/isolation.test.ts +134 -0
- package/test/unit/logging/formatter.test.ts +455 -0
- package/test/unit/merge.test.ts +268 -0
- package/test/unit/metrics.test.ts +276 -0
- package/test/unit/optimizer/noop.optimizer.test.ts +125 -0
- package/test/unit/optimizer/rule-based.optimizer.test.ts +358 -0
- package/test/unit/prd-auto-default.test.ts +290 -0
- package/test/unit/prd-failure-category.test.ts +176 -0
- package/test/unit/prd-get-next-story.test.ts +186 -0
- package/test/unit/precheck-checks.test.ts +840 -0
- package/test/unit/precheck-story-size-gate.test.ts +287 -0
- package/test/unit/precheck-types.test.ts +142 -0
- package/test/unit/prompts.test.ts +475 -0
- package/test/unit/queue.test.ts +237 -0
- package/test/unit/rectification.test.ts +284 -0
- package/test/unit/registry.test.ts +287 -0
- package/test/unit/routing.test.ts +937 -0
- package/test/unit/run-lifecycle.test.ts +140 -0
- package/test/unit/storyid-events.test.ts +224 -0
- package/test/unit/tdd-verdict.test.ts +492 -0
- package/test/unit/test-output-parser.test.ts +377 -0
- package/test/unit/verdict.test.ts +324 -0
- package/test/unit/worktree-manager.test.ts +158 -0
- 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
|