Repository navigation
ci: install cargo-make as a prebuilt binary - #794
Merged
Merged
Conversation
Compiling cargo-make 0.37.24 from source now fails: every zip 2.x release it depends on (zip = "^2") has been yanked from crates.io. The step used --force, so it recompiled on every run and the cache never helped; build and ui-playwright-tests failed at 'Install cargo-make' before reaching any code (e.g. run 38869289042). taiki-e/install-action fetches the released binary, pinned to the same version, so nothing is compiled and the cache step is dropped. Claude-Session: https://claude.ai/code/session_019J28r7v39Pf1XZDNUUAidG
…ocked Review follow-ups on #794. fallback: none stops install-action from silently dropping back to the source build this change exists to avoid. The README's plain `cargo install cargo-make` fails locally for the same yanked-zip reason; --locked uses cargo-make's own lockfile and installs cleanly (verified with 0.37.24). Claude-Session: https://claude.ai/code/session_019J28r7v39Pf1XZDNUUAidG
sanity
commented
Oct 16, 2026
sanity
left a comment
Contributor
Author
There was a problem hiding this comment.
Review: #794 (Full tier: CI configuration)
Reviewers run: code-first, skeptical and big-picture Claude lenses, plus Codex (codex review --base origin/main). All ran on 2ec7939.
Findings, all addressed in a549422:
- README told contributors to run
cargo install cargo-make, which fails locally for the same yanked-zipreason. It now uses--locked, verified to install 0.37.24 cleanly. - install-action's default fallback would silently drop back to a source build if no prebuilt binary matched the runner. It is now
fallback: none.
Considered, not changed:
- SHA-pinning install-action: the file uses floating tags for every third-party action, including the existing
taiki-e/install-action@cargo-binstall, so this keeps the convention. - The unpinned
dioxus-clibinstall is the same failure class but a separate step; filed as #795.
Verified: the install-action manifest carries 0.37.24 with an x86_64 musl binary; no other workflow compiles cargo-make. CI is green on a549422, including build and ui-playwright-tests, which previously died at the install step.
Verdict: ready to merge. The follow-up commit is review-driven and small; the diff was re-checked.
[AI-assisted - Claude]
sanity
added a commit
that referenced
this pull request
Oct 16, 2026
main fixed the same breakage in #794 (cargo-make as a prebuilt binary), which conflicts with this. Drop ours and take main's. Claude-Session: https://claude.ai/code/session_01SzES9BQh5PhrJhHdh9FSFw
This was referenced Oct 16, 2026
sanity
added a commit
that referenced
this pull request
Oct 17, 2026
…-keys (#580) (#792) * fix(ui): reload an open tab when River's room contract or delegate re-keys (#580) An open tab runs the build it loaded, with the room contract and chat delegate WASM compiled in. After a re-key it stays on the old contract key, so its rooms go quiet and what it posts reaches nobody, and it keeps writing to the old delegate, whose changes the new build no longer imports. The UI now watches River's two pointer records (100 bytes each, at fixed addresses): GET + subscribe on every connect, with a 15-minute GET backstop. build.rs bakes in which pointer version this build is, from pointer-records.toml; a PointerResolver seeded with that floor reports a newer generation only for a signature-verified record above it. On a newer generation the tab reloads its iframe into the new build, keeping the ?__sandbox=1 query. Loop bounds live in the URL, not storage: at most 4 tries per target with 2/5/15-minute backoff (the 1.2 MB web container can reach a node after the pointer does), at most 6 automatic reloads per hour, then a banner with a manual Reload. A visible tab gets a 15 s countdown with "Not now"; a hidden tab waits 30-120 s; nothing reloads over unsent text. Docs: river-publish.md step 7 now says the pointer publish is what reloads open tabs, so it must follow the UI publish (already enforced by its pre-flight) and should wait ~10 minutes; publish-river prints a reminder. Claude-Session: https://claude.ai/code/session_01SzES9BQh5PhrJhHdh9FSFw * fix(ui): re-plan the reload when the second pointer answer arrives (#580) End-to-end on a local node: when both pointers move, the room pointer's answer lands ~7 ms before the delegate's. The first names a partial target (r2d1) that has spent no tries, so the plan started with no delay and kept it when the real target (r2d2) arrived. A tab whose node lacked the new bundle then retried every 15 s and spent all four tries in under a minute. replan() now runs on every target move: refused -> manual-only, otherwise the running plan takes the later of its wait and the new target's backoff, and never gets shorter. Regression test replays the sequence; it fails with the old keep-the-plan behaviour. Also: log the cap decision when a plan is made, move the banner below the conversation header (it covered the room title), and refuse publish-river when RIVER_POINTER_RECORDS is set (dx build hides the cargo warning). Claude-Session: https://claude.ai/code/session_01SzES9BQh5PhrJhHdh9FSFw * fix(ui): size the reload retries and publish gap from measured propagation (#580) Production telemetry over River UI publishes 30000397-403 (41 sampled deliveries of the ~1.2 MB web container): median ~20 s, 71% within 60 s, 80% within 5 min, p90 ~10 min, max ~2 h; the 100-byte pointer reaches subscribers in under 0.5 s. So the guessed numbers change: the publish gap before publish-pointer-records goes from ~10 to ~2 minutes (clears the fast cluster; longer buys little), and the retries gain a fifth try at +45 min, spanning ~67 minutes instead of ~22, past the p90 with margin. Claude-Session: https://claude.ai/code/session_01SzES9BQh5PhrJhHdh9FSFw * fix(ui): address review of the stale-tab reload (#580) Must-fix findings from the Full-tier review of #792: - One reload per page. The driver re-issued location.replace every tick until the page went, each aborting the last. A reload now moves the page to Phase::Reloading, which never issues another; one that has not landed after 20 s falls back to the manual banner. - Reload through the shell's same-contract `navigate`. A self-navigating iframe left its proxied WebSocket open in the shell, and the shim numbers sockets from 1 per document, so the new page's socket collided with it. The shell closes every proxied socket before replacing the frame. The synchronizer does not reconnect while a reload is under way. - Rebuild the fragment from PROCESSED_CACHE. The iframe's own hash is stale after an invitation is processed; reloading with it replayed the invitation. - Compare reload targets per artifact. Tries were keyed on the exact target string, so a page that had heard one pointer (r2d1) reset the count for r2d2 and only the hourly ceiling held. A target no newer in any artifact carries the tries; a newer one starts afresh with the max recorded. Should-fix: - Busy check covers any visible `fixed inset-0` overlay (every modal), a focused field with text, pending invitation accepts, the composer and an edit in progress, plus a 5 s settle; pending syncs and the delegate flush get up to 5 s before navigating. - No reload before the page is 35 s old (the node's 30 s bundle-refresh window would serve this page's bundle again). - "Not now" sticks across tab switches. - A competing record at the build's own version is not "newer". - The test-pointer guard moved from publish-time env to the built archive, checked in sign-webapp before the counter bump (scripts/ check-webapp-pointer-author.sh, tested in publish-guards-test.sh, and verified on a real release build and on the E2E test-key archive). - Banner explains a long retry wait; docs no longer say pointers serve only third parties. Routing is now a pure function (on_pointer_state) so the response-to-plan path is tested; wiring pins check each hook returns; selector pins cover the busy detection. Mutations of the per-artifact compare, the call-site re-plan, a hook's return and the reconnect guard each turn a test red. Claude-Session: https://claude.ai/code/session_01SzES9BQh5PhrJhHdh9FSFw * ci: install cargo-make --locked (every zip 2.x was yanked) `cargo install cargo-make` now fails on every job: cargo-make 0.37.24 requires `zip = "^2"` and every zip 2.x release was yanked on 2026-10-16, so the unlocked install cannot resolve. --locked builds from cargo-make's own Cargo.lock (zip 2.2.2), which cargo still accepts. Verified locally. main is affected the same way on its next run. Claude-Session: https://claude.ai/code/session_01SzES9BQh5PhrJhHdh9FSFw * Revert "ci: install cargo-make --locked (every zip 2.x was yanked)" main fixed the same breakage in #794 (cargo-make as a prebuilt binary), which conflicts with this. Drop ours and take main's. Claude-Session: https://claude.ai/code/session_01SzES9BQh5PhrJhHdh9FSFw * fix(ui): address re-review of the stale-tab reload (#580) Should-fix findings from the second Full-tier review of #792: - A Connect skipped during a reload now still clears the reconnect latch, and a reload that does not happen re-sends Connect. Before, a socket lost during a reload that then failed left the tab disconnected. - The stuck clock starts when the reload is posted, not before the flush, and a flush that outlives the plan never posts a stray navigate. - A posted reload that never lands ends in ReloadFailed: the banner asks the reader to refresh the tab instead of offering the same reload again. - Reload/Not now cannot start a second reload or show a Reload button mid-reload. - A user action that queues a sync (mark_needs_sync) starts the settle period at once, so a quick send between ticks is not reloaded over; no automatic reload while disconnected; only in-flight invitation accepts count as busy. Tests: the driver's reload-due transition is the pure on_reload_due; the deliver_* return contracts are pinned; wiring pins are scoped to each hook's own block (the NotFound pin could be satisfied by the next statement), including the latch clear; all 13 overlay sites and the mark_needs_sync call are pinned; the archive guard test asserts exit 2 for an unreadable archive and that the call keeps `|| exit 1`. Docs: the remaining "pointers serve third parties only" lines; the history entry each reload adds is freenet/freenet-core#5910. Claude-Session: https://claude.ai/code/session_01SzES9BQh5PhrJhHdh9FSFw * fix(ui): only hold a generation reload while actually disconnected (#580) SYNC_STATUS is also set to Error(..) on a live socket (an unsupported operation), which would have held every reload forever. Wait only on Disconnected / Connecting. Claude-Session: https://claude.ai/code/session_01SzES9BQh5PhrJhHdh9FSFw * fix(ui): never reconnect a page the shell is replacing; hold reloads offline (#580) Must-fix findings from the third Full-tier review of #792: - "Offline" now means no live socket (WEB_API unset), not a status value. SYNC_STATUS reads Error through most of an outage, so a tab could reload into a dead node and land on the browser's error page. Nothing reloads while disconnected; the banner says it will reload once it reconnects, and the manual Reload is withheld. - A posted reload never reconnects. The shell closes the old page's sockets when it accepts `navigate`, and the new frame can take a 30 s container GET to arrive; a page that gave up at 20 s and reconnected leaked a socket into the next one. RELOAD_STUCK_MS is now 60 s, and ReloadFailed carries `reconnect`: true only if the socket is still open (the shell ignored the request). Only an unposted reload, which times out on its own after 30 s, calls abandon_reload. Should-fix: RELOADING is set synchronously with the phase change; busy and connection are re-checked just before posting (the plan is put back if not); abandon_reload retries reaching the synchronizer instead of dropping the Connect; the driver ticks every 5 s unless a reload is due within a minute; the hook is renamed note_sync_queued (network callers trigger it too); the NEEDS_SYNC wait is documented as the cheap check it is. Tests and pins: disconnected never reloads; a page being replaced never reconnects; unposted vs posted timeouts; drive() may call abandon_reload only for an unposted reload; the latch clear precedes the skip; the subscribe hook returns false; the guard script's exit-2 branches. Each new guard was mutated and a test went red. Claude-Session: https://claude.ai/code/session_01SzES9BQh5PhrJhHdh9FSFw * fix(ui): a posted reload never reconnects; let a Reload click through (#580) Findings from the fourth Full-tier review of #792: - A posted reload now never reconnects, failed or not. The "socket still open means the shell ignored it" escape only helped shells without `navigate`, which no compatible node serves, while a slow closing handshake can make a closed socket read open for up to a minute and reopen the socket leak. ReloadFailed loses its `reconnect` field; drive() never clears RELOADING. - The pre-post check is the pure `ready_to_post`, tagged with the attempt's start so a stale flush task never posts, and it lets a manual Reload through a busy reader (it used to bounce the click back to a countdown). Offline still waits. - One Offline banner (no buttons) for every state that would otherwise offer a Reload that cannot work while disconnected. - ConnectionLost with a reconnect already pending now also drops WEB_API: a failed attempt left the dead socket there, so "WEB_API set" did not mean connected. - The refresh banner warns that messages sent before refreshing may not be delivered (the page no longer reconnects). - UNPOSTED_TIMEOUT_MS 3 min: a long-hidden tab's timers run about once a minute. The driver no longer ticks every second past a due time. Tests: ready_to_post (stale tags, click through busy, offline waits); offline banners carry no Reload; a posted reload fails without reconnecting whether or not the socket looks open; drive() never clears RELOADING. Mutations of the manual exemption and the attempt tag each go red. Docs: "Reload now" -> "Reload"; river-publish no longer duplicates the telemetry figures (they live with RETRY_DELAYS_MS). The shell's late-close id race is freenet/freenet-core#5912. Claude-Session: https://claude.ai/code/session_01SzES9BQh5PhrJhHdh9FSFw * fix(ui): keep the update banner honest about the connection (#580) Findings from the fifth Full-tier review of #792 (no Must Fix): - The banner now follows the connection: the synchronizer calls generation_watch::on_connection_changed on ConnectionLost and on a failed Connect, and on_connected does too. A manual-only banner no longer keeps a Reload button after the node drops (the driver has stopped there), and an offline banner no longer outlives the outage. A click while offline shows the offline banner instead of doing nothing. - The offline banner is now "Waiting to reconnect to your node.", true for every state that shows it (Not now and a refused cap do not reload on their own). - A manual click that finds the node gone mid-flush goes back to the manual banner rather than becoming an automatic countdown. - A manual click waits out the settle period after a send before flushing. - A reload URL over the shell's 4096-byte limit counts as never posted (the shell would ignore it silently, and the page would never reconnect). - connected() treats a contended WEB_API borrow as connected (a send holds the socket). - Reverted the previous round's WEB_API take() in the ConnectionLost "reconnect pending" arm: it could close a healthy socket in a narrow sequence, a regression for every user, to avoid a rare reload into a dead node. Pins: RELOADING is cleared in one place, reached only before a post; nothing reconnects after a successful post; drive() passes manual=false with its attempt tag and reload_now passes manual=true; the banner hooks are wired. Claude-Session: https://claude.ai/code/session_01SzES9BQh5PhrJhHdh9FSFw * fix(ui): reload only once a reconnect has caught up; keep a clicked plan (#580) Findings from the sixth Full-tier review of #792 (no Must Fix): - "Connected" now also requires READY, set by on_connected (called after the synchronizer re-registers the delegate and processes the rooms) and cleared by on_disconnected (ConnectionLost, failed Connect). Before, a due reload could fire in the up-to-15 s after a socket opened but before what the reader sent offline had gone out. - A Reload click that finds the node gone mid-flush puts back exactly the phase it was clicked from: an automatic countdown stays automatic, the manual banner stays manual (reload_after_flush takes `clicked_from`). - A countdown that runs out while offline keeps a full countdown in hand, so reconnecting shows 15 s rather than reloading at once. - ReloadFailed carries `posted`: only a posted reload stops the page reconnecting, so only then does the banner warn that messages may not be delivered (a URL too long for the shell was never posted). - The shell-href limit applies only to the framed path, in UTF-16 terms. - A put-back refreshes the banner at once; comments no longer claim WEB_API is always cleared on loss. Pins: Connect is sent from abandon_reload only; the failed-Connect arm and ConnectionLost mark not-ready; READY is set only in on_connected, which runs after process_rooms; call sites pass None / Some(before). Claude-Session: https://claude.ai/code/session_01SzES9BQh5PhrJhHdh9FSFw * fix(ui): READY follows every connect and teardown, not duplicate losses (#580) Findings from the seventh Full-tier review of #792 (no Must Fix): - on_disconnected moved from the top of ConnectionLost into the teardown (armed) arm: a coalesced duplicate loss tore nothing down, but cleared READY, and a following Connect skipped as "already connected" never set it again, leaving the Offline banner on a live socket. - That skip path now calls mark_ready (the connect that made the live connection has finished; the synchronizer handles one message at a time). - A Connect that proceeds marks the page not ready before it starts: with no loss before it (the status can read Error on a live socket) it replaces the socket and spends up to 15 s catching up, and READY stayed true. - The unposted refresh banner says "Refresh this tab to get the update" (the page keeps working). Pins: on_disconnected is called in the teardown arm, before a Connect proceeds and on a failed Connect, never in the duplicate-loss arm; mark_ready in the skip path; on_disconnected clears READY; on_connected sets it before any early return; connected() requires READY && a socket; reload_now captures the pre-click phase before replacing it. The offline-hold test again pins non-countdown phases as unchanged. Claude-Session: https://claude.ai/code/session_01SzES9BQh5PhrJhHdh9FSFw * test(ui): scope the duplicate-loss pin to the ConnectionLost arm (#580) Round-8 review of #792: hook_block(&sync, "None =>") matched the first `None =>` in freenet_synchronizer.rs (an unrelated function), so the "a coalesced duplicate loss must not clear READY" assertion could never fail. Scoped to the ConnectionLost arm and checked it is the right arm; moving on_disconnected into that arm now turns the test red. The Connect-proceeds pin is now whitespace-insensitive. Claude-Session: https://claude.ai/code/session_01SzES9BQh5PhrJhHdh9FSFw
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.
cargo install --force cargo-makenow fails on every run: allzip2.x releases, which cargo-make 0.37.24 requires (zip = "^2"), have been yanked from crates.io.buildandui-playwright-testsstop at "Install cargo-make" before touching any code (e.g. run 38869289042 on #793). Because of--force, the cache never prevented the recompile.This switches both jobs to
taiki-e/install-actionwithcargo-make@0.37.24, which downloads the released binary, and drops the now-pointless cache step. Same version, no compile.Found while reviewing #793.
https://claude.ai/code/session_019J28r7v39Pf1XZDNUUAidG
[AI-assisted - Claude]