Conversation
…oved CI tests the pull request *merged with master*, not the branch alone, and master removed `_get_config_mtime` together with the config-mtime restart branch (#1355). Two tests in tests/test_hermeticity_guard.py monkeypatched that helper, so both legs failed with AttributeError: <module 'emrg.client.daemon_manager'> has no attribute '_get_config_mtime' while the same suite was green on this branch locally: the branch was cut from 951c19f, before #1355, so the attribute still existed there. The two patches are dropped — source mtime is the whole restart trigger on master — and the docstrings now say so, including why a config-mtime patch would name something that no longer exists. Re-verified on the merged tree: - mutation arm (guard removed from conftest, sha16 e113d88b1a3f14af -> b4fb6cdca30a25c0): the same 4 tests red, both negative controls green; conftest restored byte-identically. - full suite: 2994 passed, 16 skipped; the live daemon (pid 86187) alive before and after.
…n-cannot-signal-the-daemon
…n-cannot-signal-the-daemon
|
Closing as a duplicate of #1348, which is the same guard for the same acceptance (issue #1337, item 2) and is the copy that covers all three routes the issue names. Nothing here is lost — the two things this PR had and #1348 did not have been carried over, listed below. Measured, not asserted. Why #1348 is the survivor. #1337's acceptance names three routes — an in-process call, a subprocess, and the client-side restart. #1348 guards all three: What was carried over, and where.
And what this PR's CI round found, which is worth more than the PR. Its |
Closes #1337 (part 2: the subprocess/client restart routes).
A pytest run must not be able to reach a live daemon through the client's kill routes. The guard is a shim, not a stub: it interposes on the module's
osname, so a test that patches the module's ownos.killkeeps working (that is the shapetests/test_daemon_manager.pyuses), andos.kill(pid, 0)probes pass through.Contents
conftest::_guard_live_daemon_signals— the autouse tripwire on both kill-carrying modules (emrg/client/daemon_manager.py,emrg/__main__.py), with the two escape hatches above.tests/test_hermeticity_guard.py, each route driven through the real code path in both states: the route is refused before the signal lands (a real child process named in a refused kill is still alive afterwards), the liveness probe still reaches the realos, and a kill-isolating test still runs.tests/test_stop_all.py/tests/test_cli_failure_reporting.pyrecording why those routes are now guarded.Follow-up pushed after the first CI round (why the head moved)
The first version failed both legs, for two independent reasons — both found by CI, neither by the local suite:
_old_pid_alive()asks the pid on POSIX (os.kill(pid, 0)) but the port file on Windows (is_running(), because signal 0 isCTRL_C_EVENTthere — issue stop/cli:os.kill(pid, 0)is a Ctrl+C on Windows, and two product paths still use it as a liveness probe #1349). The fake answered only the POSIX question, so on Windows the wait loop exhausted and the test quietly drove the 10-second force-kill fallback instead of the path it meant to. It now answers whichever probe the platform asks, and asserts the loop settled on the SIGTERM — so the drift cannot come back silently.os.kill(server_pid, signal.SIGKILL)raisesAttributeErroron Windows, and nothing in the restart path catches it — worse than the fallback merely failing, becauseensure_connected()dies instead of respawning the daemon. It now asks for whatever force the platform has (getattr(signal, "SIGKILL", signal.SIGTERM)); Windows' SIGTERM is an immediate hard kill there, which is what the fallback is for.testleg failed because the branch was based before emrg: a config.toml edit never restarts the daemon again #1355 removed_get_config_mtimeand its guard tests monkeypatched it; CI tests the merge with master. Fixed by merging master and dropping the two patches (one prose mention kept, now describing it in the past tense).Master was merged again in this round, so the head is the landing tree — no landing-tree measurement is needed to vote.
Verification
90f1c2a6, master merged in):uv run pytest tests/ -q→ 3049 passed, 16 skipped.sys.platformforced towin32in that process): with the daemon dying, one SIGTERM, one port probe, 0.2 s, no fallback — the shape the fixed test drives.signal.SIGKILLdeleted (the Windows state) the fixed line runs the fallback and returns; the pre-fix line raisesAttributeError: module 'signal' has no attribute 'SIGKILL'— the CI failure verbatim.uv run python -c "from emrg.client.app import run_client"→ ok;uv run python -m emrg --help→ usage prints.