Skip to content

chore(agent): tripwire — warn when a turn starts before the previous turn's persist - #64936

Closed
Rival wants to merge 1 commit into
NousResearch:mainfrom
Rival:chore/turn-overlap-tripwire
Closed

chore(agent): tripwire — warn when a turn starts before the previous turn's persist#64936
Rival wants to merge 1 commit into
NousResearch:mainfrom
Rival:chore/turn-overlap-tripwire

Conversation

@Rival

@Rival Rival commented Jul 15, 2026

Copy link
Copy Markdown

#64934 documents two turns running concurrently on one gateway session
(busy-guard miss, route unidentified): interleaved flushes persisted user
rows out of arrival order and swallowed an assistant row, leaving a
permanent alternation wedge.

This adds a log-only tripwire: note_turn_start in build_turn_context
warns — naming both turn_ids, the session, and the previous turn's age —
when a turn starts before the previous turn's _persist_session completed;
note_turn_persisted clears the slot in the persist funnel (both lock
branches). The WARNING's two turn_ids correlate with dispatch logs, so the
next occurrence in any deployment identifies the route that bypassed the
busy guard.

Semantics tuned against noise: ownership transfer keeps a turn that crashed
before its persist from warning more than once; the unconditional clear
makes the tripwire under-report rather than double-report under a real
overlap; same-turn_id re-entry (retry paths) is silent. No behavior change.

4 unit tests (tests/agent/test_turn_overlap_tripwire.py); full
tests/agent/ suite green (5723 tests).

🤖 Generated with Claude Code

…turn's persist

Two turns interleaving on one session corrupt the durable transcript:
flushes race (user rows persist out of arrival order), the identity-marker
dedup over shared history dicts can swallow a row, and the second turn
runs on a history base that never saw the first turn's exchange. The
dispatch route that lets the second turn through the busy guard is not
yet identified.

Add note_turn_start (build_turn_context) / note_turn_persisted
(_persist_session funnel): one WARNING naming both turn_ids when a turn
starts before the previous turn's turn-end persist. Ownership transfer
keeps a crashed turn from warning more than once; the unconditional clear
makes the tripwire under-report rather than double-report under a real
overlap. Log-only, no behavior change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@alt-glitch alt-glitch added type/feature New feature or request comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state P3 Low — cosmetic, nice to have labels Jul 15, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Thanks for adding a focused diagnostic for the concurrency report. The current implementation needs a lifecycle correction before it can reliably identify the bypass route.

Problems

  • note_turn_persisted() is wired into every AIAgent._persist_session() call, but build_turn_context() already calls _persist_session() for crash-resilient turn-start persistence at agent/turn_context.py:379-389. That clears the marker before the pre-LLM work and conversation loop complete, so an overlapping turn starting after that initial flush is silent. agent/conversation_loop.py also has multiple mid-turn persistence calls.
  • tests/agent/test_turn_overlap_tripwire.py tests helpers in isolation, so it does not cover the turn-start-flush → overlap sequence above.

Suggested changes

  • Clear the diagnostic only at a genuine terminal turn boundary (the normal finalizer persists at agent/turn_finalizer.py:240) and cover required terminal error paths.
  • Add an integration test that blocks turn A after its initial persistence, starts turn B, and asserts that the warning is emitted.

Automated hermes-sweeper review.

@teknium1

Copy link
Copy Markdown
Contributor

Merged via PR #65499 — your commit was cherry-picked onto current main with authorship preserved. The noise-tuning semantics (ownership transfer on crashed turns, unconditional clear so overlaps under-report, silent same-turn re-entry) survived review intact; we E2E-verified the persist-funnel clear in both lock branches.

Next occurrence of the #64934 overlap in any deployment should now name both turn_ids in the WARNING — please share the correlated dispatch log lines on the issue when it fires.

@teknium1 teknium1 closed this Jul 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P3 Low — cosmetic, nice to have sweeper:blast-broad Sweeper blast radius: broad — a core path most sessions hit sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants