# Clean Code Plan 1: Split Local Library and Operation UI Signals ## Goal Replace the `a9f9845` local-update dedup cache with explicit event semantics. The peer runtime should report local library changes and active operation changes as separate facts, while the Tauri layer keeps joining those facts into the existing `games-list-updated` payload for the frontend. ## Architectural Picture The current overloaded shape makes `LocalGamesUpdated` carry two independent signals: - local library contents, whose source of truth is `LocalLibraryState` and `LocalLibraryState::update_from_scan`; - active operation status, whose source of truth is `Ctx::active_operations`. The clean boundary is: - peer scanning emits a local-library event when the scanned library state changes, with an explicit force policy for accepted path changes where the UI needs a fresh snapshot but peers do not need a delta; - operation-state mutation emits an operation snapshot when the mutation happens; - Tauri owns UI joining: it stores the latest catalog/local games and latest operation snapshot, then emits `games-list-updated` for the frontend. That keeps the frontend contract stable while removing the cross-cutting cache and every manual invalidation call. ## Implementation Steps 1. Remove commit `a9f9845` from the local branch history before implementing the replacement, so the final code is not built on the band-aid. 2. Replace `PeerEvent::LocalGamesUpdated { games, active_operations }` with: - `PeerEvent::LocalLibraryChanged { games }`; - `PeerEvent::ActiveOperationsChanged { active_operations }`. 3. Add one operation-snapshot publisher near the peer event helpers. All normal operation mutations must go through helpers that mutate `Ctx::active_operations` and then emit `ActiveOperationsChanged`. 4. Make `OperationGuard` publish an operation snapshot when it performs exceptional cleanup on drop, so cancellation or aborted tasks do not leave UI state stale. 5. Keep the existing scan behavior that freezes active game summaries while an operation is running, but emit `LocalLibraryChanged` only when `update_from_scan` returns a real delta or the scan was explicitly forced by an accepted path change. 6. Update the Tauri event loop to reconcile `ActiveOperationsChanged` independently, and call `emit_games_list` after both library and operation state changes. 7. Update focused tests in peer handlers, local monitor, liveness, context guard, and Tauri reconciliation to prove: - unchanged settled scans do not emit local-library events; - operation starts/transitions/ends emit authoritative snapshots; - exceptional guard cleanup clears the operation snapshot; - Tauri still emits the same `games-list-updated` UI payload. 8. Update `CLEAN_CODE.md`, `crates/lanspread-peer/ARCHITECTURE.md`, and `crates/lanspread-peer/README.md` so the docs describe the new shape rather than the dedup warning. ## Review Gates - No `last_local_update_key`, `LocalUpdateKey`, or invalidate helper remains. - No operation-state mutation that should be visible to the UI bypasses the snapshot publisher. - The peer event names reflect domain facts, not UI implementation details. - Tauri remains the compatibility boundary for the frontend payload. - Verification runs through `just fmt`, `just test`, `just clippy`, and `git diff --check`.