Merge pull request #4575 from nesquena/stage-4566
Release v0.51.546 — fix flaky gateway_sync test (#4566/#4557)
This commit is contained in:
4 files changed
+35
-2
No files matched your search
@@ -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
|
||||
|
||||
@@ -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
@@ -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(
|
||||
|
||||
@@ -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 ────────────────────────────────────────────────────────
|
||||
|
||||
Reference in new issue
Block a user