PR #34 made FileStore's joinRoom re-derive the invited view from the per-agent operation maps, but inviteToRoom and declineInvite (src/core/store.ts) still mutate the invited array directly without recording invitedJoins/invitedLeaves. Consequence: on a FileStore, after inviting X and Y, any subsequent joinRoom — by anyone, even to a public room — re-derives invited from maps that never recorded those invites and wipes both pending invites.
The MeshStore path was fully converted and is test-covered; FileStore has no test coverage at all, which is why the suite stayed green. Fix: convert both sites to record ops exactly as the MeshStore sites do, and add FileStore coverage (invite survives an unrelated public join; decline/kick keep views and maps consistent).
Found while auditing #34's blast radius after the fact.
PR #34 made FileStore's
joinRoomre-derive theinvitedview from the per-agent operation maps, butinviteToRoomanddeclineInvite(src/core/store.ts) still mutate the invited array directly without recordinginvitedJoins/invitedLeaves. Consequence: on a FileStore, after inviting X and Y, any subsequentjoinRoom— by anyone, even to a public room — re-derivesinvitedfrom maps that never recorded those invites and wipes both pending invites.The MeshStore path was fully converted and is test-covered; FileStore has no test coverage at all, which is why the suite stayed green. Fix: convert both sites to record ops exactly as the MeshStore sites do, and add FileStore coverage (invite survives an unrelated public join; decline/kick keep views and maps consistent).
Found while auditing #34's blast radius after the fact.