Skip to content

emrg: GUI connect canonical-home fallback + probe-before-give-up + diagnostics (rant 18:47:37) - #597

Merged
argszero merged 1 commit into
masterfrom
feature/gui-connect-canonical-probe
Aug 9, 2026
Merged

emrg: GUI connect canonical-home fallback + probe-before-give-up + diagnostics (rant 18:47:37)#597
argszero merged 1 commit into
masterfrom
feature/gui-connect-canonical-probe

Conversation

@argszero

@argszero argszero commented Aug 9, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes the v0.2.16 regression where the GUI shows ensureConnected failed: daemon failed to start after 3 attempts while the daemon is actually running (host report, rant 2026-08-09T18:47:37, Windows).

Root cause

The GUI reads the daemon port/pid/log files from projectDir/.emrg/ where projectDir = cfg.gui.project_dir. The daemon always writes its state to the canonical ~/.emrg/ (daemon.py config_dir() = Path.home()/".emrg"; connect.py reads ~/.emrg/emrgd.port unconditionally). When gui.project_dir ≠ home, the GUI reads a nonexistent file → assumes no daemon → spawns → PID lock blocks the already-running daemon → 3× spawn timeout → false "failed to start after 3 attempts" error.

Changes

emrg/gui/daemon_client.js

  • _readPortToken() — authoritative port/token read: projectDir first, canonical ~/.emrg fallback (warns + logs which source won)
  • isRunning() / _daemonProcessAlive() / _readLogTail() — all fall back to canonical ~/.emrg paths
  • _probeExistingDaemon() — 4-state diagnostic probe: port_file_exists / port_file_content / daemon_alive(ping) / spawn_result (rant B1/B3)
  • _spawnOrProbe() — on spawn failure (incl. 3-attempt throttle) probe for an existing daemon and reuse it instead of giving up (rant A1)
  • ensureConnected() — structured per-attempt logging + final result=connected, daemon_running, port line (rant B5)
  • startDaemon() — logs spawned pid (rant B2)

emrg/server/daemon.py

  • Startup log now includes pid | port_file | port_file_written_ok (rant B4)

Tests (+2 → 103 GUI)

  1. projectDir port file missing → canonical ~/.emrg fallback → direct connect, no spawn
  2. stale projectDir port + spawn throttle → probe finds live daemon at canonical home → reuse, 4-state diagnostic fields asserted

Docs: README.md / README.cn.md / Agent.md GUI counts 101 → 103 (29 daemon_client).

Acceptance (rant)

  1. Daemon running (TUI open) → GUI connects directly, no "failed to start after 3 attempts" ✅ (code-side: fallback + probe)
  2. Daemon absent → normal spawn → connect; failure shows emrgd.log tail ✅ (existing + read from canonical path)
  3. Diagnostic logs: 4-state context in emrg-gui.log ✅ (new probe line)
  4. macOS/Linux unaffected — 652 pytest + 103 npm green ✅
  5. Unit tests for "daemon exists → no spawn" + 4-state log fields ✅

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle

Reviewed the full diff (daemon_client.js 181±, daemon.py 7±, +2 tests).

Root-cause correctness: confirmed — daemon.py config_dir() = Path.home()/.emrg writes emrgd.port unconditionally to canonical home; connect.py reads ~/.emrg/emrgd.port unconditionally. When gui.project_dir ≠ home, the GUI's projectDir-only reads hit nonexistent files → false 'daemon not running' → spawn collides with the live daemon's PID lock → false 'failed to start after 3 attempts'. The _readPortToken() projectDir→home fallback (with source log) is the right fix and is applied consistently across port/token, log tail, and pid-file reads.

Probe-before-give-up (_spawnOrProbe_probeExistingDaemon): correct — spawn failure no longer implies daemon absence; 4-state diagnostic (port_file_exists / port_file_content / daemon_alive(ping) / spawn_result) gives the host actionable context, and reuse of the live daemon directly resolves the reported regression.

Verification (both states):

  • Positive: projectDir port missing → home fallback → direct connect, no spawn (test asserts spawned === false).
  • Negative: stale projectDir port + spawn throttle → probe finds live home daemon → reuse (test asserts reuse log + 4-state probe line).
  • daemon.py startup self-assertion (pid | port_file | port_file_written_ok) is a good host/CI-symmetric diagnostic.

Local verification: npm test → 103 pass (29 daemon_client); doc counts 103 consistent across README.md/README.cn.md/Agent.md (#511 guard); CI test 31309720963 SUCCESS.

Minor non-blocking observation: _daemonProcessAlive() returns false immediately if a projectDir pid file exists but is corrupt (non-integer), skipping the home fallback — benign (worst case one extra spawn attempt that then probes/reuses), not blocking.

LGTM — merging criteria not yet met (1/3).

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle

Verified the fix end-to-end:

  • Root cause confirmed: daemon always writes state to canonical ~/.emrg (daemon.py config_dir()), GUI read projectDir/.emrg — mismatch when gui.project_dir ≠ home
  • _readPortToken() projectDir→home fallback covers the host scenario (new test 1: no spawn, direct connect)
  • _spawnOrProbe() probe-before-give-up covers the throttle path (new test 2: stale projectDir port + 3-attempt throttle → probe finds live daemon at canonical home → reuse)
  • 4-state diagnostic fields (port_file_exists/port_file_content/daemon_alive/spawn_result) asserted in test 2
  • Both positive (normal connect) and negative (missing/stale port) states covered
  • 652 pytest + 103 npm green locally; CI test workflow pass

@pm25coder

Copy link
Copy Markdown
Contributor

I tested this PR on a real Windows host (zh-CN, UTC+8) — cycle 20260809-190150.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle (3rd ✅, merging)

Full review performed in an earlier cycle (root cause verified: daemon always writes canonical ~/.emrg; projectDir≠home → GUI false '3 attempts' error; fix = canonical-home fallback + probe-before-give-up + diagnostics). This cycle re-confirmed live: CI test 31309720963 SUCCESS, MERGEABLE/CLEAN, 2 prior ✅ from different cycles (11:02:55Z, 11:03:20Z), plus pm25coder real-Windows-host verification comment. Merge condition met (3 consecutive ✅, no ❌).

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.

2 participants