popeye-cli 1.10.0 → 2.1.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 +114 -0
- package/CONTRIBUTING.md +38 -3
- package/README.md +104 -18
- package/dist/adapters/gemini.js +3 -3
- package/dist/adapters/openai.js +2 -2
- package/dist/adapters/openai.js.map +1 -1
- package/dist/auth/gemini.js +1 -1
- package/dist/cli/commands/create.d.ts.map +1 -1
- package/dist/cli/commands/create.js +11 -5
- package/dist/cli/commands/create.js.map +1 -1
- package/dist/cli/commands/resume.d.ts.map +1 -1
- package/dist/cli/commands/resume.js +9 -1
- package/dist/cli/commands/resume.js.map +1 -1
- package/dist/cli/interactive.d.ts.map +1 -1
- package/dist/cli/interactive.js +29 -3
- package/dist/cli/interactive.js.map +1 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +7 -2
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/index.d.ts +1 -7
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/popeye-md.d.ts +32 -0
- package/dist/config/popeye-md.d.ts.map +1 -0
- package/dist/config/popeye-md.js +111 -0
- package/dist/config/popeye-md.js.map +1 -0
- package/dist/config/schema.d.ts +3 -21
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +21 -8
- package/dist/config/schema.js.map +1 -1
- package/dist/pipeline/artifact-manager.d.ts +47 -0
- package/dist/pipeline/artifact-manager.d.ts.map +1 -0
- package/dist/pipeline/artifact-manager.js +251 -0
- package/dist/pipeline/artifact-manager.js.map +1 -0
- package/dist/pipeline/artifact-validators.d.ts +29 -0
- package/dist/pipeline/artifact-validators.d.ts.map +1 -0
- package/dist/pipeline/artifact-validators.js +173 -0
- package/dist/pipeline/artifact-validators.js.map +1 -0
- package/dist/pipeline/bridges/review-bridge.d.ts +70 -0
- package/dist/pipeline/bridges/review-bridge.d.ts.map +1 -0
- package/dist/pipeline/bridges/review-bridge.js +266 -0
- package/dist/pipeline/bridges/review-bridge.js.map +1 -0
- package/dist/pipeline/change-request.d.ts +47 -0
- package/dist/pipeline/change-request.d.ts.map +1 -0
- package/dist/pipeline/change-request.js +91 -0
- package/dist/pipeline/change-request.js.map +1 -0
- package/dist/pipeline/check-runner.d.ts +47 -0
- package/dist/pipeline/check-runner.d.ts.map +1 -0
- package/dist/pipeline/check-runner.js +417 -0
- package/dist/pipeline/check-runner.js.map +1 -0
- package/dist/pipeline/command-resolver.d.ts +9 -0
- package/dist/pipeline/command-resolver.d.ts.map +1 -0
- package/dist/pipeline/command-resolver.js +140 -0
- package/dist/pipeline/command-resolver.js.map +1 -0
- package/dist/pipeline/consensus/consensus-runner.d.ts +44 -0
- package/dist/pipeline/consensus/consensus-runner.d.ts.map +1 -0
- package/dist/pipeline/consensus/consensus-runner.js +212 -0
- package/dist/pipeline/consensus/consensus-runner.js.map +1 -0
- package/dist/pipeline/constitution.d.ts +45 -0
- package/dist/pipeline/constitution.d.ts.map +1 -0
- package/dist/pipeline/constitution.js +82 -0
- package/dist/pipeline/constitution.js.map +1 -0
- package/dist/pipeline/gate-engine.d.ts +55 -0
- package/dist/pipeline/gate-engine.d.ts.map +1 -0
- package/dist/pipeline/gate-engine.js +270 -0
- package/dist/pipeline/gate-engine.js.map +1 -0
- package/dist/pipeline/index.d.ts +26 -0
- package/dist/pipeline/index.d.ts.map +1 -0
- package/dist/pipeline/index.js +35 -0
- package/dist/pipeline/index.js.map +1 -0
- package/dist/pipeline/migration.d.ts +15 -0
- package/dist/pipeline/migration.d.ts.map +1 -0
- package/dist/pipeline/migration.js +76 -0
- package/dist/pipeline/migration.js.map +1 -0
- package/dist/pipeline/orchestrator.d.ts +30 -0
- package/dist/pipeline/orchestrator.d.ts.map +1 -0
- package/dist/pipeline/orchestrator.js +242 -0
- package/dist/pipeline/orchestrator.js.map +1 -0
- package/dist/pipeline/packets/audit-report-builder.d.ts +11 -0
- package/dist/pipeline/packets/audit-report-builder.d.ts.map +1 -0
- package/dist/pipeline/packets/audit-report-builder.js +32 -0
- package/dist/pipeline/packets/audit-report-builder.js.map +1 -0
- package/dist/pipeline/packets/consensus-packet-builder.d.ts +35 -0
- package/dist/pipeline/packets/consensus-packet-builder.d.ts.map +1 -0
- package/dist/pipeline/packets/consensus-packet-builder.js +80 -0
- package/dist/pipeline/packets/consensus-packet-builder.js.map +1 -0
- package/dist/pipeline/packets/index.d.ts +12 -0
- package/dist/pipeline/packets/index.d.ts.map +1 -0
- package/dist/pipeline/packets/index.js +8 -0
- package/dist/pipeline/packets/index.js.map +1 -0
- package/dist/pipeline/packets/plan-packet-builder.d.ts +21 -0
- package/dist/pipeline/packets/plan-packet-builder.d.ts.map +1 -0
- package/dist/pipeline/packets/plan-packet-builder.js +27 -0
- package/dist/pipeline/packets/plan-packet-builder.js.map +1 -0
- package/dist/pipeline/packets/rca-packet-builder.d.ts +19 -0
- package/dist/pipeline/packets/rca-packet-builder.d.ts.map +1 -0
- package/dist/pipeline/packets/rca-packet-builder.js +22 -0
- package/dist/pipeline/packets/rca-packet-builder.js.map +1 -0
- package/dist/pipeline/phases/architecture.d.ts +7 -0
- package/dist/pipeline/phases/architecture.d.ts.map +1 -0
- package/dist/pipeline/phases/architecture.js +60 -0
- package/dist/pipeline/phases/architecture.js.map +1 -0
- package/dist/pipeline/phases/audit.d.ts +8 -0
- package/dist/pipeline/phases/audit.d.ts.map +1 -0
- package/dist/pipeline/phases/audit.js +144 -0
- package/dist/pipeline/phases/audit.js.map +1 -0
- package/dist/pipeline/phases/consensus-architecture.d.ts +7 -0
- package/dist/pipeline/phases/consensus-architecture.d.ts.map +1 -0
- package/dist/pipeline/phases/consensus-architecture.js +84 -0
- package/dist/pipeline/phases/consensus-architecture.js.map +1 -0
- package/dist/pipeline/phases/consensus-master-plan.d.ts +7 -0
- package/dist/pipeline/phases/consensus-master-plan.d.ts.map +1 -0
- package/dist/pipeline/phases/consensus-master-plan.js +81 -0
- package/dist/pipeline/phases/consensus-master-plan.js.map +1 -0
- package/dist/pipeline/phases/consensus-role-plans.d.ts +7 -0
- package/dist/pipeline/phases/consensus-role-plans.d.ts.map +1 -0
- package/dist/pipeline/phases/consensus-role-plans.js +85 -0
- package/dist/pipeline/phases/consensus-role-plans.js.map +1 -0
- package/dist/pipeline/phases/done.d.ts +7 -0
- package/dist/pipeline/phases/done.d.ts.map +1 -0
- package/dist/pipeline/phases/done.js +45 -0
- package/dist/pipeline/phases/done.js.map +1 -0
- package/dist/pipeline/phases/implementation.d.ts +8 -0
- package/dist/pipeline/phases/implementation.d.ts.map +1 -0
- package/dist/pipeline/phases/implementation.js +45 -0
- package/dist/pipeline/phases/implementation.js.map +1 -0
- package/dist/pipeline/phases/index.d.ts +20 -0
- package/dist/pipeline/phases/index.d.ts.map +1 -0
- package/dist/pipeline/phases/index.js +19 -0
- package/dist/pipeline/phases/index.js.map +1 -0
- package/dist/pipeline/phases/intake.d.ts +8 -0
- package/dist/pipeline/phases/intake.d.ts.map +1 -0
- package/dist/pipeline/phases/intake.js +49 -0
- package/dist/pipeline/phases/intake.js.map +1 -0
- package/dist/pipeline/phases/phase-context.d.ts +30 -0
- package/dist/pipeline/phases/phase-context.d.ts.map +1 -0
- package/dist/pipeline/phases/phase-context.js +33 -0
- package/dist/pipeline/phases/phase-context.js.map +1 -0
- package/dist/pipeline/phases/production-gate.d.ts +8 -0
- package/dist/pipeline/phases/production-gate.d.ts.map +1 -0
- package/dist/pipeline/phases/production-gate.js +84 -0
- package/dist/pipeline/phases/production-gate.js.map +1 -0
- package/dist/pipeline/phases/qa-validation.d.ts +7 -0
- package/dist/pipeline/phases/qa-validation.d.ts.map +1 -0
- package/dist/pipeline/phases/qa-validation.js +50 -0
- package/dist/pipeline/phases/qa-validation.js.map +1 -0
- package/dist/pipeline/phases/recovery-loop.d.ts +7 -0
- package/dist/pipeline/phases/recovery-loop.d.ts.map +1 -0
- package/dist/pipeline/phases/recovery-loop.js +93 -0
- package/dist/pipeline/phases/recovery-loop.js.map +1 -0
- package/dist/pipeline/phases/review.d.ts +8 -0
- package/dist/pipeline/phases/review.d.ts.map +1 -0
- package/dist/pipeline/phases/review.js +127 -0
- package/dist/pipeline/phases/review.js.map +1 -0
- package/dist/pipeline/phases/role-planning.d.ts +7 -0
- package/dist/pipeline/phases/role-planning.d.ts.map +1 -0
- package/dist/pipeline/phases/role-planning.js +75 -0
- package/dist/pipeline/phases/role-planning.js.map +1 -0
- package/dist/pipeline/phases/stuck.d.ts +7 -0
- package/dist/pipeline/phases/stuck.d.ts.map +1 -0
- package/dist/pipeline/phases/stuck.js +51 -0
- package/dist/pipeline/phases/stuck.js.map +1 -0
- package/dist/pipeline/repo-snapshot.d.ts +24 -0
- package/dist/pipeline/repo-snapshot.d.ts.map +1 -0
- package/dist/pipeline/repo-snapshot.js +343 -0
- package/dist/pipeline/repo-snapshot.js.map +1 -0
- package/dist/pipeline/role-execution-adapter.d.ts +59 -0
- package/dist/pipeline/role-execution-adapter.d.ts.map +1 -0
- package/dist/pipeline/role-execution-adapter.js +159 -0
- package/dist/pipeline/role-execution-adapter.js.map +1 -0
- package/dist/pipeline/skill-loader.d.ts +34 -0
- package/dist/pipeline/skill-loader.d.ts.map +1 -0
- package/dist/pipeline/skill-loader.js +156 -0
- package/dist/pipeline/skill-loader.js.map +1 -0
- package/dist/pipeline/skills/defaults.d.ts +16 -0
- package/dist/pipeline/skills/defaults.d.ts.map +1 -0
- package/dist/pipeline/skills/defaults.js +189 -0
- package/dist/pipeline/skills/defaults.js.map +1 -0
- package/dist/pipeline/type-defs/artifacts.d.ts +207 -0
- package/dist/pipeline/type-defs/artifacts.d.ts.map +1 -0
- package/dist/pipeline/type-defs/artifacts.js +67 -0
- package/dist/pipeline/type-defs/artifacts.js.map +1 -0
- package/dist/pipeline/type-defs/audit.d.ts +259 -0
- package/dist/pipeline/type-defs/audit.d.ts.map +1 -0
- package/dist/pipeline/type-defs/audit.js +54 -0
- package/dist/pipeline/type-defs/audit.js.map +1 -0
- package/dist/pipeline/type-defs/checks.d.ts +82 -0
- package/dist/pipeline/type-defs/checks.d.ts.map +1 -0
- package/dist/pipeline/type-defs/checks.js +38 -0
- package/dist/pipeline/type-defs/checks.js.map +1 -0
- package/dist/pipeline/type-defs/enums.d.ts +43 -0
- package/dist/pipeline/type-defs/enums.d.ts.map +1 -0
- package/dist/pipeline/type-defs/enums.js +55 -0
- package/dist/pipeline/type-defs/enums.js.map +1 -0
- package/dist/pipeline/type-defs/index.d.ts +12 -0
- package/dist/pipeline/type-defs/index.d.ts.map +1 -0
- package/dist/pipeline/type-defs/index.js +12 -0
- package/dist/pipeline/type-defs/index.js.map +1 -0
- package/dist/pipeline/type-defs/packets.d.ts +821 -0
- package/dist/pipeline/type-defs/packets.d.ts.map +1 -0
- package/dist/pipeline/type-defs/packets.js +109 -0
- package/dist/pipeline/type-defs/packets.js.map +1 -0
- package/dist/pipeline/type-defs/snapshot.d.ts +52 -0
- package/dist/pipeline/type-defs/snapshot.d.ts.map +1 -0
- package/dist/pipeline/type-defs/snapshot.js +35 -0
- package/dist/pipeline/type-defs/snapshot.js.map +1 -0
- package/dist/pipeline/type-defs/state.d.ts +455 -0
- package/dist/pipeline/type-defs/state.d.ts.map +1 -0
- package/dist/pipeline/type-defs/state.js +90 -0
- package/dist/pipeline/type-defs/state.js.map +1 -0
- package/dist/pipeline/types.d.ts +16 -0
- package/dist/pipeline/types.d.ts.map +1 -0
- package/dist/pipeline/types.js +16 -0
- package/dist/pipeline/types.js.map +1 -0
- package/dist/types/audit.d.ts +6 -6
- package/dist/types/consensus.d.ts +5 -1
- package/dist/types/consensus.d.ts.map +1 -1
- package/dist/types/consensus.js +15 -4
- package/dist/types/consensus.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/project.d.ts +1 -1
- package/dist/types/project.d.ts.map +1 -1
- package/dist/types/project.js +39 -10
- package/dist/types/project.js.map +1 -1
- package/dist/types/workflow.d.ts +1 -7
- package/dist/types/workflow.d.ts.map +1 -1
- package/dist/types/workflow.js +1 -1
- package/dist/types/workflow.js.map +1 -1
- package/dist/upgrade/handlers.js +5 -5
- package/dist/upgrade/handlers.js.map +1 -1
- package/dist/workflow/index.d.ts.map +1 -1
- package/dist/workflow/index.js +52 -0
- package/dist/workflow/index.js.map +1 -1
- package/dist/workflow/website-strategy.js +1 -1
- package/dist/workflow/website-strategy.js.map +1 -1
- package/package.json +1 -1
- package/skills/PHASE_GATE_ENGINE_SPEC.md +113 -20
- package/skills/POPEYE_FULL_AUTONOMY_PIPELINE.md +66 -13
- package/src/adapters/gemini.ts +3 -3
- package/src/adapters/openai.ts +2 -2
- package/src/auth/gemini.ts +1 -1
- package/src/cli/commands/create.ts +12 -6
- package/src/cli/commands/resume.ts +9 -1
- package/src/cli/interactive.ts +32 -3
- package/src/config/defaults.ts +7 -2
- package/src/config/popeye-md.ts +139 -0
- package/src/config/schema.ts +21 -8
- package/src/pipeline/artifact-manager.ts +339 -0
- package/src/pipeline/artifact-validators.ts +224 -0
- package/src/pipeline/bridges/review-bridge.ts +371 -0
- package/src/pipeline/change-request.ts +119 -0
- package/src/pipeline/check-runner.ts +504 -0
- package/src/pipeline/command-resolver.ts +168 -0
- package/src/pipeline/consensus/consensus-runner.ts +317 -0
- package/src/pipeline/constitution.ts +109 -0
- package/src/pipeline/gate-engine.ts +347 -0
- package/src/pipeline/index.ts +82 -0
- package/src/pipeline/migration.ts +91 -0
- package/src/pipeline/orchestrator.ts +322 -0
- package/src/pipeline/packets/audit-report-builder.ts +47 -0
- package/src/pipeline/packets/consensus-packet-builder.ts +112 -0
- package/src/pipeline/packets/index.ts +15 -0
- package/src/pipeline/packets/plan-packet-builder.ts +52 -0
- package/src/pipeline/packets/rca-packet-builder.ts +38 -0
- package/src/pipeline/phases/architecture.ts +73 -0
- package/src/pipeline/phases/audit.ts +193 -0
- package/src/pipeline/phases/consensus-architecture.ts +104 -0
- package/src/pipeline/phases/consensus-master-plan.ts +100 -0
- package/src/pipeline/phases/consensus-role-plans.ts +105 -0
- package/src/pipeline/phases/done.ts +68 -0
- package/src/pipeline/phases/implementation.ts +52 -0
- package/src/pipeline/phases/index.ts +21 -0
- package/src/pipeline/phases/intake.ts +68 -0
- package/src/pipeline/phases/phase-context.ts +86 -0
- package/src/pipeline/phases/production-gate.ts +113 -0
- package/src/pipeline/phases/qa-validation.ts +63 -0
- package/src/pipeline/phases/recovery-loop.ts +120 -0
- package/src/pipeline/phases/review.ts +149 -0
- package/src/pipeline/phases/role-planning.ts +92 -0
- package/src/pipeline/phases/stuck.ts +62 -0
- package/src/pipeline/repo-snapshot.ts +395 -0
- package/src/pipeline/role-execution-adapter.ts +238 -0
- package/src/pipeline/skill-loader.ts +192 -0
- package/src/pipeline/skills/defaults.ts +215 -0
- package/src/pipeline/type-defs/artifacts.ts +82 -0
- package/src/pipeline/type-defs/audit.ts +67 -0
- package/src/pipeline/type-defs/checks.ts +47 -0
- package/src/pipeline/type-defs/enums.ts +62 -0
- package/src/pipeline/type-defs/index.ts +12 -0
- package/src/pipeline/type-defs/packets.ts +131 -0
- package/src/pipeline/type-defs/snapshot.ts +55 -0
- package/src/pipeline/type-defs/state.ts +167 -0
- package/src/pipeline/types.ts +16 -0
- package/src/types/consensus.ts +16 -4
- package/src/types/index.ts +1 -0
- package/src/types/project.ts +39 -10
- package/src/types/workflow.ts +1 -1
- package/src/upgrade/handlers.ts +5 -5
- package/src/workflow/index.ts +52 -0
- package/src/workflow/website-strategy.ts +1 -1
- package/tests/cli/model-command.test.ts +19 -9
- package/tests/config/config.test.ts +3 -3
- package/tests/config/popeye-md.test.ts +168 -0
- package/tests/pipeline/artifact-manager.test.ts +183 -0
- package/tests/pipeline/artifact-validators.test.ts +207 -0
- package/tests/pipeline/bridges/review-bridge.test.ts +243 -0
- package/tests/pipeline/change-request.test.ts +180 -0
- package/tests/pipeline/check-runner.test.ts +157 -0
- package/tests/pipeline/command-resolver.test.ts +159 -0
- package/tests/pipeline/consensus-runner.test.ts +206 -0
- package/tests/pipeline/consensus-scoring.test.ts +163 -0
- package/tests/pipeline/constitution.test.ts +122 -0
- package/tests/pipeline/gate-engine.test.ts +195 -0
- package/tests/pipeline/migration.test.ts +133 -0
- package/tests/pipeline/orchestrator.test.ts +614 -0
- package/tests/pipeline/packets/builders.test.ts +347 -0
- package/tests/pipeline/repo-snapshot.test.ts +189 -0
- package/tests/pipeline/role-execution-adapter.test.ts +299 -0
- package/tests/pipeline/session-guidance.test.ts +205 -0
- package/tests/pipeline/skill-loader.test.ts +186 -0
- package/tests/pipeline/start-env-checks.test.ts +123 -0
- package/tests/pipeline/types.test.ts +156 -0
- package/tests/types/consensus.test.ts +1 -1
- package/tests/workflow/pipeline-bootstrap.test.ts +162 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Artifact Validators tests — completeness checks for each artifact type.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect } from 'vitest';
|
|
6
|
+
import {
|
|
7
|
+
validateArtifactCompleteness,
|
|
8
|
+
getValidatableArtifactTypes,
|
|
9
|
+
} from '../../src/pipeline/artifact-validators.js';
|
|
10
|
+
|
|
11
|
+
describe('validateArtifactCompleteness', () => {
|
|
12
|
+
describe('master_plan', () => {
|
|
13
|
+
it('should pass for complete master plan', () => {
|
|
14
|
+
const content = [
|
|
15
|
+
'# Master Plan',
|
|
16
|
+
'## Goals',
|
|
17
|
+
'Build a comprehensive todo application with real-time sync capabilities.',
|
|
18
|
+
'The application should support multiple users and collaborative editing features.',
|
|
19
|
+
'## Milestones',
|
|
20
|
+
'Milestone 1: Setup project structure, install dependencies, configure CI/CD pipeline',
|
|
21
|
+
'Milestone 2: Core features including task CRUD, real-time updates, and user auth',
|
|
22
|
+
'## Success Criteria',
|
|
23
|
+
'All tests pass with 80% coverage, app deploys successfully to production environment.',
|
|
24
|
+
].join('\n');
|
|
25
|
+
|
|
26
|
+
const result = validateArtifactCompleteness('master_plan', content);
|
|
27
|
+
expect(result.valid).toBe(true);
|
|
28
|
+
expect(result.errors).toHaveLength(0);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should fail for empty content', () => {
|
|
32
|
+
const result = validateArtifactCompleteness('master_plan', '');
|
|
33
|
+
expect(result.valid).toBe(false);
|
|
34
|
+
expect(result.errors[0]).toContain('empty content');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should fail for too-short content', () => {
|
|
38
|
+
const result = validateArtifactCompleteness('master_plan', '# Plan\nGoals: TBD');
|
|
39
|
+
expect(result.valid).toBe(false);
|
|
40
|
+
expect(result.errors.some((e) => e.includes('too short'))).toBe(true);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should fail when missing Goals section', () => {
|
|
44
|
+
const content = [
|
|
45
|
+
'# Master Plan',
|
|
46
|
+
'Some text that is long enough to pass the minimum length check.',
|
|
47
|
+
'## Milestones',
|
|
48
|
+
'Milestone 1: Setup project structure and dependencies.',
|
|
49
|
+
'## Success Criteria',
|
|
50
|
+
'All tests pass and the application deploys.',
|
|
51
|
+
].join('\n');
|
|
52
|
+
|
|
53
|
+
const result = validateArtifactCompleteness('master_plan', content);
|
|
54
|
+
expect(result.valid).toBe(false);
|
|
55
|
+
expect(result.errors.some((e) => e.includes('Goals'))).toBe(true);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should fail when missing Milestones section', () => {
|
|
59
|
+
const content = [
|
|
60
|
+
'# Master Plan',
|
|
61
|
+
'## Goals',
|
|
62
|
+
'Build a comprehensive todo application with real-time sync.',
|
|
63
|
+
'The application should support multiple users.',
|
|
64
|
+
'## Success Criteria',
|
|
65
|
+
'All tests pass and the application deploys successfully.',
|
|
66
|
+
].join('\n');
|
|
67
|
+
|
|
68
|
+
const result = validateArtifactCompleteness('master_plan', content);
|
|
69
|
+
expect(result.valid).toBe(false);
|
|
70
|
+
expect(result.errors.some((e) => e.includes('Milestones'))).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('architecture', () => {
|
|
75
|
+
it('should pass for complete architecture', () => {
|
|
76
|
+
const content = [
|
|
77
|
+
'# Architecture',
|
|
78
|
+
'## Components',
|
|
79
|
+
'Frontend: React SPA in src/app/ with component-based architecture using TypeScript.',
|
|
80
|
+
'Backend: FastAPI in src/server/ with layered architecture (routes, services, models).',
|
|
81
|
+
'## Data Flow',
|
|
82
|
+
'REST API contracts between FE and BE, with JSON payloads and OpenAPI specification.',
|
|
83
|
+
'## Tech Stack',
|
|
84
|
+
'React 18, TypeScript 5.x, FastAPI 0.100+, PostgreSQL 15, Redis for caching.',
|
|
85
|
+
].join('\n');
|
|
86
|
+
|
|
87
|
+
const result = validateArtifactCompleteness('architecture', content);
|
|
88
|
+
expect(result.valid).toBe(true);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should fail when missing components section', () => {
|
|
92
|
+
const content = [
|
|
93
|
+
'# Architecture',
|
|
94
|
+
'Some long enough content for the min length check.',
|
|
95
|
+
'## Data Flow',
|
|
96
|
+
'REST API between FE and BE using src/api/ routes.',
|
|
97
|
+
'## Tech Stack',
|
|
98
|
+
'React, TypeScript, FastAPI',
|
|
99
|
+
].join('\n');
|
|
100
|
+
|
|
101
|
+
const result = validateArtifactCompleteness('architecture', content);
|
|
102
|
+
expect(result.valid).toBe(false);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should warn when no file paths referenced', () => {
|
|
106
|
+
const content = [
|
|
107
|
+
'# Architecture',
|
|
108
|
+
'## Components',
|
|
109
|
+
'Frontend and Backend modules communicating via REST protocol for data exchange.',
|
|
110
|
+
'The component architecture follows a modular design pattern with clear separation.',
|
|
111
|
+
'## Contracts',
|
|
112
|
+
'JSON-based API contracts define the interface between all system components clearly.',
|
|
113
|
+
'## Tech Stack',
|
|
114
|
+
'React for the frontend, TypeScript for type safety, and a backend runtime environment.',
|
|
115
|
+
].join('\n');
|
|
116
|
+
|
|
117
|
+
const result = validateArtifactCompleteness('architecture', content);
|
|
118
|
+
expect(result.warnings.some((w) => w.includes('file path'))).toBe(true);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe('role_plan', () => {
|
|
123
|
+
it('should pass for complete role plan', () => {
|
|
124
|
+
const content = [
|
|
125
|
+
'# FRONTEND_PROGRAMMER Role Plan',
|
|
126
|
+
'## Tasks',
|
|
127
|
+
'- Build login page',
|
|
128
|
+
'- Implement dashboard',
|
|
129
|
+
'## Dependencies',
|
|
130
|
+
'Requires API contracts from BACKEND_PROGRAMMER.',
|
|
131
|
+
'## Acceptance Criteria',
|
|
132
|
+
'All pages render, tests pass.',
|
|
133
|
+
].join('\n');
|
|
134
|
+
|
|
135
|
+
const result = validateArtifactCompleteness('role_plan', content);
|
|
136
|
+
expect(result.valid).toBe(true);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should fail for too-short role plan', () => {
|
|
140
|
+
const result = validateArtifactCompleteness('role_plan', '# Plan');
|
|
141
|
+
expect(result.valid).toBe(false);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
describe('qa_validation', () => {
|
|
146
|
+
it('should pass with test results and coverage', () => {
|
|
147
|
+
const content = [
|
|
148
|
+
'# QA Validation',
|
|
149
|
+
'## Test Results',
|
|
150
|
+
'45 tests passing, 0 failing',
|
|
151
|
+
'## Coverage',
|
|
152
|
+
'Overall coverage: 87%',
|
|
153
|
+
].join('\n');
|
|
154
|
+
|
|
155
|
+
const result = validateArtifactCompleteness('qa_validation', content);
|
|
156
|
+
expect(result.valid).toBe(true);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('should fail without test results section', () => {
|
|
160
|
+
const content = '# QA\n## Coverage\n80% coverage';
|
|
161
|
+
const result = validateArtifactCompleteness('qa_validation', content);
|
|
162
|
+
expect(result.valid).toBe(false);
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
describe('audit_report (JSON)', () => {
|
|
167
|
+
it('should pass for valid JSON audit report', () => {
|
|
168
|
+
const content = JSON.stringify({
|
|
169
|
+
findings: [{ id: '1', severity: 'P2' }],
|
|
170
|
+
overall_status: 'PASS',
|
|
171
|
+
system_risk_score: 25,
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const result = validateArtifactCompleteness('audit_report', content);
|
|
175
|
+
expect(result.valid).toBe(true);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('should fail when missing findings array', () => {
|
|
179
|
+
const content = JSON.stringify({
|
|
180
|
+
overall_status: 'PASS',
|
|
181
|
+
system_risk_score: 25,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const result = validateArtifactCompleteness('audit_report', content);
|
|
185
|
+
expect(result.valid).toBe(false);
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
describe('unknown artifact types', () => {
|
|
190
|
+
it('should pass for artifact types without validators', () => {
|
|
191
|
+
const result = validateArtifactCompleteness('release_notes', 'Any content');
|
|
192
|
+
expect(result.valid).toBe(true);
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
describe('getValidatableArtifactTypes', () => {
|
|
197
|
+
it('should return artifact types with registered validators', () => {
|
|
198
|
+
const types = getValidatableArtifactTypes();
|
|
199
|
+
expect(types).toContain('master_plan');
|
|
200
|
+
expect(types).toContain('architecture');
|
|
201
|
+
expect(types).toContain('role_plan');
|
|
202
|
+
expect(types).toContain('qa_validation');
|
|
203
|
+
expect(types).toContain('audit_report');
|
|
204
|
+
expect(types.length).toBe(5);
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
});
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Review Bridge tests — severity mapping, category mapping, CR routing,
|
|
3
|
+
* pipeline detection, finding conversion.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, it, expect } from 'vitest';
|
|
7
|
+
import {
|
|
8
|
+
mapSeverity,
|
|
9
|
+
mapCategory,
|
|
10
|
+
categoryToChangeType,
|
|
11
|
+
convertFinding,
|
|
12
|
+
isPipelineManaged,
|
|
13
|
+
extractPipelineState,
|
|
14
|
+
} from '../../../src/pipeline/bridges/review-bridge.js';
|
|
15
|
+
import { createDefaultPipelineState } from '../../../src/pipeline/types.js';
|
|
16
|
+
import type { AuditFinding as WorkflowFinding } from '../../../src/types/audit.js';
|
|
17
|
+
import type { ArtifactRef } from '../../../src/pipeline/types.js';
|
|
18
|
+
import type { ProjectState } from '../../../src/types/workflow.js';
|
|
19
|
+
|
|
20
|
+
// ─── Test Data ───────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
function makeSnapshotRef(): ArtifactRef {
|
|
23
|
+
return {
|
|
24
|
+
artifact_id: 'snap-001',
|
|
25
|
+
path: 'docs/snapshots/repo_snapshot_001.json',
|
|
26
|
+
sha256: 'abc123',
|
|
27
|
+
version: 1,
|
|
28
|
+
type: 'repo_snapshot',
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function makeWorkflowFinding(overrides: Partial<WorkflowFinding> = {}): WorkflowFinding {
|
|
33
|
+
return {
|
|
34
|
+
id: 'finding-1',
|
|
35
|
+
category: 'integration-wiring',
|
|
36
|
+
severity: 'critical',
|
|
37
|
+
title: 'API endpoint mismatch',
|
|
38
|
+
description: 'Frontend calls /api/users but backend serves /api/v1/users',
|
|
39
|
+
evidence: [{ file: 'src/api.ts', line: 42, snippet: 'fetch("/api/users")' }],
|
|
40
|
+
recommendation: 'Update frontend API base URL',
|
|
41
|
+
autoFixable: true,
|
|
42
|
+
...overrides,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function makeProjectState(withPipeline = false): ProjectState {
|
|
47
|
+
const base: ProjectState = {
|
|
48
|
+
id: 'test-id',
|
|
49
|
+
name: 'test-project',
|
|
50
|
+
idea: 'Build something',
|
|
51
|
+
language: 'python',
|
|
52
|
+
phase: 'execution',
|
|
53
|
+
status: 'in-progress',
|
|
54
|
+
milestones: [],
|
|
55
|
+
currentMilestone: null,
|
|
56
|
+
currentTask: null,
|
|
57
|
+
consensusHistory: [],
|
|
58
|
+
createdAt: new Date().toISOString(),
|
|
59
|
+
updatedAt: new Date().toISOString(),
|
|
60
|
+
} as ProjectState;
|
|
61
|
+
|
|
62
|
+
if (withPipeline) {
|
|
63
|
+
(base as unknown as { pipeline: unknown }).pipeline = createDefaultPipelineState();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return base;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ─── Tests ───────────────────────────────────────────────
|
|
70
|
+
|
|
71
|
+
describe('Review Bridge', () => {
|
|
72
|
+
describe('severity mapping', () => {
|
|
73
|
+
it('should map critical to P0', () => {
|
|
74
|
+
expect(mapSeverity('critical')).toBe('P0');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should map major to P1', () => {
|
|
78
|
+
expect(mapSeverity('major')).toBe('P1');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should map minor to P2', () => {
|
|
82
|
+
expect(mapSeverity('minor')).toBe('P2');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should map info to P3', () => {
|
|
86
|
+
expect(mapSeverity('info')).toBe('P3');
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe('category mapping', () => {
|
|
91
|
+
it('should map integration-wiring to integration', () => {
|
|
92
|
+
expect(mapCategory('integration-wiring')).toBe('integration');
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('should map feature-completeness to integration', () => {
|
|
96
|
+
expect(mapCategory('feature-completeness')).toBe('integration');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should map test-coverage to tests', () => {
|
|
100
|
+
expect(mapCategory('test-coverage')).toBe('tests');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('should map config-deployment to config', () => {
|
|
104
|
+
expect(mapCategory('config-deployment')).toBe('config');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should map security to security', () => {
|
|
108
|
+
expect(mapCategory('security')).toBe('security');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should map dependency-sanity to deployment', () => {
|
|
112
|
+
expect(mapCategory('dependency-sanity')).toBe('deployment');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should map consistency to schema', () => {
|
|
116
|
+
expect(mapCategory('consistency')).toBe('schema');
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should map documentation to deployment', () => {
|
|
120
|
+
expect(mapCategory('documentation')).toBe('deployment');
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
describe('CR change type routing', () => {
|
|
125
|
+
it('should route integration to architecture CR', () => {
|
|
126
|
+
expect(categoryToChangeType('integration')).toBe('architecture');
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('should route schema to architecture CR', () => {
|
|
130
|
+
expect(categoryToChangeType('schema')).toBe('architecture');
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should route security to requirement CR', () => {
|
|
134
|
+
expect(categoryToChangeType('security')).toBe('requirement');
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('should route tests to config CR', () => {
|
|
138
|
+
expect(categoryToChangeType('tests')).toBe('config');
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('should route config to config CR', () => {
|
|
142
|
+
expect(categoryToChangeType('config')).toBe('config');
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should route deployment to config CR', () => {
|
|
146
|
+
expect(categoryToChangeType('deployment')).toBe('config');
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
describe('finding conversion', () => {
|
|
151
|
+
it('should convert a critical workflow finding to P0 pipeline finding', () => {
|
|
152
|
+
const wf = makeWorkflowFinding({ severity: 'critical', category: 'integration-wiring' });
|
|
153
|
+
const ref = makeSnapshotRef();
|
|
154
|
+
|
|
155
|
+
const pf = convertFinding(wf, ref);
|
|
156
|
+
|
|
157
|
+
expect(pf.id).toBe('finding-1');
|
|
158
|
+
expect(pf.severity).toBe('P0');
|
|
159
|
+
expect(pf.category).toBe('integration');
|
|
160
|
+
expect(pf.blocking).toBe(true);
|
|
161
|
+
expect(pf.description).toContain('API endpoint mismatch');
|
|
162
|
+
expect(pf.file_path).toBe('src/api.ts');
|
|
163
|
+
expect(pf.line_number).toBe(42);
|
|
164
|
+
expect(pf.evidence).toEqual([ref]);
|
|
165
|
+
expect(pf.suggested_owner).toBe('AUDITOR');
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('should convert an info finding to P3 non-blocking', () => {
|
|
169
|
+
const wf = makeWorkflowFinding({ severity: 'info', category: 'documentation' });
|
|
170
|
+
const ref = makeSnapshotRef();
|
|
171
|
+
|
|
172
|
+
const pf = convertFinding(wf, ref);
|
|
173
|
+
|
|
174
|
+
expect(pf.severity).toBe('P3');
|
|
175
|
+
expect(pf.blocking).toBe(false);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('should mark P0 and P1 as blocking, P2 and P3 as non-blocking', () => {
|
|
179
|
+
const ref = makeSnapshotRef();
|
|
180
|
+
|
|
181
|
+
expect(convertFinding(makeWorkflowFinding({ severity: 'critical' }), ref).blocking).toBe(true);
|
|
182
|
+
expect(convertFinding(makeWorkflowFinding({ severity: 'major' }), ref).blocking).toBe(true);
|
|
183
|
+
expect(convertFinding(makeWorkflowFinding({ severity: 'minor' }), ref).blocking).toBe(false);
|
|
184
|
+
expect(convertFinding(makeWorkflowFinding({ severity: 'info' }), ref).blocking).toBe(false);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('should handle finding with no evidence', () => {
|
|
188
|
+
const wf = makeWorkflowFinding({ evidence: [] });
|
|
189
|
+
const ref = makeSnapshotRef();
|
|
190
|
+
|
|
191
|
+
const pf = convertFinding(wf, ref);
|
|
192
|
+
|
|
193
|
+
expect(pf.file_path).toBeUndefined();
|
|
194
|
+
expect(pf.line_number).toBeUndefined();
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
describe('pipeline detection', () => {
|
|
199
|
+
it('should detect pipeline-managed state', () => {
|
|
200
|
+
const state = makeProjectState(true);
|
|
201
|
+
expect(isPipelineManaged(state)).toBe(true);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('should detect non-pipeline state', () => {
|
|
205
|
+
const state = makeProjectState(false);
|
|
206
|
+
expect(isPipelineManaged(state)).toBe(false);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('should extract pipeline state when present', () => {
|
|
210
|
+
const state = makeProjectState(true);
|
|
211
|
+
const pipeline = extractPipelineState(state);
|
|
212
|
+
|
|
213
|
+
expect(pipeline).toBeDefined();
|
|
214
|
+
expect(pipeline!.pipelinePhase).toBe('INTAKE');
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it('should return undefined when no pipeline state', () => {
|
|
218
|
+
const state = makeProjectState(false);
|
|
219
|
+
expect(extractPipelineState(state)).toBeUndefined();
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
describe('CR routing determinism', () => {
|
|
224
|
+
it('should route integration findings to CONSENSUS_ARCHITECTURE', () => {
|
|
225
|
+
// Integration → architecture CR → CONSENSUS_ARCHITECTURE (via change-request.ts routing)
|
|
226
|
+
const changeType = categoryToChangeType('integration');
|
|
227
|
+
expect(changeType).toBe('architecture');
|
|
228
|
+
// architecture routes to CONSENSUS_ARCHITECTURE per CHANGE_TYPE_ROUTING
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it('should route security findings to CONSENSUS_MASTER_PLAN', () => {
|
|
232
|
+
const changeType = categoryToChangeType('security');
|
|
233
|
+
expect(changeType).toBe('requirement');
|
|
234
|
+
// requirement routes to CONSENSUS_MASTER_PLAN per CHANGE_TYPE_ROUTING
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('should route test findings to QA_VALIDATION', () => {
|
|
238
|
+
const changeType = categoryToChangeType('tests');
|
|
239
|
+
expect(changeType).toBe('config');
|
|
240
|
+
// config routes to QA_VALIDATION per CHANGE_TYPE_ROUTING
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
});
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Change Request tests — builder, routing, formatting.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect } from 'vitest';
|
|
6
|
+
import {
|
|
7
|
+
buildChangeRequest,
|
|
8
|
+
routeChangeRequest,
|
|
9
|
+
formatChangeRequest,
|
|
10
|
+
} from '../../src/pipeline/change-request.js';
|
|
11
|
+
import type { ArtifactRef } from '../../src/pipeline/types.js';
|
|
12
|
+
|
|
13
|
+
const mockRef: ArtifactRef = {
|
|
14
|
+
artifact_id: 'test-artifact',
|
|
15
|
+
path: 'docs/test.md',
|
|
16
|
+
sha256: 'abc',
|
|
17
|
+
version: 1,
|
|
18
|
+
type: 'repo_snapshot',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
describe('buildChangeRequest', () => {
|
|
22
|
+
it('should create a CR with generated ID and timestamp', () => {
|
|
23
|
+
const cr = buildChangeRequest({
|
|
24
|
+
originPhase: 'REVIEW',
|
|
25
|
+
requestedBy: 'REVIEWER',
|
|
26
|
+
changeType: 'config',
|
|
27
|
+
description: 'Config files changed',
|
|
28
|
+
justification: 'Drift detected',
|
|
29
|
+
affectedArtifacts: [mockRef],
|
|
30
|
+
affectedPhases: ['IMPLEMENTATION'],
|
|
31
|
+
riskLevel: 'medium',
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
expect(cr.cr_id).toMatch(/^CR-/);
|
|
35
|
+
expect(cr.timestamp).toBeTruthy();
|
|
36
|
+
expect(cr.status).toBe('proposed');
|
|
37
|
+
expect(cr.origin_phase).toBe('REVIEW');
|
|
38
|
+
expect(cr.requested_by).toBe('REVIEWER');
|
|
39
|
+
expect(cr.change_type).toBe('config');
|
|
40
|
+
expect(cr.impact_analysis.risk_level).toBe('medium');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should generate unique IDs for different CRs', () => {
|
|
44
|
+
const cr1 = buildChangeRequest({
|
|
45
|
+
originPhase: 'AUDIT',
|
|
46
|
+
requestedBy: 'AUDITOR',
|
|
47
|
+
changeType: 'architecture',
|
|
48
|
+
description: 'Arch change',
|
|
49
|
+
justification: 'Finding',
|
|
50
|
+
affectedArtifacts: [],
|
|
51
|
+
affectedPhases: [],
|
|
52
|
+
riskLevel: 'high',
|
|
53
|
+
});
|
|
54
|
+
const cr2 = buildChangeRequest({
|
|
55
|
+
originPhase: 'AUDIT',
|
|
56
|
+
requestedBy: 'AUDITOR',
|
|
57
|
+
changeType: 'scope',
|
|
58
|
+
description: 'Scope change',
|
|
59
|
+
justification: 'Finding 2',
|
|
60
|
+
affectedArtifacts: [],
|
|
61
|
+
affectedPhases: [],
|
|
62
|
+
riskLevel: 'low',
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
expect(cr1.cr_id).not.toBe(cr2.cr_id);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should include impact analysis', () => {
|
|
69
|
+
const cr = buildChangeRequest({
|
|
70
|
+
originPhase: 'REVIEW',
|
|
71
|
+
requestedBy: 'REVIEWER',
|
|
72
|
+
changeType: 'scope',
|
|
73
|
+
description: 'Scope expanded',
|
|
74
|
+
justification: 'New requirements',
|
|
75
|
+
affectedArtifacts: [mockRef],
|
|
76
|
+
affectedPhases: ['CONSENSUS_MASTER_PLAN', 'IMPLEMENTATION'],
|
|
77
|
+
riskLevel: 'high',
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
expect(cr.impact_analysis.affected_artifacts).toHaveLength(1);
|
|
81
|
+
expect(cr.impact_analysis.affected_phases).toContain('CONSENSUS_MASTER_PLAN');
|
|
82
|
+
expect(cr.impact_analysis.risk_level).toBe('high');
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe('routeChangeRequest', () => {
|
|
87
|
+
it('should route scope changes to CONSENSUS_MASTER_PLAN', () => {
|
|
88
|
+
const cr = buildChangeRequest({
|
|
89
|
+
originPhase: 'REVIEW',
|
|
90
|
+
requestedBy: 'REVIEWER',
|
|
91
|
+
changeType: 'scope',
|
|
92
|
+
description: 'test',
|
|
93
|
+
justification: 'test',
|
|
94
|
+
affectedArtifacts: [],
|
|
95
|
+
affectedPhases: [],
|
|
96
|
+
riskLevel: 'low',
|
|
97
|
+
});
|
|
98
|
+
expect(routeChangeRequest(cr)).toBe('CONSENSUS_MASTER_PLAN');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should route architecture changes to CONSENSUS_ARCHITECTURE', () => {
|
|
102
|
+
const cr = buildChangeRequest({
|
|
103
|
+
originPhase: 'AUDIT',
|
|
104
|
+
requestedBy: 'AUDITOR',
|
|
105
|
+
changeType: 'architecture',
|
|
106
|
+
description: 'test',
|
|
107
|
+
justification: 'test',
|
|
108
|
+
affectedArtifacts: [],
|
|
109
|
+
affectedPhases: [],
|
|
110
|
+
riskLevel: 'high',
|
|
111
|
+
});
|
|
112
|
+
expect(routeChangeRequest(cr)).toBe('CONSENSUS_ARCHITECTURE');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should route dependency changes to CONSENSUS_ROLE_PLANS', () => {
|
|
116
|
+
const cr = buildChangeRequest({
|
|
117
|
+
originPhase: 'REVIEW',
|
|
118
|
+
requestedBy: 'REVIEWER',
|
|
119
|
+
changeType: 'dependency',
|
|
120
|
+
description: 'test',
|
|
121
|
+
justification: 'test',
|
|
122
|
+
affectedArtifacts: [],
|
|
123
|
+
affectedPhases: [],
|
|
124
|
+
riskLevel: 'medium',
|
|
125
|
+
});
|
|
126
|
+
expect(routeChangeRequest(cr)).toBe('CONSENSUS_ROLE_PLANS');
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('should route config changes to QA_VALIDATION', () => {
|
|
130
|
+
const cr = buildChangeRequest({
|
|
131
|
+
originPhase: 'REVIEW',
|
|
132
|
+
requestedBy: 'REVIEWER',
|
|
133
|
+
changeType: 'config',
|
|
134
|
+
description: 'test',
|
|
135
|
+
justification: 'test',
|
|
136
|
+
affectedArtifacts: [],
|
|
137
|
+
affectedPhases: [],
|
|
138
|
+
riskLevel: 'low',
|
|
139
|
+
});
|
|
140
|
+
expect(routeChangeRequest(cr)).toBe('QA_VALIDATION');
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('should route requirement changes to CONSENSUS_MASTER_PLAN', () => {
|
|
144
|
+
const cr = buildChangeRequest({
|
|
145
|
+
originPhase: 'AUDIT',
|
|
146
|
+
requestedBy: 'AUDITOR',
|
|
147
|
+
changeType: 'requirement',
|
|
148
|
+
description: 'test',
|
|
149
|
+
justification: 'test',
|
|
150
|
+
affectedArtifacts: [],
|
|
151
|
+
affectedPhases: [],
|
|
152
|
+
riskLevel: 'high',
|
|
153
|
+
});
|
|
154
|
+
expect(routeChangeRequest(cr)).toBe('CONSENSUS_MASTER_PLAN');
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
describe('formatChangeRequest', () => {
|
|
159
|
+
it('should format CR as markdown', () => {
|
|
160
|
+
const cr = buildChangeRequest({
|
|
161
|
+
originPhase: 'REVIEW',
|
|
162
|
+
requestedBy: 'REVIEWER',
|
|
163
|
+
changeType: 'config',
|
|
164
|
+
description: 'Config files changed during implementation',
|
|
165
|
+
justification: 'Detected by snapshot diff',
|
|
166
|
+
affectedArtifacts: [mockRef],
|
|
167
|
+
affectedPhases: ['IMPLEMENTATION'],
|
|
168
|
+
riskLevel: 'medium',
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
const md = formatChangeRequest(cr);
|
|
172
|
+
expect(md).toContain('# Change Request');
|
|
173
|
+
expect(md).toContain(cr.cr_id);
|
|
174
|
+
expect(md).toContain('proposed');
|
|
175
|
+
expect(md).toContain('config');
|
|
176
|
+
expect(md).toContain('REVIEWER');
|
|
177
|
+
expect(md).toContain('medium');
|
|
178
|
+
expect(md).toContain('Config files changed');
|
|
179
|
+
});
|
|
180
|
+
});
|