@nathapp/nax 0.28.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -2
- package/dist/nax.js +72691 -0
- package/package.json +12 -4
- package/src/cli/config.ts +3 -1
- package/src/config/defaults.ts +1 -0
- package/src/config/schemas.ts +1 -0
- package/src/config/types.ts +1 -0
- package/src/context/builder.ts +10 -1
- package/src/prompts/sections/role-task.ts +4 -2
- package/src/review/runner.ts +6 -1
- package/src/version.ts +2 -1
- package/.claude/rules/01-project-conventions.md +0 -34
- package/.claude/rules/02-test-architecture.md +0 -39
- package/.claude/rules/03-test-writing.md +0 -58
- package/.claude/rules/04-forbidden-patterns.md +0 -29
- package/.claude/settings.json +0 -15
- package/.githooks/pre-commit +0 -16
- package/.gitlab-ci.yml +0 -103
- package/.mcp.json +0 -8
- package/BRIEF.md +0 -140
- package/CLAUDE.md +0 -143
- package/US-007-IMPLEMENTATION.md +0 -139
- package/biome.json +0 -14
- package/bun.lock +0 -163
- package/bunfig.toml +0 -12
- package/docker-compose.test.yml +0 -15
- package/docs/20260216-fix-plan-context-review.md +0 -56
- package/docs/20260216-relentless-vs-ngent-comparison.md +0 -208
- package/docs/20260216-v02-plan.md +0 -136
- package/docs/20260216-v02-review.md +0 -685
- package/docs/20260217-dogfood-findings.md +0 -56
- package/docs/20260217-p2-plus-plan.md +0 -117
- package/docs/20260217-partial-fixes-plan.md +0 -62
- package/docs/20260217-plan-analyze-spec.md +0 -117
- package/docs/20260217-post-impl-review.md +0 -1137
- package/docs/20260217-quick-wins-plan.md +0 -66
- package/docs/20260217-split-runner-plan.md +0 -75
- package/docs/20260217-v03-impl-plan.md +0 -80
- package/docs/20260217-v03-post-impl-review.md +0 -589
- package/docs/20260217-v04-impl-plan.md +0 -86
- package/docs/20260217-v05-post-impl-review.md +0 -850
- package/docs/20260217-v06-post-impl-review.md +0 -817
- package/docs/20260218-adr003-port-plan.md +0 -151
- package/docs/20260218-review-adr003-verification.md +0 -175
- package/docs/20260219-fix-plan-bug16-19.md +0 -79
- package/docs/20260219-fix-plan-bug20-22.md +0 -114
- package/docs/20260219-plan-llm-routing.md +0 -116
- package/docs/20260219-review-bug20-22-fixes.md +0 -135
- package/docs/20260219-routing-baseline-keyword.md +0 -63
- package/docs/20260220-plan-structured-logging-p1.md +0 -80
- package/docs/20260220-plan-structured-logging-p2.md +0 -37
- package/docs/20260220-review-llm-routing.md +0 -180
- package/docs/20260220-review-post-fix-llm-routing.md +0 -70
- package/docs/20260221-fix-plan-relevantfiles-split.md +0 -101
- package/docs/20260221-fix-plan-routing-mode.md +0 -125
- package/docs/20260221-review-v0.9-implementation.md +0 -379
- package/docs/20260222-fix-plan-v091-routing-isolation.md +0 -197
- package/docs/20260223-fix-plan-prompt-audit.md +0 -62
- package/docs/20260224-nax-roadmap-phases.md +0 -189
- package/docs/20260225-phase2-llm-service-layer.md +0 -401
- package/docs/20260225-review-v0.10.1.md +0 -187
- package/docs/20260303-v010-implementation-plan.md +0 -165
- package/docs/20260304-review-nax.md +0 -492
- package/docs/CLAUDE.md.bak +0 -191
- package/docs/ROADMAP.md +0 -390
- package/docs/SPEC-rectification.md +0 -0
- package/docs/SPEC.md +0 -324
- package/docs/US-001-plugin-loading-verification.md +0 -152
- package/docs/adr/ADR-005-implementation-plan.md +0 -655
- package/docs/adr/ADR-005-pipeline-re-architecture.md +0 -464
- package/docs/architecture-analysis.md +0 -1076
- package/docs/bugs/BUG-21-escalation-null-attempts.md +0 -48
- package/docs/bugs-from-dogfood-run-c.md +0 -243
- package/docs/code-review-20260228.md +0 -612
- package/docs/code-review-v0.15.0.md +0 -629
- package/docs/hook-lifecycle-test-plan.md +0 -149
- package/docs/releases/v0.11.0-and-earlier.md +0 -20
- package/docs/releases/v0.12.0.md +0 -15
- package/docs/releases/v0.13.0.md +0 -14
- package/docs/releases/v0.14.0.md +0 -20
- package/docs/releases/v0.14.1.md +0 -36
- package/docs/releases/v0.14.2.md +0 -51
- package/docs/releases/v0.14.3.md +0 -174
- package/docs/releases/v0.14.4.md +0 -94
- package/docs/releases/v0.15.0.md +0 -502
- package/docs/releases/v0.15.1.md +0 -170
- package/docs/releases/v0.15.3.md +0 -193
- package/docs/specs/bug-039-orphan-processes.md +0 -131
- package/docs/specs/bug-040-review-rectification.md +0 -82
- package/docs/specs/bug-041-cross-story-test-isolation.md +0 -88
- package/docs/specs/bug-042-verifier-failure-capture.md +0 -117
- package/docs/specs/bun-pty-migration.md +0 -171
- package/docs/specs/central-run-registry.md +0 -116
- package/docs/specs/feat-010-smart-runner-git-history.md +0 -96
- package/docs/specs/feat-011-file-context-strategy.md +0 -73
- package/docs/specs/feat-012-tdd-writer-tier.md +0 -79
- package/docs/specs/feat-013-test-after-review.md +0 -89
- package/docs/specs/feat-014-heartbeat-observability.md +0 -127
- package/docs/specs/status-file-consolidation.md +0 -93
- package/docs/specs/status-file-v0.10.1.md +0 -812
- package/docs/specs/trigger-completion.md +0 -145
- package/docs/specs/verification-architecture-v2.md +0 -343
- package/docs/tdd/strategies.md +0 -97
- package/docs/v0.10-global-config.md +0 -206
- package/docs/v0.10-plugin-system.md +0 -415
- package/docs/v0.10-prompt-optimizer.md +0 -234
- package/docs/v0.3-spec.md +0 -244
- package/docs/v0.4-spec.md +0 -140
- package/docs/v0.5-spec.md +0 -237
- package/docs/v0.6-spec.md +0 -371
- package/docs/v0.7-spec.md +0 -177
- package/docs/v0.8-llm-routing.md +0 -206
- package/docs/v0.8-structured-logging.md +0 -132
- package/docs/v0.9.3-prompt-audit.md +0 -112
- package/examples/plugins/console-reporter/index.test.ts +0 -207
- package/examples/plugins/console-reporter/index.ts +0 -110
- package/memory/topic/feat-010-baseref.md +0 -28
- package/memory/topic/feat-013-test-after-deprecation.md +0 -22
- package/nax/config.json +0 -154
- package/nax/features/bug-039-medium/prd.json +0 -45
- package/nax/features/bugfix-v0171/prd.json +0 -52
- package/nax/features/central-run-registry/prd.json +0 -105
- package/nax/features/config-management/prd.json +0 -108
- package/nax/features/config-management/progress.txt +0 -5
- package/nax/features/diagnose/acceptance.test.ts +0 -414
- package/nax/features/diagnose/prd.json +0 -41
- package/nax/features/nax-compliance/prd.json +0 -52
- package/nax/features/nax-compliance/progress.txt +0 -1
- package/nax/features/orchestration-fixes/prd.json +0 -89
- package/nax/features/orchestration-fixes/progress.txt +0 -1
- package/nax/features/plugin-integration/US-007-VERIFICATION.md +0 -259
- package/nax/features/plugin-integration/prd.json +0 -208
- package/nax/features/plugin-integration/progress.txt +0 -5
- package/nax/features/post-rearch-bugfix/prd.json +0 -137
- package/nax/features/precheck/prd.json +0 -205
- package/nax/features/precheck/progress.txt +0 -15
- package/nax/features/prompt-builder/prd.json +0 -152
- package/nax/features/prompt-builder/progress.txt +0 -3
- package/nax/features/review-quality/prd.json +0 -55
- package/nax/features/routing-persistence/prd.json +0 -104
- package/nax/features/routing-persistence/progress.txt +0 -1
- package/nax/features/smart-test-runner/plan.md +0 -7
- package/nax/features/smart-test-runner/prd.json +0 -203
- package/nax/features/smart-test-runner/progress.txt +0 -13
- package/nax/features/smart-test-runner/spec.md +0 -7
- package/nax/features/smart-test-runner/tasks.md +0 -8
- package/nax/features/status-file-consolidation/prd.json +0 -106
- package/nax/features/structured-logging/prd.json +0 -199
- package/nax/features/trigger-completion/prd.json +0 -150
- package/nax/features/trigger-completion/progress.txt +0 -7
- package/nax/features/unlock/prd.json +0 -36
- package/nax/features/v0.18.3-execution-reliability/prd.json +0 -80
- package/nax/features/v0.18.3-execution-reliability/progress.txt +0 -3
- package/nax/features/v0.19.0-hardening/plan.md +0 -7
- package/nax/features/v0.19.0-hardening/prd.json +0 -84
- package/nax/features/v0.19.0-hardening/progress.txt +0 -7
- package/nax/features/v0.19.0-hardening/spec.md +0 -18
- package/nax/features/v0.19.0-hardening/tasks.md +0 -8
- package/nax/features/verify-v2/prd.json +0 -79
- package/nax/features/verify-v2/progress.txt +0 -3
- package/nax/status.json +0 -36
- package/test/COVERAGE-GAPS.md +0 -333
- package/test/e2e/cm-003-default-view.test.ts +0 -195
- package/test/e2e/plan-analyze-run.test.ts +0 -902
- package/test/helpers/helpers.test.ts +0 -295
- package/test/helpers/timeout.ts +0 -42
- package/test/integration/US-002-TEST-SUMMARY.md +0 -107
- package/test/integration/US-003-TEST-SUMMARY.md +0 -149
- package/test/integration/US-004-TEST-SUMMARY.md +0 -106
- package/test/integration/US-005-TEST-SUMMARY.md +0 -138
- package/test/integration/US-007-TEST-SUMMARY.md +0 -100
- package/test/integration/cli/agent-validation.test.ts +0 -439
- package/test/integration/cli/cli-config-default-edge-cases.test.ts +0 -223
- package/test/integration/cli/cli-config-default-view.test.ts +0 -230
- package/test/integration/cli/cli-config-diff.test.ts +0 -461
- package/test/integration/cli/cli-config-prompts-explain.test.ts +0 -74
- package/test/integration/cli/cli-config.test.ts +0 -737
- package/test/integration/cli/cli-diagnose.test.ts +0 -595
- package/test/integration/cli/cli-logs.test.ts +0 -346
- package/test/integration/cli/cli-plugins.test.ts +0 -679
- package/test/integration/cli/cli-precheck.test.ts +0 -372
- package/test/integration/cli/cli-run-headless.test.ts +0 -174
- package/test/integration/cli/cli.test.ts +0 -76
- package/test/integration/cli/precheck-integration.test.ts +0 -476
- package/test/integration/cli/precheck-orchestrator.test.ts +0 -247
- package/test/integration/cli/precheck.test.ts +0 -806
- package/test/integration/config/config-loader.test.ts +0 -266
- package/test/integration/config/config.test.ts +0 -444
- package/test/integration/config/merger.test.ts +0 -466
- package/test/integration/config/paths.test.ts +0 -52
- package/test/integration/config/security-loader.test.ts +0 -83
- package/test/integration/context/context-integration.test.ts +0 -703
- package/test/integration/context/context-path-security.test.ts +0 -173
- package/test/integration/context/context-provider-injection.test.ts +0 -507
- package/test/integration/context/context-verification-integration.test.ts +0 -296
- package/test/integration/context/s5-greenfield-fallback.test.ts +0 -298
- package/test/integration/execution/execution-isolation.test.ts +0 -143
- package/test/integration/execution/execution.test.ts +0 -634
- package/test/integration/execution/feature-status-write.test.ts +0 -302
- package/test/integration/execution/parallel.test.ts +0 -251
- package/test/integration/execution/prd-pause.test.ts +0 -205
- package/test/integration/execution/prd-resolvers.test.ts +0 -186
- package/test/integration/execution/progress.test.ts +0 -34
- package/test/integration/execution/runner-batching.test.ts +0 -682
- package/test/integration/execution/runner-config-plugins.test.ts +0 -462
- package/test/integration/execution/runner-escalation.test.ts +0 -561
- package/test/integration/execution/runner-fixes.test.ts +0 -400
- package/test/integration/execution/runner-plugin-integration.test.ts +0 -544
- package/test/integration/execution/runner-queue-and-attempts.test.ts +0 -476
- package/test/integration/execution/status-file-integration.test.ts +0 -289
- package/test/integration/execution/status-file.test.ts +0 -380
- package/test/integration/execution/status-writer.test.ts +0 -447
- package/test/integration/execution/story-id-in-events.test.ts +0 -274
- package/test/integration/interaction/interaction-chain-pipeline.test.ts +0 -476
- package/test/integration/pipeline/hooks.test.ts +0 -363
- package/test/integration/pipeline/pipeline-acceptance.test.ts +0 -303
- package/test/integration/pipeline/pipeline-events.test.ts +0 -476
- package/test/integration/pipeline/pipeline.test.ts +0 -660
- package/test/integration/pipeline/reporter-lifecycle.test.ts +0 -862
- package/test/integration/pipeline/verify-stage.test.ts +0 -286
- package/test/integration/plan/analyze-integration.test.ts +0 -262
- package/test/integration/plan/analyze-scanner.test.ts +0 -132
- package/test/integration/plan/logger.test.ts +0 -461
- package/test/integration/plan/plan.test.ts +0 -157
- package/test/integration/plugins/config-integration.test.ts +0 -173
- package/test/integration/plugins/config-resolution.test.ts +0 -523
- package/test/integration/plugins/loader.test.ts +0 -644
- package/test/integration/plugins/plugins-registry.test.ts +0 -747
- package/test/integration/plugins/validator.test.ts +0 -564
- package/test/integration/prompts/pb-004-migration.test.ts +0 -523
- package/test/integration/review/review-config-commands.test.ts +0 -320
- package/test/integration/review/review-config-schema.test.ts +0 -117
- package/test/integration/review/review-plugin-integration.test.ts +0 -729
- package/test/integration/review/review.test.ts +0 -150
- package/test/integration/routing/plugin-routing-advanced.test.ts +0 -461
- package/test/integration/routing/plugin-routing-core.test.ts +0 -527
- package/test/integration/routing/routing-stage-bug-021.test.ts +0 -275
- package/test/integration/routing/routing-stage-greenfield.test.ts +0 -287
- package/test/integration/tdd/tdd-cleanup.test.ts +0 -246
- package/test/integration/tdd/tdd-orchestrator-core.test.ts +0 -565
- package/test/integration/tdd/tdd-orchestrator-failureCategory.test.ts +0 -355
- package/test/integration/tdd/tdd-orchestrator-fallback.test.ts +0 -311
- package/test/integration/tdd/tdd-orchestrator-lite.test.ts +0 -289
- package/test/integration/tdd/tdd-orchestrator-prompts.test.ts +0 -260
- package/test/integration/tdd/tdd-orchestrator-verdict.test.ts +0 -536
- package/test/integration/tmp/headless-test/test.jsonl +0 -30
- package/test/integration/verification/test-scanner.test.ts +0 -403
- package/test/integration/verification/verification-asset-check.test.ts +0 -143
- package/test/integration/worktree/manager.test.ts +0 -218
- package/test/integration/worktree/worktree-merge.test.ts +0 -341
- package/test/manual/logging-formatter-demo.ts +0 -158
- package/test/ui/tui-agent-panel.test.tsx +0 -99
- package/test/ui/tui-pty-integration.test.tsx +0 -146
- package/test/unit/acceptance.test.ts +0 -187
- package/test/unit/agent-stderr-capture.test.ts +0 -147
- package/test/unit/agents/claude.test.ts +0 -107
- package/test/unit/analyze-classifier.test.ts +0 -216
- package/test/unit/analyze.test.ts +0 -224
- package/test/unit/auto-detect.test.ts +0 -250
- package/test/unit/cli-status-project-level.test.ts +0 -283
- package/test/unit/cli-status.test.ts +0 -418
- package/test/unit/commands/common.test.ts +0 -321
- package/test/unit/commands/logs.test.ts +0 -458
- package/test/unit/commands/runs.test.ts +0 -303
- package/test/unit/commands/unlock.test.ts +0 -320
- package/test/unit/config/defaults.test.ts +0 -70
- package/test/unit/config/quality-commands-schema.test.ts +0 -72
- package/test/unit/config/regression-gate-schema.test.ts +0 -160
- package/test/unit/config/smart-runner-flag.test.ts +0 -250
- package/test/unit/constitution-generators.test.ts +0 -161
- package/test/unit/constitution.test.ts +0 -210
- package/test/unit/context/context-autodetect.test.ts +0 -297
- package/test/unit/context/context-build.test.ts +0 -575
- package/test/unit/context/context-coverage.test.ts +0 -236
- package/test/unit/context/context-error.test.ts +0 -93
- package/test/unit/context/context-estimate-tokens.test.ts +0 -201
- package/test/unit/context/context-format.test.ts +0 -302
- package/test/unit/context/context-isolation.test.ts +0 -267
- package/test/unit/context/context-sort.test.ts +0 -93
- package/test/unit/context/context-story.test.ts +0 -108
- package/test/unit/context/prior-failures.test.ts +0 -463
- package/test/unit/context.test.ts +0 -1726
- package/test/unit/cost.test.ts +0 -231
- package/test/unit/crash-recovery.test.ts +0 -309
- package/test/unit/escalation.test.ts +0 -127
- package/test/unit/execution/lifecycle/run-completion.test.ts +0 -240
- package/test/unit/execution/lifecycle/run-regression.test.ts +0 -420
- package/test/unit/execution/pid-registry.test.ts +0 -241
- package/test/unit/execution/sequential-executor.test.ts +0 -235
- package/test/unit/execution/sfc-004-dead-code-cleanup.test.ts +0 -89
- package/test/unit/execution/structured-failure.test.ts +0 -415
- package/test/unit/execution-logging-stderr.test.ts +0 -157
- package/test/unit/execution-stage.test.ts +0 -123
- package/test/unit/fix-generator.test.ts +0 -276
- package/test/unit/formatters.test.ts +0 -468
- package/test/unit/greenfield.test.ts +0 -180
- package/test/unit/hooks/shell-security.test.ts +0 -40
- package/test/unit/interaction/auto-plugin.test.ts +0 -162
- package/test/unit/interaction/human-review-trigger.test.ts +0 -165
- package/test/unit/interaction-network-failures.test.ts +0 -390
- package/test/unit/interaction-plugins.test.ts +0 -472
- package/test/unit/logging/formatter.test.ts +0 -456
- package/test/unit/merge.test.ts +0 -269
- package/test/unit/metrics/aggregator.test.ts +0 -164
- package/test/unit/metrics/tracker.test.ts +0 -186
- package/test/unit/metrics.test.ts +0 -276
- package/test/unit/optimizer/noop.optimizer.test.ts +0 -125
- package/test/unit/optimizer/rule-based.optimizer.test.ts +0 -358
- package/test/unit/pipeline/event-bus.test.ts +0 -105
- package/test/unit/pipeline/routing-partial-override.test.ts +0 -121
- package/test/unit/pipeline/runner-retry.test.ts +0 -89
- package/test/unit/pipeline/stages/autofix.test.ts +0 -97
- package/test/unit/pipeline/stages/completion-review-gate.test.ts +0 -218
- package/test/unit/pipeline/stages/execution-ambiguity.test.ts +0 -311
- package/test/unit/pipeline/stages/execution-merge-conflict.test.ts +0 -218
- package/test/unit/pipeline/stages/rectify.test.ts +0 -101
- package/test/unit/pipeline/stages/regression-stage.test.ts +0 -69
- package/test/unit/pipeline/stages/review.test.ts +0 -201
- package/test/unit/pipeline/stages/routing-idempotence.test.ts +0 -139
- package/test/unit/pipeline/stages/routing-initial-complexity.test.ts +0 -321
- package/test/unit/pipeline/stages/routing-persistence.test.ts +0 -380
- package/test/unit/pipeline/stages/verify.test.ts +0 -267
- package/test/unit/pipeline/subscribers/events-writer.test.ts +0 -227
- package/test/unit/pipeline/subscribers/hooks.test.ts +0 -84
- package/test/unit/pipeline/subscribers/interaction.test.ts +0 -313
- package/test/unit/pipeline/subscribers/registry.test.ts +0 -149
- package/test/unit/pipeline/subscribers/reporters.test.ts +0 -90
- package/test/unit/pipeline/verify-smart-runner.test.ts +0 -345
- package/test/unit/prd-auto-default.test.ts +0 -291
- package/test/unit/prd-failure-category.test.ts +0 -177
- package/test/unit/prd-get-next-story.test.ts +0 -215
- package/test/unit/precheck/checks-warnings.test.ts +0 -114
- package/test/unit/precheck-checks.test.ts +0 -841
- package/test/unit/precheck-story-size-gate.test.ts +0 -288
- package/test/unit/precheck-types.test.ts +0 -143
- package/test/unit/prompts/builder.test.ts +0 -258
- package/test/unit/prompts/loader.test.ts +0 -355
- package/test/unit/prompts/sections/conventions.test.ts +0 -30
- package/test/unit/prompts/sections/isolation.test.ts +0 -35
- package/test/unit/prompts/sections/role-task.test.ts +0 -40
- package/test/unit/prompts/sections/sections.test.ts +0 -238
- package/test/unit/prompts/sections/story.test.ts +0 -45
- package/test/unit/prompts/sections/verdict.test.ts +0 -58
- package/test/unit/prompts.test.ts +0 -476
- package/test/unit/queue.test.ts +0 -237
- package/test/unit/rectification.test.ts +0 -285
- package/test/unit/registry.test.ts +0 -288
- package/test/unit/review/runner.test.ts +0 -117
- package/test/unit/routing/content-hash.test.ts +0 -99
- package/test/unit/routing/routing-stability.test.ts +0 -208
- package/test/unit/routing/strategies/llm.test.ts +0 -306
- package/test/unit/routing-advanced.test.ts +0 -313
- package/test/unit/routing-core.test.ts +0 -341
- package/test/unit/routing-strategies.test.ts +0 -440
- package/test/unit/storyid-events.test.ts +0 -213
- package/test/unit/tdd-verdict.test.ts +0 -492
- package/test/unit/test-output-parser.test.ts +0 -377
- package/test/unit/ui/tui-controls.test.ts +0 -335
- package/test/unit/ui/tui-cost-and-pty.test.ts +0 -190
- package/test/unit/ui/tui-layout.test.ts +0 -379
- package/test/unit/ui/tui-stories.test.ts +0 -333
- package/test/unit/unit-isolation.test.ts +0 -135
- package/test/unit/utils/git.test.ts +0 -50
- package/test/unit/utils/path-security.test.ts +0 -47
- package/test/unit/utils-helpers.test.ts +0 -318
- package/test/unit/verdict.test.ts +0 -325
- package/test/unit/verification/orchestrator-types.test.ts +0 -54
- package/test/unit/verification/orchestrator.test.ts +0 -66
- package/test/unit/verification/smart-runner-config.test.ts +0 -163
- package/test/unit/verification/smart-runner-discovery.test.ts +0 -354
- package/test/unit/verification/smart-runner.test.ts +0 -262
- package/test/unit/verification/strategies/acceptance.test.ts +0 -33
- package/test/unit/verification/strategies/regression.test.ts +0 -87
- package/test/unit/verification/strategies/scoped.test.ts +0 -100
- package/test/unit/worktree-manager.test.ts +0 -159
- package/tsconfig.json +0 -27
|
@@ -1,440 +0,0 @@
|
|
|
1
|
-
// RE-ARCH: keep
|
|
2
|
-
/**
|
|
3
|
-
* Routing Tests
|
|
4
|
-
*
|
|
5
|
-
* Consolidated test suite for routing system including:
|
|
6
|
-
* - Core routing logic (classifyComplexity, determineTestStrategy, routeTask)
|
|
7
|
-
* - Routing strategies (keyword, llm, manual, adaptive)
|
|
8
|
-
* - Strategy chain execution
|
|
9
|
-
* - Async support and chain delegation
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { beforeEach, describe, expect, mock, spyOn, test } from "bun:test";
|
|
13
|
-
import { DEFAULT_CONFIG } from "../../src/config";
|
|
14
|
-
import type { NaxConfig } from "../../src/config";
|
|
15
|
-
import { escalateTier } from "../../src/execution/runner";
|
|
16
|
-
import type { AggregateMetrics } from "../../src/metrics/types";
|
|
17
|
-
import type { UserStory } from "../../src/prd/types";
|
|
18
|
-
import { classifyComplexity, determineTestStrategy, routeTask } from "../../src/routing";
|
|
19
|
-
import { buildStrategyChain } from "../../src/routing/builder";
|
|
20
|
-
import { StrategyChain } from "../../src/routing/chain";
|
|
21
|
-
import { keywordStrategy, llmStrategy, manualStrategy } from "../../src/routing/strategies";
|
|
22
|
-
import { adaptiveStrategy } from "../../src/routing/strategies/adaptive";
|
|
23
|
-
import {
|
|
24
|
-
buildBatchPrompt,
|
|
25
|
-
buildRoutingPrompt,
|
|
26
|
-
clearCache,
|
|
27
|
-
clearCacheForStory,
|
|
28
|
-
getCacheSize,
|
|
29
|
-
llmStrategy as llmStrategyFull,
|
|
30
|
-
parseRoutingResponse,
|
|
31
|
-
routeBatch,
|
|
32
|
-
stripCodeFences,
|
|
33
|
-
validateRoutingDecision,
|
|
34
|
-
} from "../../src/routing/strategies/llm";
|
|
35
|
-
import type { RoutingContext, RoutingDecision, RoutingStrategy } from "../../src/routing/strategy";
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const simpleStory: UserStory = {
|
|
39
|
-
id: "US-001",
|
|
40
|
-
title: "Fix typo in README",
|
|
41
|
-
description: "Correct spelling mistake",
|
|
42
|
-
acceptanceCriteria: ["Update README.md with correct spelling"],
|
|
43
|
-
tags: ["docs"],
|
|
44
|
-
dependencies: [],
|
|
45
|
-
status: "pending",
|
|
46
|
-
passes: false,
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const complexStory: UserStory = {
|
|
50
|
-
id: "US-002",
|
|
51
|
-
title: "Add JWT authentication",
|
|
52
|
-
description: "Implement JWT authentication with refresh tokens",
|
|
53
|
-
acceptanceCriteria: ["Secure token storage", "Token refresh endpoint", "Expiry handling", "Logout functionality"],
|
|
54
|
-
tags: ["security", "auth"],
|
|
55
|
-
dependencies: [],
|
|
56
|
-
status: "pending",
|
|
57
|
-
passes: false,
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const testContext: RoutingContext = {
|
|
61
|
-
config: DEFAULT_CONFIG,
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
describe("StrategyChain", () => {
|
|
65
|
-
test("uses first strategy that returns non-null", async () => {
|
|
66
|
-
const alwaysNullStrategy: RoutingStrategy = {
|
|
67
|
-
name: "always-null",
|
|
68
|
-
route: () => null,
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
const alwaysReturnStrategy: RoutingStrategy = {
|
|
72
|
-
name: "always-return",
|
|
73
|
-
route: () => ({
|
|
74
|
-
complexity: "simple",
|
|
75
|
-
modelTier: "fast",
|
|
76
|
-
testStrategy: "test-after",
|
|
77
|
-
reasoning: "Always return strategy",
|
|
78
|
-
}),
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
const chain = new StrategyChain([alwaysNullStrategy, alwaysReturnStrategy]);
|
|
82
|
-
|
|
83
|
-
const story: UserStory = {
|
|
84
|
-
id: "US-001",
|
|
85
|
-
title: "Test story",
|
|
86
|
-
description: "Test",
|
|
87
|
-
acceptanceCriteria: [],
|
|
88
|
-
tags: [],
|
|
89
|
-
dependencies: [],
|
|
90
|
-
status: "pending",
|
|
91
|
-
passes: false,
|
|
92
|
-
escalations: [],
|
|
93
|
-
attempts: 0,
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
const configWithoutLlm = { ...DEFAULT_CONFIG, routing: { ...DEFAULT_CONFIG.routing, llm: undefined } };
|
|
97
|
-
const context: RoutingContext = { config: configWithoutLlm };
|
|
98
|
-
const decision = await chain.route(story, context);
|
|
99
|
-
|
|
100
|
-
expect(decision.reasoning).toBe("Always return strategy");
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
test("throws error if all strategies return null", async () => {
|
|
104
|
-
const alwaysNullStrategy: RoutingStrategy = {
|
|
105
|
-
name: "always-null",
|
|
106
|
-
route: () => null,
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
const chain = new StrategyChain([alwaysNullStrategy]);
|
|
110
|
-
|
|
111
|
-
const story: UserStory = {
|
|
112
|
-
id: "US-001",
|
|
113
|
-
title: "Test story",
|
|
114
|
-
description: "Test",
|
|
115
|
-
acceptanceCriteria: [],
|
|
116
|
-
tags: [],
|
|
117
|
-
dependencies: [],
|
|
118
|
-
status: "pending",
|
|
119
|
-
passes: false,
|
|
120
|
-
escalations: [],
|
|
121
|
-
attempts: 0,
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
const configWithoutLlm = { ...DEFAULT_CONFIG, routing: { ...DEFAULT_CONFIG.routing, llm: undefined } };
|
|
125
|
-
const context: RoutingContext = { config: configWithoutLlm };
|
|
126
|
-
|
|
127
|
-
await expect(chain.route(story, context)).rejects.toThrow("No routing strategy returned a decision");
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
test("getStrategyNames returns strategy names", () => {
|
|
131
|
-
const chain = new StrategyChain([keywordStrategy, llmStrategy]);
|
|
132
|
-
expect(chain.getStrategyNames()).toEqual(["keyword", "llm"]);
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
describe("async support", () => {
|
|
136
|
-
test("handles async strategy that returns decision", async () => {
|
|
137
|
-
const asyncStrategy: RoutingStrategy = {
|
|
138
|
-
name: "async-test",
|
|
139
|
-
route: async () => {
|
|
140
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
141
|
-
return {
|
|
142
|
-
complexity: "medium",
|
|
143
|
-
modelTier: "balanced",
|
|
144
|
-
testStrategy: "test-after",
|
|
145
|
-
reasoning: "Async strategy result",
|
|
146
|
-
};
|
|
147
|
-
},
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
const chain = new StrategyChain([asyncStrategy]);
|
|
151
|
-
|
|
152
|
-
const story: UserStory = {
|
|
153
|
-
id: "US-001",
|
|
154
|
-
title: "Test async story",
|
|
155
|
-
description: "Test async routing",
|
|
156
|
-
acceptanceCriteria: [],
|
|
157
|
-
tags: [],
|
|
158
|
-
dependencies: [],
|
|
159
|
-
status: "pending",
|
|
160
|
-
passes: false,
|
|
161
|
-
escalations: [],
|
|
162
|
-
attempts: 0,
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
const context: RoutingContext = { config: DEFAULT_CONFIG };
|
|
166
|
-
const decision = await chain.route(story, context);
|
|
167
|
-
|
|
168
|
-
expect(decision.reasoning).toBe("Async strategy result");
|
|
169
|
-
expect(decision.complexity).toBe("medium");
|
|
170
|
-
expect(decision.modelTier).toBe("balanced");
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
test("handles mixed sync and async strategies", async () => {
|
|
174
|
-
const syncStrategy: RoutingStrategy = {
|
|
175
|
-
name: "sync-first",
|
|
176
|
-
route: () => null,
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
const asyncStrategy: RoutingStrategy = {
|
|
180
|
-
name: "async-second",
|
|
181
|
-
route: async () => {
|
|
182
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
183
|
-
return {
|
|
184
|
-
complexity: "complex",
|
|
185
|
-
modelTier: "powerful",
|
|
186
|
-
testStrategy: "three-session-tdd",
|
|
187
|
-
reasoning: "Mixed chain result",
|
|
188
|
-
};
|
|
189
|
-
},
|
|
190
|
-
};
|
|
191
|
-
|
|
192
|
-
const chain = new StrategyChain([syncStrategy, asyncStrategy]);
|
|
193
|
-
|
|
194
|
-
const story: UserStory = {
|
|
195
|
-
id: "US-003",
|
|
196
|
-
title: "Test mixed",
|
|
197
|
-
description: "Test mixed sync/async",
|
|
198
|
-
acceptanceCriteria: [],
|
|
199
|
-
tags: [],
|
|
200
|
-
dependencies: [],
|
|
201
|
-
status: "pending",
|
|
202
|
-
passes: false,
|
|
203
|
-
escalations: [],
|
|
204
|
-
attempts: 0,
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
const context: RoutingContext = { config: DEFAULT_CONFIG };
|
|
208
|
-
const decision = await chain.route(story, context);
|
|
209
|
-
|
|
210
|
-
expect(decision.reasoning).toBe("Mixed chain result");
|
|
211
|
-
expect(decision.testStrategy).toBe("three-session-tdd");
|
|
212
|
-
});
|
|
213
|
-
});
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
describe("keywordStrategy", () => {
|
|
217
|
-
test("classifies simple story correctly", () => {
|
|
218
|
-
const story: UserStory = {
|
|
219
|
-
id: "US-001",
|
|
220
|
-
title: "Update button color",
|
|
221
|
-
description: "Change button to blue",
|
|
222
|
-
acceptanceCriteria: ["Button is blue"],
|
|
223
|
-
tags: [],
|
|
224
|
-
dependencies: [],
|
|
225
|
-
status: "pending",
|
|
226
|
-
passes: false,
|
|
227
|
-
escalations: [],
|
|
228
|
-
attempts: 0,
|
|
229
|
-
};
|
|
230
|
-
|
|
231
|
-
const configWithoutLlm = { ...DEFAULT_CONFIG, routing: { ...DEFAULT_CONFIG.routing, llm: undefined } };
|
|
232
|
-
const context: RoutingContext = { config: configWithoutLlm };
|
|
233
|
-
const decision = keywordStrategy.route(story, context);
|
|
234
|
-
|
|
235
|
-
expect(decision).not.toBeNull();
|
|
236
|
-
expect(decision!.complexity).toBe("simple");
|
|
237
|
-
expect(decision!.modelTier).toBe("fast");
|
|
238
|
-
expect(decision!.testStrategy).toBe("test-after");
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
test("classifies complex story with security keywords", () => {
|
|
242
|
-
const story: UserStory = {
|
|
243
|
-
id: "US-002",
|
|
244
|
-
title: "Add JWT authentication",
|
|
245
|
-
description: "Implement JWT auth with refresh tokens",
|
|
246
|
-
acceptanceCriteria: ["Token storage", "Refresh logic", "Expiry"],
|
|
247
|
-
tags: ["security", "auth"],
|
|
248
|
-
dependencies: [],
|
|
249
|
-
status: "pending",
|
|
250
|
-
passes: false,
|
|
251
|
-
escalations: [],
|
|
252
|
-
attempts: 0,
|
|
253
|
-
};
|
|
254
|
-
|
|
255
|
-
const configWithoutLlm = { ...DEFAULT_CONFIG, routing: { ...DEFAULT_CONFIG.routing, llm: undefined } };
|
|
256
|
-
const context: RoutingContext = { config: configWithoutLlm };
|
|
257
|
-
const decision = keywordStrategy.route(story, context);
|
|
258
|
-
|
|
259
|
-
expect(decision).not.toBeNull();
|
|
260
|
-
expect(decision!.complexity).toBe("complex");
|
|
261
|
-
expect(decision!.modelTier).toBe("powerful");
|
|
262
|
-
expect(decision!.testStrategy).toBe("three-session-tdd");
|
|
263
|
-
expect(decision!.reasoning).toContain("security-critical");
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
test("uses three-session-tdd for public API", () => {
|
|
267
|
-
const story: UserStory = {
|
|
268
|
-
id: "US-005",
|
|
269
|
-
title: "Add public API endpoint",
|
|
270
|
-
description: "Create external API for consumers",
|
|
271
|
-
acceptanceCriteria: ["Endpoint returns JSON"],
|
|
272
|
-
tags: ["public api"],
|
|
273
|
-
dependencies: [],
|
|
274
|
-
status: "pending",
|
|
275
|
-
passes: false,
|
|
276
|
-
escalations: [],
|
|
277
|
-
attempts: 0,
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
const configWithoutLlm = { ...DEFAULT_CONFIG, routing: { ...DEFAULT_CONFIG.routing, llm: undefined } };
|
|
281
|
-
const context: RoutingContext = { config: configWithoutLlm };
|
|
282
|
-
const decision = keywordStrategy.route(story, context);
|
|
283
|
-
|
|
284
|
-
expect(decision).not.toBeNull();
|
|
285
|
-
expect(decision!.testStrategy).toBe("three-session-tdd");
|
|
286
|
-
expect(decision!.reasoning).toContain("public-api");
|
|
287
|
-
});
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
describe("manualStrategy", () => {
|
|
291
|
-
test("returns decision from story.routing metadata", () => {
|
|
292
|
-
const story: UserStory = {
|
|
293
|
-
id: "US-006",
|
|
294
|
-
title: "Manual override test",
|
|
295
|
-
description: "Story with manual routing",
|
|
296
|
-
acceptanceCriteria: [],
|
|
297
|
-
tags: [],
|
|
298
|
-
dependencies: [],
|
|
299
|
-
status: "pending",
|
|
300
|
-
passes: false,
|
|
301
|
-
escalations: [],
|
|
302
|
-
attempts: 0,
|
|
303
|
-
routing: {
|
|
304
|
-
complexity: "expert",
|
|
305
|
-
modelTier: "powerful",
|
|
306
|
-
testStrategy: "three-session-tdd",
|
|
307
|
-
reasoning: "Manual override for critical task",
|
|
308
|
-
},
|
|
309
|
-
};
|
|
310
|
-
|
|
311
|
-
const configWithoutLlm = { ...DEFAULT_CONFIG, routing: { ...DEFAULT_CONFIG.routing, llm: undefined } };
|
|
312
|
-
const context: RoutingContext = { config: configWithoutLlm };
|
|
313
|
-
const decision = manualStrategy.route(story, context);
|
|
314
|
-
|
|
315
|
-
expect(decision).not.toBeNull();
|
|
316
|
-
expect(decision!.complexity).toBe("expert");
|
|
317
|
-
expect(decision!.modelTier).toBe("powerful");
|
|
318
|
-
expect(decision!.testStrategy).toBe("three-session-tdd");
|
|
319
|
-
expect(decision!.reasoning).toBe("Manual override for critical task");
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
test("returns null when no routing metadata", () => {
|
|
323
|
-
const story: UserStory = {
|
|
324
|
-
id: "US-007",
|
|
325
|
-
title: "No manual routing",
|
|
326
|
-
description: "Story without routing metadata",
|
|
327
|
-
acceptanceCriteria: [],
|
|
328
|
-
tags: [],
|
|
329
|
-
dependencies: [],
|
|
330
|
-
status: "pending",
|
|
331
|
-
passes: false,
|
|
332
|
-
escalations: [],
|
|
333
|
-
attempts: 0,
|
|
334
|
-
};
|
|
335
|
-
|
|
336
|
-
const configWithoutLlm = { ...DEFAULT_CONFIG, routing: { ...DEFAULT_CONFIG.routing, llm: undefined } };
|
|
337
|
-
const context: RoutingContext = { config: configWithoutLlm };
|
|
338
|
-
const decision = manualStrategy.route(story, context);
|
|
339
|
-
|
|
340
|
-
expect(decision).toBeNull();
|
|
341
|
-
});
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
describe("LLM Routing Strategy - Prompt Building", () => {
|
|
345
|
-
test("buildRoutingPrompt formats story correctly", () => {
|
|
346
|
-
const prompt = buildRoutingPrompt(simpleStory, DEFAULT_CONFIG);
|
|
347
|
-
|
|
348
|
-
expect(prompt).toContain("Title: Fix typo in README");
|
|
349
|
-
expect(prompt).toContain("Description: Correct spelling mistake");
|
|
350
|
-
expect(prompt).toContain("1. Update README.md with correct spelling");
|
|
351
|
-
expect(prompt).toContain("Tags: docs");
|
|
352
|
-
expect(prompt).toContain("fast: Simple changes");
|
|
353
|
-
expect(prompt).toContain("balanced: Standard features");
|
|
354
|
-
expect(prompt).toContain("powerful: Complex architecture");
|
|
355
|
-
});
|
|
356
|
-
|
|
357
|
-
test("buildBatchPrompt formats multiple stories", () => {
|
|
358
|
-
const stories = [simpleStory, complexStory];
|
|
359
|
-
const prompt = buildBatchPrompt(stories, DEFAULT_CONFIG);
|
|
360
|
-
|
|
361
|
-
expect(prompt).toContain("1. US-001: Fix typo in README");
|
|
362
|
-
expect(prompt).toContain("2. US-002: Add JWT authentication");
|
|
363
|
-
expect(prompt).toContain("Tags: docs");
|
|
364
|
-
expect(prompt).toContain("Tags: security, auth");
|
|
365
|
-
expect(prompt).toContain('{"id":"US-001"');
|
|
366
|
-
});
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
describe("LLM Routing Strategy - Response Parsing", () => {
|
|
370
|
-
test("parseRoutingResponse handles valid JSON", () => {
|
|
371
|
-
const output =
|
|
372
|
-
'{"complexity":"simple","modelTier":"fast","testStrategy":"test-after","reasoning":"Simple documentation fix"}';
|
|
373
|
-
const decision = parseRoutingResponse(output, simpleStory, DEFAULT_CONFIG);
|
|
374
|
-
|
|
375
|
-
expect(decision.complexity).toBe("simple");
|
|
376
|
-
expect(decision.modelTier).toBe("fast");
|
|
377
|
-
expect(decision.testStrategy).toBe("test-after");
|
|
378
|
-
expect(decision.reasoning).toBe("Simple documentation fix");
|
|
379
|
-
});
|
|
380
|
-
|
|
381
|
-
test("parseRoutingResponse strips markdown code blocks", () => {
|
|
382
|
-
const output =
|
|
383
|
-
'```json\n{"complexity":"complex","modelTier":"powerful","testStrategy":"three-session-tdd","reasoning":"Security-critical"}\n```';
|
|
384
|
-
const decision = parseRoutingResponse(output, complexStory, DEFAULT_CONFIG);
|
|
385
|
-
|
|
386
|
-
expect(decision.complexity).toBe("complex");
|
|
387
|
-
expect(decision.modelTier).toBe("powerful");
|
|
388
|
-
expect(decision.testStrategy).toBe("three-session-tdd");
|
|
389
|
-
});
|
|
390
|
-
|
|
391
|
-
test("parseRoutingResponse throws on invalid JSON", () => {
|
|
392
|
-
const output = "This is not JSON";
|
|
393
|
-
expect(() => parseRoutingResponse(output, simpleStory, DEFAULT_CONFIG)).toThrow();
|
|
394
|
-
});
|
|
395
|
-
|
|
396
|
-
test("parseRoutingResponse throws on missing fields", () => {
|
|
397
|
-
const output = '{"complexity":"simple","modelTier":"fast"}';
|
|
398
|
-
expect(() => parseRoutingResponse(output, simpleStory, DEFAULT_CONFIG)).toThrow("Missing required fields");
|
|
399
|
-
});
|
|
400
|
-
});
|
|
401
|
-
|
|
402
|
-
describe("stripCodeFences", () => {
|
|
403
|
-
test("returns plain JSON unchanged", () => {
|
|
404
|
-
const input = '{"complexity":"simple"}';
|
|
405
|
-
expect(stripCodeFences(input)).toBe('{"complexity":"simple"}');
|
|
406
|
-
});
|
|
407
|
-
|
|
408
|
-
test("strips ```json ... ``` fences", () => {
|
|
409
|
-
const input = '```json\n{"complexity":"simple"}\n```';
|
|
410
|
-
expect(stripCodeFences(input)).toBe('{"complexity":"simple"}');
|
|
411
|
-
});
|
|
412
|
-
|
|
413
|
-
test("strips leading 'json' keyword (no backticks)", () => {
|
|
414
|
-
const input = 'json\n{"complexity":"simple"}';
|
|
415
|
-
expect(stripCodeFences(input)).toBe('{"complexity":"simple"}');
|
|
416
|
-
});
|
|
417
|
-
});
|
|
418
|
-
|
|
419
|
-
describe("validateRoutingDecision", () => {
|
|
420
|
-
test("returns valid decision for correct input", () => {
|
|
421
|
-
const input = { complexity: "simple", modelTier: "fast", testStrategy: "test-after", reasoning: "trivial" };
|
|
422
|
-
const result = validateRoutingDecision(input, DEFAULT_CONFIG);
|
|
423
|
-
expect(result).toEqual({
|
|
424
|
-
complexity: "simple",
|
|
425
|
-
modelTier: "fast",
|
|
426
|
-
testStrategy: "test-after",
|
|
427
|
-
reasoning: "trivial",
|
|
428
|
-
});
|
|
429
|
-
});
|
|
430
|
-
|
|
431
|
-
test("throws on missing complexity", () => {
|
|
432
|
-
const input = { modelTier: "fast", testStrategy: "test-after", reasoning: "test" };
|
|
433
|
-
expect(() => validateRoutingDecision(input, DEFAULT_CONFIG)).toThrow("Missing required fields");
|
|
434
|
-
});
|
|
435
|
-
|
|
436
|
-
test("throws on invalid complexity value", () => {
|
|
437
|
-
const input = { complexity: "mega", modelTier: "fast", testStrategy: "test-after", reasoning: "test" };
|
|
438
|
-
expect(() => validateRoutingDecision(input, DEFAULT_CONFIG)).toThrow("Invalid complexity: mega");
|
|
439
|
-
});
|
|
440
|
-
});
|
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
// RE-ARCH: keep
|
|
2
|
-
/**
|
|
3
|
-
* BUG-020: Verify storyId is present in JSONL event logger calls.
|
|
4
|
-
*
|
|
5
|
-
* Tests three key stages: verify, execution, tdd orchestrator.
|
|
6
|
-
* Uses mocks — does NOT spawn nax processes.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from "bun:test";
|
|
10
|
-
import type { NaxConfig } from "../../src/config";
|
|
11
|
-
import { getLogger, initLogger, resetLogger } from "../../src/logger";
|
|
12
|
-
import type { PipelineContext } from "../../src/pipeline/types";
|
|
13
|
-
import type { UserStory } from "../../src/prd/types";
|
|
14
|
-
|
|
15
|
-
// ── Static imports (uses _deps pattern — no mock.module() needed) ────────────
|
|
16
|
-
|
|
17
|
-
import { verifyStage } from "../../src/pipeline/stages/verify";
|
|
18
|
-
import { _executionDeps, executionStage } from "../../src/pipeline/stages/execution";
|
|
19
|
-
import { runThreeSessionTdd } from "../../src/tdd/orchestrator";
|
|
20
|
-
|
|
21
|
-
// ── Mock agent ────────────────────────────────────────────────────────────────
|
|
22
|
-
|
|
23
|
-
const mockAgentRun = mock(async () => ({
|
|
24
|
-
success: true,
|
|
25
|
-
rateLimited: false,
|
|
26
|
-
estimatedCost: 0.01,
|
|
27
|
-
output: "done",
|
|
28
|
-
exitCode: 0,
|
|
29
|
-
durationMs: 100,
|
|
30
|
-
}));
|
|
31
|
-
|
|
32
|
-
const mockAgent = {
|
|
33
|
-
name: "claude",
|
|
34
|
-
// Only supports "balanced"/"powerful" — triggers tier mismatch when ctx.routing.modelTier="fast"
|
|
35
|
-
capabilities: { supportedTiers: ["balanced", "powerful"] },
|
|
36
|
-
run: mockAgentRun,
|
|
37
|
-
isInstalled: async () => true,
|
|
38
|
-
buildCommand: () => ["claude"],
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
// ── Capture originals for afterEach restoration ───────────────────────────────
|
|
42
|
-
|
|
43
|
-
const _origExecutionDeps = { ..._executionDeps };
|
|
44
|
-
|
|
45
|
-
// ── Shared fixtures ───────────────────────────────────────────────────────────
|
|
46
|
-
|
|
47
|
-
const STORY_ID = "story-bug020-test";
|
|
48
|
-
|
|
49
|
-
const mockStory: UserStory = {
|
|
50
|
-
id: STORY_ID,
|
|
51
|
-
title: "Test story for BUG-020",
|
|
52
|
-
description: "Verifies storyId appears in event payloads",
|
|
53
|
-
acceptanceCriteria: [],
|
|
54
|
-
status: "pending",
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Build a minimal PipelineContext with configurable quality overrides.
|
|
59
|
-
*/
|
|
60
|
-
function makeCtx(
|
|
61
|
-
qualityOverrides: Partial<{ requireTests: boolean; testCommand: string | undefined }> = {},
|
|
62
|
-
): PipelineContext {
|
|
63
|
-
const { requireTests = false, testCommand = undefined } = qualityOverrides;
|
|
64
|
-
return {
|
|
65
|
-
config: {
|
|
66
|
-
quality: {
|
|
67
|
-
requireTests,
|
|
68
|
-
commands: { test: testCommand },
|
|
69
|
-
},
|
|
70
|
-
review: undefined,
|
|
71
|
-
execution: {
|
|
72
|
-
sessionTimeoutSeconds: 60,
|
|
73
|
-
verificationTimeoutSeconds: 60,
|
|
74
|
-
dangerouslySkipPermissions: false,
|
|
75
|
-
costLimit: 10,
|
|
76
|
-
maxIterations: 50,
|
|
77
|
-
iterationDelayMs: 0,
|
|
78
|
-
},
|
|
79
|
-
models: {
|
|
80
|
-
fast: "claude-3-haiku-20240307",
|
|
81
|
-
balanced: "claude-3-5-sonnet-20241022",
|
|
82
|
-
powerful: "claude-opus-4-20250514",
|
|
83
|
-
},
|
|
84
|
-
autoMode: { defaultAgent: "claude" },
|
|
85
|
-
tdd: { rollbackOnFailure: false },
|
|
86
|
-
routing: { strategy: "complexity", llm: { mode: "per-story" } },
|
|
87
|
-
} as unknown as NaxConfig,
|
|
88
|
-
story: mockStory,
|
|
89
|
-
stories: [mockStory],
|
|
90
|
-
routing: {
|
|
91
|
-
complexity: "simple",
|
|
92
|
-
modelTier: "fast",
|
|
93
|
-
testStrategy: "test-after",
|
|
94
|
-
reasoning: "test fixture",
|
|
95
|
-
},
|
|
96
|
-
workdir: "/tmp/nax-test-storyid",
|
|
97
|
-
prd: { feature: "test", userStories: [mockStory] },
|
|
98
|
-
hooks: {} as any,
|
|
99
|
-
} as PipelineContext;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// ── Logger lifecycle ──────────────────────────────────────────────────────────
|
|
103
|
-
|
|
104
|
-
beforeEach(() => {
|
|
105
|
-
_executionDeps.getAgent = () => mockAgent as any;
|
|
106
|
-
resetLogger();
|
|
107
|
-
initLogger({ level: "debug", useChalk: false });
|
|
108
|
-
mockAgentRun.mockClear();
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
afterEach(() => {
|
|
112
|
-
Object.assign(_executionDeps, _origExecutionDeps);
|
|
113
|
-
mock.restore();
|
|
114
|
-
resetLogger();
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
// ── Tests ─────────────────────────────────────────────────────────────────────
|
|
118
|
-
|
|
119
|
-
describe("BUG-020: storyId in JSONL event payloads", () => {
|
|
120
|
-
// ── Verify stage ────────────────────────────────────────────────────────────
|
|
121
|
-
|
|
122
|
-
describe("verify stage", () => {
|
|
123
|
-
test("skip log (requireTests=false) includes storyId", async () => {
|
|
124
|
-
const logger = getLogger();
|
|
125
|
-
const debugSpy = spyOn(logger, "debug").mockImplementation(() => {});
|
|
126
|
-
|
|
127
|
-
const ctx = makeCtx({ requireTests: false });
|
|
128
|
-
await verifyStage.execute(ctx);
|
|
129
|
-
|
|
130
|
-
const call = debugSpy.mock.calls.find(
|
|
131
|
-
([, msg]) => msg === "Skipping verification (quality.requireTests = false)",
|
|
132
|
-
);
|
|
133
|
-
expect(call).toBeDefined();
|
|
134
|
-
expect(call![2]).toEqual(expect.objectContaining({ storyId: STORY_ID }));
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
test("skip log (no test command) includes storyId", async () => {
|
|
138
|
-
const logger = getLogger();
|
|
139
|
-
const debugSpy = spyOn(logger, "debug").mockImplementation(() => {});
|
|
140
|
-
|
|
141
|
-
const ctx = makeCtx({ requireTests: true, testCommand: undefined });
|
|
142
|
-
await verifyStage.execute(ctx);
|
|
143
|
-
|
|
144
|
-
const call = debugSpy.mock.calls.find(
|
|
145
|
-
([, msg]) => msg === "Skipping verification (no test command configured)",
|
|
146
|
-
);
|
|
147
|
-
expect(call).toBeDefined();
|
|
148
|
-
expect(call![2]).toEqual(expect.objectContaining({ storyId: STORY_ID }));
|
|
149
|
-
});
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
// ── Execution stage ─────────────────────────────────────────────────────────
|
|
153
|
-
|
|
154
|
-
describe("execution stage", () => {
|
|
155
|
-
test("agent tier mismatch warn includes storyId", async () => {
|
|
156
|
-
const logger = getLogger();
|
|
157
|
-
const warnSpy = spyOn(logger, "warn").mockImplementation(() => {});
|
|
158
|
-
spyOn(logger, "info").mockImplementation(() => {});
|
|
159
|
-
spyOn(logger, "error").mockImplementation(() => {});
|
|
160
|
-
|
|
161
|
-
const ctx = makeCtx();
|
|
162
|
-
ctx.prompt = "implement the feature";
|
|
163
|
-
await executionStage.execute(ctx);
|
|
164
|
-
|
|
165
|
-
const call = warnSpy.mock.calls.find(([, msg]) => msg === "Agent tier mismatch");
|
|
166
|
-
expect(call).toBeDefined();
|
|
167
|
-
expect(call![2]).toEqual(
|
|
168
|
-
expect.objectContaining({
|
|
169
|
-
storyId: STORY_ID,
|
|
170
|
-
agentName: "claude",
|
|
171
|
-
requestedTier: "fast",
|
|
172
|
-
}),
|
|
173
|
-
);
|
|
174
|
-
});
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
// ── TDD orchestrator ────────────────────────────────────────────────────────
|
|
178
|
-
|
|
179
|
-
describe("tdd orchestrator", () => {
|
|
180
|
-
test("dry-run info log includes storyId", async () => {
|
|
181
|
-
const logger = getLogger();
|
|
182
|
-
const infoSpy = spyOn(logger, "info").mockImplementation(() => {});
|
|
183
|
-
|
|
184
|
-
const mockAgent = {
|
|
185
|
-
name: "dry-run-agent",
|
|
186
|
-
capabilities: { supportedTiers: ["fast"] },
|
|
187
|
-
run: mock(async () => ({
|
|
188
|
-
success: true,
|
|
189
|
-
rateLimited: false,
|
|
190
|
-
estimatedCost: 0,
|
|
191
|
-
output: "",
|
|
192
|
-
exitCode: 0,
|
|
193
|
-
durationMs: 0,
|
|
194
|
-
})),
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
await runThreeSessionTdd({
|
|
198
|
-
agent: mockAgent as any,
|
|
199
|
-
story: mockStory,
|
|
200
|
-
config: makeCtx().config,
|
|
201
|
-
workdir: "/tmp/nax-test-storyid",
|
|
202
|
-
modelTier: "fast",
|
|
203
|
-
dryRun: true,
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
const dryRunCall = infoSpy.mock.calls.find(
|
|
207
|
-
([, msg]) => msg === "[DRY RUN] Would run 3-session TDD",
|
|
208
|
-
);
|
|
209
|
-
expect(dryRunCall).toBeDefined();
|
|
210
|
-
expect(dryRunCall![2]).toEqual(expect.objectContaining({ storyId: STORY_ID }));
|
|
211
|
-
});
|
|
212
|
-
});
|
|
213
|
-
});
|