Build Camino packages from explicit contract inputs
Project source-free capability contracts and keep exact source provenance in package assembly. Reuse compiled groups across unrelated graph and dependency implementation edits. Keep React public inputs separate from workspace query lowering and retain explicit type-companion dependencies. Allow independent execution-package checks, scope resource compilation to declared dependencies, and memoize source closure traversal. Document generic-specialization limits and measured Reader rebuild behavior. Verified protocol, artifact, package, React, and managed activation checks; retained-Git independent/workspace artifact equality and incompatible type dependency rejection; nix fmt -- --check and lint. One-off Reader measurements recompiled 1 of 13 groups for a child edit and 0 for a workspace QX default edit.
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { test } from "node:test";
|
||||
import { compileCapabilityResourceSource } from "../src/capability-language/index.js";
|
||||
import { packageBuildContract } from "../src/execution-world/build-contract.js";
|
||||
import { generatePortableTypeScriptBindings } from "../src/bindings/portable.js";
|
||||
import type { BindingSchema } from "../src/bindings/index.js";
|
||||
import type { InterfaceRevision } from "../src/capability-model/types.js";
|
||||
|
||||
function fixture() {
|
||||
const source = { repository: "https://example.test/source", commit: "1".repeat(40) };
|
||||
const interfaces = new Map<string, InterfaceRevision>();
|
||||
for (const name of ["Value", "Unrelated"]) {
|
||||
const result = compileCapabilityResourceSource(
|
||||
`interface ${name} id "${name}" revision "${name}@1" {
|
||||
value text id "text" : string { get id "text:get" execution snapshot; }
|
||||
}`,
|
||||
{ source },
|
||||
);
|
||||
assert.ok(result.ok && result.resource.kind === "interface", JSON.stringify(result.diagnostics));
|
||||
interfaces.set(name, result.resource.revision);
|
||||
}
|
||||
const result = compileCapabilityResourceSource(
|
||||
`import interface Value;
|
||||
package Adapter id "adapter" revision "adapter@1" {
|
||||
operation fetchText id "read" : unit -> string mode call execution snapshot targets [server]
|
||||
receiver any requires { interface data id "value" : Value using [text.get]; };
|
||||
}`,
|
||||
{ source, environment: { interfaces, interfaceClosure: [...interfaces.values()] } },
|
||||
);
|
||||
assert.ok(result.ok && result.resource.kind === "package", JSON.stringify(result.diagnostics));
|
||||
return {
|
||||
format: "quixos-bindings",
|
||||
version: 1,
|
||||
interfaces: [...interfaces.values()],
|
||||
packages: [result.resource.revision],
|
||||
} satisfies BindingSchema;
|
||||
}
|
||||
|
||||
test("package builds ignore exact pins and unrelated declarations, and preserve generated port types", () => {
|
||||
const schema = fixture();
|
||||
const original = packageBuildContract(schema, "adapter@1");
|
||||
const changed = structuredClone(schema);
|
||||
changed.interfaces.forEach((iface) => {
|
||||
iface.source.commit = "2".repeat(40);
|
||||
});
|
||||
changed.packages[0]!.source.commit = "3".repeat(40);
|
||||
changed.interfaces.find((iface) => iface.displayName === "Unrelated")!.members = [];
|
||||
assert.deepEqual(packageBuildContract(changed, "adapter@1"), original);
|
||||
assert.equal(JSON.stringify(original).includes("https://example.test/source"), false);
|
||||
assert.equal(
|
||||
generatePortableTypeScriptBindings(original.definition.bindings, "adapter@1", { target: "server" }),
|
||||
generatePortableTypeScriptBindings(schema, "adapter@1", { target: "server" }),
|
||||
);
|
||||
});
|
||||
|
||||
test("changing a consumed interface or an owned port contract invalidates the build", () => {
|
||||
const schema = fixture();
|
||||
const original = packageBuildContract(schema, "adapter@1");
|
||||
const changed = structuredClone(schema);
|
||||
changed.interfaces[0]!.members[0]!.operations[0]!.outputType = { kind: "scalar", name: "bool" };
|
||||
assert.notEqual(packageBuildContract(changed, "adapter@1").digest, original.digest);
|
||||
const own = structuredClone(schema);
|
||||
own.packages[0]!.exports[0]!.outputType = { kind: "scalar", name: "bool" };
|
||||
assert.notEqual(packageBuildContract(own, "adapter@1").digest, original.digest);
|
||||
});
|
||||
|
||||
test("a nominal reference does not import the referenced interface's entire dependency graph", () => {
|
||||
const schema = fixture();
|
||||
schema.packages[0]!.exports[0]!.inputType = {
|
||||
kind: "object-ref",
|
||||
expectation: { kind: "interface", interfaceRevisionId: schema.interfaces[1]!.revisionId },
|
||||
};
|
||||
const original = packageBuildContract(schema, "adapter@1");
|
||||
schema.interfaces[1]!.members = [];
|
||||
assert.deepEqual(packageBuildContract(schema, "adapter@1"), original);
|
||||
schema.packages[0]!.exports[0]!.inputType = { kind: "scalar", name: "string" };
|
||||
assert.notEqual(packageBuildContract(schema, "adapter@1").digest, original.digest);
|
||||
});
|
||||
@@ -10,6 +10,9 @@ import {
|
||||
generatePackageQueryClientBindings,
|
||||
} from "../src/execution-world/client-contracts.js";
|
||||
import { compileQueryProgram } from "../src/execution-world/queries.js";
|
||||
import { presentationDeclarations, preparationArtifact } from "../src/react-build/declarations.js";
|
||||
import { compileQueryComposition } from "../src/query/composition.js";
|
||||
import type { PackageRevision } from "../src/capability-model/types.js";
|
||||
const source = { repository: "https://example.test/device-owner.git", commit: "a".repeat(40) };
|
||||
const factory = compileCapabilityResourceSource(
|
||||
`external atom Entry id "atom:entry";
|
||||
@@ -51,6 +54,17 @@ const view = compileCapabilityResourceSource(
|
||||
);
|
||||
assert.ok(view.ok && view.resource.kind === "interface", JSON.stringify(view.diagnostics));
|
||||
const viewInterface = view.resource.revision;
|
||||
function declareInputs(pkg: PackageRevision) {
|
||||
const declarations = presentationDeclarations(
|
||||
JSON.stringify({
|
||||
modules: Object.fromEntries((pkg.modules ?? []).map((module) => [module.displayName, { inputs: [] }])),
|
||||
}),
|
||||
pkg,
|
||||
[dataInterface, viewInterface],
|
||||
);
|
||||
pkg.buildArtifacts = { [preparationArtifact]: declarations.artifact };
|
||||
pkg.queryCompositions = declarations.compositions.map((entry) => compileQueryComposition(entry, new Map()));
|
||||
}
|
||||
const ui = compileCapabilityResourceSource(
|
||||
'import interface Data; import interface View; package UI id "package:ui" revision "package:ui@1" { module Card id "component:card" implements View.render; }',
|
||||
{
|
||||
@@ -65,6 +79,7 @@ const ui = compileCapabilityResourceSource(
|
||||
},
|
||||
);
|
||||
assert.ok(ui.ok && ui.resource.kind === "package", JSON.stringify(ui.diagnostics));
|
||||
declareInputs(ui.resource.revision);
|
||||
for (const variant of ["base", "added", "gateway", "gateway-next", "session"]) {
|
||||
const session = variant === "session",
|
||||
gateway = session || variant.startsWith("gateway"),
|
||||
@@ -107,6 +122,7 @@ package Owner id "package:owner" revision "package:owner@1" {
|
||||
},
|
||||
);
|
||||
assert.ok(pkg.ok && pkg.resource.kind === "package", JSON.stringify(pkg.diagnostics));
|
||||
if (session) declareInputs(pkg.resource.revision);
|
||||
if (session)
|
||||
pkg.resource.revision.checkedQueries = await Promise.all(
|
||||
pkg.resource.revision.queries!.map((query) =>
|
||||
|
||||
Reference in New Issue
Block a user