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 b95cd149c6
commit e8d19d2bb7
23 changed files with 726 additions and 227 deletions
+41
View File
@@ -0,0 +1,41 @@
// An independent package check witnesses its contract and bytes, without
// inventing a workspace or granting installation/activation authority.
import { readFile, writeFile } from "node:fs/promises";
import { createHash } from "node:crypto";
import { pathToFileURL } from "node:url";
import { join } from "node:path";
const [compilerPath, schemaPath, checksPath, output] = process.argv.slice(2);
const compiler = await import(pathToFileURL(compilerPath));
const schema = JSON.parse(await readFile(schemaPath, "utf8"));
const checks = JSON.parse(await readFile(checksPath, "utf8"));
const generator = createHash("sha256")
.update(await readFile(compilerPath))
.digest("hex");
const evidence = [];
for (const check of checks) {
const pkg = schema.packages.find((pkg) => pkg.revisionId === check.packageRevisionId);
if (!pkg) throw Error("Unknown checked package");
const contract = compiler.packageBuildContract(schema, pkg.revisionId);
const sourceDigest = compiler.hexDigest({ revision: pkg.revisionId, source: pkg.source });
const manifest = compiler.parsePackageArtifacts(
JSON.parse(await readFile(join(check.artifactPath, "share/quixos/package-artifacts.json"), "utf8")),
);
compiler.checkPackageCoverage(
{ ...contract.definition.package, bindingDigest: contract.digest, sourceDigest },
manifest,
);
const receipt = JSON.parse(await readFile(join(check.artifactPath, "share/quixos/build-receipt.json"), "utf8"));
const expected = compiler.expectedPackageReceipt(contract, manifest, sourceDigest, generator);
if (compiler.hexDigest(receipt) !== compiler.hexDigest(expected.receipt))
throw Error("Invalid package build receipt");
const read = await compiler.artifactFileReader({ [pkg.revisionId]: check.artifactPath });
await compiler.checkArtifactFiles(manifest, read);
for (const [file, bytes] of expected.sources)
if (!Buffer.from(bytes).equals(await read(pkg.revisionId, file, bytes.length)))
throw Error("Modified generated binding " + file);
evidence.push({ ...check, contract: contract.digest, sourceDigest, receipt });
}
await writeFile(
join(output, "package-checks.json"),
JSON.stringify({ codec: "camino-package-checks-v1", generator, packages: evidence }),
);
+19 -11
View File
@@ -24,18 +24,26 @@ let
package = builtins.getFlake (
"path:" + builtins.unsafeDiscardStringContext (toString packageSource)
);
pkgs = import package.inputs.nixpkgs { inherit system; };
buildContext = import ./package-context.nix {
inherit pkgs packageRevisionId;
protocol = builtins.storePath generator;
plan = builtins.path {
path = /. + plan;
name = "candidate-execution-plan.json";
};
};
checked =
package.quixosPackages.${system}.checkedArtifacts
or (throw "Package ${packageRevisionId} lacks checkedArtifacts for the portable execution world.");
in
checked {
inherit packageRevisionId;
plan = builtins.path {
path = /. + plan;
name = "candidate-execution-plan.json";
};
generator = builtins.storePath generator;
core = builtins.storePath core;
sharedRuntime = builtins.storePath sharedRuntime;
typescript = builtins.storePath typescript;
}
checked (
buildContext
// {
inherit packageRevisionId;
generator = builtins.storePath generator;
core = builtins.storePath core;
sharedRuntime = builtins.storePath sharedRuntime;
typescript = builtins.storePath typescript;
}
)
+146 -90
View File
@@ -20,26 +20,45 @@ let
ref = "refs/tags/quixos-reachability/${source.commit}";
shallow = true;
};
load =
ancestors: source:
if builtins.elem (sourceKey source) ancestors then
throw "Source dependency cycle at ${sourceKey source}"
else if builtins.length ancestors >= 100 then
throw "Source dependency depth exceeds 100"
else
let
directory = fetch source;
lockFile = pkgs.runCommand "qx-source-lock.json" { } ''
${protocol}/bin/quixos-lock-check ${directory}/quixos.lock > "$out"
'';
lock = builtins.fromJSON (builtins.readFile lockFile);
# Memoize by exact source identity. A diamond-shaped dependency graph must
# not recursively evaluate every path through the same imported subtree.
loadSource =
source:
let
directory = fetch source;
lockFile = pkgs.runCommand "qx-source-lock.json" { } ''
${protocol}/bin/quixos-lock-check ${directory}/quixos.lock > "$out"
'';
lock = builtins.fromJSON (builtins.readFile lockFile);
in
source // { inherit directory lock; };
sourceEntry = source: {
key = sourceKey source;
value = loadSource source;
};
sourceGraph = builtins.genericClosure {
startSet = [ (sourceEntry { inherit kind repository commit; }) ];
operator =
entry:
map (
resource: sourceEntry (resource.source // { inherit (resource) kind; })
) entry.value.lock.resources;
};
nodeTable = builtins.listToAttrs (
map (entry: {
name = entry.key;
value = entry.value // {
children = map (
entry:
load (ancestors ++ [ (sourceKey source) ]) (entry.source // { inherit (entry) kind binding; })
) lock.resources;
in
source // { inherit directory children lock; };
root = load [ ] { inherit kind repository commit; };
resource:
nodeTable.${sourceKey (resource.source // { inherit (resource) kind; })}
// {
inherit (resource) binding;
}
) entry.value.lock.resources;
};
}) sourceGraph
);
root = nodeTable.${sourceKey { inherit kind repository commit; }};
configuration =
if builtins.pathExists (root.directory + "/quixos.check.json") then
builtins.fromJSON (builtins.readFile (root.directory + "/quixos.check.json"))
@@ -50,54 +69,61 @@ let
"git+${root.lock.quixos.repository}?rev=${root.lock.quixos.commit}&ref=refs/tags/quixos-reachability/${root.lock.quixos.commit}"
);
runtimePackages = runtime.packages.${system};
flatten = node: [ node ] ++ pkgs.lib.concatMap flatten node.children;
capabilityFlatten =
node:
if node.kind == "build" then
[ ]
else
[ node ] ++ pkgs.lib.concatMap capabilityFlatten node.children;
nodes = builtins.attrValues (
builtins.listToAttrs (
map (node: {
name = sourceKey node;
value = node;
}) (flatten root)
)
);
resourceClosure =
includeBuild: node:
map (entry: entry.value) (
builtins.genericClosure {
startSet = pkgs.lib.optional (includeBuild || node.kind != "build") {
key = sourceKey node;
value = node;
};
operator =
entry:
map (child: {
key = sourceKey child;
value = child;
}) (builtins.filter (child: includeBuild || child.kind != "build") entry.value.children);
}
);
capabilityFlatten = resourceClosure false;
# Frontends are an explicit build choice. The capability assembler itself
# neither discovers React contracts nor loads executable package code.
queryFrontends = pkgs.lib.unique (
pkgs.lib.concatMap (
node:
let
config = node.directory + "/quixos.check.json";
in
if builtins.pathExists config then
(builtins.fromJSON (builtins.readFile config)).queryFrontends or [ ]
else
[ ]
) (capabilityFlatten root)
);
queryFrontends =
node:
pkgs.lib.unique (
pkgs.lib.concatMap (
node:
let
config = node.directory + "/quixos.check.json";
in
if builtins.pathExists config then
(builtins.fromJSON (builtins.readFile config)).queryFrontends or [ ]
else
[ ]
) (capabilityFlatten node)
);
queryGeneratorFlags =
if queryFrontends == [ ] then
node:
if queryFrontends node == [ ] then
""
else if queryFrontends == [ "react" ] then
else if queryFrontends node == [ "react" ] then
"--query-generator ${protocol}/libexec/quixos-protocol/react-query-generator.mjs"
else
throw "Unsupported query frontend selection: ${builtins.toJSON queryFrontends}";
snapshots = pkgs.writeText "qx-nix-source-graph.json" (
builtins.toJSON {
resources = map (node: {
inherit (node)
kind
repository
commit
directory
;
}) (builtins.filter (node: node.kind != "workspace") nodes);
}
);
throw "Unsupported query frontend selection: ${builtins.toJSON (queryFrontends node)}";
snapshots =
node:
pkgs.writeText "qx-nix-source-graph.json" (
builtins.toJSON {
resources = map (node: {
inherit (node)
kind
repository
commit
directory
;
}) (builtins.filter (entry: entry.kind != "workspace") (resourceClosure true node));
}
);
compile =
node:
pkgs.runCommand "qx-${node.kind}-contract" { } ''
@@ -106,19 +132,22 @@ let
if node.kind == "workspace" then
''
${protocol}/bin/quixos-workspace-compile --root ${node.directory} \
${queryGeneratorFlags} \
${queryGeneratorFlags node} \
--source-root-commit ${pkgs.lib.escapeShellArg node.commit} \
--checkout-root "$TMPDIR/checkouts" --snapshot-map ${snapshots} \
--checkout-root "$TMPDIR/checkouts" --snapshot-map ${snapshots node} \
--graph-out "$out/graph.json" --schemas-out "$out/package-schemas.json" \
${pkgs.lib.optionalString execution ''--execution-plan-out "$out/execution-plan.json"''} > "$out/candidate.json"
${
pkgs.lib.optionalString (execution && kind == "workspace")
''--execution-plan-out "$out/execution-plan.json" --build-contexts-out "$out/build-contexts.json"''
} > "$out/candidate.json"
''
else
''
${protocol}/bin/quixos-resource-compile --root ${node.directory} \
${queryGeneratorFlags} \
${queryGeneratorFlags node} \
--kind ${node.kind} --repository ${pkgs.lib.escapeShellArg node.repository} \
--commit ${pkgs.lib.escapeShellArg node.commit} \
--checkout-root "$TMPDIR/checkouts" --snapshot-map ${snapshots} --snapshot-only true \
--checkout-root "$TMPDIR/checkouts" --snapshot-map ${snapshots node} --snapshot-only true \
--graph-out "$out/graph.json" --schema-out "$out/bindings.json" > "$out/candidate.json"
''
}
@@ -137,7 +166,7 @@ let
}) (builtins.filter (dependency: dependency.kind == "build") node.children)
);
reactContracts =
node:
node: moduleInterfaces:
let
interfaces = builtins.attrValues (
builtins.listToAttrs (
@@ -159,6 +188,17 @@ let
in
if build == null then
[ ]
else if
!(builtins.any (
entry:
let
resource = builtins.fromJSON (builtins.readFile "${compile dependency}/candidate.json");
in
entry.revisionId == resource.revision.revisionId
|| (entry.definitionId or null) == resource.revision.revisionId
) moduleInterfaces)
then
[ ]
else
[
(build {
@@ -174,15 +214,26 @@ let
node:
let
compiled = compile node;
candidate = builtins.fromJSON (builtins.readFile "${compiled}/candidate.json");
componentEntries =
if execution then
(pkgs.lib.findFirst (
entry: entry.revision == candidate.revision.revisionId
) { } (builtins.fromJSON (builtins.readFile "${contract}/execution-plan.json")).definition.packages)
.components or [ ]
candidate =
if execution && kind == "workspace" then
{
revision =
pkgs.lib.findFirst
(pkg: pkg.source.repository == node.repository && pkg.source.commit == node.commit)
(throw "Source package missing from workspace compilation: ${node.repository}")
(builtins.fromJSON (builtins.readFile "${contract}/execution-plan.json"))
.definition.bindingSchema.packages;
}
else
[ ];
builtins.fromJSON (builtins.readFile "${compiled}/candidate.json");
buildContext = import ./package-context.nix {
inherit pkgs protocol;
contexts = if kind == "workspace" then "${contract}/build-contexts.json" else null;
plan = "${compiled}/bindings.json";
packageRevisionId = candidate.revision.revisionId;
};
buildContract = builtins.fromJSON (builtins.readFile buildContext.buildContract);
componentEntries = if execution then buildContract.definition.package.components or [ ] else [ ];
package = builtins.getFlake (
"git+${node.repository}?rev=${node.commit}&ref=refs/tags/quixos-reachability/${node.commit}"
);
@@ -195,8 +246,8 @@ let
or (throw "Package ${node.repository} lacks checkedServer; use the supported package scaffold.");
artifact = checked (
if execution then
{
plan = "${contract}/execution-plan.json";
buildContext
// {
generator = protocol;
core = runtimePackages.camino-replica-core;
sharedRuntime = runtimePackages.camino-shared-runtime;
@@ -208,7 +259,7 @@ let
react = {
sdk = runtimePackages.camino-react;
runtime = runtimePackages.camino-react-runtime;
contracts = reactContracts node;
contracts = reactContracts node buildContract.definition.moduleInterfaces;
};
}
else
@@ -236,16 +287,18 @@ let
[ ]
else
map checkPackage (
builtins.filter (node: node.kind == "package") (
builtins.attrValues (
builtins.listToAttrs (
map (node: {
name = sourceKey node;
value = node;
}) (capabilityFlatten root)
builtins.filter
(node: node.kind == "package" && (kind == "workspace" || sourceKey node == sourceKey root))
(
builtins.attrValues (
builtins.listToAttrs (
map (node: {
name = sourceKey node;
value = node;
}) (capabilityFlatten root)
)
)
)
)
);
manifest = pkgs.writeText "qx-candidate-checks.json" (builtins.toJSON checks);
bindingOptions = pkgs.writeText "qx-typescript-options.json" (
@@ -254,8 +307,6 @@ let
)
);
in
assert pkgs.lib.assertMsg (!execution || kind == "workspace")
"Execution packages must be checked in their complete workspace; run qx-workspace check from the workspace root.";
pkgs.runCommand (if contractOnly then "qx-contract" else "qx-checked-candidate") { } ''
mkdir -p "$out"
cp ${
@@ -264,7 +315,7 @@ pkgs.runCommand (if contractOnly then "qx-contract" else "qx-checked-candidate")
cp ${contract}/candidate.json "$out/candidate.json"
cp ${contract}/graph.json "$out/graph.json"
cp ${manifest} "$out/checks.json"
${pkgs.lib.optionalString execution ''
${pkgs.lib.optionalString (execution && kind == "workspace") ''
${
if builtins.pathExists "${root.directory}/quixos.entry.json" then
''
@@ -291,7 +342,12 @@ pkgs.runCommand (if contractOnly then "qx-contract" else "qx-checked-candidate")
${pkgs.lib.optionalString (
kind != "workspace"
) ''cp ${contract}/bindings.json "$out/bindings.json"''}
${pkgs.lib.optionalString (kind == "package") ''
${pkgs.lib.optionalString (execution && kind == "package" && !contractOnly) ''
${pkgs.nodejs_24}/bin/node ${./check-package.mjs} \
${protocol}/libexec/quixos-protocol/execution-world.mjs ${contract}/bindings.json \
"$out/checks.json" "$out"
''}
${pkgs.lib.optionalString (kind == "package" && !execution) ''
${protocol}/bin/quixos-codegen-ts ${contract}/bindings.json \
${pkgs.lib.escapeShellArg (builtins.fromJSON (builtins.readFile "${contract}/candidate.json")).revision.revisionId} \
"$out/bindings.ts" ${bindingOptions}
+15
View File
@@ -0,0 +1,15 @@
import fs from "node:fs/promises";
import { pathToFileURL } from "node:url";
const compiler = await import(pathToFileURL(process.argv[2]));
const input = JSON.parse(await fs.readFile(process.argv[3], "utf8"));
const revision = process.argv[4];
const schema = input.definition?.bindingSchema ?? input;
if (input.definition && compiler.hexDigest(input.definition) !== input.digest) throw Error("Invalid execution plan");
const pkg = schema.packages.find((entry) => entry.revisionId === revision);
if (!pkg) throw Error("Unknown build package " + revision);
process.stdout.write(
JSON.stringify({
contract: compiler.packageBuildContract(schema, revision),
sourceDigest: compiler.hexDigest({ revision, source: pkg.source }),
}),
);
+30
View File
@@ -0,0 +1,30 @@
# Workspace composition may reevaluate this projection after any graph edit.
# Only the canonical, source-free value becomes a package compilation input.
{
pkgs,
protocol,
plan ? null,
contexts ? null,
packageRevisionId,
}:
let
projected = pkgs.runCommand "camino-package-context.json" { } ''
${pkgs.nodejs_24}/bin/node ${./package-context.mjs} \
${protocol}/libexec/quixos-protocol/execution-world.mjs ${plan} \
${pkgs.lib.escapeShellArg packageRevisionId} > "$out"
'';
context =
if contexts == null then
builtins.fromJSON (builtins.readFile projected)
else
(builtins.fromJSON (builtins.readFile contexts)).${packageRevisionId};
in
{
# This is typed semantic data (nominal IDs, types and generated source), never
# Nix artifact paths. Remove the projection derivation's string context, not
# any code/toolchain dependency. Those are separate explicit helper arguments.
buildContract = builtins.toFile "camino-package-contract.json" (
builtins.unsafeDiscardStringContext (builtins.toJSON context.contract)
);
sourceDigest = builtins.unsafeDiscardStringContext context.sourceDigest;
}