Add exact runtime conformance lookup and agent-visible language limits

Add authorized exact-contract lookup, revision-fenced views, generated typed package/browser descriptors, and lifecycle-safe React discovery. Preserve closed generic contracts without competing-conformance policies or new authority grants. Document supported workarounds and privacy boundaries for agent feedback. Publish matching protocol/SDK exports and update scaffold/starter pins; leave the deployed template unchanged.
This commit is contained in:
Timothy J. Aveni
2026-09-17 11:29:56 -07:00
parent 47efd9659d
commit 7e69e675ba
19 changed files with 504 additions and 190 deletions
+22 -12
View File
@@ -2,7 +2,20 @@ import { create } from "@bufbuild/protobuf";
import { ValueSchema, ObjectValueSchema } from "./camino/api_pb.js";
import { derived, jsToProtoValue, liveValue, protoValueToJs, } from "./index.js";
import { assertReferenceFree, referenceToWire } from "./references.js";
export const defineQxInterfaceContract = (interfaceRevisionId, operations) => Object.freeze({ interfaceRevisionId, operations });
export const qxDerived = (get) => ({ kind: "derived", get });
const bindInterfaceView = (target, contract, messages) => ({
objectId: target.objectId,
contract,
live: Object.fromEntries(Object.entries(contract.operations).map(([name, operation]) => [
name,
(input) => target.live(operation.id, inputFields(operation.inputType, input, messages)),
])),
...Object.fromEntries(Object.entries(contract.operations).map(([name, operation]) => [
name,
async (input) => decodeQxValue(operation.outputType, (await target.live(operation.id, inputFields(operation.inputType, input, messages))).$quixosValue, messages),
])),
});
// Conversion belongs at the binding boundary. It does not add orchestrator validation.
export const decodeQxValue = (type, value, messages) => {
if (type.kind === "builtin" && type.name === "unit")
@@ -154,18 +167,7 @@ export const bindQxHandler = (spec, handler, messages) => {
const target = raw.interface(port.id);
return [
name,
{
objectId: target.objectId,
live: Object.fromEntries(Object.entries(port.operations).map(([name, operation]) => [
name,
(input) => target.live(operation.id, inputFields(operation.inputType, input, messages)),
])),
...Object.fromEntries(Object.entries(port.operations).map(([name, operation]) => [
name,
async (input) => decodeQxValue(operation.outputType, (await target.live(operation.id, inputFields(operation.inputType, input, messages)))
.$quixosValue, messages),
])),
},
bindInterfaceView(target, defineQxInterfaceContract(port.interfaceRevisionId, port.operations), messages),
];
}
case "constructor":
@@ -178,6 +180,14 @@ export const bindQxHandler = (spec, handler, messages) => {
}
}));
return {
conform: {
async tryConform(object, contract) {
const target = await raw.tryConform(object, contract.interfaceRevisionId);
return target
? bindInterfaceView(target, contract, messages)
: undefined;
},
},
...(spec.receiver === "none" ? {} : { objectId: raw.objectId }),
signal: raw.signal,
...(spec.receiver !== "none" && raw.openSession