From aef8e45bbda1cf7ea39cc0e77556213379389974 Mon Sep 17 00:00:00 2001 From: mintaka Date: Sat, 12 Sep 2026 19:50:56 -0400 Subject: [PATCH 1/3] feat(agent-image): make the entrypoint FOD hash and native-addon copy per-system (RIG-3749) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The agent container only built on x86_64-linux: `nodeModules.outputHash` was a single x64 value, and the bundle copied `pi-natives-linux-x64`'s two AVX2 variants by name. An aarch64 build fails at the fixed-output hash, and again at the `cp` — the x64 natives package is cpu-gated in bun.lock, so it is not installed on arm64 at all. Both the hash and the addon set now come from one per-system record keyed by `pkgs.stdenv.hostPlatform.system`, following the shape of `tools/toolchain/versions/bun.nix`. The addon list is generated, not a fixed pair, because the file count differs by arch: x64 ships `pi_natives.linux-x64-{modern,baseline}.node` (the loader picks by AVX2, which is x86-only) while arm64 ships a single unsuffixed `pi_natives.linux-arm64.node`. An unsupported system throws by name rather than falling back to a wrong hash. x86_64-linux is unchanged in effect: same hash, and the generated copy shell is byte-identical to the three lines it replaces. The aarch64 hash is `lib.fakeSha256` in this commit. The arm64 build spike reports the real value and it lands before this leaves draft. Co-authored-by: Matt Wilkinson --- agent-image/entrypoint.nix | 44 ++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/agent-image/entrypoint.nix b/agent-image/entrypoint.nix index fc9e9f417..660bf34e4 100644 --- a/agent-image/entrypoint.nix +++ b/agent-image/entrypoint.nix @@ -28,6 +28,29 @@ # execDir = `dirname(process.execPath)`, which is exactly that dir — so a cold # container with no node_modules and no network still loads the native addon. let + system = pkgs.stdenv.hostPlatform.system; + + # Per-system native pins: the FOD hash covers the platform-specific + # optionalDependency, and the addon set differs by arch (x64 two, arm64 one). + nativeBySystem = { + "x86_64-linux" = { + outputHash = "sha256-JbgM44AwH7/b3Y/2T44+eBXwyvMi8owXToGVspEeCk4="; + nativesPkg = "pi-natives-linux-x64"; + addons = [ + "pi_natives.linux-x64-modern.node" + "pi_natives.linux-x64-baseline.node" + ]; + }; + "aarch64-linux" = { + outputHash = lib.fakeSha256; # placeholder until the arm64 CI spike reports the real hash + nativesPkg = "pi-natives-linux-arm64"; + addons = [ "pi_natives.linux-arm64.node" ]; + }; + }; + native = + nativeBySystem.${system} + or (throw "compass-agent entrypoint: unsupported system ${system}"); + # The package's dependency closure, fetched once as a fixed-output derivation # (the only derivation here allowed network access). `--frozen-lockfile` pins # the VERSIONS to `bun.lock`; the output hash below pins the installed tree as @@ -131,7 +154,7 @@ let dontFixup = true; outputHashMode = "recursive"; outputHashAlgo = "sha256"; - outputHash = "sha256-JbgM44AwH7/b3Y/2T44+eBXwyvMi8owXToGVspEeCk4="; + outputHash = native.outputHash; }; # The package's own source. A BARE path here (`${../packages/…}`) would copy @@ -205,19 +228,12 @@ let --external omp-legacy-pi-modules \ --outfile=$out/compass-agent - # Ship the prebuilt native addon BESIDE the compiled binary. It is not - # inside `@oh-my-pi/pi-natives`; it ships in the platform optionalDependency - # `@oh-my-pi/pi-natives-linux-x64` (pinned in bun.lock, so present in the - # FOD tree). bun's isolated install keeps the platform package in its `.bun` - # virtual store and hoists it through the version-independent symlink - # `node_modules/.bun/node_modules/@oh-my-pi/pi-natives-linux-x64` (it is NOT - # hoisted to the plain top-level `node_modules/@oh-my-pi/`). It carries two - # CPU variants; the loader picks `modern` when the host has AVX2 else - # `baseline` (loader-state.js), so BOTH must be present for either host to - # resolve. `cp` follows the hoist symlink to copy the real files. - natives=node_modules/.bun/node_modules/@oh-my-pi/pi-natives-linux-x64 - cp $natives/pi_natives.linux-x64-modern.node $out/ - cp $natives/pi_natives.linux-x64-baseline.node $out/ + # The prebuilt addon ships in the per-system optionalDependency + # `@oh-my-pi/pi-natives-linux-` (pinned in bun.lock, so in the FOD tree), + # hoisted into `.bun/node_modules/@oh-my-pi/`. x64 carries two AVX2 variants + # (modern/baseline); arm64 carries one. `cp` follows the hoist symlink. + natives=node_modules/.bun/node_modules/@oh-my-pi/${native.nativesPkg} + ${lib.concatMapStringsSep "\n" (f: "cp $natives/${f} $out/") native.addons} ''; in # The bundle is now a STANDALONE compiled binary, not an interpreted `cli.js`, From e2d90fe973ad7e117664e403b2e67cc503846d2f Mon Sep 17 00:00:00 2001 From: mintaka Date: Sat, 12 Sep 2026 20:07:08 -0400 Subject: [PATCH 2/3] style(agent-image): drop process vocabulary from the placeholder comment The comment named a development task rather than the mechanism, which reads as stale once that task is merged. Describe what replaces the value instead. Co-authored-by: Matt Wilkinson --- agent-image/entrypoint.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent-image/entrypoint.nix b/agent-image/entrypoint.nix index 660bf34e4..14730c96a 100644 --- a/agent-image/entrypoint.nix +++ b/agent-image/entrypoint.nix @@ -42,7 +42,7 @@ let ]; }; "aarch64-linux" = { - outputHash = lib.fakeSha256; # placeholder until the arm64 CI spike reports the real hash + outputHash = lib.fakeSha256; # placeholder; replace with the hash an aarch64 build reports nativesPkg = "pi-natives-linux-arm64"; addons = [ "pi_natives.linux-arm64.node" ]; }; From 46c9e16125822d740b0a3b5bf6535110b00e44ec Mon Sep 17 00:00:00 2001 From: mintaka Date: Sat, 12 Sep 2026 23:56:00 -0400 Subject: [PATCH 3/3] feat(agent-image): pin the measured aarch64 node_modules hash (RIG-3749) Replace the placeholder with the hash an aarch64 install actually produces. Measured on two hosts with different arch and bun version, each carrying a positive control that reproduces the committed x86_64 hash: x86_64-linux, bun 1.4.0 x64 sha256-JbgM44... (matches) / arm64 sha256-asK46R... aarch64-darwin, bun 1.3.13 x64 sha256-JbgM44... (matches) / arm64 sha256-asK46R... The arm64 tree carries one addon, pi_natives.linux-arm64.node, confirming the single-entry addon list. The x86_64 fixed-output derivation is the same store path before and after this change. Co-authored-by: Matt Wilkinson --- agent-image/entrypoint.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent-image/entrypoint.nix b/agent-image/entrypoint.nix index 14730c96a..4828a2037 100644 --- a/agent-image/entrypoint.nix +++ b/agent-image/entrypoint.nix @@ -42,7 +42,7 @@ let ]; }; "aarch64-linux" = { - outputHash = lib.fakeSha256; # placeholder; replace with the hash an aarch64 build reports + outputHash = "sha256-asK46RRcPuByIjHMJUYL/UCp4f0UJBvPvZehUiyeW0I="; nativesPkg = "pi-natives-linux-arm64"; addons = [ "pi_natives.linux-arm64.node" ]; };