@nathapp/nax 0.28.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -2
- package/bin/nax.ts +2 -3
- package/dist/nax.js +72753 -0
- package/package.json +11 -3
- package/src/cli/analyze.ts +2 -7
- package/src/cli/config.ts +3 -1
- package/src/config/defaults.ts +1 -0
- package/src/config/schemas.ts +1 -0
- package/src/config/types.ts +1 -0
- package/src/context/builder.ts +10 -1
- package/src/execution/lifecycle/headless-formatter.ts +2 -4
- package/src/prompts/builder.ts +12 -69
- package/src/prompts/sections/isolation.ts +38 -8
- package/src/prompts/sections/role-task.ts +79 -17
- package/src/review/runner.ts +6 -1
- package/src/version.ts +2 -1
- package/.claude/rules/01-project-conventions.md +0 -34
- package/.claude/rules/02-test-architecture.md +0 -39
- package/.claude/rules/03-test-writing.md +0 -58
- package/.claude/rules/04-forbidden-patterns.md +0 -29
- package/.claude/settings.json +0 -15
- package/.githooks/pre-commit +0 -16
- package/.gitlab-ci.yml +0 -103
- package/.mcp.json +0 -8
- package/BRIEF.md +0 -140
- package/CLAUDE.md +0 -143
- package/US-007-IMPLEMENTATION.md +0 -139
- package/biome.json +0 -14
- package/bun.lock +0 -163
- package/bunfig.toml +0 -12
- package/docker-compose.test.yml +0 -15
- package/docs/20260216-fix-plan-context-review.md +0 -56
- package/docs/20260216-relentless-vs-ngent-comparison.md +0 -208
- package/docs/20260216-v02-plan.md +0 -136
- package/docs/20260216-v02-review.md +0 -685
- package/docs/20260217-dogfood-findings.md +0 -56
- package/docs/20260217-p2-plus-plan.md +0 -117
- package/docs/20260217-partial-fixes-plan.md +0 -62
- package/docs/20260217-plan-analyze-spec.md +0 -117
- package/docs/20260217-post-impl-review.md +0 -1137
- package/docs/20260217-quick-wins-plan.md +0 -66
- package/docs/20260217-split-runner-plan.md +0 -75
- package/docs/20260217-v03-impl-plan.md +0 -80
- package/docs/20260217-v03-post-impl-review.md +0 -589
- package/docs/20260217-v04-impl-plan.md +0 -86
- package/docs/20260217-v05-post-impl-review.md +0 -850
- package/docs/20260217-v06-post-impl-review.md +0 -817
- package/docs/20260218-adr003-port-plan.md +0 -151
- package/docs/20260218-review-adr003-verification.md +0 -175
- package/docs/20260219-fix-plan-bug16-19.md +0 -79
- package/docs/20260219-fix-plan-bug20-22.md +0 -114
- package/docs/20260219-plan-llm-routing.md +0 -116
- package/docs/20260219-review-bug20-22-fixes.md +0 -135
- package/docs/20260219-routing-baseline-keyword.md +0 -63
- package/docs/20260220-plan-structured-logging-p1.md +0 -80
- package/docs/20260220-plan-structured-logging-p2.md +0 -37
- package/docs/20260220-review-llm-routing.md +0 -180
- package/docs/20260220-review-post-fix-llm-routing.md +0 -70
- package/docs/20260221-fix-plan-relevantfiles-split.md +0 -101
- package/docs/20260221-fix-plan-routing-mode.md +0 -125
- package/docs/20260221-review-v0.9-implementation.md +0 -379
- package/docs/20260222-fix-plan-v091-routing-isolation.md +0 -197
- package/docs/20260223-fix-plan-prompt-audit.md +0 -62
- package/docs/20260224-nax-roadmap-phases.md +0 -189
- package/docs/20260225-phase2-llm-service-layer.md +0 -401
- package/docs/20260225-review-v0.10.1.md +0 -187
- package/docs/20260303-v010-implementation-plan.md +0 -165
- package/docs/20260304-review-nax.md +0 -492
- package/docs/CLAUDE.md.bak +0 -191
- package/docs/ROADMAP.md +0 -390
- package/docs/SPEC-rectification.md +0 -0
- package/docs/SPEC.md +0 -324
- package/docs/US-001-plugin-loading-verification.md +0 -152
- package/docs/adr/ADR-005-implementation-plan.md +0 -655
- package/docs/adr/ADR-005-pipeline-re-architecture.md +0 -464
- package/docs/architecture-analysis.md +0 -1076
- package/docs/bugs/BUG-21-escalation-null-attempts.md +0 -48
- package/docs/bugs-from-dogfood-run-c.md +0 -243
- package/docs/code-review-20260228.md +0 -612
- package/docs/code-review-v0.15.0.md +0 -629
- package/docs/hook-lifecycle-test-plan.md +0 -149
- package/docs/releases/v0.11.0-and-earlier.md +0 -20
- package/docs/releases/v0.12.0.md +0 -15
- package/docs/releases/v0.13.0.md +0 -14
- package/docs/releases/v0.14.0.md +0 -20
- package/docs/releases/v0.14.1.md +0 -36
- package/docs/releases/v0.14.2.md +0 -51
- package/docs/releases/v0.14.3.md +0 -174
- package/docs/releases/v0.14.4.md +0 -94
- package/docs/releases/v0.15.0.md +0 -502
- package/docs/releases/v0.15.1.md +0 -170
- package/docs/releases/v0.15.3.md +0 -193
- package/docs/specs/bug-039-orphan-processes.md +0 -131
- package/docs/specs/bug-040-review-rectification.md +0 -82
- package/docs/specs/bug-041-cross-story-test-isolation.md +0 -88
- package/docs/specs/bug-042-verifier-failure-capture.md +0 -117
- package/docs/specs/bun-pty-migration.md +0 -171
- package/docs/specs/central-run-registry.md +0 -116
- package/docs/specs/feat-010-smart-runner-git-history.md +0 -96
- package/docs/specs/feat-011-file-context-strategy.md +0 -73
- package/docs/specs/feat-012-tdd-writer-tier.md +0 -79
- package/docs/specs/feat-013-test-after-review.md +0 -89
- package/docs/specs/feat-014-heartbeat-observability.md +0 -127
- package/docs/specs/status-file-consolidation.md +0 -93
- package/docs/specs/status-file-v0.10.1.md +0 -812
- package/docs/specs/trigger-completion.md +0 -145
- package/docs/specs/verification-architecture-v2.md +0 -343
- package/docs/tdd/strategies.md +0 -97
- package/docs/v0.10-global-config.md +0 -206
- package/docs/v0.10-plugin-system.md +0 -415
- package/docs/v0.10-prompt-optimizer.md +0 -234
- package/docs/v0.3-spec.md +0 -244
- package/docs/v0.4-spec.md +0 -140
- package/docs/v0.5-spec.md +0 -237
- package/docs/v0.6-spec.md +0 -371
- package/docs/v0.7-spec.md +0 -177
- package/docs/v0.8-llm-routing.md +0 -206
- package/docs/v0.8-structured-logging.md +0 -132
- package/docs/v0.9.3-prompt-audit.md +0 -112
- package/examples/plugins/console-reporter/index.test.ts +0 -207
- package/examples/plugins/console-reporter/index.ts +0 -110
- package/memory/topic/feat-010-baseref.md +0 -28
- package/memory/topic/feat-013-test-after-deprecation.md +0 -22
- package/nax/config.json +0 -154
- package/nax/features/bug-039-medium/prd.json +0 -45
- package/nax/features/bugfix-v0171/prd.json +0 -52
- package/nax/features/central-run-registry/prd.json +0 -105
- package/nax/features/config-management/prd.json +0 -108
- package/nax/features/config-management/progress.txt +0 -5
- package/nax/features/diagnose/acceptance.test.ts +0 -414
- package/nax/features/diagnose/prd.json +0 -41
- package/nax/features/nax-compliance/prd.json +0 -52
- package/nax/features/nax-compliance/progress.txt +0 -1
- package/nax/features/orchestration-fixes/prd.json +0 -89
- package/nax/features/orchestration-fixes/progress.txt +0 -1
- package/nax/features/plugin-integration/US-007-VERIFICATION.md +0 -259
- package/nax/features/plugin-integration/prd.json +0 -208
- package/nax/features/plugin-integration/progress.txt +0 -5
- package/nax/features/post-rearch-bugfix/prd.json +0 -137
- package/nax/features/precheck/prd.json +0 -205
- package/nax/features/precheck/progress.txt +0 -15
- package/nax/features/prompt-builder/prd.json +0 -152
- package/nax/features/prompt-builder/progress.txt +0 -3
- package/nax/features/review-quality/prd.json +0 -55
- package/nax/features/routing-persistence/prd.json +0 -104
- package/nax/features/routing-persistence/progress.txt +0 -1
- package/nax/features/smart-test-runner/plan.md +0 -7
- package/nax/features/smart-test-runner/prd.json +0 -203
- package/nax/features/smart-test-runner/progress.txt +0 -13
- package/nax/features/smart-test-runner/spec.md +0 -7
- package/nax/features/smart-test-runner/tasks.md +0 -8
- package/nax/features/status-file-consolidation/prd.json +0 -106
- package/nax/features/structured-logging/prd.json +0 -199
- package/nax/features/trigger-completion/prd.json +0 -150
- package/nax/features/trigger-completion/progress.txt +0 -7
- package/nax/features/unlock/prd.json +0 -36
- package/nax/features/v0.18.3-execution-reliability/prd.json +0 -80
- package/nax/features/v0.18.3-execution-reliability/progress.txt +0 -3
- package/nax/features/v0.19.0-hardening/plan.md +0 -7
- package/nax/features/v0.19.0-hardening/prd.json +0 -84
- package/nax/features/v0.19.0-hardening/progress.txt +0 -7
- package/nax/features/v0.19.0-hardening/spec.md +0 -18
- package/nax/features/v0.19.0-hardening/tasks.md +0 -8
- package/nax/features/verify-v2/prd.json +0 -79
- package/nax/features/verify-v2/progress.txt +0 -3
- package/nax/status.json +0 -36
- package/src/prompts/templates/implementer.ts +0 -6
- package/src/prompts/templates/single-session.ts +0 -6
- package/src/prompts/templates/test-writer.ts +0 -6
- package/src/prompts/templates/verifier.ts +0 -6
- package/test/COVERAGE-GAPS.md +0 -333
- package/test/e2e/cm-003-default-view.test.ts +0 -195
- package/test/e2e/plan-analyze-run.test.ts +0 -902
- package/test/helpers/helpers.test.ts +0 -295
- package/test/helpers/timeout.ts +0 -42
- package/test/integration/US-002-TEST-SUMMARY.md +0 -107
- package/test/integration/US-003-TEST-SUMMARY.md +0 -149
- package/test/integration/US-004-TEST-SUMMARY.md +0 -106
- package/test/integration/US-005-TEST-SUMMARY.md +0 -138
- package/test/integration/US-007-TEST-SUMMARY.md +0 -100
- package/test/integration/cli/agent-validation.test.ts +0 -439
- package/test/integration/cli/cli-config-default-edge-cases.test.ts +0 -223
- package/test/integration/cli/cli-config-default-view.test.ts +0 -230
- package/test/integration/cli/cli-config-diff.test.ts +0 -461
- package/test/integration/cli/cli-config-prompts-explain.test.ts +0 -74
- package/test/integration/cli/cli-config.test.ts +0 -737
- package/test/integration/cli/cli-diagnose.test.ts +0 -595
- package/test/integration/cli/cli-logs.test.ts +0 -346
- package/test/integration/cli/cli-plugins.test.ts +0 -679
- package/test/integration/cli/cli-precheck.test.ts +0 -372
- package/test/integration/cli/cli-run-headless.test.ts +0 -174
- package/test/integration/cli/cli.test.ts +0 -76
- package/test/integration/cli/precheck-integration.test.ts +0 -476
- package/test/integration/cli/precheck-orchestrator.test.ts +0 -247
- package/test/integration/cli/precheck.test.ts +0 -806
- package/test/integration/config/config-loader.test.ts +0 -266
- package/test/integration/config/config.test.ts +0 -444
- package/test/integration/config/merger.test.ts +0 -466
- package/test/integration/config/paths.test.ts +0 -52
- package/test/integration/config/security-loader.test.ts +0 -83
- package/test/integration/context/context-integration.test.ts +0 -703
- package/test/integration/context/context-path-security.test.ts +0 -173
- package/test/integration/context/context-provider-injection.test.ts +0 -507
- package/test/integration/context/context-verification-integration.test.ts +0 -296
- package/test/integration/context/s5-greenfield-fallback.test.ts +0 -298
- package/test/integration/execution/execution-isolation.test.ts +0 -143
- package/test/integration/execution/execution.test.ts +0 -634
- package/test/integration/execution/feature-status-write.test.ts +0 -302
- package/test/integration/execution/parallel.test.ts +0 -251
- package/test/integration/execution/prd-pause.test.ts +0 -205
- package/test/integration/execution/prd-resolvers.test.ts +0 -186
- package/test/integration/execution/progress.test.ts +0 -34
- package/test/integration/execution/runner-batching.test.ts +0 -682
- package/test/integration/execution/runner-config-plugins.test.ts +0 -462
- package/test/integration/execution/runner-escalation.test.ts +0 -561
- package/test/integration/execution/runner-fixes.test.ts +0 -400
- package/test/integration/execution/runner-plugin-integration.test.ts +0 -544
- package/test/integration/execution/runner-queue-and-attempts.test.ts +0 -476
- package/test/integration/execution/status-file-integration.test.ts +0 -289
- package/test/integration/execution/status-file.test.ts +0 -380
- package/test/integration/execution/status-writer.test.ts +0 -447
- package/test/integration/execution/story-id-in-events.test.ts +0 -274
- package/test/integration/interaction/interaction-chain-pipeline.test.ts +0 -476
- package/test/integration/pipeline/hooks.test.ts +0 -363
- package/test/integration/pipeline/pipeline-acceptance.test.ts +0 -303
- package/test/integration/pipeline/pipeline-events.test.ts +0 -476
- package/test/integration/pipeline/pipeline.test.ts +0 -660
- package/test/integration/pipeline/reporter-lifecycle.test.ts +0 -862
- package/test/integration/pipeline/verify-stage.test.ts +0 -286
- package/test/integration/plan/analyze-integration.test.ts +0 -262
- package/test/integration/plan/analyze-scanner.test.ts +0 -132
- package/test/integration/plan/logger.test.ts +0 -461
- package/test/integration/plan/plan.test.ts +0 -157
- package/test/integration/plugins/config-integration.test.ts +0 -173
- package/test/integration/plugins/config-resolution.test.ts +0 -523
- package/test/integration/plugins/loader.test.ts +0 -644
- package/test/integration/plugins/plugins-registry.test.ts +0 -747
- package/test/integration/plugins/validator.test.ts +0 -564
- package/test/integration/prompts/pb-004-migration.test.ts +0 -523
- package/test/integration/review/review-config-commands.test.ts +0 -320
- package/test/integration/review/review-config-schema.test.ts +0 -117
- package/test/integration/review/review-plugin-integration.test.ts +0 -729
- package/test/integration/review/review.test.ts +0 -150
- package/test/integration/routing/plugin-routing-advanced.test.ts +0 -461
- package/test/integration/routing/plugin-routing-core.test.ts +0 -527
- package/test/integration/routing/routing-stage-bug-021.test.ts +0 -275
- package/test/integration/routing/routing-stage-greenfield.test.ts +0 -287
- package/test/integration/tdd/tdd-cleanup.test.ts +0 -246
- package/test/integration/tdd/tdd-orchestrator-core.test.ts +0 -565
- package/test/integration/tdd/tdd-orchestrator-failureCategory.test.ts +0 -355
- package/test/integration/tdd/tdd-orchestrator-fallback.test.ts +0 -311
- package/test/integration/tdd/tdd-orchestrator-lite.test.ts +0 -289
- package/test/integration/tdd/tdd-orchestrator-prompts.test.ts +0 -260
- package/test/integration/tdd/tdd-orchestrator-verdict.test.ts +0 -536
- package/test/integration/tmp/headless-test/test.jsonl +0 -30
- package/test/integration/verification/test-scanner.test.ts +0 -403
- package/test/integration/verification/verification-asset-check.test.ts +0 -143
- package/test/integration/worktree/manager.test.ts +0 -218
- package/test/integration/worktree/worktree-merge.test.ts +0 -341
- package/test/manual/logging-formatter-demo.ts +0 -158
- package/test/ui/tui-agent-panel.test.tsx +0 -99
- package/test/ui/tui-pty-integration.test.tsx +0 -146
- package/test/unit/acceptance.test.ts +0 -187
- package/test/unit/agent-stderr-capture.test.ts +0 -147
- package/test/unit/agents/claude.test.ts +0 -107
- package/test/unit/analyze-classifier.test.ts +0 -216
- package/test/unit/analyze.test.ts +0 -224
- package/test/unit/auto-detect.test.ts +0 -250
- package/test/unit/cli-status-project-level.test.ts +0 -283
- package/test/unit/cli-status.test.ts +0 -418
- package/test/unit/commands/common.test.ts +0 -321
- package/test/unit/commands/logs.test.ts +0 -458
- package/test/unit/commands/runs.test.ts +0 -303
- package/test/unit/commands/unlock.test.ts +0 -320
- package/test/unit/config/defaults.test.ts +0 -70
- package/test/unit/config/quality-commands-schema.test.ts +0 -72
- package/test/unit/config/regression-gate-schema.test.ts +0 -160
- package/test/unit/config/smart-runner-flag.test.ts +0 -250
- package/test/unit/constitution-generators.test.ts +0 -161
- package/test/unit/constitution.test.ts +0 -210
- package/test/unit/context/context-autodetect.test.ts +0 -297
- package/test/unit/context/context-build.test.ts +0 -575
- package/test/unit/context/context-coverage.test.ts +0 -236
- package/test/unit/context/context-error.test.ts +0 -93
- package/test/unit/context/context-estimate-tokens.test.ts +0 -201
- package/test/unit/context/context-format.test.ts +0 -302
- package/test/unit/context/context-isolation.test.ts +0 -267
- package/test/unit/context/context-sort.test.ts +0 -93
- package/test/unit/context/context-story.test.ts +0 -108
- package/test/unit/context/prior-failures.test.ts +0 -463
- package/test/unit/context.test.ts +0 -1726
- package/test/unit/cost.test.ts +0 -231
- package/test/unit/crash-recovery.test.ts +0 -309
- package/test/unit/escalation.test.ts +0 -127
- package/test/unit/execution/lifecycle/run-completion.test.ts +0 -240
- package/test/unit/execution/lifecycle/run-regression.test.ts +0 -420
- package/test/unit/execution/pid-registry.test.ts +0 -241
- package/test/unit/execution/sequential-executor.test.ts +0 -235
- package/test/unit/execution/sfc-004-dead-code-cleanup.test.ts +0 -89
- package/test/unit/execution/structured-failure.test.ts +0 -415
- package/test/unit/execution-logging-stderr.test.ts +0 -157
- package/test/unit/execution-stage.test.ts +0 -123
- package/test/unit/fix-generator.test.ts +0 -276
- package/test/unit/formatters.test.ts +0 -468
- package/test/unit/greenfield.test.ts +0 -180
- package/test/unit/hooks/shell-security.test.ts +0 -40
- package/test/unit/interaction/auto-plugin.test.ts +0 -162
- package/test/unit/interaction/human-review-trigger.test.ts +0 -165
- package/test/unit/interaction-network-failures.test.ts +0 -390
- package/test/unit/interaction-plugins.test.ts +0 -472
- package/test/unit/logging/formatter.test.ts +0 -456
- package/test/unit/merge.test.ts +0 -269
- package/test/unit/metrics/aggregator.test.ts +0 -164
- package/test/unit/metrics/tracker.test.ts +0 -186
- package/test/unit/metrics.test.ts +0 -276
- package/test/unit/optimizer/noop.optimizer.test.ts +0 -125
- package/test/unit/optimizer/rule-based.optimizer.test.ts +0 -358
- package/test/unit/pipeline/event-bus.test.ts +0 -105
- package/test/unit/pipeline/routing-partial-override.test.ts +0 -121
- package/test/unit/pipeline/runner-retry.test.ts +0 -89
- package/test/unit/pipeline/stages/autofix.test.ts +0 -97
- package/test/unit/pipeline/stages/completion-review-gate.test.ts +0 -218
- package/test/unit/pipeline/stages/execution-ambiguity.test.ts +0 -311
- package/test/unit/pipeline/stages/execution-merge-conflict.test.ts +0 -218
- package/test/unit/pipeline/stages/rectify.test.ts +0 -101
- package/test/unit/pipeline/stages/regression-stage.test.ts +0 -69
- package/test/unit/pipeline/stages/review.test.ts +0 -201
- package/test/unit/pipeline/stages/routing-idempotence.test.ts +0 -139
- package/test/unit/pipeline/stages/routing-initial-complexity.test.ts +0 -321
- package/test/unit/pipeline/stages/routing-persistence.test.ts +0 -380
- package/test/unit/pipeline/stages/verify.test.ts +0 -267
- package/test/unit/pipeline/subscribers/events-writer.test.ts +0 -227
- package/test/unit/pipeline/subscribers/hooks.test.ts +0 -84
- package/test/unit/pipeline/subscribers/interaction.test.ts +0 -313
- package/test/unit/pipeline/subscribers/registry.test.ts +0 -149
- package/test/unit/pipeline/subscribers/reporters.test.ts +0 -90
- package/test/unit/pipeline/verify-smart-runner.test.ts +0 -345
- package/test/unit/prd-auto-default.test.ts +0 -291
- package/test/unit/prd-failure-category.test.ts +0 -177
- package/test/unit/prd-get-next-story.test.ts +0 -215
- package/test/unit/precheck/checks-warnings.test.ts +0 -114
- package/test/unit/precheck-checks.test.ts +0 -841
- package/test/unit/precheck-story-size-gate.test.ts +0 -288
- package/test/unit/precheck-types.test.ts +0 -143
- package/test/unit/prompts/builder.test.ts +0 -258
- package/test/unit/prompts/loader.test.ts +0 -355
- package/test/unit/prompts/sections/conventions.test.ts +0 -30
- package/test/unit/prompts/sections/isolation.test.ts +0 -35
- package/test/unit/prompts/sections/role-task.test.ts +0 -40
- package/test/unit/prompts/sections/sections.test.ts +0 -238
- package/test/unit/prompts/sections/story.test.ts +0 -45
- package/test/unit/prompts/sections/verdict.test.ts +0 -58
- package/test/unit/prompts.test.ts +0 -476
- package/test/unit/queue.test.ts +0 -237
- package/test/unit/rectification.test.ts +0 -285
- package/test/unit/registry.test.ts +0 -288
- package/test/unit/review/runner.test.ts +0 -117
- package/test/unit/routing/content-hash.test.ts +0 -99
- package/test/unit/routing/routing-stability.test.ts +0 -208
- package/test/unit/routing/strategies/llm.test.ts +0 -306
- package/test/unit/routing-advanced.test.ts +0 -313
- package/test/unit/routing-core.test.ts +0 -341
- package/test/unit/routing-strategies.test.ts +0 -440
- package/test/unit/storyid-events.test.ts +0 -213
- package/test/unit/tdd-verdict.test.ts +0 -492
- package/test/unit/test-output-parser.test.ts +0 -377
- package/test/unit/ui/tui-controls.test.ts +0 -335
- package/test/unit/ui/tui-cost-and-pty.test.ts +0 -190
- package/test/unit/ui/tui-layout.test.ts +0 -379
- package/test/unit/ui/tui-stories.test.ts +0 -333
- package/test/unit/unit-isolation.test.ts +0 -135
- package/test/unit/utils/git.test.ts +0 -50
- package/test/unit/utils/path-security.test.ts +0 -47
- package/test/unit/utils-helpers.test.ts +0 -318
- package/test/unit/verdict.test.ts +0 -325
- package/test/unit/verification/orchestrator-types.test.ts +0 -54
- package/test/unit/verification/orchestrator.test.ts +0 -66
- package/test/unit/verification/smart-runner-config.test.ts +0 -163
- package/test/unit/verification/smart-runner-discovery.test.ts +0 -354
- package/test/unit/verification/smart-runner.test.ts +0 -262
- package/test/unit/verification/strategies/acceptance.test.ts +0 -33
- package/test/unit/verification/strategies/regression.test.ts +0 -87
- package/test/unit/verification/strategies/scoped.test.ts +0 -100
- package/test/unit/worktree-manager.test.ts +0 -159
- package/tsconfig.json +0 -27
|
@@ -1,288 +0,0 @@
|
|
|
1
|
-
// RE-ARCH: keep
|
|
2
|
-
/**
|
|
3
|
-
* Tests for src/plugins/registry.ts
|
|
4
|
-
*
|
|
5
|
-
* Covers: PluginRegistry getters and teardownAll
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { describe, expect, it, mock } from "bun:test";
|
|
9
|
-
import { PluginRegistry } from "../../src/plugins/registry";
|
|
10
|
-
import type { NaxPlugin } from "../../src/plugins/types";
|
|
11
|
-
|
|
12
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
13
|
-
// Test fixtures
|
|
14
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
15
|
-
|
|
16
|
-
const createMockPlugin = (name: string, provides: string[], extensions: any = {}): NaxPlugin => ({
|
|
17
|
-
name,
|
|
18
|
-
version: "1.0.0",
|
|
19
|
-
provides,
|
|
20
|
-
extensions,
|
|
21
|
-
init: async () => {},
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
25
|
-
// PluginRegistry.getOptimizers
|
|
26
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
27
|
-
|
|
28
|
-
describe("PluginRegistry.getOptimizers", () => {
|
|
29
|
-
it("returns empty array when no optimizer plugins", () => {
|
|
30
|
-
const registry = new PluginRegistry([createMockPlugin("agent-plugin", ["agent"])]);
|
|
31
|
-
|
|
32
|
-
const optimizers = registry.getOptimizers();
|
|
33
|
-
expect(optimizers.length).toBe(0);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it("returns all optimizer plugins", () => {
|
|
37
|
-
const optimizer1 = { name: "optimizer1", optimize: async () => "optimized" };
|
|
38
|
-
const optimizer2 = { name: "optimizer2", optimize: async () => "optimized" };
|
|
39
|
-
|
|
40
|
-
const registry = new PluginRegistry([
|
|
41
|
-
createMockPlugin("opt-1", ["optimizer"], { optimizer: optimizer1 }),
|
|
42
|
-
createMockPlugin("opt-2", ["optimizer"], { optimizer: optimizer2 }),
|
|
43
|
-
]);
|
|
44
|
-
|
|
45
|
-
const optimizers = registry.getOptimizers();
|
|
46
|
-
expect(optimizers.length).toBe(2);
|
|
47
|
-
expect(optimizers).toContain(optimizer1);
|
|
48
|
-
expect(optimizers).toContain(optimizer2);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it("filters out plugins without optimizer extension", () => {
|
|
52
|
-
const optimizer1 = { name: "optimizer1", optimize: async () => "optimized" };
|
|
53
|
-
|
|
54
|
-
const registry = new PluginRegistry([
|
|
55
|
-
createMockPlugin("opt-1", ["optimizer"], { optimizer: optimizer1 }),
|
|
56
|
-
createMockPlugin("no-opt", ["optimizer"], {}),
|
|
57
|
-
]);
|
|
58
|
-
|
|
59
|
-
const optimizers = registry.getOptimizers();
|
|
60
|
-
expect(optimizers.length).toBe(1);
|
|
61
|
-
expect(optimizers[0]).toBe(optimizer1);
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
66
|
-
// PluginRegistry.getRouters
|
|
67
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
68
|
-
|
|
69
|
-
describe("PluginRegistry.getRouters", () => {
|
|
70
|
-
it("returns empty array when no router plugins", () => {
|
|
71
|
-
const registry = new PluginRegistry([createMockPlugin("agent-plugin", ["agent"])]);
|
|
72
|
-
|
|
73
|
-
const routers = registry.getRouters();
|
|
74
|
-
expect(routers.length).toBe(0);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it("returns all router plugins in load order", () => {
|
|
78
|
-
const router1 = { name: "router1" } as any;
|
|
79
|
-
const router2 = { name: "router2" } as any;
|
|
80
|
-
|
|
81
|
-
const registry = new PluginRegistry([
|
|
82
|
-
createMockPlugin("router-1", ["router"], { router: router1 }),
|
|
83
|
-
createMockPlugin("router-2", ["router"], { router: router2 }),
|
|
84
|
-
]);
|
|
85
|
-
|
|
86
|
-
const routers = registry.getRouters();
|
|
87
|
-
expect(routers.length).toBe(2);
|
|
88
|
-
expect(routers[0]).toBe(router1);
|
|
89
|
-
expect(routers[1]).toBe(router2);
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
94
|
-
// PluginRegistry.getAgent
|
|
95
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
96
|
-
|
|
97
|
-
describe("PluginRegistry.getAgent", () => {
|
|
98
|
-
it("returns undefined when no agent plugins", () => {
|
|
99
|
-
const registry = new PluginRegistry([createMockPlugin("optimizer-plugin", ["optimizer"])]);
|
|
100
|
-
|
|
101
|
-
const agent = registry.getAgent("claude");
|
|
102
|
-
expect(agent).toBeUndefined();
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it("returns agent by name", () => {
|
|
106
|
-
const claudeAgent = { name: "claude" } as any;
|
|
107
|
-
const cursorAgent = { name: "cursor" } as any;
|
|
108
|
-
|
|
109
|
-
const registry = new PluginRegistry([
|
|
110
|
-
createMockPlugin("claude-plugin", ["agent"], { agent: claudeAgent }),
|
|
111
|
-
createMockPlugin("cursor-plugin", ["agent"], { agent: cursorAgent }),
|
|
112
|
-
]);
|
|
113
|
-
|
|
114
|
-
const agent = registry.getAgent("claude");
|
|
115
|
-
expect(agent).toBe(claudeAgent);
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
it("returns undefined when agent name not found", () => {
|
|
119
|
-
const claudeAgent = { name: "claude" } as any;
|
|
120
|
-
|
|
121
|
-
const registry = new PluginRegistry([createMockPlugin("claude-plugin", ["agent"], { agent: claudeAgent })]);
|
|
122
|
-
|
|
123
|
-
const agent = registry.getAgent("windsurf");
|
|
124
|
-
expect(agent).toBeUndefined();
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it("last loaded wins on name collision", () => {
|
|
128
|
-
const claudeAgent1 = { name: "claude", version: 1 } as any;
|
|
129
|
-
const claudeAgent2 = { name: "claude", version: 2 } as any;
|
|
130
|
-
|
|
131
|
-
const registry = new PluginRegistry([
|
|
132
|
-
createMockPlugin("claude-v1", ["agent"], { agent: claudeAgent1 }),
|
|
133
|
-
createMockPlugin("claude-v2", ["agent"], { agent: claudeAgent2 }),
|
|
134
|
-
]);
|
|
135
|
-
|
|
136
|
-
const agent = registry.getAgent("claude");
|
|
137
|
-
expect(agent).toBe(claudeAgent2);
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
142
|
-
// PluginRegistry.getReviewers
|
|
143
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
144
|
-
|
|
145
|
-
describe("PluginRegistry.getReviewers", () => {
|
|
146
|
-
it("returns empty array when no reviewer plugins", () => {
|
|
147
|
-
const registry = new PluginRegistry([createMockPlugin("agent-plugin", ["agent"])]);
|
|
148
|
-
|
|
149
|
-
const reviewers = registry.getReviewers();
|
|
150
|
-
expect(reviewers.length).toBe(0);
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
it("returns all reviewer plugins", () => {
|
|
154
|
-
const reviewer1 = { name: "reviewer1" } as any;
|
|
155
|
-
const reviewer2 = { name: "reviewer2" } as any;
|
|
156
|
-
|
|
157
|
-
const registry = new PluginRegistry([
|
|
158
|
-
createMockPlugin("rev-1", ["reviewer"], { reviewer: reviewer1 }),
|
|
159
|
-
createMockPlugin("rev-2", ["reviewer"], { reviewer: reviewer2 }),
|
|
160
|
-
]);
|
|
161
|
-
|
|
162
|
-
const reviewers = registry.getReviewers();
|
|
163
|
-
expect(reviewers.length).toBe(2);
|
|
164
|
-
expect(reviewers).toContain(reviewer1);
|
|
165
|
-
expect(reviewers).toContain(reviewer2);
|
|
166
|
-
});
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
170
|
-
// PluginRegistry.getContextProviders
|
|
171
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
172
|
-
|
|
173
|
-
describe("PluginRegistry.getContextProviders", () => {
|
|
174
|
-
it("returns empty array when no context provider plugins", () => {
|
|
175
|
-
const registry = new PluginRegistry([createMockPlugin("agent-plugin", ["agent"])]);
|
|
176
|
-
|
|
177
|
-
const providers = registry.getContextProviders();
|
|
178
|
-
expect(providers.length).toBe(0);
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
it("returns all context provider plugins", () => {
|
|
182
|
-
const provider1 = { name: "provider1" } as any;
|
|
183
|
-
const provider2 = { name: "provider2" } as any;
|
|
184
|
-
|
|
185
|
-
const registry = new PluginRegistry([
|
|
186
|
-
createMockPlugin("prov-1", ["context-provider"], { contextProvider: provider1 }),
|
|
187
|
-
createMockPlugin("prov-2", ["context-provider"], { contextProvider: provider2 }),
|
|
188
|
-
]);
|
|
189
|
-
|
|
190
|
-
const providers = registry.getContextProviders();
|
|
191
|
-
expect(providers.length).toBe(2);
|
|
192
|
-
expect(providers).toContain(provider1);
|
|
193
|
-
expect(providers).toContain(provider2);
|
|
194
|
-
});
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
198
|
-
// PluginRegistry.getReporters
|
|
199
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
200
|
-
|
|
201
|
-
describe("PluginRegistry.getReporters", () => {
|
|
202
|
-
it("returns empty array when no reporter plugins", () => {
|
|
203
|
-
const registry = new PluginRegistry([createMockPlugin("agent-plugin", ["agent"])]);
|
|
204
|
-
|
|
205
|
-
const reporters = registry.getReporters();
|
|
206
|
-
expect(reporters.length).toBe(0);
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
it("returns all reporter plugins", () => {
|
|
210
|
-
const reporter1 = { name: "reporter1" } as any;
|
|
211
|
-
const reporter2 = { name: "reporter2" } as any;
|
|
212
|
-
|
|
213
|
-
const registry = new PluginRegistry([
|
|
214
|
-
createMockPlugin("rep-1", ["reporter"], { reporter: reporter1 }),
|
|
215
|
-
createMockPlugin("rep-2", ["reporter"], { reporter: reporter2 }),
|
|
216
|
-
]);
|
|
217
|
-
|
|
218
|
-
const reporters = registry.getReporters();
|
|
219
|
-
expect(reporters.length).toBe(2);
|
|
220
|
-
expect(reporters).toContain(reporter1);
|
|
221
|
-
expect(reporters).toContain(reporter2);
|
|
222
|
-
});
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
226
|
-
// PluginRegistry.teardownAll
|
|
227
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
228
|
-
|
|
229
|
-
describe("PluginRegistry.teardownAll", () => {
|
|
230
|
-
it("calls teardown on all plugins with teardown method", async () => {
|
|
231
|
-
const teardown1 = mock(async () => {});
|
|
232
|
-
const teardown2 = mock(async () => {});
|
|
233
|
-
|
|
234
|
-
const plugin1 = createMockPlugin("plugin-1", ["agent"]);
|
|
235
|
-
plugin1.teardown = teardown1;
|
|
236
|
-
|
|
237
|
-
const plugin2 = createMockPlugin("plugin-2", ["optimizer"]);
|
|
238
|
-
plugin2.teardown = teardown2;
|
|
239
|
-
|
|
240
|
-
const registry = new PluginRegistry([plugin1, plugin2]);
|
|
241
|
-
|
|
242
|
-
await registry.teardownAll();
|
|
243
|
-
|
|
244
|
-
expect(teardown1).toHaveBeenCalledTimes(1);
|
|
245
|
-
expect(teardown2).toHaveBeenCalledTimes(1);
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
it("skips plugins without teardown method", async () => {
|
|
249
|
-
const teardown1 = mock(async () => {});
|
|
250
|
-
|
|
251
|
-
const plugin1 = createMockPlugin("plugin-1", ["agent"]);
|
|
252
|
-
plugin1.teardown = teardown1;
|
|
253
|
-
|
|
254
|
-
const plugin2 = createMockPlugin("plugin-2", ["optimizer"]);
|
|
255
|
-
// plugin2 has no teardown
|
|
256
|
-
|
|
257
|
-
const registry = new PluginRegistry([plugin1, plugin2]);
|
|
258
|
-
|
|
259
|
-
await registry.teardownAll();
|
|
260
|
-
|
|
261
|
-
expect(teardown1).toHaveBeenCalledTimes(1);
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
it("continues teardown even if one plugin fails", async () => {
|
|
265
|
-
const teardown1 = mock(async () => {
|
|
266
|
-
throw new Error("Teardown failed");
|
|
267
|
-
});
|
|
268
|
-
const teardown2 = mock(async () => {});
|
|
269
|
-
|
|
270
|
-
const plugin1 = createMockPlugin("plugin-1", ["agent"]);
|
|
271
|
-
plugin1.teardown = teardown1;
|
|
272
|
-
|
|
273
|
-
const plugin2 = createMockPlugin("plugin-2", ["optimizer"]);
|
|
274
|
-
plugin2.teardown = teardown2;
|
|
275
|
-
|
|
276
|
-
const registry = new PluginRegistry([plugin1, plugin2]);
|
|
277
|
-
|
|
278
|
-
await registry.teardownAll();
|
|
279
|
-
|
|
280
|
-
expect(teardown1).toHaveBeenCalledTimes(1);
|
|
281
|
-
expect(teardown2).toHaveBeenCalledTimes(1);
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
it("handles empty plugin list", async () => {
|
|
285
|
-
const registry = new PluginRegistry([]);
|
|
286
|
-
await expect(registry.teardownAll()).resolves.toBeUndefined();
|
|
287
|
-
});
|
|
288
|
-
});
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unit tests for src/review/runner.ts
|
|
3
|
-
* RQ-001: Assert clean working tree before running review typecheck/lint (BUG-049)
|
|
4
|
-
*
|
|
5
|
-
* Tests verify that runReview() checks for uncommitted tracked-file changes
|
|
6
|
-
* (via git diff --name-only HEAD) before running typecheck or lint.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
10
|
-
import { _deps, runReview } from "../../../src/review/runner";
|
|
11
|
-
import type { ReviewConfig } from "../../../src/review/types";
|
|
12
|
-
|
|
13
|
-
/** Minimal ReviewConfig with typecheck enabled but command set to disable via executionConfig */
|
|
14
|
-
const typecheckConfig: ReviewConfig = {
|
|
15
|
-
enabled: true,
|
|
16
|
-
checks: ["typecheck"],
|
|
17
|
-
commands: {},
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
/** ReviewConfig with no checks — used to isolate the dirty-tree guard logic */
|
|
21
|
-
const noChecksConfig: ReviewConfig = {
|
|
22
|
-
enabled: true,
|
|
23
|
-
checks: [],
|
|
24
|
-
commands: {},
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
describe("runReview — dirty working tree guard (RQ-001)", () => {
|
|
28
|
-
let originalGetUncommittedFiles: typeof _deps.getUncommittedFiles;
|
|
29
|
-
|
|
30
|
-
beforeEach(() => {
|
|
31
|
-
originalGetUncommittedFiles = _deps.getUncommittedFiles;
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
afterEach(() => {
|
|
35
|
-
mock.restore();
|
|
36
|
-
_deps.getUncommittedFiles = originalGetUncommittedFiles;
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
describe("dirty working tree", () => {
|
|
40
|
-
test("returns failure with uncommitted files listed in failureReason", async () => {
|
|
41
|
-
_deps.getUncommittedFiles = mock(async (_workdir: string) => [
|
|
42
|
-
"src/types.ts",
|
|
43
|
-
"src/routing.ts",
|
|
44
|
-
]);
|
|
45
|
-
|
|
46
|
-
const result = await runReview(typecheckConfig, "/tmp/fake-workdir");
|
|
47
|
-
|
|
48
|
-
expect(result.success).toBe(false);
|
|
49
|
-
expect(result.failureReason).toBeDefined();
|
|
50
|
-
expect(result.failureReason).toContain("src/types.ts");
|
|
51
|
-
expect(result.failureReason).toContain("src/routing.ts");
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test("does not run typecheck when working tree is dirty", async () => {
|
|
55
|
-
_deps.getUncommittedFiles = mock(async (_workdir: string) => ["src/types.ts"]);
|
|
56
|
-
|
|
57
|
-
// If typecheck were run it would fail (no real workdir), but we expect
|
|
58
|
-
// an early return with zero checks executed.
|
|
59
|
-
const result = await runReview(typecheckConfig, "/tmp/fake-workdir");
|
|
60
|
-
|
|
61
|
-
expect(result.checks).toHaveLength(0);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
test("calls getUncommittedFiles with the provided workdir", async () => {
|
|
65
|
-
const mockFn = mock(async (_workdir: string) => ["src/types.ts"]);
|
|
66
|
-
_deps.getUncommittedFiles = mockFn;
|
|
67
|
-
|
|
68
|
-
await runReview(typecheckConfig, "/tmp/my-project");
|
|
69
|
-
|
|
70
|
-
expect(mockFn).toHaveBeenCalledWith("/tmp/my-project");
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
describe("clean working tree", () => {
|
|
75
|
-
test("proceeds past dirty-tree guard when no uncommitted files", async () => {
|
|
76
|
-
_deps.getUncommittedFiles = mock(async (_workdir: string) => []);
|
|
77
|
-
|
|
78
|
-
// typecheckCommand: null disables the check so no real process is spawned.
|
|
79
|
-
const result = await runReview(typecheckConfig, "/tmp/fake-workdir", {
|
|
80
|
-
typecheckCommand: null,
|
|
81
|
-
maxIterations: 5,
|
|
82
|
-
iterationDelayMs: 0,
|
|
83
|
-
costLimit: 10,
|
|
84
|
-
sessionTimeoutSeconds: 300,
|
|
85
|
-
verificationTimeoutSeconds: 60,
|
|
86
|
-
maxStoriesPerFeature: 20,
|
|
87
|
-
contextProviderTokenBudget: 2000,
|
|
88
|
-
rectification: { enabled: false, maxIterations: 3 },
|
|
89
|
-
regressionGate: { enabled: false },
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
expect(result.success).toBe(true);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
test("calls getUncommittedFiles before running checks", async () => {
|
|
96
|
-
const mockFn = mock(async (_workdir: string) => []);
|
|
97
|
-
_deps.getUncommittedFiles = mockFn;
|
|
98
|
-
|
|
99
|
-
await runReview(noChecksConfig, "/tmp/clean-workdir");
|
|
100
|
-
|
|
101
|
-
expect(mockFn).toHaveBeenCalledWith("/tmp/clean-workdir");
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
describe("untracked files only", () => {
|
|
106
|
-
test("review proceeds when git diff HEAD returns empty (only untracked files exist)", async () => {
|
|
107
|
-
// git diff --name-only HEAD only reports tracked files with changes.
|
|
108
|
-
// Untracked files are invisible to this command — working tree is considered clean.
|
|
109
|
-
_deps.getUncommittedFiles = mock(async (_workdir: string) => []);
|
|
110
|
-
|
|
111
|
-
const result = await runReview(noChecksConfig, "/tmp/fake-workdir");
|
|
112
|
-
|
|
113
|
-
// Should succeed — no dirty tracked files, review can proceed
|
|
114
|
-
expect(result.success).toBe(true);
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
});
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* computeStoryContentHash — RRP-003
|
|
3
|
-
*
|
|
4
|
-
* AC-2: helper function computes a hash of title+description+ACs+tags
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { describe, expect, test } from "bun:test";
|
|
8
|
-
import { computeStoryContentHash } from "../../../src/routing";
|
|
9
|
-
import type { UserStory } from "../../../src/prd/types";
|
|
10
|
-
|
|
11
|
-
// ---------------------------------------------------------------------------
|
|
12
|
-
// Helpers
|
|
13
|
-
// ---------------------------------------------------------------------------
|
|
14
|
-
|
|
15
|
-
function makeStory(overrides?: Partial<UserStory>): UserStory {
|
|
16
|
-
return {
|
|
17
|
-
id: "US-001",
|
|
18
|
-
title: "Add login page",
|
|
19
|
-
description: "Users can log in with email and password",
|
|
20
|
-
acceptanceCriteria: ["Shows email field", "Shows password field", "Submits form"],
|
|
21
|
-
tags: ["auth", "ui"],
|
|
22
|
-
dependencies: [],
|
|
23
|
-
status: "pending",
|
|
24
|
-
passes: false,
|
|
25
|
-
escalations: [],
|
|
26
|
-
attempts: 0,
|
|
27
|
-
...overrides,
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
|
-
// AC-2: computeStoryContentHash exists and returns a string
|
|
33
|
-
// ---------------------------------------------------------------------------
|
|
34
|
-
|
|
35
|
-
describe("computeStoryContentHash", () => {
|
|
36
|
-
test("returns a non-empty string", () => {
|
|
37
|
-
const story = makeStory();
|
|
38
|
-
const hash = computeStoryContentHash(story);
|
|
39
|
-
expect(typeof hash).toBe("string");
|
|
40
|
-
expect(hash.length).toBeGreaterThan(0);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test("same story content produces the same hash (deterministic)", () => {
|
|
44
|
-
const story1 = makeStory();
|
|
45
|
-
const story2 = makeStory();
|
|
46
|
-
expect(computeStoryContentHash(story1)).toBe(computeStoryContentHash(story2));
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test("different title produces different hash", () => {
|
|
50
|
-
const base = makeStory();
|
|
51
|
-
const changed = makeStory({ title: "Add registration page" });
|
|
52
|
-
expect(computeStoryContentHash(base)).not.toBe(computeStoryContentHash(changed));
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
test("different description produces different hash", () => {
|
|
56
|
-
const base = makeStory();
|
|
57
|
-
const changed = makeStory({ description: "Users can log in via OAuth" });
|
|
58
|
-
expect(computeStoryContentHash(base)).not.toBe(computeStoryContentHash(changed));
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test("different acceptanceCriteria produces different hash", () => {
|
|
62
|
-
const base = makeStory();
|
|
63
|
-
const changed = makeStory({
|
|
64
|
-
acceptanceCriteria: ["Shows email field", "Shows password field"],
|
|
65
|
-
});
|
|
66
|
-
expect(computeStoryContentHash(base)).not.toBe(computeStoryContentHash(changed));
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
test("different tags produces different hash", () => {
|
|
70
|
-
const base = makeStory();
|
|
71
|
-
const changed = makeStory({ tags: ["auth", "api"] });
|
|
72
|
-
expect(computeStoryContentHash(base)).not.toBe(computeStoryContentHash(changed));
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
test("story ID, status, and attempts do NOT affect the hash (only content fields)", () => {
|
|
76
|
-
const base = makeStory({ id: "US-001", status: "pending", attempts: 0 });
|
|
77
|
-
const differentMeta = makeStory({ id: "US-099", status: "in-progress", attempts: 3 });
|
|
78
|
-
expect(computeStoryContentHash(base)).toBe(computeStoryContentHash(differentMeta));
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
test("empty acceptanceCriteria and tags produce a valid hash", () => {
|
|
82
|
-
const story = makeStory({ acceptanceCriteria: [], tags: [] });
|
|
83
|
-
const hash = computeStoryContentHash(story);
|
|
84
|
-
expect(typeof hash).toBe("string");
|
|
85
|
-
expect(hash.length).toBeGreaterThan(0);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
test("adding an AC changes the hash", () => {
|
|
89
|
-
const before = makeStory({ acceptanceCriteria: ["AC1", "AC2"] });
|
|
90
|
-
const after = makeStory({ acceptanceCriteria: ["AC1", "AC2", "AC3 — new"] });
|
|
91
|
-
expect(computeStoryContentHash(before)).not.toBe(computeStoryContentHash(after));
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
test("adding a tag changes the hash", () => {
|
|
95
|
-
const before = makeStory({ tags: ["backend"] });
|
|
96
|
-
const after = makeStory({ tags: ["backend", "security"] });
|
|
97
|
-
expect(computeStoryContentHash(before)).not.toBe(computeStoryContentHash(after));
|
|
98
|
-
});
|
|
99
|
-
});
|