Skip to content

emrg: sync test counts to 484 + guard test against doc drift (recurs #426/#430/#510) - #511

Merged
argszero merged 2 commits into
masterfrom
feature/docs-test-count-482
Aug 6, 2026
Merged

emrg: sync test counts to 484 + guard test against doc drift (recurs #426/#430/#510)#511
argszero merged 2 commits into
masterfrom
feature/docs-test-count-482

Conversation

@argszero

@argszero argszero commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Summary

The #510 doc sync fixed counts as of master before #509 merged. After #509 (evolution_summary e2e tests, +2 tests) landed, the Python suite is 484 — docs had drifted again (the recurring #426/#430/#510 pattern).

This PR not only re-syncs the numbers but adds a guard test to structurally stop the recurrence:

Changes

  • tests/test_doc_counts.py (new):
    • test_python_count_matches_docs — runs pytest --collect-only and asserts README.md (currently N items) and Agent.md ((N)) match the real collection count
    • test_gui_breakdown_sums_to_headline — asserts every documented GUI npm test breakdown (README/Agent.md) sums to its headline number
  • README.md: currently 482 itemscurrently 484 items
  • Agent.md: Python (482)(484)

Verification

  • uv run pytest tests/ -q → 484 passed (includes the 2 new guard tests)
  • The guard test already proved its worth: it caught the 482→484 mismatch immediately after being added
  • Doc + test-only change; no runtime code touched

@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 20260806-232437 (emrg-00c41753, author self-check, 1/3)

Verified on master 4058022: the #510 sync was correct as of its base (480), but #509 (+2 evolution_summary e2e tests) merged on top, so uv run pytest tests/ -q now reports 482. This PR syncs README.md + Agent.md to 482. Doc-only; GUI count (86) unchanged and still correct.

@argszero argszero changed the title emrg: docs — sync Python test count 480→482 emrg: sync test counts to 484 + guard test against doc drift (recurs #426/#430/#510) Aug 6, 2026

@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 20260806-233406 (emrg-00c41753, 2/3)

Independently verified in an isolated worktree at head 37543f7:

  • Count consistency: master collects 482; #511 adds exactly 2 guard tests → 484 documented = 484 collected. Self-consistent (no off-by-2).
  • Guard validated in BOTH states (per #455 lesson): positive (484=484) passes; negative (temporarily set README to 999) fails with a precise message 'documents 999 Python tests but 484 are collected'. GUI breakdown guard also passes (86 = 22+22+17+15+7+3).
  • Full suite on head: 484 passed (482 + 2 new guard tests). Docs-only apart from the new test file; CI test workflow green.
  • This guard directly kills the recurring #426#430#510#511 drift pattern. Excellent — the count can no longer silently rot.

@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 20260806-233252 (emrg-00c41753, 2/3 — final state)

Final PR state verified (supersedes the 1/3 note about the pre-guard diff):

  • README.md + Agent.md Python count 480→484; GUI breakdown (86) untouched
  • tests/test_doc_counts.py guard: (1) test_python_count_matches_docs runs pytest --collect-only and asserts README (currently N items) + Agent.md ((N)) match the real collection; (2) test_gui_breakdown_sums_to_headline asserts each documented npm-test breakdown sums to its headline (parses per-part leading numbers — avoids the 'i18n' digit trap, e.g. 15 i18n must not contribute '18')
  • Consistency check: 484 = 482 pre-existing + 2 guard tests; the guard caught the 482 vs 484 mismatch immediately when added, proving the detector works
  • First CI run failed at 'Set up job' (runner infra, no code involved); re-run 31116216570 green

This structurally closes the #426#430#510#511 doc-drift recurrence: any future test add/remove without doc sync now fails CI. Doc + test-only change.

@argszero
argszero merged commit 0acfa7d into master Aug 6, 2026
1 check passed
@argszero
argszero deleted the feature/docs-test-count-482 branch August 6, 2026 15:37
argszero added a commit that referenced this pull request Aug 6, 2026
…18n leak closures, e2e tests, doc-count guard) (#512)

Co-authored-by: EMRG Evolution <emrg@argszero.dev>
argszero added a commit that referenced this pull request Aug 8, 2026
…emote-tracking refs (#567)

* emrg: evolution prompt Step 2.2 uses FETCH_HEAD — robust to missing remote-tracking refs

* emrg: bump test count 590→591 after #566 merge (doc-count guard #511)

---------

Co-authored-by: EMRG Evolution <emrg@argszero.dev>
argszero added a commit that referenced this pull request Aug 9, 2026
…egression hotfix) (#592)

* emrg: fix Windows cmd-window storm + daemon spawn throttle (v0.2.15 regression hotfix)

Rant 2026-08-09T13:16:36 (emergency, highest priority): Windows v0.2.15
host observed continuous cmd popups (had to reboot) + daemon startup
failure leaving GUI/scheduler unable to connect.

Root causes:
1. Zero CREATE_NO_WINDOW anywhere in the codebase — every subprocess
   spawn (git/gh/bash tool/scheduler/daemon spawn) popped a console
   window on Windows.
2. GUI reconnect loop respawned emrgd.cmd every ~5s forever; each
   spawn raced the previous daemon's startup (G43 stale-port unlink
   deleted a healthy daemon's port file → its scheduler logged
   'cannot connect' 93 times while the GUI kept spawning).
3. Scheduler had no connect-failure backoff.

Fixes:
- NEW emrg/_win.py: win32_no_window_kwargs() = {creationflags:
  CREATE_NO_WINDOW} on Windows, {} elsewhere. Splatted into all 34
  subprocess call sites (bash_tool, scheduler x12, daemon x5,
  git_utils, daemon_manager, installer, __main__ x3, client/app x9).
- GUI daemon_client.js: spawn throttle (max 3 attempts per connect
  lifecycle, then throw with emrgd.log tail instead of respawning);
  reset counter on successful auth. Both spawn-timeout errors now
  surface the real emrgd.log tail (readLogTail).
- GUI main.js: reconnect exponential backoff 1s→2s→4s→…cap 60s;
  daemon_stopped status surfaces the real failure to the renderer
  (zh/en i18n) instead of infinite 5s respawns.
- scheduler.py: connect-failure exponential backoff
  max(30s, interval*2^n) capped at 10 min — no more per-tick retry
  storm while the daemon is down.

Tests: +6 Python (win32_no_window_kwargs POSIX/Windows/splat; backoff
zero/exp/cap/floor; 641→647), +2 GUI (spawn throttle + counter reset;
96→98). Docs synced (#511 guard). macOS/Linux unaffected (win32 branch
is a no-op empty dict).

* emrg: GUI daemon_stopped warning one-time per connect lifecycle (rant 2026-08-09T13:16:36)

After the spawn throttle exhausts, scheduleReconnect keeps retrying with
backoff capped at 60s — each retry hit the throttle and re-sent
daemon_stopped status, so the renderer appended a duplicate 'run emrg
server' system message every minute forever. Add daemonStoppedNotified:
the warning is sent once per connect lifecycle (reset on successful
connect), symmetric with the TUI _throttle_warned guard (PR #594).
argszero added a commit that referenced this pull request Aug 9, 2026
…ate (Windows v0.2.15 root cause) (#593)

Rant 2026-08-09T13:16:36 root-cause follow-up: PR #592 contains the
window-storm (CREATE_NO_WINDOW + spawn throttle + backoff), but the
underlying deletion race remains: G43 stale-port logic deletes a
healthy daemon's emrgd.port after ONE transient ws failure →
the daemon's own scheduler loses the file (93x 'cannot connect' in the
host's emrgd.log) while the PID lock makes every respawn exit instantly
(zombie state — daemon alive, forever unreachable).

Two complementary fixes:
1. daemon-side self-heal: new _assert_port_file() + _port_keepalive_loop
   re-asserts emrgd.port every 60s if it was deleted/overwritten — the
   daemon is the living core and re-asserts its own identity.
2. GUI-side guard: _daemonProcessAlive() checks emrgd.pid before G43
   deletes the port file — process alive → keep the file and let the
   reconnect backoff retry (transient failure); only truly-dead daemons
   get the delete+respawn path.

Tests: +3 Python (test_daemon.py _assert_port_file write/rewrite +
keepalive restore), +3 GUI (daemon_client.test.js G43 guard alive/dead/
no-pid). 641→644 py, 96→99 gui, docs synced (#511).
argszero added a commit that referenced this pull request Aug 9, 2026
* emrg: TUI daemon spawn throttle — complete the anti-storm fix (rant 2026-08-09T13:16:36)

PRs #592 (CREATE_NO_WINDOW + GUI spawn throttle + scheduler backoff) and
#593 (port-file self-heal + G43 PID guard) contain the Windows v0.2.15
storm fix, but the TUI client had the same storm pattern the GUI had:
app.py _reconnect() loops every 1s calling ensure_connected() → with a
down daemon each iteration calls start_daemon() → spawns a NEW daemon
process every second. On Windows each spawn was a cmd-window source
(pre-#592); even windowless it is process churn + PID-lock exit races
post-#592.

This completes rant acceptance item ① ("启动 GUI/TUI 后零 cmd 窗口弹出"):
- daemon_manager.start_daemon: spawn throttle — max 3 attempts per
  connect lifecycle, then raise with a clear 'run emrg server manually'
  message instead of spawning forever; counter resets on successful
  connect in ensure_connected (mirrors GUI daemon_client.js MAX_SPAWN_ATTEMPTS).
- app.py _reconnect: on throttle, surface a one-time system message +
  status hint so the host knows to start the daemon manually (recovery
  path intact: host starts daemon → is_running True → connect succeeds
  → counter resets).

Tests: +2 (start_daemon throttles after 3 attempts, no 4th spawn;
counter resets on success). 641→643 py, doc counts synced (#511).

* emrg: sync doc test counts to 652 (post-#593 merge + #594 tests)

---------

Co-authored-by: EMRG Evolution <emrg@argszero.dev>
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