@nathapp/nax 0.21.0 → 0.22.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/.mcp.json +8 -0
- package/docs/ROADMAP.md +20 -5
- package/docs/adr/ADR-005-implementation-plan.md +655 -0
- package/docs/adr/ADR-005-pipeline-re-architecture.md +464 -0
- package/package.json +1 -1
- package/src/agents/claude.ts +44 -9
- package/src/config/types.ts +11 -0
- package/src/execution/dry-run.ts +81 -0
- package/src/execution/escalation/tier-outcome.ts +29 -44
- package/src/execution/executor-types.ts +65 -0
- package/src/execution/index.ts +0 -17
- package/src/execution/iteration-runner.ts +132 -0
- package/src/execution/lifecycle/index.ts +0 -1
- package/src/execution/lifecycle/run-regression.ts +5 -5
- package/src/execution/pipeline-result-handler.ts +51 -254
- package/src/execution/sequential-executor.ts +72 -316
- package/src/execution/story-selector.ts +75 -0
- package/src/pipeline/event-bus.ts +276 -0
- package/src/pipeline/runner.ts +51 -77
- package/src/pipeline/stages/autofix.ts +133 -0
- package/src/pipeline/stages/completion.ts +22 -30
- package/src/pipeline/stages/index.ts +30 -13
- package/src/pipeline/stages/rectify.ts +93 -0
- package/src/pipeline/stages/regression.ts +88 -0
- package/src/pipeline/stages/review.ts +19 -153
- package/src/pipeline/stages/verify.ts +18 -2
- package/src/pipeline/subscribers/hooks.ts +133 -0
- package/src/pipeline/subscribers/interaction.ts +68 -0
- package/src/pipeline/subscribers/reporters.ts +174 -0
- package/src/pipeline/types.ts +10 -1
- package/src/review/orchestrator.ts +105 -0
- package/src/tdd/prompts.ts +1 -1
- package/src/verification/index.ts +1 -1
- package/src/verification/orchestrator-types.ts +145 -0
- package/src/verification/orchestrator.ts +76 -0
- package/src/{execution/post-verify-rectification.ts → verification/rectification-loop.ts} +13 -20
- package/src/verification/{gate.ts → runners.ts} +17 -105
- package/src/verification/strategies/acceptance.ts +133 -0
- package/src/verification/strategies/regression.ts +90 -0
- package/src/verification/strategies/scoped.ts +123 -0
- package/test/COVERAGE-GAPS.md +333 -0
- package/test/{acceptance → e2e}/cm-003-default-view.test.ts +1 -0
- package/test/{integration/e2e.test.ts → e2e/plan-analyze-run.test.ts} +1 -0
- package/test/integration/{agent-validation.test.ts → cli/agent-validation.test.ts} +3 -3
- package/test/integration/{cli-config-default-edge-cases.test.ts → cli/cli-config-default-edge-cases.test.ts} +6 -5
- package/test/integration/{cli-config-default-view.test.ts → cli/cli-config-default-view.test.ts} +8 -7
- package/test/integration/{cli-config-diff.test.ts → cli/cli-config-diff.test.ts} +3 -2
- package/test/integration/{cli-config.test.ts → cli/cli-config.test.ts} +3 -2
- package/test/integration/{cli-diagnose.test.ts → cli/cli-diagnose.test.ts} +5 -4
- package/test/integration/{cli-logs.test.ts → cli/cli-logs.test.ts} +12 -3
- package/test/integration/{cli-plugins.test.ts → cli/cli-plugins.test.ts} +4 -3
- package/test/integration/{cli-precheck.test.ts → cli/cli-precheck.test.ts} +4 -3
- package/test/integration/{cli-run-headless.test.ts → cli/cli-run-headless.test.ts} +3 -2
- package/test/integration/{cli.test.ts → cli/cli.test.ts} +2 -1
- package/test/integration/{precheck-integration.test.ts → cli/precheck-integration.test.ts} +10 -9
- package/test/integration/{precheck-orchestrator.test.ts → cli/precheck-orchestrator.test.ts} +4 -3
- package/test/integration/{precheck.test.ts → cli/precheck.test.ts} +5 -4
- package/test/integration/{config-loader.test.ts → config/config-loader.test.ts} +2 -1
- package/test/integration/{config.test.ts → config/config.test.ts} +2 -2
- package/test/integration/config/merger.test.ts +1 -0
- package/test/integration/config/paths.test.ts +1 -0
- package/test/integration/{security-loader.test.ts → config/security-loader.test.ts} +2 -2
- package/test/integration/{context-integration.test.ts → context/context-integration.test.ts} +7 -6
- package/test/integration/{path-security.test.ts → context/context-path-security.test.ts} +2 -2
- package/test/integration/{context-provider-injection.test.ts → context/context-provider-injection.test.ts} +7 -6
- package/test/integration/{context-verification-integration.test.ts → context/context-verification-integration.test.ts} +5 -4
- package/test/integration/{s5-greenfield-fallback.test.ts → context/s5-greenfield-fallback.test.ts} +4 -3
- package/test/integration/{isolation.test.ts → execution/execution-isolation.test.ts} +1 -1
- package/test/integration/{execution.test.ts → execution/execution.test.ts} +8 -8
- package/test/integration/{parallel.test.ts → execution/parallel.test.ts} +2 -1
- package/test/integration/{prd-pause.test.ts → execution/prd-pause.test.ts} +2 -2
- package/test/integration/{prd-resolvers.test.ts → execution/prd-resolvers.test.ts} +3 -2
- package/test/integration/{progress.test.ts → execution/progress.test.ts} +1 -1
- package/test/integration/execution/runner-batching.test.ts +682 -0
- package/test/integration/{runner-config-plugins.test.ts → execution/runner-config-plugins.test.ts} +3 -2
- package/test/integration/execution/runner-escalation.test.ts +561 -0
- package/test/integration/{runner-fixes.test.ts → execution/runner-fixes.test.ts} +4 -3
- package/test/integration/{runner-plugin-integration.test.ts → execution/runner-plugin-integration.test.ts} +6 -5
- package/test/integration/execution/runner-queue-and-attempts.test.ts +476 -0
- package/test/integration/{status-file-integration.test.ts → execution/status-file-integration.test.ts} +9 -8
- package/test/integration/{status-file.test.ts → execution/status-file.test.ts} +3 -2
- package/test/integration/{status-writer.test.ts → execution/status-writer.test.ts} +5 -4
- package/test/integration/{story-id-in-events.test.ts → execution/story-id-in-events.test.ts} +9 -8
- package/test/integration/{interaction-chain-pipeline.test.ts → interaction/interaction-chain-pipeline.test.ts} +26 -14
- package/test/integration/{hooks.test.ts → pipeline/hooks.test.ts} +4 -2
- package/test/integration/{pipeline-acceptance.test.ts → pipeline/pipeline-acceptance.test.ts} +7 -6
- package/test/integration/{pipeline-events.test.ts → pipeline/pipeline-events.test.ts} +7 -6
- package/test/integration/{pipeline.test.ts → pipeline/pipeline.test.ts} +9 -7
- package/test/integration/{reporter-lifecycle.test.ts → pipeline/reporter-lifecycle.test.ts} +9 -7
- package/test/integration/{verify-stage.test.ts → pipeline/verify-stage.test.ts} +7 -5
- package/test/integration/{analyze-integration.test.ts → plan/analyze-integration.test.ts} +3 -2
- package/test/integration/{analyze-scanner.test.ts → plan/analyze-scanner.test.ts} +8 -7
- package/test/integration/{logger.test.ts → plan/logger.test.ts} +1 -1
- package/test/integration/{plan.test.ts → plan/plan.test.ts} +3 -3
- package/test/integration/plugins/config-integration.test.ts +1 -0
- package/test/integration/plugins/config-resolution.test.ts +1 -0
- package/test/integration/plugins/loader.test.ts +1 -0
- package/test/integration/plugins/{registry.test.ts → plugins-registry.test.ts} +1 -0
- package/test/integration/plugins/validator.test.ts +1 -0
- package/test/integration/{review-config-commands.test.ts → review/review-config-commands.test.ts} +4 -3
- package/test/integration/{review-config-schema.test.ts → review/review-config-schema.test.ts} +3 -2
- package/test/integration/{review-plugin-integration.test.ts → review/review-plugin-integration.test.ts} +5 -4
- package/test/integration/{review.test.ts → review/review.test.ts} +3 -2
- package/test/integration/routing/plugin-routing-advanced.test.ts +461 -0
- package/test/integration/{plugin-routing.test.ts → routing/plugin-routing-core.test.ts} +9 -403
- package/test/integration/{routing-stage-bug-021.test.ts → routing/routing-stage-bug-021.test.ts} +8 -7
- package/test/integration/{routing-stage-greenfield.test.ts → routing/routing-stage-greenfield.test.ts} +7 -6
- package/test/integration/{tdd-cleanup.test.ts → tdd/tdd-cleanup.test.ts} +1 -1
- package/test/integration/tdd/tdd-orchestrator-core.test.ts +565 -0
- package/test/integration/tdd/tdd-orchestrator-failureCategory.test.ts +355 -0
- package/test/integration/tdd/tdd-orchestrator-fallback.test.ts +311 -0
- package/test/integration/tdd/tdd-orchestrator-lite.test.ts +289 -0
- package/test/integration/tdd/tdd-orchestrator-prompts.test.ts +260 -0
- package/test/integration/tdd/tdd-orchestrator-verdict.test.ts +536 -0
- package/test/integration/tmp/headless-test/test.jsonl +30 -0
- package/test/integration/{test-scanner.test.ts → verification/test-scanner.test.ts} +1 -1
- package/test/integration/{verification-asset-check.test.ts → verification/verification-asset-check.test.ts} +3 -2
- package/test/unit/acceptance.test.ts +1 -0
- package/test/unit/agent-stderr-capture.test.ts +1 -0
- package/test/unit/agents/claude.test.ts +1 -0
- package/test/unit/analyze-classifier.test.ts +1 -0
- package/test/unit/auto-detect.test.ts +1 -0
- package/test/unit/cli-status.test.ts +1 -0
- package/test/unit/commands/common.test.ts +1 -0
- package/test/unit/commands/logs.test.ts +1 -0
- package/test/unit/commands/unlock.test.ts +1 -0
- package/test/unit/config/defaults.test.ts +1 -0
- package/test/unit/config/regression-gate-schema.test.ts +1 -0
- package/test/unit/config/smart-runner-flag.test.ts +1 -0
- package/test/unit/constitution-generators.test.ts +1 -0
- package/test/unit/constitution.test.ts +1 -0
- package/test/unit/context/context-autodetect.test.ts +297 -0
- package/test/unit/context/context-build.test.ts +575 -0
- package/test/unit/context/context-coverage.test.ts +236 -0
- package/test/unit/context/context-error.test.ts +93 -0
- package/test/unit/context/context-estimate-tokens.test.ts +201 -0
- package/test/unit/context/context-format.test.ts +302 -0
- package/test/unit/context/context-isolation.test.ts +267 -0
- package/test/unit/context/context-sort.test.ts +93 -0
- package/test/unit/context/context-story.test.ts +108 -0
- package/test/{context → unit/context}/prior-failures.test.ts +5 -4
- package/test/unit/context.test.ts +1 -0
- package/test/unit/crash-recovery.test.ts +1 -0
- package/test/unit/escalation.test.ts +1 -0
- package/test/unit/execution/lifecycle/run-completion.test.ts +1 -0
- package/test/unit/execution/lifecycle/run-regression.test.ts +2 -0
- package/test/{execution → unit/execution}/pid-registry.test.ts +2 -1
- package/test/{execution → unit/execution}/structured-failure.test.ts +3 -2
- package/test/unit/execution-logging-stderr.test.ts +1 -0
- package/test/unit/execution-stage.test.ts +1 -0
- package/test/unit/fix-generator.test.ts +1 -0
- package/test/unit/greenfield.test.ts +1 -0
- package/test/unit/interaction/human-review-trigger.test.ts +1 -0
- package/test/unit/interaction-network-failures.test.ts +1 -0
- package/test/unit/interaction-plugins.test.ts +1 -0
- package/test/unit/logging/formatter.test.ts +1 -0
- package/test/unit/merge.test.ts +1 -0
- package/test/unit/pipeline/event-bus.test.ts +105 -0
- package/test/unit/pipeline/routing-partial-override.test.ts +1 -0
- package/test/unit/pipeline/runner-retry.test.ts +89 -0
- package/test/unit/pipeline/stages/autofix.test.ts +97 -0
- package/test/unit/pipeline/stages/rectify.test.ts +101 -0
- package/test/unit/pipeline/stages/regression-stage.test.ts +69 -0
- package/test/unit/pipeline/stages/verify.test.ts +1 -0
- package/test/unit/pipeline/subscribers/hooks.test.ts +45 -0
- package/test/unit/pipeline/subscribers/interaction.test.ts +31 -0
- package/test/unit/pipeline/subscribers/reporters.test.ts +90 -0
- package/test/unit/pipeline/verify-smart-runner.test.ts +1 -0
- package/test/unit/prd-auto-default.test.ts +1 -0
- package/test/unit/prd-failure-category.test.ts +1 -0
- package/test/unit/prd-get-next-story.test.ts +1 -0
- package/test/unit/precheck-checks.test.ts +1 -0
- package/test/unit/precheck-story-size-gate.test.ts +1 -0
- package/test/unit/precheck-types.test.ts +1 -0
- package/test/unit/prompts.test.ts +1 -0
- package/test/unit/rectification.test.ts +2 -1
- package/test/unit/registry.test.ts +1 -0
- package/test/unit/routing/routing-stability.test.ts +1 -0
- package/test/unit/routing/strategies/llm.test.ts +1 -0
- package/test/unit/routing-advanced.test.ts +313 -0
- package/test/unit/routing-core.test.ts +341 -0
- package/test/unit/routing-strategies.test.ts +442 -0
- package/test/unit/storyid-events.test.ts +1 -0
- package/test/{ui → unit/ui}/tui-controls.test.ts +8 -7
- package/test/{ui → unit/ui}/tui-cost-and-pty.test.ts +4 -3
- package/test/{ui → unit/ui}/tui-layout.test.ts +5 -4
- package/test/{ui → unit/ui}/tui-stories.test.ts +5 -4
- package/test/unit/{isolation.test.ts → unit-isolation.test.ts} +1 -0
- package/test/unit/{helpers.test.ts → utils-helpers.test.ts} +1 -0
- package/test/unit/verdict.test.ts +1 -0
- package/test/unit/verification/orchestrator-types.test.ts +54 -0
- package/test/unit/verification/orchestrator.test.ts +66 -0
- package/test/unit/verification/smart-runner-config.test.ts +1 -0
- package/test/unit/verification/smart-runner-discovery.test.ts +8 -7
- package/test/unit/verification/strategies/acceptance.test.ts +33 -0
- package/test/unit/verification/strategies/regression.test.ts +87 -0
- package/test/unit/verification/strategies/scoped.test.ts +100 -0
- package/test/unit/worktree-manager.test.ts +1 -0
- package/src/execution/lifecycle/story-hooks.ts +0 -38
- package/src/execution/post-verify.ts +0 -193
- package/src/execution/rectification.ts +0 -13
- package/src/execution/verification.ts +0 -72
- package/test/integration/rectification-flow.test.ts +0 -512
- package/test/integration/runner.test.ts +0 -1679
- package/test/integration/tdd-orchestrator.test.ts +0 -1762
- package/test/unit/execution/post-verify-regression.test.ts +0 -362
- package/test/unit/execution/post-verify.test.ts +0 -236
- package/test/unit/routing.test.ts +0 -1039
- /package/test/{integration → helpers}/helpers.test.ts +0 -0
- /package/test/integration/worktree/{merge.test.ts → worktree-merge.test.ts} +0 -0
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
// RE-ARCH: keep
|
|
2
|
+
/**
|
|
3
|
+
* Runner Tests — Story Batching + TDD Escalation
|
|
4
|
+
*
|
|
5
|
+
* Tests for grouping consecutive simple stories into batches,
|
|
6
|
+
* and TDD escalation handling (retryAsLite, failure category outcomes).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { describe, expect, test } from "bun:test";
|
|
10
|
+
import { groupStoriesIntoBatches, precomputeBatchPlan } from "../../../src/execution/batching";
|
|
11
|
+
import type { StoryBatch } from "../../../src/execution/batching";
|
|
12
|
+
import { escalateTier } from "../../../src/execution/escalation";
|
|
13
|
+
import { buildBatchPrompt } from "../../../src/execution/prompts";
|
|
14
|
+
import { resolveMaxAttemptsOutcome } from "../../../src/execution/runner";
|
|
15
|
+
import type { UserStory } from "../../../src/prd";
|
|
16
|
+
import type { FailureCategory } from "../../../src/tdd/types";
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
describe("Queue Commands Before Batch Execution", () => {
|
|
20
|
+
test("SKIP command should filter story from batch before execution", () => {
|
|
21
|
+
// Simulate a batch of 3 simple stories: [US-001, US-002, US-003]
|
|
22
|
+
// User issues SKIP US-002 in .queue.txt
|
|
23
|
+
// Expected: Batch should only contain [US-001, US-003]
|
|
24
|
+
const batchStories: UserStory[] = [
|
|
25
|
+
{
|
|
26
|
+
id: "US-001",
|
|
27
|
+
title: "Simple 1",
|
|
28
|
+
description: "First story in batch",
|
|
29
|
+
acceptanceCriteria: ["AC1"],
|
|
30
|
+
tags: [],
|
|
31
|
+
dependencies: [],
|
|
32
|
+
status: "pending",
|
|
33
|
+
passes: false,
|
|
34
|
+
escalations: [],
|
|
35
|
+
attempts: 0,
|
|
36
|
+
routing: { complexity: "simple", modelTier: "fast", testStrategy: "test-after", reasoning: "simple" },
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: "US-002",
|
|
40
|
+
title: "Simple 2",
|
|
41
|
+
description: "Second story in batch (to be skipped)",
|
|
42
|
+
acceptanceCriteria: ["AC2"],
|
|
43
|
+
tags: [],
|
|
44
|
+
dependencies: [],
|
|
45
|
+
status: "pending",
|
|
46
|
+
passes: false,
|
|
47
|
+
escalations: [],
|
|
48
|
+
attempts: 0,
|
|
49
|
+
routing: { complexity: "simple", modelTier: "fast", testStrategy: "test-after", reasoning: "simple" },
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: "US-003",
|
|
53
|
+
title: "Simple 3",
|
|
54
|
+
description: "Third story in batch",
|
|
55
|
+
acceptanceCriteria: ["AC3"],
|
|
56
|
+
tags: [],
|
|
57
|
+
dependencies: [],
|
|
58
|
+
status: "pending",
|
|
59
|
+
passes: false,
|
|
60
|
+
escalations: [],
|
|
61
|
+
attempts: 0,
|
|
62
|
+
routing: { complexity: "simple", modelTier: "fast", testStrategy: "test-after", reasoning: "simple" },
|
|
63
|
+
},
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
// Simulate SKIP command processing
|
|
67
|
+
const skipCommand = { type: "SKIP" as const, storyId: "US-002" };
|
|
68
|
+
const storyIndex = batchStories.findIndex((s) => s.id === skipCommand.storyId);
|
|
69
|
+
|
|
70
|
+
expect(storyIndex).toBe(1);
|
|
71
|
+
|
|
72
|
+
// Remove from batch
|
|
73
|
+
const filteredBatch = batchStories.filter((s) => s.id !== skipCommand.storyId);
|
|
74
|
+
|
|
75
|
+
expect(filteredBatch).toHaveLength(2);
|
|
76
|
+
expect(filteredBatch.map((s) => s.id)).toEqual(["US-001", "US-003"]);
|
|
77
|
+
expect(filteredBatch.every((s) => s.status === "pending")).toBe(true);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("SKIP all stories in batch should result in empty batch and continue to next iteration", () => {
|
|
81
|
+
// Simulate a batch of 2 simple stories: [US-001, US-002]
|
|
82
|
+
// User issues SKIP US-001 and SKIP US-002
|
|
83
|
+
// Expected: Batch becomes empty, runner should continue to next iteration
|
|
84
|
+
const batchStories: UserStory[] = [
|
|
85
|
+
{
|
|
86
|
+
id: "US-001",
|
|
87
|
+
title: "Simple 1",
|
|
88
|
+
description: "First story",
|
|
89
|
+
acceptanceCriteria: ["AC1"],
|
|
90
|
+
tags: [],
|
|
91
|
+
dependencies: [],
|
|
92
|
+
status: "pending",
|
|
93
|
+
passes: false,
|
|
94
|
+
escalations: [],
|
|
95
|
+
attempts: 0,
|
|
96
|
+
routing: { complexity: "simple", modelTier: "fast", testStrategy: "test-after", reasoning: "simple" },
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
id: "US-002",
|
|
100
|
+
title: "Simple 2",
|
|
101
|
+
description: "Second story",
|
|
102
|
+
acceptanceCriteria: ["AC2"],
|
|
103
|
+
tags: [],
|
|
104
|
+
dependencies: [],
|
|
105
|
+
status: "pending",
|
|
106
|
+
passes: false,
|
|
107
|
+
escalations: [],
|
|
108
|
+
attempts: 0,
|
|
109
|
+
routing: { complexity: "simple", modelTier: "fast", testStrategy: "test-after", reasoning: "simple" },
|
|
110
|
+
},
|
|
111
|
+
];
|
|
112
|
+
|
|
113
|
+
// Simulate SKIP commands
|
|
114
|
+
const skipCommands = [
|
|
115
|
+
{ type: "SKIP" as const, storyId: "US-001" },
|
|
116
|
+
{ type: "SKIP" as const, storyId: "US-002" },
|
|
117
|
+
];
|
|
118
|
+
|
|
119
|
+
let filteredBatch = [...batchStories];
|
|
120
|
+
for (const cmd of skipCommands) {
|
|
121
|
+
filteredBatch = filteredBatch.filter((s) => s.id !== cmd.storyId);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
expect(filteredBatch).toHaveLength(0);
|
|
125
|
+
// When batch is empty, runner should continue to next iteration
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test("PAUSE command should halt execution before batch starts", () => {
|
|
129
|
+
// When PAUSE is issued before batch execution
|
|
130
|
+
// Expected: Execution stops, no stories are processed
|
|
131
|
+
const pauseCommand = "PAUSE" as const;
|
|
132
|
+
const batchStories: UserStory[] = [
|
|
133
|
+
{
|
|
134
|
+
id: "US-001",
|
|
135
|
+
title: "Simple 1",
|
|
136
|
+
description: "First story",
|
|
137
|
+
acceptanceCriteria: ["AC1"],
|
|
138
|
+
tags: [],
|
|
139
|
+
dependencies: [],
|
|
140
|
+
status: "pending",
|
|
141
|
+
passes: false,
|
|
142
|
+
escalations: [],
|
|
143
|
+
attempts: 0,
|
|
144
|
+
routing: { complexity: "simple", modelTier: "fast", testStrategy: "test-after", reasoning: "simple" },
|
|
145
|
+
},
|
|
146
|
+
];
|
|
147
|
+
|
|
148
|
+
// Simulate PAUSE processing
|
|
149
|
+
let shouldHalt = false;
|
|
150
|
+
if (pauseCommand === "PAUSE") {
|
|
151
|
+
shouldHalt = true;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
expect(shouldHalt).toBe(true);
|
|
155
|
+
// When halted, no stories should be executed
|
|
156
|
+
expect(batchStories.every((s) => s.status === "pending")).toBe(true);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test("SKIP command for story not in batch should still mark it as skipped", () => {
|
|
160
|
+
// Simulate batch [US-001, US-002] but user issues SKIP US-003
|
|
161
|
+
// Expected: US-003 is marked skipped even though not in current batch
|
|
162
|
+
const batchStories: UserStory[] = [
|
|
163
|
+
{
|
|
164
|
+
id: "US-001",
|
|
165
|
+
title: "Simple 1",
|
|
166
|
+
description: "First story",
|
|
167
|
+
acceptanceCriteria: ["AC1"],
|
|
168
|
+
tags: [],
|
|
169
|
+
dependencies: [],
|
|
170
|
+
status: "pending",
|
|
171
|
+
passes: false,
|
|
172
|
+
escalations: [],
|
|
173
|
+
attempts: 0,
|
|
174
|
+
routing: { complexity: "simple", modelTier: "fast", testStrategy: "test-after", reasoning: "simple" },
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
id: "US-002",
|
|
178
|
+
title: "Simple 2",
|
|
179
|
+
description: "Second story",
|
|
180
|
+
acceptanceCriteria: ["AC2"],
|
|
181
|
+
tags: [],
|
|
182
|
+
dependencies: [],
|
|
183
|
+
status: "pending",
|
|
184
|
+
passes: false,
|
|
185
|
+
escalations: [],
|
|
186
|
+
attempts: 0,
|
|
187
|
+
routing: { complexity: "simple", modelTier: "fast", testStrategy: "test-after", reasoning: "simple" },
|
|
188
|
+
},
|
|
189
|
+
];
|
|
190
|
+
|
|
191
|
+
const skipCommand = { type: "SKIP" as const, storyId: "US-003" };
|
|
192
|
+
const storyIndex = batchStories.findIndex((s) => s.id === skipCommand.storyId);
|
|
193
|
+
|
|
194
|
+
// Story not found in batch
|
|
195
|
+
expect(storyIndex).toBe(-1);
|
|
196
|
+
|
|
197
|
+
// But should still be processed (in actual runner, PRD would be checked)
|
|
198
|
+
// This test validates the logic path exists
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
test("batch size reduction from 4 to 1 should disable batch execution flag", () => {
|
|
202
|
+
// Simulate batch [US-001, US-002, US-003, US-004]
|
|
203
|
+
// User issues SKIP US-002, SKIP US-003, SKIP US-004
|
|
204
|
+
// Expected: Only US-001 remains, isBatchExecution should be false
|
|
205
|
+
const batchStories: UserStory[] = [
|
|
206
|
+
{
|
|
207
|
+
id: "US-001",
|
|
208
|
+
title: "Simple 1",
|
|
209
|
+
description: "First story",
|
|
210
|
+
acceptanceCriteria: ["AC1"],
|
|
211
|
+
tags: [],
|
|
212
|
+
dependencies: [],
|
|
213
|
+
status: "pending",
|
|
214
|
+
passes: false,
|
|
215
|
+
escalations: [],
|
|
216
|
+
attempts: 0,
|
|
217
|
+
routing: { complexity: "simple", modelTier: "fast", testStrategy: "test-after", reasoning: "simple" },
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
id: "US-002",
|
|
221
|
+
title: "Simple 2",
|
|
222
|
+
description: "Second story",
|
|
223
|
+
acceptanceCriteria: ["AC2"],
|
|
224
|
+
tags: [],
|
|
225
|
+
dependencies: [],
|
|
226
|
+
status: "pending",
|
|
227
|
+
passes: false,
|
|
228
|
+
escalations: [],
|
|
229
|
+
attempts: 0,
|
|
230
|
+
routing: { complexity: "simple", modelTier: "fast", testStrategy: "test-after", reasoning: "simple" },
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
id: "US-003",
|
|
234
|
+
title: "Simple 3",
|
|
235
|
+
description: "Third story",
|
|
236
|
+
acceptanceCriteria: ["AC3"],
|
|
237
|
+
tags: [],
|
|
238
|
+
dependencies: [],
|
|
239
|
+
status: "pending",
|
|
240
|
+
passes: false,
|
|
241
|
+
escalations: [],
|
|
242
|
+
attempts: 0,
|
|
243
|
+
routing: { complexity: "simple", modelTier: "fast", testStrategy: "test-after", reasoning: "simple" },
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
id: "US-004",
|
|
247
|
+
title: "Simple 4",
|
|
248
|
+
description: "Fourth story",
|
|
249
|
+
acceptanceCriteria: ["AC4"],
|
|
250
|
+
tags: [],
|
|
251
|
+
dependencies: [],
|
|
252
|
+
status: "pending",
|
|
253
|
+
passes: false,
|
|
254
|
+
escalations: [],
|
|
255
|
+
attempts: 0,
|
|
256
|
+
routing: { complexity: "simple", modelTier: "fast", testStrategy: "test-after", reasoning: "simple" },
|
|
257
|
+
},
|
|
258
|
+
];
|
|
259
|
+
|
|
260
|
+
let isBatchExecution = true; // Initially true for 4 stories
|
|
261
|
+
const skipCommands = [
|
|
262
|
+
{ type: "SKIP" as const, storyId: "US-002" },
|
|
263
|
+
{ type: "SKIP" as const, storyId: "US-003" },
|
|
264
|
+
{ type: "SKIP" as const, storyId: "US-004" },
|
|
265
|
+
];
|
|
266
|
+
|
|
267
|
+
let filteredBatch = [...batchStories];
|
|
268
|
+
for (const cmd of skipCommands) {
|
|
269
|
+
filteredBatch = filteredBatch.filter((s) => s.id !== cmd.storyId);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Re-check batch flag
|
|
273
|
+
if (isBatchExecution && filteredBatch.length === 1) {
|
|
274
|
+
isBatchExecution = false;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
expect(filteredBatch).toHaveLength(1);
|
|
278
|
+
expect(filteredBatch[0].id).toBe("US-001");
|
|
279
|
+
expect(isBatchExecution).toBe(false);
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
test("ABORT command should mark all pending stories as skipped", () => {
|
|
283
|
+
// When ABORT is issued
|
|
284
|
+
// Expected: All pending stories should be marked as skipped
|
|
285
|
+
const abortCommand = "ABORT" as const;
|
|
286
|
+
const allStories: UserStory[] = [
|
|
287
|
+
{
|
|
288
|
+
id: "US-001",
|
|
289
|
+
title: "Passed",
|
|
290
|
+
description: "Already done",
|
|
291
|
+
acceptanceCriteria: ["AC1"],
|
|
292
|
+
tags: [],
|
|
293
|
+
dependencies: [],
|
|
294
|
+
status: "passed",
|
|
295
|
+
passes: true,
|
|
296
|
+
escalations: [],
|
|
297
|
+
attempts: 1,
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
id: "US-002",
|
|
301
|
+
title: "Pending 1",
|
|
302
|
+
description: "Not started",
|
|
303
|
+
acceptanceCriteria: ["AC2"],
|
|
304
|
+
tags: [],
|
|
305
|
+
dependencies: [],
|
|
306
|
+
status: "pending",
|
|
307
|
+
passes: false,
|
|
308
|
+
escalations: [],
|
|
309
|
+
attempts: 0,
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
id: "US-003",
|
|
313
|
+
title: "Pending 2",
|
|
314
|
+
description: "Not started",
|
|
315
|
+
acceptanceCriteria: ["AC3"],
|
|
316
|
+
tags: [],
|
|
317
|
+
dependencies: [],
|
|
318
|
+
status: "pending",
|
|
319
|
+
passes: false,
|
|
320
|
+
escalations: [],
|
|
321
|
+
attempts: 0,
|
|
322
|
+
},
|
|
323
|
+
];
|
|
324
|
+
|
|
325
|
+
// Simulate ABORT processing
|
|
326
|
+
let shouldAbort = false;
|
|
327
|
+
if (abortCommand === "ABORT") {
|
|
328
|
+
shouldAbort = true;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
expect(shouldAbort).toBe(true);
|
|
332
|
+
|
|
333
|
+
// Filter pending stories that should be skipped
|
|
334
|
+
const pendingStories = allStories.filter((s) => s.status === "pending");
|
|
335
|
+
expect(pendingStories).toHaveLength(2);
|
|
336
|
+
expect(pendingStories.map((s) => s.id)).toEqual(["US-002", "US-003"]);
|
|
337
|
+
|
|
338
|
+
// In actual runner, these would be marked as skipped via markStorySkipped()
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
describe("TDD escalation attempts counting", () => {
|
|
344
|
+
const defaultTiers = [
|
|
345
|
+
{ tier: "fast", attempts: 5 },
|
|
346
|
+
{ tier: "balanced", attempts: 3 },
|
|
347
|
+
{ tier: "powerful", attempts: 2 },
|
|
348
|
+
];
|
|
349
|
+
|
|
350
|
+
test("attempts increment on each TDD escalation", () => {
|
|
351
|
+
// Simulate a TDD story escalating: fast(attempt 1) → balanced(attempt 2) → ...
|
|
352
|
+
let story: UserStory = {
|
|
353
|
+
id: "US-001",
|
|
354
|
+
title: "TDD Story",
|
|
355
|
+
description: "Complex TDD story",
|
|
356
|
+
acceptanceCriteria: ["All tests pass"],
|
|
357
|
+
tags: [],
|
|
358
|
+
dependencies: [],
|
|
359
|
+
status: "pending",
|
|
360
|
+
passes: false,
|
|
361
|
+
escalations: [],
|
|
362
|
+
attempts: 0,
|
|
363
|
+
routing: { complexity: "complex", modelTier: "fast", testStrategy: "three-session-tdd", reasoning: "complex" },
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
// Simulate escalation (what runner does)
|
|
367
|
+
story = {
|
|
368
|
+
...story,
|
|
369
|
+
attempts: story.attempts + 1,
|
|
370
|
+
routing: story.routing ? { ...story.routing, modelTier: "balanced" } : undefined,
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
expect(story.attempts).toBe(1);
|
|
374
|
+
expect(story.routing?.modelTier).toBe("balanced");
|
|
375
|
+
|
|
376
|
+
// Second escalation
|
|
377
|
+
story = {
|
|
378
|
+
...story,
|
|
379
|
+
attempts: story.attempts + 1,
|
|
380
|
+
routing: story.routing ? { ...story.routing, modelTier: "powerful" } : undefined,
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
expect(story.attempts).toBe(2);
|
|
384
|
+
expect(story.routing?.modelTier).toBe("powerful");
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
test("TDD story with retryAsLite gets lite strategy on first isolation-violation escalation", () => {
|
|
388
|
+
let story: UserStory = {
|
|
389
|
+
id: "US-001",
|
|
390
|
+
title: "TDD Story",
|
|
391
|
+
description: "Complex TDD story",
|
|
392
|
+
acceptanceCriteria: ["All tests pass"],
|
|
393
|
+
tags: [],
|
|
394
|
+
dependencies: [],
|
|
395
|
+
status: "pending",
|
|
396
|
+
passes: false,
|
|
397
|
+
escalations: [],
|
|
398
|
+
attempts: 0,
|
|
399
|
+
routing: { complexity: "complex", modelTier: "fast", testStrategy: "three-session-tdd", reasoning: "complex" },
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
// First escalation: isolation-violation → retryAsLite=true
|
|
403
|
+
const retryAsLite = true;
|
|
404
|
+
const nextTier = "balanced" as const;
|
|
405
|
+
|
|
406
|
+
story = {
|
|
407
|
+
...story,
|
|
408
|
+
attempts: story.attempts + 1,
|
|
409
|
+
routing: story.routing
|
|
410
|
+
? {
|
|
411
|
+
...story.routing,
|
|
412
|
+
modelTier: nextTier,
|
|
413
|
+
...(retryAsLite ? { testStrategy: "three-session-tdd-lite" as const } : {}),
|
|
414
|
+
}
|
|
415
|
+
: undefined,
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
expect(story.attempts).toBe(1);
|
|
419
|
+
expect(story.routing?.modelTier).toBe("balanced");
|
|
420
|
+
expect(story.routing?.testStrategy).toBe("three-session-tdd-lite");
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
test("second escalation after retryAsLite does NOT change strategy again", () => {
|
|
424
|
+
// Story is now in lite mode after first escalation
|
|
425
|
+
let story: UserStory = {
|
|
426
|
+
id: "US-001",
|
|
427
|
+
title: "TDD Story",
|
|
428
|
+
description: "Complex TDD story",
|
|
429
|
+
acceptanceCriteria: ["All tests pass"],
|
|
430
|
+
tags: [],
|
|
431
|
+
dependencies: [],
|
|
432
|
+
status: "pending",
|
|
433
|
+
passes: false,
|
|
434
|
+
escalations: [],
|
|
435
|
+
attempts: 1,
|
|
436
|
+
routing: {
|
|
437
|
+
complexity: "complex",
|
|
438
|
+
modelTier: "balanced",
|
|
439
|
+
testStrategy: "three-session-tdd-lite", // Already downgraded
|
|
440
|
+
reasoning: "complex",
|
|
441
|
+
},
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
// Second escalation: lite mode failure → retryAsLite is NOT set (only fires once)
|
|
445
|
+
const retryAsLite = false; // Not set on subsequent escalations
|
|
446
|
+
const nextTier = "powerful" as const;
|
|
447
|
+
|
|
448
|
+
story = {
|
|
449
|
+
...story,
|
|
450
|
+
attempts: story.attempts + 1,
|
|
451
|
+
routing: story.routing
|
|
452
|
+
? {
|
|
453
|
+
...story.routing,
|
|
454
|
+
modelTier: nextTier,
|
|
455
|
+
...(retryAsLite ? { testStrategy: "three-session-tdd-lite" as const } : {}),
|
|
456
|
+
}
|
|
457
|
+
: undefined,
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
expect(story.attempts).toBe(2);
|
|
461
|
+
expect(story.routing?.modelTier).toBe("powerful");
|
|
462
|
+
// Strategy remains lite (not reset) — retryAsLite only fires once
|
|
463
|
+
expect(story.routing?.testStrategy).toBe("three-session-tdd-lite");
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
test("max attempts check works correctly for TDD stories using total across tiers", () => {
|
|
467
|
+
const { calculateMaxIterations } = require("../../../src/execution/escalation");
|
|
468
|
+
const maxAttempts = calculateMaxIterations(defaultTiers);
|
|
469
|
+
|
|
470
|
+
// A TDD story at attempt 9 (one below max) should still be escalatable
|
|
471
|
+
expect(9 < maxAttempts).toBe(true);
|
|
472
|
+
|
|
473
|
+
// A TDD story at attempt 10 (= max) should NOT be escalatable
|
|
474
|
+
expect(10 < maxAttempts).toBe(false);
|
|
475
|
+
});
|
|
476
|
+
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// RE-ARCH: keep
|
|
1
2
|
/**
|
|
2
3
|
* Integration Tests: Status File — runner + CLI (T2)
|
|
3
4
|
*
|
|
@@ -15,7 +16,7 @@ import * as nodeFs from "node:fs";
|
|
|
15
16
|
import * as fs from "node:fs/promises";
|
|
16
17
|
import * as os from "node:os";
|
|
17
18
|
import * as path from "node:path";
|
|
18
|
-
import { ALL_AGENTS } from "
|
|
19
|
+
import { ALL_AGENTS } from "../../../src/agents/registry";
|
|
19
20
|
import type {
|
|
20
21
|
AgentAdapter,
|
|
21
22
|
AgentCapabilities,
|
|
@@ -25,13 +26,13 @@ import type {
|
|
|
25
26
|
DecomposeResult,
|
|
26
27
|
PlanOptions,
|
|
27
28
|
PlanResult,
|
|
28
|
-
} from "
|
|
29
|
-
import { DEFAULT_CONFIG } from "
|
|
30
|
-
import type { NaxConfig } from "
|
|
31
|
-
import { run } from "
|
|
32
|
-
import type { RunOptions } from "
|
|
33
|
-
import type { NaxStatusFile } from "
|
|
34
|
-
import type { PRD } from "
|
|
29
|
+
} from "../../../src/agents/types";
|
|
30
|
+
import { DEFAULT_CONFIG } from "../../../src/config";
|
|
31
|
+
import type { NaxConfig } from "../../../src/config";
|
|
32
|
+
import { run } from "../../../src/execution/runner";
|
|
33
|
+
import type { RunOptions } from "../../../src/execution/runner";
|
|
34
|
+
import type { NaxStatusFile } from "../../../src/execution/status-file";
|
|
35
|
+
import type { PRD } from "../../../src/prd/types";
|
|
35
36
|
|
|
36
37
|
// ============================================================================
|
|
37
38
|
// Mock agent (satisfies agent installation check in runner)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// RE-ARCH: keep
|
|
1
2
|
/**
|
|
2
3
|
* Status File Tests
|
|
3
4
|
*
|
|
@@ -20,8 +21,8 @@ import {
|
|
|
20
21
|
buildStatusSnapshot,
|
|
21
22
|
countProgress,
|
|
22
23
|
writeStatusFile,
|
|
23
|
-
} from "
|
|
24
|
-
import type { PRD, UserStory } from "
|
|
24
|
+
} from "../../../src/execution/status-file";
|
|
25
|
+
import type { PRD, UserStory } from "../../../src/prd";
|
|
25
26
|
|
|
26
27
|
// ============================================================================
|
|
27
28
|
// Helpers
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// RE-ARCH: keep
|
|
1
2
|
/**
|
|
2
3
|
* StatusWriter Tests
|
|
3
4
|
*
|
|
@@ -13,10 +14,10 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
13
14
|
import { mkdtemp, rm } from "node:fs/promises";
|
|
14
15
|
import { tmpdir } from "node:os";
|
|
15
16
|
import { join } from "node:path";
|
|
16
|
-
import type { NaxConfig } from "
|
|
17
|
-
import type { NaxStatusFile } from "
|
|
18
|
-
import { StatusWriter, type StatusWriterContext } from "
|
|
19
|
-
import type { PRD, UserStory } from "
|
|
17
|
+
import type { NaxConfig } from "../../../src/config";
|
|
18
|
+
import type { NaxStatusFile } from "../../../src/execution/status-file";
|
|
19
|
+
import { StatusWriter, type StatusWriterContext } from "../../../src/execution/status-writer";
|
|
20
|
+
import type { PRD, UserStory } from "../../../src/prd";
|
|
20
21
|
|
|
21
22
|
// ============================================================================
|
|
22
23
|
// Helpers
|
package/test/integration/{story-id-in-events.test.ts → execution/story-id-in-events.test.ts}
RENAMED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// RE-ARCH: keep
|
|
1
2
|
/**
|
|
2
3
|
* Test: Verify storyId presence in JSONL events (BUG-020)
|
|
3
4
|
*
|
|
@@ -9,14 +10,14 @@ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
|
9
10
|
import { mkdtempSync, rmSync } from "node:fs";
|
|
10
11
|
import { tmpdir } from "node:os";
|
|
11
12
|
import { join } from "node:path";
|
|
12
|
-
import type { NaxConfig } from "
|
|
13
|
-
import { initLogger, resetLogger } from "
|
|
14
|
-
import { getLogger } from "
|
|
15
|
-
import type { LogEntry } from "
|
|
16
|
-
import { executionStage } from "
|
|
17
|
-
import { verifyStage } from "
|
|
18
|
-
import type { PipelineContext } from "
|
|
19
|
-
import type { PRD, UserStory } from "
|
|
13
|
+
import type { NaxConfig } from "../../../src/config/schema";
|
|
14
|
+
import { initLogger, resetLogger } from "../../../src/logger";
|
|
15
|
+
import { getLogger } from "../../../src/logger";
|
|
16
|
+
import type { LogEntry } from "../../../src/logger/types";
|
|
17
|
+
import { executionStage } from "../../../src/pipeline/stages/execution";
|
|
18
|
+
import { verifyStage } from "../../../src/pipeline/stages/verify";
|
|
19
|
+
import type { PipelineContext } from "../../../src/pipeline/types";
|
|
20
|
+
import type { PRD, UserStory } from "../../../src/prd/types";
|
|
20
21
|
|
|
21
22
|
/** Captured log entries */
|
|
22
23
|
let capturedLogs: LogEntry[] = [];
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// RE-ARCH: rewrite
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Integration Tests: Interaction Chain → Pipeline (BUG-025)
|
|
3
5
|
*
|
|
@@ -10,14 +12,16 @@
|
|
|
10
12
|
*/
|
|
11
13
|
|
|
12
14
|
import { describe, expect, mock, test } from "bun:test";
|
|
13
|
-
import type { NaxConfig } from "
|
|
14
|
-
import { InteractionChain } from "
|
|
15
|
-
import {
|
|
16
|
-
import
|
|
17
|
-
import {
|
|
18
|
-
import type {
|
|
19
|
-
import
|
|
20
|
-
import type {
|
|
15
|
+
import type { NaxConfig } from "../../../src/config";
|
|
16
|
+
import { InteractionChain } from "../../../src/interaction/chain";
|
|
17
|
+
import { pipelineEventBus } from "../../../src/pipeline/event-bus";
|
|
18
|
+
import { wireInteraction } from "../../../src/pipeline/subscribers/interaction";
|
|
19
|
+
import { CLIInteractionPlugin } from "../../../src/interaction/plugins/cli";
|
|
20
|
+
import type { InteractionPlugin, InteractionRequest, InteractionResponse, TriggerName } from "../../../src/interaction/types";
|
|
21
|
+
import { TRIGGER_METADATA } from "../../../src/interaction/types";
|
|
22
|
+
import type { PipelineContext } from "../../../src/pipeline/types";
|
|
23
|
+
import type { SequentialExecutionContext } from "../../../src/execution/sequential-executor";
|
|
24
|
+
import type { PRD, UserStory } from "../../../src/prd/types";
|
|
21
25
|
|
|
22
26
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
23
27
|
// Fixtures
|
|
@@ -227,9 +231,13 @@ describe("AC2: max retries triggers human-review interaction", () => {
|
|
|
227
231
|
|
|
228
232
|
const prd: PRD = { ...basePrd, userStories: [exhaustedStory] };
|
|
229
233
|
|
|
234
|
+
// Wire interaction subscriber on the singleton bus (Phase 3: replaces direct executeTrigger call)
|
|
235
|
+
pipelineEventBus.clear();
|
|
236
|
+
wireInteraction(pipelineEventBus, chain, baseConfig as any);
|
|
237
|
+
|
|
230
238
|
// Import and invoke the failure handler or sequential executor path
|
|
231
239
|
// that should fire 'human-review' when a story has exceeded max retries
|
|
232
|
-
const { handlePipelineFailure } = await import("
|
|
240
|
+
const { handlePipelineFailure } = await import("../../../src/execution/pipeline-result-handler");
|
|
233
241
|
await handlePipelineFailure(
|
|
234
242
|
{
|
|
235
243
|
config: baseConfig as NaxConfig,
|
|
@@ -282,6 +290,10 @@ describe("AC2: max retries triggers human-review interaction", () => {
|
|
|
282
290
|
const { plugin, sentRequests } = buildCapturingPlugin();
|
|
283
291
|
chain.register(plugin, 10);
|
|
284
292
|
|
|
293
|
+
// Wire interaction subscriber on the singleton bus (Phase 3)
|
|
294
|
+
pipelineEventBus.clear();
|
|
295
|
+
wireInteraction(pipelineEventBus, chain, baseConfig as any);
|
|
296
|
+
|
|
285
297
|
const failingStory: UserStory = {
|
|
286
298
|
...baseStory,
|
|
287
299
|
id: "US-FAILING",
|
|
@@ -292,12 +304,12 @@ describe("AC2: max retries triggers human-review interaction", () => {
|
|
|
292
304
|
const prd: PRD = { ...basePrd, userStories: [failingStory] };
|
|
293
305
|
|
|
294
306
|
// Verify the trigger is enabled
|
|
295
|
-
const { isTriggerEnabled } = await import("
|
|
307
|
+
const { isTriggerEnabled } = await import("../../../src/interaction/triggers");
|
|
296
308
|
const enabled = isTriggerEnabled("human-review" as TriggerName, baseConfig as NaxConfig);
|
|
297
309
|
expect(enabled).toBe(true);
|
|
298
310
|
|
|
299
311
|
// Call handlePipelineFailure to trigger the human-review request
|
|
300
|
-
const { handlePipelineFailure } = await import("
|
|
312
|
+
const { handlePipelineFailure } = await import("../../../src/execution/pipeline-result-handler");
|
|
301
313
|
await handlePipelineFailure(
|
|
302
314
|
{
|
|
303
315
|
config: baseConfig as NaxConfig,
|
|
@@ -360,7 +372,7 @@ describe("AC2: max retries triggers human-review interaction", () => {
|
|
|
360
372
|
chain.register(plugin, 10);
|
|
361
373
|
|
|
362
374
|
// When human-review returns 'skip', the story outcome should be 'skipped'
|
|
363
|
-
const { executeSequential } = await import("
|
|
375
|
+
const { executeSequential } = await import("../../../src/execution/sequential-executor");
|
|
364
376
|
|
|
365
377
|
const exhaustedStory: UserStory = {
|
|
366
378
|
...baseStory,
|
|
@@ -414,7 +426,7 @@ describe("AC3: CLI interaction plugin for non-headless human-review", () => {
|
|
|
414
426
|
|
|
415
427
|
test("initInteractionChain registers CLI plugin for non-headless mode", async () => {
|
|
416
428
|
// FAILS if initInteractionChain doesn't register CLI plugin when headless=false
|
|
417
|
-
const { initInteractionChain } = await import("
|
|
429
|
+
const { initInteractionChain } = await import("../../../src/interaction");
|
|
418
430
|
|
|
419
431
|
const config = {
|
|
420
432
|
...baseConfig,
|
|
@@ -436,7 +448,7 @@ describe("AC3: CLI interaction plugin for non-headless human-review", () => {
|
|
|
436
448
|
|
|
437
449
|
test("human-review request sent through CLI plugin contains all required fields", async () => {
|
|
438
450
|
// FAILS until BUG-025 implements human-review trigger in TRIGGER_METADATA
|
|
439
|
-
const { createTriggerRequest } = await import("
|
|
451
|
+
const { createTriggerRequest } = await import("../../../src/interaction/triggers");
|
|
440
452
|
|
|
441
453
|
const request = createTriggerRequest(
|
|
442
454
|
"human-review" as TriggerName,
|