D142 — reconnect: rebuild a client configuration, never automatically¶
cartographer reconnect [provider|all] is a full disconnect followed by a full connect for the
selected providers, in one invocation. It reuses doDisconnect and doConnect rather than
being a third implementation of either: the two halves already encode every rule about what may be
removed and what must be written, and a parallel implementation would drift from them silently.
Why a rebuild is needed at all. sync does more than fetch artifacts — it re-enumerates the
mounted KBs, rewrites the MCP entries, re-ensures the bootstrap hook and materializes — and covers
almost every kind of drift. What it structurally cannot cover is what an older Cartographer
version left behind: pruning is managed-only, so a generated plugin whose filename changed, a
managed block whose marker spelling changed, or a hook registered outside the block is not in the
current managed[] and survives every sync. The code already carries scars from exactly this —
instructionsBlockBeginPrefix exists solely to recognize blocks written by older versions in
another language, and D99's repair removes Codex hook registrations left outside the managed block
so a hook does not fire twice. The connect half writes the current shape from nothing, which is what
removes them.
It is a rebuild, not a reset. Every setting is read from .cartographer.yaml and re-applied:
server URL and name, auth mode, token env, trust, pinned signing keys, MCP approvals, search roots
and paths. That falls out of two existing rules rather than new code — disconnect never deletes
the file (D64), and connect reads it back — but it is the load-bearing property: a user who has to
re-approve every MCP descriptor after an upgrade will simply stop running the command.
It is never automatic. No upgrade path invokes it. The reasoning is D121's — automatic repair
never invents an approval and never broadens trust — plus the observation that removing and
rewriting provider configuration is a bigger hammer than repairing it in place. upgrade-repair
stays the automatic path and keeps calling the ordinary sync.
Partial-failure contract. If the connect half fails after the disconnect half succeeded, the
command exits 2, names the providers now left without a configuration, and prints the exact
cartographer connect invocation — same settings — that finishes the job. Silence there would leave
an agent without its MCP endpoint and no way to know it; a dry run leaves nothing disconnected and
therefore says nothing.
The lockfile records the server version. Each provider's Lock gains server_version
(optional, omitempty), taken from the /health snapshot sync already fetches — no second
request. Empty means "unknown" (every lockfile written before this, and any sync that could not
reach the server) and never triggers a report: the first sync after an upgrade must not tell every
user something it cannot know. An unreachable server leaves the recorded value unchanged rather
than blanking it, and a dev version on either side is ignored, the same rule the advisory
client/server skew line already uses. On a real difference sync prints exactly one line — both
versions and the reconnect recommendation — once per invocation regardless of provider count, then
proceeds with the ordinary sync. It reports; it does not escalate. status shows the same fact
without running a sync. The version is recorded per provider because providers are synced
independently.