docs(changelog): stamp #6938 + add loadSession compression-cleanup regression test
Co-authored-by: happy5318 <happy5318@users.noreply.github.com>
This commit is contained in:
1 parent
f7887bfc87
commit
fb5a40f132
2 files changed
+99
No files matched your search
@@ -5,6 +5,8 @@
|
||||
|
||||
### Fixed
|
||||
|
||||
- **No more phantom "Compressing context" barrier after switching sessions.** The compression UI state is per-session, but `loadSession()` did not clear it on a switch, so a compression card from a prior session could leak across the load and appear as a phantom "Compressing context" barrier on a fresh session that never triggered compression. Switching sessions now clears the compression UI (state, elapsed timer, composer session-lock, and barrier element) alongside the other per-session resets, before the transcript loads. A compression genuinely running on the session you switch *to* is unaffected — it re-surfaces from that session's own live event stream (and manual compression from its server job status). Thanks @happy5318. (#6938)
|
||||
|
||||
- **Layout test helper no longer flags scroll-reachable fields as off-viewport.** The shared `assert_layout_sane` degenerate check reported a false "interactive element is off-viewport" for an input that sits below the fold at rest but is reachable by scrolling an `overflow-y:auto` ancestor (e.g. a tall dialog on a short landscape viewport). It now exempts elements whose off-viewport edge is absorbed by a scrollable ancestor, while still flagging genuinely-unreachable elements (no scroll escape). The Kanban board settings modal layout test also drops its synthetic 480×320 short-landscape case (a viewport no real device uses, whose sub-fold geometry was environment-marginal and CI-flaky); real desktop/tablet/narrow viewports still assert the layout. (internal test infra)
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
"""Regression: ``loadSession`` must clear stale compression UI state on switch (#6572).
|
||||
|
||||
Context
|
||||
-------
|
||||
The compression UI state (``window._compressionUi`` plus its elapsed timer,
|
||||
composer session-lock, and the "Compressing context" barrier element) is
|
||||
per-session. Before this fix, ``loadSession`` in ``static/sessions.js`` did not
|
||||
clear it when switching sessions, so a compression card belonging to a prior
|
||||
session leaked across the load and surfaced as a phantom "Compressing context"
|
||||
barrier on a fresh session that never triggered compression.
|
||||
|
||||
The fix clears the state near the top of ``loadSession`` — alongside the other
|
||||
per-session resets (``_yoloEnabled=false``, ``stopClarifyPolling``,
|
||||
``hideClarifyCard``) and before transcript loading — by calling the canonical
|
||||
``clearCompressionUi()`` teardown (defined in ``static/ui.js``), with a
|
||||
fail-soft ``window._compressionUi=null`` fallback if the function is not yet
|
||||
defined:
|
||||
|
||||
if(typeof clearCompressionUi==='function') clearCompressionUi();
|
||||
else window._compressionUi=null;
|
||||
|
||||
This is safe for a compression genuinely running on the *target* session:
|
||||
clearing only tears down browser-local UI state; an active automatic
|
||||
compression re-surfaces from the target session's own SSE ``compressing``
|
||||
stream, and a manual compression is re-discovered from server job status when
|
||||
its session loads. Releasing the composer session-lock does not signal or
|
||||
cancel the backend compression.
|
||||
|
||||
Per AGENTS.md the WEBUI suite intentionally avoids a node/jsdom dependency, so
|
||||
this is a source-level grep + brace-balance assertion — the same convention the
|
||||
rest of the JS regression suite uses (e.g.
|
||||
``test_bg_task_complete_loadsession_stream_restart.py``).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
def _read_sessions_js() -> str:
|
||||
return (REPO_ROOT / "static" / "sessions.js").read_text()
|
||||
|
||||
|
||||
def _load_session_body() -> str:
|
||||
"""Return the ``async function loadSession(`` source slice → next top-level
|
||||
``function`` / ``async function`` declaration."""
|
||||
js = _read_sessions_js()
|
||||
start = js.index("async function loadSession(")
|
||||
rest = js[start + 1 :]
|
||||
m = re.search(r"\n(async function |function )", rest)
|
||||
end = start + 1 + (m.start() if m else len(rest))
|
||||
return js[start:end]
|
||||
|
||||
|
||||
def test_loadsession_clears_compression_ui_state():
|
||||
"""loadSession must clear per-session compression UI state on switch."""
|
||||
body = _load_session_body()
|
||||
# The canonical teardown must be invoked, with a fail-soft fallback so a
|
||||
# partial script load cannot leave a dangling barrier/timer/lock.
|
||||
assert "clearCompressionUi()" in body, (
|
||||
"loadSession must call clearCompressionUi() to clear stale per-session "
|
||||
"compression state (#6572 phantom barrier)"
|
||||
)
|
||||
assert re.search(
|
||||
r"typeof\s+clearCompressionUi\s*===\s*['\"]function['\"]", body
|
||||
), "the clearCompressionUi call must be typeof-guarded"
|
||||
assert re.search(
|
||||
r"else\s+window\._compressionUi\s*=\s*null", body
|
||||
), "a fail-soft window._compressionUi=null fallback must guard the guarded call"
|
||||
|
||||
|
||||
def test_loadsession_clears_compression_before_transcript_load():
|
||||
"""The clear must precede transcript rendering so no phantom barrier shows.
|
||||
|
||||
It must sit with the other early per-session resets (near hideClarifyCard),
|
||||
not after renderMessages(), otherwise a stale barrier could paint for a
|
||||
frame on the freshly loaded session.
|
||||
"""
|
||||
body = _load_session_body()
|
||||
clear_idx = body.index("clearCompressionUi")
|
||||
# Anchored to a sibling early reset that is known to run near the top.
|
||||
assert "hideClarifyCard" in body, "expected hideClarifyCard reset in loadSession"
|
||||
clarify_idx = body.index("hideClarifyCard")
|
||||
# The compression clear should be co-located with the other early resets.
|
||||
assert abs(clear_idx - clarify_idx) < 600, (
|
||||
"clearCompressionUi() should sit with the other early per-session resets "
|
||||
"(near hideClarifyCard), before transcript loading"
|
||||
)
|
||||
# And it must come before the success-tail render.
|
||||
render_match = re.search(r"renderMessages\s*\(", body)
|
||||
if render_match:
|
||||
assert clear_idx < render_match.start(), (
|
||||
"clearCompressionUi() must run before renderMessages() so a stale "
|
||||
"compression barrier never paints on the loaded session"
|
||||
)
|
||||
Reference in new issue
Block a user