@openclawbrain/cli 0.4.34 → 0.4.36

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.
@@ -0,0 +1,1185 @@
1
+ #!/usr/bin/env node
2
+ import { createHash } from "node:crypto";
3
+ import { mkdirSync, writeFileSync } from "node:fs";
4
+ import path from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+ const repoRoot = path.resolve(__dirname, "../../../..");
10
+
11
+ export const GRAPHIFY_COMPILED_ARTIFACT_KIND_ORDER_V1 = [
12
+ "map_of_territory",
13
+ "concept_page",
14
+ "neighborhood_summary",
15
+ "provenance_gap_report",
16
+ ];
17
+ export const GRAPHIFY_COMPILED_ARTIFACT_PACK_LAYOUT_V1 = {
18
+ manifest: "pack.manifest.json",
19
+ artifactsDir: "artifacts",
20
+ proposalsDir: "proposals",
21
+ compilerProposal: "proposals/compiler-proposal.json",
22
+ surfaceMap: "surface-map.json",
23
+ proposalReport: "proposal-report.json",
24
+ verdict: "verdict.json",
25
+ };
26
+ export const DEFAULT_GRAPHIFY_COMPILED_ARTIFACT_PACK_PARENT = path.join(repoRoot, "artifacts", "teacher-v3-proof");
27
+ function sha256Text(text) {
28
+ return `sha256:${createHash("sha256").update(String(text ?? ""), "utf8").digest("hex")}`;
29
+ }
30
+ function renderJson(value) {
31
+ return `${JSON.stringify(value, null, 2)}\n`;
32
+ }
33
+ function ensureDir(dirPath) {
34
+ mkdirSync(dirPath, { recursive: true });
35
+ }
36
+ function writeText(filePath, text) {
37
+ ensureDir(path.dirname(filePath));
38
+ writeFileSync(filePath, text, "utf8");
39
+ }
40
+ function writeJson(filePath, value) {
41
+ writeText(filePath, renderJson(value));
42
+ }
43
+ function normalizeText(value) {
44
+ if (typeof value !== "string") {
45
+ return null;
46
+ }
47
+ const trimmed = value.trim();
48
+ return trimmed.length > 0 ? trimmed : null;
49
+ }
50
+ function normalizeBoolean(value) {
51
+ return value === true ? true : value === false ? false : null;
52
+ }
53
+ function normalizeNumber(value) {
54
+ return Number.isFinite(value) ? Number(value) : null;
55
+ }
56
+ function slugify(value) {
57
+ return value
58
+ .toLowerCase()
59
+ .replace(/[^a-z0-9]+/gu, "-")
60
+ .replace(/^-+|-+$/gu, "")
61
+ .replace(/-{2,}/gu, "-") || "bundle";
62
+ }
63
+ function timestampToken(date = new Date()) {
64
+ const resolvedDate = date instanceof Date ? date : new Date(date);
65
+ return resolvedDate.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z").replace("T", "-");
66
+ }
67
+ function relativeRepoPath(filePath) {
68
+ const resolvedPath = path.resolve(filePath);
69
+ const relativePath = path.relative(repoRoot, resolvedPath);
70
+ return relativePath.startsWith("..") ? resolvedPath : relativePath;
71
+ }
72
+ function relativeBundlePath(filePath, baseDir) {
73
+ return path.relative(path.resolve(baseDir), path.resolve(filePath));
74
+ }
75
+ function makeSourceRef(sourceKind, sourceId, excerpt, authority = "raw_source", derivation = "teacher_compilation") {
76
+ return {
77
+ sourceKind,
78
+ sourceId,
79
+ excerpt,
80
+ authority,
81
+ derivation,
82
+ sourceHash: sha256Text(`${sourceId}\n${excerpt}`),
83
+ };
84
+ }
85
+ function makeEvidence(evidenceId, sourceRef, derivation = sourceRef.derivation ?? "teacher_compilation") {
86
+ return {
87
+ evidenceId,
88
+ sourceKind: sourceRef.sourceKind,
89
+ sourceId: sourceRef.sourceId,
90
+ authority: sourceRef.authority,
91
+ derivation,
92
+ excerpt: sourceRef.excerpt,
93
+ sourceHash: sourceRef.sourceHash ?? sha256Text(`${sourceRef.sourceId}\n${sourceRef.excerpt}`),
94
+ };
95
+ }
96
+ function makeClaim(claimId, text, confidence, evidenceIds, status = "supported") {
97
+ return {
98
+ claimId,
99
+ text,
100
+ confidence,
101
+ status,
102
+ evidenceIds,
103
+ };
104
+ }
105
+ function makeFrontmatter(lines) {
106
+ return `---\n${lines.join("\n")}\n---\n`;
107
+ }
108
+ function quoteList(values) {
109
+ return values.map((value) => `- ${value}`).join("\n");
110
+ }
111
+ function quoteSourceList(entries) {
112
+ return entries.map((entry) => `- \`${entry.evidenceId}\` — ${entry.sourceId}`).join("\n");
113
+ }
114
+ function quoteAnchorList(entries) {
115
+ return entries.map((entry) => `- \`${entry.id}\` (${entry.state}/${entry.kind}) — ${entry.source}`).join("\n");
116
+ }
117
+ function hashJoinedLines(lines) {
118
+ return sha256Text(lines.join("\n"));
119
+ }
120
+ function normalizeIsoTimestamp(value) {
121
+ if (value instanceof Date) {
122
+ return value.toISOString();
123
+ }
124
+ const normalized = normalizeText(value);
125
+ return normalized ?? new Date().toISOString();
126
+ }
127
+ function defaultGraphifyRunMetadata(input) {
128
+ const bundleStartedAt = normalizeIsoTimestamp(input.bundleStartedAt);
129
+ const bundleId = normalizeText(input.bundleId) ?? `graphify-compiled-artifacts-${timestampToken(bundleStartedAt)}`;
130
+ const bundleSlug = slugify(bundleId);
131
+ const graphifyRunId = normalizeText(input.graphifyRunId) ?? bundleId;
132
+ const graphifyVersion = normalizeText(input.graphifyVersion) ?? "graphify-bridge@wave1";
133
+ const graphifyCommand = normalizeText(input.graphifyCommand) ?? "graphify compile compiled-artifacts";
134
+ const sourceBundleId = normalizeText(input.sourceBundleId) ?? "compiled-artifacts-target-state-scaffold";
135
+ const sourceDocs = input.sourceDocs ?? [
136
+ "docs/architecture/compiled-artifacts.md",
137
+ "docs/architecture/teacher-v3.md",
138
+ "docs/architecture/teacher-v3-proposals.md",
139
+ "docs/architecture/teacher-v3-lints.md",
140
+ "docs/architecture/teacher-v3-proof.md",
141
+ ];
142
+ const sourceFixtures = input.sourceFixtures ?? [
143
+ "artifacts/fixtures/compiled-artifacts/target-state-scaffold/README.md",
144
+ "artifacts/fixtures/compiled-artifacts/target-state-scaffold/pack.manifest.json",
145
+ "artifacts/fixtures/compiled-artifacts/target-state-scaffold/artifacts/ca_example_concept_substrate_01/artifact.md",
146
+ "artifacts/fixtures/compiled-artifacts/target-state-scaffold/artifacts/ca_example_concept_substrate_01/artifact.meta.json",
147
+ "artifacts/fixtures/compiled-artifacts/target-state-scaffold/artifacts/ca_example_map_of_territory_01/artifact.md",
148
+ "artifacts/fixtures/compiled-artifacts/target-state-scaffold/artifacts/ca_example_map_of_territory_01/artifact.meta.json",
149
+ "artifacts/fixtures/compiled-artifacts/target-state-scaffold/artifacts/ca_example_provenance_gap_report_01/artifact.md",
150
+ "artifacts/fixtures/compiled-artifacts/target-state-scaffold/artifacts/ca_example_provenance_gap_report_01/artifact.meta.json",
151
+ ];
152
+ const sourceBundleHash = normalizeText(input.sourceBundleHash) ?? sha256Text(JSON.stringify({
153
+ bundleId,
154
+ graphifyRunId,
155
+ graphifyVersion,
156
+ graphifyCommand,
157
+ sourceBundleId,
158
+ sourceDocs,
159
+ sourceFixtures,
160
+ }));
161
+ const graphHash = normalizeText(input.graphHash) ?? sha256Text(JSON.stringify({
162
+ sourceBundleId,
163
+ sourceBundleHash,
164
+ graphifyRunId,
165
+ graphifyVersion,
166
+ }));
167
+ const configHash = normalizeText(input.configHash) ?? sha256Text(JSON.stringify({
168
+ graphifyVersion,
169
+ graphifyCommand,
170
+ sourceBundleId,
171
+ bundleId,
172
+ }));
173
+ const labelsHash = normalizeText(input.labelsHash) ?? sha256Text(JSON.stringify(GRAPHIFY_COMPILED_ARTIFACT_KIND_ORDER_V1));
174
+ return {
175
+ bundleStartedAt,
176
+ bundleId,
177
+ bundleSlug,
178
+ graphifyRunId,
179
+ graphifyVersion,
180
+ graphifyCommand,
181
+ sourceBundleId,
182
+ sourceBundleHash,
183
+ graphHash,
184
+ configHash,
185
+ labelsHash,
186
+ sourceDocs,
187
+ sourceFixtures,
188
+ };
189
+ }
190
+ function buildDefaultArtifactSpecs(metadata) {
191
+ const createdAt = metadata.bundleStartedAt;
192
+ const sharedSourceRoots = [
193
+ "docs/architecture",
194
+ "artifacts/fixtures/compiled-artifacts/target-state-scaffold",
195
+ ];
196
+ const mapOfTerritoryEvidence = [
197
+ makeEvidence(
198
+ "ev-graphify-surface-hierarchy",
199
+ makeSourceRef(
200
+ "file",
201
+ "docs/architecture/teacher-v3-proof.md#surface-hierarchy",
202
+ "Teacher v3 should read truth in runtime, proof, docs, then proposal order.",
203
+ ),
204
+ ),
205
+ makeEvidence(
206
+ "ev-compiled-artifacts-runtime-layout",
207
+ makeSourceRef(
208
+ "file",
209
+ "docs/architecture/compiled-artifacts.md#runtime-storage-layout",
210
+ "The authoritative runtime store should live under the activation root, not in the source repo.",
211
+ ),
212
+ ),
213
+ makeEvidence(
214
+ "ev-compiled-artifacts-scaffold-readme",
215
+ makeSourceRef(
216
+ "file",
217
+ "artifacts/fixtures/compiled-artifacts/target-state-scaffold/README.md",
218
+ "This directory is intentionally synthetic target-state scaffolding.",
219
+ ),
220
+ ),
221
+ ];
222
+ const conceptPageEvidence = [
223
+ makeEvidence(
224
+ "ev-compiled-artifacts-core-rules",
225
+ makeSourceRef(
226
+ "file",
227
+ "docs/architecture/compiled-artifacts.md#core-rules",
228
+ "compiled artifacts are derived, off-path knowledge products",
229
+ ),
230
+ ),
231
+ makeEvidence(
232
+ "ev-compiled-artifacts-sidecar-shape",
233
+ makeSourceRef(
234
+ "file",
235
+ "docs/architecture/compiled-artifacts.md#markdown--sidecar-shape",
236
+ "The sidecar JSON should be the authoritative metadata source.",
237
+ ),
238
+ ),
239
+ makeEvidence(
240
+ "ev-teacher-v3-off-path",
241
+ makeSourceRef(
242
+ "file",
243
+ "docs/architecture/teacher-v3.md#what-problem-teacher-v3-solves",
244
+ "Teacher v3 is an off-path compiler of graph structure and compiled artifacts, not an arbiter of current truth.",
245
+ ),
246
+ ),
247
+ ];
248
+ const neighborhoodSummaryEvidence = [
249
+ makeEvidence(
250
+ "ev-teacher-v3-layers",
251
+ makeSourceRef(
252
+ "file",
253
+ "docs/architecture/teacher-v3.md#layers",
254
+ "Compiled artifact layer, candidate graph layer, promoted pack layer.",
255
+ ),
256
+ ),
257
+ makeEvidence(
258
+ "ev-teacher-v3-proof-surface-hierarchy",
259
+ makeSourceRef(
260
+ "file",
261
+ "docs/architecture/teacher-v3-proof.md#surface-hierarchy",
262
+ "Teacher v3 should read truth in runtime, proof, docs, then proposal order.",
263
+ ),
264
+ ),
265
+ makeEvidence(
266
+ "ev-compiled-artifacts-scaffold-manifest",
267
+ makeSourceRef(
268
+ "file",
269
+ "artifacts/fixtures/compiled-artifacts/target-state-scaffold/pack.manifest.json",
270
+ "Sidecar hashes must be regenerated whenever the markdown bodies change.",
271
+ ),
272
+ ),
273
+ ];
274
+ const provenanceGapEvidence = [
275
+ makeEvidence(
276
+ "ev-compiled-artifacts-provenance",
277
+ makeSourceRef(
278
+ "file",
279
+ "docs/architecture/compiled-artifacts.md#provenance-fields",
280
+ "The provenance block should explain where the artifact came from and how it was produced.",
281
+ ),
282
+ ),
283
+ makeEvidence(
284
+ "ev-teacher-v3-lints-ci-first",
285
+ makeSourceRef(
286
+ "file",
287
+ "docs/architecture/teacher-v3-lints.md#1-ci-first-deterministic-lint-family",
288
+ "Deterministic checks run first; teacher-assisted audits run second.",
289
+ ),
290
+ ),
291
+ makeEvidence(
292
+ "ev-teacher-v3-lints-release-drift",
293
+ makeSourceRef(
294
+ "file",
295
+ "docs/architecture/teacher-v3-lints.md#3-release-drift-motivating-case",
296
+ "Objective mismatches should be caught before semantic audits run.",
297
+ ),
298
+ ),
299
+ ];
300
+ return [
301
+ {
302
+ artifactId: "ca_graphify_map_of_territory_01",
303
+ kind: "map_of_territory",
304
+ title: "Graphify territory map",
305
+ summary: "Shows the split between runtime/proof/docs truth and the Graphify-derived compiled-artifact bridge, with the target-state pack kept off the serve path.",
306
+ subjectIds: ["topic:graphify", "topic:compiled-artifacts", "topic:teacher-v3"],
307
+ confidence: 0.96,
308
+ evidence: mapOfTerritoryEvidence,
309
+ counterevidence: [
310
+ makeEvidence(
311
+ "cevi-graphify-target-only",
312
+ makeSourceRef(
313
+ "file",
314
+ "docs/architecture/teacher-v3-proof.md#target-state-surfaces",
315
+ "Teacher v3 reporting may summarize and cross-reference truth, but it must not become a new source of truth for the live runtime.",
316
+ "raw_source",
317
+ "teacher_lint",
318
+ ),
319
+ "teacher_lint",
320
+ ),
321
+ ],
322
+ openQuestions: [
323
+ "Should the next bridge lane generate a source bundle hash or only the compiled artifact pack?",
324
+ "Which later surface should consume this pack first: import slice, lint diff, or replay packet?",
325
+ ],
326
+ promotionNotes: [
327
+ "Keep the bridge off the serve path.",
328
+ "Treat the scaffold and docs as source evidence, not as live authority.",
329
+ ],
330
+ claims: [
331
+ makeClaim(
332
+ "claim-graphify-territory-subordinate",
333
+ "Graphify-derived compiled artifacts stay subordinate to runtime, proof, and docs truth layers.",
334
+ 0.98,
335
+ ["ev-graphify-surface-hierarchy", "ev-compiled-artifacts-runtime-layout"],
336
+ ),
337
+ makeClaim(
338
+ "claim-graphify-target-state-scaffold",
339
+ "The bridge output is target-state scaffolding and should not be treated as live truth.",
340
+ 0.96,
341
+ ["ev-compiled-artifacts-scaffold-readme", "ev-graphify-surface-hierarchy"],
342
+ ),
343
+ ],
344
+ replaySuites: ["graphify-territory-map-smoke", "proof-surface-order-smoke"],
345
+ rollbackKey: "rollback:graphify-compiled-artifacts:map-of-territory",
346
+ sourceRoots: sharedSourceRoots,
347
+ },
348
+ {
349
+ artifactId: "ca_graphify_concept_page_01",
350
+ kind: "concept_page",
351
+ title: "Compiled artifact substrate concept page",
352
+ summary: "Explains the markdown body plus authoritative sidecar pair, the provenance block contract, and why the bridge remains off-path.",
353
+ subjectIds: ["topic:compiled-artifacts", "topic:graphify", "topic:provenance"],
354
+ confidence: 0.95,
355
+ evidence: conceptPageEvidence,
356
+ counterevidence: [
357
+ makeEvidence(
358
+ "cevi-concept-live-boundary",
359
+ makeSourceRef(
360
+ "file",
361
+ "docs/architecture/teacher-v3.md#what-problem-teacher-v3-solves",
362
+ "Teacher v3 is an off-path compiler of graph structure and compiled artifacts, not an arbiter of current truth.",
363
+ "raw_source",
364
+ "teacher_lint",
365
+ ),
366
+ "teacher_lint",
367
+ ),
368
+ ],
369
+ openQuestions: [
370
+ "Should future content-hash verification include normalized frontmatter or just the markdown body?",
371
+ "Which later lane should own stale-hash detection after the pack is generated?",
372
+ ],
373
+ promotionNotes: [
374
+ "The sidecar JSON should be the authoritative metadata source.",
375
+ "Use the sidecar as the machine-readable source of truth.",
376
+ "Recompute content hashes whenever the markdown body changes.",
377
+ ],
378
+ claims: [
379
+ makeClaim(
380
+ "claim-concept-body-plus-sidecar",
381
+ "A compiled artifact should be represented as a markdown body plus a canonical sidecar metadata record.",
382
+ 0.99,
383
+ ["ev-compiled-artifacts-core-rules", "ev-compiled-artifacts-sidecar-shape"],
384
+ ),
385
+ makeClaim(
386
+ "claim-concept-provenance-explains-production",
387
+ "The provenance block must explain where the artifact came from and how it was produced.",
388
+ 0.97,
389
+ ["ev-compiled-artifacts-provenance", "ev-compiled-artifacts-sidecar-shape"],
390
+ ),
391
+ ],
392
+ replaySuites: ["compiled-artifact-pair-shape-smoke", "sidecar-authority-smoke"],
393
+ rollbackKey: "rollback:graphify-compiled-artifacts:concept-page",
394
+ sourceRoots: sharedSourceRoots,
395
+ },
396
+ {
397
+ artifactId: "ca_graphify_neighborhood_summary_01",
398
+ kind: "neighborhood_summary",
399
+ title: "Graphify neighborhood summary",
400
+ summary: "Summarizes the source neighborhoods feeding the bridge: architecture docs, scaffold fixtures, and the target-state compiled-artifact pack surface.",
401
+ subjectIds: ["topic:graphify", "topic:source-neighborhoods", "topic:compiled-artifacts"],
402
+ confidence: 0.92,
403
+ evidence: neighborhoodSummaryEvidence,
404
+ counterevidence: [
405
+ makeEvidence(
406
+ "cevi-neighborhood-not-authority",
407
+ makeSourceRef(
408
+ "file",
409
+ "docs/architecture/teacher-v3-proof.md#target-state-surfaces",
410
+ "Teacher v3 reporting may summarize and cross-reference truth, but it must not become a new source of truth for the live runtime.",
411
+ "raw_source",
412
+ "teacher_lint",
413
+ ),
414
+ "teacher_lint",
415
+ ),
416
+ ],
417
+ openQuestions: [
418
+ "Should future neighborhood summaries group by truth layer or by source topic?",
419
+ "Which repository surface should own source-neighborhood promotion review?",
420
+ ],
421
+ promotionNotes: [
422
+ "Keep the source neighborhoods explicit and bounded.",
423
+ "Make shipped-versus-target labels visible in downstream review surfaces.",
424
+ ],
425
+ claims: [
426
+ makeClaim(
427
+ "claim-neighborhood-bounded",
428
+ "Neighborhood summaries should stay bounded and inspectable while preserving evidence refs.",
429
+ 0.94,
430
+ ["ev-teacher-v3-layers", "ev-compiled-artifacts-scaffold-manifest"],
431
+ ),
432
+ makeClaim(
433
+ "claim-neighborhood-ordered",
434
+ "Source neighborhoods must remain ordered under runtime, proof, docs, then proposal truth precedence.",
435
+ 0.95,
436
+ ["ev-teacher-v3-proof-surface-hierarchy", "ev-teacher-v3-layers"],
437
+ ),
438
+ ],
439
+ replaySuites: ["graphify-neighborhood-summary-smoke", "bounded-review-surface-smoke"],
440
+ rollbackKey: "rollback:graphify-compiled-artifacts:neighborhood-summary",
441
+ sourceRoots: sharedSourceRoots,
442
+ },
443
+ {
444
+ artifactId: "ca_graphify_provenance_gap_report_01",
445
+ kind: "provenance_gap_report",
446
+ title: "Graphify provenance gap report",
447
+ summary: "Lists the follow-on implementation gaps that still need hash verification, replay wiring, and import-slice work before any promotion or import claim.",
448
+ subjectIds: ["topic:graphify", "topic:provenance", "topic:teacher-v3-lints"],
449
+ confidence: 0.90,
450
+ evidence: provenanceGapEvidence,
451
+ counterevidence: [
452
+ makeEvidence(
453
+ "cevi-provenance-shadow-only",
454
+ makeSourceRef(
455
+ "file",
456
+ "docs/architecture/teacher-v3-proof.md#target-state-surfaces",
457
+ "The target-state proof bundle is an overlay on top of the first three surfaces, not a replacement for them.",
458
+ "raw_source",
459
+ "teacher_lint",
460
+ ),
461
+ "teacher_lint",
462
+ ),
463
+ ],
464
+ openQuestions: [
465
+ "Should hash verification live in the bridge writer or a separate validator?",
466
+ "Which later lane should consume the replay suites carried on this proposal envelope?",
467
+ ],
468
+ promotionNotes: [
469
+ "Use this report only for shadow review.",
470
+ "Do not treat missing launch lanes as successful live adoption.",
471
+ ],
472
+ claims: [
473
+ makeClaim(
474
+ "claim-gap-needs-hash-verification",
475
+ "The bridge still needs deterministic hash verification and replayable manifest wiring before it should be treated as promotable.",
476
+ 0.98,
477
+ ["ev-compiled-artifacts-provenance", "ev-teacher-v3-lints-ci-first"],
478
+ ),
479
+ makeClaim(
480
+ "claim-gap-shadow-only",
481
+ "This report is a shadow-review surface and not live truth.",
482
+ 0.97,
483
+ ["ev-teacher-v3-lints-ci-first", "cevi-provenance-shadow-only"],
484
+ ),
485
+ ],
486
+ replaySuites: ["provenance-gap-smoke", "lint-boundary-smoke"],
487
+ rollbackKey: "rollback:graphify-compiled-artifacts:provenance-gap-report",
488
+ sourceRoots: sharedSourceRoots,
489
+ },
490
+ ].map((spec) => ({
491
+ ...spec,
492
+ createdAt,
493
+ updatedAt: createdAt,
494
+ proposalLane: "compiler",
495
+ status: "proposed",
496
+ packId: null,
497
+ proposalId: null,
498
+ }));
499
+ }
500
+ function buildArtifactMarkdown(spec, context) {
501
+ const frontmatter = makeFrontmatter([
502
+ `artifact_id: ${spec.artifactId}`,
503
+ `kind: ${spec.kind}`,
504
+ `status: proposed`,
505
+ `title: ${spec.title}`,
506
+ `proposal_id: ${context.proposalId}`,
507
+ `proposal_lane: compiler`,
508
+ `pack_id: ${context.packId}`,
509
+ `graphify_run_id: ${context.graphifyRunId}`,
510
+ `graphify_run_hash: ${context.graphifyRun.graphHash}`,
511
+ `source_bundle_id: ${context.graphifyRun.sourceBundleId}`,
512
+ `source_bundle_hash: ${context.graphifyRun.sourceBundleHash}`,
513
+ `subject_ids:`,
514
+ ...spec.subjectIds.map((subjectId) => ` - ${subjectId}`),
515
+ `confidence: ${spec.confidence}`,
516
+ `created_at: ${spec.createdAt}`,
517
+ `updated_at: ${spec.updatedAt}`,
518
+ ]);
519
+ const evidenceLines = quoteSourceList(spec.evidence);
520
+ const counterevidenceLines = spec.counterevidence.length > 0 ? quoteSourceList(spec.counterevidence) : "- none";
521
+ const claimLines = spec.claims.map((claim) => `- \`${claim.claimId}\` (${claim.status}, ${claim.confidence.toFixed(2)}) — ${claim.text}`).join("\n");
522
+ const summaryText = spec.summary;
523
+ return [
524
+ frontmatter,
525
+ "## Summary",
526
+ "",
527
+ summaryText,
528
+ "",
529
+ "## Stronger-truth anchors",
530
+ "",
531
+ "- runtime truth: not used",
532
+ "- proof truth: not used",
533
+ "- docs truth: see evidence refs below",
534
+ "- fixture truth: see evidence refs below",
535
+ "",
536
+ "## Evidence",
537
+ evidenceLines,
538
+ "",
539
+ "## Counterevidence / boundary",
540
+ counterevidenceLines,
541
+ "",
542
+ "## Claims",
543
+ claimLines,
544
+ "",
545
+ "## Open questions",
546
+ quoteList(spec.openQuestions),
547
+ "",
548
+ "## Promotion notes",
549
+ quoteList(spec.promotionNotes),
550
+ "",
551
+ ].join("\n");
552
+ }
553
+ function buildArtifactMeta(spec, context, contentHash) {
554
+ return {
555
+ schemaVersion: 1,
556
+ artifactId: spec.artifactId,
557
+ kind: spec.kind,
558
+ title: spec.title,
559
+ status: "proposed",
560
+ packId: context.packId,
561
+ proposalId: context.proposalId,
562
+ proposalLane: "compiler",
563
+ subjectIds: [...spec.subjectIds],
564
+ evidence: spec.evidence,
565
+ counterevidence: spec.counterevidence,
566
+ provenance: {
567
+ producer: "graphify",
568
+ producerVersion: context.graphifyRun.graphifyVersion,
569
+ promptHash: sha256Text(JSON.stringify({
570
+ artifactId: spec.artifactId,
571
+ bundleId: context.bundleId,
572
+ graphifyRunId: context.graphifyRunId,
573
+ graphHash: context.graphifyRun.graphHash,
574
+ sourceBundleHash: context.graphifyRun.sourceBundleHash,
575
+ })),
576
+ scope: "graphify/compiled-artifacts",
577
+ idempotencyKey: sha256Text(JSON.stringify({
578
+ packId: context.packId,
579
+ proposalId: context.proposalId,
580
+ artifactId: spec.artifactId,
581
+ graphHash: context.graphifyRun.graphHash,
582
+ })),
583
+ sourceRoots: [...spec.sourceRoots],
584
+ transformChain: ["extract", "cluster", "synthesize", "validate"],
585
+ sourceBundleId: context.graphifyRun.sourceBundleId,
586
+ sourceBundleHash: context.graphifyRun.sourceBundleHash,
587
+ graphHash: context.graphifyRun.graphHash,
588
+ graphifyRunId: context.graphifyRunId,
589
+ },
590
+ contentHash,
591
+ markdownPath: context.bundlePaths.artifacts[spec.artifactId].markdown,
592
+ metaPath: context.bundlePaths.artifacts[spec.artifactId].meta,
593
+ createdAt: spec.createdAt,
594
+ updatedAt: spec.updatedAt,
595
+ confidence: spec.confidence,
596
+ claims: spec.claims,
597
+ promotion: {
598
+ replaySuites: [...spec.replaySuites],
599
+ rollbackKey: spec.rollbackKey,
600
+ },
601
+ };
602
+ }
603
+ function buildDefaultGraphifyCompiledArtifactPack(input = {}) {
604
+ const graphifyRun = defaultGraphifyRunMetadata(input);
605
+ const bundleId = graphifyRun.bundleId;
606
+ const bundleSlug = graphifyRun.bundleSlug;
607
+ const proposalId = normalizeText(input.proposalId) ?? `prop_graphify_compiled_artifacts_${bundleSlug}`;
608
+ const packId = normalizeText(input.packId) ?? `pack_graphify_compiled_artifacts_${bundleSlug}`;
609
+ const outputDir = path.resolve(input.outputDir ?? resolveGraphifyCompiledArtifactPackOutputDir({ bundleId, bundleStartedAt: graphifyRun.bundleStartedAt }));
610
+ const graphifyRunId = graphifyRun.graphifyRunId;
611
+ const createdAt = graphifyRun.bundleStartedAt;
612
+ const bundleRoot = outputDir;
613
+ const paths = {
614
+ manifest: path.join(bundleRoot, GRAPHIFY_COMPILED_ARTIFACT_PACK_LAYOUT_V1.manifest),
615
+ compilerProposal: path.join(bundleRoot, GRAPHIFY_COMPILED_ARTIFACT_PACK_LAYOUT_V1.compilerProposal),
616
+ surfaceMap: path.join(bundleRoot, GRAPHIFY_COMPILED_ARTIFACT_PACK_LAYOUT_V1.surfaceMap),
617
+ proposalReport: path.join(bundleRoot, GRAPHIFY_COMPILED_ARTIFACT_PACK_LAYOUT_V1.proposalReport),
618
+ verdict: path.join(bundleRoot, GRAPHIFY_COMPILED_ARTIFACT_PACK_LAYOUT_V1.verdict),
619
+ artifactKinds: {},
620
+ artifacts: {},
621
+ };
622
+ const artifactSpecs = (input.artifactSpecs ?? buildDefaultArtifactSpecs(graphifyRun)).map((spec) => ({
623
+ ...spec,
624
+ proposalId,
625
+ packId,
626
+ }));
627
+ for (const spec of artifactSpecs) {
628
+ const artifactPaths = {
629
+ markdown: path.join(bundleRoot, GRAPHIFY_COMPILED_ARTIFACT_PACK_LAYOUT_V1.artifactsDir, spec.artifactId, "artifact.md"),
630
+ meta: path.join(bundleRoot, GRAPHIFY_COMPILED_ARTIFACT_PACK_LAYOUT_V1.artifactsDir, spec.artifactId, "artifact.meta.json"),
631
+ };
632
+ paths.artifactKinds[spec.artifactId] = artifactPaths;
633
+ paths.artifacts[spec.artifactId] = artifactPaths;
634
+ }
635
+ const bundlePaths = {
636
+ manifest: relativeBundlePath(paths.manifest, bundleRoot),
637
+ compilerProposal: relativeBundlePath(paths.compilerProposal, bundleRoot),
638
+ surfaceMap: relativeBundlePath(paths.surfaceMap, bundleRoot),
639
+ proposalReport: relativeBundlePath(paths.proposalReport, bundleRoot),
640
+ verdict: relativeBundlePath(paths.verdict, bundleRoot),
641
+ artifacts: Object.fromEntries(Object.entries(paths.artifacts).map(([artifactId, artifactPaths]) => [artifactId, {
642
+ markdown: relativeBundlePath(artifactPaths.markdown, bundleRoot),
643
+ meta: relativeBundlePath(artifactPaths.meta, bundleRoot),
644
+ }])),
645
+ };
646
+ const artifactEntries = artifactSpecs.map((spec) => {
647
+ const markdown = buildArtifactMarkdown(spec, {
648
+ bundleId,
649
+ packId,
650
+ proposalId,
651
+ graphifyRunId,
652
+ graphifyRun,
653
+ paths,
654
+ bundlePaths,
655
+ });
656
+ const contentHash = sha256Text(markdown);
657
+ const meta = buildArtifactMeta(spec, {
658
+ bundleId,
659
+ packId,
660
+ proposalId,
661
+ graphifyRunId,
662
+ graphifyRun,
663
+ paths,
664
+ bundlePaths,
665
+ }, contentHash);
666
+ return {
667
+ artifactId: spec.artifactId,
668
+ kind: spec.kind,
669
+ title: spec.title,
670
+ summary: spec.summary,
671
+ markdown,
672
+ meta,
673
+ contentHash,
674
+ markdownPath: meta.markdownPath,
675
+ metaPath: meta.metaPath,
676
+ };
677
+ });
678
+ const artifactSummaries = artifactEntries.map((entry) => ({
679
+ artifactId: entry.artifactId,
680
+ kind: entry.kind,
681
+ title: entry.title,
682
+ markdownPath: entry.markdownPath,
683
+ metaPath: entry.metaPath,
684
+ contentHash: entry.contentHash,
685
+ summary: entry.summary,
686
+ }));
687
+ const packManifest = {
688
+ contract: "graphify_compiled_artifact_pack.v1",
689
+ packId,
690
+ title: "Graphify compiled artifact pack (bridge scaffold)",
691
+ status: "proposed",
692
+ proposalId,
693
+ lane: "compiler",
694
+ scope: "graphify/compiled-artifacts",
695
+ createdAt: graphifyRun.bundleStartedAt,
696
+ updatedAt: graphifyRun.bundleStartedAt,
697
+ graphifyRun: {
698
+ runId: graphifyRunId,
699
+ graphifyVersion: graphifyRun.graphifyVersion,
700
+ graphifyCommand: graphifyRun.graphifyCommand,
701
+ sourceBundleId: graphifyRun.sourceBundleId,
702
+ sourceBundleHash: graphifyRun.sourceBundleHash,
703
+ graphHash: graphifyRun.graphHash,
704
+ configHash: graphifyRun.configHash,
705
+ labelsHash: graphifyRun.labelsHash,
706
+ },
707
+ sourceDocs: [...graphifyRun.sourceDocs],
708
+ sourceFixtures: [...graphifyRun.sourceFixtures],
709
+ sourceRoots: ["docs/architecture", "artifacts/fixtures/compiled-artifacts/target-state-scaffold"],
710
+ artifacts: artifactSummaries,
711
+ notes: [
712
+ "Graphify outputs are derived and do not supersede runtime, proof, or docs truth.",
713
+ "The sidecar remains authoritative for each compiled artifact record.",
714
+ "Sidecar hashes should be regenerated whenever the markdown body changes.",
715
+ ],
716
+ };
717
+ const sourceTruthAnchors = [
718
+ {
719
+ id: "compiled-artifacts-core-rules",
720
+ state: "shipped",
721
+ kind: "docs_truth",
722
+ source: "docs/architecture/compiled-artifacts.md#core-rules",
723
+ note: "compiled artifacts are derived, off-path knowledge products",
724
+ },
725
+ {
726
+ id: "compiled-artifacts-provenance-fields",
727
+ state: "shipped",
728
+ kind: "docs_truth",
729
+ source: "docs/architecture/compiled-artifacts.md#provenance-fields",
730
+ note: "The provenance block should explain where the artifact came from and how it was produced.",
731
+ },
732
+ {
733
+ id: "teacher-v3-layers",
734
+ state: "shipped",
735
+ kind: "docs_truth",
736
+ source: "docs/architecture/teacher-v3.md#layers",
737
+ note: "Compiled artifact layer, candidate graph layer, promoted pack layer.",
738
+ },
739
+ {
740
+ id: "teacher-v3-proof-surface-hierarchy",
741
+ state: "shipped",
742
+ kind: "docs_truth",
743
+ source: "docs/architecture/teacher-v3-proof.md#surface-hierarchy",
744
+ note: "Teacher v3 should read truth in runtime, proof, docs, then proposal order.",
745
+ },
746
+ {
747
+ id: "compiled-artifacts-scaffold",
748
+ state: "shipped",
749
+ kind: "fixture_truth",
750
+ source: "artifacts/fixtures/compiled-artifacts/target-state-scaffold/pack.manifest.json",
751
+ note: "This directory is intentionally synthetic target-state scaffolding.",
752
+ },
753
+ ];
754
+ const compilerProposalEvidence = [
755
+ makeEvidence(
756
+ "ev-graphify-surface-hierarchy",
757
+ makeSourceRef(
758
+ "file",
759
+ "docs/architecture/teacher-v3-proof.md#surface-hierarchy",
760
+ "Teacher v3 should read truth in runtime, proof, docs, then proposal order.",
761
+ ),
762
+ ),
763
+ makeEvidence(
764
+ "ev-compiled-artifacts-core-rules",
765
+ makeSourceRef(
766
+ "file",
767
+ "docs/architecture/compiled-artifacts.md#core-rules",
768
+ "compiled artifacts are derived, off-path knowledge products",
769
+ ),
770
+ ),
771
+ makeEvidence(
772
+ "ev-compiled-artifacts-provenance",
773
+ makeSourceRef(
774
+ "file",
775
+ "docs/architecture/compiled-artifacts.md#provenance-fields",
776
+ "The provenance block should explain where the artifact came from and how it was produced.",
777
+ ),
778
+ ),
779
+ makeEvidence(
780
+ "ev-compiled-artifacts-scaffold-readme",
781
+ makeSourceRef(
782
+ "file",
783
+ "artifacts/fixtures/compiled-artifacts/target-state-scaffold/README.md",
784
+ "This directory is intentionally synthetic target-state scaffolding.",
785
+ ),
786
+ ),
787
+ ];
788
+ const compilerProposalCounterevidence = [
789
+ makeEvidence(
790
+ "cevi-graphify-target-state-only",
791
+ makeSourceRef(
792
+ "file",
793
+ "docs/architecture/teacher-v3-proof.md#target-state-surfaces",
794
+ "The target-state proof bundle is an overlay on top of the first three surfaces, not a replacement for them.",
795
+ "raw_source",
796
+ "teacher_lint",
797
+ ),
798
+ "teacher_lint",
799
+ ),
800
+ ];
801
+ const compilerProposal = {
802
+ contract: "graphify_compiled_artifact_pack_compiler_proposal.v1",
803
+ proposalId,
804
+ proposalClass: "compiler",
805
+ lane: "compiler",
806
+ status: "validated",
807
+ reviewMode: "promotable",
808
+ lineage: {
809
+ proposalClass: "compiler",
810
+ producerVersion: graphifyRun.graphifyVersion,
811
+ producerBuildId: graphifyRunId,
812
+ promptHash: sha256Text(JSON.stringify({
813
+ bundleId,
814
+ proposalId,
815
+ packId,
816
+ graphifyRunId,
817
+ graphHash: graphifyRun.graphHash,
818
+ sourceBundleHash: graphifyRun.sourceBundleHash,
819
+ })),
820
+ templateId: "graphify-compiled-artifacts/compiler-v1",
821
+ scope: "graphify/compiled-artifacts",
822
+ profile: "bridge-scaffold",
823
+ idempotencyKey: sha256Text(JSON.stringify({
824
+ bundleId,
825
+ proposalId,
826
+ packId,
827
+ graphifyRunId,
828
+ graphHash: graphifyRun.graphHash,
829
+ })),
830
+ sourceBundleId: graphifyRun.sourceBundleId,
831
+ parentProposalIds: [],
832
+ },
833
+ subjectIds: ["topic:graphify", "topic:compiled-artifacts", "topic:teacher-v3", "topic:provenance"],
834
+ evidence: compilerProposalEvidence,
835
+ counterevidence: compilerProposalCounterevidence,
836
+ payload: {
837
+ kind: "graphify-compiled-artifact-pack",
838
+ summary: "Graphify-derived compiled-artifact pack with explicit evidence refs, provenance, and stronger-truth anchoring.",
839
+ packId,
840
+ outputRoot: "compiled-artifacts",
841
+ artifactKinds: [...GRAPHIFY_COMPILED_ARTIFACT_KIND_ORDER_V1],
842
+ sourceBundleId: graphifyRun.sourceBundleId,
843
+ sourceBundleHash: graphifyRun.sourceBundleHash,
844
+ graphHash: graphifyRun.graphHash,
845
+ graphifyRunId,
846
+ sourceDocs: [...graphifyRun.sourceDocs],
847
+ sourceFixtures: [...graphifyRun.sourceFixtures],
848
+ },
849
+ expectedEffect: {
850
+ retrieval: "better",
851
+ truthRisk: "low",
852
+ reviewBurden: "bounded",
853
+ },
854
+ confidence: 0.95,
855
+ replaySuites: ["graphify-pack-shape-smoke", "compiled-artifacts-provenance-smoke"],
856
+ rollbackKey: `rollback:graphify-compiled-artifacts:${packId}`,
857
+ replayGate: {
858
+ proposalClass: "compiler",
859
+ reviewMode: "promotable",
860
+ dimensions: {
861
+ truthInvariants: {
862
+ name: "truth_invariants",
863
+ summary: "Graphify bridge: keep derived output subordinate to explicit authority.",
864
+ requirements: [
865
+ "Explicit correction memory still outranks Graphify synthesis.",
866
+ "The live path stays read-only to the proposal.",
867
+ "Evidence refs stay attached to any non-trivial claim.",
868
+ ],
869
+ },
870
+ attributionFloor: {
871
+ name: "attribution_floor",
872
+ summary: "Graphify bridge: every proposed change needs clear evidence coverage.",
873
+ requirements: [
874
+ "Every proposal carries durable evidence refs.",
875
+ "Source ids must be stable record ids, not display labels.",
876
+ "Unattributed payload stays out of promotion.",
877
+ ],
878
+ },
879
+ boundedness: {
880
+ name: "boundedness",
881
+ summary: "Graphify bridge: keep the reviewable surface compact and inspectable.",
882
+ requirements: [
883
+ "Proposal subject sets stay finite and small.",
884
+ "Payloads avoid raw corpus dumps and unbounded excerpts.",
885
+ "Replay fits inside a single review pass.",
886
+ ],
887
+ },
888
+ reversibility: {
889
+ name: "reversibility",
890
+ summary: "Graphify bridge: preserve rollback and replay identity.",
891
+ requirements: [
892
+ "RollbackKey identifies the reversible path.",
893
+ "Prior state remains recoverable for replay.",
894
+ "Rejected or superseded proposals keep lineage.",
895
+ ],
896
+ },
897
+ },
898
+ },
899
+ strongerTruthAnchors: sourceTruthAnchors,
900
+ createdAt,
901
+ updatedAt: createdAt,
902
+ targetStateOnly: true,
903
+ };
904
+ const controlSurfaces = [
905
+ {
906
+ id: "pack-manifest",
907
+ state: "target",
908
+ kind: "proposal_truth",
909
+ source: bundlePaths.manifest,
910
+ note: "compiled-artifact pack manifest",
911
+ },
912
+ {
913
+ id: "compiler-proposal",
914
+ state: "target",
915
+ kind: "proposal_truth",
916
+ source: bundlePaths.compilerProposal,
917
+ note: "proposal envelope with evidence, rollback key, and replay gate",
918
+ },
919
+ {
920
+ id: "surface-map",
921
+ state: "target",
922
+ kind: "proposal_truth",
923
+ source: bundlePaths.surfaceMap,
924
+ note: "shipped-vs-target inventory",
925
+ },
926
+ {
927
+ id: "proposal-report",
928
+ state: "target",
929
+ kind: "proposal_truth",
930
+ source: bundlePaths.proposalReport,
931
+ note: "bounded machine-readable report",
932
+ },
933
+ {
934
+ id: "verdict",
935
+ state: "target",
936
+ kind: "proposal_truth",
937
+ source: bundlePaths.verdict,
938
+ note: "review verdict",
939
+ },
940
+ ...artifactEntries.map((entry) => ({
941
+ id: entry.artifactId,
942
+ state: "target",
943
+ kind: entry.kind,
944
+ source: entry.markdownPath,
945
+ note: "markdown + sidecar pair",
946
+ })),
947
+ ];
948
+ const surfaceMap = {
949
+ contract: "graphify_compiled_artifact_pack_surface_map.v1",
950
+ bundleId,
951
+ packId,
952
+ proposalId,
953
+ sourceTruthAnchors,
954
+ controlSurfaces,
955
+ counts: {
956
+ shippedSurfaceCount: sourceTruthAnchors.length,
957
+ targetSurfaceCount: controlSurfaces.length,
958
+ totalSurfaceCount: sourceTruthAnchors.length + controlSurfaces.length,
959
+ },
960
+ };
961
+ const validation = validateGraphifyCompiledArtifactPackBundle({
962
+ packManifest,
963
+ compilerProposal,
964
+ artifactEntries,
965
+ bundlePaths,
966
+ paths,
967
+ });
968
+ const proposalReport = {
969
+ contract: "graphify_compiled_artifact_pack_proposal_report.v1",
970
+ bundleId,
971
+ packId,
972
+ proposalId,
973
+ proposalClass: compilerProposal.proposalClass,
974
+ lane: compilerProposal.lane,
975
+ status: compilerProposal.status,
976
+ reviewMode: compilerProposal.reviewMode,
977
+ surfaceCounts: surfaceMap.counts,
978
+ sourceTruthAnchors,
979
+ compilerProposalSummary: {
980
+ proposalId: compilerProposal.proposalId,
981
+ status: compilerProposal.status,
982
+ reviewMode: compilerProposal.reviewMode,
983
+ rollbackKey: compilerProposal.rollbackKey,
984
+ replaySuites: [...compilerProposal.replaySuites],
985
+ evidenceCount: compilerProposal.evidence.length,
986
+ counterevidenceCount: compilerProposal.counterevidence.length,
987
+ subjectCount: compilerProposal.subjectIds.length,
988
+ confidence: compilerProposal.confidence,
989
+ },
990
+ packManifest: {
991
+ path: bundlePaths.manifest,
992
+ artifactCount: packManifest.artifacts.length,
993
+ sourceBundleId: graphifyRun.sourceBundleId,
994
+ sourceBundleHash: graphifyRun.sourceBundleHash,
995
+ graphHash: graphifyRun.graphHash,
996
+ },
997
+ graphifyRun,
998
+ validation: {
999
+ ok: validation.ok,
1000
+ errors: [...validation.errors],
1001
+ bundleHash: validation.bundleHash,
1002
+ fileCount: validation.fileCount,
1003
+ artifactCount: validation.artifactCount,
1004
+ },
1005
+ publicationSafeArtifacts: controlSurfaces.map((surface) => ({
1006
+ artifactId: surface.id,
1007
+ kind: surface.kind,
1008
+ path: surface.source,
1009
+ redactions: surface.state === "target" ? ["raw source payloads", "secret-bearing values"] : ["raw source payloads"],
1010
+ containsRawLogs: false,
1011
+ })),
1012
+ recommendations: validation.ok
1013
+ ? [
1014
+ "Keep Graphify-derived surfaces off the serve path.",
1015
+ "Use the compiled-artifact pack as an inspection and diff surface first.",
1016
+ "Treat the scaffold and architecture docs as stronger truth than the proposal envelope.",
1017
+ ]
1018
+ : [
1019
+ "Repair the validation errors before considering any promotion or import claim.",
1020
+ "Keep the bridge target-state only until hash and provenance checks pass.",
1021
+ ],
1022
+ createdAt: graphifyRun.bundleStartedAt,
1023
+ updatedAt: graphifyRun.bundleStartedAt,
1024
+ };
1025
+ const verdict = {
1026
+ contract: "graphify_compiled_artifact_pack_verdict.v1",
1027
+ bundleId,
1028
+ packId,
1029
+ proposalId,
1030
+ verdict: validation.ok ? "reviewable" : "rejected",
1031
+ severity: validation.ok ? "info" : "blocking",
1032
+ why: validation.ok
1033
+ ? "Graphify compiled-artifact pack is bounded, hash-consistent, and anchored below runtime/proof/docs truth; it remains target-state only and does not supersede live authority."
1034
+ : `Graphify compiled-artifact pack failed validation: ${validation.errors.join("; ")}`,
1035
+ reviewMode: compilerProposal.reviewMode,
1036
+ targetStateOnly: true,
1037
+ surfaceCounts: surfaceMap.counts,
1038
+ strongerTruthAnchors: sourceTruthAnchors,
1039
+ validation: {
1040
+ ok: validation.ok,
1041
+ errors: [...validation.errors],
1042
+ bundleHash: validation.bundleHash,
1043
+ },
1044
+ recommendations: [...proposalReport.recommendations],
1045
+ createdAt: graphifyRun.bundleStartedAt,
1046
+ updatedAt: graphifyRun.bundleStartedAt,
1047
+ };
1048
+ const files = {
1049
+ [GRAPHIFY_COMPILED_ARTIFACT_PACK_LAYOUT_V1.manifest]: renderJson(packManifest),
1050
+ [GRAPHIFY_COMPILED_ARTIFACT_PACK_LAYOUT_V1.compilerProposal]: renderJson(compilerProposal),
1051
+ [GRAPHIFY_COMPILED_ARTIFACT_PACK_LAYOUT_V1.surfaceMap]: renderJson(surfaceMap),
1052
+ [GRAPHIFY_COMPILED_ARTIFACT_PACK_LAYOUT_V1.proposalReport]: renderJson(proposalReport),
1053
+ [GRAPHIFY_COMPILED_ARTIFACT_PACK_LAYOUT_V1.verdict]: renderJson(verdict),
1054
+ };
1055
+ for (const entry of artifactEntries) {
1056
+ files[entry.meta.markdownPath] = entry.markdown;
1057
+ files[entry.meta.metaPath] = renderJson(entry.meta);
1058
+ }
1059
+ const digest = buildGraphifyCompiledArtifactPackDigest({
1060
+ bundleId,
1061
+ packId,
1062
+ proposalId,
1063
+ files,
1064
+ });
1065
+ return {
1066
+ bundleId,
1067
+ bundleSlug,
1068
+ bundleStartedAt: graphifyRun.bundleStartedAt,
1069
+ outputDir,
1070
+ packId,
1071
+ proposalId,
1072
+ graphifyRunId,
1073
+ graphifyRun,
1074
+ packManifest,
1075
+ compilerProposal,
1076
+ surfaceMap,
1077
+ proposalReport,
1078
+ verdict,
1079
+ artifactEntries,
1080
+ artifactSummaries,
1081
+ bundlePaths,
1082
+ paths: {
1083
+ manifest: relativeRepoPath(paths.manifest),
1084
+ compilerProposal: relativeRepoPath(paths.compilerProposal),
1085
+ surfaceMap: relativeRepoPath(paths.surfaceMap),
1086
+ proposalReport: relativeRepoPath(paths.proposalReport),
1087
+ verdict: relativeRepoPath(paths.verdict),
1088
+ artifacts: Object.fromEntries(Object.entries(paths.artifactKinds).map(([artifactId, pathsForArtifact]) => [artifactId, {
1089
+ markdown: relativeRepoPath(pathsForArtifact.markdown),
1090
+ meta: relativeRepoPath(pathsForArtifact.meta),
1091
+ }])),
1092
+ },
1093
+ validation,
1094
+ digest,
1095
+ files,
1096
+ };
1097
+ }
1098
+ function validateGraphifyCompiledArtifactPackBundle(bundle) {
1099
+ const errors = [];
1100
+ const artifacts = bundle.artifactEntries ?? [];
1101
+ const requiredKinds = [...GRAPHIFY_COMPILED_ARTIFACT_KIND_ORDER_V1];
1102
+ const seenKinds = artifacts.map((entry) => entry.kind);
1103
+ for (const requiredKind of requiredKinds) {
1104
+ if (!seenKinds.includes(requiredKind)) {
1105
+ errors.push(`missing required artifact kind: ${requiredKind}`);
1106
+ }
1107
+ }
1108
+ for (const entry of artifacts) {
1109
+ const markdownPath = bundle.bundlePaths?.artifacts?.[entry.artifactId]?.markdown ?? bundle.paths.artifacts[entry.artifactId]?.markdown;
1110
+ const metaPath = bundle.bundlePaths?.artifacts?.[entry.artifactId]?.meta ?? bundle.paths.artifacts[entry.artifactId]?.meta;
1111
+ if (!markdownPath || !metaPath) {
1112
+ errors.push(`missing artifact paths for ${entry.artifactId}`);
1113
+ continue;
1114
+ }
1115
+ if (entry.meta.markdownPath !== markdownPath) {
1116
+ errors.push(`markdown path mismatch for ${entry.artifactId}`);
1117
+ }
1118
+ if (entry.meta.metaPath !== metaPath) {
1119
+ errors.push(`meta path mismatch for ${entry.artifactId}`);
1120
+ }
1121
+ if (entry.meta.contentHash !== entry.contentHash) {
1122
+ errors.push(`content hash mismatch for ${entry.artifactId}`);
1123
+ }
1124
+ const manifestEntry = bundle.packManifest.artifacts.find((artifact) => artifact.artifactId === entry.artifactId);
1125
+ if (!manifestEntry) {
1126
+ errors.push(`manifest entry missing for ${entry.artifactId}`);
1127
+ continue;
1128
+ }
1129
+ if (manifestEntry.contentHash !== entry.contentHash) {
1130
+ errors.push(`manifest content hash mismatch for ${entry.artifactId}`);
1131
+ }
1132
+ }
1133
+ const digest = buildGraphifyCompiledArtifactPackDigest({
1134
+ bundleId: bundle.bundleId,
1135
+ packId: bundle.packId,
1136
+ proposalId: bundle.proposalId,
1137
+ files: bundle.files ?? {},
1138
+ });
1139
+ return {
1140
+ ok: errors.length === 0,
1141
+ errors,
1142
+ bundleHash: digest.bundleHash,
1143
+ fileCount: digest.fileCount,
1144
+ artifactCount: artifacts.length,
1145
+ };
1146
+ }
1147
+ export function resolveGraphifyCompiledArtifactPackOutputDir({ outputDir = null, bundleStartedAt = new Date(), bundleId = null, } = {}) {
1148
+ if (typeof outputDir === "string" && outputDir.trim().length > 0) {
1149
+ return path.resolve(outputDir);
1150
+ }
1151
+ const resolvedStartedAt = normalizeIsoTimestamp(bundleStartedAt);
1152
+ const resolvedBundleId = normalizeText(bundleId) ?? `graphify-compiled-artifacts-${timestampToken(resolvedStartedAt)}`;
1153
+ return path.join(DEFAULT_GRAPHIFY_COMPILED_ARTIFACT_PACK_PARENT, slugify(resolvedBundleId), "compiled-artifacts");
1154
+ }
1155
+ export function buildGraphifyCompiledArtifactPack(input = {}) {
1156
+ return buildDefaultGraphifyCompiledArtifactPack(input);
1157
+ }
1158
+ export function writeGraphifyCompiledArtifactPack(outputDir, bundle) {
1159
+ ensureDir(outputDir);
1160
+ const writtenFiles = [];
1161
+ for (const [relativePath, content] of Object.entries(bundle.files)) {
1162
+ const absolutePath = path.join(outputDir, relativePath);
1163
+ writeText(absolutePath, content);
1164
+ writtenFiles.push(absolutePath);
1165
+ }
1166
+ return {
1167
+ outputDir: path.resolve(outputDir),
1168
+ writtenFiles,
1169
+ fileCount: writtenFiles.length,
1170
+ };
1171
+ }
1172
+ export function buildGraphifyCompiledArtifactPackDigest(bundle) {
1173
+ const fileEntries = Object.entries(bundle.files ?? {}).sort(([left], [right]) => left.localeCompare(right));
1174
+ const files = Object.fromEntries(fileEntries.map(([relativePath, content]) => [relativePath, sha256Text(content)]));
1175
+ const bundleHash = sha256Text(fileEntries.map(([relativePath, content]) => `${relativePath}\n${sha256Text(content)}`).join("\n"));
1176
+ return {
1177
+ bundleId: bundle.bundleId,
1178
+ packId: bundle.packId,
1179
+ proposalId: bundle.proposalId,
1180
+ files,
1181
+ fileCount: fileEntries.length,
1182
+ bundleHash,
1183
+ };
1184
+ }
1185
+ //# sourceMappingURL=graphify-compiled-artifacts.js.map