Skip to content

emrg: turn lifecycle timer fix (TUI freeze on mid-turn auto-compact + GUI per-session timers) - #1105

Merged
argszero merged 3 commits into
masterfrom
feature/turn-lifecycle-timer-fix
Sep 2, 2026
Merged

emrg: turn lifecycle timer fix (TUI freeze on mid-turn auto-compact + GUI per-session timers)#1105
argszero merged 3 commits into
masterfrom
feature/turn-lifecycle-timer-fix

Conversation

@argszero

@argszero argszero commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes two host-reported timer bugs with a single shared root cause: there was no authoritative turn lifecycle from the daemon, so clients derived timers from incomplete signals (send time, done frames, compact results).

Rant 2026-09-02T10:31:11 (TUI timer freeze): auto-compact triggered mid-turn (between tool-loop rounds) broadcasts a compact_result completed frame; the TUI treated it as turn end, killed the elapsed timer, cleared the status-bar timer, and left the terminal title stuck at [1:37] while the turn kept running.

Rant 2026-09-02T10:36:26 (GUI sidebar per-session timer): the sidebar needs a per-session elapsed timer for every running session (incl. background evolution), aligned to the actual turn start — queued requests must not count queue wait.

Changes

  • daemon (emrg/server/daemon.py): authoritative turn_start (with real started_at) / turn_end broadcasts in the tool-loop wrapper, covering all turn sources (TUI/GUI/scheduler/evolution/upgrade — all run through this locked wrapper). turn_end is broadcast before _session_task_cwds is cleared so the frame stays cwd-filtered (wrong-cwd ghost connections never receive it, per rant 2026-08-25T17:38:56).
  • TUI (emrg/client/app.py): mid-turn auto-compact no longer sets busy = False (the timer loop stays alive; only manual /compact when idle is treated as terminal); turn_start aligns _request_start to the real execution time; ESC interrupt now resets the terminal title (was leaking a stuck [m:ss]).
  • GUI renderer: daemonBridge.ts tracks turnStartBySid (turn_start/turn_end handlers + cleanup on done/cancelled/disconnect); Sidebar.tsx renders a per-session elapsed timer for every running session, aligned to the authoritative turn start; Shell.tsx drives a 1s tick. New pure formatElapsed in sidebar.ts.
  • Tests: daemon e2e test_turn_start_end_broadcast_lifecycle (two-client form covering start→output→end ordering and queue-boundary turns) + test_broadcast_cwd_filtered now also guards the turn frames; renderer +3 daemonBridge +4 sidebar tests.

Verification

  • pytest: 1221 passed / 1 skipped (1222 collected, Agent.md synced)
  • renderer: tsc clean, 494 passed (Agent.md breakdown synced: sidebar 16, daemonBridge 18)
  • GUI main: 93 pass / 0 fail, node --check clean
  • import check + CLI help green

Conflict awareness

PR #1104 (GUI history) also bumps Agent.md count lines (python 1221→1222, renderer 487→490). Whoever merges second must reconcile: combined target is pytest 1223 collected, renderer 497.

…ompact guard, GUI sidebar per-session timers)

- daemon: broadcast authoritative turn_start (started_at) / turn_end frames
  from the tool-loop wrapper, covering all turn sources (TUI/GUI/evolution/
  upgrade). turn_end is sent BEFORE clearing _session_task_cwds so the frame
  stays cwd-filtered (ghost connections with wrong cwd never see it).
- TUI (client/app.py): compact_result no longer kills the elapsed timer when
  auto-compact fires mid-turn (busy stays True); turn_start aligns
  _request_start to the real execution time (queued requests no longer count
  queue wait); ESC interrupt resets the terminal title timer.
- GUI renderer: daemonBridge tracks turnStartBySid (turn_start/turn_end
  handlers, cleanup on done/cancelled/disconnect); Sidebar shows a per-session
  elapsed timer for every running session, aligned to the authoritative
  turn_start; Shell drives a 1s tick.
- Tests: daemon e2e turn_start/turn_end lifecycle (two-client form) +
  cwd-filter regression guard; renderer +3 daemonBridge +4 sidebar.

Fixes rants 2026-09-02T10:31:11 (TUI timer freeze on mid-turn auto-compact)
and 2026-09-02T10:36:26 (GUI sidebar per-session timers aligned to real turn
start). Note: Agent.md count lines also touched by PR #1104 — whoever merges
second must reconcile (combined target: pytest 1223, renderer 497).

@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 cyc20260902-110446

Reviewed the full diff (daemon turn lifecycle broadcasts, TUI compact guard, GUI per-session timers) + verified locally on the branch: test_turn_start_end_broadcast_lifecycle + test_broadcast_cwd_filtered + doc-counts = 7 passed.

  • daemon: turn_start (started_at = actual execution start) / turn_end broadcast from _run_tool_loop_locked covers all turn sources; turn_end is sent BEFORE _session_task_cwds.pop() so the frame stays cwd-filtered (ghost connections never see it) — correct fix for the test_broadcast_cwd_filtered regression.
  • TUI: busy is set at send time (app.py:477/2011) so the turn_start alignment fires reliably; compact_result only resets state when idle (not busy) — mid-turn auto-compact no longer kills the timer; ESC title reset matches the done path.
  • GUI: clearTurnTimer is idempotent across turn_end/done/cancelled/disconnect; Shell's 1s tick runs only while turnStartBySid is non-empty (no idle re-render cost); formatElapsed [m:ss] matches the TUI format.
  • CI test + test-windows both pass (33585236110).

@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 cyc20260902-111336 (2nd)

Re-reviewed the updated branch (9fc3760 = merge of master after #1104 + Agent.md reconciliation: pytest 1223 collected, renderer 497, GUI main corrected to true static 100 incl. nav-policy). Full local verification on the merged branch: pytest 1222 passed/1 skipped, renderer tsc clean + 497 passed, GUI 93 pass/0 fail, import + CLI green. CI re-fired after the push: test + test-windows both pass (33586460986). No new issues introduced by the merge.

@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 cyc20260902-112723 (3rd consecutive)

Third independent-cycle approval. Head unchanged (9fc3760) since the previous review; CI test + test-windows both green (33586460986); mergeStateStatus CLEAN. Verified the final diff: daemon turn_start/turn_end broadcasts (turn_end before _session_task_cwds pop — cwd-filter preserved), TUI compact guard + ESC title reset + _request_start alignment, GUI turnStartBySid sidebar timers. Local verification on this head already passed in cyc111336 (pytest 1222/1 skip, renderer 497, GUI 93). Satisfies the 3-consecutive-LGTM gate — merging.

@argszero
argszero merged commit 5c039b4 into master Sep 2, 2026
2 checks passed
argszero added a commit that referenced this pull request Sep 2, 2026
… msgs, #1105 — turn lifecycle timer, #1106 — composer draft channel) (#1107)

Co-authored-by: EMRG Evolution <emrg@argszero.dev>
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