@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,125 @@
|
|
|
1
|
+
# Fix Plan: Configurable LLM Routing Mode
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-02-21
|
|
4
|
+
**Branch:** `feat/v0.9-routing-mode`
|
|
5
|
+
**Issue:** #2
|
|
6
|
+
**Base:** `master` (`b459e9f`)
|
|
7
|
+
|
|
8
|
+
## Context
|
|
9
|
+
|
|
10
|
+
Current `batchMode: boolean` is a binary on/off. Issue #2 replaces it with
|
|
11
|
+
`mode: "one-shot" | "per-story" | "hybrid"` for fine-grained control.
|
|
12
|
+
|
|
13
|
+
**Mode semantics:**
|
|
14
|
+
- `one-shot`: batch-route ALL pending stories once at run start. If a story
|
|
15
|
+
is missing from cache at execution time, use keyword fallback (no new LLM call).
|
|
16
|
+
Minimises Claude sessions spawned (1 total). Eliminates hook noise.
|
|
17
|
+
- `per-story`: route each story individually just before execution.
|
|
18
|
+
Current behaviour when `batchMode: false`. Max LLM calls = N stories.
|
|
19
|
+
- `hybrid` (DEFAULT): batch-route upfront like one-shot, but on story
|
|
20
|
+
retry/failure, re-route that story individually. Best quality + cost balance.
|
|
21
|
+
|
|
22
|
+
**Problem solved:** With LLM routing, Run H spawned 9+ separate Claude sessions
|
|
23
|
+
for routing (one per story) causing hook noise and extra cost. One-shot or hybrid
|
|
24
|
+
reduces this to 1 batch call.
|
|
25
|
+
|
|
26
|
+
## Phase 1: Config Schema
|
|
27
|
+
|
|
28
|
+
### Fix 1.1: Replace batchMode with mode enum
|
|
29
|
+
**File:** `src/config/schema.ts`
|
|
30
|
+
**Change:**
|
|
31
|
+
- In `LlmRoutingConfig` interface: remove `batchMode?: boolean`, add `mode?: "one-shot" | "per-story" | "hybrid"`
|
|
32
|
+
- In Zod schema: replace `batchMode: z.boolean().optional()` with
|
|
33
|
+
`mode: z.enum(["one-shot", "per-story", "hybrid"]).optional()`
|
|
34
|
+
- Default value: `"hybrid"` (applied in defaults/config resolver)
|
|
35
|
+
|
|
36
|
+
### Fix 1.2: Update config defaults
|
|
37
|
+
**File:** `src/config/defaults.ts` (or wherever defaults are set)
|
|
38
|
+
**Change:** Set `routing.llm.mode` default to `"hybrid"`.
|
|
39
|
+
|
|
40
|
+
### Fix 1.3: Backward compat shim
|
|
41
|
+
**File:** `src/config/resolver.ts` (or schema.ts transform)
|
|
42
|
+
**Change:** If old `batchMode: true` is present, map to `mode: "one-shot"`.
|
|
43
|
+
If `batchMode: false`, map to `mode: "per-story"`. Log deprecation warning.
|
|
44
|
+
|
|
45
|
+
**Commit:** `feat(config): replace routing.llm.batchMode with routing.llm.mode enum`
|
|
46
|
+
|
|
47
|
+
## Phase 2: LLM Strategy — One-Shot Strict Cache
|
|
48
|
+
|
|
49
|
+
### Fix 2.1: Add one-shot cache-miss behaviour
|
|
50
|
+
**File:** `src/routing/strategies/llm.ts`
|
|
51
|
+
**Change:** In `llmStrategy.route()` (the per-story routing call), check if mode
|
|
52
|
+
is `one-shot`. If so and the story is NOT in cache → return keyword fallback
|
|
53
|
+
result immediately without making a new LLM call.
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
// In llmStrategy.route()
|
|
57
|
+
if (config.routing.llm?.mode === "one-shot" && cachedDecisions.has(story.id)) {
|
|
58
|
+
return cachedDecisions.get(story.id)!;
|
|
59
|
+
}
|
|
60
|
+
if (config.routing.llm?.mode === "one-shot") {
|
|
61
|
+
// Cache miss in one-shot mode — fall back to keyword, no new LLM call
|
|
62
|
+
return keywordStrategy.route(context);
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Fix 2.2: Export mode helper
|
|
67
|
+
**File:** `src/routing/strategies/llm.ts`
|
|
68
|
+
**Change:** Add `getCacheSize(): number` export for test verification.
|
|
69
|
+
|
|
70
|
+
**Commit:** `feat(routing): one-shot mode skips per-story LLM calls on cache miss`
|
|
71
|
+
|
|
72
|
+
## Phase 3: Runner — Wire Mode to Batch Trigger
|
|
73
|
+
|
|
74
|
+
### Fix 3.1: Update tryLlmBatchRoute guard
|
|
75
|
+
**File:** `src/execution/runner.ts`
|
|
76
|
+
**Change:** Replace the `batchMode` guard with mode check:
|
|
77
|
+
```typescript
|
|
78
|
+
// OLD:
|
|
79
|
+
if (config.routing.strategy !== "llm" || !config.routing.llm?.batchMode ...) return;
|
|
80
|
+
// NEW:
|
|
81
|
+
const mode = config.routing.llm?.mode ?? "hybrid";
|
|
82
|
+
if (config.routing.strategy !== "llm" || mode === "per-story" ...) return;
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Fix 3.2: Hybrid re-route on failure
|
|
86
|
+
**File:** `src/execution/runner.ts`
|
|
87
|
+
**Change:** In story retry logic, when mode is `hybrid` and story failed:
|
|
88
|
+
- Call `llmRouteBatch([story], ...)` to re-route just that story
|
|
89
|
+
- This invalidates and refreshes its cache entry before the next attempt
|
|
90
|
+
Look for where stories are retried (error handling after agent run) and inject the re-route call.
|
|
91
|
+
|
|
92
|
+
### Fix 3.3: Log mode at run start
|
|
93
|
+
**File:** `src/execution/runner.ts`
|
|
94
|
+
**Change:** In the run-start logging block, include `routingMode` in the log entry.
|
|
95
|
+
|
|
96
|
+
**Commit:** `feat(runner): wire routing mode to batch trigger and hybrid re-route`
|
|
97
|
+
|
|
98
|
+
## Phase 4: Tests
|
|
99
|
+
|
|
100
|
+
### Fix 4.1: Config schema tests
|
|
101
|
+
**Change:** Test `mode` enum is accepted (`one-shot`, `per-story`, `hybrid`).
|
|
102
|
+
Test backward compat: `batchMode: true` → `mode: "one-shot"`.
|
|
103
|
+
Test default is `"hybrid"`.
|
|
104
|
+
|
|
105
|
+
### Fix 4.2: LLM strategy tests
|
|
106
|
+
**Change:** Test one-shot mode: after `routeBatch()`, a cache-miss story returns
|
|
107
|
+
keyword fallback without making another LLM call.
|
|
108
|
+
Test per-story mode: each story triggers individual LLM call.
|
|
109
|
+
Test hybrid: upfront batch + per-story call on cache miss.
|
|
110
|
+
|
|
111
|
+
### Fix 4.3: Runner integration tests (if any)
|
|
112
|
+
**Change:** Verify `tryLlmBatchRoute` is called on `one-shot`/`hybrid` but not `per-story`.
|
|
113
|
+
|
|
114
|
+
**Commit:** `test: add tests for routing mode config and one-shot/hybrid behaviour`
|
|
115
|
+
|
|
116
|
+
## Test Strategy
|
|
117
|
+
- Mode: test-after
|
|
118
|
+
- Run `bun test` after each phase
|
|
119
|
+
- Backward compat: existing configs with `batchMode: true` must still work
|
|
120
|
+
|
|
121
|
+
## Commits
|
|
122
|
+
1. `feat(config): replace routing.llm.batchMode with routing.llm.mode enum`
|
|
123
|
+
2. `feat(routing): one-shot mode skips per-story LLM calls on cache miss`
|
|
124
|
+
3. `feat(runner): wire routing mode to batch trigger and hybrid re-route`
|
|
125
|
+
4. `test: add tests for routing mode config and one-shot/hybrid behaviour`
|
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
# v0.9 Implementation Review
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-02-21
|
|
4
|
+
**Reviewer:** code-reviewer agent (Opus 4.6)
|
|
5
|
+
**Branches:** `feat/v0.9-relevantfiles-split` (Issue #1), `feat/v0.9-routing-mode` (Issue #2)
|
|
6
|
+
**Test Status:** 710 pass, 2 skip, 6 fail (out of 718). All failures are pre-existing.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Overall Grade: B+ (84/100)
|
|
11
|
+
|
|
12
|
+
| Category | Score | Max | Notes |
|
|
13
|
+
|--------------------|-------|-----|--------------------------------------------------|
|
|
14
|
+
| Security | 18 | 20 | No injection risks. Minor: mutation of raw config object in compat shim. |
|
|
15
|
+
| Reliability | 16 | 20 | Global config compat shim missing. Edge case with empty array fallback well-handled. |
|
|
16
|
+
| API Design | 18 | 20 | Clean resolver pattern. `LlmRoutingMode` enum well-designed. Minor JSDoc gap in `classifier.ts` bridge. |
|
|
17
|
+
| Code Quality | 16 | 20 | Good test coverage. `runner.ts` at 921 lines (exceeds 800 guideline). Mutation in `applyCachedRouting`. |
|
|
18
|
+
| Best Practices | 16 | 20 | Bun-native APIs used throughout. Immutability violated in 2 places. LLM prompt not updated in classifier. |
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Findings
|
|
23
|
+
|
|
24
|
+
### CRITICAL
|
|
25
|
+
|
|
26
|
+
None.
|
|
27
|
+
|
|
28
|
+
### HIGH
|
|
29
|
+
|
|
30
|
+
#### [HIGH-1] `applyBatchModeCompat` not applied to global config
|
|
31
|
+
**File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/config/loader.ts:99-102`
|
|
32
|
+
**Branch:** `feat/v0.9-routing-mode`
|
|
33
|
+
|
|
34
|
+
The backward compatibility shim `applyBatchModeCompat()` is called on `projConf` (line 111) but NOT on `globalConf` (line 100-101). If a user has `routing.llm.batchMode: true` in their global config (`~/.nax/config.json`) but no project config, the shim never runs.
|
|
35
|
+
|
|
36
|
+
After `deepMerge` with defaults (which now set `mode: "hybrid"`), the `"mode" in llm` guard in `applyBatchModeCompat` would prevent mapping even if the shim were called later. But the root issue is that global-only users with `batchMode` will silently get `mode: "hybrid"` from defaults instead of the expected `mode: "one-shot"`.
|
|
37
|
+
|
|
38
|
+
**Impact:** Users with global-only config using deprecated `batchMode: true` will get unexpected routing behavior. Silent behavior change with no deprecation warning.
|
|
39
|
+
|
|
40
|
+
**Fix:**
|
|
41
|
+
```typescript
|
|
42
|
+
// In loadConfig(), after loading global config:
|
|
43
|
+
const globalConf = await loadJsonFile<Record<string, unknown>>(globalConfigPath());
|
|
44
|
+
if (globalConf) {
|
|
45
|
+
applyBatchModeCompat(globalConf); // <-- Add this line
|
|
46
|
+
rawConfig = deepMerge(rawConfig, globalConf);
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
#### [HIGH-2] `applyBatchModeCompat` mutates its argument
|
|
53
|
+
**File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/config/loader.ts:76-91`
|
|
54
|
+
**Branch:** `feat/v0.9-routing-mode`
|
|
55
|
+
|
|
56
|
+
The function mutates the `conf` object in-place (`llm.mode = ...`). While this works because the caller does not reuse the raw config, it violates the project's immutability guideline (from CLAUDE.md: "Immutable patterns -- avoid mutation"). The `deepMerge` function correctly uses spread operators; the compat shim should follow the same pattern.
|
|
57
|
+
|
|
58
|
+
**Impact:** Low immediate risk (caller does not reuse), but sets a bad precedent and makes the code harder to reason about. Could cause subtle bugs if `loadConfig` is refactored to reuse partial configs.
|
|
59
|
+
|
|
60
|
+
**Fix:**
|
|
61
|
+
Return a new object instead of mutating, or document the intentional mutation:
|
|
62
|
+
```typescript
|
|
63
|
+
function applyBatchModeCompat(conf: Record<string, unknown>): Record<string, unknown> {
|
|
64
|
+
const routing = conf.routing as Record<string, unknown> | undefined;
|
|
65
|
+
const llm = routing?.llm as Record<string, unknown> | undefined;
|
|
66
|
+
if (llm && "batchMode" in llm && !("mode" in llm)) {
|
|
67
|
+
const batchMode = llm.batchMode;
|
|
68
|
+
if (typeof batchMode === "boolean") {
|
|
69
|
+
return {
|
|
70
|
+
...conf,
|
|
71
|
+
routing: {
|
|
72
|
+
...routing,
|
|
73
|
+
llm: {
|
|
74
|
+
...llm,
|
|
75
|
+
mode: batchMode ? "one-shot" : "per-story",
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return conf;
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
#### [HIGH-3] `applyCachedRouting` mutates the routing object
|
|
88
|
+
**File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts:77-86`
|
|
89
|
+
**Branch:** `feat/v0.9-routing-mode` (pre-existing, but worsened by new code paths)
|
|
90
|
+
|
|
91
|
+
The function directly mutates `routing.complexity`, `routing.modelTier`, and `routing.testStrategy`. This is called from the main loop and the routing object is reused as `pipelineContext.routing`. If any downstream code assumes the routing object is the original from `routeTask()`, it will get incorrect values.
|
|
92
|
+
|
|
93
|
+
**Impact:** The mutation is currently "safe" because the routing object is scoped to a single iteration, but it makes the code fragile. The new hybrid re-route call at line 340 uses the `story` object (not the routing), so no immediate bug, but the pattern is error-prone.
|
|
94
|
+
|
|
95
|
+
**Fix:**
|
|
96
|
+
```typescript
|
|
97
|
+
function applyCachedRouting(
|
|
98
|
+
routing: ReturnType<typeof routeTask>,
|
|
99
|
+
story: UserStory,
|
|
100
|
+
config: NaxConfig
|
|
101
|
+
): ReturnType<typeof routeTask> {
|
|
102
|
+
if (!story.routing) return routing;
|
|
103
|
+
return {
|
|
104
|
+
...routing,
|
|
105
|
+
...(story.routing.complexity && {
|
|
106
|
+
complexity: story.routing.complexity,
|
|
107
|
+
modelTier: config.autoMode.complexityRouting[story.routing.complexity] ?? "balanced",
|
|
108
|
+
}),
|
|
109
|
+
...(story.routing.testStrategy && {
|
|
110
|
+
testStrategy: story.routing.testStrategy,
|
|
111
|
+
}),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
### MEDIUM
|
|
119
|
+
|
|
120
|
+
#### [MED-1] `runner.ts` exceeds 800-line file size limit (921 lines)
|
|
121
|
+
**File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts`
|
|
122
|
+
**Branch:** `feat/v0.9-routing-mode` (pre-existing, worsened by +12 lines)
|
|
123
|
+
|
|
124
|
+
The file was already at 909 lines before this change. The new routing mode code adds 12 more lines (two `tryLlmBatchRoute` calls and `routingMode` variable). The CLAUDE.md guidelines state "200-400 lines typical, 800 max per file." This file is now 15% over limit.
|
|
125
|
+
|
|
126
|
+
**Impact:** Reduced readability and maintainability. The acceptance retry loop (lines 669-853) alone is ~184 lines and could be extracted.
|
|
127
|
+
|
|
128
|
+
**Fix:** Extract the acceptance retry loop into `src/execution/acceptance-runner.ts`. This is already identified as STYLE-1 in the project backlog.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
#### [MED-2] LLM prompt in classifier still uses `relevantFiles` instead of `contextFiles`
|
|
133
|
+
**File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/analyze/classifier.ts:217`
|
|
134
|
+
**Branch:** `feat/v0.9-relevantfiles-split`
|
|
135
|
+
|
|
136
|
+
The LLM prompt template still instructs the model to output `"relevantFiles"` in its JSON response. The parser correctly maps `rawItem.relevantFiles` to `contextFiles`, creating an implicit bridge. However:
|
|
137
|
+
1. This bridge is undocumented -- a future developer may update the prompt without updating the parser or vice versa.
|
|
138
|
+
2. The raw JSON type at line 21 still declares `relevantFiles: unknown`, not `contextFiles`.
|
|
139
|
+
|
|
140
|
+
**Impact:** Confusion for future maintainers. If someone updates the prompt to use `contextFiles`, the parser will break (it reads `rawItem.relevantFiles`).
|
|
141
|
+
|
|
142
|
+
**Fix:** Either:
|
|
143
|
+
- (a) Update the prompt to output `contextFiles` and update the parser accordingly.
|
|
144
|
+
- (b) Add a code comment documenting the intentional bridge: `// BRIDGE: LLM prompt outputs "relevantFiles", mapped to contextFiles here. Update both together.`
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
#### [MED-3] LLM prompt in `claude.ts` agent updated but no backward compat for existing LLM outputs
|
|
149
|
+
**File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/agents/claude.ts:538-541`
|
|
150
|
+
**Branch:** `feat/v0.9-relevantfiles-split`
|
|
151
|
+
|
|
152
|
+
The `decompose()` method now reads `item.contextFiles` from the LLM response. If an older cached LLM response or a different LLM version outputs `relevantFiles`, the parser will set `contextFiles: []` (empty array from the `Array.isArray` fallback). The `getContextFiles()` resolver would then return `[]` instead of falling back to `relevantFiles`.
|
|
153
|
+
|
|
154
|
+
**Impact:** Context injection silently breaks for any LLM response that uses the old field name. The probability is low since decompose is called interactively, but if responses are cached or replayed, context will be lost.
|
|
155
|
+
|
|
156
|
+
**Fix:** Parse both fields with fallback:
|
|
157
|
+
```typescript
|
|
158
|
+
contextFiles: Array.isArray(item.contextFiles)
|
|
159
|
+
? item.contextFiles
|
|
160
|
+
: Array.isArray(item.relevantFiles)
|
|
161
|
+
? item.relevantFiles
|
|
162
|
+
: [],
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
#### [MED-4] Module-level mutable cache (`cachedDecisions`) with no eviction policy
|
|
168
|
+
**File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/routing/strategies/llm.ts:16`
|
|
169
|
+
**Branch:** `feat/v0.9-routing-mode` (pre-existing, now more relevant due to one-shot mode reliance on cache)
|
|
170
|
+
|
|
171
|
+
The `cachedDecisions` Map grows without bound during a run. For one-shot mode, the cache is the primary data store -- if it is cleared unexpectedly (e.g., module reload in watch mode), all subsequent stories fall back to keyword routing.
|
|
172
|
+
|
|
173
|
+
**Impact:** Memory accumulation for very large PRDs. More importantly, one-shot mode's correctness depends on cache integrity.
|
|
174
|
+
|
|
175
|
+
**Fix:** Add a `maxCacheSize` guard or LRU eviction. Document the cache's role in one-shot mode.
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
#### [MED-5] `batchMode: false` + `mode: "one-shot"` conflict not validated
|
|
180
|
+
**File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/config/schema.ts:458-465`
|
|
181
|
+
**Branch:** `feat/v0.9-routing-mode`
|
|
182
|
+
|
|
183
|
+
A user can set both `batchMode: false` and `mode: "one-shot"` in their config. The compat shim only maps `batchMode` when `mode` is absent (guard: `!("mode" in llm)`), so when both are set, `mode` wins. But there is no validation warning for the contradictory combination. This can confuse users during migration.
|
|
184
|
+
|
|
185
|
+
**Impact:** User confusion. `batchMode: false` semantically means "don't batch" but `mode: "one-shot"` means "batch everything once." No error or warning.
|
|
186
|
+
|
|
187
|
+
**Fix:** Add a Zod `.refine()` to warn when both fields are set with contradictory values:
|
|
188
|
+
```typescript
|
|
189
|
+
const LlmRoutingConfigSchema = z.object({
|
|
190
|
+
// ...existing fields
|
|
191
|
+
}).refine((data) => {
|
|
192
|
+
if (data.batchMode !== undefined && data.mode !== undefined) {
|
|
193
|
+
// Both set - check for contradiction
|
|
194
|
+
const implied = data.batchMode ? "one-shot" : "per-story";
|
|
195
|
+
if (implied !== data.mode) {
|
|
196
|
+
// Could log warning here
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return true;
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
#### [MED-6] Duplicate log lines in iteration start
|
|
206
|
+
**File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts:385-403`
|
|
207
|
+
**Branch:** `feat/v0.9-routing-mode` (pre-existing)
|
|
208
|
+
|
|
209
|
+
Lines 385-392 log `"Starting iteration N"` with event name `"execution"`, and lines 395-403 log the same message with event name `"iteration.start"`. Both contain overlapping data. This was pre-existing but is worth noting as it inflates structured log output.
|
|
210
|
+
|
|
211
|
+
**Impact:** Log noise. JSONL log files contain two near-identical entries per iteration.
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
### LOW
|
|
216
|
+
|
|
217
|
+
#### [LOW-1] `getCacheSize()` exposed for testing only
|
|
218
|
+
**File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/routing/strategies/llm.ts:24-26`
|
|
219
|
+
**Branch:** `feat/v0.9-routing-mode`
|
|
220
|
+
|
|
221
|
+
The function is exported solely for testing (`/** Get the current cache size (for testing) */`). While harmless, it widens the public API surface for a test utility. Consider using Bun's test mocking or accessing the cache through the module's test exports pattern instead.
|
|
222
|
+
|
|
223
|
+
**Impact:** Negligible. Minor API surface bloat.
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
#### [LOW-2] `fix-generator.ts` uses `contextFiles: []` instead of leaving field undefined
|
|
228
|
+
**File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/acceptance/fix-generator.ts:361`
|
|
229
|
+
**Branch:** `feat/v0.9-relevantfiles-split`
|
|
230
|
+
|
|
231
|
+
Setting `contextFiles: []` explicitly means `getContextFiles()` returns `[]` even if a parent process later sets `relevantFiles` on the story. This is technically correct (fix stories should not inherit context from parent stories), but the behavior depends on `[]` being truthy for `??` -- which is correct in JavaScript but could confuse developers unfamiliar with nullish coalescing semantics.
|
|
232
|
+
|
|
233
|
+
**Impact:** Negligible. Behavior is correct.
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
#### [LOW-3] Missing JSDoc on `LlmRoutingMode` type
|
|
238
|
+
**File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/config/schema.ts:233-234`
|
|
239
|
+
**Branch:** `feat/v0.9-routing-mode`
|
|
240
|
+
|
|
241
|
+
The type has a one-line comment (`/** LLM routing mode */`) but no documentation of what each enum value means. The detailed documentation is on the `mode` field in `LlmRoutingConfig`, but the type itself should also document its values for consumers who import it directly.
|
|
242
|
+
|
|
243
|
+
**Impact:** Minor developer experience issue.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
#### [LOW-4] Test file backs up and restores global config
|
|
248
|
+
**File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/test/config-loader.test.ts:30-39`
|
|
249
|
+
**Branch:** `feat/v0.9-routing-mode`
|
|
250
|
+
|
|
251
|
+
The test manipulates the real global config at `~/.nax/config.json` using rename+restore. While the cleanup is in `afterEach`, a crash between backup and restore could leave the user's config in a broken state. Consider using a mock or environment variable to redirect the config path during tests.
|
|
252
|
+
|
|
253
|
+
**Impact:** Test safety. If test runner crashes, user's global config is a backup file.
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
#### [LOW-5] Two empty lines between `deepMerge` and `applyBatchModeCompat`
|
|
258
|
+
**File:** `/Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/config/loader.ts:73-74`
|
|
259
|
+
**Branch:** `feat/v0.9-routing-mode`
|
|
260
|
+
|
|
261
|
+
Minor formatting inconsistency -- double blank line where the rest of the file uses single blank lines between functions.
|
|
262
|
+
|
|
263
|
+
**Impact:** Cosmetic.
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## Backward Compatibility Assessment
|
|
268
|
+
|
|
269
|
+
### Branch 1: `feat/v0.9-relevantfiles-split`
|
|
270
|
+
|
|
271
|
+
| Scenario | Behavior | Correct? |
|
|
272
|
+
|----------|----------|----------|
|
|
273
|
+
| `contextFiles` set, `relevantFiles` unset | Uses `contextFiles` for context | Yes |
|
|
274
|
+
| `contextFiles` unset, `relevantFiles` set | Falls back to `relevantFiles` for context | Yes |
|
|
275
|
+
| Both `contextFiles` and `relevantFiles` set | Prefers `contextFiles` (nullish coalescing) | Yes |
|
|
276
|
+
| Neither set | Returns empty array | Yes |
|
|
277
|
+
| `expectedFiles` set | Uses for asset verification | Yes |
|
|
278
|
+
| `expectedFiles` unset, `relevantFiles` set | Returns empty array (no fallback) | Yes, by design |
|
|
279
|
+
| `expectedFiles: []` | Returns empty array (skips verification) | Yes |
|
|
280
|
+
| LLM outputs `relevantFiles` in classify response | Mapped to `contextFiles` via bridge | Yes, but undocumented (MED-2) |
|
|
281
|
+
| LLM outputs `relevantFiles` in decompose response | **Silently drops data** | No (MED-3) |
|
|
282
|
+
|
|
283
|
+
### Branch 2: `feat/v0.9-routing-mode`
|
|
284
|
+
|
|
285
|
+
| Scenario | Behavior | Correct? |
|
|
286
|
+
|----------|----------|----------|
|
|
287
|
+
| `mode: "one-shot"` | Batch upfront, keyword fallback on miss | Yes |
|
|
288
|
+
| `mode: "per-story"` | Individual LLM call per story | Yes |
|
|
289
|
+
| `mode: "hybrid"` | Batch upfront + re-route on escalation | Yes |
|
|
290
|
+
| `mode` unset | Defaults to `"hybrid"` | Yes |
|
|
291
|
+
| `batchMode: true`, `mode` unset (project config) | Maps to `mode: "one-shot"` | Yes |
|
|
292
|
+
| `batchMode: false`, `mode` unset (project config) | Maps to `mode: "per-story"` | Yes |
|
|
293
|
+
| `batchMode: true`, `mode: "per-story"` | `mode` wins (explicit takes precedence) | Yes |
|
|
294
|
+
| `batchMode: true`, `mode` unset (global config only) | **Silently ignored, gets "hybrid"** | No (HIGH-1) |
|
|
295
|
+
| `batchMode: "yes"` (invalid type) | Zod validation rejects | Yes |
|
|
296
|
+
| `mode: "ultra-batch"` (invalid value) | Zod validation rejects | Yes |
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## Test Coverage Assessment
|
|
301
|
+
|
|
302
|
+
### Branch 1: `feat/v0.9-relevantfiles-split`
|
|
303
|
+
|
|
304
|
+
| Test File | Tests Added | Coverage |
|
|
305
|
+
|-----------|-------------|----------|
|
|
306
|
+
| `test/prd-resolvers.test.ts` | 12 tests | Excellent: covers all fallback/precedence combinations |
|
|
307
|
+
| `test/verification-asset-check.test.ts` | 9 tests | Excellent: covers opt-in semantics, legacy compat, dogfood scenarios |
|
|
308
|
+
| `test/context-verification-integration.test.ts` | 6 tests | Good: end-to-end with temp files |
|
|
309
|
+
| `test/context-integration.test.ts` | 3 tests added | Good: contextFiles, relevantFiles fallback, no-files |
|
|
310
|
+
| `test/context.test.ts` | 3 tests added, 6 updated | Good: preference, fallback, limits |
|
|
311
|
+
| `test/analyze-classifier.test.ts` | 1 updated | Adequate |
|
|
312
|
+
|
|
313
|
+
**Missing coverage:**
|
|
314
|
+
- No test for the `classifier.ts` bridge pattern where LLM outputs `relevantFiles` and it maps to `contextFiles`
|
|
315
|
+
- No test for `claude.ts` decompose response with old `relevantFiles` field name
|
|
316
|
+
|
|
317
|
+
### Branch 2: `feat/v0.9-routing-mode`
|
|
318
|
+
|
|
319
|
+
| Test File | Tests Added | Coverage |
|
|
320
|
+
|-----------|-------------|----------|
|
|
321
|
+
| `test/config.test.ts` | 6 tests | Good: all three modes + invalid + deprecated |
|
|
322
|
+
| `test/config-loader.test.ts` | 4 tests | Good: compat shim, precedence, invalid type, defaults |
|
|
323
|
+
| `test/routing/llm-strategy.test.ts` | 5 tests | Good: one-shot miss, one-shot hit, per-story, hybrid, default |
|
|
324
|
+
|
|
325
|
+
**Missing coverage:**
|
|
326
|
+
- No test for `batchMode` in global config (HIGH-1)
|
|
327
|
+
- No test for hybrid re-route in `runner.ts` (lines 339-341, 591-593) -- these are integration paths
|
|
328
|
+
- No test for `batchMode: false` mapping to `mode: "per-story"` in isolation (the loader test only covers `batchMode: true`)
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## Logic Correctness
|
|
333
|
+
|
|
334
|
+
### `getContextFiles()` and `getExpectedFiles()` (Branch 1)
|
|
335
|
+
|
|
336
|
+
The semantic split is correct and well-reasoned:
|
|
337
|
+
- **contextFiles** = input to the agent (pre-execution context injection). Falls back to `relevantFiles` because existing PRDs should continue to provide context.
|
|
338
|
+
- **expectedFiles** = output verification gate (post-execution asset check). Does NOT fall back because the old `relevantFiles` field was LLM-generated and unreliable for asset verification (documented in dogfood Run F findings).
|
|
339
|
+
|
|
340
|
+
The `??` (nullish coalescing) operator is the correct choice here. An empty array `[]` is an explicit "no files" signal and should not trigger fallback. This is tested in `test/prd-resolvers.test.ts`.
|
|
341
|
+
|
|
342
|
+
### Routing Mode Logic (Branch 2)
|
|
343
|
+
|
|
344
|
+
The three-mode design is correct:
|
|
345
|
+
|
|
346
|
+
1. **one-shot**: `tryLlmBatchRoute` runs at startup (line 208). On individual `route()`, cache hit returns cached decision; cache miss falls back to `keywordStrategy.route()` without an LLM call (line 380-386). This is cost-optimal for stable PRDs.
|
|
347
|
+
|
|
348
|
+
2. **per-story**: `tryLlmBatchRoute` returns early when `mode === "per-story"` (line 60). Each `route()` call triggers an individual LLM call (lines 388-409). This is quality-optimal for dynamic PRDs.
|
|
349
|
+
|
|
350
|
+
3. **hybrid**: `tryLlmBatchRoute` runs at startup (same as one-shot). On cache miss during `route()`, an individual LLM call is made (same as per-story). On escalation, `tryLlmBatchRoute` is called again for the escalated story (lines 339-341, 591-593). This combines upfront batching with retry precision.
|
|
351
|
+
|
|
352
|
+
The `mode ?? "hybrid"` default is applied consistently in all three locations: `tryLlmBatchRoute` (line 59), `llmStrategy.route` (line 364), and `run()` (line 144).
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
## Priority Fix Order
|
|
357
|
+
|
|
358
|
+
1. **HIGH-1**: Apply `applyBatchModeCompat` to global config -- prevents silent behavior regression for global-config-only users.
|
|
359
|
+
2. **MED-3**: Add fallback for `relevantFiles` in `claude.ts` decompose parser -- prevents data loss from older LLM responses.
|
|
360
|
+
3. **HIGH-2**: Refactor `applyBatchModeCompat` to return new object -- aligns with project immutability guidelines.
|
|
361
|
+
4. **HIGH-3**: Refactor `applyCachedRouting` to return new object -- same rationale.
|
|
362
|
+
5. **MED-2**: Document or fix the classifier bridge pattern -- prevents future maintainer confusion.
|
|
363
|
+
6. **MED-5**: Add validation for contradictory `batchMode` + `mode` combinations.
|
|
364
|
+
7. **MED-1**: Extract acceptance retry loop from `runner.ts` -- file size reduction.
|
|
365
|
+
8. **LOW-4**: Mock global config path in tests instead of manipulating real file.
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## Verdict
|
|
370
|
+
|
|
371
|
+
**Approve with conditions (HIGH issues must be fixed before merge)**
|
|
372
|
+
|
|
373
|
+
The v0.9 changes are well-structured with clear semantics, comprehensive test coverage, and proper backward compatibility design. The resolver function pattern (`getContextFiles`, `getExpectedFiles`) is clean and the three-mode routing enum is well-thought-out.
|
|
374
|
+
|
|
375
|
+
However, three HIGH-priority issues need resolution before merge:
|
|
376
|
+
1. Global config compat shim gap (HIGH-1) is a user-facing regression risk
|
|
377
|
+
2. Two mutation patterns (HIGH-2, HIGH-3) violate project guidelines
|
|
378
|
+
|
|
379
|
+
Once these are fixed, the changes are ready for v0.9.0 release.
|