Skip to content

Dock snapshot polling scales O(N) with every process the session ever observed #15

Open

Description

@SamGalanakis

Risk (from the arc-4 delta review; not currently user-visible)

Since the #14 fix, the dock snapshot feed uses session.processes().list_all() on the ~250ms UI snapshot cadence (200ms deadline). At Lash 9debf5aab, list_all() → ProcessWorkObserver::observe_records awaits get_process_lease once per record, serialized on the same tokio_rusqlite connection live turns write through. Observer edges are deleted only on session deletion and lash-cli never calls prune_terminal_processes, so record count N grows monotonically for the session's lifetime (every subagent spawn adds one). On a deadline breach the snapshot returns processes: None and the dock silently stops updating.

Today N is small (a handful of subagent spawns per session), so this is a scaling cliff, not a live bug — but it is monotonic and silent.

Fix directions (either suffices)

  • Drive terminal-row visibility off the ProcessChanged event stream instead of polling list_all() (poll list() for running rows only; terminal rows enter via events and expire via the existing 10s window), or
  • Bound the poll: upstream ProcessListFilter gains a terminal-recency filter / bounded query (filed as Lash feedback), or CLI-side prune via prune_terminal_processes on a slow cadence.

Evidence

  • crates/lash-cli/src/ui_effects.rs (collect_ui_snapshot → list_all()), snapshot cadence crates/lash-cli/src/interactive/mod.rs (~854), 200ms deadline crates/lash-cli/src/interactive/helpers.rs.
  • Lash: crates/lash-core/src/process/observation.rs:234 (per-record lease await); crates/lash-sqlite-store/src/process_registry.rs:362 (edges deleted only with the session).

Activity

  1. SamGalanakis commented on Sep 8, 2026

    @SamGalanakis
    OwnerAuthor

    Re-scoped after PR #17 (pin 46dfed8ea): upstream landed the FIG-2311 asks — ProcessListFilter.retired_since_ms + batched lease reads — and the dock snapshot now polls list_observed_by with Any status and a retention-derived horizon, so per-record serialized lease lookups and unbounded result sizes are gone. Residual: list_observed_by still fetches all observer records at the registry and filters in memory (observer edges only die with the session), so the scan itself remains O(N-ever-observed). That SQL pushdown is tracked upstream as FIG-2488; keeping this open, narrowed to adopting whatever bounded observer read lands there (or moving terminal-row discovery to the ProcessChanged stream).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions