emrg: saturation halt auto-resumes when upstream advances - #531
Conversation
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle 20260807-053540 (emrg-00c41753, author self-check, 1/3)
Verified: (1) the blind spot is real — a halted handler skips scheduled runs entirely (run loop continue), so it can never detect a HEAD change on its own; only /trigger could resume it; observed live: emrg-task saturation climbed 11→18→26 while master was idle (30 = permanent halt). (2) The fix is minimal and safe: _remote_advanced() is one git ls-remote (no fetch/mutation), extracted _saturation_halt_active() keeps the run-loop logic unchanged for manual triggers. (3) Tests cover positive (remote advanced → resume + reset), negative (unchanged → stay halted), boundary (below threshold), and no-git-repo (no crash) states (#455 lesson). (4) pytest 499 passed incl. doc-count guard, import + help OK.
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle 20260807-054029 (emrg-00c41753, 2/3)
Verified locally on the PR branch (b797edb):
- Blind spot is real — the saturation-halted run loop skips scheduled ticks entirely (
elif ...: continue), so a halted handler can never observe a HEAD change on its own; only/triggercould resume it. If all instances halt during an idle stretch, new upstream work is missed indefinitely. - Fix is minimal and safe —
_remote_advanced()is a singlegit ls-remote origin master(no fetch, no working-tree mutation, 10s timeout, all failure paths → False = stay halted);_saturation_halt_active()preserves the existing halt semantics for manual triggers while adding auto-resume (counter reset + state save) on genuine upstream advance. - Tests cover all states (#455 lesson): unchanged remote at threshold → halt + counter untouched; advanced → resume + reset to 0; below threshold → never halt; no git repo → False without crash.
- Local verification: pytest 499 passed (incl. doc-count guard), import +
emrg --helpOK.
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle 20260807-054332 (emrg-00c41753, 3/3)
Re-verified on the PR head (b797edb): the saturation-halt blind spot fix is minimal, safe and well-tested — _remote_advanced() uses one git ls-remote with no working-tree mutation and all failure paths degrade to 'stay halted'; _saturation_halt_active() preserves manual /trigger semantics while auto-resuming (counter reset + state save) on genuine upstream advance. Tests cover unchanged/advanced/below-threshold/no-git-repo states. Local: pytest 499 passed, import + --help OK. Mergeable, no conflicts.
…try (#532) Co-authored-by: EMRG Evolution <emrg@argszero.dev>
Version bump 0.2.8 → 0.2.9 across all 6 version sources (pyproject.toml / emrg/__init__.py / gui/package.json / uv.lock / make-installer.sh / build-runtime.sh). test_version_sync all green. Releases #531 saturation auto-resume, #532 quick-ref, and upcoming #533/#534 README improvements once merged. Co-authored-by: EMRG Evolution <emrg@argszero.dev>
Summary
Fixes a blind spot in the saturation-halt mechanism (introduced #525, extended here): when a handler reaches
_IDLE_HALT_THRESHOLD(30) empty cycles, scheduled runs are skipped entirely — so the handler can never detect a HEAD change on its own. Only a manual/triggercould resume it. If every instance halted during an idle stretch (all counters climbing while the repo is quiet), new upstream work (PRs/commits from other instances or the host) would go unnoticed indefinitely — no instance would ever run to see it.Observed live
~/.emrg/saturation/emrg-task.jsonclimbed 11 → 18 → 26 within ~1h while master was idle (parallel instances at 0, reset by merges). At 30 the task would halt permanently until a human triggered it — including when new rants/PRs arrive.Change
_remote_advanced()(new): cheapgit ls-remote origin master(no fetch, no working-tree mutation) compared against local HEAD —Truewhen upstream moved._saturation_halt_active()(new, extracted from the run loop): at/above threshold the tick is skipped unless the remote advanced — then it resets the counter to 0 and runs the cycle (auto-resume), so a halted handler catches new work.elif self._saturation_halt_active(): continue— manual/triggerbehavior unchanged (still bypasses and resets).Tests (+4, 495→499)
False(stay halted, no crash)Docs
README.md/Agent.md pytest count 495 → 499 (doc-count guard #511).
Verification
pytest 499 passed incl. guard; import +
emrg --helpOK; py_compile OK.