Merge pull request #4575 from nesquena/stage-4566

Release v0.51.546 — fix flaky gateway_sync test (#4566/#4557)
This commit is contained in:
nesquena-hermes authored and GitHub committed 2026-06-20 19:21:59 -07:00
commit fde3b0962a
4 files changed
+35 -2

No files matched your search

+6
View File
@@ -3,6 +3,12 @@
## [Unreleased]
## [v0.51.546] — 2026-06-21 — Release TE (fix a flaky gateway-sync CI test)
### Fixed
- **Eliminated a non-deterministic CI test flake (#4557).** `test_gateway_sync` could intermittently fail (a session missing from `/api/sessions`) when a settings-visibility toggle rewrote the settings file inside the same `mtime_ns` bucket, colliding two cache layers. The session-list cache source stamp now includes a monotonic per-process settings-write counter (so a same-millisecond rewrite can't reuse a stale cache entry), and the model-layer CLI-sessions cache is now flushed on the visibility toggle. Test-infrastructure reliability only — no runtime behavior change. Thanks @rodboev.
## [v0.51.545] — 2026-06-20 — Release TD (extension manifest asset bundles)
### Added
+6
View File
@@ -7372,6 +7372,9 @@ _SETTINGS_BOOL_KEYS = {
# Language codes are validated as short alphanumeric BCP-47-like tags (e.g. 'en', 'zh', 'fr')
_SETTINGS_LANG_RE = __import__("re").compile(r"^[a-zA-Z]{2,10}(-[a-zA-Z0-9]{2,8})?$")
_SETTINGS_WRITE_VERSION = 0
_SETTINGS_WRITE_LOCK = __import__("threading").Lock()
def save_settings(settings: dict) -> dict:
"""Save settings to disk. Returns the merged settings. Ignores unknown keys."""
@@ -7481,6 +7484,9 @@ def save_settings(settings: dict) -> dict:
json.dumps(persisted, ensure_ascii=False, indent=2),
encoding="utf-8",
)
global _SETTINGS_WRITE_VERSION
with _SETTINGS_WRITE_LOCK:
_SETTINGS_WRITE_VERSION += 1
# Invalidate the in-memory password hash cache so the next call to
# get_password_hash() picks up the new value from disk immediately.
if _password_changed:
+13 -2
View File
@@ -1690,10 +1690,10 @@ def _session_list_cache_path_stamp(path: Path | None) -> tuple[int, int]:
return (0, 0)
def _session_list_cache_source_stamp(key: tuple) -> tuple[tuple[int, int], tuple[int, int], tuple[int, int], tuple[int, int], tuple[int, int]]:
def _session_list_cache_source_stamp(key: tuple) -> tuple[tuple[int, int], tuple[int, int], tuple[int, int], tuple[int, int], tuple[int, int], object, int]:
_cache_profile, _cache_all_profiles, cache_show_cli_sessions, *_rest = key
if not cache_show_cli_sessions:
return ((0, 0), (0, 0), (0, 0), (0, 0), (0, 0))
return ((0, 0), (0, 0), (0, 0), (0, 0), (0, 0), None, 0)
try:
state_db_path = Path(_active_state_db_path())
except Exception:
@@ -1714,6 +1714,11 @@ def _session_list_cache_source_stamp(key: tuple) -> tuple[tuple[int, int], tuple
settings_file = SETTINGS_FILE
except Exception:
settings_file = None
try:
from api.config import _SETTINGS_WRITE_VERSION
swv = _SETTINGS_WRITE_VERSION
except Exception:
swv = 0
return (
_session_list_cache_path_stamp(state_db_path),
_session_list_cache_path_stamp(state_db_wal_path),
@@ -1725,6 +1730,7 @@ def _session_list_cache_source_stamp(key: tuple) -> tuple[tuple[int, int], tuple
# frame size), so without this a freshly-committed CLI/gateway session
# could be served stale for the cache TTL. Mirrors the models-layer fix.
_session_list_cache_state_db_fingerprint(state_db_path),
swv,
)
@@ -11426,6 +11432,11 @@ def handle_post(handler, parsed) -> bool:
_clear_session_list_cache()
except Exception:
pass
try:
from api.models import clear_cli_sessions_cache
clear_cli_sessions_cache()
except Exception:
pass
auth_enabled_after = is_auth_enabled()
auth_just_enabled = bool(
+10
View File
@@ -1086,6 +1086,11 @@ def cleanup_test_sessions():
_post(TEST_BASE, "/api/settings", {"show_cli_sessions": False})
except Exception:
pass
try:
from api.models import clear_cli_sessions_cache
clear_cli_sessions_cache()
except Exception:
pass
yield created
for sid in created:
@@ -1111,6 +1116,11 @@ def cleanup_test_sessions():
_post(TEST_BASE, "/api/settings", {"show_cli_sessions": False})
except Exception:
pass
try:
from api.models import clear_cli_sessions_cache
clear_cli_sessions_cache()
except Exception:
pass
# ── Convenience helpers ────────────────────────────────────────────────────────