emrg: daemon observability (exit records + crash log) & promote blog cadence 1-3 days - #970
Conversation
…rant 2026-08-25T09:25:32)
…ant 2026-08-25T10:01:20)
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle
Reviewed the full diff (daemon observability + blog cadence, rant 2026-08-25T09:25:32 / 10:01:20):
emrg/server/__main__.py: StreamHandler gated onsys.stderr.isatty()(daemon_manager spawns with stderr=DEVNULL — the handler was pure waste and would duplicate the log into the crash log after redirect);_redirect_std_streams()best-effort (OSError → keep DEVNULL) + faulthandler enabled with the stream; main() wrapsasyncio.runand records DaemonExit on EVERY path (sigint/sigterm/crash/normal) withsys.exit(result.exit_code).emrg/server/daemon.py:DaemonExit(slots) →_write_exit_recordappends one JSON line to ~/.emrg/emrgd-exit.log (survives emrgd.log rotation) + mirrors into emrgd.log;_asyncio_exception_handlerroutes background-task crashes to the RotatingFileHandler instead of stderr=DEVNULL (task identity + exc_info kept);_sigterm_handlerPOSIX-only (guarded for Windows); serve() crash now captures_crash_traceback. run_server returns DaemonExit on normal/cancel/sigint/BaseException paths — every stop is attributable.promote_prompt.md: blog cadence ≤1/week → 1-3 days (at least 2/week) with rationale; consistent between the channel table and the Blog Publishing section.- Tests:
test_write_exit_record(durable JSON, traceback/timestamp/pid) +test_asyncio_exception_handler_routes_to_logger(exc_text/ValueError verified). Agent.md 1052→1054 matches the +2 tests (#511 guard green on both jobs). - CI: test + test-windows both green (run 32801450030).
No issues found; solid follow-through on the silent-death observability rant.
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle (re-review)
Head unchanged (bba65b5), CI double-green (run 32801450030). Re-verified against the previous review's findings: DaemonExit write path (survives emrgd.log rotation), _asyncio_exception_handler routes background-task crashes to the RotatingFileHandler (stderr=DEVNULL otherwise swallows them), _sigterm_handler POSIX-guarded, all run_server exit paths return a DaemonExit with the exit code, and the blog cadence change (≤1/week → 1-3 days) is consistent between the channel table and the Blog Publishing section. No issues found — 2/3.
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle (3/3)
Head unchanged (bba65b5), CI double-green (run 32801450030), MERGEABLE. Full diff was reviewed in the two prior cycles (daemon observability: DaemonExit exit records, crash-log redirect via _redirect_std_streams + faulthandler, asyncio exception handler routing to RotatingFileHandler, POSIX-guarded SIGTERM attribution, run_server DaemonExit on every exit path; blog cadence 1-3 days consistent in channel table + Blog Publishing section; Agent.md doc count 1052→1054 matches the +2 tests). No issues found — merging.
Uh oh!
There was an error while loading. Please reload this page.
…re/test-stop-all-hermeticity — resolve Agent.md pytest count 1056+2 → 1058
Two independent fixes driven by two host rants.
1. Daemon observability — durable exit records + stderr crash log
Rant (verbatim, 2026-08-25T09:25:32+08:00):
Root cause:
daemon_managerspawns emrgd withstderr=DEVNULL, so anything bypassing logging — asyncio's default exception handler, C-level abort traces, faulthandler dumps — vanished without a trace. A background-task crash or fatal signal left zero evidence inemrgd.log.This PR covers acceptance items ① and ②:
DaemonExit+_write_exit_record(daemon.py): every stop path ofrun_server(normal return,serve()crash, SIGINT, SIGTERM, cancellation, unexpected BaseException) now produces aDaemonExit(reason, exit_code, traceback)that the entry point persists as one-line JSON in~/.emrg/emrgd-exit.log(append-only, survives emrgd.log rotation) and mirrors into emrgd.log. Exit-code 0 vs 1 vs 130/143 distinguishes clean stops from crashes.__main__.py):_redirect_std_streams()pointssys.stdout/sys.stderrat~/.emrg/emrgd-crash.log(independent sink, keeps the file handler on emrgd.log separate) and enablesfaulthandlerso even fatal-signal deaths (SIGSEGV, no Python code runs) leave a stack dump. StreamHandler is now only attached for interactive TTY runs, so it cannot duplicate the log into the crash file._asyncio_exception_handler(daemon.py): installed inrun_server, routes background-task crashes (TaskHandler, websockets callbacks) into emrgd.log with the task identity + traceback instead of the default handler's stderr → DEVNULL void._sigterm_handler: POSIX SIGTERM → SystemExit so SIGTERM stops are attributable (Windows keeps its hard-kill path, guarded).test_write_exit_record(durable JSON records) andtest_asyncio_exception_handler_routes_to_logger(background crash reaches the logger).Items ③ (TaskHandler progress heartbeat) and ④ (scheduler next-run persistence) are staged for a follow-up PR — this change already makes every daemon death attributable.
2. Promote prompt — blog cadence 1-3 days per post
Rant (verbatim, 2026-08-25T10:01:20.923337+08:00):
promote_prompt.md§2.y Blog Publishing: cadence rule changed fromlow frequency, high quality — default ≤1 post/weekto 1-3 days per post (at least 2 posts/week), keeping the quality gates (depth > length, §0.4 fact-check, no hard ads).low cadence (≤1 post/week)→cadence 1-3 days per post (see Blog Publishing)so the two spots no longer contradict each other.Verification
uv run pytest tests/ -q→ 989 passed, 65 skipped (1054 collected, doc-count guard updated)from emrg.client.app import run_clientOK;python -m emrg --helpOK