nix/npm-12-0-2.nix pinned npm 12.0.2 with an SRI hash while
runtime-pins.json pinned the same npm with a hex digest, and nothing
connected them: two files to bump, and a devShell free to ship a
different npm than every user's install. Nix is now a consumer of the
pin table, not a second table.
Shape: one derivation per pinned tool, `extends` in the table becoming a
real Nix dependency (npm's derivation takes node's, so Nix orders the
builds and neither side restates "npm needs node"), and a bundle that
symlinks them into a runtime dir.
That bundle is not a set of specially-wrapped programs. It is the layout
runtime_registry.py already describes, and Nix does not reimplement any
of the knowledge about it: the build RUNS the real loaders and writes
what they return. runtimes.json comes from save_facts, path-dirs from
runtime_env.managed_path_dirs, tool-env from managed_tool_env. Nix reads
those three files. That is load-bearing, not tidiness — the layout is
per-tool, and a hand-rolled lib.makeBinPath silently dropped uv and
ripgrep, which keep their binary at the tree root rather than in bin/.
The devShell and the package therefore both ship the pinned toolchain:
node 26.7.0 (nixpkgs carried 26.5.0), npm 12.0.2, uv, git, gh, ripgrep,
each with the env its layout needs. `hermes doctor` on the built package
reports all six as managed at their pinned versions.
Sealed installs fail loudly on drift. A git checkout provisions on
demand, so a mismatch there is transient and raising would break the run
that fixes it; a nix/docker/desktop tree cannot provision at all, so a
mismatch means the artifact was assembled against a different pin table
than the code it ships. require_current_runtimes refuses at that point
and `hermes doctor` reports drift as an error rather than a warning,
both keyed off the existing runtime_tree Sealed/GitCheckout split.
Packaged installs locate the table through HERMES_RUNTIME_PINS and the
prebuilt tools through HERMES_RUNTIME_DIR, set by the package wrapper —
the same bare-data-dir treatment as HERMES_OPTIONAL_SKILLS and
HERMES_BUILD_INFO. The table is deliberately not wheel package-data: we
build wheels only for the Nix package, and package-data would put it in
every wheel anyone ever builds.
Evaluation stays free of import-from-derivation. The generated files are
read in build phases, never with builtins.readFile on a derivation, so
`nix flake check --no-build` and cross-system eval still work.
run_tests.sh forwards the git env vars alongside PATH. The devShell puts
a relocated git on PATH, and `env -i` kept PATH while dropping the env
that git needs — the two have to travel together.