From f9e47aa6feed6b93fa4247ef1ff923e147b07127 Mon Sep 17 00:00:00 2001 From: joaomarcos Date: Sun, 13 Sep 2026 19:36:21 +0530 Subject: [PATCH] fix(migrate): write the rollback manifest before the first destructive operation An interruption during the first secondary stop/uninstall left no recovery metadata on disk. Write the complete manifest first; the dict never changes afterwards, so the per-secondary and post-flag rewrites were byte-identical and are dropped. Based on #109490 by @JoaoMarcos44. --- hermes_cli/gateway_migrate.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hermes_cli/gateway_migrate.py b/hermes_cli/gateway_migrate.py index 989387ef1e..9343c6b816 100644 --- a/hermes_cli/gateway_migrate.py +++ b/hermes_cli/gateway_migrate.py @@ -587,6 +587,9 @@ def apply_migration(plan: MigrationPlan, *, served_wait: float = _SERVED_WAIT_SE "default": plan.default.to_dict(), "secondaries": [p.to_dict() for p in plan.standalone_secondaries], } + # Recovery metadata must exist before the first destructive operation; the manifest never + # changes afterwards, so this is the only write it needs. + _write_manifest(plan.default_home, manifest) for p in plan.standalone_secondaries: if p.service is not None: kind, system = p.service @@ -596,10 +599,7 @@ def apply_migration(plan: MigrationPlan, *, served_wait: float = _SERVED_WAIT_SE if p.pid is not None: _stop_gateway_process(p.home) print(f" ✓ {p.name}: stopped standalone gateway (pid {p.pid})") - # Record progressively so a crash mid-way still leaves a usable rollback manifest. - _write_manifest(plan.default_home, manifest) _write_multiplex_flag(plan.default_home, True) - _write_manifest(plan.default_home, manifest) print(f" ✓ default: gateway.multiplex_profiles: true ({plan.default_home / 'config.yaml'})") print(f" ✓ {_restart_default(plan.default, plan.target_service_kind(), plan.default_home)}")