From 17f6941f64a10e1c173b8554d794a45d98698588 Mon Sep 17 00:00:00 2001 From: "Timothy J. Aveni" Date: Thu, 17 Sep 2026 11:29:56 -0700 Subject: [PATCH] Add exact runtime conformance lookup and agent-visible language limits --- proto/quixos/orch.proto | 11 ++++ proto/quixos/refs.proto | 10 +++ src/bindings/generics.ts | 6 +- src/bindings/index.ts | 60 ++++++++++++------ src/bindings/react-platform.ts | 6 ++ src/bindings/react.ts | 23 ++++++- src/gen/quixos/orch_pb.ts | 107 ++++++++++++++++++++++++--------- src/gen/quixos/refs_pb.ts | 52 ++++++++++++++-- test/generic-packages.test.ts | 96 ++++++++++++++++++++++++++++- test/react-fields.test.ts | 12 +++- 10 files changed, 328 insertions(+), 55 deletions(-) diff --git a/proto/quixos/orch.proto b/proto/quixos/orch.proto index cabf65c..d454d78 100644 --- a/proto/quixos/orch.proto +++ b/proto/quixos/orch.proto @@ -8,6 +8,7 @@ import "quixos/refs.proto"; import "quixos/runtime.proto"; service OrchestratorRuntime { + rpc TryConform(TryConformRequest) returns (TryConformResponse); rpc InvokeCapability(InvokeCapabilityRequest) returns (InvokeCapabilityResponse); rpc EditCapabilityField(EditCapabilityFieldRequest) returns (InvokeCapabilityResponse); rpc InvokeClassCapability(InvokeClassCapabilityRequest) returns (InvokeCapabilityResponse); @@ -22,6 +23,16 @@ service OrchestratorRuntime { rpc CloseActivation(CloseActivationRequest) returns (CloseActivationResponse); } +// Exact closed interface lookup; no policy selection or competing conformances. +message TryConformRequest { + string object_id = 1; + string interface_revision_id = 2; +} +message TryConformResponse { + // Absent only when this object lacks a known contract. Other failures are errors. + quixos.ConformanceWitness conformance = 1; +} + message ConstructObjectRequest { string atom_id = 1; map input = 2; diff --git a/proto/quixos/refs.proto b/proto/quixos/refs.proto index 1227b6c..9213cea 100644 --- a/proto/quixos/refs.proto +++ b/proto/quixos/refs.proto @@ -5,6 +5,16 @@ package quixos; message CapabilityRef { string interface_revision_id = 1; string operation_id = 2; + // Optional fence for a view acquired through TryConform. Not an authority grant. + ConformanceWitness conformance = 3; +} + +message ConformanceWitness { + string object_id = 1; + string interface_revision_id = 2; + string conformance_id = 3; + string workspace_revision_id = 4; + string workspace_epoch = 5; } message PackageExportRef { diff --git a/src/bindings/generics.ts b/src/bindings/generics.ts index f9d8f1a..e2fa66a 100644 --- a/src/bindings/generics.ts +++ b/src/bindings/generics.ts @@ -127,7 +127,7 @@ export const genericImplementationType = ( .filter((op) => op.mode === "call" && op.scope !== "class") .map((op) => ({ ...op, name: `${member.displayName}.${op.displayName}` })), ); - return object([ + const methods: [string, string][] = [ ["objectId", `QxObjectRef<${target({ kind: "application", application: requirement.application }, scope)}>`], ["live", object(operations.map((op) => [op.name, `(${params(op.inputType, local)})=>Promise`]))], ...operations.map( @@ -137,7 +137,8 @@ export const genericImplementationType = ( string, ], ), - ]); + ]; + return object([...methods, ["contract", `QxInterfaceContract<${object(methods)}>`]]); } } }; @@ -146,6 +147,7 @@ export const genericImplementationType = ( .join(","); const receiver = definition.receiverRequirement; const context = object([ + ["conform", "QxConformer"], ...(definition.kind === "function" ? [] : [ diff --git a/src/bindings/index.ts b/src/bindings/index.ts index 5043659..00d20a6 100644 --- a/src/bindings/index.ts +++ b/src/bindings/index.ts @@ -7,6 +7,7 @@ import type { } from "../capability-model/types.js"; import type { CompiledCapabilityResourceRepository } from "../capability-language/assembly.js"; import { genericImplementationType } from "./generics.js"; +import { capabilityId } from "../capability-model/types.js"; /** Portable generator input. New backends consume this instead of the parser or TS runtime. */ export type BindingSchema = { @@ -183,26 +184,28 @@ export const generateTypeScriptBindings = ( .filter((operation) => operation.mode === "call" && operation.scope !== "class") .map((operation) => ({ ...operation, name: `${member.displayName}.${operation.displayName}` })), ); - return { - type: object([ - ["objectId", ref({ kind: "interface", interfaceRevisionId: requirement.interfaceRevisionId })], - [ - "live", - object( - operations.map((operation) => [ - operation.name, - `(${params(operation.inputType)}) => Promise`, - ]), - ), - ], - ...operations.map((operation): [string, string] => [ - operation.name, - `(${params(operation.inputType)}) => Promise<${type(operation.outputType)}>`, - ]), + const methods: [string, string][] = [ + ["objectId", ref({ kind: "interface", interfaceRevisionId: requirement.interfaceRevisionId })], + [ + "live", + object( + operations.map((operation) => [ + operation.name, + `(${params(operation.inputType)}) => Promise`, + ]), + ), + ], + ...operations.map((operation): [string, string] => [ + operation.name, + `(${params(operation.inputType)}) => Promise<${type(operation.outputType)}>`, ]), + ]; + return { + type: object([...methods, ["contract", `QxInterfaceContract<${object(methods)}>`]]), spec: { kind: "interface", id: entry.id, + interfaceRevisionId: requirement.interfaceRevisionId, operations: Object.fromEntries( operations.map(({ name, id, inputType, outputType }) => [name, { id, inputType, outputType }]), ), @@ -245,6 +248,7 @@ export const generateTypeScriptBindings = ( ? `QxObjectRef<${entry.receiverRequirement.interfaceRevisionIds.map((id) => q(`interface:${id}`)).join(" | ") || "never"}>` : "QxObjectRef"; const contextShape = object([ + ["conform", "QxConformer"], ...(entry.kind === "function" ? [] : [["objectId", receiver] as [string, string]]), ["input", type(entry.inputType)], ["ports", object(ports.map((port) => [port.name, port.type]))], @@ -281,13 +285,26 @@ export const generateTypeScriptBindings = ( genericImplementationType(definition, [...schema.interfaces, ...(schema.interfaceTemplates ?? [])], type), ]); } + const contracts = schema.interfaces.map((iface) => { + const generated = port({ + id: capabilityId.dependencyPort("contract"), + displayName: iface.displayName, + requirement: { kind: "interface", interfaceRevisionId: iface.revisionId }, + }); + const spec = generated.spec as { operations: unknown }; + return { + iface, + type: generated.type, + code: `defineQxInterfaceContract<${generated.type}>(${q(iface.revisionId)}, ${JSON.stringify(spec.operations)})`, + }; + }); const imports = [...messages].map(([id, alias]) => { const binding = options.messages![id]!; if (!/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(binding.export)) throw new Error(`Invalid message binding export ${binding.export}`); return `import { ${binding.export} as ${alias} } from ${q(binding.module)};`; }); - const signatures = `${object(contexts)} ${object(handlers)} ${object(results)}`; + const signatures = `${object(contexts)} ${object(handlers)} ${object(results)} ${contracts.map((entry) => entry.type).join(" ")}`; const typeImports = [ "BindingValue", "QxObjectRef", @@ -295,17 +312,24 @@ export const generateTypeScriptBindings = ( "QxHandler", "QxDerived", "QxContextLifecycle", + "QxConformer", + "QxInterfaceContract", "QxLiveValue", "RelationshipCollection", "RelationshipEntry", ].filter((name) => new RegExp(`\\b${name}\\b`).test(signatures)); return ( `// Generated by quixos-codegen-ts. Do not edit. Binding ABI version 1.\n` + - `import { ${exports.length ? "bindQxHandler, " : ""}${[...typeImports, "QxHandlerSpec", "QxMessages"].map((name) => `type ${name}`).join(", ")} } from ${q(options.runtimeModule ?? "@quixos/camino-package-runtime")};\n` + + `import { ${contracts.length ? "defineQxInterfaceContract, " : ""}${exports.length ? "bindQxHandler, " : ""}${[...typeImports, "QxHandlerSpec", "QxMessages"].map((name) => `type ${name}`).join(", ")} } from ${q(options.runtimeModule ?? "@quixos/camino-package-runtime")};\n` + imports.join("\n") + `\nexport const packageRevisionId = ${q(pkg.revisionId)};\n` + `declare const appliedType: unique symbol;\ntype QxApplied = string & {readonly [appliedType]: (value: [Definition, Arguments]) => [Definition, Arguments]};\n` + `export type Contexts = ${object(contexts)};\nexport type Results = ${object(results)};\nexport type Implementation = ${object(handlers)};\n` + + `export const contracts = {${contracts.map((entry) => `${q(entry.iface.revisionId)}: ${entry.code}`).join(",\n")}};\n` + + `export const interfaces = {${contracts + .filter((entry) => contracts.filter((other) => other.iface.displayName === entry.iface.displayName).length === 1) + .map((entry) => `${q(entry.iface.displayName)}: contracts[${q(entry.iface.revisionId)}]`) + .join(",\n")}};\n` + `const messages = { ${[...messages].map(([id, alias]) => `${q(id)}: ${alias}`).join(", ")} } satisfies QxMessages;\n` + `const specs = ${JSON.stringify(specs, null, 2)} satisfies Record;\n` + `export const createRuntime = (implementation: Implementation) => ({\n packageRevisionId,\n exports: {\n` + diff --git a/src/bindings/react-platform.ts b/src/bindings/react-platform.ts index d674291..8485915 100644 --- a/src/bindings/react-platform.ts +++ b/src/bindings/react-platform.ts @@ -15,6 +15,12 @@ declare module "@quixos/web-studio-react-runtime" { export type WritableField = ReadableField & {readonly $writeType?: (value: T) => T; readonly writable: true; readonly capability: FieldCapability & {setOperationId: string}}; export type LiveFieldProp = ReadableField; export type InterfaceReference = {readonly $quixosRef: string; readonly interfaceRevisionId: I; readonly fields: Fields}; + const conformanceView: unique symbol; + export type ReactInterfaceContract = {readonly interfaceRevisionId: string; readonly [conformanceView]: (view: View) => View}; + export function defineReactInterfaceContract(interfaceRevisionId: string, interfaces: unknown): ReactInterfaceContract; + export function tryConform(object: string | {readonly $quixosRef: string}, contract: ReactInterfaceContract, options?: {signal?: AbortSignal}): Promise; + export type ConformanceResult = {status: "loading"} | {status: "absent"} | {status: "available"; view: View} | {status: "error"; error: Error}; + export function useTryConform(object: string | {readonly $quixosRef: string}, contract: ReactInterfaceContract): ConformanceResult; export type ReactComponentHostProps = { onAction?: (action: Action) => void; fallback?: React.ReactNode; diff --git a/src/bindings/react.ts b/src/bindings/react.ts index f34cab3..020f71f 100644 --- a/src/bindings/react.ts +++ b/src/bindings/react.ts @@ -78,8 +78,29 @@ export function generateReactBindings( throw new Error("React component check must name a local module relative to generated bindings"); return `type Component${i} = CheckedComponent<${q(component.propsExport)}, typeof import(${q(component.module)})["default"]>;`; }); + const contracts = schema.interfaces.map((iface) => { + const reference = type({ + kind: "object-ref", + expectation: { kind: "interface", interfaceRevisionId: iface.revisionId }, + }); + const calls = iface.members.flatMap((member) => + member.operations + .filter((operation) => operation.mode === "call" && operation.scope !== "class") + .map( + (operation) => + `${q(`${member.displayName}.${operation.displayName}`)}: (${operation.inputType.kind === "builtin" && operation.inputType.name === "unit" ? "" : `input: ${type(operation.inputType)}`}) => Promise<${type(operation.outputType)}>`, + ), + ); + return { iface, view: `${reference} & {call: {${calls.join(";")}}}` }; + }); return ( - `// Generated from checked QX contracts. Do not edit.\nimport type {ObjectRef, InterfaceReference, ReadableField, WritableField} from "@quixos/web-studio-react-runtime";\n${declarations.join("\n")}\nexport type ReactResults = {${results.join(";\n")}};\n` + + `// Generated from checked QX contracts. Do not edit.\nimport {defineReactInterfaceContract} from "@quixos/web-studio-react-runtime";\nimport type {ObjectRef, InterfaceReference, ReadableField, WritableField} from "@quixos/web-studio-react-runtime";\n${declarations.join("\n")}\nexport type ReactResults = {${results.join(";\n")}};\n` + + `const contractsData = ${JSON.stringify(schema.interfaces)};\n` + + `export const reactContracts = {${contracts.map(({ iface, view }) => `${q(iface.revisionId)}: defineReactInterfaceContract<${view}>(${q(iface.revisionId)}, contractsData)`).join(",\n")}};\n` + + `export const reactInterfaces = {${contracts + .filter(({ iface }) => contracts.filter((other) => other.iface.displayName === iface.displayName).length === 1) + .map(({ iface }) => `${q(iface.displayName)}: reactContracts[${q(iface.revisionId)}]`) + .join(",\n")}};\n` + (checks.length ? `type CheckedComponent void}) => unknown> = C;\n${checks.join("\n")}\n` : "") diff --git a/src/gen/quixos/orch_pb.ts b/src/gen/quixos/orch_pb.ts index 3b5f13a..f699575 100644 --- a/src/gen/quixos/orch_pb.ts +++ b/src/gen/quixos/orch_pb.ts @@ -8,7 +8,7 @@ import type { CaminoObject, CrdtValue, Value } from "../camino/api_pb.js"; import { file_camino_api } from "../camino/api_pb.js"; import type { PackageDescriptor } from "./package_pb.js"; import { file_quixos_package } from "./package_pb.js"; -import type { CapabilityRef, PackageExportRef } from "./refs_pb.js"; +import type { CapabilityRef, ConformanceWitness, PackageExportRef } from "./refs_pb.js"; import { file_quixos_refs } from "./refs_pb.js"; import type { DerivedDependency } from "./runtime_pb.js"; import { file_quixos_runtime } from "./runtime_pb.js"; @@ -18,7 +18,50 @@ import type { Message } from "@bufbuild/protobuf"; * Describes the file quixos/orch.proto. */ export const file_quixos_orch: GenFile = /*@__PURE__*/ - fileDesc("ChFxdWl4b3Mvb3JjaC5wcm90bxILcXVpeG9zLm9yY2gipQEKFkNvbnN0cnVjdE9iamVjdFJlcXVlc3QSDwoHYXRvbV9pZBgBIAEoCRI9CgVpbnB1dBgCIAMoCzIuLnF1aXhvcy5vcmNoLkNvbnN0cnVjdE9iamVjdFJlcXVlc3QuSW5wdXRFbnRyeRo7CgpJbnB1dEVudHJ5EgsKA2tleRgBIAEoCRIcCgV2YWx1ZRgCIAEoCzINLmNhbWluby5WYWx1ZToCOAEiPwoXQ29uc3RydWN0T2JqZWN0UmVzcG9uc2USJAoGb2JqZWN0GAEgASgLMhQuY2FtaW5vLkNhbWlub09iamVjdCJtCiZSZXNvbHZlT3JDb25zdHJ1Y3RSZWxhdGVkT2JqZWN0UmVxdWVzdBIRCglvYmplY3RfaWQYASABKAkSHQoVaW50ZXJmYWNlX3JldmlzaW9uX2lkGAIgASgJEhEKCW1lbWJlcl9pZBgDIAEoCSJkCidSZXNvbHZlT3JDb25zdHJ1Y3RSZWxhdGVkT2JqZWN0UmVzcG9uc2USJAoGb2JqZWN0GAEgASgLMhQuY2FtaW5vLkNhbWlub09iamVjdBITCgtjb25zdHJ1Y3RlZBgCIAEoCCLwAQoXSW52b2tlQ2FwYWJpbGl0eVJlcXVlc3QSKQoKY2FwYWJpbGl0eRgBIAEoCzIVLnF1aXhvcy5DYXBhYmlsaXR5UmVmEhEKCW9iamVjdF9pZBgCIAEoCRI+CgVpbnB1dBgDIAMoCzIvLnF1aXhvcy5vcmNoLkludm9rZUNhcGFiaWxpdHlSZXF1ZXN0LklucHV0RW50cnkSGgoSY2xpZW50X211dGF0aW9uX2lkGAQgASgJGjsKCklucHV0RW50cnkSCwoDa2V5GAEgASgJEhwKBXZhbHVlGAIgASgLMg0uY2FtaW5vLlZhbHVlOgI4ASLOAQocSW52b2tlQ2xhc3NDYXBhYmlsaXR5UmVxdWVzdBIWCg5jb25mb3JtYW5jZV9pZBgBIAEoCRIUCgxvcGVyYXRpb25faWQYAiABKAkSQwoFaW5wdXQYAyADKAsyNC5xdWl4b3Mub3JjaC5JbnZva2VDbGFzc0NhcGFiaWxpdHlSZXF1ZXN0LklucHV0RW50cnkaOwoKSW5wdXRFbnRyeRILCgNrZXkYASABKAkSHAoFdmFsdWUYAiABKAsyDS5jYW1pbm8uVmFsdWU6AjgBIoMCChhJbnZva2VDYXBhYmlsaXR5UmVzcG9uc2USFQoNaW52b2NhdGlvbl9pZBgBIAEoCRIrCgphY3RpdmF0aW9uGAIgASgLMhcucXVpeG9zLm9yY2guQWN0aXZhdGlvbhIKCgJvaxgDIAEoCBIdCgZyZXN1bHQYBCABKAsyDS5jYW1pbm8uVmFsdWUSDQoFZXJyb3IYBSABKAkSNwoMZGVwZW5kZW5jaWVzGAYgAygLMiEucXVpeG9zLnJ1bnRpbWUuRGVyaXZlZERlcGVuZGVuY3kSMAoNZmllbGRfZWRpdGluZxgHIAEoCzIZLnF1aXhvcy5vcmNoLkZpZWxkRWRpdGluZyJ3CgxGaWVsZEVkaXRpbmcSGwoTZ2V0dGVyX29wZXJhdGlvbl9pZBgBIAEoCRIbChNzZXR0ZXJfb3BlcmF0aW9uX2lkGAIgASgJEhUKDWRvY3VtZW50X3R5cGUYAyABKAkSFgoOYmluZGluZ19kaWdlc3QYBCABKAkizgEKGkVkaXRDYXBhYmlsaXR5RmllbGRSZXF1ZXN0EikKCmNhcGFiaWxpdHkYASABKAsyFS5xdWl4b3MuQ2FwYWJpbGl0eVJlZhIRCglvYmplY3RfaWQYAiABKAkSGwoTc2V0dGVyX29wZXJhdGlvbl9pZBgDIAEoCRIWCg5iaW5kaW5nX2RpZ2VzdBgEIAEoCRIhCgZ1cGRhdGUYBSABKAsyES5jYW1pbm8uQ3JkdFZhbHVlEhoKEmNsaWVudF9tdXRhdGlvbl9pZBgGIAEoCSLSAQoWV2F0Y2hDYXBhYmlsaXR5UmVxdWVzdBIpCgpjYXBhYmlsaXR5GAEgASgLMhUucXVpeG9zLkNhcGFiaWxpdHlSZWYSEQoJb2JqZWN0X2lkGAIgASgJEj0KBWlucHV0GAMgAygLMi4ucXVpeG9zLm9yY2guV2F0Y2hDYXBhYmlsaXR5UmVxdWVzdC5JbnB1dEVudHJ5GjsKCklucHV0RW50cnkSCwoDa2V5GAEgASgJEhwKBXZhbHVlGAIgASgLMg0uY2FtaW5vLlZhbHVlOgI4ASKVAgoUV2F0Y2hDYXBhYmlsaXR5RXZlbnQSFQoNaW52b2NhdGlvbl9pZBgBIAEoCRIrCgphY3RpdmF0aW9uGAIgASgLMhcucXVpeG9zLm9yY2guQWN0aXZhdGlvbhIQCgh3YXRjaF9pZBgDIAEoCRIcCgV2YWx1ZRgEIAEoCzINLmNhbWluby5WYWx1ZRI3CgxkZXBlbmRlbmNpZXMYBSADKAsyIS5xdWl4b3MucnVudGltZS5EZXJpdmVkRGVwZW5kZW5jeRINCgVlcnJvchgGIAEoCRIPCgdpbml0aWFsGAcgASgIEjAKDWZpZWxkX2VkaXRpbmcYCCABKAsyGS5xdWl4b3Mub3JjaC5GaWVsZEVkaXRpbmciOgoTR2V0V29ya3NwYWNlUmVxdWVzdBIjChtpbmNsdWRlX2ludGVyZmFjZV9jb250cmFjdHMYASABKAgi6gIKFEdldFdvcmtzcGFjZVJlc3BvbnNlEhQKDHdvcmtzcGFjZV9pZBgBIAEoCRIdChV3b3Jrc3BhY2VfcmV2aXNpb25faWQYAiABKAkSGgoSc291cmNlX3Jvb3RfY29tbWl0GAMgASgJEioKImVtcHR5X2lucHV0X2NvbnN0cnVjdGlibGVfYXRvbV9pZHMYBCADKAkSPwoRY2FwYWJpbGl0eV9pbnB1dHMYBSADKAsyJC5xdWl4b3Mub3JjaC5DYXBhYmlsaXR5SW5wdXRDb250cmFjdBJBChJjb25zdHJ1Y3Rvcl9pbnB1dHMYBiADKAsyJS5xdWl4b3Mub3JjaC5Db25zdHJ1Y3RvcklucHV0Q29udHJhY3QSFwoPaW50ZXJmYWNlc19qc29uGAcgASgJEjgKEmNsYXNzX2NhcGFiaWxpdGllcxgIIAMoCzIcLnF1aXhvcy5vcmNoLkNsYXNzQ2FwYWJpbGl0eSK5AQoPQ2xhc3NDYXBhYmlsaXR5EhYKDmNvbmZvcm1hbmNlX2lkGAEgASgJEg8KB2F0b21faWQYAiABKAkSHQoVaW50ZXJmYWNlX3JldmlzaW9uX2lkGAMgASgJEhUKDWRlZmluaXRpb25faWQYBCABKAkSFAoMb3BlcmF0aW9uX2lkGAUgASgJEhcKD2lucHV0X3R5cGVfanNvbhgGIAEoCRIYChBvdXRwdXRfdHlwZV9qc29uGAcgASgJImEKF0NhcGFiaWxpdHlJbnB1dENvbnRyYWN0Eh0KFWludGVyZmFjZV9yZXZpc2lvbl9pZBgBIAEoCRIUCgxvcGVyYXRpb25faWQYAiABKAkSEQoJdHlwZV9qc29uGAMgASgJIj4KGENvbnN0cnVjdG9ySW5wdXRDb250cmFjdBIPCgdhdG9tX2lkGAEgASgJEhEKCXR5cGVfanNvbhgCIAEoCSIYChZMaXN0QWN0aXZhdGlvbnNSZXF1ZXN0Ih8KHUxpc3RQYWNrYWdlRGVzY3JpcHRvcnNSZXF1ZXN0IlAKHkxpc3RQYWNrYWdlRGVzY3JpcHRvcnNSZXNwb25zZRIuCgtkZXNjcmlwdG9ycxgBIAMoCzIZLnF1aXhvcy5QYWNrYWdlRGVzY3JpcHRvciIcChpMaXN0UGFja2FnZVJ1bnRpbWVzUmVxdWVzdCJSChtMaXN0UGFja2FnZVJ1bnRpbWVzUmVzcG9uc2USMwoIcnVudGltZXMYASADKAsyIS5xdWl4b3Mub3JjaC5QYWNrYWdlUnVudGltZVN0YXR1cyJHChdMaXN0QWN0aXZhdGlvbnNSZXNwb25zZRIsCgthY3RpdmF0aW9ucxgBIAMoCzIXLnF1aXhvcy5vcmNoLkFjdGl2YXRpb24iPwoWQ2xvc2VBY3RpdmF0aW9uUmVxdWVzdBIVCg1hY3RpdmF0aW9uX2lkGAEgASgJEg4KBnJlYXNvbhgCIAEoCSJGChdDbG9zZUFjdGl2YXRpb25SZXNwb25zZRIrCgphY3RpdmF0aW9uGAEgASgLMhcucXVpeG9zLm9yY2guQWN0aXZhdGlvbiLrAQoKQWN0aXZhdGlvbhIVCg1hY3RpdmF0aW9uX2lkGAEgASgJEigKBmV4cG9ydBgCIAEoCzIYLnF1aXhvcy5QYWNrYWdlRXhwb3J0UmVmEhEKCW9iamVjdF9pZBgDIAEoCRINCgVzdGF0ZRgEIAEoCRIOCgZkZW1hbmQYBSABKA0SEQoJb3BlbmVkX2F0GAYgASgJEhQKDGxhc3RfdXNlZF9hdBgHIAEoCRIYChBpZGxlX2RlYWRsaW5lX2F0GAggASgJEhEKCWNsb3NlZF9hdBgJIAEoCRIUCgxjbG9zZV9yZWFzb24YCiABKAkiswIKFFBhY2thZ2VSdW50aW1lU3RhdHVzEhMKC3J1bnRpbWVfa2V5GAEgASgJEhsKE3BhY2thZ2VfcmV2aXNpb25faWQYAiABKAkSGQoRc291cmNlX3JlcG9zaXRvcnkYAyABKAkSFQoNc291cmNlX2NvbW1pdBgEIAEoCRIUCgxidWlsZF90YXJnZXQYBSABKAkSEwoLc2VydmVyX3BhdGgYBiABKAkSCwoDcGlkGAcgASgNEg0KBXN0YXRlGAggASgJEhIKCnN0YXJ0ZWRfYXQYCSABKAkSGQoRbGFzdF9oYW5kc2hha2VfYXQYCiABKAkSIAoYcnVudGltZV9wcm90b2NvbF92ZXJzaW9uGAsgASgJEh8KF2FkdmVydGlzZWRfZXhwb3J0X2NvdW50GAwgASgNMoAJChNPcmNoZXN0cmF0b3JSdW50aW1lEl8KEEludm9rZUNhcGFiaWxpdHkSJC5xdWl4b3Mub3JjaC5JbnZva2VDYXBhYmlsaXR5UmVxdWVzdBolLnF1aXhvcy5vcmNoLkludm9rZUNhcGFiaWxpdHlSZXNwb25zZRJlChNFZGl0Q2FwYWJpbGl0eUZpZWxkEicucXVpeG9zLm9yY2guRWRpdENhcGFiaWxpdHlGaWVsZFJlcXVlc3QaJS5xdWl4b3Mub3JjaC5JbnZva2VDYXBhYmlsaXR5UmVzcG9uc2USaQoVSW52b2tlQ2xhc3NDYXBhYmlsaXR5EikucXVpeG9zLm9yY2guSW52b2tlQ2xhc3NDYXBhYmlsaXR5UmVxdWVzdBolLnF1aXhvcy5vcmNoLkludm9rZUNhcGFiaWxpdHlSZXNwb25zZRJbCg9XYXRjaENhcGFiaWxpdHkSIy5xdWl4b3Mub3JjaC5XYXRjaENhcGFiaWxpdHlSZXF1ZXN0GiEucXVpeG9zLm9yY2guV2F0Y2hDYXBhYmlsaXR5RXZlbnQwARJcCg9Db25zdHJ1Y3RPYmplY3QSIy5xdWl4b3Mub3JjaC5Db25zdHJ1Y3RPYmplY3RSZXF1ZXN0GiQucXVpeG9zLm9yY2guQ29uc3RydWN0T2JqZWN0UmVzcG9uc2USjAEKH1Jlc29sdmVPckNvbnN0cnVjdFJlbGF0ZWRPYmplY3QSMy5xdWl4b3Mub3JjaC5SZXNvbHZlT3JDb25zdHJ1Y3RSZWxhdGVkT2JqZWN0UmVxdWVzdBo0LnF1aXhvcy5vcmNoLlJlc29sdmVPckNvbnN0cnVjdFJlbGF0ZWRPYmplY3RSZXNwb25zZRJTCgxHZXRXb3Jrc3BhY2USIC5xdWl4b3Mub3JjaC5HZXRXb3Jrc3BhY2VSZXF1ZXN0GiEucXVpeG9zLm9yY2guR2V0V29ya3NwYWNlUmVzcG9uc2UScQoWTGlzdFBhY2thZ2VEZXNjcmlwdG9ycxIqLnF1aXhvcy5vcmNoLkxpc3RQYWNrYWdlRGVzY3JpcHRvcnNSZXF1ZXN0GisucXVpeG9zLm9yY2guTGlzdFBhY2thZ2VEZXNjcmlwdG9yc1Jlc3BvbnNlEmgKE0xpc3RQYWNrYWdlUnVudGltZXMSJy5xdWl4b3Mub3JjaC5MaXN0UGFja2FnZVJ1bnRpbWVzUmVxdWVzdBooLnF1aXhvcy5vcmNoLkxpc3RQYWNrYWdlUnVudGltZXNSZXNwb25zZRJcCg9MaXN0QWN0aXZhdGlvbnMSIy5xdWl4b3Mub3JjaC5MaXN0QWN0aXZhdGlvbnNSZXF1ZXN0GiQucXVpeG9zLm9yY2guTGlzdEFjdGl2YXRpb25zUmVzcG9uc2USXAoPQ2xvc2VBY3RpdmF0aW9uEiMucXVpeG9zLm9yY2guQ2xvc2VBY3RpdmF0aW9uUmVxdWVzdBokLnF1aXhvcy5vcmNoLkNsb3NlQWN0aXZhdGlvblJlc3BvbnNlYgZwcm90bzM", [file_camino_api, file_quixos_package, file_quixos_refs, file_quixos_runtime]); + fileDesc("ChFxdWl4b3Mvb3JjaC5wcm90bxILcXVpeG9zLm9yY2giRQoRVHJ5Q29uZm9ybVJlcXVlc3QSEQoJb2JqZWN0X2lkGAEgASgJEh0KFWludGVyZmFjZV9yZXZpc2lvbl9pZBgCIAEoCSJFChJUcnlDb25mb3JtUmVzcG9uc2USLwoLY29uZm9ybWFuY2UYASABKAsyGi5xdWl4b3MuQ29uZm9ybWFuY2VXaXRuZXNzIqUBChZDb25zdHJ1Y3RPYmplY3RSZXF1ZXN0Eg8KB2F0b21faWQYASABKAkSPQoFaW5wdXQYAiADKAsyLi5xdWl4b3Mub3JjaC5Db25zdHJ1Y3RPYmplY3RSZXF1ZXN0LklucHV0RW50cnkaOwoKSW5wdXRFbnRyeRILCgNrZXkYASABKAkSHAoFdmFsdWUYAiABKAsyDS5jYW1pbm8uVmFsdWU6AjgBIj8KF0NvbnN0cnVjdE9iamVjdFJlc3BvbnNlEiQKBm9iamVjdBgBIAEoCzIULmNhbWluby5DYW1pbm9PYmplY3QibQomUmVzb2x2ZU9yQ29uc3RydWN0UmVsYXRlZE9iamVjdFJlcXVlc3QSEQoJb2JqZWN0X2lkGAEgASgJEh0KFWludGVyZmFjZV9yZXZpc2lvbl9pZBgCIAEoCRIRCgltZW1iZXJfaWQYAyABKAkiZAonUmVzb2x2ZU9yQ29uc3RydWN0UmVsYXRlZE9iamVjdFJlc3BvbnNlEiQKBm9iamVjdBgBIAEoCzIULmNhbWluby5DYW1pbm9PYmplY3QSEwoLY29uc3RydWN0ZWQYAiABKAgi8AEKF0ludm9rZUNhcGFiaWxpdHlSZXF1ZXN0EikKCmNhcGFiaWxpdHkYASABKAsyFS5xdWl4b3MuQ2FwYWJpbGl0eVJlZhIRCglvYmplY3RfaWQYAiABKAkSPgoFaW5wdXQYAyADKAsyLy5xdWl4b3Mub3JjaC5JbnZva2VDYXBhYmlsaXR5UmVxdWVzdC5JbnB1dEVudHJ5EhoKEmNsaWVudF9tdXRhdGlvbl9pZBgEIAEoCRo7CgpJbnB1dEVudHJ5EgsKA2tleRgBIAEoCRIcCgV2YWx1ZRgCIAEoCzINLmNhbWluby5WYWx1ZToCOAEizgEKHEludm9rZUNsYXNzQ2FwYWJpbGl0eVJlcXVlc3QSFgoOY29uZm9ybWFuY2VfaWQYASABKAkSFAoMb3BlcmF0aW9uX2lkGAIgASgJEkMKBWlucHV0GAMgAygLMjQucXVpeG9zLm9yY2guSW52b2tlQ2xhc3NDYXBhYmlsaXR5UmVxdWVzdC5JbnB1dEVudHJ5GjsKCklucHV0RW50cnkSCwoDa2V5GAEgASgJEhwKBXZhbHVlGAIgASgLMg0uY2FtaW5vLlZhbHVlOgI4ASKDAgoYSW52b2tlQ2FwYWJpbGl0eVJlc3BvbnNlEhUKDWludm9jYXRpb25faWQYASABKAkSKwoKYWN0aXZhdGlvbhgCIAEoCzIXLnF1aXhvcy5vcmNoLkFjdGl2YXRpb24SCgoCb2sYAyABKAgSHQoGcmVzdWx0GAQgASgLMg0uY2FtaW5vLlZhbHVlEg0KBWVycm9yGAUgASgJEjcKDGRlcGVuZGVuY2llcxgGIAMoCzIhLnF1aXhvcy5ydW50aW1lLkRlcml2ZWREZXBlbmRlbmN5EjAKDWZpZWxkX2VkaXRpbmcYByABKAsyGS5xdWl4b3Mub3JjaC5GaWVsZEVkaXRpbmcidwoMRmllbGRFZGl0aW5nEhsKE2dldHRlcl9vcGVyYXRpb25faWQYASABKAkSGwoTc2V0dGVyX29wZXJhdGlvbl9pZBgCIAEoCRIVCg1kb2N1bWVudF90eXBlGAMgASgJEhYKDmJpbmRpbmdfZGlnZXN0GAQgASgJIs4BChpFZGl0Q2FwYWJpbGl0eUZpZWxkUmVxdWVzdBIpCgpjYXBhYmlsaXR5GAEgASgLMhUucXVpeG9zLkNhcGFiaWxpdHlSZWYSEQoJb2JqZWN0X2lkGAIgASgJEhsKE3NldHRlcl9vcGVyYXRpb25faWQYAyABKAkSFgoOYmluZGluZ19kaWdlc3QYBCABKAkSIQoGdXBkYXRlGAUgASgLMhEuY2FtaW5vLkNyZHRWYWx1ZRIaChJjbGllbnRfbXV0YXRpb25faWQYBiABKAki0gEKFldhdGNoQ2FwYWJpbGl0eVJlcXVlc3QSKQoKY2FwYWJpbGl0eRgBIAEoCzIVLnF1aXhvcy5DYXBhYmlsaXR5UmVmEhEKCW9iamVjdF9pZBgCIAEoCRI9CgVpbnB1dBgDIAMoCzIuLnF1aXhvcy5vcmNoLldhdGNoQ2FwYWJpbGl0eVJlcXVlc3QuSW5wdXRFbnRyeRo7CgpJbnB1dEVudHJ5EgsKA2tleRgBIAEoCRIcCgV2YWx1ZRgCIAEoCzINLmNhbWluby5WYWx1ZToCOAEilQIKFFdhdGNoQ2FwYWJpbGl0eUV2ZW50EhUKDWludm9jYXRpb25faWQYASABKAkSKwoKYWN0aXZhdGlvbhgCIAEoCzIXLnF1aXhvcy5vcmNoLkFjdGl2YXRpb24SEAoId2F0Y2hfaWQYAyABKAkSHAoFdmFsdWUYBCABKAsyDS5jYW1pbm8uVmFsdWUSNwoMZGVwZW5kZW5jaWVzGAUgAygLMiEucXVpeG9zLnJ1bnRpbWUuRGVyaXZlZERlcGVuZGVuY3kSDQoFZXJyb3IYBiABKAkSDwoHaW5pdGlhbBgHIAEoCBIwCg1maWVsZF9lZGl0aW5nGAggASgLMhkucXVpeG9zLm9yY2guRmllbGRFZGl0aW5nIjoKE0dldFdvcmtzcGFjZVJlcXVlc3QSIwobaW5jbHVkZV9pbnRlcmZhY2VfY29udHJhY3RzGAEgASgIIuoCChRHZXRXb3Jrc3BhY2VSZXNwb25zZRIUCgx3b3Jrc3BhY2VfaWQYASABKAkSHQoVd29ya3NwYWNlX3JldmlzaW9uX2lkGAIgASgJEhoKEnNvdXJjZV9yb290X2NvbW1pdBgDIAEoCRIqCiJlbXB0eV9pbnB1dF9jb25zdHJ1Y3RpYmxlX2F0b21faWRzGAQgAygJEj8KEWNhcGFiaWxpdHlfaW5wdXRzGAUgAygLMiQucXVpeG9zLm9yY2guQ2FwYWJpbGl0eUlucHV0Q29udHJhY3QSQQoSY29uc3RydWN0b3JfaW5wdXRzGAYgAygLMiUucXVpeG9zLm9yY2guQ29uc3RydWN0b3JJbnB1dENvbnRyYWN0EhcKD2ludGVyZmFjZXNfanNvbhgHIAEoCRI4ChJjbGFzc19jYXBhYmlsaXRpZXMYCCADKAsyHC5xdWl4b3Mub3JjaC5DbGFzc0NhcGFiaWxpdHkiuQEKD0NsYXNzQ2FwYWJpbGl0eRIWCg5jb25mb3JtYW5jZV9pZBgBIAEoCRIPCgdhdG9tX2lkGAIgASgJEh0KFWludGVyZmFjZV9yZXZpc2lvbl9pZBgDIAEoCRIVCg1kZWZpbml0aW9uX2lkGAQgASgJEhQKDG9wZXJhdGlvbl9pZBgFIAEoCRIXCg9pbnB1dF90eXBlX2pzb24YBiABKAkSGAoQb3V0cHV0X3R5cGVfanNvbhgHIAEoCSJhChdDYXBhYmlsaXR5SW5wdXRDb250cmFjdBIdChVpbnRlcmZhY2VfcmV2aXNpb25faWQYASABKAkSFAoMb3BlcmF0aW9uX2lkGAIgASgJEhEKCXR5cGVfanNvbhgDIAEoCSI+ChhDb25zdHJ1Y3RvcklucHV0Q29udHJhY3QSDwoHYXRvbV9pZBgBIAEoCRIRCgl0eXBlX2pzb24YAiABKAkiGAoWTGlzdEFjdGl2YXRpb25zUmVxdWVzdCIfCh1MaXN0UGFja2FnZURlc2NyaXB0b3JzUmVxdWVzdCJQCh5MaXN0UGFja2FnZURlc2NyaXB0b3JzUmVzcG9uc2USLgoLZGVzY3JpcHRvcnMYASADKAsyGS5xdWl4b3MuUGFja2FnZURlc2NyaXB0b3IiHAoaTGlzdFBhY2thZ2VSdW50aW1lc1JlcXVlc3QiUgobTGlzdFBhY2thZ2VSdW50aW1lc1Jlc3BvbnNlEjMKCHJ1bnRpbWVzGAEgAygLMiEucXVpeG9zLm9yY2guUGFja2FnZVJ1bnRpbWVTdGF0dXMiRwoXTGlzdEFjdGl2YXRpb25zUmVzcG9uc2USLAoLYWN0aXZhdGlvbnMYASADKAsyFy5xdWl4b3Mub3JjaC5BY3RpdmF0aW9uIj8KFkNsb3NlQWN0aXZhdGlvblJlcXVlc3QSFQoNYWN0aXZhdGlvbl9pZBgBIAEoCRIOCgZyZWFzb24YAiABKAkiRgoXQ2xvc2VBY3RpdmF0aW9uUmVzcG9uc2USKwoKYWN0aXZhdGlvbhgBIAEoCzIXLnF1aXhvcy5vcmNoLkFjdGl2YXRpb24i6wEKCkFjdGl2YXRpb24SFQoNYWN0aXZhdGlvbl9pZBgBIAEoCRIoCgZleHBvcnQYAiABKAsyGC5xdWl4b3MuUGFja2FnZUV4cG9ydFJlZhIRCglvYmplY3RfaWQYAyABKAkSDQoFc3RhdGUYBCABKAkSDgoGZGVtYW5kGAUgASgNEhEKCW9wZW5lZF9hdBgGIAEoCRIUCgxsYXN0X3VzZWRfYXQYByABKAkSGAoQaWRsZV9kZWFkbGluZV9hdBgIIAEoCRIRCgljbG9zZWRfYXQYCSABKAkSFAoMY2xvc2VfcmVhc29uGAogASgJIrMCChRQYWNrYWdlUnVudGltZVN0YXR1cxITCgtydW50aW1lX2tleRgBIAEoCRIbChNwYWNrYWdlX3JldmlzaW9uX2lkGAIgASgJEhkKEXNvdXJjZV9yZXBvc2l0b3J5GAMgASgJEhUKDXNvdXJjZV9jb21taXQYBCABKAkSFAoMYnVpbGRfdGFyZ2V0GAUgASgJEhMKC3NlcnZlcl9wYXRoGAYgASgJEgsKA3BpZBgHIAEoDRINCgVzdGF0ZRgIIAEoCRISCgpzdGFydGVkX2F0GAkgASgJEhkKEWxhc3RfaGFuZHNoYWtlX2F0GAogASgJEiAKGHJ1bnRpbWVfcHJvdG9jb2xfdmVyc2lvbhgLIAEoCRIfChdhZHZlcnRpc2VkX2V4cG9ydF9jb3VudBgMIAEoDTLPCQoTT3JjaGVzdHJhdG9yUnVudGltZRJNCgpUcnlDb25mb3JtEh4ucXVpeG9zLm9yY2guVHJ5Q29uZm9ybVJlcXVlc3QaHy5xdWl4b3Mub3JjaC5UcnlDb25mb3JtUmVzcG9uc2USXwoQSW52b2tlQ2FwYWJpbGl0eRIkLnF1aXhvcy5vcmNoLkludm9rZUNhcGFiaWxpdHlSZXF1ZXN0GiUucXVpeG9zLm9yY2guSW52b2tlQ2FwYWJpbGl0eVJlc3BvbnNlEmUKE0VkaXRDYXBhYmlsaXR5RmllbGQSJy5xdWl4b3Mub3JjaC5FZGl0Q2FwYWJpbGl0eUZpZWxkUmVxdWVzdBolLnF1aXhvcy5vcmNoLkludm9rZUNhcGFiaWxpdHlSZXNwb25zZRJpChVJbnZva2VDbGFzc0NhcGFiaWxpdHkSKS5xdWl4b3Mub3JjaC5JbnZva2VDbGFzc0NhcGFiaWxpdHlSZXF1ZXN0GiUucXVpeG9zLm9yY2guSW52b2tlQ2FwYWJpbGl0eVJlc3BvbnNlElsKD1dhdGNoQ2FwYWJpbGl0eRIjLnF1aXhvcy5vcmNoLldhdGNoQ2FwYWJpbGl0eVJlcXVlc3QaIS5xdWl4b3Mub3JjaC5XYXRjaENhcGFiaWxpdHlFdmVudDABElwKD0NvbnN0cnVjdE9iamVjdBIjLnF1aXhvcy5vcmNoLkNvbnN0cnVjdE9iamVjdFJlcXVlc3QaJC5xdWl4b3Mub3JjaC5Db25zdHJ1Y3RPYmplY3RSZXNwb25zZRKMAQofUmVzb2x2ZU9yQ29uc3RydWN0UmVsYXRlZE9iamVjdBIzLnF1aXhvcy5vcmNoLlJlc29sdmVPckNvbnN0cnVjdFJlbGF0ZWRPYmplY3RSZXF1ZXN0GjQucXVpeG9zLm9yY2guUmVzb2x2ZU9yQ29uc3RydWN0UmVsYXRlZE9iamVjdFJlc3BvbnNlElMKDEdldFdvcmtzcGFjZRIgLnF1aXhvcy5vcmNoLkdldFdvcmtzcGFjZVJlcXVlc3QaIS5xdWl4b3Mub3JjaC5HZXRXb3Jrc3BhY2VSZXNwb25zZRJxChZMaXN0UGFja2FnZURlc2NyaXB0b3JzEioucXVpeG9zLm9yY2guTGlzdFBhY2thZ2VEZXNjcmlwdG9yc1JlcXVlc3QaKy5xdWl4b3Mub3JjaC5MaXN0UGFja2FnZURlc2NyaXB0b3JzUmVzcG9uc2USaAoTTGlzdFBhY2thZ2VSdW50aW1lcxInLnF1aXhvcy5vcmNoLkxpc3RQYWNrYWdlUnVudGltZXNSZXF1ZXN0GigucXVpeG9zLm9yY2guTGlzdFBhY2thZ2VSdW50aW1lc1Jlc3BvbnNlElwKD0xpc3RBY3RpdmF0aW9ucxIjLnF1aXhvcy5vcmNoLkxpc3RBY3RpdmF0aW9uc1JlcXVlc3QaJC5xdWl4b3Mub3JjaC5MaXN0QWN0aXZhdGlvbnNSZXNwb25zZRJcCg9DbG9zZUFjdGl2YXRpb24SIy5xdWl4b3Mub3JjaC5DbG9zZUFjdGl2YXRpb25SZXF1ZXN0GiQucXVpeG9zLm9yY2guQ2xvc2VBY3RpdmF0aW9uUmVzcG9uc2ViBnByb3RvMw", [file_camino_api, file_quixos_package, file_quixos_refs, file_quixos_runtime]); + +/** + * Exact closed interface lookup; no policy selection or competing conformances. + * + * @generated from message quixos.orch.TryConformRequest + */ +export type TryConformRequest = Message<"quixos.orch.TryConformRequest"> & { + /** + * @generated from field: string object_id = 1; + */ + objectId: string; + + /** + * @generated from field: string interface_revision_id = 2; + */ + interfaceRevisionId: string; +}; + +/** + * Describes the message quixos.orch.TryConformRequest. + * Use `create(TryConformRequestSchema)` to create a new message. + */ +export const TryConformRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_quixos_orch, 0); + +/** + * @generated from message quixos.orch.TryConformResponse + */ +export type TryConformResponse = Message<"quixos.orch.TryConformResponse"> & { + /** + * Absent only when this object lacks a known contract. Other failures are errors. + * + * @generated from field: quixos.ConformanceWitness conformance = 1; + */ + conformance?: ConformanceWitness | undefined; +}; + +/** + * Describes the message quixos.orch.TryConformResponse. + * Use `create(TryConformResponseSchema)` to create a new message. + */ +export const TryConformResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_quixos_orch, 1); /** * @generated from message quixos.orch.ConstructObjectRequest @@ -40,7 +83,7 @@ export type ConstructObjectRequest = Message<"quixos.orch.ConstructObjectRequest * Use `create(ConstructObjectRequestSchema)` to create a new message. */ export const ConstructObjectRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 0); + messageDesc(file_quixos_orch, 2); /** * @generated from message quixos.orch.ConstructObjectResponse @@ -57,7 +100,7 @@ export type ConstructObjectResponse = Message<"quixos.orch.ConstructObjectRespon * Use `create(ConstructObjectResponseSchema)` to create a new message. */ export const ConstructObjectResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 1); + messageDesc(file_quixos_orch, 3); /** * @generated from message quixos.orch.ResolveOrConstructRelatedObjectRequest @@ -84,7 +127,7 @@ export type ResolveOrConstructRelatedObjectRequest = Message<"quixos.orch.Resolv * Use `create(ResolveOrConstructRelatedObjectRequestSchema)` to create a new message. */ export const ResolveOrConstructRelatedObjectRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 2); + messageDesc(file_quixos_orch, 4); /** * @generated from message quixos.orch.ResolveOrConstructRelatedObjectResponse @@ -106,7 +149,7 @@ export type ResolveOrConstructRelatedObjectResponse = Message<"quixos.orch.Resol * Use `create(ResolveOrConstructRelatedObjectResponseSchema)` to create a new message. */ export const ResolveOrConstructRelatedObjectResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 3); + messageDesc(file_quixos_orch, 5); /** * @generated from message quixos.orch.InvokeCapabilityRequest @@ -141,7 +184,7 @@ export type InvokeCapabilityRequest = Message<"quixos.orch.InvokeCapabilityReque * Use `create(InvokeCapabilityRequestSchema)` to create a new message. */ export const InvokeCapabilityRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 4); + messageDesc(file_quixos_orch, 6); /** * @generated from message quixos.orch.InvokeClassCapabilityRequest @@ -168,7 +211,7 @@ export type InvokeClassCapabilityRequest = Message<"quixos.orch.InvokeClassCapab * Use `create(InvokeClassCapabilityRequestSchema)` to create a new message. */ export const InvokeClassCapabilityRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 5); + messageDesc(file_quixos_orch, 7); /** * @generated from message quixos.orch.InvokeCapabilityResponse @@ -215,7 +258,7 @@ export type InvokeCapabilityResponse = Message<"quixos.orch.InvokeCapabilityResp * Use `create(InvokeCapabilityResponseSchema)` to create a new message. */ export const InvokeCapabilityResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 6); + messageDesc(file_quixos_orch, 8); /** * Resolved from the checked native getter/setter binding, not Value.source. @@ -249,7 +292,7 @@ export type FieldEditing = Message<"quixos.orch.FieldEditing"> & { * Use `create(FieldEditingSchema)` to create a new message. */ export const FieldEditingSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 7); + messageDesc(file_quixos_orch, 9); /** * @generated from message quixos.orch.EditCapabilityFieldRequest @@ -293,7 +336,7 @@ export type EditCapabilityFieldRequest = Message<"quixos.orch.EditCapabilityFiel * Use `create(EditCapabilityFieldRequestSchema)` to create a new message. */ export const EditCapabilityFieldRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 8); + messageDesc(file_quixos_orch, 10); /** * @generated from message quixos.orch.WatchCapabilityRequest @@ -320,7 +363,7 @@ export type WatchCapabilityRequest = Message<"quixos.orch.WatchCapabilityRequest * Use `create(WatchCapabilityRequestSchema)` to create a new message. */ export const WatchCapabilityRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 9); + messageDesc(file_quixos_orch, 11); /** * @generated from message quixos.orch.WatchCapabilityEvent @@ -372,7 +415,7 @@ export type WatchCapabilityEvent = Message<"quixos.orch.WatchCapabilityEvent"> & * Use `create(WatchCapabilityEventSchema)` to create a new message. */ export const WatchCapabilityEventSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 10); + messageDesc(file_quixos_orch, 12); /** * @generated from message quixos.orch.GetWorkspaceRequest @@ -391,7 +434,7 @@ export type GetWorkspaceRequest = Message<"quixos.orch.GetWorkspaceRequest"> & { * Use `create(GetWorkspaceRequestSchema)` to create a new message. */ export const GetWorkspaceRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 11); + messageDesc(file_quixos_orch, 13); /** * @generated from message quixos.orch.GetWorkspaceResponse @@ -448,7 +491,7 @@ export type GetWorkspaceResponse = Message<"quixos.orch.GetWorkspaceResponse"> & * Use `create(GetWorkspaceResponseSchema)` to create a new message. */ export const GetWorkspaceResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 12); + messageDesc(file_quixos_orch, 14); /** * @generated from message quixos.orch.ClassCapability @@ -495,7 +538,7 @@ export type ClassCapability = Message<"quixos.orch.ClassCapability"> & { * Use `create(ClassCapabilitySchema)` to create a new message. */ export const ClassCapabilitySchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 13); + messageDesc(file_quixos_orch, 15); /** * @generated from message quixos.orch.CapabilityInputContract @@ -522,7 +565,7 @@ export type CapabilityInputContract = Message<"quixos.orch.CapabilityInputContra * Use `create(CapabilityInputContractSchema)` to create a new message. */ export const CapabilityInputContractSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 14); + messageDesc(file_quixos_orch, 16); /** * @generated from message quixos.orch.ConstructorInputContract @@ -544,7 +587,7 @@ export type ConstructorInputContract = Message<"quixos.orch.ConstructorInputCont * Use `create(ConstructorInputContractSchema)` to create a new message. */ export const ConstructorInputContractSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 15); + messageDesc(file_quixos_orch, 17); /** * @generated from message quixos.orch.ListActivationsRequest @@ -557,7 +600,7 @@ export type ListActivationsRequest = Message<"quixos.orch.ListActivationsRequest * Use `create(ListActivationsRequestSchema)` to create a new message. */ export const ListActivationsRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 16); + messageDesc(file_quixos_orch, 18); /** * @generated from message quixos.orch.ListPackageDescriptorsRequest @@ -570,7 +613,7 @@ export type ListPackageDescriptorsRequest = Message<"quixos.orch.ListPackageDesc * Use `create(ListPackageDescriptorsRequestSchema)` to create a new message. */ export const ListPackageDescriptorsRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 17); + messageDesc(file_quixos_orch, 19); /** * @generated from message quixos.orch.ListPackageDescriptorsResponse @@ -587,7 +630,7 @@ export type ListPackageDescriptorsResponse = Message<"quixos.orch.ListPackageDes * Use `create(ListPackageDescriptorsResponseSchema)` to create a new message. */ export const ListPackageDescriptorsResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 18); + messageDesc(file_quixos_orch, 20); /** * @generated from message quixos.orch.ListPackageRuntimesRequest @@ -600,7 +643,7 @@ export type ListPackageRuntimesRequest = Message<"quixos.orch.ListPackageRuntime * Use `create(ListPackageRuntimesRequestSchema)` to create a new message. */ export const ListPackageRuntimesRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 19); + messageDesc(file_quixos_orch, 21); /** * @generated from message quixos.orch.ListPackageRuntimesResponse @@ -617,7 +660,7 @@ export type ListPackageRuntimesResponse = Message<"quixos.orch.ListPackageRuntim * Use `create(ListPackageRuntimesResponseSchema)` to create a new message. */ export const ListPackageRuntimesResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 20); + messageDesc(file_quixos_orch, 22); /** * @generated from message quixos.orch.ListActivationsResponse @@ -634,7 +677,7 @@ export type ListActivationsResponse = Message<"quixos.orch.ListActivationsRespon * Use `create(ListActivationsResponseSchema)` to create a new message. */ export const ListActivationsResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 21); + messageDesc(file_quixos_orch, 23); /** * @generated from message quixos.orch.CloseActivationRequest @@ -656,7 +699,7 @@ export type CloseActivationRequest = Message<"quixos.orch.CloseActivationRequest * Use `create(CloseActivationRequestSchema)` to create a new message. */ export const CloseActivationRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 22); + messageDesc(file_quixos_orch, 24); /** * @generated from message quixos.orch.CloseActivationResponse @@ -673,7 +716,7 @@ export type CloseActivationResponse = Message<"quixos.orch.CloseActivationRespon * Use `create(CloseActivationResponseSchema)` to create a new message. */ export const CloseActivationResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 23); + messageDesc(file_quixos_orch, 25); /** * @generated from message quixos.orch.Activation @@ -735,7 +778,7 @@ export type Activation = Message<"quixos.orch.Activation"> & { * Use `create(ActivationSchema)` to create a new message. */ export const ActivationSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 24); + messageDesc(file_quixos_orch, 26); /** * @generated from message quixos.orch.PackageRuntimeStatus @@ -807,12 +850,20 @@ export type PackageRuntimeStatus = Message<"quixos.orch.PackageRuntimeStatus"> & * Use `create(PackageRuntimeStatusSchema)` to create a new message. */ export const PackageRuntimeStatusSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_orch, 25); + messageDesc(file_quixos_orch, 27); /** * @generated from service quixos.orch.OrchestratorRuntime */ export const OrchestratorRuntime: GenService<{ + /** + * @generated from rpc quixos.orch.OrchestratorRuntime.TryConform + */ + tryConform: { + methodKind: "unary"; + input: typeof TryConformRequestSchema; + output: typeof TryConformResponseSchema; + }, /** * @generated from rpc quixos.orch.OrchestratorRuntime.InvokeCapability */ diff --git a/src/gen/quixos/refs_pb.ts b/src/gen/quixos/refs_pb.ts index bdc9302..28dea6c 100644 --- a/src/gen/quixos/refs_pb.ts +++ b/src/gen/quixos/refs_pb.ts @@ -10,7 +10,7 @@ import type { Message } from "@bufbuild/protobuf"; * Describes the file quixos/refs.proto. */ export const file_quixos_refs: GenFile = /*@__PURE__*/ - fileDesc("ChFxdWl4b3MvcmVmcy5wcm90bxIGcXVpeG9zIkQKDUNhcGFiaWxpdHlSZWYSHQoVaW50ZXJmYWNlX3JldmlzaW9uX2lkGAEgASgJEhQKDG9wZXJhdGlvbl9pZBgCIAEoCSJCChBQYWNrYWdlRXhwb3J0UmVmEhsKE3BhY2thZ2VfcmV2aXNpb25faWQYASABKAkSEQoJZXhwb3J0X2lkGAIgASgJIsQBChJJbmplY3RlZERlcGVuZGVuY3kSDwoHcG9ydF9pZBgBIAEoCRIXCg1zdGF0ZV9zbG90X2lkGAIgASgJSAASJgoEZWRnZRgDIAEoCzIWLnF1aXhvcy5FZGdlRGVwZW5kZW5jeUgAEh8KFWludGVyZmFjZV9yZXZpc2lvbl9pZBgEIAEoCUgAEh0KE2NvbnN0cnVjdG9yX2F0b21faWQYBSABKAlIABIRCglvYmplY3RfaWQYBiABKAlCCQoHYmluZGluZyI9Cg5FZGdlRGVwZW5kZW5jeRIUCgxlZGdlX3R5cGVfaWQYASABKAkSFQoNcHJvamVjdGlvbl9pZBgCIAEoCWIGcHJvdG8z"); + fileDesc("ChFxdWl4b3MvcmVmcy5wcm90bxIGcXVpeG9zInUKDUNhcGFiaWxpdHlSZWYSHQoVaW50ZXJmYWNlX3JldmlzaW9uX2lkGAEgASgJEhQKDG9wZXJhdGlvbl9pZBgCIAEoCRIvCgtjb25mb3JtYW5jZRgDIAEoCzIaLnF1aXhvcy5Db25mb3JtYW5jZVdpdG5lc3MilgEKEkNvbmZvcm1hbmNlV2l0bmVzcxIRCglvYmplY3RfaWQYASABKAkSHQoVaW50ZXJmYWNlX3JldmlzaW9uX2lkGAIgASgJEhYKDmNvbmZvcm1hbmNlX2lkGAMgASgJEh0KFXdvcmtzcGFjZV9yZXZpc2lvbl9pZBgEIAEoCRIXCg93b3Jrc3BhY2VfZXBvY2gYBSABKAkiQgoQUGFja2FnZUV4cG9ydFJlZhIbChNwYWNrYWdlX3JldmlzaW9uX2lkGAEgASgJEhEKCWV4cG9ydF9pZBgCIAEoCSLEAQoSSW5qZWN0ZWREZXBlbmRlbmN5Eg8KB3BvcnRfaWQYASABKAkSFwoNc3RhdGVfc2xvdF9pZBgCIAEoCUgAEiYKBGVkZ2UYAyABKAsyFi5xdWl4b3MuRWRnZURlcGVuZGVuY3lIABIfChVpbnRlcmZhY2VfcmV2aXNpb25faWQYBCABKAlIABIdChNjb25zdHJ1Y3Rvcl9hdG9tX2lkGAUgASgJSAASEQoJb2JqZWN0X2lkGAYgASgJQgkKB2JpbmRpbmciPQoORWRnZURlcGVuZGVuY3kSFAoMZWRnZV90eXBlX2lkGAEgASgJEhUKDXByb2plY3Rpb25faWQYAiABKAliBnByb3RvMw"); /** * @generated from message quixos.CapabilityRef @@ -25,6 +25,13 @@ export type CapabilityRef = Message<"quixos.CapabilityRef"> & { * @generated from field: string operation_id = 2; */ operationId: string; + + /** + * Optional fence for a view acquired through TryConform. Not an authority grant. + * + * @generated from field: quixos.ConformanceWitness conformance = 3; + */ + conformance?: ConformanceWitness | undefined; }; /** @@ -34,6 +41,43 @@ export type CapabilityRef = Message<"quixos.CapabilityRef"> & { export const CapabilityRefSchema: GenMessage = /*@__PURE__*/ messageDesc(file_quixos_refs, 0); +/** + * @generated from message quixos.ConformanceWitness + */ +export type ConformanceWitness = Message<"quixos.ConformanceWitness"> & { + /** + * @generated from field: string object_id = 1; + */ + objectId: string; + + /** + * @generated from field: string interface_revision_id = 2; + */ + interfaceRevisionId: string; + + /** + * @generated from field: string conformance_id = 3; + */ + conformanceId: string; + + /** + * @generated from field: string workspace_revision_id = 4; + */ + workspaceRevisionId: string; + + /** + * @generated from field: string workspace_epoch = 5; + */ + workspaceEpoch: string; +}; + +/** + * Describes the message quixos.ConformanceWitness. + * Use `create(ConformanceWitnessSchema)` to create a new message. + */ +export const ConformanceWitnessSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_quixos_refs, 1); + /** * @generated from message quixos.PackageExportRef */ @@ -54,7 +98,7 @@ export type PackageExportRef = Message<"quixos.PackageExportRef"> & { * Use `create(PackageExportRefSchema)` to create a new message. */ export const PackageExportRefSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_refs, 1); + messageDesc(file_quixos_refs, 2); /** * @generated from message quixos.InjectedDependency @@ -108,7 +152,7 @@ export type InjectedDependency = Message<"quixos.InjectedDependency"> & { * Use `create(InjectedDependencySchema)` to create a new message. */ export const InjectedDependencySchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_refs, 2); + messageDesc(file_quixos_refs, 3); /** * @generated from message quixos.EdgeDependency @@ -130,5 +174,5 @@ export type EdgeDependency = Message<"quixos.EdgeDependency"> & { * Use `create(EdgeDependencySchema)` to create a new message. */ export const EdgeDependencySchema: GenMessage = /*@__PURE__*/ - messageDesc(file_quixos_refs, 3); + messageDesc(file_quixos_refs, 4); diff --git a/test/generic-packages.test.ts b/test/generic-packages.test.ts index 1d8525c..790afc2 100644 --- a/test/generic-packages.test.ts +++ b/test/generic-packages.test.ts @@ -12,6 +12,100 @@ import { genericImplementationType } from "../src/bindings/generics.js"; import { compileWorkspaceRevision, runtimeContracts } from "../src/capability-model/index.js"; import { generateAppliedClientContracts } from "../src/bindings/client.js"; const source = { repository: "https://example.test/generic.git", commit: "a".repeat(40) }; +test("runtime conformance descriptors preserve closed and universal collection item types", async (t) => { + const sdk = path.resolve("../quixos-instance/packages/camino-package-runtime/dist/index.js"); + // The protocol is also published and tested as a standalone subtree. This + // integration uses the real SDK only when both projects are checked out. + if ( + !(await fs.access(sdk).then( + () => true, + () => false, + )) + ) { + t.skip("Real SDK integration requires the monorepo checkout"); + return; + } + const collection = compileCapabilityResourceSource( + `interface Collection id "collection" revision "collection@1" { + relation items id "items" : many-unique object Item {resolve id "get"; connect id "add";} + }`, + { source }, + ); + assert.ok(collection.ok && collection.resource.kind === "interface"); + if (!collection.ok || collection.resource.kind !== "interface") throw Error("interface failed"); + const pkg = compileCapabilityResourceSource( + `import interface Collection; + external atom Book id "book"; external atom Tool id "tool"; + package P id "p" revision "p@1" { + operation both id "both" : record {book:atom-ref; tool:atom-ref;} -> unit mode call receiver any requires { + interface books id "books" : Collection; + interface tools id "tools" : Collection; + }; + operation inspect id "inspect" : ref -> unit mode call receiver any requires { + interface items id "items" : Collection; + }; + }`, + { source, environment: { interfaces: new Map([["Collection", collection.resource.revision]]) } }, + ); + assert.ok(pkg.ok && pkg.resource.kind === "package", JSON.stringify(pkg.diagnostics)); + if (!pkg.ok || pkg.resource.kind !== "package") throw Error("package failed"); + const directory = await fs.mkdtemp(path.join(os.tmpdir(), "qx-conformance-types-")); + try { + const generated = generateTypeScriptBindings( + { + format: "quixos-bindings", + version: 1, + interfaces: pkg.resource.specializations ?? [], + interfaceTemplates: [collection.resource.revision], + packages: [pkg.resource.revision], + }, + "p@1", + { runtimeModule: sdk }, + ); + await fs.writeFile(path.join(directory, "bindings.mts"), generated); + await fs.writeFile( + path.join(directory, "consumer.mts"), + `import type {Implementation} from "./bindings.mjs"; + const implementation: Implementation = { + both: async (context) => { + const view = await context.conform.tryConform(context.objectId, context.ports.books.contract); + if (view) { + await view["items.connect"](context.input.book); + // @ts-expect-error Tool is not Book + await view["items.connect"](context.input.tool); + } + return null; + }, + inspect: async (context) => { + const view = await context.conform.tryConform(context.objectId, context.ports.items.contract); + if (view) await view["items.connect"](context.input); + return null; + }, + };`, + ); + const compiler = path.join( + path.dirname(createRequire(import.meta.url).resolve("typescript/package.json")), + "bin/tsc", + ); + const result = await promisify(execFile)(process.execPath, [ + compiler, + "--ignoreConfig", + "--noEmit", + "--strict", + "--skipLibCheck", + "--target", + "es2023", + "--module", + "nodenext", + path.join(directory, "consumer.mts"), + ]).catch((error) => { + throw Error(error.stdout + error.stderr); + }); + assert.equal(result.stderr, ""); + } finally { + await fs.rm(directory, { recursive: true, force: true }); + } +}); test("generic port aliases retain their defining scope, including shadowed alias names", () => { const iface = compileCapabilityResourceSource( 'type Box = list; interface Data id "data" revision "data@1" {value payload id "payload" : Box {get id "payload:get";}}', @@ -108,7 +202,7 @@ test("generated universal implementations compile and cannot assume a concrete v const require = createRequire(import.meta.url); const compiler = path.join(path.dirname(require.resolve("typescript/package.json")), "bin/tsc"); const run = promisify(execFile); - const preamble = `type QxObjectRef={readonly identity:T}; type QxContextLifecycle={signal?:AbortSignal}; type Handler=${signature};\n`; + const preamble = `type QxObjectRef={readonly identity:T}; type QxConformer={}; type QxContextLifecycle={signal?:AbortSignal}; type Handler=${signature};\n`; try { const file = path.join(directory, "generic.ts"); await fs.writeFile(file, preamble + `const handler:Handler=({input})=>input;`); diff --git a/test/react-fields.test.ts b/test/react-fields.test.ts index 40f34ab..c0bfc4b 100644 --- a/test/react-fields.test.ts +++ b/test/react-fields.test.ts @@ -54,8 +54,18 @@ test("React bindings preserve read-only, writable and nested reference contracts ); await fs.writeFile( path.join(root, "consumer.ts"), - `import {useLiveField, type ReadableField, type WritableField} from "@quixos/web-studio-react-runtime"; + `import {useLiveField, tryConform, type ReadableField, type WritableField} from "@quixos/web-studio-react-runtime"; +import {reactInterfaces} from "./react-props.gen.js"; import type {ReactResults} from "./react-props.gen.js"; +async function lookup() { + const view = await tryConform("object", reactInterfaces.Fields); + if (!view) return; + await view.call["title.set"]("works"); + // @ts-expect-error exact checked setter input + await view.call["title.set"](123); + // @ts-expect-error no invented operation + await view.call["summary.set"]("no setter"); +} declare const props: ReactResults["props"]; const [title, setTitle] = useLiveField(props.fields.fields.title); setTitle("new");