fix(session): evaluate rotation against post-accumulation totals

`accumulateAndRotateSession` called `evaluateRotation` on the
pre-accumulation `session` object, then re-read the row only
inside the shouldRotate branch. A run that tipped the token
threshold on its own usage would read "below threshold" on this
cycle and wait a full additional run before rotating — long
enough for the transcript to keep growing past the point where
rotation was supposed to protect the context window.

Read once after accumulation, evaluate against the fresh totals,
rotate from the same object. No new queries, no new branches — the
failure mode is just an off-by-one-run bug in the original
read-eval-rotate sequence.
This commit is contained in:
ZacharyZhang-NY committed 2026-04-19 01:03:44 -04:00
1 parent 4842a9a2e2
commit 76c2f085b6
1 file changed
+9 -7
@@ -116,14 +116,16 @@ export function accumulateAndRotateSession(
event.outputTokens ?? 0,
event.runId,
);
const rotationResult = sessionService.evaluateRotation(session);
// Re-read after accumulation: evaluateRotation must see the counts
// that include this run, otherwise a run that just crossed the
// threshold waits a full additional cycle to rotate — the exact
// failure mode that let transcripts balloon past the context window.
const updatedSession = db.getSessionById(agentRecord.sessionId);
if (!updatedSession) return;
const rotationResult = sessionService.evaluateRotation(updatedSession);
if (rotationResult.shouldRotate) {
// Re-read to get updated counts after accumulation.
const updatedSession = db.getSessionById(agentRecord.sessionId);
if (updatedSession) {
sessionService.rotateSession(updatedSession);
logger.info(`[session] Rotated session for agent ${run.agentId}: ${rotationResult.reason}`);
}
sessionService.rotateSession(updatedSession);
logger.info(`[session] Rotated session for agent ${run.agentId}: ${rotationResult.reason}`);
}
}