fix(gateway): log the foreign-standalone-owner warning once per start

decide() runs twice per start (the CLI guard in hermes_cli.gateway and again
from start_gateway -> _host_attach_or_none), and the lock-losing path in
_claim_host_gateway_role re-derives the same fact via _owner_is_standalone(),
so every boot of a generated unit beside another profile's standalone gateway
logged the "starting beside it" WARNING three times. decide() is a verdict
function; reporting belongs at the action site. Demote host_attach's copy to
INFO and keep run.py's lock-claim WARNING, which fires exactly once on both the
--replace and plain paths and carries the `gateway migrate --multiplex` hint.

The lifecycle test still asserts the converge hint is logged by decide(); it
now captures at INFO.
This commit is contained in:
kshitijk4poor
2026-09-23 21:14:22 +05:30
committed by kshitij
parent 9a27bcc903
commit 78fbbb0557
2 changed files with 5 additions and 4 deletions

View File

@@ -381,9 +381,10 @@ def decide(our_home: Path, *, replace: bool = False) -> HostAttachDecision:
if attached is not None and attached.standalone:
# One-process-per-profile fleet: the owner is another profile's standalone gateway. Refusing
# here exits 78, which every supervisor treats as permanent — on a launchd fleet that parked
# every unit but the first to claim the host lock. Start beside it; the host-lock claim logs
# the topology and the `gateway migrate --multiplex` path stays the way to converge.
logger.warning(
# every unit but the first to claim the host lock. Start beside it. decide() runs twice per
# start (CLI guard + start_gateway), so this is INFO; the host-lock claim in run.py logs the
# one WARNING with the `gateway migrate --multiplex` converge hint.
logger.info(
"Another profile's standalone gateway owns this host (%s); starting profile '%s' beside it. "
"Fold every profile onto one gateway with: hermes gateway migrate --multiplex",
attached.describe(), profile)

View File

@@ -159,7 +159,7 @@ def test_a_standalone_owner_is_the_per_profile_topology_not_a_refusal(tmp_path,
monkeypatch.setattr("gateway.control_socket.rescan_gateway_profiles",
lambda home, timeout=8.0: {"multiplex": False, "served_profiles": ["tank"]})
with caplog.at_level("WARNING", logger="gateway.host_attach"):
with caplog.at_level("INFO", logger="gateway.host_attach"):
assert host_attach.decide(tmp_path / "root" / "profiles" / "nous").outcome == host_attach.START
assert any("migrate --multiplex" in r.getMessage() for r in caplog.records), "the converge hint is logged"
assert asyncio.run(gateway_run._host_attach_or_none(replace=False)) is None