Skip to content

fix(sidebar): prevent orphan coordinator sessions from consuming SDE page capacity #803

Description

@ShiboSheng

Description

The SDE AGENT sidebar section can render far fewer than its configured 10-row first page even though many standalone SDE sessions exist. In the observed database, the first backend page contained 10 rows, but 8 were orphaned Agent Org coordinator sessions. The frontend correctly hid those member rows, leaving only 2 visible SDE sessions and a Load more control.

PR #576 and PR #628 fixed the same class of pagination bug for normal Agent Org topology, but their backend predicates cover child sessions through parent_session_id and roots through agent_org_runs.root_session_id. They do not cover a historical coordinator row whose run record is no longer present:

session_type = 'sde'
parent_session_id = NULL
org_member_id = 'coordinator'
no matching agent_org_runs.root_session_id

That row is classified differently across the pagination boundary:

  • The backend standaloneAgent query treats it as standalone and counts it before LIMIT.
  • The frontend isPrimarySessionListSession treats it as an Agent Org member and removes it after the page is returned.

This violates the sidebar invariant that every row consuming native page capacity must be listable in the owning section.

Steps to Reproduce

  1. Persist at least 8 recent agent_sessions rows with session_type='sde', parent_session_id IS NULL, and org_member_id='coordinator', without matching agent_org_runs rows.
  2. Persist at least 11 ordinary, unpinned, non-archived standalone SDE sessions behind them by updated_at.
  3. Launch ORG2 and open the session-history sidebar.
  4. Inspect the SDE AGENT section.

Expected Behavior

  • The first standaloneAgent page contains 10 listable standalone SDE sessions.
  • Orphaned Agent Org member/coordinator rows do not consume standalone or pinned native page capacity.
  • hasMore and the keyset cursor are calculated from eligible rows.
  • Valid Agent Org roots with a matching agent_org_runs.root_session_id continue to appear in the Agent Org or Pinned stream.

Actual Behavior

  • The backend returns 10 raw standalone rows and reports more history.
  • The frontend removes rows carrying orgMemberId without agentOrgId.
  • In the observed data shape, 8 of the first 10 rows were removed and only 2 SDE sessions rendered.
  • Clicking Load more reveals older standalone sessions because the next cursor starts after the hidden rows.

Root Cause

list_standalone_coding_sessions_page applies session_type, archive, pin, parent, and Agent Org root predicates before LIMIT, but does not apply the existing listability invariant represented by org_member_id.

The same issue class can affect the global Pinned native stream: a pinned orphan coordinator can consume its bounded page and then be removed by the frontend. The Pinned predicate must continue allowing valid Agent Org roots while excluding member rows that have no matching run.

Proposed Scope

  • In src-tauri/crates/agent-core/src/core/session/persistence/sidebar.rs, exclude s.org_member_id IS NOT NULL from the standalone SDE stream before LIMIT.
  • In src-tauri/src/agent_sessions/session_directory/aggregation.rs, exclude orphan member rows from the Pinned native query before LIMIT, while retaining rows that are valid Agent Org roots.
  • Keep the frontend visibility predicate as defense in depth; do not add another UI-only filter.
  • Do not mutate or delete historical session data as part of this fix.
  • No schema, migration, RPC, or TypeScript change should be required. The existing idx_agent_sessions_sidebar query plan remains usable with the additional predicate.

Acceptance Criteria

  • A page containing newer orphan coordinator rows still returns 10 standalone SDE rows when 10 are available.
  • Keyset continuation returns the next eligible standalone row without duplicates or skips.
  • Orphan member rows cannot inflate hasMore or consume Pinned native capacity.
  • Valid Agent Org roots remain visible in their normal and pinned placements.
  • Rust regression coverage includes org_member_id='coordinator' with no matching run row.
  • The relevant SQLite query-plan test continues to use idx_agent_sessions_sidebar and idx_agent_org_runs_root_session.
  • Rendered/manual verification proves the SDE first page is full without an initial Load more click.

Environment

  • OS: macOS
  • App version / commit: 1.2.5 / 29f031b07
  • Agent type: SDE Agent / Agent Org coordinator history

Logs / Screenshots

Observed authoritative database counts:

non-archived SDE sessions: 107
SDE rows with org_member_id='coordinator': 43
first backend standalone page: 10 rows
frontend-listable rows in that page: 2

Additional Context

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions