mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 03:49:26 +00:00
search-with-proof: per-search fair-share pilot budget (stop one search starving the rest)
--ceiling-usd was one shared SpendBudget passed to every search, so an expensive search drained the pool and starved later ones: in the last 2-pair/$2 run the first search spent $1.60 and the second hit the ceiling at $0.34 after finishing its analysis. The driver now allocates a dynamic fair share per search (remaining_ceiling / searches_not_yet_started), rolls unused settled budget forward, caps each search at its share, and keeps total settled <= ceiling. A search now gets room to author and verify after it finds the path. Driver-only change (benchmarks/search/pilot_run.py) plus tests. tests/test_search_pilot_run.py 39 passed; ruff clean; mypy unchanged (pre-existing benchmarks errors only). Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
e8e6637833
commit
2c0c45fd1f
@@ -67,6 +67,79 @@ def test_ceiling_refuses_before_stub_call(tmp_path):
|
||||
assert record["task_metrics"][0]["end"] == "run_ceiling"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"ceiling,first_spend,allocations",
|
||||
[(2.0, 0.25, [1.0, 1.75]), (2.0, 1.0, [1.0, 1.0]), (0.0, 0.0, [0.0, 0.0])],
|
||||
)
|
||||
def test_driver_allocates_fair_share_with_settled_rollover(tmp_path, monkeypatch, ceiling, first_spend, allocations):
|
||||
from types import SimpleNamespace
|
||||
|
||||
from benchmarks.search import pilot_run
|
||||
from openultrasast.plane.budget import BudgetExhausted
|
||||
|
||||
monkeypatch.chdir(tmp_path)
|
||||
root = Path("benchmarks/search/private")
|
||||
root.mkdir(parents=True)
|
||||
row = dict(
|
||||
repo="https://github.com/private/project",
|
||||
vulnerable="a" * 40,
|
||||
fixed="b" * 40,
|
||||
family="path",
|
||||
language="python",
|
||||
file="app.py",
|
||||
function="main",
|
||||
)
|
||||
(root / "pilot.json").write_text(json.dumps({"pairs": [row] * 3}))
|
||||
monkeypatch.setattr(pilot_run, "load_dotenv", lambda: None)
|
||||
monkeypatch.setenv(pilot_run.DEEPSEEK_KEY_ENV, "fake-test-key")
|
||||
monkeypatch.setattr(pilot_run, "OpenRouterChatClient", lambda **kw: SimpleNamespace(max_attempts=1))
|
||||
monkeypatch.setattr(pilot_run, "AXLane", lambda *args: object())
|
||||
budgets = []
|
||||
|
||||
def run(pilot):
|
||||
budget = pilot.worker.run_budget
|
||||
share = allocations[len(budgets)]
|
||||
assert all(budget is not previous for previous in budgets)
|
||||
assert budget.spent == budget.reserved == 0
|
||||
# Prove the cap through admission, then settle less than reserved to test rollover.
|
||||
with pytest.raises(BudgetExhausted):
|
||||
budget.reserve(share + 0.01)
|
||||
reservation = budget.reserve(share)
|
||||
reservation.settle(first_spend if not budgets else share)
|
||||
budgets.append(budget)
|
||||
pilot.record.update(spend={"reserved": share, "settled": budget.spent}, model_calls=0, tokens_in=0, tokens_out=0)
|
||||
return pilot.record
|
||||
|
||||
monkeypatch.setattr(pilot_run.Pilot, "run", run)
|
||||
output = tmp_path / "records.jsonl"
|
||||
assert (
|
||||
main(
|
||||
[
|
||||
"--side",
|
||||
"vulnerable",
|
||||
"--pairs",
|
||||
"2,0",
|
||||
"--ceiling-usd",
|
||||
str(ceiling),
|
||||
"--verify-lane",
|
||||
"ax",
|
||||
"--image",
|
||||
"image@sha256:" + "a" * 64,
|
||||
"--out",
|
||||
str(output),
|
||||
]
|
||||
)
|
||||
== 0
|
||||
)
|
||||
first, second, summary = [json.loads(line) for line in output.read_text().splitlines()]
|
||||
assert [first["pair_index"], second["pair_index"]] == [2, 0]
|
||||
assert len(budgets) == summary["searches"] == 2
|
||||
assert second["spend"]["settled"] == pytest.approx(allocations[1])
|
||||
total = sum(record["spend"]["settled"] for record in (first, second))
|
||||
assert summary["spend"]["settled"] == total <= ceiling
|
||||
assert total == pytest.approx(ceiling)
|
||||
|
||||
|
||||
def make_pilot(tmp_path, *, side="fixed", dry_run=False):
|
||||
from argparse import Namespace
|
||||
|
||||
|
||||
Reference in New Issue
Block a user