role-os 2.0.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/src/artifacts.mjs CHANGED
@@ -1,437 +1,526 @@
1
- /**
2
- * Artifact Spine — Phase Q (v1.6.0)
3
- *
4
- * Every important role produces a declared artifact with a known shape.
5
- * Downstream roles never guess what they received.
6
- *
7
- * 1. Per-role artifact contracts (required sections, evidence, references)
8
- * 2. Structural validation (completeness, not semantic perfection)
9
- * 3. Pack-level handoff contracts (expected artifact flow between steps)
10
- * 4. Composite artifact ledger integration
11
- */
12
-
13
- // ── Per-role artifact contracts ───────────────────────────────────────────────
14
-
15
- /**
16
- * Each contract defines what a role MUST produce for its handoff to be valid.
17
- * Not every role needs a contract — only chain-critical roles that hand off
18
- * to other roles.
19
- */
20
- export const ROLE_ARTIFACT_CONTRACTS = {
21
- "Product Strategist": {
22
- artifactType: "strategy-brief",
23
- requiredSections: ["problem-framing", "scope", "non-goals", "tradeoffs"],
24
- optionalSections: ["user-value", "risks", "success-criteria"],
25
- requiredEvidence: [],
26
- consumedBy: ["Spec Writer", "Orchestrator"],
27
- completionRule: "All 4 required sections must be present and non-empty.",
28
- },
29
- "Spec Writer": {
30
- artifactType: "implementation-spec",
31
- requiredSections: ["acceptance-criteria", "edge-cases", "interface-spec"],
32
- optionalSections: ["data-schema", "nfrs", "open-questions"],
33
- requiredEvidence: ["strategy-brief"],
34
- consumedBy: ["Backend Engineer", "Frontend Developer"],
35
- completionRule: "At least 3 acceptance criteria. Edge cases identified. Interface shape defined.",
36
- },
37
- "Backend Engineer": {
38
- artifactType: "change-plan",
39
- requiredSections: ["files-to-change", "implementation-approach", "risk-notes"],
40
- optionalSections: ["test-strategy", "migration-notes"],
41
- requiredEvidence: ["implementation-spec"],
42
- consumedBy: ["Test Engineer", "Critic Reviewer"],
43
- completionRule: "Files named. Approach described. Risks surfaced.",
44
- },
45
- "Frontend Developer": {
46
- artifactType: "change-plan",
47
- requiredSections: ["files-to-change", "implementation-approach", "risk-notes"],
48
- optionalSections: ["component-structure", "accessibility-notes"],
49
- requiredEvidence: ["implementation-spec"],
50
- consumedBy: ["Test Engineer", "Critic Reviewer"],
51
- completionRule: "Files named. Approach described. Risks surfaced.",
52
- },
53
- "Test Engineer": {
54
- artifactType: "test-package",
55
- requiredSections: ["test-plan", "test-cases", "false-confidence-assessment"],
56
- optionalSections: ["edge-case-coverage", "regression-defense"],
57
- requiredEvidence: ["change-plan"],
58
- consumedBy: ["Critic Reviewer"],
59
- completionRule: "Test plan present. At least 3 test cases. False confidence assessment honest.",
60
- },
61
- "Security Reviewer": {
62
- artifactType: "security-findings",
63
- requiredSections: ["findings", "severity-assessment", "recommendations"],
64
- optionalSections: ["threat-model", "exploitation-scenarios"],
65
- requiredEvidence: ["change-plan"],
66
- consumedBy: ["Backend Engineer", "Critic Reviewer"],
67
- completionRule: "Each finding has severity + recommendation. No finding without remediation path.",
68
- },
69
- "Coverage Auditor": {
70
- artifactType: "coverage-report",
71
- requiredSections: ["well-defended", "poorly-defended", "false-confidence", "priority-recommendations"],
72
- optionalSections: ["missing-defenses", "regression-vectors"],
73
- requiredEvidence: [],
74
- consumedBy: ["Test Engineer", "Critic Reviewer"],
75
- completionRule: "Coverage honestly assessed. False confidence identified. Priorities ranked.",
76
- },
77
- "Docs Architect": {
78
- artifactType: "doc-map",
79
- requiredSections: ["page-structure", "content-gaps", "navigation-design"],
80
- optionalSections: ["getting-started-flow", "search-requirements"],
81
- requiredEvidence: [],
82
- consumedBy: ["Metadata Curator", "Release Engineer"],
83
- completionRule: "Pages listed. Gaps identified. Navigation designed.",
84
- },
85
- "Launch Strategist": {
86
- artifactType: "launch-brief",
87
- requiredSections: ["launch-sequence", "proof-packaging", "channel-selection", "success-criteria"],
88
- optionalSections: ["risk-assessment", "what-not-to-say"],
89
- requiredEvidence: [],
90
- consumedBy: ["Launch Copywriter"],
91
- completionRule: "Sequence defined. Proof mapped. Channels selected. Success measurable.",
92
- },
93
- "Launch Copywriter": {
94
- artifactType: "copy-package",
95
- requiredSections: ["release-notes", "short-announcement"],
96
- optionalSections: ["npm-description", "social-variants", "messaging-angle"],
97
- requiredEvidence: ["launch-brief"],
98
- consumedBy: ["Critic Reviewer"],
99
- completionRule: "Release notes present. At least one announcement variant.",
100
- },
101
- "Repo Researcher": {
102
- artifactType: "repo-map",
103
- requiredSections: ["entrypoints", "module-map", "build-test-commands"],
104
- optionalSections: ["seams", "dependencies"],
105
- requiredEvidence: [],
106
- consumedBy: ["Backend Engineer", "Coverage Auditor", "Security Reviewer"],
107
- completionRule: "Entrypoints listed. Module responsibilities described. Commands documented.",
108
- },
109
- "Metadata Curator": {
110
- artifactType: "metadata-audit",
111
- requiredSections: ["manifest-audit", "registry-alignment"],
112
- optionalSections: ["badge-verification", "discovery-surface", "recommendations"],
113
- requiredEvidence: [],
114
- consumedBy: ["Release Engineer"],
115
- completionRule: "Package.json audited. Registry alignment checked.",
116
- },
117
- "Release Engineer": {
118
- artifactType: "release-plan",
119
- requiredSections: ["version-decision", "changelog-draft", "pre-publish-checklist"],
120
- optionalSections: ["packaging-check", "release-steps"],
121
- requiredEvidence: [],
122
- consumedBy: ["Deployment Verifier", "Critic Reviewer"],
123
- completionRule: "Version decided with rationale. Changelog written. Checklist present.",
124
- },
125
- "Deployment Verifier": {
126
- artifactType: "deployment-report",
127
- requiredSections: ["live-state-assessment"],
128
- optionalSections: ["npm-verification", "github-verification", "badge-verification", "translation-check"],
129
- requiredEvidence: [],
130
- consumedBy: ["Critic Reviewer"],
131
- completionRule: "All deployed surfaces checked. Stale/mismatched items named.",
132
- },
133
- "Critic Reviewer": {
134
- artifactType: "verdict",
135
- requiredSections: ["verdict", "evidence", "required-corrections"],
136
- optionalSections: ["notes", "next-owner", "chain-assessment"],
137
- requiredEvidence: [],
138
- consumedBy: [],
139
- completionRule: "Verdict stated. Evidence cited. Corrections listed if not accept.",
140
- },
141
- "UX Researcher": {
142
- artifactType: "ux-evaluation",
143
- requiredSections: ["friction-inventory", "severity-ranking", "recommendations"],
144
- optionalSections: ["flow-analysis", "heuristic-evaluation"],
145
- requiredEvidence: [],
146
- consumedBy: ["Product Strategist", "UI Designer"],
147
- completionRule: "Friction points identified. Severity ranked. Evidence-based recommendations.",
148
- },
149
- "Competitive Analyst": {
150
- artifactType: "landscape-analysis",
151
- requiredSections: ["competitor-inventory", "differentiation", "honest-disadvantages"],
152
- optionalSections: ["positioning-gaps", "recommendations"],
153
- requiredEvidence: [],
154
- consumedBy: ["Product Strategist"],
155
- completionRule: "Competitors listed. Differentiation clear. Disadvantages honest.",
156
- },
157
- "Feedback Synthesizer": {
158
- artifactType: "signal-synthesis",
159
- requiredSections: ["theme-extraction", "theme-ranking", "confidence-assessment"],
160
- optionalSections: ["contradictions", "complaint-to-action"],
161
- requiredEvidence: [],
162
- consumedBy: ["Product Strategist"],
163
- completionRule: "Themes extracted. Ranking justified. Confidence assessed.",
164
- },
165
- "Refactor Engineer": {
166
- artifactType: "refactor-plan",
167
- requiredSections: ["structural-assessment", "module-boundaries", "migration-path"],
168
- optionalSections: ["duplication-inventory", "proposed-structure"],
169
- requiredEvidence: [],
170
- consumedBy: ["Test Engineer", "Critic Reviewer"],
171
- completionRule: "Current structure assessed. Target boundaries defined. Migration preserves tests.",
172
- },
173
- "Support Triage Lead": {
174
- artifactType: "triage-report",
175
- requiredSections: ["classification", "priority-assignment", "routing"],
176
- optionalSections: ["recurring-patterns", "systemic-recommendations"],
177
- requiredEvidence: [],
178
- consumedBy: ["Feedback Synthesizer", "Docs Architect"],
179
- completionRule: "Each item classified. Priority assigned. Route to owner named.",
180
- },
181
- };
182
-
183
- // ── Artifact validation ───────────────────────────────────────────────────────
184
-
185
- /**
186
- * Validate an artifact against its role contract.
187
- * Checks structural completeness, not semantic quality.
188
- *
189
- * @param {string} roleName
190
- * @param {string} artifactContent - The artifact text
191
- * @returns {{ valid: boolean, missing: string[], warnings: string[], contract: object|null }}
192
- */
193
- export function validateArtifact(roleName, artifactContent) {
194
- const contract = ROLE_ARTIFACT_CONTRACTS[roleName];
195
- if (!contract) {
196
- return { valid: true, missing: [], warnings: ["No artifact contract defined for this role."], contract: null };
197
- }
198
-
199
- const lower = artifactContent.toLowerCase();
200
- const missing = [];
201
- const warnings = [];
202
-
203
- // Check required sections
204
- for (const section of contract.requiredSections) {
205
- // Look for the section as a heading or key phrase
206
- const patterns = [
207
- section.toLowerCase(),
208
- section.replace(/-/g, " ").toLowerCase(),
209
- `## ${section.replace(/-/g, " ")}`.toLowerCase(),
210
- `### ${section.replace(/-/g, " ")}`.toLowerCase(),
211
- ];
212
- const found = patterns.some(p => lower.includes(p));
213
- if (!found) {
214
- missing.push(section);
215
- }
216
- }
217
-
218
- // Check required evidence references
219
- for (const evidence of contract.requiredEvidence) {
220
- const patterns = [
221
- evidence.toLowerCase(),
222
- evidence.replace(/-/g, " ").toLowerCase(),
223
- ];
224
- const found = patterns.some(p => lower.includes(p));
225
- if (!found) {
226
- warnings.push(`Expected reference to "${evidence}" from upstream role.`);
227
- }
228
- }
229
-
230
- // Check minimum content length (not just headers)
231
- const contentLines = artifactContent.split("\n").filter(l => l.trim() && !l.trim().startsWith("#"));
232
- if (contentLines.length < 5) {
233
- warnings.push("Artifact appears thin fewer than 5 content lines.");
234
- }
235
-
236
- return {
237
- valid: missing.length === 0,
238
- missing,
239
- warnings,
240
- contract,
241
- };
242
- }
243
-
244
- // ── Pack-level handoff contracts ──────────────────────────────────────────────
245
-
246
- /**
247
- * Defines the expected artifact flow for each pack.
248
- * Each step produces an artifact that the next step consumes.
249
- */
250
- export const PACK_HANDOFF_CONTRACTS = {
251
- feature: {
252
- flow: [
253
- { role: "Product Strategist", produces: "strategy-brief", consumedBy: "Spec Writer" },
254
- { role: "Spec Writer", produces: "implementation-spec", consumedBy: "Backend Engineer" },
255
- { role: "Backend Engineer", produces: "change-plan", consumedBy: "Test Engineer" },
256
- { role: "Test Engineer", produces: "test-package", consumedBy: "Critic Reviewer" },
257
- { role: "Critic Reviewer", produces: "verdict", consumedBy: null },
258
- ],
259
- },
260
- bugfix: {
261
- flow: [
262
- { role: "Repo Researcher", produces: "repo-map", consumedBy: "Backend Engineer" },
263
- { role: "Backend Engineer", produces: "change-plan", consumedBy: "Test Engineer" },
264
- { role: "Test Engineer", produces: "test-package", consumedBy: "Critic Reviewer" },
265
- { role: "Critic Reviewer", produces: "verdict", consumedBy: null },
266
- ],
267
- },
268
- security: {
269
- flow: [
270
- { role: "Security Reviewer", produces: "security-findings", consumedBy: "Critic Reviewer" },
271
- { role: "Dependency Auditor", produces: "metadata-audit", consumedBy: "Critic Reviewer" },
272
- { role: "Critic Reviewer", produces: "verdict", consumedBy: null },
273
- ],
274
- },
275
- docs: {
276
- flow: [
277
- { role: "Support Triage Lead", produces: "triage-report", consumedBy: "Feedback Synthesizer" },
278
- { role: "Feedback Synthesizer", produces: "signal-synthesis", consumedBy: "Docs Architect" },
279
- { role: "Docs Architect", produces: "doc-map", consumedBy: "Metadata Curator" },
280
- { role: "Metadata Curator", produces: "metadata-audit", consumedBy: "Critic Reviewer" },
281
- { role: "Critic Reviewer", produces: "verdict", consumedBy: null },
282
- ],
283
- },
284
- launch: {
285
- flow: [
286
- { role: "Launch Strategist", produces: "launch-brief", consumedBy: "Launch Copywriter" },
287
- { role: "Launch Copywriter", produces: "copy-package", consumedBy: "Critic Reviewer" },
288
- { role: "Critic Reviewer", produces: "verdict", consumedBy: null },
289
- ],
290
- },
291
- research: {
292
- flow: [
293
- { role: "Product Strategist", produces: "strategy-brief", consumedBy: "UX Researcher" },
294
- { role: "UX Researcher", produces: "ux-evaluation", consumedBy: "Competitive Analyst" },
295
- { role: "Competitive Analyst", produces: "landscape-analysis", consumedBy: "Feedback Synthesizer" },
296
- { role: "Feedback Synthesizer", produces: "signal-synthesis", consumedBy: "Critic Reviewer" },
297
- { role: "Critic Reviewer", produces: "verdict", consumedBy: null },
298
- ],
299
- },
300
- treatment: {
301
- flow: [
302
- { role: "Repo Researcher", produces: "repo-map", consumedBy: "Security Reviewer" },
303
- { role: "Security Reviewer", produces: "security-findings", consumedBy: "Coverage Auditor" },
304
- { role: "Coverage Auditor", produces: "coverage-report", consumedBy: "Docs Architect" },
305
- { role: "Docs Architect", produces: "doc-map", consumedBy: "Metadata Curator" },
306
- { role: "Metadata Curator", produces: "metadata-audit", consumedBy: "Release Engineer" },
307
- { role: "Release Engineer", produces: "release-plan", consumedBy: "Deployment Verifier" },
308
- { role: "Deployment Verifier", produces: "deployment-report", consumedBy: "Critic Reviewer" },
309
- { role: "Critic Reviewer", produces: "verdict", consumedBy: null },
310
- ],
311
- },
312
- };
313
-
314
- /**
315
- * Validate a pack's artifact chain — check that each step's output
316
- * matches what the next step expects.
317
- *
318
- * @param {string} packName
319
- * @param {Record<string, string>} artifacts - Map of role name → artifact content
320
- * @returns {{ valid: boolean, steps: object[] }}
321
- */
322
- export function validatePackChain(packName, artifacts) {
323
- const contract = PACK_HANDOFF_CONTRACTS[packName];
324
- if (!contract) {
325
- return { valid: false, steps: [{ role: "unknown", status: "error", detail: `No handoff contract for pack "${packName}"` }] };
326
- }
327
-
328
- const steps = [];
329
- let chainValid = true;
330
-
331
- for (const step of contract.flow) {
332
- const content = artifacts[step.role];
333
- if (!content) {
334
- steps.push({
335
- role: step.role,
336
- produces: step.produces,
337
- status: "missing",
338
- detail: `No artifact from ${step.role}.`,
339
- });
340
- chainValid = false;
341
- continue;
342
- }
343
-
344
- const validation = validateArtifact(step.role, content);
345
- steps.push({
346
- role: step.role,
347
- produces: step.produces,
348
- status: validation.valid ? "valid" : "incomplete",
349
- missing: validation.missing,
350
- warnings: validation.warnings,
351
- detail: validation.valid
352
- ? `${step.produces} is structurally complete.`
353
- : `Missing sections: ${validation.missing.join(", ")}`,
354
- });
355
-
356
- if (!validation.valid) chainValid = false;
357
- }
358
-
359
- return { valid: chainValid, steps };
360
- }
361
-
362
- /**
363
- * Get the artifact contract for a specific role.
364
- *
365
- * @param {string} roleName
366
- * @returns {object|null}
367
- */
368
- export function getArtifactContract(roleName) {
369
- return ROLE_ARTIFACT_CONTRACTS[roleName] || null;
370
- }
371
-
372
- /**
373
- * Get the handoff contract for a specific pack.
374
- *
375
- * @param {string} packName
376
- * @returns {object|null}
377
- */
378
- export function getHandoffContract(packName) {
379
- return PACK_HANDOFF_CONTRACTS[packName] || null;
380
- }
381
-
382
- /**
383
- * Format artifact validation result for display.
384
- *
385
- * @param {string} roleName
386
- * @param {object} validation
387
- * @returns {string}
388
- */
389
- export function formatArtifactValidation(roleName, validation) {
390
- const lines = [`Artifact validation — ${roleName}`];
391
-
392
- if (validation.valid) {
393
- lines.push(` ✓ Structurally complete`);
394
- } else {
395
- lines.push(` ✗ Incomplete missing: ${validation.missing.join(", ")}`);
396
- }
397
-
398
- if (validation.warnings.length > 0) {
399
- for (const w of validation.warnings) {
400
- lines.push(` ! ${w}`);
401
- }
402
- }
403
-
404
- if (validation.contract) {
405
- lines.push(` Contract: ${validation.contract.artifactType}`);
406
- lines.push(` Consumed by: ${validation.contract.consumedBy.join(", ") || "terminal"}`);
407
- }
408
-
409
- return lines.join("\n");
410
- }
411
-
412
- /**
413
- * Format pack chain validation for display.
414
- *
415
- * @param {string} packName
416
- * @param {object} chainValidation
417
- * @returns {string}
418
- */
419
- export function formatPackChain(packName, chainValidation) {
420
- const lines = [
421
- `\nPack Chain Validation — ${packName}`,
422
- `─────────────────────────────────`,
423
- ];
424
-
425
- for (const step of chainValidation.steps) {
426
- const icon = step.status === "valid" ? "✓" : step.status === "missing" ? "○" : "!";
427
- lines.push(` ${icon} ${step.role} ${step.produces}: ${step.detail}`);
428
- }
429
-
430
- lines.push(``);
431
- lines.push(chainValidation.valid
432
- ? `Chain valid — all artifacts structurally complete.`
433
- : `Chain incomplete see above for missing artifacts.`
434
- );
435
-
436
- return lines.join("\n");
437
- }
1
+ /**
2
+ * Artifact Spine — Phase Q (v1.6.0)
3
+ *
4
+ * Every important role produces a declared artifact with a known shape.
5
+ * Downstream roles never guess what they received.
6
+ *
7
+ * 1. Per-role artifact contracts (required sections, evidence, references)
8
+ * 2. Structural validation (completeness, not semantic perfection)
9
+ * 3. Pack-level handoff contracts (expected artifact flow between steps)
10
+ * 4. Composite artifact ledger integration
11
+ */
12
+
13
+ // ── Per-role artifact contracts ───────────────────────────────────────────────
14
+
15
+ /**
16
+ * Each contract defines what a role MUST produce for its handoff to be valid.
17
+ * Not every role needs a contract — only chain-critical roles that hand off
18
+ * to other roles.
19
+ */
20
+ export const ROLE_ARTIFACT_CONTRACTS = {
21
+ "Product Strategist": {
22
+ artifactType: "strategy-brief",
23
+ requiredSections: ["problem-framing", "scope", "non-goals", "tradeoffs"],
24
+ optionalSections: ["user-value", "risks", "success-criteria"],
25
+ requiredEvidence: [],
26
+ consumedBy: ["Spec Writer", "Orchestrator"],
27
+ completionRule: "All 4 required sections must be present and non-empty.",
28
+ },
29
+ "Spec Writer": {
30
+ artifactType: "implementation-spec",
31
+ requiredSections: ["acceptance-criteria", "edge-cases", "interface-spec"],
32
+ optionalSections: ["data-schema", "nfrs", "open-questions"],
33
+ requiredEvidence: ["strategy-brief"],
34
+ consumedBy: ["Backend Engineer", "Frontend Developer"],
35
+ completionRule: "At least 3 acceptance criteria. Edge cases identified. Interface shape defined.",
36
+ },
37
+ "Backend Engineer": {
38
+ artifactType: "change-plan",
39
+ requiredSections: ["files-to-change", "implementation-approach", "risk-notes"],
40
+ optionalSections: ["test-strategy", "migration-notes"],
41
+ requiredEvidence: ["implementation-spec"],
42
+ consumedBy: ["Test Engineer", "Critic Reviewer"],
43
+ completionRule: "Files named. Approach described. Risks surfaced.",
44
+ },
45
+ "Frontend Developer": {
46
+ artifactType: "change-plan",
47
+ requiredSections: ["files-to-change", "implementation-approach", "risk-notes"],
48
+ optionalSections: ["component-structure", "accessibility-notes"],
49
+ requiredEvidence: ["implementation-spec"],
50
+ consumedBy: ["Test Engineer", "Critic Reviewer"],
51
+ completionRule: "Files named. Approach described. Risks surfaced.",
52
+ },
53
+ "Test Engineer": {
54
+ artifactType: "test-package",
55
+ requiredSections: ["test-plan", "test-cases", "false-confidence-assessment"],
56
+ optionalSections: ["edge-case-coverage", "regression-defense"],
57
+ requiredEvidence: ["change-plan"],
58
+ consumedBy: ["Critic Reviewer"],
59
+ completionRule: "Test plan present. At least 3 test cases. False confidence assessment honest.",
60
+ },
61
+ "Security Reviewer": {
62
+ artifactType: "security-findings",
63
+ requiredSections: ["findings", "severity-assessment", "recommendations"],
64
+ optionalSections: ["threat-model", "exploitation-scenarios"],
65
+ requiredEvidence: ["change-plan"],
66
+ consumedBy: ["Backend Engineer", "Critic Reviewer"],
67
+ completionRule: "Each finding has severity + recommendation. No finding without remediation path.",
68
+ },
69
+ "Coverage Auditor": {
70
+ artifactType: "coverage-report",
71
+ requiredSections: ["well-defended", "poorly-defended", "false-confidence", "priority-recommendations"],
72
+ optionalSections: ["missing-defenses", "regression-vectors"],
73
+ requiredEvidence: [],
74
+ consumedBy: ["Test Engineer", "Critic Reviewer"],
75
+ completionRule: "Coverage honestly assessed. False confidence identified. Priorities ranked.",
76
+ },
77
+ "Docs Architect": {
78
+ artifactType: "doc-map",
79
+ requiredSections: ["page-structure", "content-gaps", "navigation-design"],
80
+ optionalSections: ["getting-started-flow", "search-requirements"],
81
+ requiredEvidence: [],
82
+ consumedBy: ["Metadata Curator", "Release Engineer"],
83
+ completionRule: "Pages listed. Gaps identified. Navigation designed.",
84
+ },
85
+ "Launch Strategist": {
86
+ artifactType: "launch-brief",
87
+ requiredSections: ["launch-sequence", "proof-packaging", "channel-selection", "success-criteria"],
88
+ optionalSections: ["risk-assessment", "what-not-to-say"],
89
+ requiredEvidence: [],
90
+ consumedBy: ["Launch Copywriter"],
91
+ completionRule: "Sequence defined. Proof mapped. Channels selected. Success measurable.",
92
+ },
93
+ "Launch Copywriter": {
94
+ artifactType: "copy-package",
95
+ requiredSections: ["release-notes", "short-announcement"],
96
+ optionalSections: ["npm-description", "social-variants", "messaging-angle"],
97
+ requiredEvidence: ["launch-brief"],
98
+ consumedBy: ["Critic Reviewer"],
99
+ completionRule: "Release notes present. At least one announcement variant.",
100
+ },
101
+ "Repo Researcher": {
102
+ artifactType: "repo-map",
103
+ requiredSections: ["entrypoints", "module-map", "build-test-commands"],
104
+ optionalSections: ["seams", "dependencies"],
105
+ requiredEvidence: [],
106
+ consumedBy: ["Backend Engineer", "Coverage Auditor", "Security Reviewer"],
107
+ completionRule: "Entrypoints listed. Module responsibilities described. Commands documented.",
108
+ },
109
+ "Metadata Curator": {
110
+ artifactType: "metadata-audit",
111
+ requiredSections: ["manifest-audit", "registry-alignment"],
112
+ optionalSections: ["badge-verification", "discovery-surface", "recommendations"],
113
+ requiredEvidence: [],
114
+ consumedBy: ["Release Engineer"],
115
+ completionRule: "Package.json audited. Registry alignment checked.",
116
+ },
117
+ "Release Engineer": {
118
+ artifactType: "release-plan",
119
+ requiredSections: ["version-decision", "changelog-draft", "pre-publish-checklist"],
120
+ optionalSections: ["packaging-check", "release-steps"],
121
+ requiredEvidence: [],
122
+ consumedBy: ["Deployment Verifier", "Critic Reviewer"],
123
+ completionRule: "Version decided with rationale. Changelog written. Checklist present.",
124
+ },
125
+ "Deployment Verifier": {
126
+ artifactType: "deployment-report",
127
+ requiredSections: ["live-state-assessment"],
128
+ optionalSections: ["npm-verification", "github-verification", "badge-verification", "translation-check"],
129
+ requiredEvidence: [],
130
+ consumedBy: ["Critic Reviewer"],
131
+ completionRule: "All deployed surfaces checked. Stale/mismatched items named.",
132
+ },
133
+ "Critic Reviewer": {
134
+ artifactType: "verdict",
135
+ requiredSections: ["verdict", "evidence", "required-corrections"],
136
+ optionalSections: ["notes", "next-owner", "chain-assessment"],
137
+ requiredEvidence: [],
138
+ consumedBy: [],
139
+ completionRule: "Verdict stated. Evidence cited. Corrections listed if not accept.",
140
+ },
141
+ "UX Researcher": {
142
+ artifactType: "ux-evaluation",
143
+ requiredSections: ["friction-inventory", "severity-ranking", "recommendations"],
144
+ optionalSections: ["flow-analysis", "heuristic-evaluation"],
145
+ requiredEvidence: [],
146
+ consumedBy: ["Product Strategist", "UI Designer"],
147
+ completionRule: "Friction points identified. Severity ranked. Evidence-based recommendations.",
148
+ },
149
+ "Competitive Analyst": {
150
+ artifactType: "landscape-analysis",
151
+ requiredSections: ["competitor-inventory", "differentiation", "honest-disadvantages"],
152
+ optionalSections: ["positioning-gaps", "recommendations"],
153
+ requiredEvidence: [],
154
+ consumedBy: ["Product Strategist"],
155
+ completionRule: "Competitors listed. Differentiation clear. Disadvantages honest.",
156
+ },
157
+ "Feedback Synthesizer": {
158
+ artifactType: "signal-synthesis",
159
+ requiredSections: ["theme-extraction", "theme-ranking", "confidence-assessment"],
160
+ optionalSections: ["contradictions", "complaint-to-action"],
161
+ requiredEvidence: [],
162
+ consumedBy: ["Product Strategist"],
163
+ completionRule: "Themes extracted. Ranking justified. Confidence assessed.",
164
+ },
165
+ "Refactor Engineer": {
166
+ artifactType: "refactor-plan",
167
+ requiredSections: ["structural-assessment", "module-boundaries", "migration-path"],
168
+ optionalSections: ["duplication-inventory", "proposed-structure"],
169
+ requiredEvidence: [],
170
+ consumedBy: ["Test Engineer", "Critic Reviewer"],
171
+ completionRule: "Current structure assessed. Target boundaries defined. Migration preserves tests.",
172
+ },
173
+ "Support Triage Lead": {
174
+ artifactType: "triage-report",
175
+ requiredSections: ["classification", "priority-assignment", "routing"],
176
+ optionalSections: ["recurring-patterns", "systemic-recommendations"],
177
+ requiredEvidence: [],
178
+ consumedBy: ["Feedback Synthesizer", "Docs Architect"],
179
+ completionRule: "Each item classified. Priority assigned. Route to owner named.",
180
+ },
181
+
182
+ // ── Brainstorm mission roles (v0.4) ─────────────────────────────────────────
183
+ //
184
+ // Layer 1: Truth — role-native schemas, provenance atoms, dispute graph
185
+ // Layer 2: Render — human-legible presentation (opt-in, never consumed by synthesis)
186
+ //
187
+ "Context Analyst": {
188
+ artifactType: "context-map",
189
+ requiredSections: ["terms", "category-map", "lineage-claims", "boundary-claims"],
190
+ optionalSections: [],
191
+ requiredEvidence: ["brainstorm-frame"],
192
+ consumedBy: ["Normalizer"],
193
+ completionRule: "3+ terms with adjacency. 2+ categories with examples. 1+ lineage claims with precedent. 1+ boundary claims. No forbidden phrases (blindspot enforced). Rendered as Boundary Memo (taxonomist voice).",
194
+ },
195
+ "User Value Analyst": {
196
+ artifactType: "user-value-map",
197
+ requiredSections: ["jobs", "frictions", "unmet-desires", "willingness-signals"],
198
+ optionalSections: [],
199
+ requiredEvidence: ["brainstorm-frame"],
200
+ consumedBy: ["Normalizer"],
201
+ completionRule: "2+ jobs (actor/situation/outcome). 2+ frictions with severity. 1+ unmet desires. 1+ willingness signals. No forbidden phrases (blindspot enforced). Rendered as Field Notes (ethnographer voice).",
202
+ },
203
+ "Mechanics Analyst": {
204
+ artifactType: "mechanics-map",
205
+ requiredSections: ["loops", "dependencies", "failure-points", "irreducible-mechanisms"],
206
+ optionalSections: [],
207
+ requiredEvidence: ["brainstorm-frame"],
208
+ consumedBy: ["Normalizer"],
209
+ completionRule: "1+ named loops (input/transform/output). 1+ dependencies. 1+ failure points. 1+ irreducible mechanisms. No forbidden phrases (blindspot enforced). Rendered as System Sketch (whiteboard voice).",
210
+ },
211
+ "Positioning Analyst": {
212
+ artifactType: "positioning-map",
213
+ requiredSections: ["substitutes", "wedge-candidates", "category-frame"],
214
+ optionalSections: ["forbidden-claims"],
215
+ requiredEvidence: ["brainstorm-frame"],
216
+ consumedBy: ["Normalizer"],
217
+ completionRule: "1+ substitutes (name/overlap/gap). 1+ wedge candidates (claim/timing/risk). Category frame as single declarative sentence. No forbidden phrases (blindspot enforced). Rendered as Claim Brief (strategist voice).",
218
+ },
219
+ "Contrarian Analyst": {
220
+ artifactType: "challenge-set",
221
+ requiredSections: ["challenges"],
222
+ optionalSections: [],
223
+ requiredEvidence: ["provenance-atoms"],
224
+ consumedBy: ["Normalizer"],
225
+ completionRule: "1+ challenges targeting specific atom IDs. Each has challenge_type, argument, evidence_grade, confidence. Only challenges permitted by cross-exam matrix accepted. Rendered as Cross-Exam Transcript (litigator voice).",
226
+ },
227
+ "Normalizer": {
228
+ artifactType: "provenance-atoms",
229
+ requiredSections: ["atoms", "conflicts", "stats"],
230
+ optionalSections: ["unsupported-high-confidence-flags", "rebuttal-set"],
231
+ requiredEvidence: ["context-map", "user-value-map", "mechanics-map", "positioning-map"],
232
+ consumedBy: ["Contrarian Analyst", "Synthesizer"],
233
+ completionRule: "Every atom carries source_role, source_artifact_type, claim_kind, allowed_challengers. No claim kinds overlap between roles. Rebuttal set: each original analyst defends/narrows/retracts challenged claims.",
234
+ },
235
+ "Synthesizer": {
236
+ artifactType: "synthesis-report",
237
+ requiredSections: ["topic-model", "major-themes", "advancing-directions", "archived-directions"],
238
+ optionalSections: ["tensions", "incubation-directions"],
239
+ requiredEvidence: ["provenance-atoms", "challenge-set", "rebuttal-set"],
240
+ consumedBy: ["Product Expander"],
241
+ completionRule: "Exactly breadth advancing directions. Each cites >= 2 truth-layer atoms (never rendered prose). Tensions reference dispute graph outcomes. Archived directions have reasons.",
242
+ },
243
+ "Product Expander": {
244
+ artifactType: "expanded-concept",
245
+ requiredSections: ["product-shape"],
246
+ optionalSections: ["scenarios", "moat"],
247
+ requiredEvidence: ["synthesis-report"],
248
+ consumedBy: ["Judge"],
249
+ completionRule: "Product shape has target_user, core_mechanism, features, core_loop, smallest_proof. Each concept maps to a synthesis direction.",
250
+ },
251
+ "Judge": {
252
+ artifactType: "judge-report",
253
+ requiredSections: ["disposition", "per-direction", "reasons"],
254
+ optionalSections: ["revision-targets", "revision-guidance"],
255
+ requiredEvidence: ["expanded-concept", "synthesis-report", "brainstorm-frame"],
256
+ consumedBy: [],
257
+ completionRule: "Disposition is accept/revise_expand/revise_synthesize/reject. Verdicts: ready_to_advance/needs_incubation/not_active_now. Actions: build_now/hold_for_followon/archive_but_retain. Revise requires targets.",
258
+ },
259
+ };
260
+
261
+ // ── Artifact validation ───────────────────────────────────────────────────────
262
+
263
+ /**
264
+ * Validate an artifact against its role contract.
265
+ * Checks structural completeness, not semantic quality.
266
+ *
267
+ * @param {string} roleName
268
+ * @param {string} artifactContent - The artifact text
269
+ * @returns {{ valid: boolean, missing: string[], warnings: string[], contract: object|null }}
270
+ */
271
+ export function validateArtifact(roleName, artifactContent) {
272
+ const contract = ROLE_ARTIFACT_CONTRACTS[roleName];
273
+ if (!contract) {
274
+ return { valid: true, missing: [], warnings: ["No artifact contract defined for this role."], contract: null };
275
+ }
276
+
277
+ const lower = artifactContent.toLowerCase();
278
+ const missing = [];
279
+ const warnings = [];
280
+
281
+ // Check required sections
282
+ for (const section of contract.requiredSections) {
283
+ // Look for the section as a heading or key phrase
284
+ const patterns = [
285
+ section.toLowerCase(),
286
+ section.replace(/-/g, " ").toLowerCase(),
287
+ `## ${section.replace(/-/g, " ")}`.toLowerCase(),
288
+ `### ${section.replace(/-/g, " ")}`.toLowerCase(),
289
+ ];
290
+ const found = patterns.some(p => lower.includes(p));
291
+ if (!found) {
292
+ missing.push(section);
293
+ }
294
+ }
295
+
296
+ // Check required evidence references
297
+ for (const evidence of contract.requiredEvidence) {
298
+ const patterns = [
299
+ evidence.toLowerCase(),
300
+ evidence.replace(/-/g, " ").toLowerCase(),
301
+ ];
302
+ const found = patterns.some(p => lower.includes(p));
303
+ if (!found) {
304
+ warnings.push(`Expected reference to "${evidence}" from upstream role.`);
305
+ }
306
+ }
307
+
308
+ // Check minimum content length (not just headers)
309
+ const contentLines = artifactContent.split("\n").filter(l => l.trim() && !l.trim().startsWith("#"));
310
+ if (contentLines.length < 5) {
311
+ warnings.push("Artifact appears thin — fewer than 5 content lines.");
312
+ }
313
+
314
+ return {
315
+ valid: missing.length === 0,
316
+ missing,
317
+ warnings,
318
+ contract,
319
+ };
320
+ }
321
+
322
+ // ── Pack-level handoff contracts ──────────────────────────────────────────────
323
+
324
+ /**
325
+ * Defines the expected artifact flow for each pack.
326
+ * Each step produces an artifact that the next step consumes.
327
+ */
328
+ export const PACK_HANDOFF_CONTRACTS = {
329
+ feature: {
330
+ flow: [
331
+ { role: "Product Strategist", produces: "strategy-brief", consumedBy: "Spec Writer" },
332
+ { role: "Spec Writer", produces: "implementation-spec", consumedBy: "Backend Engineer" },
333
+ { role: "Backend Engineer", produces: "change-plan", consumedBy: "Test Engineer" },
334
+ { role: "Test Engineer", produces: "test-package", consumedBy: "Critic Reviewer" },
335
+ { role: "Critic Reviewer", produces: "verdict", consumedBy: null },
336
+ ],
337
+ },
338
+ bugfix: {
339
+ flow: [
340
+ { role: "Repo Researcher", produces: "repo-map", consumedBy: "Backend Engineer" },
341
+ { role: "Backend Engineer", produces: "change-plan", consumedBy: "Test Engineer" },
342
+ { role: "Test Engineer", produces: "test-package", consumedBy: "Critic Reviewer" },
343
+ { role: "Critic Reviewer", produces: "verdict", consumedBy: null },
344
+ ],
345
+ },
346
+ security: {
347
+ flow: [
348
+ { role: "Security Reviewer", produces: "security-findings", consumedBy: "Critic Reviewer" },
349
+ { role: "Dependency Auditor", produces: "metadata-audit", consumedBy: "Critic Reviewer" },
350
+ { role: "Critic Reviewer", produces: "verdict", consumedBy: null },
351
+ ],
352
+ },
353
+ docs: {
354
+ flow: [
355
+ { role: "Support Triage Lead", produces: "triage-report", consumedBy: "Feedback Synthesizer" },
356
+ { role: "Feedback Synthesizer", produces: "signal-synthesis", consumedBy: "Docs Architect" },
357
+ { role: "Docs Architect", produces: "doc-map", consumedBy: "Metadata Curator" },
358
+ { role: "Metadata Curator", produces: "metadata-audit", consumedBy: "Critic Reviewer" },
359
+ { role: "Critic Reviewer", produces: "verdict", consumedBy: null },
360
+ ],
361
+ },
362
+ launch: {
363
+ flow: [
364
+ { role: "Launch Strategist", produces: "launch-brief", consumedBy: "Launch Copywriter" },
365
+ { role: "Launch Copywriter", produces: "copy-package", consumedBy: "Critic Reviewer" },
366
+ { role: "Critic Reviewer", produces: "verdict", consumedBy: null },
367
+ ],
368
+ },
369
+ research: {
370
+ flow: [
371
+ { role: "Product Strategist", produces: "strategy-brief", consumedBy: "UX Researcher" },
372
+ { role: "UX Researcher", produces: "ux-evaluation", consumedBy: "Competitive Analyst" },
373
+ { role: "Competitive Analyst", produces: "landscape-analysis", consumedBy: "Feedback Synthesizer" },
374
+ { role: "Feedback Synthesizer", produces: "signal-synthesis", consumedBy: "Critic Reviewer" },
375
+ { role: "Critic Reviewer", produces: "verdict", consumedBy: null },
376
+ ],
377
+ },
378
+ brainstorm: {
379
+ flow: [
380
+ { role: "Context Scout", produces: "scout-finding", consumedBy: "Normalizer" },
381
+ { role: "User Value Scout", produces: "scout-finding", consumedBy: "Normalizer" },
382
+ { role: "Creative Leap Scout", produces: "scout-finding", consumedBy: "Normalizer" },
383
+ { role: "Normalizer", produces: "normalized-finding-set", consumedBy: "Synthesizer" },
384
+ { role: "Synthesizer", produces: "synthesis-report", consumedBy: "Product Expander" },
385
+ { role: "Product Expander", produces: "expanded-concept", consumedBy: "Judge" },
386
+ { role: "Judge", produces: "judge-report", consumedBy: null },
387
+ ],
388
+ },
389
+ treatment: {
390
+ flow: [
391
+ { role: "Repo Researcher", produces: "repo-map", consumedBy: "Security Reviewer" },
392
+ { role: "Security Reviewer", produces: "security-findings", consumedBy: "Coverage Auditor" },
393
+ { role: "Coverage Auditor", produces: "coverage-report", consumedBy: "Docs Architect" },
394
+ { role: "Docs Architect", produces: "doc-map", consumedBy: "Metadata Curator" },
395
+ { role: "Metadata Curator", produces: "metadata-audit", consumedBy: "Release Engineer" },
396
+ { role: "Release Engineer", produces: "release-plan", consumedBy: "Deployment Verifier" },
397
+ { role: "Deployment Verifier", produces: "deployment-report", consumedBy: "Critic Reviewer" },
398
+ { role: "Critic Reviewer", produces: "verdict", consumedBy: null },
399
+ ],
400
+ },
401
+ };
402
+
403
+ /**
404
+ * Validate a pack's artifact chain — check that each step's output
405
+ * matches what the next step expects.
406
+ *
407
+ * @param {string} packName
408
+ * @param {Record<string, string>} artifacts - Map of role name → artifact content
409
+ * @returns {{ valid: boolean, steps: object[] }}
410
+ */
411
+ export function validatePackChain(packName, artifacts) {
412
+ const contract = PACK_HANDOFF_CONTRACTS[packName];
413
+ if (!contract) {
414
+ return { valid: false, steps: [{ role: "unknown", status: "error", detail: `No handoff contract for pack "${packName}"` }] };
415
+ }
416
+
417
+ const steps = [];
418
+ let chainValid = true;
419
+
420
+ for (const step of contract.flow) {
421
+ const content = artifacts[step.role];
422
+ if (!content) {
423
+ steps.push({
424
+ role: step.role,
425
+ produces: step.produces,
426
+ status: "missing",
427
+ detail: `No artifact from ${step.role}.`,
428
+ });
429
+ chainValid = false;
430
+ continue;
431
+ }
432
+
433
+ const validation = validateArtifact(step.role, content);
434
+ steps.push({
435
+ role: step.role,
436
+ produces: step.produces,
437
+ status: validation.valid ? "valid" : "incomplete",
438
+ missing: validation.missing,
439
+ warnings: validation.warnings,
440
+ detail: validation.valid
441
+ ? `${step.produces} is structurally complete.`
442
+ : `Missing sections: ${validation.missing.join(", ")}`,
443
+ });
444
+
445
+ if (!validation.valid) chainValid = false;
446
+ }
447
+
448
+ return { valid: chainValid, steps };
449
+ }
450
+
451
+ /**
452
+ * Get the artifact contract for a specific role.
453
+ *
454
+ * @param {string} roleName
455
+ * @returns {object|null}
456
+ */
457
+ export function getArtifactContract(roleName) {
458
+ return ROLE_ARTIFACT_CONTRACTS[roleName] || null;
459
+ }
460
+
461
+ /**
462
+ * Get the handoff contract for a specific pack.
463
+ *
464
+ * @param {string} packName
465
+ * @returns {object|null}
466
+ */
467
+ export function getHandoffContract(packName) {
468
+ return PACK_HANDOFF_CONTRACTS[packName] || null;
469
+ }
470
+
471
+ /**
472
+ * Format artifact validation result for display.
473
+ *
474
+ * @param {string} roleName
475
+ * @param {object} validation
476
+ * @returns {string}
477
+ */
478
+ export function formatArtifactValidation(roleName, validation) {
479
+ const lines = [`Artifact validation — ${roleName}`];
480
+
481
+ if (validation.valid) {
482
+ lines.push(` ✓ Structurally complete`);
483
+ } else {
484
+ lines.push(` ✗ Incomplete — missing: ${validation.missing.join(", ")}`);
485
+ }
486
+
487
+ if (validation.warnings.length > 0) {
488
+ for (const w of validation.warnings) {
489
+ lines.push(` ! ${w}`);
490
+ }
491
+ }
492
+
493
+ if (validation.contract) {
494
+ lines.push(` Contract: ${validation.contract.artifactType}`);
495
+ lines.push(` Consumed by: ${validation.contract.consumedBy.join(", ") || "terminal"}`);
496
+ }
497
+
498
+ return lines.join("\n");
499
+ }
500
+
501
+ /**
502
+ * Format pack chain validation for display.
503
+ *
504
+ * @param {string} packName
505
+ * @param {object} chainValidation
506
+ * @returns {string}
507
+ */
508
+ export function formatPackChain(packName, chainValidation) {
509
+ const lines = [
510
+ `\nPack Chain Validation — ${packName}`,
511
+ `─────────────────────────────────`,
512
+ ];
513
+
514
+ for (const step of chainValidation.steps) {
515
+ const icon = step.status === "valid" ? "✓" : step.status === "missing" ? "○" : "!";
516
+ lines.push(` ${icon} ${step.role} → ${step.produces}: ${step.detail}`);
517
+ }
518
+
519
+ lines.push(``);
520
+ lines.push(chainValidation.valid
521
+ ? `Chain valid — all artifacts structurally complete.`
522
+ : `Chain incomplete — see above for missing artifacts.`
523
+ );
524
+
525
+ return lines.join("\n");
526
+ }