Repository navigation
Conversation
…ib 0.12 upgrade Registers the committed chat_delegate.wasm (code hash da47cbd9...) and room_contract.wasm (fa9e59e8...), both built against freenet-stdlib 0.8.5, before the upgrade rebuilds them. Claude-Session: https://claude.ai/code/session_01Xxpwzvt4ucaGfbeCr77Jns
…grate 0.8 Re-keys the room contract (fa9e59e8 -> abd7eb67) and the chat delegate (da47cbd9 -> b703ec55); both outgoing generations were registered as V38 in the previous commit. river-core 0.3.1 -> 0.4.0 (its public API carries stdlib types) and riverctl 0.2.24 -> 0.2.25 (it embeds the new room contract). - OutboundDelegateMsg gained UnsubscribeContractRequest; name it in the exhaustive log-kind match. - Pointer records re-signed for both artifacts (room contract v8, chat delegate v9). - Registry pin (38 generations) and the chat-delegate byte-identity pin updated. The new artifacts import and export exactly what the old ones did, and carry no manifest section, so nodes on older freenet-core still instantiate them. The web container is published from the committed frozen WASM, so the River URL does not move. Claude-Session: https://claude.ai/code/session_01Xxpwzvt4ucaGfbeCr77Jns
- Cargo comments: freenet-migrate unifies with the workspace's stdlib 0.12, and 0.8 is the stdlib 0.12 line. - The RegisterDelegate layout note now covers stdlib 0.12.1. - River's rules no longer send a room-contract re-key to `cargo make publish-all`: it bumps riverctl a second time and never publishes river-core, so it fails whenever riverctl pins a river-core version crates.io does not have (true for this PR's river-core 0.4.0). Release riverctl by tag instead, which publishes river-core first. Comment and doc changes only; neither key-bearing WASM is affected. Claude-Session: https://claude.ai/code/session_01Xxpwzvt4ucaGfbeCr77Jns
sanity
left a comment
There was a problem hiding this comment.
Comprehensive PR Review: #834
Summary
- PR: upgrade River to freenet-stdlib 0.12.1 and freenet-migrate 0.8 (re-keys the room contract and chat delegate)
- Review tier: Full (contract and delegate WASM re-key, migration, wire format)
- Reviewers run:
freenet:code-first-reviewer,freenet:testing-reviewer,freenet:skeptical-reviewerandfreenet:big-picture-reviewer, plus a data-loss lens, each blind, on f7206f8. The fixes after that (c8355b4) are comment and doc changes only; I re-checked them diff-of-diff. - External model:
codex reviewwas unavailable tonight ("You've hit your usage limit … try again at 12:55 AM", on two attempts, on freenet/freenet-migrate#51 in the same session). The data-loss lens ran in its place, alongside the four. Per the multi-model-review rule I did not wait. - CI: green on c8355b4 (build, playwright, check-wasm-sync, check-delegate-migration, check-room-contract-migration, check-pointer-freshness).
Verified independently by reviewers
- V38 equals what is live. The registry entries equal b3sum of
origin/main's committed WASMs (da47cbd9…,fa9e59e8…), anddelegate_key = BLAKE3(code_hash)=5e2084d5…. The live bundle fetched through nova's node embeds main's delegate and room contract. No generation from V24 to V38 is missing. - The committed WASMs are the build of this tree. Two reviewers rebuilt both (
--locked, a different checkout path and target dir) and got byte-identicalabd7eb67…/b703ec55…. - The UI and riverctl derive the same room key.
ui/public/contractsandcli/contractsare identical. Pointer records are fresh and signed (v8/v9). The pins match. - Old nodes are unaffected. Import and export sets are identical to the previous generation's, with no custom sections. Comparing stdlib 0.8.5 with 0.12.1:
- the client-API enums are unchanged apart from the removed last
DelegateRequestvariant; - the delegate enums gained only appended variants;
- the contract interface code is unchanged;
get_contextno longer returningNoneforUserResponseis irrelevant here, since River never calls it.
- the client-API enums are unchanged apart from the removed last
- No behaviour change from the crate bump. freenet-migrate 0.6/0.7 → 0.8 changes only doc comments, and published 0.8.0 is byte-identical to git
d5152e2. - The River URL does not move.
publish-riveruses the frozen committedpublished-contract/web_container_contract.wasm.
Findings and resolution
Must Fix (deploy plan, PR body): fixed. The body said to run cargo make publish-all. That bumps riverctl a second time (0.2.26), commits on local main, and cargo publishes riverctl without river-core 0.4.0. crates.io doesn't have 0.4.0, so the publish fails (reproduced with cargo package -p riverctl) after the UI is already live. The deploy section now gives the correct sequence:
- UI via
publish-river; - the counter-bump PR;
- the
riverctl-v0.2.25tag (the workflow publishes river-core first); - the pointer records, with their environment variables;
- nova autoupdate, once crates.io shows 0.2.25;
- the live checks.
River's own rules (river-publish.md, delegate-migration.md) sent re-keys to publish-all too. They are corrected in this PR, as are the user-level river-publish skill and memory note.
Should Fix: fixed.
- Stale
Cargo.tomlcomments (stdlib "0.8.x"; the 0.7.0 rehearsal note). - The
RegisterDelegatelayout note now covers 0.12.1. - Untested node range: the body says 0.2.122-0.2.133 were not rehearsed.
- Dev-dependency wording:
freenet0.1.x is not the latest, porting it is #836.
Should Fix (rehearsal gaps, data-loss lens): run and added to the body.
-
A skipped release (V37 data, V38 never installed): every room, message, member and the DM recovered. The walk recorded V38 as Unresponsive and imported V37.
-
Old riverctl after the upgrade:
- before any pointer, its write lands only on the V38 key and is not seen;
- after this PR's re-signed records were published to the node, it refuses to write.
That is the existing re-key window. The deploy section now says to keep the gap between the UI and pointer publishes short, and to update nova's riverctl promptly.
Should Fix (CI gaps, testing): filed, predate this PR. No CI rebuild-and-compare of the committed WASMs (the existing issue #678, with this PR's evidence added). No pin on the WASM import and export surface (#835). Both were verified by hand for this PR.
Consider: noted, not changed.
- The lockfile re-resolves
windows-sysfor Windows-only native dependencies. Windows builds only in the release workflow, which builds before it publishes. - An open tab on the old build after the journal resolves is covered by the existing top-up window. This PR doesn't change it, and I did not rehearse it.
Verdict
State: Ready to Merge on review and CI grounds. Held on purpose: Ian asked for the merge and deploy to happen together, supervised, in the morning.
HEAD SHA reviewed: c8355b4 (full review on f7206f8, light re-check of the comment- and doc-only delta).
[AI-assisted - Claude]
|
Closing without merging. The freenet-stdlib 0.12.1 / freenet-migrate 0.8 upgrade will land together with the room-state v2 work instead, so users go through one migration rather than two. The branch is kept so that work can reuse this PR's rehearsal and legacy-registry changes. [AI-assisted - Claude] |
Brings in #837 (webpki-roots 1.0.11) and #838 (rustls-webpki 0.103.16) ahead of folding in #834's stdlib 0.12.1 upgrade. No conflicts. Claude-Session: https://claude.ai/code/session_01F9yCAkah1PdW8SVGV2q5oa
river-core now builds against stdlib 0.12.1 (#834's upgrade, folded in), and two stdlib versions cannot link. The contract interface needed no change; its tests pass. The measurement tool's lock follows. Claude-Session: https://claude.ai/code/session_01F9yCAkah1PdW8SVGV2q5oa
Problem
River was built against freenet-stdlib 0.8.5 while freenet-core links 0.12.1, and its UI and riverctl used freenet-migrate 0.7 / 0.6, which require stdlib 0.8. Moving River forward needed the new freenet-migrate 0.8 line (freenet/freenet-migrate#51, published as 0.8.0).
Approach
One upgrade, every River crate:
freenet-stdlib0.8.5 -> 0.12.1 (workspace),freenet-migrate-> 0.8 in both the UI (was 0.7) and riverctl (was 0.6; riverctl uses only the pointer/probe half, unchanged since 0.6).freenet-macros0.2.0 -> 0.3.1 follows stdlib.freenet-scaffold0.2.2 andfreenet-migrate-build0.2.0 were already current..claude/rules/delegate-migration.md:legacy_delegates.toml(chat delegateda47cbd9…, key5e2084d5…) andcommon/legacy_room_contracts.toml(room contractfa9e59e8…). Both equal the committed artifacts onmain.sync-wasm: room contractfa9e59e8…->abd7eb67…, chat delegateda47cbd9…->b703ec55…,ui/public/contracts/andcli/contracts/in sync.check-pointer-freshnesspasses.=), riverctl 0.2.24 -> 0.2.25 (it embeds the new room contract).chat_delegate_wasm_is_byte_identical.OutboundDelegateMsggainedUnsubscribeContractRequest(tag 8), so the exhaustive log-kind match names it.Compatibility with nodes on older freenet-core. The new delegate and room contract import and export exactly what the old ones did (
wasm-objdump: delegate imports the fourfreenet_delegate_secretscalls plus the logger; contract imports only__frnt__fill_buffer), and neither carries afreenet-manifestsection. Between stdlib 0.8.5 and 0.12.1 the contract interface code is unchanged, the delegate message enums only gained appended variants (River emits none of them), and the client-request variant 0.9.0 removed was the last one. The rehearsal below ran on freenet 0.2.151, and a second one on 0.2.134, whose host links stdlib 0.8.5. Nodes 0.2.122-0.2.133 (also stdlib 0.8.x hosts) were not rehearsed; the wire analysis says they behave like 0.2.134.The River URL does not move.
publish-riverpublishes from the committed frozenpublished-contract/web_container_contract.wasm(7c9d7dbe…), which this PR does not touch; with the committed params it still derivesraAqMh…. (Rebuilding that crate does not reproduce7c9d7dbe…, onmainor here; publishing never uses a rebuild.)Dev-dependencies not moved.
freenetstays on the 0.1 line (0.1.188) for room-contract's integration tests. They are feature-gated and#[ignore]d, and porting them to freenet 0.2.x is #836.freenet-test-network0.1.24 is already the latest release.Only test-only old stdlibs remain.
cargo tree --workspace --all-features -e normal,build --target all -dshows no duplicate stdlib. The 0.1.40 and 0.3.5 copies inCargo.lockcome only from dev-dependencies (freenet-test-network0.1.24, already the latest, for riverctl;freenet0.1.188 for room-contract's integration tests). They don't ship and weren't changed here.Rehearsal (isolated network-mode node, judged by arithmetic)
A
freenet networkgateway (0.2.151) on its own ports with no peers and telemetry off. The UI was published under a throwaway container key, using the committed frozen container WASM so both builds share one origin. The node registered only V38: its secrets dir7LS5qk…is bs58 of V38's registry key, which I derived myself. The successor's dir (3vggzN…) was absent before the upgrade.Baseline, built from
main(V38) through the real old UI and old riverctl. Alice owns Rehearsal Public (3 messages) and Rehearsal Private (2 messages). Bob and Carol joined Public and posted. Bob owns Bob Room (2 messages) and invited Alice, who joined and posted. Alice DM'd Bob.Upgrade. Published the new UI (version 2) over the same container and reloaded Alice's existing browser profile.
Each room logged "Re-key merge … finished: every older key it owed returned the room". Console: 0 errors, 0 warnings, 0 panics.
Identities survive (the contract rejects a post from a non-member key):
Second load (populated successor). 3 rooms; 8 / 3 / 5 messages; no duplicates, no errors. The journal reports V38 resolved, no interrupted import, 0 rejected items. The 34 older generations were never installed on this node, so they stay pending and are retried on the #761 cadence, the same as on the old build.
Emptied successor. I moved the new delegate's store aside and reloaded. Everything recovered from V38: 3 rooms, all 16 messages including the post-upgrade ones, the DM plaintext, 3 room slots, 3 signing keys, rooms_meta. A post after recovery was accepted (Private 3->4).
Caveat: the rehearsed UI linked freenet-migrate from its source checkout at the PR head, before the crates.io publish. It is the same source as the published 0.8.0, and it is UI-only (it enters neither key-bearing WASM).
Rehearsal: skipped release (V37 user, V38 never installed)
A fresh isolated 0.2.151 node, populated through the V37-era UI and riverctl (
2b79676d2; delegate0fc3625e…, room contract8bfd9bcd…). The node's only delegate was V37 (7uJ65G…, bs58 of V37's registry key). Alice owned Public (Bob a member) and Private, and DM'd Bob. I then published the new UI directly, skipping V38.The walk recorded V38 (gen 34) as Unresponsive (not installed) and went on to import V37 (gen 33). Each room's re-key merge asked both older keys (V38 empty, V37 holding the room) and finished. Posts were accepted afterwards from Alice (new UI) and Bob (new riverctl). Console: 0 errors, 0 panics.
Rehearsal: old riverctl and the pointer records
On the main fixture after the upgrade:
That is River's existing re-key window, not something this PR adds. It is why the deploy order below matters.
Testing
All of CI's test steps were run locally on this branch:
check-migration,check-room-contract-migrationandcheck-pointer-freshnesspass.Rehearsal on an older node (freenet 0.2.134, host stdlib 0.8.5)
The same upgrade, run again on a fresh isolated 0.2.134 node. It is the last release whose host links stdlib 0.8.5. Alice owned one room, Bob was a member, 4 messages. After the new UI loaded:
Alice's post on the new build and Bob's on the new riverctl were both accepted: 7 messages at the new key. So the stdlib 0.12 delegate and contract run on a stdlib 0.8.5 host.
Deploy (not done here; held for a supervised run)
Do not merge yet. Ian asked for the merge and deploy to happen together, supervised. Do not use
cargo make publish-all: it bumps riverctl a second time (0.2.25 -> 0.2.26), commits on localmain, andcargo publishes riverctl without river-core 0.4.0, which crates.io does not have, so it fails with the UI already live. This PR corrects River's rules to say so. The sequence, frommainafter the merge:export PATH=$HOME/.cargo/bin:$PATH RUSTC_WRAPPER= CARGO_BUILD_RUSTC_WRAPPER=, checkdx --version= 0.7.10, thencargo make compress-webapp && cargo make publish-river. Grep the log forincompatible(must be empty) and read the advisory read-back.riverctl-v0.2.25.release-riverctl.ymlpublishes river-core 0.4.0, then riverctl 0.2.25, and cuts the GitHub release.published-contract/contract-version.txt(river-publish.md step 6). It must merge before step 5's pre-flight (CI green on main's SHA) can pass.POINTER_NODE_PORT=<a network node of yours, not 7509> POINTER_WASM=~/code/freenet/freenet-migrate/contracts/pointer-contract/pointer-v1.wasm cargo make publish-pointer-records.~/bin/riverctl-autoupdate.shon nova, then confirmriverctl debug contract-key 4uNUKFzZQCnzo4K2ecZ16cMsYEEfoaRS35z6exEsbvm4gives the new key.Keep the gap between the UI publish (2) and the pointer publish (5) short, and get nova's riverctl updated promptly. I measured this on the rehearsal node. After the upgrade and before any pointer, an old riverctl's write landed only on the V38 key (old key 11 messages, new key 10), and the upgraded UI never saw it. Once the re-signed pointer records were published, the old riverctl refused to write ("Refusing to write with a room-contract generation this riverctl does not know"), and the new riverctl wrote to the new key. Nova's moderator and announcer run riverctl, so anything they write in that gap is stranded on the old key.
[AI-assisted - Claude]
https://claude.ai/code/session_01Xxpwzvt4ucaGfbeCr77Jns