Acquire installed portable operations with explicit authority and input coverage
This commit is contained in:
@@ -8,3 +8,5 @@ export * from "./receipts.js";
|
||||
export { generatePortableTypeScriptBindings } from "../bindings/portable.js";
|
||||
|
||||
export * from "./kernel.js";
|
||||
export * from "./projections.js";
|
||||
export { generatePortableClientBindings } from "../bindings/portable-client.js";
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import { ExecutionPlanError, hexDigest, type ExecutionPlan, type PlannedQuery } from "./plan.js";
|
||||
/** Contracts promised by a direct result. Interface dependencies are explicit; accidental
|
||||
* overlap among today's implementations does not silently widen an exported interface contract. */
|
||||
export function resultInterfaces(plan: ExecutionPlan, operationKey: string): string[] {
|
||||
const operation = plan.definition.operations.find((operation) => operation.key === operationKey);
|
||||
if (!operation) throw new ExecutionPlanError("UNKNOWN_OPERATION", operationKey, "No installed public operation");
|
||||
if (operation.output.kind !== "object-ref") return [];
|
||||
const expected = operation.output.expectation;
|
||||
if (expected.kind === "atom")
|
||||
return plan.definition.workspace.conformances
|
||||
.filter((c) => c.atomId === expected.atomId)
|
||||
.map((c) => c.interfaceRevisionId)
|
||||
.sort();
|
||||
const interfaces = new Map(plan.definition.workspace.interfaceImports.map((i) => [String(i.revisionId), i]));
|
||||
const result = new Set<string>();
|
||||
const visit = (id: string) => {
|
||||
if (result.has(id)) return;
|
||||
result.add(id);
|
||||
for (const dependency of interfaces.get(id)?.requiredInterfaces ?? []) visit(dependency);
|
||||
};
|
||||
visit(expected.interfaceRevisionId);
|
||||
return [...result].sort();
|
||||
}
|
||||
/** Compile-time observeResult compatibility. Observation does not grant read or mutation authority. */
|
||||
export function checkResultProjection(plan: ExecutionPlan, operationKey: string, queryId: string): PlannedQuery {
|
||||
if (hexDigest(plan.definition) !== plan.digest)
|
||||
throw new ExecutionPlanError("INVALID_PLAN", "projection", "Plan digest mismatch");
|
||||
const query = plan.definition.queries.find((q) => q.id === queryId);
|
||||
if (!query) throw new ExecutionPlanError("UNKNOWN_PROJECTION", queryId, "No installed query");
|
||||
const declaration = query.query.checked.declaration;
|
||||
if (declaration.placement?.kind !== "replica" || declaration.root.kind !== "object")
|
||||
throw new ExecutionPlanError(
|
||||
"INVALID_RESULT_PROJECTION",
|
||||
queryId,
|
||||
"Result observation requires a direct-object replica declaration",
|
||||
);
|
||||
if (!resultInterfaces(plan, operationKey).includes(declaration.root.interface))
|
||||
throw new ExecutionPlanError(
|
||||
"RESULT_PROJECTION_MISMATCH",
|
||||
operationKey,
|
||||
`Result does not promise ${declaration.root.interface}`,
|
||||
);
|
||||
return query;
|
||||
}
|
||||
Reference in New Issue
Block a user