Repository navigation
feat(capture): bound sync's download by max_cases; fill slots with leading turns - #58
Merged
Merged
Conversation
With captures.max_cases set, the fetch takes only each suite's newest 3 x max_cases captures inside max_age (by the store's last-modified time, ties by key). Captures already local or promoted count toward the budget, so a re-run with nothing new downloads nothing. capture list now fetches the same window and budget instead of the whole bucket. Under limits, a turn whose history would be rebuilt from earlier turns that are not on disk (cut by the budget or window, or promoted on another machine) is no longer eligible: "missing earlier turns". When no whole conversation fits a suite's free slots, the slots left take the leading turns of the next one, so a long conversation can no longer leave a capped suite nearly empty. Build warnings now print only for captures that became cases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…write Sync now prints one warning per suite when turns are not promoted for missing earlier turns, naming the causes: the fetch window or budget, turns promoted elsewhere or removed by capture clean, the SDK's per-turn sample rate, or a turn_index numbered from 1. A deferred build warning now prints only after its case file is written. Docs: the budget bounds each sync, not the local mirror; a part-added conversation's later turns can only enter while its earlier captures are local; EVALSHIFT_SAMPLE_RATE draws per turn; capture list's fetch and the max_cases download cap in the field table and capture fetch entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5 tasks done
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.
What this changes
This follows up #57 (unreleased) after its first sync against a real bucket: 52 captures,
max_cases: 10.captures.max_casesset, sync's automatic fetch takes only each suite's newest3 × max_casescaptures insidemax_age. "Newest" goes by the bucket's last-modified time; an unknown time counts as oldest, and ties go by key. Captures already local or promoted count toward the budget, so a re-sync with nothing new downloads nothing. Before this, sync downloaded every capture in the window even though it uses at mostmax_casesper suite. At thousands of captures a day, that meant thousands of downloads per sync. The summary names the cut:(skipped 2 beyond each suite's newest 30).--sincereplaces the age cutoff, not the budget.--repairstill fetches what its rebuilds need.capture listfetches what sync would, applying the same window and budget. Before, it fetched the entire bucket.capture fetchis unchanged.max_cases: 10produced a 1-case suite.not eligible: N missing earlier turnsand warns once per suite with the likely causes:capture clean;turn_indexfrom 1.max_casesset, build warnings print only for captures that become cases, after the case file is written.With neither limit set, nothing changes.
Why
The first real sync showed both problems: a fetch that grows with the bucket, and a capped suite left almost empty.
Test plan
make ci: 3288 passed, 1 skipped (the existing evalshift-server skip), coverage 95.19%.ruff,ruff format,mypy --strictandpre-commit run --all-filesare clean.--sincewith the budget;capture listfetching within the limits;max_agealone,turn_indexNone, and an earlier turn that is local but ineligible;fetched 50 capture(s) … (skipped 2 beyond each suite's newest 30), giving converter 10, planner 10 and triage 9 cases.turn_indexcaveats, thecapture cleanwording, stale docs, and warning order.Follow-up (not in this PR)
The SDK's
EVALSHIFT_SAMPLE_RATEdraws once per agent run, which means once per turn, so a sampled conversation keeps some turns and loses others. Drawing perconversation_id(hash-based) in the SDK would keep conversations whole.🤖 Generated with Claude Code