/**
 * Tests for Story 31-4: Migrate TDD Flow to Workflow Definition
 *
 * These tests verify that the workflow YAML files correctly capture
 * the hardcoded TDD flow from the SM agent. This is a migration verification
 * test suite - it ensures the YAML definitions match expected behavior.
 *
 * Acceptance Criteria:
 * - AC1: tdd.yaml workflow exists in pennyfarthing-dist/workflows/
 * - AC2: Defines SM → TEA → Dev → Reviewer → SM phases
 * - AC3: Scale routing (1-2 pts skip TEA) preserved via trivial.yaml
 * - AC4: Existing /new-work behavior unchanged (regression tested)
 *
 * Run with: npm test
 */
import { describe, it } from 'node:test';
import assert from 'node:assert';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { existsSync } from 'node:fs';
import { loadWorkflowFile, loadWorkflowsFromDir } from './workflow-loader.js';
import { routeStoryToWorkflow } from './workflow-router.js';
// =============================================================================
// Test Setup - Find workflow directory
// =============================================================================
function findMonorepoRoot(startDir) {
    let dir = startDir;
    for (let i = 0; i < 10; i++) {
        if (existsSync(join(dir, 'pennyfarthing-dist'))) {
            return dir;
        }
        const parent = dirname(dir);
        if (parent === dir)
            break;
        dir = parent;
    }
    return null;
}
const __dirname = dirname(fileURLToPath(import.meta.url));
const monorepoRoot = findMonorepoRoot(__dirname);
const workflowsDir = monorepoRoot ? join(monorepoRoot, 'pennyfarthing-dist', 'workflows') : null;
// =============================================================================
// AC1: tdd.yaml workflow exists in pennyfarthing-dist/workflows/
// =============================================================================
describe('AC1: tdd.yaml workflow exists', () => {
    it('should find pennyfarthing-dist/workflows directory', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        assert.ok(existsSync(workflowsDir), `Workflows directory should exist: ${workflowsDir}`);
    });
    it('should load tdd.yaml from pennyfarthing-dist/workflows/', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const tddPath = join(workflowsDir, 'tdd.yaml');
        assert.ok(existsSync(tddPath), `tdd.yaml should exist at: ${tddPath}`);
        const result = loadWorkflowFile(tddPath);
        assert.ok(result.success, `tdd.yaml should load successfully: ${JSON.stringify(result.errors)}`);
        assert.ok(result.workflow, 'Should have workflow object');
        assert.strictEqual(result.workflow.name, 'tdd', 'Workflow name should be "tdd"');
    });
    it('should load trivial.yaml from pennyfarthing-dist/workflows/', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const trivialPath = join(workflowsDir, 'trivial.yaml');
        assert.ok(existsSync(trivialPath), `trivial.yaml should exist at: ${trivialPath}`);
        const result = loadWorkflowFile(trivialPath);
        assert.ok(result.success, `trivial.yaml should load successfully: ${JSON.stringify(result.errors)}`);
        assert.ok(result.workflow, 'Should have workflow object');
        assert.strictEqual(result.workflow.name, 'trivial', 'Workflow name should be "trivial"');
    });
});
// =============================================================================
// AC2: Defines SM → TEA → Dev → Reviewer → SM phases
// =============================================================================
describe('AC2: TDD workflow defines correct phases', () => {
    it('should have exactly 5 phases in tdd.yaml', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const result = loadWorkflowFile(join(workflowsDir, 'tdd.yaml'));
        assert.ok(result.success && result.workflow, 'Should load tdd.yaml');
        assert.strictEqual(result.workflow.phases?.length, 5, 'TDD workflow should have 5 phases');
    });
    it('should define phases in order: setup(SM) → red(TEA) → green(Dev) → review(Reviewer) → finish(SM)', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const result = loadWorkflowFile(join(workflowsDir, 'tdd.yaml'));
        assert.ok(result.success && result.workflow, 'Should load tdd.yaml');
        const phases = result.workflow.phases;
        const expectedFlow = [
            { name: 'setup', agent: 'sm' },
            { name: 'red', agent: 'tea' },
            { name: 'green', agent: 'dev' },
            { name: 'review', agent: 'reviewer' },
            { name: 'finish', agent: 'sm' }
        ];
        expectedFlow.forEach((expected, i) => {
            assert.strictEqual(phases[i].name, expected.name, `Phase ${i} should be "${expected.name}"`);
            assert.strictEqual(phases[i].agent, expected.agent, `Phase ${i} agent should be "${expected.agent}"`);
        });
    });
    it('should have RED phase with tests_fail gate', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const result = loadWorkflowFile(join(workflowsDir, 'tdd.yaml'));
        assert.ok(result.success && result.workflow, 'Should load tdd.yaml');
        const redPhase = result.workflow.phases?.find(p => p.name === 'red');
        assert.ok(redPhase, 'Should have RED phase');
        assert.ok(redPhase.gate, 'RED phase should have a gate');
        assert.strictEqual(redPhase.gate.type, 'tests_fail', 'RED phase gate should be tests_fail');
    });
    it('should have GREEN phase with tests_pass gate', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const result = loadWorkflowFile(join(workflowsDir, 'tdd.yaml'));
        assert.ok(result.success && result.workflow, 'Should load tdd.yaml');
        const greenPhase = result.workflow.phases?.find(p => p.name === 'green');
        assert.ok(greenPhase, 'Should have GREEN phase');
        assert.ok(greenPhase.gate, 'GREEN phase should have a gate');
        assert.strictEqual(greenPhase.gate.type, 'tests_pass', 'GREEN phase gate should be tests_pass');
    });
    it('should have REVIEW phase with approval gate', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const result = loadWorkflowFile(join(workflowsDir, 'tdd.yaml'));
        assert.ok(result.success && result.workflow, 'Should load tdd.yaml');
        const reviewPhase = result.workflow.phases?.find(p => p.name === 'review');
        assert.ok(reviewPhase, 'Should have REVIEW phase');
        assert.ok(reviewPhase.gate, 'REVIEW phase should have a gate');
        assert.strictEqual(reviewPhase.gate.type, 'approval', 'REVIEW phase gate should be approval');
    });
});
// =============================================================================
// AC3: Scale routing (1-2 pts skip TEA) preserved via trivial.yaml
// =============================================================================
describe('AC3: Scale-adaptive routing preserved', () => {
    it('should route 1-point chore to trivial workflow (skips TEA)', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const { workflows } = loadWorkflowsFromDir(workflowsDir);
        assert.ok(workflows.length >= 2, 'Should have at least 2 workflows');
        const story = {
            id: 'test-1',
            type: 'chore',
            points: 1
        };
        const result = routeStoryToWorkflow(story, workflows);
        assert.ok(result, 'Should route to a workflow');
        assert.strictEqual(result.workflow.name, 'trivial', '1-pt chore should route to trivial');
    });
    it('should route 2-point fix to trivial workflow (skips TEA)', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const { workflows } = loadWorkflowsFromDir(workflowsDir);
        const story = {
            id: 'test-2',
            type: 'fix',
            points: 2
        };
        const result = routeStoryToWorkflow(story, workflows);
        assert.ok(result, 'Should route to a workflow');
        assert.strictEqual(result.workflow.name, 'trivial', '2-pt fix should route to trivial');
    });
    it('should route 3-point feature to tdd workflow (includes TEA)', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const { workflows } = loadWorkflowsFromDir(workflowsDir);
        const story = {
            id: 'test-3',
            type: 'feature',
            points: 3
        };
        const result = routeStoryToWorkflow(story, workflows);
        assert.ok(result, 'Should route to a workflow');
        assert.strictEqual(result.workflow.name, 'tdd', '3-pt feature should route to tdd');
    });
    it('should route 5-point feature to tdd workflow (includes TEA)', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const { workflows } = loadWorkflowsFromDir(workflowsDir);
        const story = {
            id: 'test-5',
            type: 'feature',
            points: 5
        };
        const result = routeStoryToWorkflow(story, workflows);
        assert.ok(result, 'Should route to a workflow');
        assert.strictEqual(result.workflow.name, 'tdd', '5-pt feature should route to tdd');
    });
    it('should route 8-point feature to tdd workflow (complex story)', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const { workflows } = loadWorkflowsFromDir(workflowsDir);
        const story = {
            id: 'test-8',
            type: 'feature',
            points: 8
        };
        const result = routeStoryToWorkflow(story, workflows);
        assert.ok(result, 'Should route to a workflow');
        assert.strictEqual(result.workflow.name, 'tdd', '8-pt feature should route to tdd');
    });
    it('trivial workflow should NOT include TEA phase', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const result = loadWorkflowFile(join(workflowsDir, 'trivial.yaml'));
        assert.ok(result.success && result.workflow, 'Should load trivial.yaml');
        const agents = result.workflow.phases.map(p => p.agent);
        assert.ok(!agents.includes('tea'), 'Trivial workflow should not include TEA agent');
    });
    it('trivial workflow should have 4 phases: SM → Dev → Reviewer → SM', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const result = loadWorkflowFile(join(workflowsDir, 'trivial.yaml'));
        assert.ok(result.success && result.workflow, 'Should load trivial.yaml');
        assert.strictEqual(result.workflow.phases.length, 4, 'Trivial workflow should have 4 phases');
        const expectedFlow = [
            { name: 'setup', agent: 'sm' },
            { name: 'implement', agent: 'dev' },
            { name: 'review', agent: 'reviewer' },
            { name: 'finish', agent: 'sm' }
        ];
        expectedFlow.forEach((expected, i) => {
            assert.strictEqual(result.workflow.phases[i].agent, expected.agent, `Phase ${i} agent should be "${expected.agent}"`);
        });
    });
});
// =============================================================================
// AC4: Existing /new-work behavior unchanged (regression tested)
// =============================================================================
describe('AC4: /new-work behavior regression tests', () => {
    /**
     * These tests verify the routing behavior matches the hardcoded logic in SM agent:
     *
     * From sm.md:
     * | 1-2 pts (chore/fix) | Trivial | SM → Dev (skip TEA) |
     * | 3-5 pts             | Standard | SM → TEA → Dev |
     * | 8+ pts              | Complex  | SM → TEA → Dev |
     */
    it('feature type defaults to TDD workflow', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const { workflows } = loadWorkflowsFromDir(workflowsDir);
        const story = {
            id: 'regression-1',
            type: 'feature'
            // No points specified - should still route to tdd
        };
        const result = routeStoryToWorkflow(story, workflows);
        assert.ok(result, 'Should route to a workflow');
        assert.strictEqual(result.workflow.name, 'tdd', 'feature type should default to tdd');
    });
    it('enhancement type routes to TDD workflow', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const { workflows } = loadWorkflowsFromDir(workflowsDir);
        const story = {
            id: 'regression-2',
            type: 'enhancement',
            points: 5
        };
        const result = routeStoryToWorkflow(story, workflows);
        assert.ok(result, 'Should route to a workflow');
        assert.strictEqual(result.workflow.name, 'tdd', 'enhancement should route to tdd');
    });
    it('chore type with low points routes to trivial workflow', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const { workflows } = loadWorkflowsFromDir(workflowsDir);
        const story = {
            id: 'regression-3',
            type: 'chore',
            points: 1
        };
        const result = routeStoryToWorkflow(story, workflows);
        assert.ok(result, 'Should route to a workflow');
        assert.strictEqual(result.workflow.name, 'trivial', 'chore with 1 pt should route to trivial');
    });
    it('fix type with 2 points routes to trivial workflow', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const { workflows } = loadWorkflowsFromDir(workflowsDir);
        const story = {
            id: 'regression-4',
            type: 'fix',
            points: 2
        };
        const result = routeStoryToWorkflow(story, workflows);
        assert.ok(result, 'Should route to a workflow');
        assert.strictEqual(result.workflow.name, 'trivial', 'fix with 2 pts should route to trivial');
    });
    it('refactor type with 2 points routes to trivial workflow', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const { workflows } = loadWorkflowsFromDir(workflowsDir);
        const story = {
            id: 'regression-5',
            type: 'refactor',
            points: 2
        };
        const result = routeStoryToWorkflow(story, workflows);
        assert.ok(result, 'Should route to a workflow');
        assert.strictEqual(result.workflow.name, 'trivial', 'refactor with 2 pts should route to trivial');
    });
    it('boundary: 2-point feature routes to tdd (type wins over points)', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const { workflows } = loadWorkflowsFromDir(workflowsDir);
        // This is a key regression test - features should use TDD even at low points
        // because type takes priority in the current routing logic
        const story = {
            id: 'boundary-1',
            type: 'feature',
            points: 2
        };
        const result = routeStoryToWorkflow(story, workflows);
        assert.ok(result, 'Should route to a workflow');
        // Feature type matches tdd.yaml, and tdd has default: true
        // The question is: does type match or default apply?
        // According to priority: type match > points > default
        // tdd.yaml has types: [feature, enhancement] AND points.min: 3
        // So 2-pt feature shouldn't match tdd's triggers (needs min 3)
        // But tdd has default: true, so it should fall back to tdd anyway
        assert.strictEqual(result.workflow.name, 'tdd', '2-pt feature should route to tdd (default fallback)');
    });
    it('boundary: 3-point chore routes based on type not points', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const { workflows } = loadWorkflowsFromDir(workflowsDir);
        // 3-point chore: chore type matches trivial, but points exceed max: 2
        // This tests AND logic - both type AND points must match
        const story = {
            id: 'boundary-2',
            type: 'chore',
            points: 3
        };
        const result = routeStoryToWorkflow(story, workflows);
        assert.ok(result, 'Should route to a workflow');
        // trivial.yaml has: types: [chore, fix, refactor], points.max: 2
        // With AND logic, 3-pt chore exceeds max, so trivial doesn't match
        // Falls back to tdd (default: true)
        assert.strictEqual(result.workflow.name, 'tdd', '3-pt chore should fall back to tdd (exceeds trivial max)');
    });
    it('story with no type and no points falls back to default workflow', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const { workflows } = loadWorkflowsFromDir(workflowsDir);
        const story = {
            id: 'default-1'
            // No type, no points - should truly fall back to default
        };
        const result = routeStoryToWorkflow(story, workflows);
        assert.ok(result, 'Should route to a workflow');
        assert.strictEqual(result.workflow.name, 'tdd', 'No type/points should fall back to tdd (default)');
    });
    it('tdd.yaml has default: true trigger', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const result = loadWorkflowFile(join(workflowsDir, 'tdd.yaml'));
        assert.ok(result.success && result.workflow, 'Should load tdd.yaml');
        assert.ok(result.workflow.triggers, 'tdd.yaml should have triggers');
        assert.strictEqual(result.workflow.triggers.default, true, 'tdd.yaml should be the default workflow');
    });
    it('tdd.yaml triggers include feature and enhancement types', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const result = loadWorkflowFile(join(workflowsDir, 'tdd.yaml'));
        assert.ok(result.success && result.workflow, 'Should load tdd.yaml');
        const types = result.workflow.triggers?.types || [];
        assert.ok(types.includes('feature'), 'tdd.yaml should trigger on feature type');
        assert.ok(types.includes('enhancement'), 'tdd.yaml should trigger on enhancement type');
    });
    it('trivial.yaml triggers include chore, fix, refactor types', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const result = loadWorkflowFile(join(workflowsDir, 'trivial.yaml'));
        assert.ok(result.success && result.workflow, 'Should load trivial.yaml');
        const types = result.workflow.triggers?.types || [];
        assert.ok(types.includes('chore'), 'trivial.yaml should trigger on chore type');
        assert.ok(types.includes('fix'), 'trivial.yaml should trigger on fix type');
        assert.ok(types.includes('refactor'), 'trivial.yaml should trigger on refactor type');
    });
    it('trivial.yaml has points.max: 2', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const result = loadWorkflowFile(join(workflowsDir, 'trivial.yaml'));
        assert.ok(result.success && result.workflow, 'Should load trivial.yaml');
        const pointsMax = result.workflow.triggers?.points?.max;
        assert.strictEqual(pointsMax, 2, 'trivial.yaml should have points.max: 2');
    });
    it('tdd.yaml has points.min: 3', () => {
        assert.ok(workflowsDir, 'Could not find monorepo root');
        const result = loadWorkflowFile(join(workflowsDir, 'tdd.yaml'));
        assert.ok(result.success && result.workflow, 'Should load tdd.yaml');
        const pointsMin = result.workflow.triggers?.points?.min;
        assert.strictEqual(pointsMin, 3, 'tdd.yaml should have points.min: 3');
    });
});
//# sourceMappingURL=workflow-migration.test.js.map