harden #5504 on rodboev's latest head: complete the tombstone wiring + CHANGELOG

@rodboev independently pushed fixes for messaging-tombstone (matches ours) and an
audit orphan-.bak skip — but the audit skip used _marks_deleted_webui_session
(index heuristic), which re-introduces the crash-suppression bug, and the other 4
resurrection/recovery paths were still open. Rebuilt the stage on rodboev's new
head (fc21c3f3, attribution preserved) and applied the complete superset:

- routes.py claim path: tombstone 404 gated on _state_db_session_source in
  ('','webui','fork') so foreign-source rows always materialize (finding B)
- models.py sidebar projection: skip tombstoned source='webui' rows w/ no live
  sidecar so a deleted session can't resurface in /api/sessions (finding C)
- session_recovery.py orphan-.bak startup: skip restore when durable tombstone
  present, durable-only (finding D)
- session_recovery.py audit orphan-.bak: durable-only classify as
  deleted_session_skipped (corrects rodboev's index-heuristic version)
- session_recovery.py _read_state_db_missing_sidecar_rows: durable-tombstone-only
  so a genuine crash (index intact, no durable tombstone) still repairs (finding F)

Regression tests (all verified fail-without-fix): sidebar-projection, orphan-.bak
startup skip, messaging-not-tombstoned, index-only-crash-repairable. Both advisors
(Codex SAFE TO SHIP + Opus ship-with-fixes) cleared the prior stage; this rebuild
carries the same fixes onto the contributor's latest work.

Co-authored-by: rodboev <rodboev@users.noreply.github.com>
This commit is contained in:
nesquena-hermesandrodboev committed 2026-07-04 05:32:51 +00:00
1 parent 06217c93b8
commit 63d0c00f8d
7 files changed
+193 -26

No files matched your search

+18
View File
@@ -5756,6 +5756,16 @@ def _load_cli_sessions_uncached(
return None
profile_value = _cli_profile or 'default'
# A deleted WebUI session is tombstoned (see _record_webui_deleted_session_tombstone)
# so recovery/audit/claim treat it as gone. The sidebar's own state.db projection
# must honor the same tombstone, or a deleted WebUI session reappears here as an
# "Agent" ghost the moment non-WebUI sessions are shown (#5498, second path). Only
# suppress genuine WebUI rows with no live sidecar — a re-created/re-imported sid
# (live {sid}.json) always beats a stale tombstone.
try:
_deleted_webui_tombstone = _load_webui_deleted_session_tombstone()
except Exception:
_deleted_webui_tombstone = frozenset()
for row in read_importable_agent_session_rows(
db_path,
limit=visible_session_limit if visible_session_limit is not None else (
@@ -5774,6 +5784,14 @@ def _load_cli_sessions_uncached(
profile = profile_value # CLI DB has no profile column; use active profile
_source = row['source'] or 'cli'
# Honor the deleted-WebUI tombstone: a WebUI row the user deleted must
# not resurface in this projection (the #5498 ghost). Live sidecar wins.
if (
_source == 'webui'
and sid in _deleted_webui_tombstone
and not (SESSION_DIR / f"{sid}.json").exists()
):
continue
_source_meta = normalize_agent_session_source(_source)
_title = row['title']
if not _title and _source == 'cron':