66c7d5912b
Claude Fable 5's branch review found that receiver cancellation or a QUIC send failure could leave the sender-side archive producer blocked on the bounded frame channel. That kept the outbound transfer guard alive and could block later installs or updates of the same game. Route archive frames through a cancellable StreamInstallFrameSink instead of exposing the raw channel sender to providers. The QUIC forwarder now cancels and closes the receive side before awaiting the producer, so a blocked send wakes and the transfer guard can drop normally. Make PeerCommand::StreamInstallGame own its peer metadata preflight inside the peer core. The Tauri layer now sends the command directly, and the peer runtime fetches file details from catalog-version peers before running the existing majority validation and retry logic. This removes the UI-only pending streamed install set and gives PeerEvent::GotGameFiles one meaning again: continue a normal archive download. Tighten the receiver transaction edge cases too. Rollback removes a newly created empty game root, but preserves pre-existing roots. Once streamed staging has been promoted to local/, intent or launch-settings cleanup failures are logged for startup recovery instead of reporting a failed install for bytes that are already committed. Accept missing RAR CRC32 metadata for zero-byte files as CRC32 00000000 while still requiring CRC32 metadata for non-empty files. Update the peer README, scenario docs, and next-steps handoff so the documented ownership and remaining trust limitation match the implementation. Test Plan: - just fmt - just test - just frontend-test - just clippy - git diff --check - python3 -m py_compile \ crates/lanspread-peer-cli/scripts/run_extended_scenarios.py - python3 crates/lanspread-peer-cli/scripts/run_extended_scenarios.py \ S39 S40 S41 S42 S43 S44 S45 S46 S47 --build-image Refs: streamed-install review handoff from Claude Fable 5
67 lines
3.3 KiB
Markdown
67 lines
3.3 KiB
Markdown
# Streamed Install Next Steps
|
||
|
||
I’d treat the prototype as proof of the hard part: “can we stream
|
||
archive-derived install bytes into `local/` without making the receiver a
|
||
source?” Yes. Next I’d harden the pieces that decide whether this is
|
||
product-ready.
|
||
|
||
1. **Done — Move from CLI-only to real app integration**
|
||
|
||
The GUI now has an explicit “Low disk install” action in the game detail
|
||
modal for remote-only games. The Tauri backend queues that path through
|
||
`stream_install_game`, injects the shared external `unrar` stream provider,
|
||
and hands fetched file details to `StreamInstallGame` instead of the normal
|
||
download command.
|
||
|
||
2. **Done — Replace per-file `unrar p` with a final archive provider**
|
||
|
||
The shared external `unrar` stream provider now runs `unrar lt` once for the
|
||
archive metadata and one sequential `unrar p` pass per archive for payload
|
||
bytes. It frames directories, file starts, file chunks, and file ends from
|
||
the technical listing, so CLI and GUI callers use one purpose-built provider
|
||
instead of a per-file extraction loop.
|
||
|
||
3. **Done — Handle solid archives deliberately**
|
||
|
||
The provider exposes the RAR `solid` flag in `ArchiveBegin` and always uses
|
||
one sequential payload pass per archive, which is the safe path for solid
|
||
archives. S41 now verifies a real solid RAR fixture through the Docker
|
||
peer-cli flow, including local-only final state, absent root archive/sentinel,
|
||
byte count, and extracted payload SHA-256 hashes.
|
||
|
||
4. **Done — Decide the integrity model**
|
||
|
||
Streamed installs intentionally verify against sender archive metadata for
|
||
now: each file must match the RAR-advertised size and CRC32. That catches
|
||
transport corruption, truncation, and provider bugs, but does not claim
|
||
malicious-peer protection. Trusted content remains a separate catalog schema
|
||
step: add catalog-owned archive or extracted-file SHA-256 hashes, then verify
|
||
those at the receiver before commit.
|
||
|
||
5. **Done — Upgrade retry/resume semantics**
|
||
|
||
Streamed install attempts now use the same majority-validated peer set as
|
||
normal downloads, and each failed attempt rolls back its staging transaction
|
||
before trying the next peer. S42 pins the policy: retry the whole stream from
|
||
another validated peer, keep no partial files across attempts, and do not add
|
||
byte-offset resume until there is a strong reason.
|
||
|
||
6. **Done — Expand scenario coverage**
|
||
|
||
S43-S47 cover the remaining streamed-install edges: already-installed
|
||
rejection, corrupt archive rollback, sender disconnect mid-stream, receiver
|
||
cancel mid-stream, and multi-archive `.eti` roots streamed in sorted order.
|
||
The peer-cli harness now exposes `cancel-download` so cancellation scenarios
|
||
exercise the same runtime path as the GUI.
|
||
|
||
7. **Done — Clean product semantics**
|
||
|
||
The UI now keeps streamed installs in the installed visual state while making
|
||
the sharing limitation explicit: cards show `Not shareable`, and the detail
|
||
modal status shows `Installed, not shareable`. Downloaded-and-installed games
|
||
keep the normal `Installed` label.
|
||
|
||
The remaining production-readiness step is additive: move from sender-owned RAR
|
||
metadata to catalog-owned archive or extracted-file hashes, then verify those
|
||
at the receiver before committing the streamed install.
|