- host.py: 7 one-shot reads switched to with open (run_health_check
pidfile, daemon-status pid/log, daemon-stop pid, daemon old pid,
interrupt poll state, parallel jobs); read content, encoding args
and error semantics unchanged.
- tests/test_host_thread_cli.py: test_old_archive_unchanged state
read switched to with open; added a warnings-capture assertion
scoped to the state read so a regression fails the test.
- Intentionally untouched: daemonize log handle (daemon-lifetime
dup2 target) and the two _load_config_file / init sites owned
by PR #266.
Replace bare open().read()/write() in tests with Path.read_text/
write_text (or json.loads over read_text); the five remaining
open(...).close() empty-file creations become Path.write_text('').
No assertion, predicate, or production code changed; no behaviour
change beyond closing the handle deterministically.
Long-function splits and server.py module split intentionally not
included: the longest functions (_dispatch, _create_task,
_dispatch_project, ~375-395 lines in a 10430-line server.py) are
central routing/creation paths, and splitting them is not low-risk;
see PR body.