varve 0.28.0

The PulseEngine toolchain layer manager — pinned, signed, dated toolchain bundles
# varve export-sdk [--layer <l>] --out <dir> [--select <name>]

Unpacks the layer's verified `sdk` tree into `<dir>` and **relocates** it there:
the absolute prefix the SDK was built for is rewritten to `<dir>` throughout,
the way Yocto's own `relocate_sdk.py` and `toolchain-shar-relocate.sh` do it.

A Yocto SDK is thousands of files, and installing one is not extraction — the
installer byte-patches the ELF interpreter path and the loader's SYSDIRS table
in place, `sed -i`s every text file, and re-points every absolute symlink. After
that the bytes no longer hash to anything the producer signed, which is why the
store keeps the **archive** exactly as signed and the usable tree lives here, in
the export. What lands under `<dir>` is derived, deliberately outside the trust
path: `varve verify` re-hashes the archive in the store, never the tree.

## Depositing an SDK

`kind = "sdk"`, plus the one field this adapter cannot work without:

```toml
layer   = "2026.08.0"
channel = "qualified"
counter = 1

[[tool]]
name       = "poky-cortexa53"
version    = "4.0.15"
kind       = "sdk"
path       = "sdk/poky-glibc-x86_64-cortexa53.tar.gz"
sdk-prefix = "/opt/poky/4.0.15"      # the absolute path this SDK was BUILT for
```

`sdk-prefix` is signed into the manifest, so the relocation budget is
attributable rather than guessed. `deposit` **refuses** an `sdk` without it —
the layer would install, verify, and then be impossible to export, which a
consumer would discover on the far side of an air gap. It equally refuses the
field on any other kind: nothing else is relocated, so it would be signed,
ignored, and believed.

## Exporting

```sh
varve install
varve export-sdk --out ./toolchains/poky

# exported sdk poky-cortexa53@4.0.15 to /w/toolchains/poky — 812 dir(s),
#   9143 file(s), 402 symlink(s); relocated from /opt/poky/4.0.15
#   (37 field(s) patched in place, 1180 text substitution(s), 44 symlink(s) re-pointed)

. ./toolchains/poky/environment-setup-cortexa53-poky-linux
$CC --version
```

Use `--select <name>` when a layer carries more than one `sdk`: one destination
is patched into **one** tree, so several of them in one directory would
overwrite each other. varve refuses that by name rather than choosing.

## The destination can only get shorter

The interpreter path is patched into a **fixed-size field**, so an SDK can only
ever move to a path no longer than the one it was built with — this is
`relocate_sdk.py`'s own limit (`if len(new_dl_path) >= p_filesz: ERROR`). varve
checks it as a single comparison **before the archive is opened**, rather than
after writing thousands of files:

```sh
varve export-sdk --out /home/ci/workspace/builds/embedded/toolchains/poky
# error: cannot relocate this sdk to /home/ci/…/poky: the destination is 52
# characters and the sdk was built for /opt/poky/4.0.15 (17). … Choose a
# destination of at most 17 characters.
```

That is also why varve does not relocate into its own store: the store path is
~90 characters before any content.

## Declaring it, so verify checks it

An SDK is *entered*, not pointed at. Declare it in `varve.toml` and both halves
become automatic — `varve verify` checks the export without being told, and
`varve env` emits the sourcing in the right order:

```toml
manifest-version = 1

[toolchain]
channel = "qualified"
layer   = "2026.08.0"

[[export]]
kind = "sdk"
out  = "toolchains/poky"

[export.env]
script = "environment-setup-cortexa53-poky-linux"
path   = "before-shims"
```

`path` says where this environment sits relative to varve's shims once sourced.
`before-shims` means the SDK's cross-compiler is meant to win on PATH; without
the declaration `varve verify` would report it as a hijacked PATH
(REQ-SHADOW-001) on a setup that is entirely correct. See `varve docs verify`
and `varve docs env`.

## What is deliberately not done

* varve never writes back into the store, and never records a
  post-relocation digest — that would put the relocator inside the trust path.
* The tree is laid down **whole or not at all**: every member's path is
  validated, every destination resolved before a byte is written, colliding
  members refused, and a symlink that leaves the export — or a member written
  *through* one — refused as well.
* varve does not run the SDK's own installer, and does not know what
  `environment-setup-*` sets. It gives you the relocated tree; sourcing it is
  yours.