Conversation
…ousResearch#85413) The cont-init.d s6 reconciler decided whether to auto-start named per-profile gateway slots by reading multiplex routing ONLY from the GATEWAY_MULTIPLEX_PROFILES environment variable. A user who enabled multiplexing exactly as documented — setting `multiplex_profiles: true` in config.yaml alone, without also exporting the env var — got every named profile slot auto-started by s6. Each booted, hit the default multiplexer's double-bind guard ("already serves profile ..."), exited, and was restarted in a loop, pegging a CPU core near 100%. Resolve the effective flag through the same env-override -> config.yaml -> default precedence the gateway process itself uses (gateway/config.py), via a new `_multiplex_profiles_enabled(hermes_home)` helper: - GATEWAY_MULTIPLEX_PROFILES truthy/falsy wins (operator override). - A blank/unrecognized env value is treated as unset (not False), so a provisioned-but-empty secret cannot silently shadow a config opt-in. - Both the top-level `multiplex_profiles` key and the nested `gateway.multiplex_profiles` form are honored. - Config resolution is fail-open: a malformed config.yaml falls back to disabled rather than wedging container boot. Adds tests covering config-only opt-in (top-level and nested), env>config precedence, blank-env fallthrough, malformed-config fail-open, and the unchanged default-autostart path. Co-Authored-By: Claude <noreply@anthropic.com>
|
Noting the related PR #85437 here so maintainers can compare the two approaches side-by-side. #85437 fixes the same issue by importing Both approaches solve the duplicate-bind restart loop. The trade-offs:
I am happy to close this in favor of #85437 if maintainers prefer the shorter diff, or keep this if the additional test coverage and lack of boot-time coupling to |
fix(container): s6 reconciler honors config.yaml multiplex_profiles (#85413)
|
|
Thanks for this PR. Merged via #101242 (4a7f228) on current main — routed multiplex profiles get their own terminal cwd/backend/docker config; container boot honors config multiplex_profiles. #101242 won as the consolidated fix because it covers the whole multiplex-profile bug class in one change (with tests) rather than the single symptom addressed here; this PR is superseded by it. If anything from your original change is still missing on main >= 4a7f228, please open a fresh PR/issue against main and tag it. Thanks again. |
Summary
Fixes #85413.
The container-boot s6 reconciler (
hermes_cli/container_boot.py:reconcile_profile_gateways) decided whether to auto-start named per-profile gateway slots by reading multiplex routing only from theGATEWAY_MULTIPLEX_PROFILESenvironment variable:A user who enabled multiplexing exactly as documented — setting
multiplex_profiles: trueinconfig.yamlalone, without also exporting the env var — got every named profile slot auto-started by s6. Each booted, hit the default multiplexer's double-bind guard (✗ The default gateway is running as a profile multiplexer and already serves profile '<name>'), exited, and was restarted in a loop, pegging a CPU core near 100%.The gateway process itself already reads the documented precedence (env override →
config.yaml→ default) ingateway/config.py; only the boot-time reconciler diverged.Fix
Resolve the effective flag through the same precedence the runtime uses, via a new
_multiplex_profiles_enabled(hermes_home)helper that reusesgateway.config._env_multiplex_profiles_override():GATEWAY_MULTIPLEX_PROFILEStruthy/falsy wins (operator override).False), so a provisioned-but-empty Fly/Docker secret cannot silently shadow aconfig.yamlopt-in and reintroduce the crash-loop.config.yaml— both the top-levelmultiplex_profileskey and the nestedgateway.multiplex_profilesform (written byhermes config set gateway.multiplex_profiles true) are honored.False.Config resolution is fail-open: any error reading
config.yamlfalls back to disabled rather than wedging container boot (the gateway process surfaces the real config error later).The change is scoped to the reconciler's read of the flag; the existing
should_startlogic, default-slot handling, and stale-runtime sweeping are untouched.Behavior change
multiplex_profiles: truegateway.multiplex_profiles: truetruefalsetrue""(blank)trueTests
tests/hermes_cli/test_container_boot.py— added:test_config_only_multiplex_registers_named_slot_down— the core [Bug]: s6 boot reconciler auto-starts per-profile gateways (crash-loop, 100% CPU) when multiplex_profiles enabled via config.yaml only #85413 repro: config-only opt-in keeps named slots down.test_config_only_nested_gateway_multiplex_honored— nestedgateway.multiplex_profilesform.test_multiplex_disabled_by_default_autostarts_named_slot— no regression for the common non-multiplex deploy.test_env_var_still_wins_over_config— operator override preserved.test_env_var_false_overrides_config_true— env > config precedence.test_blank_env_var_does_not_shadow_config_optin— empty secret falls through to config.test_malformed_config_yaml_fails_open_to_disabled— malformed config never wedges boot.test_multiplex_profiles_enabled_helper_precedence— direct unit coverage of the resolver.All 13 tests in the file pass locally.
🤖 Generated with Claude Code