flow-projection-generator-e2e.test.mjs
78 lines 3.1 KB
Raw
sha256:8915fe406161f95c1681f9469375e7bae5b28c884f00bedbdef65e4b0cd0738d docs(flow): commit FLOW-V0-SPEC.md hygiene for 7A-INT merge Human 14 hours ago
1 /**
2 * Tier 3 — E2E: flow project walkthrough with --out and --check.
3 *
4 * @see docs/FLOW-PROJECTION-GENERATOR-CONTRACT-7A-11.md §9–§10
5 */
6 import { describe, it, beforeEach, afterEach } from 'node:test';
7 import assert from 'node:assert/strict';
8 import fs from 'node:fs';
9 import path from 'node:path';
10 import { fileURLToPath } from 'node:url';
11 import { handleFlowProjectRequest } from '../lib/flow/flow-handlers.mjs';
12 import { detectDrift, GENERATED_MARKER_PREFIX } from '../lib/flow/projection-generator.mjs';
13 import { getRepoRoot } from '../lib/repo-root.mjs';
14
15 const __dirname = path.dirname(fileURLToPath(import.meta.url));
16 const tmpRoot = path.join(__dirname, 'fixtures', 'tmp-flow-projection-e2e');
17 const repoRoot = getRepoRoot();
18
19 describe('E2E — flow project walkthrough', () => {
20 const dataDir = path.join(tmpRoot, 'data');
21
22 beforeEach(() => {
23 fs.rmSync(tmpRoot, { recursive: true, force: true });
24 fs.mkdirSync(dataDir, { recursive: true });
25 });
26
27 afterEach(() => {
28 fs.rmSync(tmpRoot, { recursive: true, force: true });
29 });
30
31 it('seeds starters, projects cli_runbook with six ordered steps and clean --check', () => {
32 const result = handleFlowProjectRequest({
33 dataDir,
34 vaultId: 'default',
35 flowId: 'flow_overseer_handover',
36 harness: 'cli_runbook',
37 visibleScopes: new Set(['personal', 'project', 'org']),
38 starterDir: path.join(repoRoot, 'flows/starter'),
39 generatedAt: '2026-06-20T00:00:00Z',
40 });
41 assert.equal(result.ok, true);
42 const { projection, staleness } = result.payload;
43 assert.ok(projection.rendered.includes(GENERATED_MARKER_PREFIX));
44 assert.equal((projection.rendered.match(/## Step \d+/g) ?? []).length, 6);
45 const kinds = new Set();
46 for (const line of projection.rendered.split('\n')) {
47 if (line.includes('human_review') || line.includes('artifact_exists')) {
48 kinds.add(line.includes('artifact_exists') ? 'artifact_exists' : 'human_review');
49 }
50 }
51 assert.ok(kinds.has('human_review'));
52 assert.ok(kinds.has('artifact_exists'));
53 assert.equal(staleness.stale, false);
54
55 const outFile = path.join(tmpRoot, 'AGENTS.md');
56 fs.writeFileSync(outFile, projection.rendered, 'utf8');
57 const drift = detectDrift(fs.readFileSync(outFile, 'utf8'), projection.rendered);
58 assert.deepEqual(drift, { drift: false, reason: 'clean' });
59 });
60
61 it('cursor_rule emits MDC frontmatter and drops when_not_to_run in fidelity', () => {
62 const result = handleFlowProjectRequest({
63 dataDir,
64 vaultId: 'default',
65 flowId: 'flow_overseer_handover',
66 harness: 'cursor_rule',
67 visibleScopes: new Set(['personal', 'project', 'org']),
68 starterDir: path.join(repoRoot, 'flows/starter'),
69 generatedAt: '2026-06-20T00:00:00Z',
70 });
71 assert.equal(result.ok, true);
72 const { rendered } = result.payload.projection;
73 assert.ok(rendered.startsWith('---\n'));
74 assert.ok(rendered.includes('description:'));
75 assert.ok(rendered.includes(GENERATED_MARKER_PREFIX));
76 assert.ok(result.payload.projection.fidelity.dropped_fields.includes('when_not_to_run'));
77 });
78 });
File History 1 commit
sha256:8915fe406161f95c1681f9469375e7bae5b28c884f00bedbdef65e4b0cd0738d docs(flow): commit FLOW-V0-SPEC.md hygiene for 7A-INT merge Human 14 hours ago