Implement typed module contracts and conformance bindings

This commit is contained in:
Timothy J. Aveni
2026-09-22 13:51:32 -07:00
parent 60b44a6637
commit 7173751f37
33 changed files with 2963 additions and 2261 deletions
+44 -2
View File
@@ -10,6 +10,7 @@ import type {
OperationId,
} from "../capability-model/types.js";
import { validateWorkspaceRevision } from "../capability-model/validation.js";
import { moduleContract } from "../capability-model/modules.js";
import { canonicalJson, contentDigest } from "../capability-model/evolution.js";
import { resolveForwardedBinding } from "../capability-model/forwarding.js";
import { linkQueries, type LinkedQuery } from "../query/link.js";
@@ -58,14 +59,41 @@ export interface PlannedQuery {
admittedOperations: string[];
}
export interface PlanPackage {
modules?: (NonNullable<WorkspaceRevision["packageImports"][number]["modules"]>[number] & {
contract: string;
subject?: import("../capability-model/types.js").ObjectExpectation;
})[];
controllers?: NonNullable<WorkspaceRevision["packageImports"][number]["controllers"]>;
components?: NonNullable<WorkspaceRevision["packageImports"][number]["components"]>;
components?: { id: string; displayName: string; subject: InterfaceRevisionId; runtime: "react" }[];
revision: string;
source: WorkspaceRevision["packageImports"][number]["source"];
sourceDigest: string;
bindingDigest: string;
exports: { id: string; execution: ExecutionContract }[];
}
/** React consumes these module contracts; other contracts remain metadata until
* an artifact consumer exists. This does not make modules callable operations. */
function componentDeclarations(workspace: WorkspaceRevision, pkg: WorkspaceRevision["packageImports"][number]) {
return [
...(pkg.modules ?? []).flatMap((module) => {
const contract = moduleContract(workspace.interfaceImports, module)!;
if (
!["org.quixos.react.component/1", "org.quixos.react.subject-only/1"].includes(contract.contract) ||
contract.subject?.kind !== "interface"
)
return [];
return [
{
id: module.id,
displayName: module.displayName,
subject: contract.subject.interfaceRevisionId,
runtime: "react" as const,
},
];
}),
];
}
export interface ExecutionPlanDefinition {
presentations?: NonNullable<WorkspaceRevision["presentations"]>;
codec: "camino-execution-plan-v1";
@@ -430,8 +458,22 @@ export function compileExecutionPlan(input: WorkspaceRevision): ExecutionPlan {
source: p.source,
sourceDigest: hexDigest({ revision: p.revisionId, source: p.source }),
bindingDigest: hexDigest(normalizedSchema),
...(p.modules?.length
? {
modules: sorted(p.modules, (module) => module.id).map((module) => {
const contract = moduleContract(workspace.interfaceImports, module)!;
return {
...module,
contract: contract.contract,
...(contract.subject ? { subject: contract.subject } : {}),
};
}),
}
: {}),
...(p.controllers?.length ? { controllers: sorted(p.controllers, (controller) => controller.id) } : {}),
...(p.components?.length ? { components: sorted(p.components, (component) => component.id) } : {}),
...(componentDeclarations(workspace, p).length
? { components: sorted(componentDeclarations(workspace, p), (component) => component.id) }
: {}),
exports: sorted(p.exports, (e) => e.id).map((e) => ({ id: e.id, execution: e.execution ?? { kind: "remote" } })),
})),
owners: sorted(workspace.conformances, (c) => c.id ?? "").map((c) => {