Release DL — stage-batch22 — 5-PR hold-bucket reassessment (v0.51.140)#2990
Merged
Conversation
_loadOlderMessages() previously fetched older messages with the legacy index-cursor page (msg_before=_oldestIdx&msg_limit=30) and prepended the page to S.messages. After #2716 the backend always runs the full append-only merge for /api/session?messages=1 — the same merge as a larger msg_limit on the same call — so we can ask for a larger authoritative tail window directly instead of stitching pages on the client. Behavior * Default request shape becomes msg_limit=currentLoaded+30. The newly exposed head of the response is what the user sees as 'older messages'. No new query parameters. * msg_before remains supported by the backend and is retained in the client as a race-fallback path: if the returned tail no longer has the currently displayed messages as a suffix (because the session appended new messages mid-flight, or merge filtered something), the client issues the legacy msg_before page and prepends it instead. This preserves correctness under concurrent appends. * Suffix-continuity uses the existing _sameTranscriptMessage helper, which tolerates timestamp drift and content-array reshapes. * Existing race guards (loadingSessionId, S.session.session_id, and the _messagesGeneration snapshot from #1937) are reapplied after the fallback await. Tests Updated four static-string assertions in the existing scroll/viewport tests to track the new mutation site (S.messages = nextMessages) and the new msg_limit=requestedLimit shape, while still asserting that msg_before remains in the body for the race-fallback path. pytest -q tests/test_older_history_viewport_preservation.py tests/test_parallel_session_switch.py tests/test_issue1937_endless_scroll_jumpstart_race.py tests/test_session_tail_payload.py -> 52 passed node --check static/sessions.js -> ok Notes Originally part of PR #2835. That PR was closed because of an architectural conflict with #2716 on a different file (api/models.py metadata-only path). #2716 left static/sessions.js untouched — this change applies cleanly on post-#2716 master with no rebase work.
…h.json fingerprint auth.json is rewritten by credential-pool/OAuth token refresh roughly every 14 minutes. _models_cache_source_fingerprint() hashed it via mtime/size (#1699 _models_cache_file_fingerprint), so every token refresh churned the fingerprint and the 24h /api/models cache was effectively dead -- the hot GET /api/session?resolve_model=1 path paid a cold ~11.5s rebuild every few minutes (RCA t_d127953d residual #2, t_16551f61). Add _auth_store_semantic_fingerprint(): content-hash auth.json with a DENY-list of known credential-rotation-only keys (access/refresh token, expiry, per-credential status/telemetry, request_count, save updated_at) stripped. Deny-list (not allow-list) is deliberate -- any unknown field, or a real provider/endpoint/model-set change (active_provider, a new credential_pool entry, base_url, source, label, auth_type, the providers{} block, ...) stays in the fingerprint and still correctly busts the cache. Conservative fallbacks: missing file -> marked; unreadable/corrupt -> stat-based fallback (never less safe than pre-fix). config.yaml keeps the cheap stat fingerprint (deliberate edits, no timer churn). Bidirectional invariant regression test (non-tautological -- the end-to-end churn test flips RED when the auth_json axis is reverted to stat-based): token-only churn keeps fingerprint byte-identical AND keeps a valid disk cache loadable; active_provider change / new credential_pool entry / changed base_url each flip the fingerprint AND reject the stale disk cache. Measured: 5/5 cold rebuilds per 5 refresh cycles -> 0/5. Tests: 9 new pass; 28 adjacent (#1699/#1633/display-resolver) pass; 54 models_cache/fingerprint suite pass.
# Conflicts: # CHANGELOG.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release DL / v0.51.140 — stage-batch22 (5 PRs from re-examined hold bucket)
This is a deliberate "actually-reviewable" pass through the hold bucket. All 5 PRs were previously labeled
holdbut on second read are bounded enough to ship without architectural input.PRs merged
_message_window_for_display()anchors paginated window on newest renderable row (skips tool-only tail)._smdRendererWithoutUnderscoreEmphasis()wraps smd renderer soagent_responseandfoo_barstay literal while streaming (matches settled renderer)._loadOlderMessages()switches to cumulativemsg_limit=current+30tail load with suffix-continuity guard + legacy-page fallback.renderMessages()perf: cachesrenderMd/_renderUserFencedBlocksoutput, caches visible-message scan, scopes question→assistant lookup to render window, lazy Prism highlight.Verification
ast.parseclean on 9 changed .py,node -cclean on messages/sessions/ui.js-p no:xdist)test_unknown_field_stays_in_fingerprint)_sameTranscriptMessage(role + content, not reference); fallback reapplies session/generation guards after second awaitmby reference — in-place mutations oftool_calls/contentare visible on read; cache key collision rare-but-bounded for >500 char messages_messages_offsetcontract from opposite sides, frontend just consumes the fieldHold-bucket re-classification rationale
Each of these was previously hold-labeled with a different actual blocker than "needs deep review":
holdfrom before today's sweeps; the actual conflict was CHANGELOG-only.holdfrom the cumulative-tail discussion in perf(session): optimize metadata polling and history loading #2835. The suffix-continuity guard is exactly the safety mechanism a reviewer would request — it's already there.This batch sits on top of v0.51.139 (Release DK).