Skip to content

emrg: flag truncated evolution cycles (max tool rounds) as truncated, not complete/empty - #525

Merged
argszero merged 1 commit into
masterfrom
feature/evolution-truncation-flag
Aug 6, 2026
Merged

emrg: flag truncated evolution cycles (max tool rounds) as truncated, not complete/empty#525
argszero merged 1 commit into
masterfrom
feature/evolution-truncation-flag

Conversation

@argszero

@argszero argszero commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Summary

Cross-project lesson applied to EMRG's own evolution loop (mem repo: an agent hit its tool-call cap and its truncation was silently treated as done). #523 fixed the user-facing asymmetry (TUI had a 'continue to resume' hint, GUI didn't). This PR fixes the daemon-side asymmetry: the scheduler could not distinguish a truncated evolution cycle from a successful one.

The bug

EvolutionHandler._run_evolution_cycle (emrg/server/scheduler.py) treated any done frame as successful completion — logging complete (tools=N, duration=N). But the daemon's max-tool-rounds frame (daemon.py:1582Exceeded maximum tool call rounds (270)., done: True) is also a done frame. Consequences:

  1. Misreported as complete — truncated cycles look identical to successful ones in logs and the evolution_summary GUI panel.
  2. Wrongly counted as empty cycles — when HEAD is unchanged, a truncated cycle incremented the idle-halt backoff counter (_IDLE_HALT_THRESHOLD), as if there was 'nothing to evolve'. A capped agent is the opposite of idle — it was actively working and ran out of rounds. This could halt the evolution handler prematurely after repeated truncations.

The fix

  • Detect truncation from the done frame content (exceeded in content) → log truncated (max tool rounds) via logger.warning instead of complete.
  • Exclude truncated cycles from the empty-cycle backoff (truncation is activity, not NTE); reset streak with an accurate reason.
  • Evolution log impact now reads evolution-cycle-<ts>-truncated + truncated=max-tool-rounds — visible in the GUI evolution summary.

Tests (+2, 493→495)

  • test_evolution_cycle_truncated_not_empty_not_complete — truncated done frame → backoff NOT advanced, impact flagged truncated, never -complete.
  • test_evolution_cycle_complete_unchanged_head_still_empty — normal completion with unchanged HEAD keeps existing empty-cycle semantics (no false positive).

Docs

README.md/Agent.md pytest count 493 → 495 (doc-count guard #511).

Verification

pytest 495 passed (incl. doc-count guard), import + emrg --help OK.

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

Verified: (1) the bug — daemon.py:1582 sends Exceeded maximum tool call rounds (270). with done: True, so the scheduler's done-branch previously logged it as 'complete' and (with unchanged HEAD) counted it as an empty cycle, advancing the idle-halt backoff; (2) the fix — truncation is detected from frame content, excluded from the empty-cycle counter, and written to the evolution log as truncated (visible in GUI evolution_summary); (3) positive + negative tests cover both states (#455 lesson): truncated frame → backoff NOT advanced + impact flagged; normal done frame with unchanged HEAD → existing empty-cycle semantics preserved; (4) pytest 495 passed incl. doc-count guard, import + emrg --help OK.

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

Verified locally on the PR head (8d24a13), CI down (Actions outage):

  • Full suite: 495 passed (493→495 matches Agent.md/README.md sync)
  • import + --help OK
  • Logic validated in BOTH states per #455 lesson:
    • Positive: truncated done frame ('Exceeded maximum tool call rounds') → _empty_cycles stays 0 (NOT counted as empty), impact has truncated=max-tool-rounds, no -complete tag
    • Negative: normal done + unchanged HEAD → still counted as empty (existing semantics preserved), no truncation marker
  • 'exceeded' substring guard is appropriately narrow; completes the truncation-explicitness theme across layers (#523 GUI hint → this scheduler accounting)

@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 20260807-035808 (emrg-00c41753, 3/3)

3 consecutive LGTMs from different cycles (034917, 035447, 035808). Diff unchanged since 2/3 verification (495 passed locally on head 8d24a13, both positive/negative states validated). mergeable_state=clean. Merge.

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