Compare commits

..

2 Commits

Author SHA1 Message Date
Quixos Subtree Publisher 7863ce3e12 Publish quixos-protocol from db6d7990a4ffec273258ac313b7d2aeac57b261a 2026-09-17 18:54:46 +00:00
Timothy J. Aveni ea51ca89e7 Add exact runtime conformance lookup and agent-visible language limits 2026-09-17 11:54:46 -07:00
4 changed files with 77 additions and 26 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"version": 1, "version": 1,
"sourceRepo": "https://gitea-external.egads.tutti.syntaxblitz.net/quixos/quixos", "sourceRepo": "https://gitea-external.egads.tutti.syntaxblitz.net/quixos/quixos",
"sourceCommit": "a45fd9a85b541ce6b449b28e8b47954bf04de96b", "sourceCommit": "db6d7990a4ffec273258ac313b7d2aeac57b261a",
"sourcePath": "quixos-protocol", "sourcePath": "quixos-protocol",
"exportName": "quixos-protocol", "exportName": "quixos-protocol",
"mirrorRemote": "https://gitea-external.egads.tutti.syntaxblitz.net/quixos/quixos-protocol.git" "mirrorRemote": "https://gitea-external.egads.tutti.syntaxblitz.net/quixos/quixos-protocol.git"
+17 -1
View File
@@ -285,7 +285,23 @@ export const generateTypeScriptBindings = (
genericImplementationType(definition, [...schema.interfaces, ...(schema.interfaceTemplates ?? [])], type), genericImplementationType(definition, [...schema.interfaces, ...(schema.interfaceTemplates ?? [])], type),
]); ]);
} }
const contracts = schema.interfaces.map((iface) => { // Unused imported interfaces must not introduce new message-codec obligations.
// A used port still fails above if its own required codec is missing.
const hasCodec = (value: ValueType): boolean => {
if (value.kind === "message") return !!options.messages?.[value.descriptorId];
if (value.kind === "record") return Object.values(value.fields).every(hasCodec);
if (value.kind === "list" || value.kind === "optional") return hasCodec(value.value);
return true;
};
const contracts = schema.interfaces
.filter((iface) =>
iface.members.every((member) =>
member.operations
.filter((operation) => operation.mode === "call" && operation.scope !== "class")
.every((operation) => hasCodec(operation.inputType) && hasCodec(operation.outputType)),
),
)
.map((iface) => {
const generated = port({ const generated = port({
id: capabilityId.dependencyPort("contract"), id: capabilityId.dependencyPort("contract"),
displayName: iface.displayName, displayName: iface.displayName,
+24 -1
View File
@@ -78,7 +78,30 @@ export function generateReactBindings(
throw new Error("React component check must name a local module relative to generated bindings"); 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"]>;`; return `type Component${i} = CheckedComponent<${q(component.propsExport)}, typeof import(${q(component.module)})["default"]>;`;
}); });
const contracts = schema.interfaces.map((iface) => { // Emit optional discovery descriptors only when the browser has all codecs.
// Unrelated opaque-message imports must not break an otherwise checked UI.
const browserValue = (value: ValueType, seen: Set<string>): boolean => {
if (value.kind === "message") return false;
if (value.kind === "builtin") return value.name === "unit";
if (value.kind === "record") return Object.values(value.fields).every((field) => browserValue(field, seen));
if (value.kind === "list" || value.kind === "optional") return browserValue(value.value, seen);
if (value.kind === "object-ref" && value.expectation.kind === "interface") {
const id = value.expectation.interfaceRevisionId;
if (seen.has(id)) return true;
const contract = schema.interfaces.find((entry) => entry.revisionId === id);
return !!contract && browserInterface(contract, new Set([...seen, id]));
}
return true;
};
const browserInterface = (iface: (typeof schema.interfaces)[number], seen: Set<string>): boolean =>
iface.members.every((member) =>
member.operations
.filter((op) => op.mode === "call" && op.scope !== "class")
.every((op) => browserValue(op.inputType, seen) && browserValue(op.outputType, seen)),
);
const contracts = schema.interfaces
.filter((iface) => browserInterface(iface, new Set([iface.revisionId])))
.map((iface) => {
const reference = type({ const reference = type({
kind: "object-ref", kind: "object-ref",
expectation: { kind: "interface", interfaceRevisionId: iface.revisionId }, expectation: { kind: "interface", interfaceRevisionId: iface.revisionId },
+12
View File
@@ -33,6 +33,18 @@ test("React bindings preserve read-only, writable and nested reference contracts
interfaces: [iface.resource.revision], interfaces: [iface.resource.revision],
packages: [pkg.resource.revision], packages: [pkg.resource.revision],
} as const; } as const;
const opaque = structuredClone(iface.resource.revision);
opaque.revisionId = "opaque@1" as typeof opaque.revisionId;
opaque.displayName = "Opaque";
for (const member of opaque.members)
for (const operation of member.operations)
operation.outputType = { kind: "message", descriptorId: "UnsupportedBrowserMessage" };
const withUnusedOpaque = generateReactBindings(
{ ...schema, interfaces: [...schema.interfaces, opaque], packages: [...schema.packages] },
"p@1",
["props"],
);
assert.doesNotMatch(withUnusedOpaque, /"opaque@1": defineReactInterfaceContract/);
const generated = generateReactBindings( const generated = generateReactBindings(
{ ...schema, interfaces: [...schema.interfaces], packages: [...schema.packages] }, { ...schema, interfaces: [...schema.interfaces], packages: [...schema.packages] },
"p@1", "p@1",