fix(sessions): ration the compression-heavy widening to one pass budget

Greptile P1 on #6659: the retry that follows a binding scoped raw window jumped
straight to the global `query_limit`, and every starved project got it in turn.
`remaining` bounds a project's FIRST scoped query, but the widening was not
bounded by the pass at all, so a build scanned len(starved) * query_limit —
an order of magnitude past PROJECT_ASSIGNED_CLI_SCAN_CEILING on a profile with
ten compression-heavy projects, and growing with the number of them.

The widening now comes out of a single pass-level pool of `query_limit`, charged
the full width of each retry, so the scoped reading of a build is capped at
2 * query_limit however many projects are starved. When the pool cannot widen a
retry past the window that just bound it, the loop stops instead of paying for a
query that cannot deliver.

Completeness is deliberately untouched: only the WIDENING is rationed. Every
starved project still pays its own first scoped query, which is the guarantee
the fixed per-build project cap used to break (greptile P1 on #6659). The
constants comment above PROJECT_ASSIGNED_CLI_SCAN_CEILING carried the same
overclaim ("one small project-scoped query per starved project") and now states
the widening budget.

Verified: 88 tests pass across
tests/test_project_assigned_cli_session_limit.py (75),
tests/test_issue2628_cli_sessions_perf.py and
tests/test_issue4842_cron_projection_perf.py. The new regression test
`test_compression_heavy_widening_is_one_pass_budget_not_per_project` is
parametrized over 1 and 3 compression-heavy starved projects and fails on the
old one-liner by showing three full-width retries (16, 16, 16) where the pool
funds one (16).
This commit is contained in:
rodrigogs authored and Rodrigo Gomes da Silva committed 2026-09-24 11:03:47 -03:00
1 parent 7e56aaae07
commit 634f66774b
2 files changed
+126 -6

No files matched your search

@@ -2385,3 +2385,96 @@ def test_all_profiles_view_resolves_each_context_against_its_own_profile(
assert by_id["older-assigned-b"]["project_id"] == "project-b"
# A foreign id is still not an assignment.
assert by_id["newest-foreign-b"]["project_id"] is None
@pytest.mark.parametrize("quiet_count", [1, 3])
def test_compression_heavy_widening_is_one_pass_budget_not_per_project(
fake_hermes_home, tmp_path, monkeypatch, quiet_count
):
"""The retry after a binding scoped window is paid from ONE pass budget.
``remaining`` bounds each starved project's first scoped query, but the
widening that follows a binding raw window jumped straight to the global
``query_limit`` — and it was granted to every starved project in turn. A
profile with ten compression-heavy projects therefore scanned ten times the
ceiling in a single build, growing with the number of starved projects
(greptile P1 on #6659). The widening now comes out of one pass-level pool,
so the scoped reading of a build is bounded by ``2 * query_limit`` however
many projects are starved — while every starved project still pays its own
first query, the completeness guarantee that a fixed per-build project cap
used to break (greptile P1 on #6659).
Parametrized over the number of starved projects because that is exactly
what the budget must not scale with.
"""
ceiling = 20
monkeypatch.setattr(models, "CLI_VISIBLE_SESSION_LIMIT", 5)
monkeypatch.setattr(models, "PROJECT_ASSIGNED_CLI_SCAN_CEILING", ceiling)
per_project_limit = 4
quiet = [f"project-quiet-{index}" for index in range(quiet_count)]
_register_projects(tmp_path, "project-busy", *quiet)
project_count = len(quiet) + 1
# The pass's own query budget: every project's equal share of the ceiling.
effective_limit = min(per_project_limit, max(1, ceiling // project_count))
query_limit = min(effective_limit * project_count, ceiling)
# Each quiet project's scoped raw window is consumed by its OWN compression
# segments, so its first scoped query comes back short with older assigned
# conversations of its own still waiting behind the window.
scoped_raw_window = per_project_limit * max(agent_sessions.CANDIDATE_WINDOW_MULTIPLIERS)
rows = []
for index, project_id in enumerate(quiet):
rows.append(_session(f"{project_id}-old", BASE_TS + index, project_id=project_id))
rows.extend(_lineage(
f"{project_id}-chain",
BASE_TS + 10_000 + index * 1_000,
scoped_raw_window + 100,
project_id=project_id,
step=1.0,
))
rows.extend(
_session(f"busy-{index:03d}", BASE_TS + 5_000 + index, project_id="project-busy")
for index in range(25)
)
rows.extend(_session(f"plain-{index:02d}", BASE_TS + 90_000 + index) for index in range(25))
_write_state_db(fake_hermes_home / "state.db", rows)
scoped_queries = []
real_reader = models.read_importable_agent_session_rows
def _counting_reader(*args, **kwargs):
if kwargs.get("project_ids"):
scoped_queries.append((kwargs["project_ids"][0], kwargs.get("limit")))
return real_reader(*args, **kwargs)
monkeypatch.setattr(models, "read_importable_agent_session_rows", _counting_reader)
sessions = models._load_cli_sessions_uncached(
fake_hermes_home,
fake_hermes_home / "state.db",
"default",
project_assigned_limit=per_project_limit,
)
# Completeness is untouched: EVERY starved project still gets its query.
# (The busy project is starved in this fixture too and is queried as well;
# what matters here is that no project of interest is skipped.)
tried = {project_id for project_id, _ in scoped_queries}
assert set(quiet) <= tried
# A widened query is one that asks for more than the project's own share.
widened = [limit for _, limit in scoped_queries if limit > effective_limit]
# The pool is one query_limit wide and each retry is charged its full width,
# so exactly one project can take the widest retry — not one per project.
assert widened == [query_limit]
# And the whole pass stays inside the documented 2 * query_limit bound,
# whatever the number of starved projects.
assert sum(limit for _, limit in scoped_queries) <= 2 * query_limit
# The widening the budget did fund still recovers the conversation behind
# the neediest project's window — the retry was rationed, not disabled.
widened_project = quiet[0]
assert f"{widened_project}-old" in {
session["session_id"] for session in sessions
}, "the one funded widening must still reach behind the binding window"