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:
Timothy J. Aveni
2026-09-30 22:55:07 -07:00
parent 988e10263a
commit 6227d64b08
12 changed files with 147 additions and 57 deletions
+11 -11
View File
@@ -10,9 +10,10 @@ import { execFileSync } from "node:child_process";
import { pathToFileURL } from "node:url";
const config = JSON.parse(await fs.readFile(process.argv[2], "utf8"));
const compiler = await import(pathToFileURL(config.compiler));
const plan = JSON.parse(await fs.readFile(config.plan, "utf8"));
const pkg = plan.definition.packages.find((p) => p.revision === config.packageRevisionId);
if (!pkg || compiler.hexDigest(plan.definition) !== plan.digest) throw Error("Invalid checked execution plan/package");
const contract = JSON.parse(await fs.readFile(config.buildContract, "utf8"));
compiler.checkPackageBuildContract(contract);
const pkg = contract.definition.package;
if (pkg.revision !== config.packageRevisionId) throw Error("Invalid build contract package");
const output = process.env.out;
if (!output) throw Error("Missing Nix output");
const digest = (bytes) => createHash("sha256").update(bytes).digest("hex");
@@ -86,8 +87,8 @@ for (const { target, mode, settings } of builds) {
const bindingPath = relative(settings.bindingOutput);
const source =
mode === "remote"
? compiler.generateRemoteTypeScriptBindings(plan.definition.bindingSchema, pkg.revision)
: compiler.generatePortableTypeScriptBindings(plan.definition.bindingSchema, pkg.revision, {
? compiler.generateRemoteTypeScriptBindings(contract.definition.bindings, pkg.revision)
: compiler.generatePortableTypeScriptBindings(contract.definition.bindings, pkg.revision, {
target: executionTarget,
});
await fs.mkdir(path.dirname(path.join(work, bindingPath)), { recursive: true });
@@ -179,22 +180,21 @@ for (const { target, mode, settings } of builds) {
const components =
config.group && !config.components
? []
: await buildComponents({ config, compiler, plan, pkg, output, recordFile, generated });
: await buildComponents({ config, compiler, contract, pkg, output, recordFile, generated });
if (!config.group || config.service.entry)
await buildService({ config, compiler, pkg, output, coreServer, sharedFiles, implementations, recordFile });
const manifest = compiler.parsePackageArtifacts({
const manifest = compiler.parseArtifactGroup({
schemaVersion: 1,
packageRevisionId: pkg.revision,
bindingDigest: pkg.bindingDigest,
sourceDigest: pkg.sourceDigest,
versions: plan.definition.versions,
bindingDigest: contract.digest,
versions: contract.definition.versions,
implementations,
...(components.length ? { components } : {}),
});
for (const { file, source } of generated.values())
if ((await fs.readFile(file, "utf8")) !== source) throw Error("Generated bindings changed during build");
const { receipt, sources } = compiler.expectedArtifactReceipt(plan, manifest, generatorDigest);
const { receipt, sources } = compiler.expectedGroupReceipt(contract, manifest, generatorDigest);
for (const [file, bytes] of sources)
if (!Buffer.from(bytes).equals(await fs.readFile(path.join(output, file))))
throw Error("Receipt generation differs from compiled bindings");