fix(desktop): re-arm relay-mesh runtime when the ingress is dead#2304
fix(desktop): re-arm relay-mesh runtime when the ingress is dead#2304Bartok9 wants to merge 8 commits into
Conversation
b2416c5 to
b996d81
Compare
|
Blocking evidence against current head Call-path evidenceThis PR changes one file, The current callers of
The diff adds no caller from message dispatch, the agent reconcile loop, or a periodic watchdog. If the ingress dies after launch while the agent process remains running, the next inbound message does not itself call Required correctionWire the health check/re-arm into an actual post-launch lifecycle seam:
Please add a regression/integration test with the user-visible sequence:
If re-arm fails, the test should also prove that Buzz surfaces an actionable shared-compute-offline error rather than another silent non-response. Separate end-to-end response timing evidence is tracked in #2386; this comment is specifically about the missing recovery invocation. |
|
Good catch — you're right that the probe is dead code on the post-launch failure path. I'll wire the health-check/re-arm into a real lifecycle seam — immediately before relay-mesh turn dispatch (so the next inbound message actually triggers it), with a fallback in the managed-agent reconcile loop, plus visible failure state rather than silent non-response. I'll add the integration test with your sequence: healthy |
Brad block#2304: mesh_ingress_is_live inside ensure_relay_mesh_for_record only ran on start/restore — not after launch. Local agents hit :9337 themselves, so there is no desktop turn-dispatch hook; add a bounded coordinator watchdog (15s base, double on failure to 120s) that probes ingress, drops a zombie runtime handle, and re-arms via ensure_relay_mesh_for_record for relay-mesh agents. Failed re-arm writes an actionable \"Buzz shared compute offline\" last_error. Share drop_stale_mesh_runtime_if_ingress_dead with ensure path. Unit tests cover dead-port probe, noop drop without handle, and failure copy. Refs block#2062 Signed-off-by: Bartok9 <danielrpike9@gmail.com>
b996d81 to
6d20d20
Compare
Brad #2304 addressed — post-launch re-arm seamThanks for the call-path evidence. You were right: head What changed (HEAD
|
|
Thanks — all four are fair and I agree with each. Confirming the plan against 1. Unbounded 2. Probe/evict replacement race. Agreed — releasing the lock across the 3. "Running agents" includes stopped/manual records. Correct — filtering on local backend + relay-mesh model alone lets a stopped agent start the mesh client or hold the watchdog in failure backoff. Intersecting with active 4. Error writes bypass Tests. You're right the current three don't exercise recovery. Adding deterministic coverage around injectable probe/stop/bootstrap seams for: stale handle → bounded eviction → replacement runtime; stopped agents ignored; concurrent replacement not evicted; failure persisted without clobbering concurrent store writes; and a successful recovery→inference path. The full live kill- I'll also confirm |
|
The post-launch invocation gap is fixed at 1. A wedged runtime can still wedge the watchdog
stale.stop().awaitwith no timeout. If the embedded runtime is the wedged component, this await can prevent the function from returning, so the watchdog never reaches bootstrap or its backoff loop. Please put a bounded timeout around stop and continue re-arm on timeout/error. 2. Probe/evict has a replacement raceThe helper checks 3. “Running agents” currently means every configured mesh agent
4. The new error writes bypass the store lock
Regression proof is still missingThe three added tests check a refused port, an empty handle, and error-string contents.
Please add deterministic tests around injectable probe/stop/bootstrap seams, plus the requested live kill- Current GitHub state: DCO, Semgrep, and zizmor pass, but the CI workflow is |
…opped agents Addresses Brad's block#2304 review of head 6d20d20: 1. Bounded stale stop() — a wedged runtime could hang stop().await and block the watchdog forever, defeating the never-block-re-arm intent. Wrap in a 3s tokio::time::timeout (matches probe budget); log and drop the handle on timeout/error so the watchdog keeps making progress. 2. Probe/evict race — capture the runtime identity (new monotonic DesktopMeshRuntime::id) before the ingress probe .await and only evict if the same handle is still installed on lock reacquire, so a concurrent stop/start replacement is never evicted. 3. Stopped/manual records — re-arm now filters to local relay-mesh agents whose own process is actually running (runtime_pid + process_is_running), so deliberately stopped agents are not resurrected. Adds unit tests for the running/stopped/non-mesh re-arm target filter.
|
Pushed 1. Wedged runtime can wedge the watchdog
2. Probe/evict replacement raceAdded a process-monotonic 3. "Running agents" included stopped/manual recordsRe-arm now filters through TestsAdded unit coverage for the #3 filter: On the timeout/race paths: those need a real |
…opped agents Addresses Brad's block#2304 review of head 6d20d20: 1. Bounded stale stop() — a wedged runtime could hang stop().await and block the watchdog forever, defeating the never-block-re-arm intent. Wrap in a 3s tokio::time::timeout (matches probe budget); log and drop the handle on timeout/error so the watchdog keeps making progress. 2. Probe/evict race — capture the runtime identity (new monotonic DesktopMeshRuntime::id) before the ingress probe .await and only evict if the same handle is still installed on lock reacquire, so a concurrent stop/start replacement is never evicted. 3. Stopped/manual records — re-arm now filters to local relay-mesh agents whose own process is actually running (runtime_pid + process_is_running), so deliberately stopped agents are not resurrected. Adds unit tests for the running/stopped/non-mesh re-arm target filter. Signed-off-by: Bartok9 <danielrpike9@gmail.com>
7b6963f to
c7f550d
Compare
Address remaining review gaps on the watchdog re-arm path: 1. Keep bounded stop timeout (already present) and document the never-block-re-arm invariant. 2. Extract identity-compare helper + injectable ingress probe so probe/evict never drops a concurrent replacement runtime. 3. Intersect relay-mesh records with live managed_agent_processes pubkeys (not every configured mesh record / pid-only heuristic). 4. persist/clear mesh last_error under managed_agents_store_lock, bump updated_at, preserve unrelated errors, surface save failures. Tests: process-map filter, identity skip, stop budget, error classifier; hardware-gated kill-:9337 recovery documented as Signed-off-by: Bartok9 <danielrpike9@gmail.com> #[ignore] for manual mesh machines.
Brad #2304 — remaining gaps closed on HEAD
|
79e73b0 to
e407bc7
Compare
Brad block#2304: mesh_ingress_is_live inside ensure_relay_mesh_for_record only ran on start/restore — not after launch. Local agents hit :9337 themselves, so there is no desktop turn-dispatch hook; add a bounded coordinator watchdog (15s base, double on failure to 120s) that probes ingress, drops a zombie runtime handle, and re-arms via ensure_relay_mesh_for_record for relay-mesh agents. Failed re-arm writes an actionable \"Buzz shared compute offline\" last_error. Share drop_stale_mesh_runtime_if_ingress_dead with ensure path. Unit tests cover dead-port probe, noop drop without handle, and failure copy. Refs block#2062 Signed-off-by: Bartok9 <danielrpike9@gmail.com>
…opped agents Addresses Brad's block#2304 review of head 6d20d20: 1. Bounded stale stop() — a wedged runtime could hang stop().await and block the watchdog forever, defeating the never-block-re-arm intent. Wrap in a 3s tokio::time::timeout (matches probe budget); log and drop the handle on timeout/error so the watchdog keeps making progress. 2. Probe/evict race — capture the runtime identity (new monotonic DesktopMeshRuntime::id) before the ingress probe .await and only evict if the same handle is still installed on lock reacquire, so a concurrent stop/start replacement is never evicted. 3. Stopped/manual records — re-arm now filters to local relay-mesh agents whose own process is actually running (runtime_pid + process_is_running), so deliberately stopped agents are not resurrected. Adds unit tests for the running/stopped/non-mesh re-arm target filter. Signed-off-by: Bartok9 <danielrpike9@gmail.com>
Address remaining review gaps on the watchdog re-arm path: 1. Keep bounded stop timeout (already present) and document the never-block-re-arm invariant. 2. Extract identity-compare helper + injectable ingress probe so probe/evict never drops a concurrent replacement runtime. 3. Intersect relay-mesh records with live managed_agent_processes pubkeys (not every configured mesh record / pid-only heuristic). 4. persist/clear mesh last_error under managed_agents_store_lock, bump updated_at, preserve unrelated errors, surface save failures. Tests: process-map filter, identity skip, stop budget, error classifier; hardware-gated kill-:9337 recovery documented as Signed-off-by: Bartok9 <danielrpike9@gmail.com> #[ignore] for manual mesh machines.
|
A good idea @Bartok9 and I support this - a few questions will follow (and some failure to address) but yeah- very good catch. 2 main things would be if it is slow and causes some boucing - not ideal nice one! keep pushing. |
micspiral
left a comment
There was a problem hiding this comment.
Reviewed for mesh applicability — the core design is sound: single-probe-then-drop with the identity gate (should_evict_stale_runtime_after_probe capturing runtime.id() before the .await) correctly avoids evicting a concurrently-swapped handle, and the bounded best-effort stop() (STALE_STOP_TIMEOUT, drop-anyway on timeout) is a real zombie guard, not aspirational. The is_running_relay_mesh_agent filter (Local + relay-mesh + in process-map + live pid) also correctly keeps the watchdog from resurrecting agents the user deliberately stopped. Nice.
One thing I'd change before merge, plus two smaller notes.
1. Add a consecutive-failure debounce before eviction (the warm-up risk)
drop_stale_mesh_runtime_if_ingress_dead evicts on a single failed probe, and the probe is response.status().is_success() on GET /v1/models — i.e. HTTP reachability, not model routability. That's a good "is the ingress process alive" signal, and since /v1/models returns 200 (with possibly-empty data) during catalog sync, a syncing node correctly reads LIVE and is safe. Good.
The gap is a transient stall. A healthy runtime whose HTTP responder blips past the 3s budget for one tick — a large model load/reload blocking the event loop, VRAM allocation, an mmap/GC pause, or heavy inference saturation — gets evicted and cold-restarted. Because rearm_relay_mesh_for_running_agents early-returns on a healthy handle (if !evicted && had_handle), a dead-probe is the only thing that ever touches a healthy runtime — so a single probe false-negative is the entire blast radius. On a slow box mid-warm-up that's an avoidable full re-bootstrap (and, for a serve node, a mode flip — see note 3).
Suggestion: require N consecutive dead probes (2 is plenty) before drop_stale evicts. With the 15s base cadence that costs ~15–30s extra on genuine recovery while eliminating the transient-blip false eviction. wait_for_mesh_inference already tolerates a 120s warm-up on the readiness path; the liveness probe having zero tolerance is the asymmetry worth closing.
2. clear_mesh_last_error_if_set substring match is a bit loose (nit)
err.contains("Buzz shared compute offline") || err.contains("shared compute") could clear an unrelated last_error that merely mentions "shared compute". A sentinel prefix or a typed error kind would be sturdier, so recovery only clears errors this watchdog actually set.
3. Serve→Client re-arm mode transition (not a blocker — just documenting)
Worth a comment in the code: if the dead ingress belonged to a serve node with running consumer agents, this path re-arms it as a Client (ensure_client_node_for_model → MeshNodeMode::Client). That's the correct/safe behavior — serve restoration is restore_mesh_sharing's job (config-backed, MeshNodeMode::Serve), and ensure_client_node_for_model reuses any live runtime of either mode (the router resolves per-request), so it only cold-starts Client when there's genuinely no runtime. Just flagging it so the mode change is intentional-by-design in the code, not a surprise to the next reader.
…micspiral block#2304) Address the mesh-applicability review on the re-arm watchdog: 1. Consecutive-failure debounce before eviction (merge-blocker). A single dead /v1/models probe past the 3s budget (transient stall: model load/reload, VRAM alloc, GC/mmap pause, inference saturation) no longer cold-restarts a healthy runtime. Require DEAD_PROBE_EVICT_THRESHOLD (2) consecutive dead probes on the watchdog cadence; a live probe or an identity-mismatch replacement resets the streak. Counter lives on AppState (AtomicU32). 2. clear_mesh_last_error_if_set now matches a sentinel prefix (MESH_REARM_ERROR_SENTINEL) instead of the loose "shared compute" substring, so recovery only clears errors this watchdog set. 3. Documented the serve->client re-arm mode transition as intentional-by-design (safe fail-safe; serve restoration stays restore_mesh_sharing's job). Tests: added eviction_debounces_transient_dead_probe; updated error classifier + actionable-copy tests for the sentinel. 17 passed, 2 ignored.
|
Pushed 1. Consecutive-failure debounce before eviction (the warm-up risk) — doneYou nailed the asymmetry:
2.
|
Brad block#2304: mesh_ingress_is_live inside ensure_relay_mesh_for_record only ran on start/restore — not after launch. Local agents hit :9337 themselves, so there is no desktop turn-dispatch hook; add a bounded coordinator watchdog (15s base, double on failure to 120s) that probes ingress, drops a zombie runtime handle, and re-arms via ensure_relay_mesh_for_record for relay-mesh agents. Failed re-arm writes an actionable \"Buzz shared compute offline\" last_error. Share drop_stale_mesh_runtime_if_ingress_dead with ensure path. Unit tests cover dead-port probe, noop drop without handle, and failure copy. Refs block#2062 Signed-off-by: Bartok9 <danielrpike9@gmail.com>
9a479f2 to
bed813b
Compare
…opped agents Addresses Brad's block#2304 review of head 6d20d20: 1. Bounded stale stop() — a wedged runtime could hang stop().await and block the watchdog forever, defeating the never-block-re-arm intent. Wrap in a 3s tokio::time::timeout (matches probe budget); log and drop the handle on timeout/error so the watchdog keeps making progress. 2. Probe/evict race — capture the runtime identity (new monotonic DesktopMeshRuntime::id) before the ingress probe .await and only evict if the same handle is still installed on lock reacquire, so a concurrent stop/start replacement is never evicted. 3. Stopped/manual records — re-arm now filters to local relay-mesh agents whose own process is actually running (runtime_pid + process_is_running), so deliberately stopped agents are not resurrected. Adds unit tests for the running/stopped/non-mesh re-arm target filter. Signed-off-by: Bartok9 <danielrpike9@gmail.com>
Address remaining review gaps on the watchdog re-arm path: 1. Keep bounded stop timeout (already present) and document the never-block-re-arm invariant. 2. Extract identity-compare helper + injectable ingress probe so probe/evict never drops a concurrent replacement runtime. 3. Intersect relay-mesh records with live managed_agent_processes pubkeys (not every configured mesh record / pid-only heuristic). 4. persist/clear mesh last_error under managed_agents_store_lock, bump updated_at, preserve unrelated errors, surface save failures. Tests: process-map filter, identity skip, stop budget, error classifier; hardware-gated kill-:9337 recovery documented as Signed-off-by: Bartok9 <danielrpike9@gmail.com> #[ignore] for manual mesh machines.
…micspiral block#2304) Address the mesh-applicability review on the re-arm watchdog: 1. Consecutive-failure debounce before eviction (merge-blocker). A single dead /v1/models probe past the 3s budget (transient stall: model load/reload, VRAM alloc, GC/mmap pause, inference saturation) no longer cold-restarts a healthy runtime. Require DEAD_PROBE_EVICT_THRESHOLD (2) consecutive dead probes on the watchdog cadence; a live probe or an identity-mismatch replacement resets the streak. Counter lives on AppState (AtomicU32). 2. clear_mesh_last_error_if_set now matches a sentinel prefix (MESH_REARM_ERROR_SENTINEL) instead of the loose "shared compute" substring, so recovery only clears errors this watchdog set. 3. Documented the serve->client re-arm mode transition as intentional-by-design (safe fail-safe; serve restoration stays restore_mesh_sharing's job). Tests: added eviction_debounces_transient_dead_probe; updated error classifier + actionable-copy tests for the sentinel. 17 passed, 2 ignored. Signed-off-by: Bartok9 <danielrpike9@gmail.com>
|
CI is failing in both Desktop Core and Desktop Build (macOS) for the same reason: mesh_ingress_dead_probes is feature-gated on AppState, but its initializer in app_state.rs is unconditional. Add #[cfg(feature = "mesh-llm")] to the initializer; AtomicU32 should also be feature-gated (or fully qualified) so non-mesh builds using -D warnings do not then fail on an unused import. Would you like me to take over this PR and push the fix? |
The AppState field is #[cfg(feature = "mesh-llm")] but its initializer was unconditional, breaking non-mesh builds under -D warnings. Gate the initializer and fully-qualify AtomicU32 so the import is not left unused (micspiral, block#2304).
|
Fixed in |
The AppState field is #[cfg(feature = "mesh-llm")] but its initializer was unconditional, breaking non-mesh builds under -D warnings. Gate the initializer and fully-qualify AtomicU32 so the import is not left unused (micspiral, block#2304). Signed-off-by: Bartok9 <danielrpike9@gmail.com>
ec53e4a to
0edea64
Compare
|
Pushed |
micspiral block#2304 feature-gate left app_state.rs one line over the 1089 exception (trailing-newline count = 1090). Bump narrowly.
|
@micspiral feature-gate was already on HEAD ( |
micspiral block#2304 feature-gate left app_state.rs one line over the 1089 exception (trailing-newline count = 1090). Bump narrowly. Signed-off-by: Bartok9 <danielrpike9@gmail.com>
f1f3f17 to
df41532
Compare
|
@Bartok9 I moved things over to a branch of fixes linked - and added some tweaks about how I know mesh works (as those bits I built!) |
|
Perfect — thanks @micspiral, and credit landed cleanly on #2823 (cherry-pick with original authorship/sign-offs). Deferring to your branch: you built the mesh internals, and the startup/readiness supervision + |
Brad block#2304: mesh_ingress_is_live inside ensure_relay_mesh_for_record only ran on start/restore — not after launch. Local agents hit :9337 themselves, so there is no desktop turn-dispatch hook; add a bounded coordinator watchdog (15s base, double on failure to 120s) that probes ingress, drops a zombie runtime handle, and re-arms via ensure_relay_mesh_for_record for relay-mesh agents. Failed re-arm writes an actionable \"Buzz shared compute offline\" last_error. Share drop_stale_mesh_runtime_if_ingress_dead with ensure path. Unit tests cover dead-port probe, noop drop without handle, and failure copy. Refs block#2062 Signed-off-by: Bartok9 <danielrpike9@gmail.com>
…opped agents Addresses Brad's block#2304 review of head 6d20d20: 1. Bounded stale stop() — a wedged runtime could hang stop().await and block the watchdog forever, defeating the never-block-re-arm intent. Wrap in a 3s tokio::time::timeout (matches probe budget); log and drop the handle on timeout/error so the watchdog keeps making progress. 2. Probe/evict race — capture the runtime identity (new monotonic DesktopMeshRuntime::id) before the ingress probe .await and only evict if the same handle is still installed on lock reacquire, so a concurrent stop/start replacement is never evicted. 3. Stopped/manual records — re-arm now filters to local relay-mesh agents whose own process is actually running (runtime_pid + process_is_running), so deliberately stopped agents are not resurrected. Adds unit tests for the running/stopped/non-mesh re-arm target filter. Signed-off-by: Bartok9 <danielrpike9@gmail.com>
Address remaining review gaps on the watchdog re-arm path: 1. Keep bounded stop timeout (already present) and document the never-block-re-arm invariant. 2. Extract identity-compare helper + injectable ingress probe so probe/evict never drops a concurrent replacement runtime. 3. Intersect relay-mesh records with live managed_agent_processes pubkeys (not every configured mesh record / pid-only heuristic). 4. persist/clear mesh last_error under managed_agents_store_lock, bump updated_at, preserve unrelated errors, surface save failures. Tests: process-map filter, identity skip, stop budget, error classifier; hardware-gated kill-:9337 recovery documented as Signed-off-by: Bartok9 <danielrpike9@gmail.com> #[ignore] for manual mesh machines.
df41532 to
376c26b
Compare
…micspiral block#2304) Address the mesh-applicability review on the re-arm watchdog: 1. Consecutive-failure debounce before eviction (merge-blocker). A single dead /v1/models probe past the 3s budget (transient stall: model load/reload, VRAM alloc, GC/mmap pause, inference saturation) no longer cold-restarts a healthy runtime. Require DEAD_PROBE_EVICT_THRESHOLD (2) consecutive dead probes on the watchdog cadence; a live probe or an identity-mismatch replacement resets the streak. Counter lives on AppState (AtomicU32). 2. clear_mesh_last_error_if_set now matches a sentinel prefix (MESH_REARM_ERROR_SENTINEL) instead of the loose "shared compute" substring, so recovery only clears errors this watchdog set. 3. Documented the serve->client re-arm mode transition as intentional-by-design (safe fail-safe; serve restoration stays restore_mesh_sharing's job). Tests: added eviction_debounces_transient_dead_probe; updated error classifier + actionable-copy tests for the sentinel. 17 passed, 2 ignored. Signed-off-by: Bartok9 <danielrpike9@gmail.com>
CI on block#2304 failed: cargo fmt --check on mesh_llm paths, and desktop file-size gate (app_state + mesh_llm growth for watchdog). Signed-off-by: Bartok9 <danielrpike9@gmail.com>
The AppState field is #[cfg(feature = "mesh-llm")] but its initializer was unconditional, breaking non-mesh builds under -D warnings. Gate the initializer and fully-qualify AtomicU32 so the import is not left unused (micspiral, block#2304). Signed-off-by: Bartok9 <danielrpike9@gmail.com>
micspiral block#2304 feature-gate left app_state.rs one line over the 1089 exception (trailing-newline count = 1090). Bump narrowly. Signed-off-by: Bartok9 <danielrpike9@gmail.com>
Relay-mesh agents went silent with no error if the embedded mesh runtime exited or wedged after launch: `mesh_llm_runtime` stayed `Some` while the local OpenAI ingress on :9337 was dead, so `ensure_relay_mesh_for_record` took the "already running" fast path and `wait_for_mesh_inference` just timed out against a dead endpoint (block#2062). Add a fast liveness probe (`mesh_ingress_is_live`: single 3s `GET /v1/models`, the same call the issue used to confirm the ingress was down). When a runtime handle is present but the ingress is unreachable, drop the stale runtime (best-effort stop; never block re-arm on a wedged runtime — the zombie-guard motivation) and fall through to re-arm it via the normal bootstrap path. Resolves the reported symptom (option 1 + zombie guard from the issue): long-lived sessions recover shared-compute agents on the next dispatch instead of staying silent until a manual restart. Additive; the healthy fast path (live ingress) is unchanged. Refs block#2062 Signed-off-by: Bartok9 <danielrpike9@gmail.com>
Brad block#2304: mesh_ingress_is_live inside ensure_relay_mesh_for_record only ran on start/restore — not after launch. Local agents hit :9337 themselves, so there is no desktop turn-dispatch hook; add a bounded coordinator watchdog (15s base, double on failure to 120s) that probes ingress, drops a zombie runtime handle, and re-arms via ensure_relay_mesh_for_record for relay-mesh agents. Failed re-arm writes an actionable \"Buzz shared compute offline\" last_error. Share drop_stale_mesh_runtime_if_ingress_dead with ensure path. Unit tests cover dead-port probe, noop drop without handle, and failure copy. Refs block#2062 Signed-off-by: Bartok9 <danielrpike9@gmail.com>
…opped agents Addresses Brad's block#2304 review of head 6d20d20: 1. Bounded stale stop() — a wedged runtime could hang stop().await and block the watchdog forever, defeating the never-block-re-arm intent. Wrap in a 3s tokio::time::timeout (matches probe budget); log and drop the handle on timeout/error so the watchdog keeps making progress. 2. Probe/evict race — capture the runtime identity (new monotonic DesktopMeshRuntime::id) before the ingress probe .await and only evict if the same handle is still installed on lock reacquire, so a concurrent stop/start replacement is never evicted. 3. Stopped/manual records — re-arm now filters to local relay-mesh agents whose own process is actually running (runtime_pid + process_is_running), so deliberately stopped agents are not resurrected. Adds unit tests for the running/stopped/non-mesh re-arm target filter. Signed-off-by: Bartok9 <danielrpike9@gmail.com>
Address remaining review gaps on the watchdog re-arm path: 1. Keep bounded stop timeout (already present) and document the never-block-re-arm invariant. 2. Extract identity-compare helper + injectable ingress probe so probe/evict never drops a concurrent replacement runtime. 3. Intersect relay-mesh records with live managed_agent_processes pubkeys (not every configured mesh record / pid-only heuristic). 4. persist/clear mesh last_error under managed_agents_store_lock, bump updated_at, preserve unrelated errors, surface save failures. Tests: process-map filter, identity skip, stop budget, error classifier; hardware-gated kill-:9337 recovery documented as Signed-off-by: Bartok9 <danielrpike9@gmail.com> #[ignore] for manual mesh machines.
…micspiral block#2304) Address the mesh-applicability review on the re-arm watchdog: 1. Consecutive-failure debounce before eviction (merge-blocker). A single dead /v1/models probe past the 3s budget (transient stall: model load/reload, VRAM alloc, GC/mmap pause, inference saturation) no longer cold-restarts a healthy runtime. Require DEAD_PROBE_EVICT_THRESHOLD (2) consecutive dead probes on the watchdog cadence; a live probe or an identity-mismatch replacement resets the streak. Counter lives on AppState (AtomicU32). 2. clear_mesh_last_error_if_set now matches a sentinel prefix (MESH_REARM_ERROR_SENTINEL) instead of the loose "shared compute" substring, so recovery only clears errors this watchdog set. 3. Documented the serve->client re-arm mode transition as intentional-by-design (safe fail-safe; serve restoration stays restore_mesh_sharing's job). Tests: added eviction_debounces_transient_dead_probe; updated error classifier + actionable-copy tests for the sentinel. 17 passed, 2 ignored. Signed-off-by: Bartok9 <danielrpike9@gmail.com>
CI on block#2304 failed: cargo fmt --check on mesh_llm paths, and desktop file-size gate (app_state + mesh_llm growth for watchdog). Signed-off-by: Bartok9 <danielrpike9@gmail.com>
The AppState field is #[cfg(feature = "mesh-llm")] but its initializer was unconditional, breaking non-mesh builds under -D warnings. Gate the initializer and fully-qualify AtomicU32 so the import is not left unused (micspiral, block#2304). Signed-off-by: Bartok9 <danielrpike9@gmail.com>
micspiral block#2304 feature-gate left app_state.rs one line over the 1089 exception (trailing-newline count = 1090). Bump narrowly. Signed-off-by: Bartok9 <danielrpike9@gmail.com>
376c26b to
ac95b8d
Compare
Refs #2062
Re-arm relay-mesh when local ingress (
:9337) dies: probe/v1/models, debounce before eviction, drop stale runtime, re-arm viaensure_relay_mesh_for_record. Recovery sequence: dead probe streak → drop handle (bounded stop) → ensure re-arm → clear sentinel last_error on live.Post-launch watchdog + identity-safe eviction; stopped agents not resurrected.