import { ExecutionPlanError, hexDigest, type ExecutionPlan } from "./plan.js"; import type { ExecutionInstallation } from "./installation.js"; /** Execution inputs, not build evidence. Nominal revision IDs remain dispatch * keys: replacing a contract with a structurally similar one is not continuity. * Host placement/policy/credentials are compared separately by execution groups. */ export function graphExecutionRepresentation( plan: ExecutionPlan, installation: ExecutionInstallation, kernel: unknown, queries: unknown, ) { if (installation.plan !== plan.digest || hexDigest(plan.definition) !== plan.digest) throw new ExecutionPlanError("GRAPH_PLAN_MISMATCH", "graph", "Expected one checked installation"); if ( !kernel || typeof kernel !== "object" || Array.isArray(kernel) || !queries || typeof queries !== "object" || Array.isArray(queries) ) throw new ExecutionPlanError("GRAPH_PROGRAM_MISMATCH", "graph", "Expected interpreter program records"); const input = kernel as Record, queryInput = queries as Record; const { plan: key, ...program } = input; if ( input.codec !== "camino-kernel-program-v1" || queryInput.codec !== "camino-query-program-v1" || queryInput.plan !== key || key !== hexDigest({ versions: plan.definition.versions, program }) ) throw new ExecutionPlanError("GRAPH_PROGRAM_MISMATCH", "graph", "Interpreter inputs do not match execution key"); return { codec: "camino-graph-execution-v1", versions: plan.definition.versions, kernel, queries, // Include every selected implementation, including acceptance/remote code // and the browser dependency closure, not merely the public export names. packages: installation.packages.map((pkg) => ({ revision: pkg.revision, service: pkg.service ?? null, module: pkg.module ?? null, browser: pkg.browserImplementation ?? null, })), controllers: plan.definition.packages.map((pkg) => ({ revision: pkg.revision, controllers: pkg.controllers ?? [], })), shared: { core: installation.coreURL ?? null, engine: installation.engineURL ?? null, components: [ ...new Map(installation.components.flatMap((component) => Object.entries(component.sharedModules))).entries(), ].sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)), }, }; }