fix: follow-up for salvaged #60347/#43653/#47437

- derive the compact_rows projection from SCHEMA_SQL (parse once, cache)
  instead of a hardcoded column list: the original #47437 list was cut
  against a June schema and silently dropped session_key/chat_id/chat_type/
  thread_id/display_name/origin_json/expiry_finalized/git_branch/
  git_repo_root/compression_failure_* — including desktop sidebar fields.
  Schema-derived means declaratively reconciled new columns are included
  automatically; only system_prompt is excluded.
- guard test pinning the schema<->projection contract (mutation-verified:
  dropping a column from the projection fails it)
- wire compact_rows=(not full) into /api/sessions and /api/profiles/sessions
  so the SQL projection pairs with the API-level field strip (?full=1 still
  returns complete rows end-to-end)
- pass compact_rows at the remaining hot list callers: /api/status active
  count, _session_latest_descendant fallback, /api/sessions/stats by-source
- thread compact_rows through the compression-tip projection
  (_get_session_rich_row) so projected tips can't reintroduce the blob
- add pagination tests for get_messages (#60347 shipped none): paging order,
  offset-past-end, active-flag interaction; add tip-projection compact test
- AUTHOR_MAP entries for mahdiwafy + CodeForgeNet (plain emails)
This commit is contained in:
kshitijk4poor
2026-07-08 17:17:50 +05:30
committed by kshitij
parent 22eb1af23a
commit 4f220fc88b
4 changed files with 120 additions and 23 deletions
+25 -18
View File
@@ -2947,20 +2947,27 @@ class SessionDB:
current = child_id
return current
# All sessions columns except the large system_prompt blob, each prefixed
# with the "s" table alias used in list_sessions_rich/_get_session_rich_row
# queries. Used when compact_rows=True to avoid reading the blob for
# dashboard and picker callers that only need lightweight metadata.
_SESSION_COMPACT_COLS = (
"s.id, s.source, s.user_id, s.model, s.model_config, "
"s.parent_session_id, s.started_at, s.ended_at, s.end_reason, "
"s.message_count, s.tool_call_count, s.input_tokens, s.output_tokens, "
"s.cache_read_tokens, s.cache_write_tokens, s.reasoning_tokens, "
"s.cwd, s.billing_provider, s.billing_base_url, s.billing_mode, "
"s.estimated_cost_usd, s.actual_cost_usd, s.cost_status, s.cost_source, "
"s.pricing_version, s.title, s.api_call_count, s.handoff_state, "
"s.handoff_platform, s.handoff_error, s.rewind_count, s.archived"
)
# Columns excluded from compact_rows projections: only the payload-heavy
# blob no list consumer renders. Everything else — including gateway
# routing fields and desktop sidebar fields like git_branch — stays, and
# the projection is derived from SCHEMA_SQL so columns added later via
# declarative reconciliation are included automatically instead of
# silently dropping out of list rows.
_SESSION_COMPACT_EXCLUDED = frozenset({"system_prompt"})
_session_compact_cols_sql: Optional[str] = None
@classmethod
def _compact_session_cols(cls) -> str:
"""SELECT list for compact_rows: every ``sessions`` column declared in
SCHEMA_SQL except the ``system_prompt`` blob, aliased with the ``s``
prefix used by list_sessions_rich/_get_session_rich_row queries."""
if cls._session_compact_cols_sql is None:
declared = cls._parse_schema_columns(SCHEMA_SQL)["sessions"]
cls._session_compact_cols_sql = ", ".join(
f"s.{name}" for name in declared
if name not in cls._SESSION_COMPACT_EXCLUDED
)
return cls._session_compact_cols_sql
def distinct_session_cwds(self, include_archived: bool = False) -> List[Dict[str, Any]]:
"""Distinct non-empty session cwds with usage stats, for repo discovery.
@@ -3160,7 +3167,7 @@ class SessionDB:
outer_where = (
f"{where_sql} AND {combined}" if where_sql else f"WHERE {combined}"
)
_sel = self._SESSION_COMPACT_COLS if compact_rows else "s.*"
_sel = self._compact_session_cols() if compact_rows else "s.*"
query = f"""
WITH RECURSIVE chain(root_id, cur_id) AS (
SELECT s.id, s.id FROM sessions s {where_sql}
@@ -3207,7 +3214,7 @@ class SessionDB:
# only applies to the outer select.
params = params + params + id_params + [limit, offset]
else:
_sel = self._SESSION_COMPACT_COLS if compact_rows else "s.*"
_sel = self._compact_session_cols() if compact_rows else "s.*"
query = f"""
SELECT {_sel},
COALESCE(
@@ -3260,7 +3267,7 @@ class SessionDB:
if tip_id == s["id"]:
projected.append(s)
continue
tip_row = self._get_session_rich_row(tip_id)
tip_row = self._get_session_rich_row(tip_id, compact_rows=compact_rows)
if not tip_row:
projected.append(s)
continue
@@ -3354,7 +3361,7 @@ class SessionDB:
Pass ``compact_rows=True`` to omit the ``system_prompt`` blob (see
``list_sessions_rich`` for details).
"""
_sel = self._SESSION_COMPACT_COLS if compact_rows else "s.*"
_sel = self._compact_session_cols() if compact_rows else "s.*"
query = f"""
SELECT {_sel},
COALESCE(