@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,492 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import {
|
|
7
|
+
VERDICT_FILE,
|
|
8
|
+
type VerifierVerdict,
|
|
9
|
+
categorizeVerdict,
|
|
10
|
+
cleanupVerdict,
|
|
11
|
+
readVerdict,
|
|
12
|
+
} from "../../src/tdd/verdict";
|
|
13
|
+
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Helpers
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
function makeVerdict(overrides: Partial<VerifierVerdict> = {}): VerifierVerdict {
|
|
19
|
+
return {
|
|
20
|
+
version: 1,
|
|
21
|
+
approved: true,
|
|
22
|
+
tests: {
|
|
23
|
+
allPassing: true,
|
|
24
|
+
passCount: 10,
|
|
25
|
+
failCount: 0,
|
|
26
|
+
},
|
|
27
|
+
testModifications: {
|
|
28
|
+
detected: false,
|
|
29
|
+
files: [],
|
|
30
|
+
legitimate: true,
|
|
31
|
+
reasoning: "No test files modified",
|
|
32
|
+
},
|
|
33
|
+
acceptanceCriteria: {
|
|
34
|
+
allMet: true,
|
|
35
|
+
criteria: [{ criterion: "It works", met: true }],
|
|
36
|
+
},
|
|
37
|
+
quality: {
|
|
38
|
+
rating: "good",
|
|
39
|
+
issues: [],
|
|
40
|
+
},
|
|
41
|
+
fixes: [],
|
|
42
|
+
reasoning: "All good.",
|
|
43
|
+
...overrides,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function writeVerdictFile(workdir: string, content: unknown): Promise<void> {
|
|
48
|
+
const filePath = path.join(workdir, VERDICT_FILE);
|
|
49
|
+
await writeFile(filePath, JSON.stringify(content, null, 2), "utf-8");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Setup: temp directories per test group
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
let tmpDir: string;
|
|
57
|
+
|
|
58
|
+
beforeEach(async () => {
|
|
59
|
+
tmpDir = await Bun.file(os.tmpdir())
|
|
60
|
+
.exists()
|
|
61
|
+
.then(() => `${os.tmpdir()}/nax-verdict-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
62
|
+
await mkdir(tmpDir, { recursive: true });
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
afterEach(async () => {
|
|
66
|
+
await rm(tmpDir, { recursive: true, force: true });
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// readVerdict
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
|
|
73
|
+
describe("readVerdict", () => {
|
|
74
|
+
test("returns parsed verdict when file exists and is valid", async () => {
|
|
75
|
+
const verdict = makeVerdict();
|
|
76
|
+
await writeVerdictFile(tmpDir, verdict);
|
|
77
|
+
|
|
78
|
+
const result = await readVerdict(tmpDir);
|
|
79
|
+
expect(result).not.toBeNull();
|
|
80
|
+
expect(result!.version).toBe(1);
|
|
81
|
+
expect(result!.approved).toBe(true);
|
|
82
|
+
expect(result!.tests.allPassing).toBe(true);
|
|
83
|
+
expect(result!.tests.passCount).toBe(10);
|
|
84
|
+
expect(result!.tests.failCount).toBe(0);
|
|
85
|
+
expect(result!.reasoning).toBe("All good.");
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test("returns null when verdict file does not exist (no throw)", async () => {
|
|
89
|
+
// No file written — directory is empty
|
|
90
|
+
const result = await readVerdict(tmpDir);
|
|
91
|
+
expect(result).toBeNull();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("returns null when verdict file does not exist for non-existent dir", async () => {
|
|
95
|
+
const result = await readVerdict("/tmp/this-dir-does-not-exist-xyz-nax");
|
|
96
|
+
expect(result).toBeNull();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test("returns null when JSON is malformed (no throw)", async () => {
|
|
100
|
+
const filePath = path.join(tmpDir, VERDICT_FILE);
|
|
101
|
+
await writeFile(filePath, "{ this is not valid json }", "utf-8");
|
|
102
|
+
|
|
103
|
+
const result = await readVerdict(tmpDir);
|
|
104
|
+
expect(result).toBeNull();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test("returns null when JSON is truncated (no throw)", async () => {
|
|
108
|
+
const filePath = path.join(tmpDir, VERDICT_FILE);
|
|
109
|
+
await writeFile(filePath, '{"version": 1, "approved": true, "tests":', "utf-8");
|
|
110
|
+
|
|
111
|
+
const result = await readVerdict(tmpDir);
|
|
112
|
+
expect(result).toBeNull();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("returns null when version field is missing", async () => {
|
|
116
|
+
const { version: _v, ...noVersion } = makeVerdict() as any;
|
|
117
|
+
await writeVerdictFile(tmpDir, noVersion);
|
|
118
|
+
|
|
119
|
+
const result = await readVerdict(tmpDir);
|
|
120
|
+
expect(result).toBeNull();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test("returns null when approved field is missing", async () => {
|
|
124
|
+
const data = makeVerdict() as any;
|
|
125
|
+
delete data.approved;
|
|
126
|
+
await writeVerdictFile(tmpDir, data);
|
|
127
|
+
|
|
128
|
+
const result = await readVerdict(tmpDir);
|
|
129
|
+
expect(result).toBeNull();
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test("returns null when tests field is missing", async () => {
|
|
133
|
+
const data = makeVerdict() as any;
|
|
134
|
+
delete data.tests;
|
|
135
|
+
await writeVerdictFile(tmpDir, data);
|
|
136
|
+
|
|
137
|
+
const result = await readVerdict(tmpDir);
|
|
138
|
+
expect(result).toBeNull();
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test("returns null when tests.allPassing is missing", async () => {
|
|
142
|
+
const data = makeVerdict() as any;
|
|
143
|
+
delete data.tests.allPassing;
|
|
144
|
+
await writeVerdictFile(tmpDir, data);
|
|
145
|
+
|
|
146
|
+
const result = await readVerdict(tmpDir);
|
|
147
|
+
expect(result).toBeNull();
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test("returns null when testModifications field is missing", async () => {
|
|
151
|
+
const data = makeVerdict() as any;
|
|
152
|
+
delete data.testModifications;
|
|
153
|
+
await writeVerdictFile(tmpDir, data);
|
|
154
|
+
|
|
155
|
+
const result = await readVerdict(tmpDir);
|
|
156
|
+
expect(result).toBeNull();
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test("returns null when acceptanceCriteria field is missing", async () => {
|
|
160
|
+
const data = makeVerdict() as any;
|
|
161
|
+
delete data.acceptanceCriteria;
|
|
162
|
+
await writeVerdictFile(tmpDir, data);
|
|
163
|
+
|
|
164
|
+
const result = await readVerdict(tmpDir);
|
|
165
|
+
expect(result).toBeNull();
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
test("returns null when quality field is missing", async () => {
|
|
169
|
+
const data = makeVerdict() as any;
|
|
170
|
+
delete data.quality;
|
|
171
|
+
await writeVerdictFile(tmpDir, data);
|
|
172
|
+
|
|
173
|
+
const result = await readVerdict(tmpDir);
|
|
174
|
+
expect(result).toBeNull();
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
test("returns null when quality.rating is invalid", async () => {
|
|
178
|
+
const data = makeVerdict() as any;
|
|
179
|
+
data.quality.rating = "excellent"; // Not a valid rating
|
|
180
|
+
await writeVerdictFile(tmpDir, data);
|
|
181
|
+
|
|
182
|
+
const result = await readVerdict(tmpDir);
|
|
183
|
+
expect(result).toBeNull();
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
test("returns null when fixes is missing", async () => {
|
|
187
|
+
const data = makeVerdict() as any;
|
|
188
|
+
delete data.fixes;
|
|
189
|
+
await writeVerdictFile(tmpDir, data);
|
|
190
|
+
|
|
191
|
+
const result = await readVerdict(tmpDir);
|
|
192
|
+
expect(result).toBeNull();
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
test("returns null when reasoning is missing", async () => {
|
|
196
|
+
const data = makeVerdict() as any;
|
|
197
|
+
delete data.reasoning;
|
|
198
|
+
await writeVerdictFile(tmpDir, data);
|
|
199
|
+
|
|
200
|
+
const result = await readVerdict(tmpDir);
|
|
201
|
+
expect(result).toBeNull();
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
test("parses verdict with approved=false correctly", async () => {
|
|
205
|
+
const verdict = makeVerdict({
|
|
206
|
+
approved: false,
|
|
207
|
+
tests: { allPassing: false, passCount: 5, failCount: 3 },
|
|
208
|
+
reasoning: "Tests are failing.",
|
|
209
|
+
});
|
|
210
|
+
await writeVerdictFile(tmpDir, verdict);
|
|
211
|
+
|
|
212
|
+
const result = await readVerdict(tmpDir);
|
|
213
|
+
expect(result).not.toBeNull();
|
|
214
|
+
expect(result!.approved).toBe(false);
|
|
215
|
+
expect(result!.tests.failCount).toBe(3);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
test("parses verdict with all quality ratings", async () => {
|
|
219
|
+
for (const rating of ["good", "acceptable", "poor"] as const) {
|
|
220
|
+
const verdict = makeVerdict({ quality: { rating, issues: [] } });
|
|
221
|
+
await writeVerdictFile(tmpDir, verdict);
|
|
222
|
+
|
|
223
|
+
const result = await readVerdict(tmpDir);
|
|
224
|
+
expect(result).not.toBeNull();
|
|
225
|
+
expect(result!.quality.rating).toBe(rating);
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// ---------------------------------------------------------------------------
|
|
231
|
+
// cleanupVerdict
|
|
232
|
+
// ---------------------------------------------------------------------------
|
|
233
|
+
|
|
234
|
+
describe("cleanupVerdict", () => {
|
|
235
|
+
test("deletes the verdict file when it exists", async () => {
|
|
236
|
+
const verdict = makeVerdict();
|
|
237
|
+
await writeVerdictFile(tmpDir, verdict);
|
|
238
|
+
|
|
239
|
+
const filePath = path.join(tmpDir, VERDICT_FILE);
|
|
240
|
+
expect(existsSync(filePath)).toBe(true);
|
|
241
|
+
|
|
242
|
+
await cleanupVerdict(tmpDir);
|
|
243
|
+
expect(existsSync(filePath)).toBe(false);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
test("does not throw when verdict file does not exist", async () => {
|
|
247
|
+
// File doesn't exist — should not throw
|
|
248
|
+
await expect(cleanupVerdict(tmpDir)).resolves.toBeUndefined();
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
test("does not throw when directory does not exist", async () => {
|
|
252
|
+
// Non-existent directory — should not throw
|
|
253
|
+
await expect(cleanupVerdict("/tmp/nonexistent-dir-nax-xyz")).resolves.toBeUndefined();
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
test("can be called multiple times without error", async () => {
|
|
257
|
+
const verdict = makeVerdict();
|
|
258
|
+
await writeVerdictFile(tmpDir, verdict);
|
|
259
|
+
|
|
260
|
+
await cleanupVerdict(tmpDir);
|
|
261
|
+
// Second call — file already deleted
|
|
262
|
+
await expect(cleanupVerdict(tmpDir)).resolves.toBeUndefined();
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
// ---------------------------------------------------------------------------
|
|
267
|
+
// categorizeVerdict
|
|
268
|
+
// ---------------------------------------------------------------------------
|
|
269
|
+
|
|
270
|
+
describe("categorizeVerdict", () => {
|
|
271
|
+
// --- approved=true ---
|
|
272
|
+
|
|
273
|
+
test("approved=true → success", () => {
|
|
274
|
+
const verdict = makeVerdict({ approved: true });
|
|
275
|
+
const result = categorizeVerdict(verdict, false);
|
|
276
|
+
expect(result.success).toBe(true);
|
|
277
|
+
expect(result.failureCategory).toBeUndefined();
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
test("approved=true with failing tests still → success (verifier approved)", () => {
|
|
281
|
+
// Verifier takes precedence — if it says approved, we trust it
|
|
282
|
+
const verdict = makeVerdict({
|
|
283
|
+
approved: true,
|
|
284
|
+
tests: { allPassing: false, passCount: 5, failCount: 2 },
|
|
285
|
+
});
|
|
286
|
+
const result = categorizeVerdict(verdict, false);
|
|
287
|
+
expect(result.success).toBe(true);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// --- illegitimate test modifications ---
|
|
291
|
+
|
|
292
|
+
test("illegitimate test mods → verifier-rejected", () => {
|
|
293
|
+
const verdict = makeVerdict({
|
|
294
|
+
approved: false,
|
|
295
|
+
testModifications: {
|
|
296
|
+
detected: true,
|
|
297
|
+
files: ["test/foo.test.ts"],
|
|
298
|
+
legitimate: false,
|
|
299
|
+
reasoning: "Implementer loosened assertions to mask bugs",
|
|
300
|
+
},
|
|
301
|
+
});
|
|
302
|
+
const result = categorizeVerdict(verdict, true);
|
|
303
|
+
expect(result.success).toBe(false);
|
|
304
|
+
expect(result.failureCategory).toBe("verifier-rejected");
|
|
305
|
+
expect(result.reviewReason).toContain("illegitimate test modifications");
|
|
306
|
+
expect(result.reviewReason).toContain("test/foo.test.ts");
|
|
307
|
+
expect(result.reviewReason).toContain("Implementer loosened assertions");
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
test("detected test mods but legitimate → does NOT categorize as verifier-rejected for that reason", () => {
|
|
311
|
+
const verdict = makeVerdict({
|
|
312
|
+
approved: false,
|
|
313
|
+
testModifications: {
|
|
314
|
+
detected: true,
|
|
315
|
+
files: ["test/foo.test.ts"],
|
|
316
|
+
legitimate: true, // Legitimate — should not trigger verifier-rejected for this reason
|
|
317
|
+
reasoning: "Fixed incorrect test expectations",
|
|
318
|
+
},
|
|
319
|
+
tests: { allPassing: false, passCount: 3, failCount: 2 },
|
|
320
|
+
});
|
|
321
|
+
const result = categorizeVerdict(verdict, false);
|
|
322
|
+
// Falls through to next reason: tests failing
|
|
323
|
+
expect(result.success).toBe(false);
|
|
324
|
+
expect(result.failureCategory).toBe("tests-failing");
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
// --- tests failing ---
|
|
328
|
+
|
|
329
|
+
test("tests failing → tests-failing", () => {
|
|
330
|
+
const verdict = makeVerdict({
|
|
331
|
+
approved: false,
|
|
332
|
+
tests: { allPassing: false, passCount: 4, failCount: 3 },
|
|
333
|
+
reasoning: "Some tests are still failing.",
|
|
334
|
+
});
|
|
335
|
+
const result = categorizeVerdict(verdict, false);
|
|
336
|
+
expect(result.success).toBe(false);
|
|
337
|
+
expect(result.failureCategory).toBe("tests-failing");
|
|
338
|
+
expect(result.reviewReason).toContain("3 failure(s)");
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
// --- acceptance criteria not met ---
|
|
342
|
+
|
|
343
|
+
test("acceptance criteria not met → verifier-rejected", () => {
|
|
344
|
+
const verdict = makeVerdict({
|
|
345
|
+
approved: false,
|
|
346
|
+
tests: { allPassing: true, passCount: 10, failCount: 0 },
|
|
347
|
+
acceptanceCriteria: {
|
|
348
|
+
allMet: false,
|
|
349
|
+
criteria: [
|
|
350
|
+
{ criterion: "Must validate input", met: false, note: "No validation" },
|
|
351
|
+
{ criterion: "Must return 200", met: true },
|
|
352
|
+
],
|
|
353
|
+
},
|
|
354
|
+
});
|
|
355
|
+
const result = categorizeVerdict(verdict, true);
|
|
356
|
+
expect(result.success).toBe(false);
|
|
357
|
+
expect(result.failureCategory).toBe("verifier-rejected");
|
|
358
|
+
expect(result.reviewReason).toContain("Must validate input");
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
// --- poor quality ---
|
|
362
|
+
|
|
363
|
+
test("poor quality → verifier-rejected", () => {
|
|
364
|
+
const verdict = makeVerdict({
|
|
365
|
+
approved: false,
|
|
366
|
+
tests: { allPassing: true, passCount: 10, failCount: 0 },
|
|
367
|
+
acceptanceCriteria: {
|
|
368
|
+
allMet: true,
|
|
369
|
+
criteria: [{ criterion: "Works", met: true }],
|
|
370
|
+
},
|
|
371
|
+
quality: {
|
|
372
|
+
rating: "poor",
|
|
373
|
+
issues: ["SQL injection vulnerability", "No error handling"],
|
|
374
|
+
},
|
|
375
|
+
});
|
|
376
|
+
const result = categorizeVerdict(verdict, true);
|
|
377
|
+
expect(result.success).toBe(false);
|
|
378
|
+
expect(result.failureCategory).toBe("verifier-rejected");
|
|
379
|
+
expect(result.reviewReason).toContain("SQL injection vulnerability");
|
|
380
|
+
expect(result.reviewReason).toContain("No error handling");
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
test("acceptable quality → does not trigger poor-quality rejection", () => {
|
|
384
|
+
const verdict = makeVerdict({
|
|
385
|
+
approved: false,
|
|
386
|
+
tests: { allPassing: true, passCount: 10, failCount: 0 },
|
|
387
|
+
acceptanceCriteria: {
|
|
388
|
+
allMet: true,
|
|
389
|
+
criteria: [{ criterion: "Works", met: true }],
|
|
390
|
+
},
|
|
391
|
+
quality: {
|
|
392
|
+
rating: "acceptable",
|
|
393
|
+
issues: ["Minor style issues"],
|
|
394
|
+
},
|
|
395
|
+
reasoning: "Overall acceptable but not approved for other reason",
|
|
396
|
+
});
|
|
397
|
+
const result = categorizeVerdict(verdict, true);
|
|
398
|
+
// Falls to catch-all
|
|
399
|
+
expect(result.success).toBe(false);
|
|
400
|
+
expect(result.failureCategory).toBe("verifier-rejected");
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
// --- catch-all: not approved without specific categorizable reason ---
|
|
404
|
+
|
|
405
|
+
test("not approved with no specific categorizable reason → verifier-rejected (catch-all)", () => {
|
|
406
|
+
const verdict = makeVerdict({
|
|
407
|
+
approved: false,
|
|
408
|
+
tests: { allPassing: true, passCount: 10, failCount: 0 },
|
|
409
|
+
testModifications: { detected: false, files: [], legitimate: true, reasoning: "None" },
|
|
410
|
+
acceptanceCriteria: { allMet: true, criteria: [{ criterion: "Works", met: true }] },
|
|
411
|
+
quality: { rating: "good", issues: [] },
|
|
412
|
+
reasoning: "Something else is wrong.",
|
|
413
|
+
});
|
|
414
|
+
const result = categorizeVerdict(verdict, true);
|
|
415
|
+
expect(result.success).toBe(false);
|
|
416
|
+
expect(result.failureCategory).toBe("verifier-rejected");
|
|
417
|
+
expect(result.reviewReason).toContain("Something else is wrong.");
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
// --- null verdict fallback ---
|
|
421
|
+
|
|
422
|
+
test("null verdict + testsPass=true → success", () => {
|
|
423
|
+
const result = categorizeVerdict(null, true);
|
|
424
|
+
expect(result.success).toBe(true);
|
|
425
|
+
expect(result.failureCategory).toBeUndefined();
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
test("null verdict + testsPass=false → tests-failing", () => {
|
|
429
|
+
const result = categorizeVerdict(null, false);
|
|
430
|
+
expect(result.success).toBe(false);
|
|
431
|
+
expect(result.failureCategory).toBe("tests-failing");
|
|
432
|
+
expect(result.reviewReason).toContain("no verdict file");
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
// --- priority ordering ---
|
|
436
|
+
|
|
437
|
+
test("illegitimate test mods take priority over failing tests", () => {
|
|
438
|
+
const verdict = makeVerdict({
|
|
439
|
+
approved: false,
|
|
440
|
+
tests: { allPassing: false, passCount: 2, failCount: 5 },
|
|
441
|
+
testModifications: {
|
|
442
|
+
detected: true,
|
|
443
|
+
files: ["test/bar.test.ts"],
|
|
444
|
+
legitimate: false,
|
|
445
|
+
reasoning: "Cheated",
|
|
446
|
+
},
|
|
447
|
+
});
|
|
448
|
+
const result = categorizeVerdict(verdict, false);
|
|
449
|
+
expect(result.failureCategory).toBe("verifier-rejected");
|
|
450
|
+
expect(result.reviewReason).toContain("illegitimate test modifications");
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
test("failing tests take priority over acceptance criteria", () => {
|
|
454
|
+
const verdict = makeVerdict({
|
|
455
|
+
approved: false,
|
|
456
|
+
tests: { allPassing: false, passCount: 1, failCount: 2 },
|
|
457
|
+
testModifications: {
|
|
458
|
+
detected: false,
|
|
459
|
+
files: [],
|
|
460
|
+
legitimate: true,
|
|
461
|
+
reasoning: "None",
|
|
462
|
+
},
|
|
463
|
+
acceptanceCriteria: {
|
|
464
|
+
allMet: false,
|
|
465
|
+
criteria: [{ criterion: "Unmet", met: false }],
|
|
466
|
+
},
|
|
467
|
+
});
|
|
468
|
+
const result = categorizeVerdict(verdict, false);
|
|
469
|
+
expect(result.failureCategory).toBe("tests-failing");
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
test("acceptance criteria not met takes priority over poor quality", () => {
|
|
473
|
+
const verdict = makeVerdict({
|
|
474
|
+
approved: false,
|
|
475
|
+
tests: { allPassing: true, passCount: 10, failCount: 0 },
|
|
476
|
+
testModifications: {
|
|
477
|
+
detected: false,
|
|
478
|
+
files: [],
|
|
479
|
+
legitimate: true,
|
|
480
|
+
reasoning: "None",
|
|
481
|
+
},
|
|
482
|
+
acceptanceCriteria: {
|
|
483
|
+
allMet: false,
|
|
484
|
+
criteria: [{ criterion: "Criterion A", met: false }],
|
|
485
|
+
},
|
|
486
|
+
quality: { rating: "poor", issues: ["Very bad"] },
|
|
487
|
+
});
|
|
488
|
+
const result = categorizeVerdict(verdict, true);
|
|
489
|
+
expect(result.failureCategory).toBe("verifier-rejected");
|
|
490
|
+
expect(result.reviewReason).toContain("Criterion A");
|
|
491
|
+
});
|
|
492
|
+
});
|