Skip to content

fix(identity): self-heal the "two names" split + self-report (#351)#362

Merged
laulpogan merged 3 commits into
mainfrom
fix/two-names-identity-selfheal
Jul 10, 2026
Merged

fix(identity): self-heal the "two names" split + self-report (#351)#362
laulpogan merged 3 commits into
mainfrom
fix/two-names-identity-selfheal

Conversation

@laulpogan

Copy link
Copy Markdown
Collaborator

The bug

A Claude session's statusline shows one wire identity while the session operates on wire as another. Confirmed live: a session whose CLAUDE_CODE_SESSION_ID derived daydream-gorge was sending/pairing as merry-spindle, a key matching no live session. Systemic — 115 of 434 running wire procs served an identity no live session used.

Root cause

The long-lived wire mcp server freezes its identity at launch; the statusline re-resolves live each render. When the MCP boots before Claude writes its session PID-file, resolve_session_key() misses → the server mints a throwaway mcp-proc-* key, pins it into WIRE_SESSION_ID, and serves it for life. The prior wire dash detection couldn't see it — a fresh CLI's env is already live, so it never inspected the frozen MCP process.

Fix

  1. Retry the PID-file before minting (cached ancestor walk — one bounded walk, then fs-only re-reads; no per-hop ps re-fork / fix(mcp): wire_send uses a cheap pidfile liveness check, not the full scan (#350) #353 Windows trap) → recovers the live identity.
  2. Mint no longer pins WIRE_SESSION_ID — that slot is the operator-override / live channel; a minted value there beat the live session on re-resolve (the root of the split). WIRE_HOME already pins the process + children.
  3. detect_identity_split compares served vs live-PID-file identity → the frozen MCP self-detects the drift the old env-vs-pidfile check structurally couldn't. Surfaced as an identity_split field on wire_status/wire_whoami (+ documented in the MCP session-start instructions) so an agent self-reports and recommends /mcp reconnect. RFC-008 deliberate fleet-share (WIRE_HOME pin) is exempt.
  4. wire setup bakes env:{WIRE_SESSION_ID:"${CLAUDE_CODE_SESSION_ID}"} into the MCP entry so the forward survives --apply (inert on non-Claude hosts).

Also fixes a latent bug the redesign exposed: handle_for_key hashed the sanitized (32-char-truncated) key while homes use the raw key hash → a 36-char session-id uuid resolved to the wrong home.

Verification

  • 645 lib tests green (8 new); cargo fmt --check + clippy -D warnings clean.
  • In-situ against real homes + pidfile: split banner fires (operational=merry-spindle ≠ live=verdant-palm); fleet-share WIRE_HOME pin suppressed; healthy silent; cached walk still resolves the live session.
  • Built through the build-loop: plan gate (4 blockers folded) → gate-2 on the built diff (1 blocker + 3 majors folded: hot-path ps caching, fleet-share false-positive, undocumented field, weak regression test).

Existing frozen MCPs heal on the next /mcp reconnect; the self-report makes that one-command recovery visible.

🤖 Generated with Claude Code

laulpogan and others added 3 commits July 9, 2026 23:45
…t self-report

The recurring "display name ≠ actual name" bug: a Claude session's statusline
shows one wire identity while the session operates on wire as another. Confirmed
live — a dot session's statusline read daydream-gorge (its CLAUDE_CODE_SESSION_ID)
while its MCP served merry-spindle, a key matching no live session. Box-wide it's
systemic: 434 running wire procs, 115 serving an identity no live session uses.

Root cause: the long-lived `wire mcp` server resolves + FREEZES its identity at
launch; the statusline re-resolves live each render. When they diverge — the MCP
booted before Claude wrote its session pidfile, so resolve_session_key() missed
and the server minted a throwaway `mcp-proc-*` key, pinned it into WIRE_SESSION_ID,
and served it for life — you get two permanent names. The prior dash detection
(9c3b62a) couldn't see it: a fresh CLI's env is already live, so its env-vs-pidfile
check never inspected the frozen MCP process.

Fixes:
- session.rs: before minting at MCP startup, RETRY the pidfile (walk the ancestor
  chain ONCE, re-read only the cached pids across a short backoff — no per-hop `ps`
  re-fork, avoiding the #353 Windows perf trap). Recovers the live identity instead
  of freezing a throwaway one. Stop pinning the minted key into WIRE_SESSION_ID
  (that slot is the operator-override / live channel; a minted value parked there
  masqueraded as an override and beat the live session on re-resolve — the root of
  the split). WIRE_HOME already pins the process + is inherited by children.
- session.rs: redesign detect_identity_split to compare OPERATIONAL identity (the
  home this process serves) vs LIVE pidfile identity — so the frozen MCP itself
  detects the split, which the old env-vs-pidfile check structurally could not.
  Fixes a latent bug exposed by the redesign: handle_for_key sanitized the key
  before hashing, but homes are created from the raw key hash; sanitize_name
  truncates at 32 chars, so a 36-char session-id uuid resolved to the wrong home
  and the split silently returned None. (Caught by the in-situ gate, not units.)
- mcp.rs: surface `identity_split` in wire_status + wire_whoami (null when healthy)
  so an agent self-detects drift at the session-start health check it already runs,
  instead of waiting for a human to run `wire dash`.
- setup.rs: bake `env:{WIRE_SESSION_ID:"${CLAUDE_CODE_SESSION_ID}"}` into the
  canonical MCP entry `wire setup` writes, so the forward survives `--apply`
  (was a hand-edit the next apply overwrote). Inert on non-Claude hosts (the ${...}
  guard rejects an unexpanded value). Prevention for every new session.

Existing frozen MCPs heal on next /mcp reconnect; the fix + self-report make that
one-command recovery visible. 8 new tests; 643 lib tests green; fmt + clippy clean.
In-situ: reproduced the split with real homes/pidfile — banner fires; silent when
healthy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VxnZEjrcrYR3SAq8Crv8hg
…et-share, document self-report

Gate-2 (fresh-eyes review of the built diff) found one blocker + three majors:

- BLOCKER (perf): detect_identity_split was wired into wire_status/wire_whoami
  (the session-start hot path) but re-walked the parent chain — up to 16 untimed
  `ps` forks — on EVERY call, on a box with 434 wire procs. Cache the ancestor
  chain in a OnceLock (a process's parentage is immutable): the bounded walk
  happens once, every later identity check re-reads only the tiny pidfiles.
- MAJOR (false positive): the RFC-008 §C "deliberate fleet-share" WIRE_HOME pin
  (several sessions intentionally sharing one identity) tripped the detector
  forever. Suppress when session_source is an explicit operator WIRE_HOME pin
  (env:WIRE_HOME / env:WIRE_HOME_FORCE) — wire's own minted/claude-* resolution,
  the real bug case, is never suppressed.
- MAJOR (undocumented): the new identity_split field was present but no agent was
  told to check it. Added it to the wire_status + wire_whoami descriptions and to
  the "ON SESSION START" instructions block (surface it, /mcp reconnect, don't
  send/pair until resolved) — the wiring that makes the self-report actionable.
- MAJOR (test): the regression guard didn't call handle_for_key. Added a hermetic
  test (tempdir WIRE_HOME) that drives handle_for_key directly and proves a raw
  36-char uuid key resolves its home while the sanitized/truncated form misses —
  fails if handle_for_key ever re-adds sanitize_name. Plus a suppression test.

In-situ (real homes + pidfile): fire path fires (operational=merry-spindle ≠
live=verdant-palm); fleet-share WIRE_HOME pin now suppressed (0 banner lines);
healthy silent; cached walk still resolves the live session. 647 lib tests green;
fmt + clippy clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VxnZEjrcrYR3SAq8Crv8hg
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying wireup-landing with  Cloudflare Pages  Cloudflare Pages

Latest commit: 697f315
Status: ✅  Deploy successful!
Preview URL: https://7b70e99a.wireup-landing.pages.dev
Branch Preview URL: https://fix-two-names-identity-selfh.wireup-landing.pages.dev

View logs

@laulpogan laulpogan merged commit 7c96485 into main Jul 10, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant