Commit Graph
4 Commits
Author SHA1 Message Date
happy5318 f33ac82ca1 fix(session): guard truncation flags before read in settle strategy (CI)
test_issue6867 extracts _restoreSettledSession into a bare harness where
the module-level _messagesTruncated/_oldestIdx lets are absent; a bare
read threw ReferenceError and the whole recovery path died before it
could restore. Use typeof guards like the surrounding paging restores.
The semantics are unchanged in the real page (both are always declared).
2026-09-19 13:35:13 +08:00
happy5318 95c174f038 fix(session): restore paging after compress; suffix-exclusive settle strategy (review round 3)
Two data-integrity blockers from round-3 review (nesquena-hermes 2026-09-19):

1. [CORE] A successful /compress returns the full transcript, but
   _applyManualCompressionResult kept the bounded preflight's paging
   signals (_messagesTruncated/_oldestIdx). Render now restores them
   before renderMessages(), same ordering as settle/cancel paths.

2. [SILENT] _restoreSettledSession preservation used
   (prefix || suffix), so repeated identical turns (colliding
   _messageIdentityKey) made BOTH comparisons succeed and the prefix
   branch spliced at the wrong offset - silently dropping rows and
   duplicating others. The server truncation signal now decides the
   strategy: truncated => suffix-exclusive, untruncated => prefix.

Tests: node behavioral driver covering /compress paging restore,
repeated-turn settle (no drop/dup, authoritative offset), and
gap-free msg_before paging after bounded recovery.
2026-09-19 12:55:40 +08:00
happy5318 f4b28346e5 fix(session): keep bounded-tail recovery suffix and paging offset
Bounded settle/cancel reloads return the latest 30 messages, not a
prefix of the visible window. The shorter-terminal preserve path only
compared prefixes, so a long session dropped the Connection-interrupted
marker. Anchor persist also ran before _oldestIdx was refreshed from
the bounded response, writing the scene against the wrong transcript
row.

- Treat a suffix match like a prefix match when preserving the terminal
  recovery marker
- Refresh _messagesTruncated / _oldestIdx before attaching/persisting
  the projected scene on settle, cancel, and apperror
- Document the msg_limit=30 / msg_limit=all contract
- Add runtime + source-order regression tests
2026-09-18 22:00:45 +08:00
happy5318 d24d6377f9 perf(api/session): bound recovery calls; add msg_limit=all escape hatch
Fixes the #7310 stall class: six frontend recovery paths (offline/bfcache
refreshSession, stream-end settle, cancel sync, /compress preflight, /retry,
/undo) issued bare GET /api/session reads that re-walked, re-redacted and
re-serialized the ENTIRE transcript (4-15s / 28MB on a 5k-row session,
#7625), and the same shape shipped the full session-level tool_calls list
because windowing was gated on msg_limit being present.

Changes:
- Server: add explicit msg_limit=all escape hatch; window session-level
  tool_calls by actual truncation (length comparison) instead of the
  presence of a limit parameter. The bare no-limit shape keeps its
  full-transcript contract (pinned by
  test_state_db_reconciliation_preserves_sidecar_order_when_timestamps_collide
  and the run-journal snapshot test).
- Client: refreshSession / _restoreSettledSession / cancel sync /
  /compress preflight / /retry / /undo now request the bounded tail
  (msg_limit=30) and restore the _messages_truncated/_messages_offset paging
  gate instead of hardcoding 'not truncated'; jump-to-start
  (_ensureAllMessagesLoaded) and outline jump opt in to the full transcript
  via msg_limit=all.

Tests: test_session_default_window.py covers helper semantics, per-call-site
bounded/all shapes, truncation-signal restoration, and a regression guard
that no bare GET /api/session fetch remains in static/. 454 related tests
pass; reverse-verified (reverting the fixes turns the tests red).
2026-09-18 11:24:51 +08:00