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:
+146
-90
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user