Compile and dispatch authoritative acceptance hooks with target-specific package roots
This commit is contained in:
@@ -3,6 +3,8 @@ import type {
|
||||
InitializationField,
|
||||
PersistentAttachment,
|
||||
DependencyBinding,
|
||||
BoundDependency,
|
||||
PackageExport,
|
||||
} from "../capability-model/types.js";
|
||||
import { type ExecutionPlan, ExecutionPlanError, hexDigest } from "./plan.js";
|
||||
import { portableValueSchema } from "../bindings/portable.js";
|
||||
@@ -107,57 +109,70 @@ export function compileKernelProgram(plan: ExecutionPlan): unknown {
|
||||
else {
|
||||
const pkg = workspace.packageImports.find((p) => p.revisionId === binding.packageRevisionId)!;
|
||||
const entry = pkg.exports.find((e) => e.id === binding.exportId)!;
|
||||
const ports = binding.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 === "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,
|
||||
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({ plan: plan.digest, operation: operation.key, port: dependency.portId }),
|
||||
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" };
|
||||
});
|
||||
target = { kind: "package", package: binding.packageRevisionId, export: binding.exportId, ports };
|
||||
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 === "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,
|
||||
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({ plan: plan.digest, operation: operation.key, port: dependency.portId }),
|
||||
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,
|
||||
...(check
|
||||
? { acceptance: { export: check.id, ports: compilePorts(check, binding.acceptanceDependencies ?? []) } }
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
const input = schema(operation.input),
|
||||
output = schema(operation.output);
|
||||
@@ -179,6 +194,7 @@ export function compileKernelProgram(plan: ExecutionPlan): unknown {
|
||||
revision: pkg.revisionId,
|
||||
exports: pkg.exports.map((entry) => ({
|
||||
id: entry.id,
|
||||
...(entry.acceptanceExportId ? { acceptance: entry.acceptanceExportId } : {}),
|
||||
effect: entry.execution?.kind ?? "remote",
|
||||
targets: entry.execution && entry.execution.kind !== "remote" ? entry.execution.targets : [],
|
||||
receiver:
|
||||
|
||||
Reference in New Issue
Block a user