build(deps): bump freenet-stdlib 0.3.5 → 0.6.0 with V10 delegate migration#214
Merged
build(deps): bump freenet-stdlib 0.3.5 → 0.6.0 with V10 delegate migration#214
Conversation
…ation
Catches river up three minor versions of freenet-stdlib, crossing:
- 0.4.0 seeding→hosting terminology rename (field `seeding_contracts`
became `hosting_contracts` on `SystemMetrics`).
- 0.5.0 `MessageOrigin::Delegate(DelegateKey)` variant added so the
runtime can attest inter-delegate callers; enum marked
`#[non_exhaustive]`.
- 0.6.0 hardening: `#[non_exhaustive]` added to `InboundDelegateMsg`,
`UpdateData`, `DelegateError`, `ContractError`, `APIVersion` plus
wire-format pin tests.
## Source fixes (5 sites)
- `contracts/room-contract/tests/common/test_utils.rs` — rename
`seeding_contracts` → `hosting_contracts` in the telemetry print.
- `delegates/chat-delegate/src/lib.rs` — three exhaustive matches
needed wildcard arms: the `message_type` classifier (wildcard
classifies future variants as "unknown message"), the `origin`
routing (new explicit `MessageOrigin::Delegate(caller_key)` arm
rejects inter-delegate calls — chat-delegate is driven exclusively
by the River web app and has no scenario today where another
delegate should be able to invoke it), and the message routing
match (wildcard rejects unknown variants with a clear error).
- `contracts/room-contract/src/lib.rs` — replaced `_ => unreachable!()`
on the `UpdateData` match with `_ => return Err(InvalidUpdate)`. A
panic inside contract WASM would kill the runtime for the room and
surface as a generic execution error; returning `InvalidUpdate` is
recoverable and gives a clearer diagnostic. Now that `UpdateData`
is `#[non_exhaustive]`, future variants really could reach this arm.
- `ui/src/components/app/freenet_api/response_handler/update_notification.rs`
— added `_ => warn!("unknown UpdateData variant, ignored")` wildcard
arm to the UI's update-notification match, mirroring the existing
`Related*` arms.
## Drive-by
- `common/tests/migration_test.rs` — fixed a pre-existing clippy
`manual_is_multiple_of` lint (`hex.len() % 2 == 0` →
`hex.len().is_multiple_of(2)`). Eight other pre-existing clippy
warnings in `ui/src/` are out of scope for this PR — river's CI
has clippy disabled (`.github/workflows/clippy.yml.disabled`) so
none of these gate the build.
## Migration (V10)
Added V10 entry to `legacy_delegates.toml` BEFORE any WASM-altering
edits, per the migration workflow in `.claude/rules/river-publish.md`:
[[entry]]
version = "V10"
description = "Before freenet-stdlib 0.6.0 bump (non_exhaustive \
hardening + MessageOrigin::Delegate)"
delegate_key = "c2c96b97ab5e2f38bfdfb1ea697906fb947a5cdbaea25747f4670561b3edb61b"
code_hash = "9ef1e02d5c99d9a9743972c5e618e061e0e2278658cfa178900b31a2834313c1"
This records the CURRENT deployed V9-era delegate's hash so when this
lands and users' River clients update, they can migrate their room
data from the old delegate key to the new one.
## WASMs rebuilt
- `ui/public/contracts/chat_delegate.wasm` (new code_hash: 05bc461d…)
- `ui/public/contracts/room_contract.wasm`
- `cli/contracts/room_contract.wasm` (synced to match)
All rebuilt via `cargo make sync-wasm` after the stdlib bump landed
in the working tree. Migration check confirms the V10 entry matches
the old hash and the new WASM is distinct.
## Validation
- `cargo make build` — full workspace build succeeds (room contract +
chat delegate + web-container contract + UI)
- `cargo test --package room-contract --features net` — clean
- `cargo test -p river-core --test delegate_key_test` — clean
- `cargo test -p river-core --test migration_test` — 4 tests pass
(all entries have valid hex, delegate_key = BLAKE3(code_hash), no
duplicate code_hashes, no duplicate delegate_keys)
- `cargo make check-migration` — confirms
V9→V10 migration entry exists and matches committed WASM hashes
- `cargo check -p river-ui --target wasm32-unknown-unknown --features no-sync`
— clean (UI compiles against the new `LEGACY_DELEGATES` const array
generated by `ui/build.rs` from `legacy_delegates.toml`)
## Follow-up
- Playwright tests should be run locally before un-drafting (CI
triggers them automatically).
- `cargo make publish-all` must be run post-merge on main to rebuild
and publish both the River UI to Freenet AND riverctl to crates.io
— they both embed the room contract WASM and the contract key is
derived from it.
Closes the stdlib-3-minors-behind gap; unblocks delta and ghostkeys
parallel upgrades.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Both code-first and testing reviewers of #214 flagged that the new `MessageOrigin::Delegate(caller_key)` rejection arm added in the main PR commit had zero test coverage. Per `.claude/rules/pr-quality.md` every behavioral change needs a regression test; this pins the "chat-delegate does not accept inter-delegate calls" policy so a future refactor that reorders the `match origin` arms cannot silently regress it. The test synthesizes a `MessageOrigin::Delegate(caller)` with an arbitrary DelegateKey (value doesn't matter — only the variant tag does) and asserts that the chat delegate returns `DelegateError::Other` containing the phrase "does not accept inter-delegate calls". Verified: 10/10 chat-delegate tests pass locally. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The check-wasm-sync CI workflow explicitly flagged that the room contract WASM changed but riverctl's crates.io version matched local. Per the workflow's own guidance: "If the UI is published with new WASM but riverctl isn't, they'll target different contracts." This bump triggers the republish so the UI and CLI stay in lockstep on the new contract key. Will be published to crates.io via cargo make publish-all post-merge. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
River pins
freenet-stdlib = "0.3.5"and is three minor versions behind the just-released 0.6.0 (see freenet-core 0.2.44 for the matching host release). Running without this bump means:MessageOrigin::Delegate(..)attestations (no scenario today, but the API surface is there);#[non_exhaustive]hardening onInboundDelegateMsg,UpdateData,MessageOrigin, etc. from 0.6.0 means any future variant addition would silently break river at the source level without a wildcard arm;The 0.2.44 freenet-core release is already running clean on nova + vega gateways (~4 hour soak, no regressions, VisitedPeers bloom filter populating correctly).
Approach
Mechanical stdlib bump with wildcard arms where the 0.6.0 non_exhaustive attribute now requires them. No behavioural change for known variants.
Source fixes (5 sites)
contracts/room-contract/tests/common/test_utils.rs— 0.4.0 terminology renameseeding_contracts→hosting_contracts.delegates/chat-delegate/src/lib.rs— three exhaustive matches get wildcard arms. TheMessageOriginmatch gains an explicitSome(MessageOrigin::Delegate(caller_key))arm that rejects inter-delegate calls: chat-delegate is driven exclusively by the River web app viaWebApp, and there is no scenario today where another delegate should be able to invoke it.contracts/room-contract/src/lib.rs— replaced_ => unreachable!()on theUpdateDatamatch with_ => Err(InvalidUpdate). A panic inside contract WASM kills the runtime for the room; returningInvalidUpdateis recoverable. With 0.6.0 making the enumnon_exhaustive, future variants could actually reach this arm.ui/src/components/app/freenet_api/response_handler/update_notification.rs—_ => warn!("unknown UpdateData variant, ignored")wildcard matching the existingRelated*arms.Drive-by
common/tests/migration_test.rs— fixes a pre-existing clippymanual_is_multiple_oflint. Eight other pre-existing clippy warnings inui/src/are out of scope for this PR — river's CI has clippy disabled (.github/workflows/clippy.yml.disabled) so none of these gate the build. Follow-up issue to be filed for re-enabling clippy CI + cleaning up.Migration (V10)
Added V10 entry to
legacy_delegates.tomlbefore any WASM-altering edits landed in the working tree, per.claude/rules/river-publish.md. The V10 entry records the CURRENT deployed V9-era delegate's hash:```
[[entry]]
version = "V10"
description = "Before freenet-stdlib 0.6.0 bump (non_exhaustive hardening + MessageOrigin::Delegate)"
delegate_key = "c2c96b97ab5e2f38bfdfb1ea697906fb947a5cdbaea25747f4670561b3edb61b"
code_hash = "9ef1e02d5c99d9a9743972c5e618e061e0e2278658cfa178900b31a2834313c1"
```
When users' River clients update after this merges and is republished, they will migrate room data from the old V9-era delegate key to the new V10+ delegate key via the
LEGACY_DELEGATESarray generated from this TOML byui/build.rs.Migration-chain risk — assessed low
freenet-stdlib/rust/src/delegate_interface.rs:1205+lock theInboundDelegateMsg::ApplicationMessagetag. The V4-V6 removal cause (bincode wire mismatch) does not apply here. V10 migration probe should succeed.de/serialization error.*Invalid size(V4-V6 failure signature) as a belt-and-suspenders check.Pre-existing V9 entry drift (noted by skeptical reviewer, not addressed in this PR)
V9 lists
code_hash=3a794f5e…but git history shows the actual deployedchat_delegate.wasmsince commit7456f51bhas been9ef1e02d…. Nothing in the TOML corresponds to3a794f5e…being on disk. Either V9 was recorded from an ephemeral local build or the real "V9.5" deployed state was never recorded until now as V10. This PR's V10 entry is correct for what's actually been deployed, so users are protected. The stale V9 entry is out of scope here; follow-up issue will be filed.WASMs rebuilt
ui/public/contracts/chat_delegate.wasm05bc461d…)ui/public/contracts/room_contract.wasmcli/contracts/room_contract.wasmade1e4a0…)Built via
cargo make sync-wasmafter the stdlib bump landed. Staged explicitly by name — nevergit add -Aper.claude/rules/wasm-safety.md.Testing
cargo make build— full workspace build succeeds in ~5 mincargo test --package room-contract --features net— cleancargo test -p river-core --test delegate_key_test— cleancargo test -p river-core --test migration_test— 4 tests passcargo test -p chat-delegate— 10 tests pass (9 existing + 1 new regression for `MessageOrigin::Delegate` rejection path — addresses code-first + testing reviewer feedback)cargo make check-migration— confirms V9 → V10 migration entry exists and matches committed WASM hashescargo check -p river-ui --target wasm32-unknown-unknown --features no-sync— cleanNot run locally
warn!arm on theUpdateDatawildcard; CI will exercise them automatically. Per AGENTS.md Playwright is "REQUIRED before publishing"; this PR does not publish, so the CI gate covers us. Will re-run locally if the CI run flags anything.Review status
All four internal reviewers completed:
Post-merge publish plan
cargo make publish-all— coordinated republish of BOTH River UI to Freenet AND riverctl to crates.io (they both embed room contract WASM and derive the contract key from it, so they MUST stay in lockstep)riverctl member listagainst novade/serialization error.*Invalid size— V4-V6 failure signatureFollow-up issues to file
ui/src/lint errorsRelated
deltaandghostkeys[AI-assisted - Claude]