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(); 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; }