Skip to content

restore: project sidebar rows lazily instead of materializing full slots at boot (#895 Stage 2) #6144

Description

@iamwhatever

Split out of #895 as Stage 2, so Stage 1 (taking the restore disk reads off the event loop) could land on its own.

Stage 1 recap — what already landed

#895's Stage 1 moved every startup-restore disk read into asyncio.to_thread (open_slots.json, the agent→model map, list_sessions(), and per item get_metadata_status / get_metadata + read_messages_chained), leaving only the loop-affine slot mutation on the event loop. That stops the LoopStallWatchdog from killing the gateway mid-boot.

It did not change how much gets built.

Stage 2 — the remaining ask

Startup still materializes a full _ChatSlot for every restored row, including replaying up to 500 messages into memory, purely so the row can appear in the Sessions sidebar. A sidebar row needs a small projection — title, agent, model, folder, pin, colour, timestamps, unread state — not a hydrated transcript.

So the work is still O(all restored sessions × transcript size) at boot; Stage 1 only moved it off the loop thread. On a large home that is real wall-clock boot time and real resident memory for tabs the user may never click.

Shape

  • Restore sidebar rows as a lightweight projection built from the metadata line alone (no read_messages_chained, no slot.append replay).
  • Hydrate the full slot lazily, on first open, through the seam that already exists for exactly this: rehydrate_slot_from_history_async.
  • Keep the invariants Stage 1 pinned: the restoring_open_slots flush guard, the get_metadata_status readability flag (an unreadable row stays in the reopen seed rather than being dropped), _restricted_keys seeding by restore, and the post-hop _slots + close-tombstone revalidation now that read windows are wide.

Why it is separate

Stage 1 is a contained placement change with behaviour parity. Stage 2 changes what a restored slot is at boot, which touches every consumer that assumes a restored slot carries its messages (to_dict() sidebar payloads, _flush_dirty_slots and the _disk_window_len / _disk_older_count save model, the ACP history prefix). That deserves its own change and its own review.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: dashboardDashboard UI and its backend handlersenhancementNew feature or requestneeds-investigationTriage: requires deep analysis before a fix

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions