Skip to content

Delegate-cached room snapshot can be near-empty, not merely stale, and the 5-minute debounce does not explain it #622

Description

@sanity

Problem

During a delegate-migration rehearsal on 2026-08-12, a room restored from the chat delegate rendered with one member and no messages, while the predecessor generation still held the full state (2 members, 5 messages, verified directly against the fixture node before the run).

The room slot in the delegate is a debounced cache of room_state (RoomData.room_state, persisted at room_data.rs:200). The debounce is ROOM_SNAPSHOT_MIN_INTERVAL_MS = 5 minutes (chat_delegate.rs:4677). That explains a snapshot being stale by up to five minutes. It does not explain one that is nearly empty.

Something else emptied it, and that is unexplained.

Why this is worth its own investigation

This surfaced while diagnosing #621 (the backward probe cannot fire for delegate-restored rooms, because a PUT of this cached snapshot precedes the migration GET and suppresses the probe's trigger). The two are separate defects:

The interaction is what makes it worth attention. A full-but-stale snapshot pushed forward would have looked almost correct to a user, and #621 could have stayed hidden for several more releases. The near-emptiness is what made the symptom loud enough to investigate. If the emptiness has an independent cause, it may be producing quieter damage elsewhere.

Evidence available

  • room_synchronizer.rs:1504: No new messages detected for room MemberId(LZS6FCWR) (old_ids: 0, post-merge: 0) — confirms local state held zero messages before the merge, but says nothing about why.
  • Delegate slot ciphertext sizes at baseline: public room 1293 bytes, private room 2150 bytes, rooms_meta 134 bytes. The slots are encrypted under the node-local KEK, so contents could not be decoded directly.
  • Timing, offered as data and not as an explanation: seeded activity spanned 20:20:32 to 20:21:24, and the fixture snapshot was taken around 20:26, roughly five minutes after the last write. Whether the debounce deferred those writes, whether a teardown flush ran, and whether either relates to the emptiness are all unknown.

Questions to answer

  1. What writes room_state into the delegate slot, and under what conditions can it write a state with no messages when messages exist in memory or on the contract?
  2. Does a teardown or page-unload path flush the pending snapshot? If not, what happens to writes deferred by the debounce when the page closes?
  3. Can a room be persisted before its first contract sync completes, so the cached snapshot reflects a pre-sync state?
  4. Is the 5-minute debounce ever bypassed for a first write, and should it be?

Explicitly not assumed

No cause is proposed here on purpose. The rehearsal that found it did not have evidence to decide, and attaching a plausible-sounding guess to it would make it less likely that someone measures it.

Related

[AI-assisted - Claude]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions