Skip to content

x provider pick: excluding a routing host (codex) leaves seeded routes, agentOverrides, and MCP bridges live — one disable semantics for all hosts #73

Description

@robertelee78

Summary

ak x provider pick --host <subset> disables an excluded routing host only in kit.json (its flag flips to false). Everything the host left behind stays live:

  1. Seeded routes keep pointing at the disabled host. providers.dualRouting entries (and their escalation rungs) naming the excluded host are retained verbatim and re-applied by applyAqeRouter into .agentic-qe/llm-config.json agentOverrides on every sync — aqe work keeps routing to a host the user just turned off.
  2. The codex MCP bridges stay registered. mcp__codex__codex (project .mcp.json) and the ruflo server in codex's config.toml are marker-owned (providers.codexMcp / providers.rufloCodexMcp === 'ak'), but nothing runs the matching undoCodexMcp / undoRufloMcpInCodex on exclusion — the ensure* functions merely no-op once disabled, so both bridges linger indefinitely.
  3. Stale agentOverrides on disk. applyAqeRouter merges {...existing.agentOverrides, ...projected} — entries ak projected for the excluded host are never pruned, even after the policy no longer names it.

Flagged by the cross-vendor (Codex) review on #67 (round 3, HIGH). Deliberately not fixed inside #67 to honor its maintainer-mandated scope; filed here as the follow-up.

Why now

#67 made the disable story asymmetric in a way users will feel: excluding opencode tears down surgically (marker-gated, priors restored, reported), while excluding codex silently leaves routes and bridges live. One command, two disable semantics — the same "two competing models" incoherence #67 was asked to eliminate for the adoption path. The capability-registry work in #71 will also need one teardown contract per host anyway; fixing this first gives it the codex reference implementation.

Proposed fix (sketch)

Treat routing-host exclusion in x provider pick the same as opencode exclusion — a disable, not just a flag flip:

  1. Bridge teardown (codex only): when codex goes enabled → excluded, run undoCodexMcp({ managed: providers.codexMcp === 'ak' }) and undoRufloMcpInCodex({ managed: providers.rufloCodexMcp === 'ak' }), then null both markers and persist. Marker-gated, so user-registered servers survive — the exact opencode retireOpencode analog. (The bridges are codex's integration state: claude exclusion does not touch them, but see 2.)
  2. Policy prune (either routing host): drop dualRouting entries whose host (or escalation hosts) name an excluded routing host — source: 'seeded' entries silently (ak-owned), source: 'user' entries with a per-entry warning (a pin pointing at a disabled host can only fail later).
  3. On-disk agentOverrides prune: in applyAqeRouter, prune stale ak-curated keys: the projection key space is enumerable (AGENT_ACTIVITY_MAP), so on-disk entries inside that space but absent from the current projection are deleted; hand-added/foreign entries outside the space are preserved (merge-not-clobber still holds).

Out of scope for this issue: changing what x provider off does (it already tears down everything); any change to seeding, primary-host validation, or the routing defaults themselves.

Acceptance

  • pick --host claude on a codex-enabled machine: both codex MCP bridges removed (when ak-registered), markers nulled, dualRouting + agentOverrides name only claude afterwards, and a re-pick to codex re-wires cleanly.
  • pick --host codex on a dual machine: routes naming claude pruned (user pins warned), bridges kept (they are codex's).
  • Sandboxed command-level tests mirror the opencode disable tests (argv-logging fake CLIs prove the exact removal calls; no real home/global npm/PATH touched).
  • docs/PROVIDERS.md disable semantics describe one behavior for all hosts.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions