# Fable 5 findings > **Historical / superseded:** These findings assess the removed protocol-v7 > shared-certificate, client-authored, relayed event model. The current protocol > authenticates typed peer identities, accepts local intents, generates event > authority in the core, and pulls author-owned snapshots directly. Retain this > document only as historical review context, not a current issue list. Review of the issues Fable found after the Call to Play follow-up fixes. This document records the assessment only; it is not an implementation plan. ## 1. IP-based actor verification can reject legitimate peers **Assessment: real and must-fix.** `handle_call_to_play_events` requires the QUIC connection's source IP to match the peer's advertised listener IP. That assumption is unreliable for a multi-homed LAN machine: routing may select Ethernet, Wi-Fi, a VPN, or a bridge address different from the advertised address. The receiver silently drops the event, while the one-way sender sees a successful write and does not invoke its resync fallback. The check is not strong authentication either. Two peers on one host share an IP, and the project currently uses a shared application TLS certificate rather than a cryptographic identity unique to each `peer_id`. A normal client still stamps its own peer ID, so same-host impersonation requires a modified client, but the IP comparison should not be presented as an authenticated identity boundary. A sound correction must either bind a peer ID to a connection through a same-connection protocol exchange, return an application-level acknowledgement/rejection that can trigger resync, or deliberately rely on the documented trusted-LAN model without the unreliable IP equality test. ## 2. Evicted event IDs can prevent a revived call from healing **Assessment: real and must-fix together with finding 5.** Expiry removes call events from `events` but leaves their IDs in `event_ids`. If one peer expires a call and later receives an orphan `AddTime`, a subsequent handshake cannot restore the original `Create`: it is rejected forever as a duplicate. The call can therefore be alive on its creator while remaining invisible on the other peer. The ID set also grows without a bound for the session. Pruning expired IDs alone is not sufficient with the current `insert_all` behavior. A handshake commonly supplies `Create` followed by later actions; per-event compaction can expire and remove `Create` before the merge reaches the extending `AddTime`. Healing requires atomic batch semantics: validate and deduplicate the batch, merge it with retained events, then compact once using the complete history. Retained IDs should correspond to retained events and deliberate terminal tombstones, not every event ever observed. ## 3. `insert` can accept an event that compaction immediately removes **Assessment: correct, lower-severity correctness/semantics issue.** An action targeting a call that expired more than five minutes ago can be inserted, removed by compaction in the same operation, and still return `Ok(true)`. It is then emitted to the local UI and broadcast to peers even though it has no durable effect. The presentation reducer normally hides the result, but the accepted signal is misleading and the work is wasted. Store results should distinguish retained, duplicate, rejected, and immediately obsolete events, and only retained events should be emitted or broadcast. ## 4. "Add 5 more minutes" can shorten the deadline **Assessment: real user-visible bug.** The action currently sets the deadline to `now + 5 minutes`. If a roster fills early while the call still has more than five minutes remaining, the button shortens the call despite saying that it adds time. The intended calculation is `max(now, current deadline) + 5 minutes`. That also behaves naturally for an already expired call. ## 5. Handshake history merge is quadratic **Assessment: correct, and part of the correctness fix for finding 2 rather than merely a performance nit.** `insert_all` calls `insert` for every incoming event, and each insertion rebuilds several maps over the growing store while holding its write lock. Merging a large handshake history is therefore O(n²). Compacting once after an atomic batch merge removes that cost and is also what allows `Create` plus a later `AddTime` to revive consistently. Findings 2 and 5 should be treated as one store-semantics problem. ## 6. The startup error points users at the wrong cause **Assessment: correct UX issue.** When `actorId` is still unavailable, the peer may simply be starting. Telling the user to choose a game folder is misleading unless the application actually knows that the folder is missing. The normal startup state should say that Call to Play is connecting and ask the user to try again shortly; folder guidance should be reserved for a known missing-folder condition. ## Priority 1. Replace the unreliable IP identity check or make delivery acknowledged. 2. Correct batch merge, compaction, and event-ID retention as one change. 3. Correct the deadline-extension calculation. 4. Stop reporting and broadcasting immediately obsolete events. 5. Correct the startup message. The existing QUIC connection must not be described as carrying an authenticated per-peer identity until the protocol actually establishes one.