Files
hermes-webui/tests/test_issue3595_activity_default_expanded.py
T
52261ebdaf Release v0.51.263 — Release IE (stage-r13) (#3625)
## Release v0.51.263 — Release IE (stage-r13)

Batch 1 (fresh) — trimmed to the clean pair after the gate held two.

### Fixed
| Issue/PR | Author | Fix |
|----------|--------|-----|
| #3621 | @luanxu-dev | `/codex-runtime` + `/codex_runtime` now run as a WebUI slash command (routed through the executor reusing the agent's `codex_runtime_switch`) instead of being sent to the model as a chat message. |

### Tests
| Issue/PR | Author | Change |
|----------|--------|--------|
| #3595 | @rodboev | Regression coverage for the already-shipped `activity_feed_expanded_default` setting. |

### Held back from this batch (Codex regression gate)
- **#3624** (passkey-challenge cap, security) — the cap **raises** `PasskeyRateLimitError` when full instead of **evicting oldest**, so an attacker (or 8 abandoned legit attempts per context) can lock out genuine registration/login until TTL — the protection becomes a lockout DoS. Held with the oldest-first-eviction fix.
- **#3618** (prefer server-side STT) — forcing MediaRecorder by default breaks browser `SpeechRecognition` dictation on installs with **no** server STT configured (`_transcribeBlob` only toasts on failure, never falls back). Held with the graceful-fallback fix.

### Gate
- Full pytest suite: **7714 passed, 0 failed**
- ESLint: CLEAN · ruff: CLEAN
- Codex (regression): SHIP-ONLY-WITH-FIXES (#3624 DoS-lockout + #3618 STT-no-fallback) → both dropped/held → **SAFE TO SHIP** (verified no passkeys.py/boot.js remnants, codex-runtime dispatch reaches the allowlist).

Co-authored-by: luanxu-dev <luanxu-dev@users.noreply.github.com>
Co-authored-by: rodboev <rodboev@users.noreply.github.com>
2026-06-04 23:56:44 -07:00

65 lines
2.8 KiB
Python

"""Pin the full behavioral contract for the Activity expanded-default setting."""
import pathlib
import re
ROOT = pathlib.Path(__file__).resolve().parent.parent
def test_setting_in_defaults():
src = (ROOT / "api" / "config.py").read_text(encoding="utf-8")
assert '"activity_feed_expanded_default"' in src or "'activity_feed_expanded_default'" in src, \
"activity_feed_expanded_default must exist in _SETTINGS_DEFAULTS"
# Verify default is False
assert re.search(r'["\']activity_feed_expanded_default["\']:\s*False', src), \
"activity_feed_expanded_default default must be False (collapsed)"
def test_setting_in_bool_keys():
src = (ROOT / "api" / "config.py").read_text(encoding="utf-8")
assert re.search(r'_SETTINGS_BOOL_KEYS\b.*?activity_feed_expanded_default', src, re.DOTALL), \
"activity_feed_expanded_default must appear inside _SETTINGS_BOOL_KEYS (not just anywhere in config.py)"
def test_boot_initializes_window_flag():
src = (ROOT / "static" / "boot.js").read_text(encoding="utf-8")
assert "activityFeedExpandedDefault" in src, \
"boot.js must initialize window._activityFeedExpandedDefault from settings"
def test_ensure_activity_group_checks_flag():
src = (ROOT / "static" / "ui.js").read_text(encoding="utf-8")
assert "_activityFeedExpandedDefault" in src, \
"ensureActivityGroup must check window._activityFeedExpandedDefault"
def test_per_turn_override():
src = (ROOT / "static" / "ui.js").read_text(encoding="utf-8")
assert re.search(r"savedState\s*===\s*['\"]closed['\"]", src), \
"ensureActivityGroup must check savedState==='closed' so per-turn persistence overrides the global default"
def test_collapse_class_applied():
src = (ROOT / "static" / "ui.js").read_text(encoding="utf-8")
assert "tool-call-group-collapsed" in src, \
"The collapsed class 'tool-call-group-collapsed' must be present in ui.js for the activity group"
def test_settings_checkbox_exists():
src = (ROOT / "static" / "index.html").read_text(encoding="utf-8")
assert "settings_label_activity_feed_expanded_default" in src, \
"index.html must have a settings checkbox with data-i18n for activity_feed_expanded_default"
def test_panels_wiring():
src = (ROOT / "static" / "panels.js").read_text(encoding="utf-8")
assert "activity_feed_expanded_default" in src, \
"panels.js must read/write the activity_feed_expanded_default setting"
def test_i18n_keys():
src = (ROOT / "static" / "i18n.js").read_text(encoding="utf-8")
assert "settings_label_activity_feed_expanded_default" in src, \
"i18n.js must have the label key for the setting"
assert "settings_desc_activity_feed_expanded_default" in src, \
"i18n.js must have the description key for the setting"