Make the hourly sweep reflection's only driver, with a drain loop - #466
Merged
Conversation
Reflection previously rode the chat turn's waitUntil tail as its primary driver, with the hourly cron sweep as a one-thread-per-tick catch-up. That coupled memory-formation throughput to how much the user happens to converse, and made the moment of formation unpredictable relative to the rest of the background fleet. Remove the tail call and its per-user claim path entirely, and turn runReflectionSweepTick into a sequential drain loop: claim the most-overdue eligible thread across all users, reflect it, claim the next - until the queue is empty, the per-tick cap (5 threads) is hit, or the time budget (180s of new claims) is spent. The next hourly tick resumes the drain, so throughput no longer depends on chat activity, and the strictly sequential loop keeps at most one reflection agent writing to the memory store per tick. The eligibility gates (prior-calendar-day, >= 2 user messages) are unchanged; the fixed cadence gives the user a predictable window to edit or retry a settled conversation before reflection reads it. The per-user claim_next_thread_for_reflection RPC loses its only caller and is dropped from the schema; mark_thread_reflected_if_claimed stays (the sweep's mark path). Docs, the QA walkthrough, and the dev cron shim comments follow the new drive shape.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
SYNOPSIS
Reflection (memory formation) drops its chat-turn-tail driver and becomes sweep-only: the hourly cron tick now drains the queue one thread at a time until empty, capped, or out of time budget.
PURPOSE
Currently reflection has two drivers: the completed-turn
waitUntiltail (primary) and an hourly one-thread-per-tick catch-up sweep. Bad because throughput is coupled to chat activity - a user must keep conversing to drain their own queue - and because the moment of memory formation is unpredictable: it can land seconds after any turn, unlike every other background pipeline with a fixed cadence.DESCRIPTION
Existing behavior:
getStreamingResponse's tail firedreflectOneThread(per-user claim RPC) after each completed turn;runReflectionSweepTickclaimed exactly one most-overdue thread across all users per hour.This PR: the tail call is deleted (second-thoughts, curation, and samskara stay - samskara must remain tail-driven for its 1-10 minute reaction-classify window).
runReflectionSweepTickbecomes a sequential drain loop: claim most-overdue eligible thread -> reflect -> claim next, stopping on empty queue, a 5-thread cap, or a 180s budget for starting new claims (hosted isolate dies ~400s; a thread claimed at the cutoff still has 200+ seconds, and the existing 3-attempt cap backstops overruns). The now-orphaned per-userclaim_next_thread_for_reflectionRPC is dropped from the schema;mark_thread_reflected_if_claimedand the sweep claim stay. Eligibility gates unchanged (prior-calendar-day newest message, >= 2 user messages).Result: memory formation has a fixed, predictable cadence - the user can edit or retry a settled conversation any time before the first hourly tick after the day gate opens and reflection only ever sees the corrected thread - and queue drain no longer depends on the owner conversing.
Notes:
errorcycle stops the drain loop deliberately (no hot-looping a broken dependency);claim-lostcontinuesreflection-drainQA walkthrough, and the dev cron shim comments follow the new drive shape; old QA results rows are annotated as pre-rework baselinesdrop function if exists, all historical signatures)Generated by Claude Code