fix(peer): refresh settled install state after operations
The follow-up review found a few stale lifecycle edges around local game transactions. Recovery could sweep active roots, post-operation refreshes still re-ran full startup recovery, and the UI kept inferring local-only state from downloaded and installed flags instead of the backend availability. This updates the peer lifecycle so startup recovery skips active operations, install/update/uninstall refresh only the affected game after the operation guard is dropped, and path-changing game-directory updates are rejected while operations are active. It also removes the dead UpdateGame command, drops the unused manifest_hash write field while preserving old JSON reads, renames the internal install-finished event, and carries availability through the DB, peer summaries, Tauri refreshes, and the React model. The included follow-up documents record the review source, implementation decisions, and the remaining FOLLOW_UP_2.md work so later commits can stay small instead of reopening the completed plan items. Test Plan: - git diff --check - just fmt - just clippy - just test Follow-up-Plan: FOLLOW_UP_PLAN.md
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
# Follow-up Plan #2
|
||||
|
||||
State of FOLLOW_UP_PLAN.md after two implementation rounds. Items here are what's still open.
|
||||
|
||||
## Context for next time
|
||||
|
||||
Branch `p2p-codex-muenchhausen` has uncommitted work that completes the bulk of FOLLOW_UP_PLAN.md (52 tests pass via `just test`). Specifically these items in the original plan are **done** and shouldn't be re-opened: #1, #2, #3, #4, #5, #6, #7, #8, #9, #15, #17, #20, plus parts of #12 (update success, version-ini begin/rollback, multi-eti sorted order, corrupt + mismatched-id intent JSON).
|
||||
|
||||
The OperationGuard ordering fix in `handlers.rs` is the structurally most important change: install/update/uninstall now drop the guard _before_ the finish event and `refresh_local_game`, so peers see settled state in the next announcement instead of waiting for a scan tick. Tests `*_refreshes_settled_state_after_guard_release` pin this.
|
||||
|
||||
## Still open
|
||||
|
||||
### Correctness / runtime
|
||||
|
||||
#### 1. Tauri-side `active_operations` has no reconciliation
|
||||
|
||||
If a `PeerEvent::InstallGameFinished` / `…Failed` is dropped, the UI is stuck "installing" until app restart. Include an in-progress snapshot in `PeerEvent::LocalGamesUpdated` so the UI recomputes from authoritative state instead of accumulating from event history. (Was `#10` in original plan, deferred both rounds.)
|
||||
|
||||
### Tests still missing
|
||||
|
||||
#### 2. Install-recovery matrix (~10 rows)
|
||||
|
||||
Only two intent-driven rows are covered: `Updating | no local | .local.installing | .local.backup` (`recovery_restores_backup_for_interrupted_update`) and the active-skip case (`startup_recovery_skips_active_game_roots`). The other ~9 combinations of `(intent_state ∈ {Installing, Updating, Uninstalling}, local present?, .local.installing present?, .local.backup present?)` are unverified.
|
||||
|
||||
**Approach:** convert `recovery_restores_backup_for_interrupted_update` into a table-driven test. Iterate over the named matrix rows in PLAN.md, set up FS + intent, run `recover_game_root`, assert resulting FS + intent.
|
||||
|
||||
#### 3. Update rollback on commit-rename failure
|
||||
|
||||
Only extract-failure is tested (`update_failure_restores_previous_local`). The branch where extract succeeds but the staging→local rename fails is unexercised. Force it by making `local/` un-renamable (e.g. swap in a directory under that name post-extract) or by injecting a rename hook.
|
||||
|
||||
#### 4. Uninstall delete-failure restore
|
||||
|
||||
`restore_backup` rollback in `transaction.rs:107-114` is unreached by tests.
|
||||
|
||||
#### 5. Installed-only → Ready rescan
|
||||
|
||||
PLAN listed this. No test exercises the transition where a user drops `version.ini` into a `local/`-only game root and the next rescan flips it to Ready.
|
||||
|
||||
#### 6. Scanner gating dispatch
|
||||
|
||||
`handle_watch_event` and `RescanGate` / `run_gated_rescan` (`local_monitor.rs:208-287`) have zero tests. Cover:
|
||||
|
||||
- Event for ID under active operation is dropped.
|
||||
- Burst of events collapses to ≤2 rescans for the same ID.
|
||||
- Sideload picked up by fallback scan.
|
||||
- Non-catalog game produces no library index entry and no `LibraryDelta`.
|
||||
|
||||
#### 7. Serve gating dispatch
|
||||
|
||||
`local_download_available` predicate is tested; `handle_get_game_command`, `handle_get_game_file_data`, `handle_get_game_file_chunk` dispatch paths aren't. Small tests against an in-memory `Ctx` covering: non-catalog ID, mid-operation, missing sentinel.
|
||||
|
||||
### Code hygiene
|
||||
|
||||
#### 8. Consolidate `TempDir` test helper (getting worse)
|
||||
|
||||
Reimplemented in **five** test modules now: `install/intent.rs`, `install/transaction.rs`, `local_games.rs`, `download.rs`, `handlers.rs`. Each round of new tests adds another copy. Move to a single `test_support` module (or use the `tempfile` crate, already stable). The longer this waits, the bigger the eventual consolidation diff.
|
||||
|
||||
#### 9. `availability` field is `String`, not a typed enum
|
||||
|
||||
`lanspread-db::Game::availability: String` with `AVAILABILITY_*` consts works but allows invalid values. `remote_peer::summary_from_game` already has a defensive fallback for unknown strings. A typed enum + serde would be tighter, but is a wire-format change — coordinate if/when other peers are upgraded.
|
||||
|
||||
#### 10. `save_library_index` non-atomic
|
||||
|
||||
`local_games.rs:141-148` writes without temp+rename. Corrupt index → next scan rebuilds, so blast radius is small. Match the intent-log atomic pattern if touching that module.
|
||||
|
||||
#### 11. Split `download.rs` (1162 lines, growing)
|
||||
|
||||
Mixes chunk planning, retry orchestration, version-sentinel transaction, in-memory buffer, and the main loop. Future split into `download/{transaction,chunks,orchestrator}.rs`. Pure cosmetic.
|
||||
Reference in New Issue
Block a user