0abfd1105c
Reshape the two salvaged commits onto current main (#109954): - Move the boundary guard out of the gateway_migrate facade into a new sibling hermes_cli/gateway_migrate_guards.py as a table of guard functions (_AUTO_MIGRATION_GUARDS: service domain, UNIX user, HERMES_HOME tree) plus the identity resolver. The facade grows by ~20 lines only (uid/runtime_home on ProfileGateway, one seam, the hook wiring). - Compare uids, not strings: live pid owner via /proc (ps fallback only on macOS, where /proc does not exist), else the system unit's User= via _read_systemd_user_from_unit (root when absent), else the home directory's owner. None means unknown and never blocks. - The home-tree guard reads the HERMES_HOME the installed unit pins, not the directory the plan enumerated: that is where the gateway really runs and is exactly the "stale copies under profiles/" shape from the report. - When the default is detached, a service-managed secondary is a different domain for the AUTO path (it must not elect the secondary's manager); the explicit command keeps electing it as before. - The explicit command surfaces the same findings as notices (dry run shows them) and is never blocked by them; only the update hook refuses. - Rename the opt-out key to gateway.auto_multiplex_migration (nested only, no top-level alias) and read it before a plan is built, so false prints nothing and touches nothing. The explicit command ignores it. - Tests trimmed to the invariants: one parametrized boundary test that exercises the real hook end to end (refuses, touches nothing, dry run shows the notice), one "same user / same scope still migrates" control, one opt-out test. - Docs: boundary table + renamed opt-out section in multi-profile-gateways.md; one line in hermes_cli/AGENTS.md. Co-authored-by: KoNit-K <124019182+KoNit-K@users.noreply.github.com> Co-authored-by: Athena <athena@olympus.local>