fix(codex-runtime): re-running /codex-runtime codex_app_server when already enabled now triggers migration - #26532
Conversation
…lready enabled now triggers migration The /codex-runtime slash command short-circuits with "openai_runtime already set" when invoked with the same value as the current config, and crucially skips the entire migration block below. The check conflates two things: (a) "the config value is correct" and (b) "the world state (managed block in ~/.codex/config.toml, hermes-tools MCP callback, plugin discovery) is converged". Common footgun this exposes: a user who pre-sets `model.openai_runtime: codex_app_server` directly in config.yaml (reasonable thing to do) and then runs /codex-runtime codex_app_server to trigger migration sees "already set" and silently gets no migration. ~/.codex/config.toml never receives the managed block, the hermes-tools MCP callback never registers, and codex falls through to its default runtime instead of the app-server one — visibly successful but functionally partial setup. The migration is idempotent by design (it replaces its own managed block in place between MIGRATION_MARKER and MIGRATION_END_MARKER), so re-running it is safe and cheap. Fix the short-circuit to fall through to migration when re-applying codex_app_server while skipping the config persist (no value-level change needed). The disable case (re-applying "auto") still short-circuits because disabling doesn't touch ~/.codex/config.toml at all. The user-visible message changes to "openai_runtime already set to codex_app_server — re-applying migration" so re-runs surface what happened. Regression test (test_reapply_codex_app_server_runs_migration) asserts: - migrate() was called when re-applying - persist_callback was NOT called (no config write on no-op transitions) - migration output (MCP servers, sandbox default) surfaces in the user-visible message - requires_new_session is True so callers know to /reset Verified RED→GREEN: the test fails on origin/main with "migration must run on reapply, not just first enable" and passes with this fix. Full test_codex_runtime_switch.py suite: 31 passed.
austinpickett
left a comment
There was a problem hiding this comment.
Please use .github/PULL_REQUEST_TEMPLATE.md
There was a problem hiding this comment.
Pull request overview
This PR fixes a /codex-runtime codex_app_server footgun where re-running the command while model.openai_runtime is already codex_app_server would previously short-circuit and skip the migration that converges Codex world-state (~/.codex/config.toml managed block, hermes-tools MCP callback registration, and plugin discovery).
Changes:
- Adjusted
codex_runtime_switch.apply()to not early-return when reapplyingcodex_app_server, allowing the migration block to run while skipping config persistence. - Updated the user-facing message to indicate the runtime is already set and that migration is being re-applied.
- Added a regression test ensuring migration runs on reapply and that
persist_callbackis not invoked on no-op value transitions.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
hermes_cli/codex_runtime_switch.py |
Allows “reapply codex_app_server” to run migration while avoiding unnecessary config writes; updates messaging accordingly. |
tests/hermes_cli/test_codex_runtime_switch.py |
Adds regression coverage for reapply behavior (migration runs, no persistence, messaging, requires new session). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Merged via #56563 (#56563) — your commit was cherry-picked with authorship preserved (rebase-merge, Clean salvage onto current One follow-up on top ( Nice writeup distinguishing "config value correct" from "world state converged" — that's exactly the right framing, and delegating idempotency to |
…lready enabled now triggers migration (salvage of NousResearch#26532 by @simpolism, closes NousResearch#26529) (#468) Co-authored-by: qbit-mirror-bot <qbit-mirror-bot@users.noreply.github.com>
Fixes #26529
What
When
model.openai_runtimeis already set tocodex_app_server, re-running/codex-runtime codex_app_servernow triggers the migration (writes managed block to~/.codex/config.toml, registers hermes-tools MCP callback, discovers native plugins) instead of short-circuiting with "already set".Why
The current short-circuit at
hermes_cli/codex_runtime_switch.py:148returns early whennew_value == current, skipping the entire migration block. This conflates "the config value is correct" with "the world state is converged" — which is fine for theauto→ no-op case (disabling has no world-state side effects) but breaks forcodex_app_server→ no-op, where the user can have the config value correct but be missing the~/.codex/config.tomlmanaged block, the MCP callback, and the plugin discovery.How users hit this: pre-set
openai_runtime: codex_app_serverinconfig.yaml(legitimate workflow —hermes profile create --clonedoes it automatically when cloning a profile that has codex runtime enabled), then run/codex-runtime codex_app_serverto trigger migration. Silent no-op. The bot looks like it's on the app-server runtime but is actually oncodex_responsesfallback.How
Fall through to the migration block when re-applying
codex_app_serverwhile skipping config persistence (no value-level change → no need to rewriteconfig.yaml). The migration is idempotent by design (uses_strip_existing_managed_block()before writing), so re-running is safe and cheap. The user-visible message changes to"openai_runtime already set to codex_app_server — re-applying migration"so re-runs surface what happened.The
autore-apply path keeps the early-return short-circuit since disabling has no world-state side effects to converge.Tests
New regression test
test_reapply_codex_app_server_runs_migrationasserts:migrate()was called when re-applyingpersist_callbackwas NOT called (no spurious config writes on no-op transitions)requires_new_sessionis True so callers know to/resetVerified RED→GREEN locally: the test fails on origin/main with "migration must run on reapply, not just first enable" and passes with this fix.
Scope
Single-commit, two-file change. Production code change is ~15 lines (one new code path branching on
reapplying_enable). Existing tests for the value-changing transitions remain green and unmodified.