import { executionPlanDigest, type ExecutionPlan, ExecutionPlanError, hexDigest } from "./plan.js"; import { portableReflectionType, portableReflectionValue } from "./reflection.js"; import type { ValueType, InitializationField, PersistentAttachment, DependencyBinding, BoundDependency, PackageExport, } from "../capability-model/types.js"; import { portableValueSchema } from "../bindings/portable.js"; import { subscriptionContract } from "../capability-model/journals.js"; type PreparedStep = string | null | { case: string; id: string }; function preparedInputPaths(type: ValueType, path: PreparedStep[] = []): PreparedStep[][] { if (type.kind === "change") return [path]; if (type.kind === "optional") return preparedInputPaths(type.value, path); if (type.kind === "list") return preparedInputPaths(type.value, [...path, null]); if (type.kind === "variant") return Object.entries(type.cases).flatMap(([label, entry]) => preparedInputPaths(entry.value, [...path, { case: label, id: entry.id }]), ); if (type.kind === "record") return Object.entries(type.fields).flatMap(([key, value]) => preparedInputPaths(value, [...path, key])); return []; } /** Small data-only interpreter input; no compiler, parser, Node module or SQL dependency reaches the browser. */ export function compileKernelProgram(plan: ExecutionPlan): unknown { if (executionPlanDigest(plan) !== plan.digest) throw new ExecutionPlanError("INVALID_PLAN", "kernel", "Plan digest mismatch"); const workspace = plan.definition.workspace; if (workspace.sharedAttachments.some((attachment) => attachment.kind !== "edge")) throw new ExecutionPlanError( "UNSUPPORTED_SHARED_STORAGE", "kernel", "Shared scalar storage is not implemented; use conformance-owned state", ); const schema = (type: ValueType): unknown | null => { try { return portableValueSchema(type); } catch { return null; } }; const ownerBySlot = new Map(); const edges: { id: string; owner: string | null; a: unknown; b: unknown }[] = []; const lowerEdge = (storage: Extract, owner: string | null) => { const endpoints = storage.endpoints.map((endpoint) => { if (endpoint.ordered || (endpoint.keyType && endpoint.keyType !== "string") || endpoint.retainOther) throw new ExecutionPlanError( "UNSUPPORTED_GRAPH_FEATURE", storage.id, "Ordered relations, non-string keys and automatic retention are not implemented", ); return { projection: endpoint.projectionId, constraint: { kind: endpoint.constraint.kind, id: endpoint.constraint.kind === "atom" ? endpoint.constraint.atomId : endpoint.constraint.interfaceRevisionId, }, cardinality: endpoint.cardinality, ...(endpoint.keyType ? { keyType: endpoint.keyType } : {}), ...(endpoint.onDelete ? { onDelete: endpoint.onDelete } : {}), }; }); edges.push({ id: storage.id, owner, a: endpoints[0], b: endpoints[1] }); }; for (const storage of workspace.sharedAttachments) if (storage.kind === "edge") lowerEdge(storage, null); const owners = plan.definition.owners.map((owner) => { const slots: unknown[] = []; for (const storage of owner.storage as PersistentAttachment[]) { if (storage.kind === "state") { const shape = schema(storage.valueType); if (!shape) throw new ExecutionPlanError("UNSUPPORTED_STORAGE_CODEC", storage.id, "Unsupported canonical value type"); ownerBySlot.set(storage.id, owner.id); const pinsFor = (payload: ValueType) => { const expectations = new Map(); const walk = (type: ValueType): void => { if (type.kind === "object-ref") { const expectation = { kind: type.expectation.kind, id: type.expectation.kind === "atom" ? type.expectation.atomId : type.expectation.interfaceRevisionId, }; expectations.set(JSON.stringify(expectation), expectation); } else if (type.kind === "list" || type.kind === "optional") walk(type.value); else if (type.kind === "record") Object.values(type.fields).forEach(walk); else if (type.kind === "variant") Object.values(type.cases).forEach((entry) => walk(entry.value)); }; walk(payload); const pins = [...expectations.values()].map((expectation) => { const id = `journal-pin:${hexDigest([storage.id, expectation])}`; const projection = `${id}:source`; edges.push({ id, owner: owner.id, a: { projection, constraint: { kind: "atom", id: owner.atom }, cardinality: "many", keyType: "string", onDelete: "detach", }, b: { projection: `${id}:target`, constraint: expectation, cardinality: "many", onDelete: "restrict" }, }); return { edge: id, projection }; }); return pins; }; let journal: unknown, subscription: unknown; if (storage.storagePolicy.kind === "journal") { journal = { limits: storage.storagePolicy.limits, pins: pinsFor(storage.valueType) }; } if (storage.storagePolicy.kind === "subscription") { const bindings = plan.definition.operations.filter( (operation) => operation.atomId === owner.atom && operation.binding.kind === "subscription" && operation.binding.slotId === storage.id && operation.binding.primitive === "attach", ); if (bindings.length !== 1) throw new ExecutionPlanError( "SUBSCRIPTION_ATTACHMENT_REQUIRED", storage.id, "Native subscription storage requires one checked attachment operation", ); const binding = bindings[0]!; const operation = workspace.interfaceImports .find((iface) => iface.revisionId === binding.interfaceRevisionId)! .members.flatMap((member) => member.operations) .find((operation) => operation.id === binding.operationId)!; const contract = subscriptionContract( storage.storagePolicy.payload, storage.valueType, operation, workspace.interfaceImports, ); const expectation = (value: typeof contract.source) => ({ kind: value.kind, id: value.kind === "atom" ? value.atomId : value.interfaceRevisionId, }); const source = expectation(contract.source), handler = expectation(contract.handler); const configuration: ValueType = { kind: "record", fields: { source: { kind: "object-ref", expectation: contract.source }, handler: { kind: "object-ref", expectation: contract.handler }, parameters: storage.valueType, }, }; const edge = `subscription-active:${hexDigest(storage.id)}`, projection = `${edge}:subscription`; edges.push({ id: edge, owner: owner.id, a: { projection, constraint: { kind: "atom", id: owner.atom }, cardinality: "many", onDelete: "restrict" }, b: { projection: `${edge}:stream`, constraint: source, cardinality: "many", onDelete: "restrict" }, }); subscription = { payload: schema(storage.storagePolicy.payload), source, handler, operation: contract.operation, pins: pinsFor(configuration), active: { edge, projection }, }; } slots.push({ id: storage.id, schema: shape, policy: storage.storagePolicy.kind === "crdt-document" ? "crdt" : storage.storagePolicy.kind, ...(journal ? { journal } : {}), ...(subscription ? { subscription } : {}), ...(Object.hasOwn(storage, "defaultValue") ? { defaultLiteral: storage.defaultValue } : {}), }); } else lowerEdge(storage, owner.id); } return { id: owner.id, atom: owner.atom, interface: owner.interface, slots, initialize: (owner.initialization as InitializationField[]).map((field) => ({ input: field.input, binding: field.binding.kind === "state" ? { kind: "state", slot: field.binding.slotId } : { kind: "edge", edge: field.binding.edgeTypeId, projection: field.binding.projectionId }, })), }; }); const slotOwner = (slot: string) => { const owner = ownerBySlot.get(slot); if (!owner) throw new ExecutionPlanError("MISSING_STORAGE_OWNER", slot, "No checked owner"); return owner; }; const via = (binding: DependencyBinding) => "via" in binding && binding.via ? { via: { edge: binding.via.edgeTypeId, projection: binding.via.projectionId } } : {}; const operations = plan.definition.operations.map((operation) => { const binding = operation.binding; let target: unknown; let unsupported: string | null = null; if (binding.kind === "lifecycle") target = { kind: "lifecycle", primitive: binding.primitive }; else if (binding.kind === "journal" || binding.kind === "subscription") target = { kind: binding.kind, owner: slotOwner(binding.slotId), slot: binding.slotId, primitive: binding.primitive, }; else if (binding.kind === "state") target = { kind: "state", owner: slotOwner(binding.slotId), slot: binding.slotId, primitive: binding.primitive }; else if (binding.kind === "edge") target = { kind: "edge", edge: binding.edgeTypeId, projection: binding.projectionId, primitive: binding.primitive, }; else { const pkg = workspace.packageImports.find((p) => p.revisionId === binding.packageRevisionId)!; const entry = pkg.exports.find((e) => e.id === binding.exportId)!; const compilePorts = (entry: PackageExport, dependencies: BoundDependency[]) => dependencies.map((dependency) => { const requirement = entry.dependencyPorts.find((p) => p.id === dependency.portId)!.requirement; const bound = dependency.binding; const common = { id: dependency.portId, ...via(bound) }; if (bound.kind === "reflection" && requirement.kind === "reflection") return { ...common, kind: "reflection", values: Object.fromEntries( bound.selectors.map((selector) => [ selector, { schema: portableValueSchema(portableReflectionType(selector)), value: portableReflectionValue(workspace, selector), }, ]), ), }; if (bound.kind === "state" && requirement.kind === "state") return { ...common, kind: "state", owner: slotOwner(bound.slotId), slot: bound.slotId, primitives: requirement.primitives, }; if (bound.kind === "edge" && requirement.kind === "edge") return { ...common, kind: "edge", edge: bound.edgeTypeId, projection: bound.projectionId, primitives: requirement.primitives, }; if (bound.kind === "interface" && requirement.kind === "interface") { const iface = workspace.interfaceImports.find((i) => i.revisionId === bound.interfaceRevisionId)!; return { ...common, kind: "interface", interface: bound.interfaceRevisionId, ...(!bound.receiver && !bound.via && (requirement.operations ?? iface.members.flatMap((m) => m.operations.map((o) => o.id))).every( (id) => iface.members.flatMap((m) => m.operations).find((o) => o.id === id)?.scope === "class", ) ? { staticAtom: operation.atomId } : {}), ...(bound.receiver ? { receiver: bound.receiver } : {}), operations: requirement.operations ?? iface.members.flatMap((m) => m.operations.map((o) => o.id)), }; } if (bound.kind === "creation" && requirement.kind === "creation") return { ...common, kind: "creation", atom: bound.atomId, schema: portableValueSchema(requirement.inputType), recipe: hexDigest({ codec: "camino-creation-recipe-v1", versions: plan.definition.versions, operation: operation.key, export: entry.id, port: dependency.portId, requirement, binding: bound, owners: owners.filter((owner) => owner.atom === bound.atomId), edges: edges.filter((edge) => owners.some((owner) => owner.atom === bound.atomId && owner.id === edge.owner), ), }), owners: bound.owners.map((seed) => { const owner = owners.find((o) => o.atom === bound.atomId && o.interface === seed.interfaceRevisionId); if (!owner) throw new ExecutionPlanError( "MISSING_STORAGE_OWNER", dependency.portId, "Creation has no initialization owner", ); return { owner: owner.id, inputPath: seed.inputPath }; }), }; unsupported = `UNSUPPORTED_EXECUTION_PORT:${bound.kind}`; return { ...common, kind: "unavailable" }; }); const ports = compilePorts(entry, binding.dependencies); const check = entry.acceptanceExportId ? pkg.exports.find((candidate) => candidate.id === entry.acceptanceExportId)! : undefined; target = { kind: "package", package: binding.packageRevisionId, export: binding.exportId, ports, ...(entry.preparation ? { preparation: entry.preparation } : {}), ...(check ? { acceptance: { export: check.id, ports: compilePorts(check, binding.acceptanceDependencies ?? []) } } : {}), }; } const inputChanges = preparedInputPaths(operation.input); const input = schema(operation.input), output = schema(operation.output); return { key: operation.key, atom: operation.atomId, interface: operation.interfaceRevisionId, operation: operation.operationId, scope: operation.scope, effect: operation.execution.kind, targets: operation.availableTargets, input, ...(inputChanges.length ? { inputChanges } : {}), output, unsupported: unsupported ?? (input && output ? null : "UNSUPPORTED_OPERATION_CODEC"), binding: target, }; }); const packages = workspace.packageImports.map((pkg) => ({ revision: pkg.revisionId, exports: pkg.exports.map((entry) => ({ id: entry.id, ...(entry.preparation ? { preparation: entry.preparation } : {}), ...(entry.acceptanceExportId ? { acceptance: entry.acceptanceExportId } : {}), effect: entry.execution?.kind ?? "remote", targets: entry.execution && entry.execution.kind !== "remote" ? entry.execution.targets : [], receiver: entry.kind === "function" ? null : entry.kind === "operation" && entry.receiverRequirement.kind === "exact-atom" ? { kind: "atom", id: entry.receiverRequirement.atomId } : "object", input: schema(entry.inputType), output: schema(entry.outputType), })), })); const body = { codec: "camino-kernel-program-v1", model: { workspace: workspace.workspaceId, atoms: workspace.atoms.map((atom) => atom.id), owners, edges }, operations, packages, }; // The interpreter's plan key covers its real input, not source/build evidence. return { ...body, plan: hexDigest({ versions: plan.definition.versions, program: body }) }; }