bench(valid): a training freeze may lower the ordinary floor to the ratio; the draw takes a size

The held-out benchmark keeps the 40-commit floor and the union of twelve-commit stratified draws.
A training freeze passes floor=20 (never below the ratio) and the record carries ordinary_floor.
When the union of twelve-commit draws cannot reach the count (small cells stay unallocated on
every draw), one stratified draw of the full count is used; with count equal to the eligible
commits that is every one of them.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
Marius Ciepluch
2026-10-13 18:33:10 +02:00
co-authored by Claude Fable 5.1
parent f29b3a3df2
commit bbbb0f397e
4 changed files with 54 additions and 9 deletions
+19 -4
View File
@@ -494,7 +494,20 @@ def ordinary_history(git, head: str) -> list[dict]:
return rows return rows
def draw_ordinary(rows: list[dict], fixes: set[str], known_functions: set[tuple[str, str]], *, seed: int) -> tuple[list[dict], dict]: ORDINARY_FLOOR = 40 # eligible ordinary commits a repository must have before one stratified draw of 12
def draw_ordinary(
rows: list[dict],
fixes: set[str],
known_functions: set[tuple[str, str]],
*,
seed: int,
floor: int = ORDINARY_FLOOR,
draws: int = 12,
) -> tuple[list[dict], dict]:
"""One stratified draw of ``draws`` ordinary commits (time third x size bucket, proportional, at least one per
third). ``draws`` equal to the eligible count takes every eligible commit, cell by cell."""
import random import random
from collections import Counter, defaultdict from collections import Counter, defaultdict
@@ -505,7 +518,9 @@ def draw_ordinary(rows: list[dict], fixes: set[str], known_functions: set[tuple[
counts[reason or "eligible"] += 1 counts[reason or "eligible"] += 1
if reason is None: if reason is None:
eligible.append(row) eligible.append(row)
if len(eligible) < 40: if floor < 12 or draws < 12:
raise ValueError("the ordinary floor and draw size cannot be below one draw of 12")
if len(eligible) < max(floor, draws):
failure = Rejected("ordinary_floor") failure = Rejected("ordinary_floor")
failure.counts = dict(counts) failure.counts = dict(counts)
raise failure raise failure
@@ -523,11 +538,11 @@ def draw_ordinary(rows: list[dict], fixes: set[str], known_functions: set[tuple[
# Largest-deficit rounding with the mandatory minimum of one per time third. # Largest-deficit rounding with the mandatory minimum of one per time third.
# No cell can receive more draws than it has eligible commits. # No cell can receive more draws than it has eligible commits.
allocation = Counter() allocation = Counter()
targets = {cell: 12 * len(items) / len(eligible) for cell, items in cells.items()} targets = {cell: draws * len(items) / len(eligible) for cell, items in cells.items()}
for third in range(3): for third in range(3):
cell = max(sorted(c for c in cells if c[0] == third), key=lambda c: targets[c]) cell = max(sorted(c for c in cells if c[0] == third), key=lambda c: targets[c])
allocation[cell] = 1 allocation[cell] = 1
while sum(allocation.values()) < 12: while sum(allocation.values()) < draws:
cell = max(sorted(c for c in cells if allocation[c] < len(cells[c])), key=lambda c: targets[c] - allocation[c]) cell = max(sorted(c for c in cells if allocation[c] < len(cells[c])), key=lambda c: targets[c] - allocation[c])
allocation[cell] += 1 allocation[cell] += 1
rng = random.Random(seed) rng = random.Random(seed)
+21 -5
View File
@@ -18,20 +18,27 @@ from .catalog import local_git
from .verify import verdict from .verify import verdict
def negatives(rows: list[dict], fixes: set[str], functions: set[tuple[str, str]], *, count: int, seed: int): def negatives(
"""Combine the shipped twelve-commit stratified draws without duplicates.""" rows: list[dict], fixes: set[str], functions: set[tuple[str, str]], *, count: int, seed: int, floor: int = extract.ORDINARY_FLOOR
):
"""Combine the shipped twelve-commit stratified draws without duplicates.
Small cells can stay unallocated in every twelve-commit draw, so when the union cannot reach ``count`` (a
training repository whose eligible commits barely cover the ratio) one stratified draw of ``count`` is used
instead; with ``count`` equal to the eligible commits that is every eligible commit."""
available = {row["head"] for row in rows if extract.ordinary_rejection(row, fixes, functions) is None} available = {row["head"] for row in rows if extract.ordinary_rejection(row, fixes, functions) is None}
if len(available) < count: if len(available) < count:
raise ValueError(f"insufficient ordinary commits: {len(available)} available, {count} required") raise ValueError(f"insufficient ordinary commits: {len(available)} available, {count} required")
chosen = {} chosen = {}
# Every call retains the original population and its time/size strata. # Every call retains the original population and its time/size strata.
for attempt in range(max(100, math.ceil(count / 12) * 100)): for attempt in range(max(100, math.ceil(count / 12) * 100)):
drawn, exclusions = extract.draw_ordinary(rows, fixes, functions, seed=seed + attempt) drawn, exclusions = extract.draw_ordinary(rows, fixes, functions, seed=seed + attempt, floor=floor)
for row in drawn: for row in drawn:
chosen.setdefault(row["head"], row) chosen.setdefault(row["head"], row)
if len(chosen) == count: if len(chosen) == count:
return sorted(chosen.values(), key=lambda row: row["head"]), exclusions return sorted(chosen.values(), key=lambda row: row["head"]), exclusions
raise ValueError("ordinary draw did not reach the required distinct count") drawn, exclusions = extract.draw_ordinary(rows, fixes, functions, seed=seed, floor=floor, draws=count)
return sorted(drawn, key=lambda row: row["head"]), exclusions
def freeze( def freeze(
@@ -45,9 +52,17 @@ def freeze(
ratio: int = 20, ratio: int = 20,
history_heads: dict | None = None, history_heads: dict | None = None,
fix_index: dict | None = None, fix_index: dict | None = None,
floor: int = extract.ORDINARY_FLOOR,
) -> dict: ) -> dict:
"""Freeze accepted positives with ``ratio`` ordinary pushes per fix commit from the same repositories.
``floor`` is the eligible-commit count a repository needs before its ordinary pushes are drawn. The
held-out benchmark keeps the shipped 40; a training freeze may lower it (never below the ratio) so small
repositories with 20 eligible commits still contribute, and the record carries the floor used."""
if type(ratio) is not int or ratio < 20: if type(ratio) is not int or ratio < 20:
raise ValueError("ordinary ratio must be at least 20") raise ValueError("ordinary ratio must be at least 20")
if type(floor) is not int or floor < ratio:
raise ValueError("ordinary floor must be at least the ratio")
if len({row["id"] for row in cases}) != len(cases) or len({row["id"] for row in verifications}) != len(verifications): if len({row["id"] for row in cases}) != len(cases) or len({row["id"] for row in verifications}) != len(verifications):
raise ValueError("duplicate case or verification id") raise ValueError("duplicate case or verification id")
used_names = {normalize(name) for name in (set().union(*used.sources.values()) if hasattr(used, "sources") else used)} used_names = {normalize(name) for name in (set().union(*used.sources.values()) if hasattr(used, "sources") else used)}
@@ -81,7 +96,7 @@ def freeze(
# accepted functions in one fix collapse to one vulnerability change below, so the # accepted functions in one fix collapse to one vulnerability change below, so the
# negative count must track distinct (commit, parent) pairs. # negative count must track distinct (commit, parent) pairs.
change_count = len({(case["commit"], case["parent"]) for case in positives}) change_count = len({(case["commit"], case["parent"]) for case in positives})
ordinary, exclusions = negatives(history, fixes, functions, count=ratio * change_count, seed=seed) ordinary, exclusions = negatives(history, fixes, functions, count=ratio * change_count, seed=seed, floor=floor)
draws[repo] = exclusions draws[repo] = exclusions
changes = [] changes = []
pairs = defaultdict(list) pairs = defaultdict(list)
@@ -137,6 +152,7 @@ def freeze(
history_heads=heads, history_heads=heads,
ordinary_exclusions=draws, ordinary_exclusions=draws,
negative_ratio=ratio, negative_ratio=ratio,
ordinary_floor=floor,
label_check_counts={"confirmed": sum(len(v) for v in retained.values()), "unchecked": 0, "unclear": 0, "refactor": 0}, label_check_counts={"confirmed": sum(len(v) for v in retained.values()), "unchecked": 0, "unclear": 0, "refactor": 0},
) )
payloads = [ payloads = [
+3
View File
@@ -406,6 +406,9 @@ def test_draw_seed_proportional_cells_floor_and_thirds():
assert counts["eligible"] == 120 assert counts["eligible"] == 120
with pytest.raises(s.Rejected, match="ordinary_floor"): with pytest.raises(s.Rejected, match="ordinary_floor"):
e.draw_ordinary(rows[:39], set(), set(), seed=19) e.draw_ordinary(rows[:39], set(), set(), seed=19)
assert len(e.draw_ordinary(rows[:39], set(), set(), seed=19, floor=20)[0]) == 12 # a training freeze may lower the floor
with pytest.raises(ValueError, match="below one draw"):
e.draw_ordinary(rows, set(), set(), seed=19, floor=11)
# Thirds come from the history's time span, not rank among eligible changes. # Thirds come from the history's time span, not rank among eligible changes.
with pytest.raises(s.Rejected, match="time_thirds"): with pytest.raises(s.Rejected, match="time_thirds"):
e.draw_ordinary([ordinary(i) for i in range(40)] + [ordinary(10000, message="security")], set(), set(), seed=1) e.draw_ordinary([ordinary(i) for i in range(40)] + [ordinary(10000, message="security")], set(), set(), seed=1)
+11
View File
@@ -385,7 +385,18 @@ def test_insufficient_negatives_and_invalid_ratio(pair, tmp_path, monkeypatch):
assemble.freeze(tmp_path, **kwargs) assemble.freeze(tmp_path, **kwargs)
with pytest.raises(ValueError, match="at least 20"): with pytest.raises(ValueError, match="at least 20"):
assemble.freeze(tmp_path, ratio=19, **kwargs) assemble.freeze(tmp_path, ratio=19, **kwargs)
with pytest.raises(ValueError, match="at least the ratio"):
assemble.freeze(tmp_path, floor=19, **kwargs)
assert not (tmp_path / "freeze-valid.json").exists() assert not (tmp_path / "freeze-valid.json").exists()
# A training freeze lowers the floor to the ratio: 20 eligible commits now suffice, and the record says so.
monkeypatch.setattr(extract, "ordinary_history", lambda *args: ordinary_rows(20))
with pytest.raises(ValueError, match="ordinary_floor"): # Rejected is a ValueError with a fixed reason code
assemble.freeze(tmp_path / "default", **kwargs)
result = assemble.freeze(tmp_path / "train", floor=20, **kwargs)
assert result["ordinary_floor"] == 20 and result["negative_ratio"] == 20
# Twenty eligible commits for a ratio of twenty: every one of them is drawn, none twice.
ordinary = [c for c in replay.load_slice(tmp_path / "train/pool-valid.toml", 1) if c["kind"] == "ordinary"]
assert len(ordinary) == 20 and len({c["head"] for c in ordinary}) == 20
def test_freeze_cannot_overwrite_or_trust_verdict_alone(pair, tmp_path, monkeypatch): def test_freeze_cannot_overwrite_or_trust_verdict_alone(pair, tmp_path, monkeypatch):