popeye-cli 1.10.0 → 2.0.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 +59 -0
- package/CONTRIBUTING.md +15 -1
- package/README.md +57 -0
- 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/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 +28 -0
- package/dist/pipeline/orchestrator.d.ts.map +1 -0
- package/dist/pipeline/orchestrator.js +238 -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 +42 -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 +40 -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 +91 -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 +202 -0
- package/dist/pipeline/type-defs/artifacts.d.ts.map +1 -0
- package/dist/pipeline/type-defs/artifacts.js +66 -0
- package/dist/pipeline/type-defs/artifacts.js.map +1 -0
- package/dist/pipeline/type-defs/audit.d.ts +256 -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 +81 -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 +806 -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 +449 -0
- package/dist/pipeline/type-defs/state.d.ts.map +1 -0
- package/dist/pipeline/type-defs/state.js +88 -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/workflow/index.d.ts.map +1 -1
- package/dist/workflow/index.js +48 -0
- package/dist/workflow/index.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/pipeline/artifact-manager.ts +339 -0
- package/src/pipeline/artifact-validators.ts +224 -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 +314 -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 +48 -0
- package/src/pipeline/phases/index.ts +21 -0
- package/src/pipeline/phases/intake.ts +54 -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 +118 -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 +81 -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 +165 -0
- package/src/pipeline/types.ts +16 -0
- package/src/workflow/index.ts +48 -0
- package/tests/pipeline/artifact-manager.test.ts +183 -0
- package/tests/pipeline/artifact-validators.test.ts +207 -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/skill-loader.test.ts +186 -0
- package/tests/pipeline/start-env-checks.test.ts +123 -0
- package/tests/pipeline/types.test.ts +156 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Artifact Completeness Validators — deterministic structural checks.
|
|
3
|
+
* Runs BEFORE LLM review in consensus phases to catch obvious issues.
|
|
4
|
+
* Each validator checks for required sections, minimum content length,
|
|
5
|
+
* and structural integrity specific to its artifact type.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ArtifactType } from './types.js';
|
|
9
|
+
|
|
10
|
+
// ─── Types ───────────────────────────────────────────────
|
|
11
|
+
|
|
12
|
+
export interface ValidationResult {
|
|
13
|
+
valid: boolean;
|
|
14
|
+
errors: string[];
|
|
15
|
+
warnings: string[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// ─── Section Patterns ────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
/** Regex patterns for detecting markdown sections (case-insensitive) */
|
|
21
|
+
function hasSection(content: string, patterns: RegExp[]): boolean {
|
|
22
|
+
return patterns.some((p) => p.test(content));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function findMissingSections(
|
|
26
|
+
content: string,
|
|
27
|
+
required: { name: string; patterns: RegExp[] }[],
|
|
28
|
+
): string[] {
|
|
29
|
+
const missing: string[] = [];
|
|
30
|
+
for (const { name, patterns } of required) {
|
|
31
|
+
if (!hasSection(content, patterns)) {
|
|
32
|
+
missing.push(name);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return missing;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ─── Per-Type Validators ─────────────────────────────────
|
|
39
|
+
|
|
40
|
+
function validateMasterPlan(content: string): ValidationResult {
|
|
41
|
+
const errors: string[] = [];
|
|
42
|
+
const warnings: string[] = [];
|
|
43
|
+
|
|
44
|
+
if (content.length < 200) {
|
|
45
|
+
errors.push('Master plan is too short (min 200 characters)');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const missing = findMissingSections(content, [
|
|
49
|
+
{ name: 'Goals/Objectives', patterns: [/#+\s*(goals?|objectives?)/i, /\bgoals?\b.*:/i] },
|
|
50
|
+
{ name: 'Milestones', patterns: [/#+\s*milestones?/i, /\bmilestone\s+\d/i] },
|
|
51
|
+
{ name: 'Success Criteria', patterns: [/#+\s*success\s+criteria/i, /\bsuccess\s+criteria\b/i, /#+\s*acceptance\s+criteria/i] },
|
|
52
|
+
]);
|
|
53
|
+
|
|
54
|
+
for (const section of missing) {
|
|
55
|
+
errors.push(`Missing required section: ${section}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Check for empty sections (heading followed by another heading or end)
|
|
59
|
+
const emptyHeadings = content.match(/^(#+\s+.+)\n(?=#+\s+|\s*$)/gm);
|
|
60
|
+
if (emptyHeadings && emptyHeadings.length > 2) {
|
|
61
|
+
warnings.push(`${emptyHeadings.length} potentially empty sections detected`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function validateArchitecture(content: string): ValidationResult {
|
|
68
|
+
const errors: string[] = [];
|
|
69
|
+
const warnings: string[] = [];
|
|
70
|
+
|
|
71
|
+
if (content.length < 200) {
|
|
72
|
+
errors.push('Architecture document is too short (min 200 characters)');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const missing = findMissingSections(content, [
|
|
76
|
+
{ name: 'Components/Modules', patterns: [/#+\s*(components?|modules?|services?)/i, /\bcomponent\b/i] },
|
|
77
|
+
{ name: 'Data Flow/Contracts', patterns: [/#+\s*(data\s+flow|contracts?|api|interfaces?)/i, /\bcontract\b/i, /\bdata\s+flow\b/i] },
|
|
78
|
+
{ name: 'Tech Stack', patterns: [/#+\s*(tech\s+stack|technology|stack)/i, /\btech\s+stack\b/i] },
|
|
79
|
+
]);
|
|
80
|
+
|
|
81
|
+
for (const section of missing) {
|
|
82
|
+
errors.push(`Missing required section: ${section}`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Must reference at least one file path
|
|
86
|
+
const hasFilePath = /(?:src\/|app\/|pages\/|lib\/|\.ts|\.js|\.py|\.go)/.test(content);
|
|
87
|
+
if (!hasFilePath) {
|
|
88
|
+
warnings.push('Architecture should reference at least one file path');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function validateRolePlan(content: string): ValidationResult {
|
|
95
|
+
const errors: string[] = [];
|
|
96
|
+
const warnings: string[] = [];
|
|
97
|
+
|
|
98
|
+
if (content.length < 100) {
|
|
99
|
+
errors.push('Role plan is too short (min 100 characters)');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const missing = findMissingSections(content, [
|
|
103
|
+
{ name: 'Tasks/Responsibilities', patterns: [/#+\s*(tasks?|responsibilities?|work\s+items?)/i, /\btask\b/i] },
|
|
104
|
+
{ name: 'Dependencies', patterns: [/#+\s*(dependenc|prerequisites?|requires?)/i, /\bdepend/i] },
|
|
105
|
+
{ name: 'Acceptance Criteria', patterns: [/#+\s*(acceptance|done\s+when|completion)/i, /\bacceptance\b/i, /\bdone\s+when\b/i] },
|
|
106
|
+
]);
|
|
107
|
+
|
|
108
|
+
for (const section of missing) {
|
|
109
|
+
errors.push(`Missing required section: ${section}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Should reference a role name
|
|
113
|
+
const rolePatterns = /\b(DISPATCHER|ARCHITECT|DB_EXPERT|BACKEND|FRONTEND|WEBSITE|QA_TESTER|REVIEWER|AUDITOR|JOURNALIST)\b/i;
|
|
114
|
+
if (!rolePatterns.test(content)) {
|
|
115
|
+
warnings.push('Role plan should reference the role name');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function validateQaValidation(content: string): ValidationResult {
|
|
122
|
+
const errors: string[] = [];
|
|
123
|
+
const warnings: string[] = [];
|
|
124
|
+
|
|
125
|
+
const missing = findMissingSections(content, [
|
|
126
|
+
{ name: 'Test Results', patterns: [/#+\s*(test\s+results?|results?)/i, /\btest\s+results?\b/i, /\bpass(?:ed|ing)?\b/i] },
|
|
127
|
+
{ name: 'Coverage', patterns: [/#+\s*coverage/i, /\bcoverage\b/i, /\d+\s*%/] },
|
|
128
|
+
]);
|
|
129
|
+
|
|
130
|
+
for (const section of missing) {
|
|
131
|
+
errors.push(`Missing required section: ${section}`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Should contain pass/fail counts
|
|
135
|
+
const hasPassFail = /\b\d+\s*(pass|fail|error|skip)/i.test(content);
|
|
136
|
+
if (!hasPassFail) {
|
|
137
|
+
warnings.push('QA validation should include pass/fail counts');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function validateAuditReport(content: string): ValidationResult {
|
|
144
|
+
const errors: string[] = [];
|
|
145
|
+
const warnings: string[] = [];
|
|
146
|
+
|
|
147
|
+
// Try JSON parsing
|
|
148
|
+
try {
|
|
149
|
+
const parsed = JSON.parse(content);
|
|
150
|
+
if (!Array.isArray(parsed.findings)) {
|
|
151
|
+
errors.push('Audit report must have a "findings" array');
|
|
152
|
+
}
|
|
153
|
+
if (typeof parsed.overall_status !== 'string') {
|
|
154
|
+
errors.push('Audit report must have "overall_status"');
|
|
155
|
+
}
|
|
156
|
+
if (typeof parsed.system_risk_score !== 'number') {
|
|
157
|
+
errors.push('Audit report must have "system_risk_score"');
|
|
158
|
+
}
|
|
159
|
+
} catch {
|
|
160
|
+
// Not JSON — check for markdown-style audit
|
|
161
|
+
if (!content.includes('findings') && !content.includes('finding')) {
|
|
162
|
+
errors.push('Audit report must contain findings');
|
|
163
|
+
}
|
|
164
|
+
if (!content.includes('status') && !content.includes('PASS') && !content.includes('FAIL')) {
|
|
165
|
+
errors.push('Audit report must contain overall status');
|
|
166
|
+
}
|
|
167
|
+
if (!content.includes('risk') && !content.includes('score')) {
|
|
168
|
+
warnings.push('Audit report should include risk score');
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// ─── Validator Registry ──────────────────────────────────
|
|
176
|
+
|
|
177
|
+
const VALIDATORS: Partial<Record<ArtifactType, (content: string) => ValidationResult>> = {
|
|
178
|
+
master_plan: validateMasterPlan,
|
|
179
|
+
architecture: validateArchitecture,
|
|
180
|
+
role_plan: validateRolePlan,
|
|
181
|
+
qa_validation: validateQaValidation,
|
|
182
|
+
audit_report: validateAuditReport,
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// ─── Public API ──────────────────────────────────────────
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Validate artifact content completeness based on type-specific rules.
|
|
189
|
+
* Returns a ValidationResult with errors (blocking) and warnings (non-blocking).
|
|
190
|
+
*
|
|
191
|
+
* Args:
|
|
192
|
+
* type: The artifact type to validate against.
|
|
193
|
+
* content: The artifact content string.
|
|
194
|
+
*
|
|
195
|
+
* Returns:
|
|
196
|
+
* ValidationResult with valid flag, errors, and warnings.
|
|
197
|
+
*/
|
|
198
|
+
export function validateArtifactCompleteness(
|
|
199
|
+
type: ArtifactType,
|
|
200
|
+
content: string,
|
|
201
|
+
): ValidationResult {
|
|
202
|
+
const validator = VALIDATORS[type];
|
|
203
|
+
if (!validator) {
|
|
204
|
+
// No validator for this type — pass by default
|
|
205
|
+
return { valid: true, errors: [], warnings: [] };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (!content || content.trim().length === 0) {
|
|
209
|
+
return {
|
|
210
|
+
valid: false,
|
|
211
|
+
errors: [`${type} artifact has empty content`],
|
|
212
|
+
warnings: [],
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return validator(content);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Get all artifact types that have validators.
|
|
221
|
+
*/
|
|
222
|
+
export function getValidatableArtifactTypes(): ArtifactType[] {
|
|
223
|
+
return Object.keys(VALIDATORS) as ArtifactType[];
|
|
224
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Change Request mechanism — structured change tracking for mid-pipeline modifications.
|
|
3
|
+
* CRs are created when drift is detected (REVIEW) or architectural issues found (AUDIT).
|
|
4
|
+
* Each CR routes to the appropriate consensus phase for approval.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { randomUUID } from 'node:crypto';
|
|
8
|
+
|
|
9
|
+
import type {
|
|
10
|
+
PipelinePhase,
|
|
11
|
+
PipelineRole,
|
|
12
|
+
ArtifactRef,
|
|
13
|
+
ChangeRequest,
|
|
14
|
+
} from './types.js';
|
|
15
|
+
|
|
16
|
+
// ─── CR Builder ──────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
export interface BuildChangeRequestArgs {
|
|
19
|
+
originPhase: PipelinePhase;
|
|
20
|
+
requestedBy: PipelineRole;
|
|
21
|
+
changeType: ChangeRequest['change_type'];
|
|
22
|
+
description: string;
|
|
23
|
+
justification: string;
|
|
24
|
+
affectedArtifacts: ArtifactRef[];
|
|
25
|
+
affectedPhases: PipelinePhase[];
|
|
26
|
+
riskLevel: 'low' | 'medium' | 'high';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Build a change request with generated ID and timestamp.
|
|
31
|
+
*
|
|
32
|
+
* Args:
|
|
33
|
+
* args: Change request parameters.
|
|
34
|
+
*
|
|
35
|
+
* Returns:
|
|
36
|
+
* A fully formed ChangeRequest in 'proposed' status.
|
|
37
|
+
*/
|
|
38
|
+
export function buildChangeRequest(args: BuildChangeRequestArgs): ChangeRequest {
|
|
39
|
+
return {
|
|
40
|
+
cr_id: `CR-${randomUUID().split('-')[0].toUpperCase()}`,
|
|
41
|
+
timestamp: new Date().toISOString(),
|
|
42
|
+
origin_phase: args.originPhase,
|
|
43
|
+
requested_by: args.requestedBy,
|
|
44
|
+
change_type: args.changeType,
|
|
45
|
+
description: args.description,
|
|
46
|
+
justification: args.justification,
|
|
47
|
+
impact_analysis: {
|
|
48
|
+
affected_artifacts: args.affectedArtifacts,
|
|
49
|
+
affected_phases: args.affectedPhases,
|
|
50
|
+
risk_level: args.riskLevel,
|
|
51
|
+
},
|
|
52
|
+
status: 'proposed',
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ─── CR Routing ──────────────────────────────────────────
|
|
57
|
+
|
|
58
|
+
/** Maps change types to the consensus phase that must approve them */
|
|
59
|
+
const CHANGE_TYPE_ROUTING: Record<ChangeRequest['change_type'], PipelinePhase> = {
|
|
60
|
+
scope: 'CONSENSUS_MASTER_PLAN',
|
|
61
|
+
architecture: 'CONSENSUS_ARCHITECTURE',
|
|
62
|
+
dependency: 'CONSENSUS_ROLE_PLANS',
|
|
63
|
+
config: 'QA_VALIDATION',
|
|
64
|
+
requirement: 'CONSENSUS_MASTER_PLAN',
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Determine which consensus phase should review a change request.
|
|
69
|
+
*
|
|
70
|
+
* Args:
|
|
71
|
+
* cr: The change request to route.
|
|
72
|
+
*
|
|
73
|
+
* Returns:
|
|
74
|
+
* The pipeline phase that should handle the CR approval.
|
|
75
|
+
*/
|
|
76
|
+
export function routeChangeRequest(cr: ChangeRequest): PipelinePhase {
|
|
77
|
+
return CHANGE_TYPE_ROUTING[cr.change_type];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ─── CR Formatting ───────────────────────────────────────
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Format a change request as markdown for inclusion in artifacts.
|
|
84
|
+
*
|
|
85
|
+
* Args:
|
|
86
|
+
* cr: The change request to format.
|
|
87
|
+
*
|
|
88
|
+
* Returns:
|
|
89
|
+
* Markdown-formatted string.
|
|
90
|
+
*/
|
|
91
|
+
export function formatChangeRequest(cr: ChangeRequest): string {
|
|
92
|
+
const lines = [
|
|
93
|
+
`# Change Request ${cr.cr_id}`,
|
|
94
|
+
'',
|
|
95
|
+
`**Status:** ${cr.status}`,
|
|
96
|
+
`**Type:** ${cr.change_type}`,
|
|
97
|
+
`**Origin Phase:** ${cr.origin_phase}`,
|
|
98
|
+
`**Requested By:** ${cr.requested_by}`,
|
|
99
|
+
`**Risk Level:** ${cr.impact_analysis.risk_level}`,
|
|
100
|
+
`**Timestamp:** ${cr.timestamp}`,
|
|
101
|
+
'',
|
|
102
|
+
'## Description',
|
|
103
|
+
cr.description,
|
|
104
|
+
'',
|
|
105
|
+
'## Justification',
|
|
106
|
+
cr.justification,
|
|
107
|
+
'',
|
|
108
|
+
'## Impact Analysis',
|
|
109
|
+
`- Affected phases: ${cr.impact_analysis.affected_phases.join(', ')}`,
|
|
110
|
+
`- Affected artifacts: ${cr.impact_analysis.affected_artifacts.length}`,
|
|
111
|
+
`- Risk level: ${cr.impact_analysis.risk_level}`,
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
if (cr.approval_artifact) {
|
|
115
|
+
lines.push('', `## Approval: ${cr.approval_artifact.artifact_id}`);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return lines.join('\n');
|
|
119
|
+
}
|