Three fixes to the auto-dream gate mechanism:
1. Cheap gates first: checkCheapGates() (local file reads for time +
session count) runs BEFORE any API call. provider.getAll() only
executes if both cheap gates pass. Previously every turn downloaded
the entire memory set just to compute memCount.
2. Session-keyed dream tracking: dreamSessionId replaces the
process-global dreamJustRan boolean. Only the session that triggered
dream can complete it. Prevents cross-session false completion.
3. Verified completion: agent_end checks event.messages for actual
memory tool calls (memory_store, memory_update, memory_forget,
memory_list). If the model ignored the dream prompt and just
answered the user, the lock releases but completion is NOT recorded.
Gates will re-trigger on the next eligible turn.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>