@nathapp/nax 0.28.0 → 0.30.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 +23 -2
- package/bin/nax.ts +2 -3
- package/dist/nax.js +72753 -0
- package/package.json +11 -3
- package/src/cli/analyze.ts +2 -7
- 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/execution/lifecycle/headless-formatter.ts +2 -4
- package/src/prompts/builder.ts +12 -69
- package/src/prompts/sections/isolation.ts +38 -8
- package/src/prompts/sections/role-task.ts +79 -17
- 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/src/prompts/templates/implementer.ts +0 -6
- package/src/prompts/templates/single-session.ts +0 -6
- package/src/prompts/templates/test-writer.ts +0 -6
- package/src/prompts/templates/verifier.ts +0 -6
- 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,208 +0,0 @@
|
|
|
1
|
-
// RE-ARCH: keep
|
|
2
|
-
/**
|
|
3
|
-
* v0.18.4 Routing Stability Tests
|
|
4
|
-
*
|
|
5
|
-
* BUG-031: Keyword classifier inconsistency across retries
|
|
6
|
-
* BUG-033: LLM routing retry on timeout — config fields and defaults
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
10
|
-
import { keywordStrategy } from "../../../src/routing/strategies/keyword";
|
|
11
|
-
import type { RoutingContext } from "../../../src/routing/strategy";
|
|
12
|
-
import type { UserStory } from "../../../src/prd/types";
|
|
13
|
-
import { DEFAULT_CONFIG } from "../../../src/config/defaults";
|
|
14
|
-
import { initLogger, resetLogger } from "../../../src/logger";
|
|
15
|
-
|
|
16
|
-
// ---------------------------------------------------------------------------
|
|
17
|
-
// Fixtures
|
|
18
|
-
// ---------------------------------------------------------------------------
|
|
19
|
-
|
|
20
|
-
function makeStory(overrides: Partial<UserStory> = {}): UserStory {
|
|
21
|
-
return {
|
|
22
|
-
id: "TEST-001",
|
|
23
|
-
title: "Add login button",
|
|
24
|
-
description: "Simple button feature",
|
|
25
|
-
acceptanceCriteria: ["Button renders", "Click works"],
|
|
26
|
-
tags: [],
|
|
27
|
-
dependencies: [],
|
|
28
|
-
status: "pending",
|
|
29
|
-
passes: false,
|
|
30
|
-
escalations: [],
|
|
31
|
-
attempts: 0,
|
|
32
|
-
...overrides,
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const ctx: RoutingContext = {
|
|
37
|
-
config: { ...DEFAULT_CONFIG, routing: { ...DEFAULT_CONFIG.routing, llm: undefined } },
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
beforeEach(() => {
|
|
41
|
-
resetLogger();
|
|
42
|
-
initLogger({ level: "error", useChalk: false });
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
afterEach(() => {
|
|
46
|
-
mock.restore();
|
|
47
|
-
resetLogger();
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
// ---------------------------------------------------------------------------
|
|
51
|
-
// BUG-031: Keyword classifier stable across retries
|
|
52
|
-
// ---------------------------------------------------------------------------
|
|
53
|
-
|
|
54
|
-
describe("BUG-031: keyword classifier stability across retries", () => {
|
|
55
|
-
test("classification is identical on first attempt and retry with same story", () => {
|
|
56
|
-
const story = makeStory();
|
|
57
|
-
const first = keywordStrategy.route(story, ctx);
|
|
58
|
-
const retry = keywordStrategy.route(story, ctx);
|
|
59
|
-
|
|
60
|
-
expect(first!.complexity).toBe(retry!.complexity);
|
|
61
|
-
expect(first!.testStrategy).toBe(retry!.testStrategy);
|
|
62
|
-
expect(first!.modelTier).toBe(retry!.modelTier);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
test("description containing security/auth error text does NOT shift classification", () => {
|
|
66
|
-
const clean = makeStory({ title: "Add color picker", description: "Simple UI change" });
|
|
67
|
-
const withErrors = makeStory({
|
|
68
|
-
title: "Add color picker",
|
|
69
|
-
description: "Simple UI change\n\nPrior errors:\n- auth token expired\n- security check failed\n- refactor needed",
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
const cleanResult = keywordStrategy.route(clean, ctx);
|
|
73
|
-
const errorResult = keywordStrategy.route(withErrors, ctx);
|
|
74
|
-
|
|
75
|
-
// BUG-031 fix: description excluded from classification — results must be identical
|
|
76
|
-
expect(cleanResult!.complexity).toBe(errorResult!.complexity);
|
|
77
|
-
expect(cleanResult!.testStrategy).toBe(errorResult!.testStrategy);
|
|
78
|
-
expect(cleanResult!.modelTier).toBe(errorResult!.modelTier);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
test("description with complex keywords does NOT upgrade complexity", () => {
|
|
82
|
-
const story = makeStory({
|
|
83
|
-
title: "Fix button label",
|
|
84
|
-
description: "architecture refactor security migration breaking change",
|
|
85
|
-
tags: [],
|
|
86
|
-
acceptanceCriteria: ["Label is correct"],
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
const result = keywordStrategy.route(story, ctx);
|
|
90
|
-
expect(result!.complexity).toBe("simple");
|
|
91
|
-
expect(result!.testStrategy).toBe("test-after");
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
test("complexity is driven by title and tags only (not description)", () => {
|
|
95
|
-
const simple = makeStory({ title: "Update label", description: "auth security jwt rbac encryption" });
|
|
96
|
-
const complex = makeStory({
|
|
97
|
-
title: "Add JWT authentication",
|
|
98
|
-
description: "Simple change",
|
|
99
|
-
tags: ["auth"],
|
|
100
|
-
acceptanceCriteria: ["Token issued", "Expiry set", "Refresh works"],
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
expect(keywordStrategy.route(simple, ctx)!.complexity).toBe("simple");
|
|
104
|
-
expect(keywordStrategy.route(complex, ctx)!.testStrategy).toBe("three-session-tdd");
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
// ---------------------------------------------------------------------------
|
|
109
|
-
// BUG-033: LLM routing config — retries and timeout defaults
|
|
110
|
-
// ---------------------------------------------------------------------------
|
|
111
|
-
|
|
112
|
-
describe("BUG-033: LLM routing config defaults and retry fields", () => {
|
|
113
|
-
test("LlmRoutingConfig accepts retries and retryDelayMs fields", () => {
|
|
114
|
-
const config = {
|
|
115
|
-
...DEFAULT_CONFIG,
|
|
116
|
-
routing: {
|
|
117
|
-
...DEFAULT_CONFIG.routing,
|
|
118
|
-
llm: {
|
|
119
|
-
mode: "per-story" as const,
|
|
120
|
-
timeoutMs: 30000,
|
|
121
|
-
retries: 2,
|
|
122
|
-
retryDelayMs: 500,
|
|
123
|
-
fallbackToKeywords: true,
|
|
124
|
-
cacheDecisions: true,
|
|
125
|
-
},
|
|
126
|
-
},
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
expect(config.routing.llm!.retries).toBe(2);
|
|
130
|
-
expect(config.routing.llm!.retryDelayMs).toBe(500);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
test("retries defaults to undefined — callLlm uses 1 internally", () => {
|
|
134
|
-
const config = {
|
|
135
|
-
...DEFAULT_CONFIG,
|
|
136
|
-
routing: {
|
|
137
|
-
...DEFAULT_CONFIG.routing,
|
|
138
|
-
llm: { mode: "per-story" as const, fallbackToKeywords: true, cacheDecisions: true },
|
|
139
|
-
},
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
expect(config.routing.llm!.retries).toBeUndefined();
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
test("effective timeout defaults to 30000ms (raised from 15000)", () => {
|
|
146
|
-
const config = {
|
|
147
|
-
...DEFAULT_CONFIG,
|
|
148
|
-
routing: {
|
|
149
|
-
...DEFAULT_CONFIG.routing,
|
|
150
|
-
llm: { mode: "per-story" as const, fallbackToKeywords: true, cacheDecisions: true },
|
|
151
|
-
},
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
// When timeoutMs unset, callLlm applies 30000 default (not old 15000)
|
|
155
|
-
const effectiveTimeout = config.routing.llm!.timeoutMs ?? 30000;
|
|
156
|
-
expect(effectiveTimeout).toBe(30000);
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
test("retries: 0 disables retry (single attempt only)", () => {
|
|
160
|
-
const config = {
|
|
161
|
-
...DEFAULT_CONFIG,
|
|
162
|
-
routing: {
|
|
163
|
-
...DEFAULT_CONFIG.routing,
|
|
164
|
-
llm: { mode: "per-story" as const, retries: 0, fallbackToKeywords: true, cacheDecisions: true },
|
|
165
|
-
},
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
expect(config.routing.llm!.retries).toBe(0);
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
test("NaxConfigSchema validates retries and retryDelayMs", async () => {
|
|
172
|
-
const { NaxConfigSchema } = await import("../../../src/config/schemas");
|
|
173
|
-
|
|
174
|
-
const result = NaxConfigSchema.safeParse({
|
|
175
|
-
...DEFAULT_CONFIG,
|
|
176
|
-
routing: {
|
|
177
|
-
strategy: "llm",
|
|
178
|
-
llm: {
|
|
179
|
-
mode: "per-story",
|
|
180
|
-
retries: 2,
|
|
181
|
-
retryDelayMs: 1000,
|
|
182
|
-
fallbackToKeywords: true,
|
|
183
|
-
cacheDecisions: true,
|
|
184
|
-
},
|
|
185
|
-
},
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
expect(result.success).toBe(true);
|
|
189
|
-
if (result.success) {
|
|
190
|
-
expect(result.data.routing.llm?.retries).toBe(2);
|
|
191
|
-
expect(result.data.routing.llm?.retryDelayMs).toBe(1000);
|
|
192
|
-
}
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
test("NaxConfigSchema rejects negative retries", async () => {
|
|
196
|
-
const { NaxConfigSchema } = await import("../../../src/config/schemas");
|
|
197
|
-
|
|
198
|
-
const result = NaxConfigSchema.safeParse({
|
|
199
|
-
...DEFAULT_CONFIG,
|
|
200
|
-
routing: {
|
|
201
|
-
strategy: "llm",
|
|
202
|
-
llm: { mode: "per-story", retries: -1, fallbackToKeywords: true, cacheDecisions: true },
|
|
203
|
-
},
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
expect(result.success).toBe(false);
|
|
207
|
-
});
|
|
208
|
-
});
|
|
@@ -1,306 +0,0 @@
|
|
|
1
|
-
// RE-ARCH: keep
|
|
2
|
-
/**
|
|
3
|
-
* LLM Routing Strategy Tests
|
|
4
|
-
*
|
|
5
|
-
* BUG-039: Stream drain fix — stdout/stderr cancelled before proc.kill() on timeout
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
9
|
-
import type { NaxConfig } from "../../../../src/config";
|
|
10
|
-
import { DEFAULT_CONFIG } from "../../../../src/config/defaults";
|
|
11
|
-
import { initLogger, resetLogger } from "../../../../src/logger";
|
|
12
|
-
import { type PipedProc, _deps } from "../../../../src/routing/strategies/llm";
|
|
13
|
-
|
|
14
|
-
// ---------------------------------------------------------------------------
|
|
15
|
-
// Helpers
|
|
16
|
-
// ---------------------------------------------------------------------------
|
|
17
|
-
|
|
18
|
-
function makeConfig(overrides: Partial<NaxConfig["routing"]["llm"]> = {}): NaxConfig {
|
|
19
|
-
return {
|
|
20
|
-
...DEFAULT_CONFIG,
|
|
21
|
-
routing: {
|
|
22
|
-
...DEFAULT_CONFIG.routing,
|
|
23
|
-
strategy: "llm",
|
|
24
|
-
llm: {
|
|
25
|
-
mode: "per-story",
|
|
26
|
-
timeoutMs: 50,
|
|
27
|
-
retries: 0,
|
|
28
|
-
retryDelayMs: 0,
|
|
29
|
-
fallbackToKeywords: false,
|
|
30
|
-
cacheDecisions: false,
|
|
31
|
-
model: "fast",
|
|
32
|
-
...overrides,
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
} as NaxConfig;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/** Creates a fake Bun.spawn proc that never resolves (simulates a hanging LLM call). */
|
|
39
|
-
function makeHangingProc() {
|
|
40
|
-
const stdoutCancelled = { value: false };
|
|
41
|
-
const stderrCancelled = { value: false };
|
|
42
|
-
const killCalled = { value: false };
|
|
43
|
-
const killCalledAfterCancel = { value: false };
|
|
44
|
-
|
|
45
|
-
// ReadableStream that never produces data and never closes
|
|
46
|
-
const neverStream = () => {
|
|
47
|
-
const cancelFn: () => void = () => {};
|
|
48
|
-
const stream = new ReadableStream({
|
|
49
|
-
start() {},
|
|
50
|
-
cancel() {
|
|
51
|
-
cancelFn();
|
|
52
|
-
},
|
|
53
|
-
});
|
|
54
|
-
return stream;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const stdout = neverStream();
|
|
58
|
-
const stderr = neverStream();
|
|
59
|
-
|
|
60
|
-
const originalStdoutCancel = stdout.cancel.bind(stdout);
|
|
61
|
-
const originalStderrCancel = stderr.cancel.bind(stderr);
|
|
62
|
-
|
|
63
|
-
// Wrap cancel to track calls
|
|
64
|
-
const trackedStdout = new Proxy(stdout, {
|
|
65
|
-
get(target, prop) {
|
|
66
|
-
if (prop === "cancel") {
|
|
67
|
-
return () => {
|
|
68
|
-
stdoutCancelled.value = true;
|
|
69
|
-
return originalStdoutCancel();
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
return (target as unknown as Record<string | symbol, unknown>)[prop as string | symbol];
|
|
73
|
-
},
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
const trackedStderr = new Proxy(stderr, {
|
|
77
|
-
get(target, prop) {
|
|
78
|
-
if (prop === "cancel") {
|
|
79
|
-
return () => {
|
|
80
|
-
stderrCancelled.value = true;
|
|
81
|
-
return originalStderrCancel();
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
return (target as unknown as Record<string | symbol, unknown>)[prop as string | symbol];
|
|
85
|
-
},
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
const proc = {
|
|
89
|
-
stdout: trackedStdout,
|
|
90
|
-
stderr: trackedStderr,
|
|
91
|
-
exited: new Promise<number>(() => {}), // never resolves
|
|
92
|
-
kill() {
|
|
93
|
-
killCalledAfterCancel.value = stdoutCancelled.value && stderrCancelled.value;
|
|
94
|
-
killCalled.value = true;
|
|
95
|
-
},
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
return { proc, stdoutCancelled, stderrCancelled, killCalled, killCalledAfterCancel };
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// ---------------------------------------------------------------------------
|
|
102
|
-
// Tests
|
|
103
|
-
// ---------------------------------------------------------------------------
|
|
104
|
-
|
|
105
|
-
beforeEach(() => {
|
|
106
|
-
resetLogger();
|
|
107
|
-
initLogger({ level: "error", useChalk: false });
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
afterEach(() => {
|
|
111
|
-
mock.restore();
|
|
112
|
-
resetLogger();
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
describe("BUG-039/BUG-040: stream cleanup on timeout", () => {
|
|
116
|
-
test("kills process on timeout without calling cancel() on locked streams", async () => {
|
|
117
|
-
const { proc, stdoutCancelled, stderrCancelled, killCalled } = makeHangingProc();
|
|
118
|
-
|
|
119
|
-
const originalSpawn = _deps.spawn;
|
|
120
|
-
_deps.spawn = mock(() => proc as PipedProc);
|
|
121
|
-
|
|
122
|
-
const config = makeConfig({ timeoutMs: 30 });
|
|
123
|
-
|
|
124
|
-
const { llmStrategy } = await import("../../../../src/routing/strategies/llm");
|
|
125
|
-
|
|
126
|
-
const story = {
|
|
127
|
-
id: "TEST-001",
|
|
128
|
-
title: "Test story",
|
|
129
|
-
description: "Test",
|
|
130
|
-
acceptanceCriteria: ["AC1"],
|
|
131
|
-
tags: [],
|
|
132
|
-
dependencies: [],
|
|
133
|
-
status: "pending" as const,
|
|
134
|
-
passes: false,
|
|
135
|
-
escalations: [],
|
|
136
|
-
attempts: 0,
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
const startTime = Date.now();
|
|
140
|
-
|
|
141
|
-
await expect(llmStrategy.route(story, { config })).rejects.toThrow(/timeout/i);
|
|
142
|
-
|
|
143
|
-
const elapsed = Date.now() - startTime;
|
|
144
|
-
|
|
145
|
-
// Should resolve promptly — within 500ms of the 30ms timeout
|
|
146
|
-
expect(elapsed).toBeLessThan(500);
|
|
147
|
-
|
|
148
|
-
// BUG-040: cancel() must NOT be called on locked streams — it returns a rejected
|
|
149
|
-
// Promise (per Web Streams spec) which becomes an unhandled rejection crash.
|
|
150
|
-
expect(stdoutCancelled.value).toBe(false);
|
|
151
|
-
expect(stderrCancelled.value).toBe(false);
|
|
152
|
-
expect(killCalled.value).toBe(true);
|
|
153
|
-
|
|
154
|
-
_deps.spawn = originalSpawn;
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
test("no unhandled rejection when Response.text() locks streams and proc is killed", async () => {
|
|
158
|
-
// Simulate the exact BUG-040 scenario:
|
|
159
|
-
// 1. Spawn proc with piped streams
|
|
160
|
-
// 2. Response(proc.stdout).text() locks the streams
|
|
161
|
-
// 3. Timeout fires, proc.kill() called
|
|
162
|
-
// 4. No unhandled rejection should occur
|
|
163
|
-
|
|
164
|
-
const unhandledRejections: Error[] = [];
|
|
165
|
-
const handler = (event: PromiseRejectionEvent) => {
|
|
166
|
-
unhandledRejections.push(event.reason as Error);
|
|
167
|
-
event.preventDefault();
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
// biome-ignore lint/suspicious/noGlobalAssign: test-only override
|
|
171
|
-
globalThis.addEventListener("unhandledrejection", handler);
|
|
172
|
-
|
|
173
|
-
// Create a proc where streams are locked by Response readers
|
|
174
|
-
const stdout = new ReadableStream({ start() {} });
|
|
175
|
-
const stderr = new ReadableStream({ start() {} });
|
|
176
|
-
const proc = {
|
|
177
|
-
stdout,
|
|
178
|
-
stderr,
|
|
179
|
-
exited: new Promise<number>(() => {}),
|
|
180
|
-
kill: mock(() => {}),
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
const originalSpawn = _deps.spawn;
|
|
184
|
-
_deps.spawn = mock(() => proc as PipedProc);
|
|
185
|
-
|
|
186
|
-
const config = makeConfig({ timeoutMs: 20, retries: 0 });
|
|
187
|
-
|
|
188
|
-
const { llmStrategy } = await import("../../../../src/routing/strategies/llm");
|
|
189
|
-
const story = {
|
|
190
|
-
id: "BUG040",
|
|
191
|
-
title: "Bug test",
|
|
192
|
-
description: "Test",
|
|
193
|
-
acceptanceCriteria: ["AC1"],
|
|
194
|
-
tags: [],
|
|
195
|
-
dependencies: [],
|
|
196
|
-
status: "pending" as const,
|
|
197
|
-
passes: false,
|
|
198
|
-
escalations: [],
|
|
199
|
-
attempts: 0,
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
await expect(llmStrategy.route(story, { config })).rejects.toThrow(/timeout/i);
|
|
203
|
-
|
|
204
|
-
// Give microtasks time to settle
|
|
205
|
-
await Bun.sleep(50);
|
|
206
|
-
|
|
207
|
-
globalThis.removeEventListener("unhandledrejection", handler);
|
|
208
|
-
_deps.spawn = originalSpawn;
|
|
209
|
-
|
|
210
|
-
// No unhandled rejections should have occurred
|
|
211
|
-
expect(unhandledRejections).toHaveLength(0);
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
test("clearTimeout is called on success path (no resource leak)", async () => {
|
|
215
|
-
const originalSpawn = _deps.spawn;
|
|
216
|
-
|
|
217
|
-
// proc that resolves immediately with valid output
|
|
218
|
-
const successProc = {
|
|
219
|
-
stdout: new ReadableStream({
|
|
220
|
-
start(ctrl) {
|
|
221
|
-
ctrl.enqueue(
|
|
222
|
-
new TextEncoder().encode(
|
|
223
|
-
JSON.stringify({
|
|
224
|
-
complexity: "simple",
|
|
225
|
-
modelTier: "fast",
|
|
226
|
-
testStrategy: "test-after",
|
|
227
|
-
reasoning: "Simple test story",
|
|
228
|
-
}),
|
|
229
|
-
),
|
|
230
|
-
);
|
|
231
|
-
ctrl.close();
|
|
232
|
-
},
|
|
233
|
-
}),
|
|
234
|
-
stderr: new ReadableStream({
|
|
235
|
-
start(ctrl) {
|
|
236
|
-
ctrl.close();
|
|
237
|
-
},
|
|
238
|
-
}),
|
|
239
|
-
exited: Promise.resolve(0),
|
|
240
|
-
kill: mock(() => {}),
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
_deps.spawn = mock(() => successProc as PipedProc);
|
|
244
|
-
|
|
245
|
-
const config = makeConfig({ timeoutMs: 5000 });
|
|
246
|
-
|
|
247
|
-
const { llmStrategy, clearCache } = await import("../../../../src/routing/strategies/llm");
|
|
248
|
-
clearCache();
|
|
249
|
-
|
|
250
|
-
const story = {
|
|
251
|
-
id: "TEST-002",
|
|
252
|
-
title: "Add login button",
|
|
253
|
-
description: "Simple button feature",
|
|
254
|
-
acceptanceCriteria: ["Button renders"],
|
|
255
|
-
tags: [],
|
|
256
|
-
dependencies: [],
|
|
257
|
-
status: "pending" as const,
|
|
258
|
-
passes: false,
|
|
259
|
-
escalations: [],
|
|
260
|
-
attempts: 0,
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
const result = await llmStrategy.route(story, { config });
|
|
264
|
-
|
|
265
|
-
expect(result).not.toBeNull();
|
|
266
|
-
expect(result?.complexity).toBe("simple");
|
|
267
|
-
// kill() must NOT be called on the success path
|
|
268
|
-
expect(successProc.kill).not.toHaveBeenCalled();
|
|
269
|
-
|
|
270
|
-
_deps.spawn = originalSpawn;
|
|
271
|
-
clearCache();
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
test("timeout promise rejects and does not hang beyond timeout window", async () => {
|
|
275
|
-
const originalSpawn = _deps.spawn;
|
|
276
|
-
const { proc } = makeHangingProc();
|
|
277
|
-
|
|
278
|
-
_deps.spawn = mock(() => proc as PipedProc);
|
|
279
|
-
|
|
280
|
-
const config = makeConfig({ timeoutMs: 50, retries: 0 });
|
|
281
|
-
|
|
282
|
-
const { llmStrategy } = await import("../../../../src/routing/strategies/llm");
|
|
283
|
-
|
|
284
|
-
const story = {
|
|
285
|
-
id: "TEST-003",
|
|
286
|
-
title: "Hanging story",
|
|
287
|
-
description: "This will hang",
|
|
288
|
-
acceptanceCriteria: ["AC"],
|
|
289
|
-
tags: [],
|
|
290
|
-
dependencies: [],
|
|
291
|
-
status: "pending" as const,
|
|
292
|
-
passes: false,
|
|
293
|
-
escalations: [],
|
|
294
|
-
attempts: 0,
|
|
295
|
-
};
|
|
296
|
-
|
|
297
|
-
const before = Date.now();
|
|
298
|
-
await expect(llmStrategy.route(story, { config })).rejects.toThrow();
|
|
299
|
-
const after = Date.now();
|
|
300
|
-
|
|
301
|
-
// Should complete well under 2s even though proc never exits
|
|
302
|
-
expect(after - before).toBeLessThan(2000);
|
|
303
|
-
|
|
304
|
-
_deps.spawn = originalSpawn;
|
|
305
|
-
});
|
|
306
|
-
});
|