/*
Semantic fingerprint of the platform tree (packages, integrations, services) — shared by site-kernel-checks and site-kernel-handoff.
- Do not include bundle IO or lock/manifest reading — those stay in site-kernel-handoff/bundle-io.ts.
- The fingerprint covers the platform tree only — site content is excluded by design.
- RFC-1097: step 6 — compass.migrate codemod run
Mechanical v1 to v2 header migration across the workspace: 942 files rewritten — CHANGE_SUMMARY windows collapsed into history, forbidden v1 blocks stripped, KEY_DECISIONS seeded from @ai-invariant comments (5 files) or TODO placeholders (103 files), blocks reordered to canonical order.
- RFC-1097: sweep — werkstatt-engine clean
Sweep batch 4: 73 Compass headers on headerless engine files (certification, component-runtime, isolation, evolution, testing), real KEY_DECISIONS on 75 files (kernel, cache, dht, swim, gitmesh, runtime), ~80 purpose expansions (CONTRACT-02/PURPOSE-02), non-goals on 13 CONTRACT-03 files, CS-07 history literal fix repo-wide (253 files). Policy: .template.ts/.template.astro excludedPaths. werkstatt-engine now 0 diagnostics.
*/
import path from "node:path";
import { byteHash } from "@warpgogol/werkstatt-engine/fingerprint";
import { fingerprintTree } from "@warpgogol/werkstatt-engine/fingerprint/semantic";
import { createDefaultIO, type WorkspaceIO } from "@warpgogol/werkstatt-shared/kernel/workspace-io";
/**
* RFC-0364: Semantic fingerprint of the recipient's platform tree.
*
* Uses @warpgogol/fingerprint to produce a parser-backed semantic hash that is
* invariant under formatting-only and comment-only changes. This is the
* platform drift signal for new Sternsystem/release surfaces.
*
* RFC-0533: extended to cover packages/, integrations/, and services/ —
* the full platform scope. Non-existent directories are skipped gracefully.
*/
export async function resolvePlatformSemanticHash(
workspaceRoot: string,
io: WorkspaceIO = createDefaultIO().io,
): Promise {
const ignore = ["node_modules", ".turbo", "dist", ".astro"];
const scopeDirs = ["packages", "integrations", "services"];
const allResults: { rel: string; hash: string }[] = [];
for (const dir of scopeDirs) {
const absDir = path.join(workspaceRoot, dir);
if (!(await io.exists(absDir))) {
continue;
}
const result = await fingerprintTree(absDir, {
mode: "semantic",
root: workspaceRoot,
ignore,
});
for (const file of result.files ?? []) {
const rel = path.relative(workspaceRoot, file.path);
allResults.push({ rel, hash: file.hash });
}
}
allResults.sort((a, b) => a.rel.localeCompare(b.rel));
const combinedInput = allResults.map((r) => `${r.rel}\n${r.hash}`).join("\n");
return byteHash(combinedInput);
}