52f359a011
Desktop's cold resume (defer_history + omit_messages, transcript paged over REST) only ever holds the live tip segment in memory, but session.resume bounded it against the FULL compression lineage (sessions.max_resume_messages, default 20000). A Bot Chat with 85 compaction segments / ~29k lineage rows behind a ~700-row tip was refused at 20001, sent zero model prompts, and sat on "Waking up default…" forever — the healthiest possible session shape, rejected by a guard sized for in-memory materialization. - hermes_state: one `_resume_lineage_ids` definition shared by the resume readers (get_resume_conversations, get_ancestor_display_prefix) and the guard (assert_resume_safe / get_resume_message_count). Guard grows `tip_only=` and names the scope it counted; the branch-aware lineage the readers already used is now what the guard counts too (a /branch copy was being counted against its parent's rows). - tui_gateway session.resume: deferred, omit_messages and lazy resumes are bounded by the tip; only the full in-memory lineage resume keeps the lineage-wide bound. Deferred hydration falls back to tip-only history when the lineage exceeds the limit instead of loading the rows the guard refused. - CLI mid-setup tip-only path routes through the same guard instead of borrowing assert_export_safe. - docs: sessions.max_resume_messages / max_export_messages documented with the per-surface scope. Live repro (real SessionDB fixture, 85 segments / 29,226 lineage rows / 666 tip rows, real tui_gateway.server.handle_request): before — deferred resume -> 4130; after — ok, hydrated history=666 prefix=0; the non-deferred full resume still returns 4130 on the same fixture.