From c5e79ae3c9fcf3ba4420f2fdb5e3f7317965530e Mon Sep 17 00:00:00 2001 From: "Timothy J. Aveni" Date: Tue, 22 Sep 2026 17:22:48 -0700 Subject: [PATCH] Add bounded public member inspection through shared query scopes --- src/execution-world/inspection.ts | 176 +++++++++++++++++++++++ src/execution-world/installation.ts | 11 +- src/execution-world/public-reflection.ts | 30 ++-- src/execution-world/queries.ts | 82 ++++++----- test/inspection.test.ts | 35 +++++ 5 files changed, 282 insertions(+), 52 deletions(-) create mode 100644 src/execution-world/inspection.ts create mode 100644 test/inspection.test.ts diff --git a/src/execution-world/inspection.ts b/src/execution-world/inspection.ts new file mode 100644 index 0000000..d2b879e --- /dev/null +++ b/src/execution-world/inspection.ts @@ -0,0 +1,176 @@ +import { compileKernelProgram } from "./kernel.js"; +import { hexDigest, type ExecutionPlan } from "./plan.js"; +import type { PublicQueryContract } from "./client-contracts.js"; +import { portableValueSchema } from "../bindings/portable.js"; +const scalar = (name: string) => ({ kind: "scalar", name }); +const record = (fields: Record) => ({ kind: "record", fields }); +const optional = (value: unknown) => ({ kind: "optional", value }); +const selection = (name: string, extra: Record = {}) => ({ + name, + key: name, + arguments: {}, + conditions: [], + selection: [], + ...extra, +}); +const variable = (name: string) => ({ kind: "variable", name }); +const meta = () => selection("_camino", { selection: [selection("ref")] }); +export const inspectionPackage = "org.quixos.inspection/1"; +export interface InspectionTemplate { + interface: string; + members: { id: string; name: string; key: string; flag: string; lane: "local" | "server"; many: boolean }[]; + inputs?: PublicQueryContract; + view?: PublicQueryContract; + server?: PublicQueryContract; +} +/** A finite installed template per interface/lane, not a per-client query compiler. + * Flags select public cache boundaries; normal scope identity bounds specialization. */ +export function compileInspectionTemplates(plan: ExecutionPlan) { + const kernel = compileKernelProgram(plan) as { + operations: { + key: string; + atom: string; + interface: string; + operation: string; + effect: string; + targets: string[]; + unsupported: string | null; + output: unknown; + binding: { kind: string }; + }[]; + }; + const queries: unknown[] = [], + contracts: PublicQueryContract[] = [], + templates: InspectionTemplate[] = []; + for (const iface of plan.definition.workspace.interfaceImports) { + if (iface.template) continue; + const atoms = plan.definition.workspace.conformances + .filter((c) => c.interfaceRevisionId === iface.revisionId) + .map((c) => c.atomId) + .sort(); + if (!atoms.length) continue; + const members = iface.members + .filter((member) => (member.kind === "value" || member.kind === "relationship") && member.queryRead) + .sort((a, b) => (a.id < b.id ? -1 : 1)); + if (!members.length || members.length > 128) continue; + const template: InspectionTemplate = { interface: iface.revisionId, members: [] }; + for (const lane of ["local", "server"] as const) { + const fields: unknown[] = [], + selections: unknown[] = [], + inputFields: Record = {}, + outputFields: Record = {}; + for (const [index, member] of members.entries()) { + if (member.kind !== "value" && member.kind !== "relationship") continue; + const getter = member.operations.find((op) => op.displayName === (member.kind === "value" ? "get" : "resolve")); + if (!getter) continue; + const providers = atoms.map((atom) => + kernel.operations.find( + (op) => op.atom === atom && op.interface === iface.revisionId && op.operation === getter.id, + ), + ); + if (providers.some((op) => !op || op.unsupported || !["snapshot", "remote"].includes(op.effect))) continue; + const portable = providers.every((op) => op!.effect === "snapshot" && op!.targets.includes("browser")); + if (lane === "local" && !portable) continue; + const key = "m" + index, + flag = "s" + index; + const many = member.kind === "relationship" && ["many", "many-unique"].includes(member.cardinality); + // Only native edges promise the relationship traversal used by the interpreter. + if (member.kind === "relationship" && providers.some((op) => op!.binding.kind !== "edge")) continue; + if (lane === "local" || !portable) + template.members.push({ id: member.id, name: member.displayName, key, flag, lane, many }); + inputFields[flag] = scalar("bool"); + const field = selection(member.displayName, { + key, + interfaceRevisionId: iface.revisionId, + memberId: member.id, + conditions: [{ include: true, value: variable(flag) }], + }); + let output = portableValueSchema(getter.outputType); + if (member.kind === "relationship") { + const expectation = + member.target.kind === "atom" + ? { kind: "atom", id: member.target.atomId } + : { kind: "interface", id: member.target.interfaceRevisionId }; + const node = record({ _camino: record({ ref: { kind: "object-ref", expectation } }) }); + if (member.target.kind === "interface") + Object.assign(field, { targetInterfaceRevisionId: member.target.interfaceRevisionId }); + if (many) { + inputFields[key + "First"] = scalar("int32"); + inputFields[key + "After"] = optional(scalar("string")); + Object.assign(field, { + arguments: { first: variable(key + "First"), after: variable(key + "After") }, + selection: [ + selection("entries", { selection: [selection("key"), selection("node", { selection: [meta()] })] }), + selection("pageInfo", { selection: [selection("hasNextPage"), selection("endCursor")] }), + ], + }); + output = record({ + entries: { kind: "list", value: record({ key: scalar("string"), node }) }, + pageInfo: record({ hasNextPage: scalar("bool"), endCursor: optional(scalar("string")) }), + }); + } else { + Object.assign(field, { selection: [meta()] }); + output = node; + } + } + outputFields[key] = optional(output); + selections.push(field); + for (const op of providers) + fields.push({ + atom: op!.atom, + interface: iface.revisionId, + member: member.id, + name: member.displayName, + operation: op!.key, + }); + } + if (!selections.length) continue; + const root = { kind: "object" as const, interface: iface.revisionId }; + const input = record(inputFields), + output = record({ root: record(outputFields) }); + const base = { + root, + atoms, + variables: input, + defaults: {}, + selection: [selection("root", { selection: selections })], + fields, + admittedOperations: [], + budgets: { + rows: 512, + depth: 8, + resultBytes: 8 * 1024 * 1024, + candidates: 1000, + rpcCalls: 128, + concurrency: 8, + deadlineMs: 10000, + }, + }; + for (const kind of lane === "local" ? (["inputs", "view"] as const) : (["server"] as const)) { + const query = JSON.stringify([iface.revisionId, kind]); + const sourceQuery = JSON.stringify([iface.revisionId, "inputs"]); + const program = { + ...base, + id: JSON.stringify([inspectionPackage, query]), + placement: kind === "inputs" ? "replica" : kind === "view" ? "local" : "remote", + source: kind === "view" ? JSON.stringify([inspectionPackage, sourceQuery]) : null, + }; + const contract: PublicQueryContract = { + package: inspectionPackage, + query, + definitionDigest: hexDigest(program), + root, + placement: kind === "inputs" ? "replica" : kind === "view" ? "local" : "server", + ...(kind === "view" ? { sourceQuery } : {}), + input, + output, + }; + queries.push(program); + contracts.push(contract); + template[kind] = contract; + } + } + if (template.members.length) templates.push(template); + } + return { queries, contracts, templates }; +} diff --git a/src/execution-world/installation.ts b/src/execution-world/installation.ts index 0adc7f5..fce93a4 100644 --- a/src/execution-world/installation.ts +++ b/src/execution-world/installation.ts @@ -1,3 +1,4 @@ +import { compileInspectionTemplates, type InspectionTemplate } from "./inspection.js"; import path from "node:path"; import { loadCheckedArtifactWorld } from "./receipts.js"; import { contentArtifactUrl, loadArtifactWorld, type LoadedArtifactWorld } from "./files.js"; @@ -24,6 +25,7 @@ export interface ExecutionGroupIdentity { readonly executionDigest: string; } export interface ClientContractCatalog { + readonly inspections: readonly InspectionTemplate[]; readonly resultInterfaces: Readonly>; readonly operations: readonly PublicOperationContract[]; readonly queries: readonly PublicQueryContract[]; @@ -66,14 +68,17 @@ export function clientContractCatalog( .map((operation) => publicOperationContract(iface, operation)), ), ); + const inspection = compileInspectionTemplates(plan); return { + inspections: inspection.templates, resultInterfaces: Object.fromEntries( plan.definition.operations.map((operation) => [operation.key, resultInterfaces(plan, operation.key)]), ), operations, - queries: packages.flatMap((pkg) => - (pkg.checkedQueries ?? []).map((q) => publicQueryContract(pkg, q.declaration.id)), - ), + queries: [ + ...inspection.contracts, + ...packages.flatMap((pkg) => (pkg.checkedQueries ?? []).map((q) => publicQueryContract(pkg, q.declaration.id))), + ], components: installation.components.filter((c) => requestedPackages.includes(c.packageRevision)), moduleBindings: plan.definition.workspace.conformances.flatMap((c) => (c.moduleBindings ?? []) diff --git a/src/execution-world/public-reflection.ts b/src/execution-world/public-reflection.ts index f8b5fa2..d828670 100644 --- a/src/execution-world/public-reflection.ts +++ b/src/execution-world/public-reflection.ts @@ -1,3 +1,4 @@ +import { compileInspectionTemplates } from "./inspection.js"; import { compileKernelProgram } from "./kernel.js"; import { hexDigest, type ExecutionPlan } from "./plan.js"; import { clientContractCatalog, type ExecutionInstallation } from "./installation.js"; @@ -66,17 +67,26 @@ export function publicDefinitionSnapshot(plan: ExecutionPlan, installation: Exec (binding) => binding.atom === c.atomId && binding.interface === c.interfaceRevisionId, ), })), - queries: workspace.packageImports.flatMap((pkg) => - (pkg.checkedQueries ?? []).map((query) => ({ - id: JSON.stringify([pkg.revisionId, query.declaration.id]), - name: query.declaration.displayName, - package: pkg.revisionId, - descriptor: publicQueryContract(pkg, query.declaration.id), - fragment: query.declaration.fragment, - limits: query.declaration.budgets, - watch: query.declaration.watch, + queries: [ + ...compileInspectionTemplates(plan).contracts.map((descriptor) => ({ + id: JSON.stringify([descriptor.package, descriptor.query]), + name: "Public inspection", + package: descriptor.package, + descriptor, + system: true, })), - ), + ...workspace.packageImports.flatMap((pkg) => + (pkg.checkedQueries ?? []).map((query) => ({ + id: JSON.stringify([pkg.revisionId, query.declaration.id]), + name: query.declaration.displayName, + package: pkg.revisionId, + descriptor: publicQueryContract(pkg, query.declaration.id), + fragment: query.declaration.fragment, + limits: query.declaration.budgets, + watch: query.declaration.watch, + })), + ), + ], presentations: catalog.components.map((component) => ({ id: JSON.stringify([component.packageRevision, component.id]), component, diff --git a/src/execution-world/queries.ts b/src/execution-world/queries.ts index 07d54f3..aff4ac9 100644 --- a/src/execution-world/queries.ts +++ b/src/execution-world/queries.ts @@ -1,3 +1,4 @@ +import { compileInspectionTemplates } from "./inspection.js"; import { portableValueSchema } from "../bindings/portable.js"; import { ExecutionPlanError, hexDigest, type ExecutionPlan } from "./plan.js"; import type { ValueType } from "../capability-model/types.js"; @@ -26,44 +27,47 @@ export function compileQueryProgram(plan: ExecutionPlan): unknown { return { codec: "camino-query-program-v1", plan: plan.digest, - queries: plan.definition.queries.map(({ id, query, admittedOperations }) => { - const checked = query.checked; - return { - id, - ...(checked.declaration.fragment && !checked.declaration.fragment.admission - ? { - fragment: { - package: query.packageRevisionId, - id: checked.declaration.id, - digest: checked.definitionDigest, - }, - } - : {}), - placement: checked.declaration.placement?.kind ?? "remote", - source: - checked.declaration.placement?.kind === "local" - ? JSON.stringify([query.packageRevisionId, checked.declaration.placement.sourceQueryId]) - : null, - root: checked.declaration.root, - atoms: query.rootAtoms, - variables: portableValueSchema(checked.variables), - defaults: checked.variableDefaults, - selection: lowerTypes(checked.selection), - budgets: checked.declaration.budgets, - fields: query.fields.map((field) => { - const member = interfaces - .find((i) => i.revisionId === field.interfaceRevisionId)! - .members.find((m) => m.id === field.memberId)!; - return { - atom: field.atomId, - interface: field.interfaceRevisionId, - member: field.memberId, - name: member.displayName, - operation: JSON.stringify([field.atomId, field.interfaceRevisionId, field.getter]), - }; - }), - admittedOperations, - }; - }), + queries: [ + ...compileInspectionTemplates(plan).queries, + ...plan.definition.queries.map(({ id, query, admittedOperations }) => { + const checked = query.checked; + return { + id, + ...(checked.declaration.fragment && !checked.declaration.fragment.admission + ? { + fragment: { + package: query.packageRevisionId, + id: checked.declaration.id, + digest: checked.definitionDigest, + }, + } + : {}), + placement: checked.declaration.placement?.kind ?? "remote", + source: + checked.declaration.placement?.kind === "local" + ? JSON.stringify([query.packageRevisionId, checked.declaration.placement.sourceQueryId]) + : null, + root: checked.declaration.root, + atoms: query.rootAtoms, + variables: portableValueSchema(checked.variables), + defaults: checked.variableDefaults, + selection: lowerTypes(checked.selection), + budgets: checked.declaration.budgets, + fields: query.fields.map((field) => { + const member = interfaces + .find((i) => i.revisionId === field.interfaceRevisionId)! + .members.find((m) => m.id === field.memberId)!; + return { + atom: field.atomId, + interface: field.interfaceRevisionId, + member: field.memberId, + name: member.displayName, + operation: JSON.stringify([field.atomId, field.interfaceRevisionId, field.getter]), + }; + }), + admittedOperations, + }; + }), + ], }; } diff --git a/test/inspection.test.ts b/test/inspection.test.ts new file mode 100644 index 0000000..4f416d7 --- /dev/null +++ b/test/inspection.test.ts @@ -0,0 +1,35 @@ +import assert from "node:assert/strict"; +import { test } from "node:test"; +import { loadReaderWorkspace } from "./reader-fixture.js"; +import { compileExecutionPlan, compileQueryProgram } from "../src/execution-world/index.js"; +import { compileInspectionTemplates } from "../src/execution-world/inspection.js"; +test("public member inspection installs a finite set of typed lazy templates", async () => { + const plan = compileExecutionPlan(await loadReaderWorkspace()); + const result = compileInspectionTemplates(plan); + assert.ok(result.templates.length); + const document = result.templates.find( + (template) => + template.members.some((member) => member.name === "content") && + template.members.some((member) => member.name === "highlights"), + )!; + assert.ok(document.inputs && document.view && document.server); + assert.equal(document.view.sourceQuery, document.inputs.query); + assert.ok(document.members.find((member) => member.name === "highlights")?.many); + assert.ok(!document.members.some((member) => member.name === "revise")); + const compiled = compileQueryProgram(plan) as { + queries: { id: string; selection: { selection: { conditions: unknown[] }[] }[] }[]; + }; + for (const descriptor of result.contracts) { + const query = compiled.queries.find( + (query) => query.id === JSON.stringify([descriptor.package, descriptor.query]), + )!; + assert.ok(query); + assert.ok( + query.selection[0]!.selection.every((field) => field.conditions.length === 1), + "Each field admission is independently selected", + ); + } + assert.ok(!JSON.stringify(result.templates).includes("slot:")); + assert.equal(result.queries.length, result.contracts.length); + assert.ok(result.queries.length <= plan.definition.workspace.interfaceImports.length * 3); +});