From 489df88d6ddc19826f999dae40705ecaed96ae6f Mon Sep 17 00:00:00 2001 From: kshitijk4poor <82637225+kshitijk4poor@users.noreply.github.com> Date: Sun, 20 Sep 2026 17:12:34 +0530 Subject: [PATCH] fix(gateway): runtime-status writer merges over out-of-process stamps The background writer persisted the in-memory canonical snapshot verbatim. origin/main re-read gateway_state.json on every write, so keys stamped by other processes survived; with the snapshot they were clobbered on the next publish. Out-of-process writers exist: hermes gateway migrate --standalone (_reconcile_standalone_runtime) rewrites the live multiplexer's file, and container_boot seeds desired_state/migrated_from. Re-read the file in the writer thread immediately before writing and lay the gateway's fields over it: the gateway wins for every key it owns, foreign keys survive. --- gateway/status.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/gateway/status.py b/gateway/status.py index 2f9626b980..7e7ee6ffcf 100644 --- a/gateway/status.py +++ b/gateway/status.py @@ -135,7 +135,7 @@ class _RuntimeStatusWriter: self._writing_generation = generation error: Optional[BaseException] = None try: - (self._write_fn or _write_json_file)(path, payload) + (self._write_fn or _write_json_file)(path, _merge_over_on_disk(path, payload)) except BaseException as exc: error = exc with self._condition: @@ -162,6 +162,16 @@ class _RuntimeStatusWriter: _runtime_status_state_lock = threading.RLock() _runtime_status_state_path: Optional[Path] = None _runtime_status_state: Optional[dict[str, Any]] = None + + +def _merge_over_on_disk(path: Path, payload: dict[str, Any]) -> dict[str, Any]: + """Lay the canonical snapshot over whatever is on disk right before writing. Out-of-process + writers (``hermes gateway migrate --standalone`` clearing multiplex-owned status, container_boot + seeding ``desired_state``) stamp this file directly; the gateway's fields win, theirs survive.""" + existing = _read_json_file(path) + return {**existing, **payload} if isinstance(existing, dict) else payload + + _runtime_status_writer_lock = threading.Lock() _runtime_status_writer: Optional[_RuntimeStatusWriter] = None