Opus caught a narrow timing race: if a reader re-pins between the scroll-rebuild
guard engaging and its deferred rAF firing, the stale re-restore would yank them
back off the bottom. Gate the re-restore on _messageUserUnpinned at rAF time; the
minHeight release still always runs. Normal single-render unpinned case unaffected.
Codex regression gate caught: the guard predicate keyed on a raw messagesEl.scrollTop>0,
so a pinned reader transiently at bottomDistance>250 mid-render (assistant body grows
before the anchor scene re-renders) got flipped to _messageUserUnpinned=true/_scrollPinned=false
and lost auto-follow. Require an explicit non-follow signal (_messageUserUnpinned || _scrollPinned===false)
instead. Updated the existing guard test to a genuine unpinned reader + added a pinned-large-growth
regression. Co-authored-by: franksong2702
#4774 moved the version-token substitution from the index route handler into the cached
_render_index_shell_base() helper. quote(WEBUI_VERSION, safe='') encoding is intact (verified),
just relocated, so the source-marker test scanning the route block no longer found it. Updated
to check the helper. Maintainer test-fix on boriken72's PR.
The `/`, `/index.html`, and `/session/<id>` routes are the hottest
navigations. Each request re-read the ~190 KB static/index.html from disk
and re-applied two process-constant token substitutions
(__WEBUI_VERSION__, __MAX_UPLOAD_BYTES__), then ran inject_extension_tags()
(which itself reads the extension state + manifest from disk).
WEBUI_VERSION and MAX_UPLOAD_BYTES are fixed for the process lifetime, so
this caches the partially rendered template in an in-process cache keyed by
(size, mtime_ns) -- mirroring the existing _STATIC_CACHE pattern in this
file -- so a redeploy is still picked up without a restart. The per-session
CSRF token and runtime extension tags are still applied per request, so
output is byte-identical to before.
Verified: byte-identical to the old inline render, CSRF still varies per
request, cache invalidates on mtime change, ~5x faster shell render in a
local microbenchmark. Adds tests/test_index_shell_template_cache.py.
* test(#4740): pin HERMES_HOME in readonly-scope pool test to fix order-dependent flake
test_active_request_readonly_scope_blocks_pool_env_seed failed only under
full-suite ordering (passed in isolation). Root cause, captured via an
assertion-time diagnostic: the readonly scope correctly blocks the process-env
credential fallback (branch 2 returns ''), but _has_explicit_pool_credentials
(branch 3) calls read_credential_pool, which falls back to the GLOBAL-root
auth.json via get_default_hermes_root() — and that reads os.environ['HERMES_HOME']
DIRECTLY, not the thread-local/scoped home. Under suite ordering HERMES_HOME
pointed at the shared persistent test state dir, where an earlier test had
persisted an openrouter credential_pool entry (source: env:OPENROUTER_API_KEY)
into auth.json. The global-root fallback found that leaked entry, so
_provider_has_key('openrouter') returned True and the assertion failed.
Fix: monkeypatch.setenv('HERMES_HOME', <tmp base>) so the global-root fallback
resolves to this test's own empty tmp dir with no leaked auth.json. Test-only;
no product change. Verified: passes in isolation AND the target test now passes
under the full suite (the only remaining full-suite reds were unrelated
subprocess-timeout SIGKILLs in test_tls_support under load, which pass on re-run).
* test(#4740): retry config-probe subprocesses in test_tls_support under load
The 3 TestTLSConfigFlag tests spawn a 'python -c' subprocess that imports
api.config (heavyweight) with a 10s timeout. Under the fully parallel full
suite the box can be saturated enough that the import exceeds 10s and the
runner SIGKILLs the child (returncode -9) — a pure resource-contention flake
(passes in isolation). Add _run_config_probe(): 60s timeout + retry on
TimeoutExpired/SIGKILL, returning a real non-zero exit immediately so genuine
failures still surface. Zero-flake-tolerance sweep (#4740).
---------
Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
The assistant message footer (model · duration · tokens · cost · cache% · time · actions)
could overflow its row on mobile/narrow panes, pushing the per-message action buttons off
the right edge where they were unreachable. #4724 proposed ellipsing every stat, which
shrank them into unreadable stubs (D…, 98…). This instead lets .msg-foot flex-wrap to a
second line: every stat stays full-size + readable, the actions/time are pinned flex:0 0
auto so they never shrink and stay on-screen, and on wider screens where it already fits
wrap never triggers. Pure CSS. + source-structure regression test.
Co-authored-by: starship-s <starship-s@users.noreply.github.com>