## Why The `verifyChain(bundleBytes, trustAnchorBundleBytes, options)` walker in `packages/crypto/crypto/src/bundles/chain-bundle/chain-bundle.ts` accepts a trust anchor as raw `Uint8Array`. There is no shipped helper to **load** that buffer from disk or environment, so every consumer (CLI, daemons, drive sync, network plugins) hand-rolls the same `readFile + parsePublicBundle + self-verify` sequence — or worse, skips the self-verify and trusts whatever bytes happen to live at the path. The umbrella change `restore-crypto-keychain-packer-umbrella` named this surface (`loadTrustAnchor()` / `loadTrustAnchorFromEnv()` / `SUAVEPLAN_TRUST_ANCHOR_PATH`) but the implementation slice was deferred. The `crypto-spec-restore-versioning` archive (2026-05-03) explicitly excluded the requirement because the `src/trust-anchors/` directory does not exist on genesis. The chain-bundle source already references a `TRUST_ANCHOR.MISMATCH` error code (line 199 of `chain-bundle.ts`) that is never defined in `errors/codes/codes.ts` — a stale doc-only signal that the surface was planned and never built. This change fills the gap with a small, dependency-free loader module that takes injectable filesystem and environment readers (no direct `node:fs` import in the universal package), self-verifies the bundle on load, and surfaces stable structured errors. The module is the single auditable point through which trust anchors enter a Suaveplan process — a security-relevant choke point. ## What Changes - **MODIFIED `crypto` capability**: add 1 requirement covering trust-anchor bootstrap. New surface in `packages/crypto/crypto/src/trust-anchors/`: - `TrustAnchor` type — `{ bytes: Uint8Array; bundle: PublicBundle }` - `TrustAnchorReader` interface — `read(path: string): Promise` - `loadTrustAnchor(reader, path): Promise` — reads bytes, parses, self-verifies - `loadTrustAnchorFromEnv(reader, getenv?, envVar?): Promise` — env-driven path, defaults to `SUAVEPLAN_TRUST_ANCHOR_PATH` - 3 new error codes: `TRUST_ANCHOR.PATH_MISSING`, `TRUST_ANCHOR.READ_FAILED`, `TRUST_ANCHOR.SELF_VERIFY_FAILED` - Subpath export `./trust-anchors` - **MODIFIED `crypto` capability**: extend the existing `Chain bundle traversal` requirement's `Verified by:` list to include the new trust-anchor self-verify scenario (the loader is what produces the `trustAnchorBundleBytes` `verifyChain` consumes). - This change ships **source + tests + docs**, not just spec. Every requirement carries a `Verified by:` pointer to a real test name, per the convention re-affirmed by `crypto-spec-restore-versioning`. ## Capabilities ### New Capabilities (none) ### Modified Capabilities - `crypto`: add 1 requirement (`Trust-anchor bootstrap`); no requirements modified or removed. ## Impact - **Affected specs**: `openspec/specs/crypto/spec.md` (1 requirement added). - **Affected code**: - `packages/crypto/crypto/src/trust-anchors/` (new directory — 5 files: types, impl, tests, docs, barrel). - `packages/crypto/crypto/src/errors/codes/codes.ts` (3 codes added). - `packages/crypto/crypto/src/index.ts` (re-export the new surface). - `packages/crypto/crypto/package.json` (subpath export `./trust-anchors`). - `packages/crypto/crypto/vite.config.ts` (build entry). - `packages/crypto/crypto/tests/no-duplicates.test.ts` (whitelist `trust-anchors/`). - **Affected tests**: 2 new test files (round-trip, error-code conformance). Coverage gate stays at 100/100/100/100. - **Downstream**: `crypto-cli` and any daemon that consumes a chain bundle can replace its hand-rolled loader with the shipped one. No breaking change — the existing `verifyChain` signature is unchanged; consumers opt in to the loader. - **Risk**: low. The loader is a thin wrapper over an existing tested verify-path. Filesystem and env access are caller-injected, so the universal package picks up no platform deps.