daemon lifecycle: no progress/status signal, no health-based takeover of a wedged holder, shim never re-discovers daemon #66
Labels
No labels
code-review
correctness
dos
performance
security
severity/high
severity/low
severity/medium
tech-debt
Kind/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
h-dv/code-index#66
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Source: a1x dogfood. Four related lifecycle gaps that together turned the resolve-stage wedge (#65) into ~50 min of ambiguity for the caller. Not yet fixed.
(a)
warming_upis indistinguishable from a wedged daemonwarming_uptells the caller "retry in 1-2s"; the reporter observed >14 min of it, then a silent flip toproject_not_available. There is NO status/progress RPC in the wire surface (crates/daemon/src/rpc_index.rs exposesstats+ graph methods only), andstats/project_overviewis unavailable for the entire indexing window. A caller cannot tell "indexing, wait" from "wedged, kill it". Even a monotonicfiles_indexed/refs_resolvedcounter would settle it in seconds. Consider also a degraded/partial-ready mode that serves reads off the partial index while the resolve stage runs (the read pool is already open at that point).(b) No health-based takeover of a wedged holder
The daemon lock is a kernel file lock (crates/daemon/src/lifecycle.rs,
try_lock_exclusive). A DEAD holder frees it and a replacement takes over cleanly. But a holder that is ALIVE yet WEDGED (pegging a core, no longer serving) keeps the lock, so a replacement correctly getsLockBusyand defers forever.pid_is_alive()gates the MCP attach probe, not daemon-side takeover. Suggest: a replacement should evict a holder that is alive but fails a TCP/health probe.(c) daemon.toml can advertise a port nothing is listening on
A wedged daemon published
port=58124with no listener for its entire life (only 3 threads). The state file is not a usable readiness signal on its own — pair it with a bind-liveness/health check.(d) MCP shim single_process fallback never retries daemon rediscovery
When daemon attach fails, the MCP server (crates/mcp-server/src/main.rs) falls back to opening the DB directly (
LocalIndex) and never retries daemon discovery. A shim started before the daemon therefore stays on the direct DB, surfacesproject_not_available, and only a client reconnect (/mcp) recovers. The direct-DB hold is fallback-only, not the intended daemon path. Suggest: on the fallback path, periodically re-attempt daemon discovery and switch over when one appears.These are the ergonomics half of #65: even with the tier-3 fix, the daemon should never leave a caller unable to distinguish slow from wedged, or unable to recover without a manual reconnect.
Closing — all four parts verified in-tree.
(a) progress signal —
warming_upis no longer opaque.warming_progress_counts(mcp-server) readsfiles/symbols/refs WHERE target_id IS NOT NULLon the warming slow path and rides along with the retry hint, so a caller can watch the counters move and distinguish "indexing, wait" from "wedged, kill it". That is the monotonic counter this issue asked for.(b) health-based takeover —
crates/daemon/src/takeover.rsstates the distinction explicitly: "Takeover distinguishes the two by health, not mere liveness", backed byprobe_reachable. An alive-but-wedged holder no longer keeps the lock forever.(c) port with no listener — same
probe_reachableprimitive doubles as bind-liveness, sodaemon.tomladvertising a dead port is detectable rather than trusted.(d) shim never re-discovers —
crates/mcp-server/src/main.rshasspawn_daemon_rediscovery, kicked proactively and re-triggered rather than latching on the direct-DB fallback.Note this is the ergonomics half of #65 and it is now genuinely done; #65 itself stays open for its unresolved secondary (index size ~115 KB per source file). The tier-3 wedge that motivated both is fixed, and as of today the degradation is also disclosed — see the #65 comment.