# iroh / irpc Version Update — Findings & Migration Plan **Status:** Findings complete. Migration plan drafted; not yet applied. Two cheap wins identified (dead `irpc` dep, stale-pin hypothesis ruled out), one real migration traced end-to-end against iroh 1.0.2. **Date:** 2026-07-08 **Scope:** Resolves the version-gap open question deferred by `alknet-blobs-external-store-probe.md` §"Versioning reality" and §"What this closes and what remains". Verifies latest stable versions on crates.io (not training-data defaults), determines whether alknet-core's `iroh 0.35` dep is load-bearing or a stale pin, and traces the exact `Preset` trait surface in iroh 1.0.x so the migration is concrete rather than a TODO. --- ## TL;DR 1. **Latest stable versions verified against the crates.io API** (2026-07-08): `iroh 1.0.2`, `iroh-blobs 0.103.0`, `irpc 0.17.0`, `irpc-derive 0.17.0`, `bao-tree 0.16.0`. iroh-blobs has **not** moved past 0.103 — no pre-releases, no newer stable. The probe's target version is the current latest; the 4-line/20-line fork premise still holds. 2. **`iroh 0.35` in alknet-core is load-bearing, not a stale pin.** The "pure Cargo.toml change" hypothesis is wrong. `crates/alknet-core/src/endpoint.rs` uses ~15 distinct iroh APIs under `#[cfg(feature = "iroh")]`. Three of them broke between 0.35 and 1.0 and require code edits. The bump is small (~3 edits in `endpoint.rs`) but real. 3. **`irpc 0.16` in the workspace is a dead dep — the actual cheap win.** The probe doc claimed `alknet-call` "already uses `irpc` for structured RPC." That is false: zero `.rs` files in the workspace reference `irpc`. The dep is declared in `Cargo.toml` and never imported. Dropping it (or bumping to 0.17) dissolves the `irpc 0.16 vs 0.17` half of the version gap with zero code impact. 4. **The iroh 1.0.x migration target is stable.** All three flagged APIs are byte-identical between iroh 1.0.0 and 1.0.2 (the actual latest). Pinning `iroh = "1.0"` resolves to 1.0.2 and the migration edits are stable against it. No "do it again when they update" risk on the 1.0.x line. 5. **The `Preset` trace is complete.** alknet-core should use `iroh::endpoint::presets::Minimal` — it sets only the now-mandatory `crypto_provider` and leaves relay mode, address lookup, ALPNs, and secret key for alknet-core to configure as it already does. This matches the pattern iroh-blobs 0.103's own tests use (`tests.rs:506,525`). --- ## 1. Latest stable versions (crates.io API, 2026-07-08) Queried `https://crates.io/api/v1/crates/` for each crate. Versions below are `max_stable_version` (== `newest_version` for all of these — no pre-releases in flight). | crate | latest stable | updated | alknet-core pin | iroh-blobs 0.103 requires | gap | |---|---|---|---|---|---| | `iroh` | **1.0.2** | 2026-07-06 | `0.35` (optional) | `^1.0.0` (runtime) | 2 majors | | `iroh-base` | **1.0.2** | 2026-07-06 | (transitive 0.35) | `^1.0.0` (runtime) | follows iroh | | `iroh-relay` | **1.0.2** | 2026-07-06 | (transitive 0.35) | — | follows iroh | | `iroh-blobs` | **0.103.0** | 2026-06-15 | — | — | target version, no newer | | `irpc` | **0.17.0** | 2026-06-15 | `0.16` (workspace, **unused**) | `^0.17.0` (runtime) | 1 minor — dead dep | | `irpc-derive` | **0.17.0** | 2026-06-15 | `0.16` (workspace, **unused**) | — | same as irpc | | `bao-tree` | **0.16.0** | 2025-11-04 | (not declared) | `^0.16` (runtime) | alknet-blobs will add | ### iroh-blobs has not moved past 0.103 Recent version history (crates.io `/versions` endpoint): ``` 0.103.0 2026-06-15 0.102.0 2026-05-27 0.101.0 2026-05-08 0.100.0 2026-04-20 0.99.0 2026-03-17 0.98.0 2026-01-28 ``` `max_stable == newest == 0.103.0`. No yanked releases, no pre-releases. The probe's `Command`/`Store`/`from_sender`/`Scope` surface findings (all verified against `iroh-blobs-0.103.0/src/api.rs:33,299,303` and `api/proto.rs:693`) are current. The fork premise holds. ### iroh-blobs 0.103's iroh/irpc deps are runtime, not dev The crates.io API's dependency `kind` field was misleading (reported everything as "build"). The authoritative source is the raw `Cargo.toml` in the cargo registry cache: ``` [dependencies.iroh] version = "1.0.0" default-features = false [dependencies.iroh-base] version = "1.0.0" [dependencies.irpc] version = "0.17.0" features = ["spans", "stream", "derive", "varint-util"] default-features = false ``` All three are in `[dependencies]`, not `[dev-dependencies]`. So any crate depending on `iroh-blobs 0.103` pulls `iroh 1.0` and `irpc 0.17` transitively. The version gap is real and load-bearing for alknet-blobs. --- ## 2. `iroh 0.35` is load-bearing (not a stale pin) The other session's hypothesis: "if nothing in alknet-core's current code exercises iroh 0.35-specific APIs, bumping to 1.0 may be a pure Cargo.toml change." Verified by grep — this is wrong. `crates/alknet-core/src/endpoint.rs` uses these iroh APIs under `#[cfg(feature = "iroh")]`: - `iroh::Endpoint::builder()` — `endpoint.rs:681` - `iroh::SecretKey::from_bytes` / `SecretKey::generate` — `endpoint.rs:684,688` - `iroh::RelayMap::from` / `RelayMode::Custom` / `RelayMode::Disabled` — `endpoint.rs:694-697` - `iroh::Endpoint::accept()`, `Endpoint::close()` — `endpoint.rs:403,228` - `iroh::endpoint::{Connection, SendStream, RecvStream, ConnectionError, VarInt, ApplicationClose}` — `endpoint.rs:441`; `types.rs:232,240,366,473,504,824-856` - `iroh::RelayUrl` — `config.rs:28` Three of these broke between 0.35 and 1.0 (see §4). The pin is load-bearing. --- ## 3. `irpc 0.16` is a dead dep (the actual cheap win) The probe doc (`alknet-blobs-external-store-probe.md:163`) claims: > **`alknet-call`** — already uses `irpc` (workspace dep `irpc = "0.16"`) for structured RPC. **This is false.** Grepped every `.rs` file under `crates/alknet-call/src/` and `crates/alknet-call/tests/` for `irpc` — **zero matches**. The only `irpc` reference in alknet-call is `Cargo.toml:18` (`irpc = { workspace = true }`). The actual wire protocol in `src/protocol/wire.rs` is hand-rolled length-prefixed JSON (`EventEnvelope`/`ResponseEnvelope`/`FrameFramedReader`/`FrameFramedWriter`) — no `irpc` types, no `#[rpc_requests]` macro, no `irpc::Client`. The workspace `irpc = "0.16"` / `irpc-derive = "0.16"` deps (`Cargo.toml:19-20`) are **declared but unused by any crate in the workspace**. ### Why this matters for the version gap The only thing pinning `irpc 0.16` in the workspace is a dead dep. Two options, both free: 1. **Drop the dead dep entirely** (cleanest): remove `irpc`/`irpc-derive` from workspace `Cargo.toml:19-20` and from `alknet-call/Cargo.toml:18`. Re-add when `alknet-blobs` actually needs `irpc 0.17` (it will, as a real dep). 2. **Bump to 0.17 now**: change workspace `Cargo.toml` to `irpc = "0.17"` / `irpc-derive = "0.17"`. Zero code impact since nothing uses it. Gets the version in place for `alknet-blobs`. Either way, the `irpc 0.16 vs 0.17` half of the gap dissolves with no migration work. This is the "stale pin" cheap win — it just wasn't where the probe said it was (the probe pointed at `iroh 0.35`; the stale pin was `irpc 0.16`). --- ## 4. The iroh 0.35 → 1.0.2 migration (3 edits) Diffed the actual pub surfaces of `iroh-0.35.0` vs `iroh-1.0.0` (cached in cargo registry) and `iroh-1.0.2` (fetched from static.crates.io). Three APIs broke; everything else alknet-core uses is stable. ### 4.1 Breaking changes (require code edits) | location | 0.35 | 1.0.2 | fix | |---|---|---|---| | `endpoint.rs:681` | `iroh::Endpoint::builder()` (no args) | `iroh::Endpoint::builder(preset: impl Preset)` — `endpoint.rs:950` | pass `presets::Minimal` (see §5) | | `endpoint.rs:688` | `iroh::SecretKey::generate(&mut csprng)` — `iroh-base-0.35.0/src/key.rs:273` takes `R: CryptoRngCore` | `iroh::SecretKey::generate()` — `iroh-base-1.0.2/src/key.rs:318` takes no args (uses internal rng) | drop the `&mut csprng` arg + the `let mut csprng = ...` line | | `endpoint.rs:684` | `iroh::SecretKey::from_bytes(&[u8;32]) -> Result` — `iroh-base-0.35.0/src/key.rs:109` | `iroh::SecretKey::from_bytes(&[u8;32]) -> Result` — `iroh-base-1.0.2/src/key.rs:122` (error type renamed) | add `?` + map `KeyParsingError` to `EndpointError::TlsConfig` | All three confirmed **byte-identical between iroh 1.0.0 and iroh 1.0.2** — the migration target is stable. Pinning `iroh = "1.0"` resolves to 1.0.2 and these edits hold. ### 4.2 Stable APIs (no edits needed) Confirmed by diffing `iroh-0.35.0` vs `iroh-1.0.2` cached/fetched sources: - `iroh::RelayMap::from` — stable (`iroh-relay-1.0.0/src/relay_map.rs:181`) - `iroh::RelayMode::{Custom, Disabled}` — stable (`iroh-1.0.2/src/endpoint.rs:1922`). Note: 1.0 adds `RelayMode::Default` and `RelayMode::Staging` variants, but alknet-core only uses `Custom`/`Disabled`, which are unchanged. - `iroh::Endpoint::accept()` — stable (`iroh-1.0.2/src/endpoint.rs:1162`) - `iroh::Endpoint::close()` — stable (`iroh-1.0.2/src/endpoint.rs:1703`) - `iroh::endpoint::{Connection, SendStream, RecvStream, ConnectionError, VarInt, ApplicationClose}` — stable (module path unchanged) - `Builder::secret_key`, `Builder::alpns`, `Builder::relay_mode`, `Builder::bind` — all stable (signatures unchanged in 1.0.2) ### 4.3 The 1.0 Builder also changed structurally (context, not a direct edit) The 0.35 `Builder::default()` set `relay_mode: default_relay_mode()` (n0 prod relays) and had no `crypto_provider` field. The 1.0 `Builder::empty()` starts with `RelayMode::Disabled` and **requires** `crypto_provider` to be set before `bind()` (returns `BindError::InvalidCryptoProvider` otherwise — `endpoint.rs:230`). This is why the `Preset` arg to `builder()` exists: it's the mechanism for setting the mandatory `crypto_provider`. alknet-core's existing explicit `.relay_mode(...)` call (line 695/697) overrides whatever the preset sets, so the preset only needs to supply the crypto provider. That's exactly what `presets::Minimal` does (see §5). --- ## 5. The `Preset` trait trace (iroh 1.0.x) **Location:** `iroh-1.0.2/src/endpoint/presets.rs` (re-exported as `iroh::endpoint::presets`) ### The trait ```rust // presets.rs:21 pub trait Preset { fn apply(self, builder: Builder) -> Builder; } ``` Single-method. `Endpoint::builder(preset)` calls `preset.apply(Builder::empty())`. ### The four built-in presets | preset | cfg gate | what `apply` sets | use case | |---|---|---|---| | `presets::Empty` | always | nothing — returns builder as-is | full manual control; `bind()` fails unless you set `crypto_provider` yourself | | `presets::Minimal` | `with_crypto_provider` | **only `crypto_provider`** (ring if `tls-ring`, aws-lc-rs if `tls-aws-lc-rs`; ring wins if both) | you want control over relay/discovery but not crypto boilerplate | | `presets::N0` | `with_crypto_provider` | `Minimal` + n0 DNS address lookup (pkarr publisher + DNS resolver) + `RelayMode::Default` (n0 prod relays) | the "0.35 `builder()` default" equivalent — production with n0 infra | | `presets::N0DisableRelay` | `with_crypto_provider` | `N0` but overrides relay to `RelayMode::Disabled` | n0 DNS discovery, no relay | The cfg gate `with_crypto_provider` is set by iroh's `build.rs:8` to `any(feature = "tls-ring", feature = "tls-aws-lc-rs")`. iroh's **default features include `tls-ring`**, so `Minimal`/`N0`/`N0DisableRelay` are available unless you disable default features. ### Why `presets::Minimal` is the right choice for alknet-core alknet-core's `build_iroh_endpoint` (`endpoint.rs:676-704`) does three things after constructing the builder: 1. `builder.secret_key(...)` — sets the iroh identity (line 685/688) 2. `builder.alpns(alpns.to_vec())` — sets ALPNs (line 691) 3. `builder.relay_mode(...)` — **explicitly** sets either `RelayMode::Custom(relay_map)` or `RelayMode::Disabled` based on config (lines 693-698) `presets::N0` would be wrong because: - It sets `RelayMode::Default` (n0 prod relays), but alknet-core **immediately overrides** `relay_mode`. Wasteful, and worse: - It adds n0 DNS address-lookup services (`PkarrPublisher::n0_dns()` + `DnsAddressLookup::n0_dns()` at `presets.rs:121,133`). This would publish alknet node identities to `iroh.link` DNS — not desired for a self-hosted alknet deployment that configures its own relay. - alknet-core's 0.35 `builder()` default did **not** set address-lookup (0.35's `Builder::default()` has no `address_lookup` field — that concept didn't exist). `presets::Minimal` is the exact match: it sets **only** the `crypto_provider` (mandatory since 1.0), and leaves relay mode, address lookup, ALPNs, and secret key for alknet-core to set as it already does. ### Why `presets::Empty` is wrong `Empty` sets nothing, so `bind()` returns `BindError::InvalidCryptoProvider` (`endpoint.rs:230`) unless alknet-core adds an explicit `.crypto_provider(...)` call. `Minimal` is strictly better: it handles the crypto provider selection via iroh's feature flags, which is the intended mechanism. ### Consistency with iroh-blobs 0.103 iroh-blobs 0.103's own tests use the same pattern (`src/tests.rs:506,525`): ```rust let ep = Endpoint::builder(presets::Minimal) .relay_mode(RelayMode::Default) .address_lookup(sp.clone()) .bind() .await?; ``` `Minimal` + explicit relay mode + explicit address lookup. alknet-core should follow the same shape: `Minimal` + explicit relay mode (no address lookup, since alknet doesn't use iroh's DNS discovery). No preset conflict, no duplicate crypto provider when alknet-blobs (which depends on both) is added later. --- ## 6. Cargo.toml changes ### alknet-core (`crates/alknet-core/Cargo.toml:21`) ```toml # from: iroh = { version = "0.35", optional = true } # to: iroh = { version = "1.0", optional = true, default-features = false, features = ["tls-aws-lc-rs"] } ``` **Why `default-features = false`:** iroh's defaults include `tls-ring`. alknet-core's quinn path already uses `rustls::crypto::aws_lc_rs::default_provider()` (`endpoint.rs:551,631`). To keep iroh on the same crypto provider (avoid pulling in both ring and aws-lc-rs), disable defaults and enable only `tls-aws-lc-rs`. This makes `presets::Minimal` select aws-lc-rs (the `#[cfg(all(feature = "tls-aws-lc-rs", not(feature = "tls-ring")))]` branch at `presets.rs:71`), matching the quinn path's existing provider choice. **What `default-features = false` drops:** `tls-ring`, `metrics`, `fast-apple-datapath`, `portmapper`. None are used by alknet-core today. If metrics or portmapper are wanted later, add them explicitly: `features = ["tls-aws-lc-rs", "metrics"]`. The load-bearing choice is `tls-aws-lc-rs` + not-`tls-ring` so `Minimal` picks aws-lc-rs. ### Workspace (`Cargo.toml:19-20`) — the dead dep ```toml # from: irpc = "0.16" irpc-derive = "0.16" # to (option A — cleanest, recommended): # (delete both lines; re-add as 0.17 when alknet-blobs needs them) # # or (option B — bump now, zero code impact): irpc = "0.17" irpc-derive = "0.17" ``` ### alknet-call (`crates/alknet-call/Cargo.toml:18`) — the dead dep consumer ```toml # from: irpc = { workspace = true } # to (option A): # (delete the line — nothing in src/ imports irpc) # # or (option B — leave it, it resolves to the bumped workspace 0.17): irpc = { workspace = true } ``` Option A (drop) is recommended since the dep is genuinely unused; re-adding when needed is trivial. Option B keeps the declaration in case someone planned to wire irpc into alknet-call soon, but the current code doesn't use it. --- ## 7. The migration diff for `build_iroh_endpoint` `crates/alknet-core/src/endpoint.rs:676-704`: ```rust async fn build_iroh_endpoint( static_config: &StaticConfig, alpns: &[Vec], ) -> Result { - let mut builder = iroh::Endpoint::builder(); + let mut builder = iroh::Endpoint::builder(iroh::endpoint::presets::Minimal); if let Some(TlsIdentity::RawKey(secret_key)) = static_config.tls_identity.as_ref() { - let iroh_key = iroh::SecretKey::from_bytes(&secret_key.as_bytes()); + let iroh_key = iroh::SecretKey::from_bytes(&secret_key.as_bytes()) + .map_err(|e| EndpointError::TlsConfig(io::Error::other(e)))?; builder = builder.secret_key(iroh_key); } else { - let mut csprng = rand::rngs::OsRng; - builder = builder.secret_key(iroh::SecretKey::generate(&mut csprng)); + builder = builder.secret_key(iroh::SecretKey::generate()); } builder = builder.alpns(alpns.to_vec()); if let Some(relay_url) = static_config.iroh_relay.as_ref() { let relay_map = iroh::RelayMap::from(relay_url.clone()); builder = builder.relay_mode(iroh::RelayMode::Custom(relay_map)); } else { builder = builder.relay_mode(iroh::RelayMode::Disabled); } builder .bind() .await .map_err(|e| EndpointError::BindFailed(io::Error::other(e))) } ``` **Three edits:** 1. `builder()` → `builder(presets::Minimal)` — supplies the now-mandatory `crypto_provider` (aws-lc-rs via the `tls-aws-lc-rs` feature). 2. `from_bytes(...)` now returns `Result` — add `?` + map to `EndpointError::TlsConfig`. The `TlsConfig` variant already exists (quinn path uses it at `endpoint.rs:554`); no new enum variant needed. 3. `generate(&mut csprng)` → `generate()` — the rng arg is gone; `OsRng` is used internally. Delete the `let mut csprng = rand::rngs::OsRng;` line. ### `EndpointError` note `from_bytes`'s new `KeyParsingError` needs a conversion. The cleanest path is `.map_err(|e| EndpointError::TlsConfig(io::Error::other(e)))?` (reusing the existing `TlsConfig` variant), which is what the diff above does. If a dedicated variant is preferred (`InvalidKey(KeyParsingError)`), that's a 1-line enum change + `From` impl — but the reuse path is simpler and matches how the quinn path handles crypto errors. --- ## 8. Survey: what else may need updating This section catalogs other places in the workspace that touch iroh/irpc and may need attention as part of the bump. Each item is a "check this" — not all will require edits, but all should be verified when the migration branch is opened. ### 8.1 `crates/alknet-core/src/types.rs` — iroh stream/connection types Uses `iroh::endpoint::{SendStream, RecvStream, Connection, ConnectionError, VarInt, ApplicationClose}` (lines 232, 240, 366, 473, 504, 824-856). All confirmed stable in 1.0.2 (same module paths, same enum variants). **Likely no edits**, but the `ConnectionError` match arms at `types.rs:824-856` should be re-checked against 1.0.2's `ConnectionError` enum in case any variants were added (new variants don't break exhaustive matches if the match is on `&_` or has a catch-all, but if it's exhaustive without `_`, the compiler will flag it). ### 8.2 `crates/alknet-core/src/fingerprint.rs` — ed25519 fingerprint parity test The test `fingerprint_from_ed25519_spki_matches_iroh_format` (line 220) constructs an `iroh_fp = format!("ed25519:{}", hex::encode(raw_key))` and compares it against the quinn SPKI path. It doesn't import iroh types — it just asserts string-format parity. **No edits expected.** ### 8.3 `crates/alknet-core/src/config.rs:28` — `iroh::RelayUrl` `pub iroh_relay: Option`. `RelayUrl` is stable across 0.35 → 1.0.2 (`iroh-base-1.0.2/src/relay_url.rs:21`, same `pub struct RelayUrl(Arc)` shape). **No edits expected.** ### 8.4 `Cargo.lock` — will regenerate on `cargo update -p iroh` After bumping `Cargo.toml`, `cargo update -p iroh` (and `-p iroh-base`, `-p iroh-relay`) will pull 1.0.2 and its transitive deps. The lockfile currently pins `iroh 0.35.0`, `irpc 0.16.0`, `irpc-derive 0.16.0` (verified at `Cargo.lock:1998-1999, 2202-2203, 2224-2225`). Expect a sizable lockfile diff (iroh's dep tree changed substantially between 0.35 and 1.0 — `magicsock` → `socket`, `disco` removed, `iroh-dns` added, etc.). ### 8.5 `rand` dependency — may become unused The 0.35 path uses `rand::rngs::OsRng` at `endpoint.rs:687`. After the migration (`generate()` takes no rng), this import may become dead. Check whether `rand` is used elsewhere in alknet-core before removing it from `Cargo.toml`. (`ed25519-dalek` at `Cargo.toml:39` uses `rand_core` features, but that's a separate dep.) ### 8.6 `crates/alknet-call/` — the dead `irpc` dep Covered in §3 and §6. No source changes; just `Cargo.toml` cleanup. ### 8.7 Tests under `#[cfg(feature = "iroh")]` in `endpoint.rs` `endpoint.rs:1107-1150` (`endpoint_constructs_with_iroh_raw_key_identity`, `iroh_endpoint_runs_accept_loop_and_shutdown`) and `endpoint.rs:1326-1364` (`has_iroh_identity_*`) construct test configs with `iroh_relay: None` and exercise `build_iroh_endpoint`. These will hit the same 3 breaking APIs and need the same edits applied (they call into `build_iroh_endpoint`, so if that function is fixed, the tests should pass — but verify the test helpers don't construct `iroh::SecretKey` or `iroh::Endpoint::builder()` directly). ### 8.8 Future: `alknet-blobs` crate (not yet created) When `alknet-blobs` is added as a workspace member, it will depend on `iroh-blobs = "0.103"`, which pulls `iroh 1.0` and `irpc 0.17` transitively. At that point the workspace must have a single consistent iroh version. The migration in this doc (bumping alknet-core to `iroh 1.0`) is the prerequisite for that — without it, `alknet-blobs` and `alknet-core` would depend on different iroh majors and Cargo would fail to resolve (or pick one, breaking the other). The `~20-line fork` of iroh-blobs (widening `Store::from_sender`/`ref_from_sender` + `ApiClient` + `Scope` field, per `alknet-blobs-external-store-probe.md` §"The four items that must be made pub") targets the 0.103 line. Since iroh-blobs hasn't moved past 0.103 (§1), the fork surface is stable. When iroh-blobs does eventually bump, the fork's ~20-line diff is the only thing that needs re-validation — the `Command` protocol shape is the thing to watch, and the probe confirmed it's macro-generated from a `pub enum Request`, so a breaking change there would be visible in iroh-blobs' changelog. --- ## 9. Recommended execution order 1. **Drop the dead `irpc` dep** (§3, §6) — zero code impact, dissolves the `irpc` half of the gap. Do this first as a standalone commit so the workspace is clean before the iroh migration touches anything. 2. **Bump `alknet-core` iroh to 1.0** (§4, §6) — `Cargo.toml` change + 3 edits in `endpoint.rs`. Run `cargo update -p iroh -p iroh-base -p iroh-relay`. 3. **Verify the build** with `--features iroh` and `--all-features`. Check the `ConnectionError` match arms in `types.rs` (§8.1) for exhaustiveness. 4. **Run the iroh-feature tests** (`endpoint.rs:1107-1150, 1326-1364`) to confirm the accept loop and identity paths still work. 5. **Survey + clean up** `rand` usage (§8.5) and any newly-dead imports. 6. **(Later, separate effort)** Add `alknet-blobs` as a workspace member with the `~20-line` iroh-blobs fork. This is unblocked once step 2 lands, since the workspace is then on a single consistent iroh 1.0. --- ## 10. What this closes and what remains **Closes:** - The version-gap open question deferred by `alknet-blobs-external-store-probe.md` §"Versioning reality" and §"What this closes and what remains". The gap is real (iroh 0.35 → 1.0.2, irpc 0.16 → 0.17), the irpc half is a free fix (dead dep), and the iroh half is a traced 3-edit migration with a stable target. - The probe's false claim that alknet-call uses `irpc` (§3). Corrected: alknet-call declares but never imports `irpc`. - The "is iroh 0.35 a stale pin" question (§2). Answered: no, it's load-bearing; 3 APIs broke. - The `Preset` selection question (§5). Answered: `presets::Minimal`, with `tls-aws-lc-rs` feature to match the quinn path's existing crypto provider. **Does not close (deferred to the migration branch):** - Actually applying the diff and confirming the build compiles (§7, §8). The edits are traced but not yet made. - Verifying the `ConnectionError` match exhaustiveness in `types.rs` (§8.1) — needs a compile check. - Whether `rand` can be dropped from alknet-core's deps after the migration (§8.5). - The `~20-line` iroh-blobs fork itself (that's the `alknet-blobs` crate effort, separate from this update). --- ## References - Probe doc: `docs/research/alknet-filesystem/alknet-blobs-external-store-probe.md` — the version-gap open question this doc resolves is at §"Versioning reality" (line 170) and §"What this closes and what remains" (line 206). - Storage strategy: `docs/research/alknet-storage-strategy/findings.md` — cross-references iroh-blobs as the content-addressed blob layer. - alknet-core iroh usage: `crates/alknet-core/src/endpoint.rs:676-704` (`build_iroh_endpoint`), `types.rs:231-504` (stream/connection types), `config.rs:28` (`iroh_relay`), `fingerprint.rs:220-228` (parity test). - alknet-call dead dep: `crates/alknet-call/Cargo.toml:18` (`irpc = { workspace = true }`), `crates/alknet-call/src/protocol/wire.rs` (hand-rolled JSON framing, no irpc). - Workspace deps: `Cargo.toml:19-20` (`irpc`/`irpc-derive` at 0.16). - Versions verified via crates.io API: `https://crates.io/api/v1/crates/` (queried 2026-07-08). - iroh 1.0.2 source: fetched from `https://static.crates.io/crates/iroh/iroh-1.0.2.crate` (not in cargo cache). `Preset` trait at `src/endpoint/presets.rs:21`; `Endpoint::builder(preset)` at `src/endpoint.rs:950`; `Builder::bind()` crypto check at `src/endpoint.rs:225-230`. - iroh 1.0.0 source: cached at `~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/iroh-1.0.0/`. Used for 0.35 vs 1.0.0 pub-surface diff. - iroh-blobs 0.103.0 source: cached at `~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/iroh-blobs-0.103.0/`. `from_sender`/`ref_from_sender`/`ApiClient`/`Scope` visibility confirmed at `src/api.rs:33,299,303` and `src/api/proto.rs:693`. Test preset usage at `src/tests.rs:506,525`. - iroh-base versions: cached 0.35.0 and 1.0.0; fetched 1.0.2. `SecretKey::generate` signature change at `src/key.rs:273` (0.35) vs `:318` (1.0.2); `from_bytes` error type at `:109` (0.35, `SignatureError`) vs `:122` (1.0.2, `KeyParsingError`).