Files
Open_Ultra_SAST/src/openultrasast/hunt/report.py
T
Marius CiepluchandClaude Fable 5.1 6f9613329e feat(hunt): candidates scored on folds through the runner; the pilot gain, once per accepted program (6.1)
rounds.py runs a candidate over compile or held-out folds through runner.run, so a tool-using
program has its tools bound to each change's checkout, and turns paired records into the
FoldResults accept.decide reads (closes the gap noted in bacd7a1). report.py runs an accepted
program once over the held-out pilot: a ledger line reserved before the run refuses a second run
per program id, contaminated or unchecked training runs are refused, the instrument is proved per
change and more than 5% failures makes the run invalid with no numbers quoted, the pilot's own
scorer and metrics give the after numbers, the recorded hunter numbers give the before, baseline
repeats pair with the single run, the proof arm's workload per 100 pushes is counted, and the gate
distance is read off the confidence curve. 124 hunt and stats tests pass. Implemented by Codex
(gpt-6-astra), gated here.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-10-13 20:44:18 +02:00

473 lines
23 KiB
Python

"""Report one accepted program on the held-out pilot, with instrument proof before scores."""
from __future__ import annotations
import fcntl
import json
import math
import os
from collections.abc import Mapping, Sequence
from copy import deepcopy
from dataclasses import asdict
from datetime import UTC, datetime
from pathlib import Path
from typing import Any
from .. import stats
from . import accept, contamination, runner
from .ablation import _arm_summary, _findings, _write
from .metric import search_outcome
from .propose import Candidate
from .rounds import _candidate_program, _estimate, _families, _outcome, _paired
def _reserve(root: Path, program_id: str) -> Path:
"""Reserve a program under a file lock and flush the ledger before starting its run."""
date = datetime.now(UTC).date().isoformat()
if not program_id or any(c not in "0123456789abcdef" for c in program_id):
raise ValueError("program ID must be a hexadecimal content address")
root.mkdir(parents=True, exist_ok=True)
directory = root / f"{date}-hunt-gain-{program_id[:12]}"
with (root / "hunt-pilot-runs.jsonl").open("a+", encoding="utf-8") as stream:
fcntl.flock(stream, fcntl.LOCK_EX)
stream.seek(0)
if any(json.loads(line)["program_id"] == program_id for line in stream if line.strip()):
raise ValueError("this program ID already has a pilot run")
directory.mkdir(exist_ok=False)
stream.write(json.dumps(dict(program_id=program_id, date=date, measurement_directory=str(directory.resolve()))) + "\n")
stream.flush()
os.fsync(stream.fileno())
return directory
def _records(directory: Path, changes: Sequence[Mapping]) -> list[dict]:
"""Load benchmark records and retain every expected change, even after a budget stop."""
from benchmarks.unseen import score
records = score.load_records(Path(directory)) if (Path(directory) / "inputs.json").exists() else []
indexed = {r["id"]: r for r in records}
if len(indexed) != len(records) or set(indexed) - {c["id"] for c in changes}:
raise ValueError("records do not match the pilot population")
result = []
for change in changes:
record = indexed.get(change["id"], dict(change))
if any(record.get(key) != change.get(key) for key in ("repo", "base", "head", "kind", "family", "files", "targets")):
raise ValueError("record describes a different pilot change")
result.append(record)
return result
def _instrument(records: Sequence[Mapping]) -> dict:
"""Record changed-file bytes and verified revisions; unreadable and absent changes fail."""
from benchmarks.unseen import score
proof = []
for record in records:
instrument = record.get("instrument", {})
sizes = instrument.get("changed_bytes", {})
failed = not record.get("done") or record.get("status") == "instrument_failure" or score.coverage(record) == "instrument_failure"
proof.append(
dict(
id=record["id"],
repo=record["repo"],
base=record["base"],
head=record["head"],
base_verified=bool(instrument.get("base_verified")),
head_verified=bool(instrument.get("head_verified")),
changed_bytes={f["path"]: sizes.get(f["path"], 0) for f in record.get("files", [])},
instrument=dict(instrument),
instrument_failure=failed,
reason=instrument.get("failure") or ("missing or unreadable record" if failed else None),
)
)
failures = sum(row["instrument_failure"] for row in proof)
return dict(
changes=len(proof),
failures=failures,
failure_fraction=failures / len(proof) if proof else None,
valid=bool(proof) and failures / len(proof) <= 0.05,
records=proof,
)
def _clean(records: Sequence[Mapping]) -> list[dict]:
"""Remove stale findings on failures while preserving the scorer's coverage checks."""
from benchmarks.unseen import score
result = []
for original in records:
record = deepcopy(original)
if not record.get("done") or record.get("status") == "instrument_failure" or score.coverage(record) == "instrument_failure":
record["status"] = "instrument_failure"
record.setdefault("instrument", {})["failure"] = "instrument_failure"
outcome = _outcome(record, record, 10)
if not record.get("done") or record.get("status") == "instrument_failure" or record.get("parse_failed"):
record["push"] = {"admission": {"defects": []}, "quick_tier": []}
else:
record.setdefault("push", {}).setdefault("admission", {})["defects"] = outcome["defects"]
result.append(record)
return result
def _rate(values: list[float], repos: list[str], *, binary: bool = False, scale: float = 1) -> dict:
"""Report a mean with its count and a repository-clustered interval, plus Wilson for proportions."""
from benchmarks.unseen import score
interval = score.cluster_interval(list(zip(repos, values, strict=True)), seed=0)
result = dict(
rate=scale * sum(values) / len(values) if values else None,
count=sum(values),
n=len(values),
groups=len(set(repos)),
ci=[scale * v for v in interval] if values else None,
)
if binary:
wilson = stats.wilson(int(sum(values)), len(values))
result["wilson95"] = [scale * v for v in wilson] if wilson else None
return result
def _family_records(records: Sequence[Mapping], family: str | None) -> list[dict]:
"""Keep a family's positives and count only its findings over all ordinary pushes."""
result = []
for original in records:
if family is not None and original["kind"] == "vulnerability" and original.get("family") != family:
continue
record = deepcopy(original)
admission = record.setdefault("push", {}).setdefault("admission", {})
admission["defects"] = [d for d in admission.get("defects", []) if family is None or d.get("family") == family]
result.append(record)
return result
def _summaries(records: list[dict], families: list[str]) -> dict:
"""Use the pilot functions for push metrics and the hunt metric for search outcomes."""
from benchmarks.unseen import score
from benchmarks.valid import metrics
summaries = {}
for family in ["pooled", *families]:
part = _family_records(records, None if family == "pooled" else family)
positives = [r for r in part if r["kind"] == "vulnerability"]
ordinary = [r for r in part if r["kind"] == "ordinary"]
outcomes = {r["id"]: search_outcome(r, _findings(r.get("push", {}).get("admission", {}).get("defects", []))) for r in part}
search = dict(
recall=_rate([int(outcomes[r["id"]].hit) for r in positives], [r["repo"] for r in positives], binary=True),
suspicions_per_push=_rate([outcomes[r["id"]].suspicions for r in ordinary], [r["repo"] for r in ordinary]),
)
# The whole run already passed its instrument gate. The pilot scorer excludes these failures
# from push denominators, while the search summaries above keep them as misses.
usable = [r for r in part if score.coverage(r) != "instrument_failure"]
if usable:
scored = score.score(metrics.scoring_records(usable))
push = metrics.summarize(usable, scored=scored)
else:
push = {key: score.rate([]) for key in ("recall", "precision", "false_alarms_per_100_pushes")}
summaries[family] = dict(search=search, push=push)
return summaries
def _curve(records: list[dict]) -> tuple[list[dict], dict]:
"""Extend ablation confidence cuts with false alarms, intervals and the two gate bounds."""
from benchmarks.unseen import score
units = [dict(change=r, after=_outcome(r, r, 10)) for r in records]
curve = _arm_summary(units, "after", 10)["curve"]
for point in curve:
cut = point["confidence"]
filtered = deepcopy(records)
for record in filtered:
defects = record.get("push", {}).get("admission", {}).get("defects", [])
record.setdefault("push", {}).setdefault("admission", {})["defects"] = [
d
for d in defects
if isinstance(d.get("confidence"), int | float) and math.isfinite(d["confidence"]) and d["confidence"] >= cut
]
positives = [r for r in filtered if r["kind"] == "vulnerability"]
ordinary = [r for r in filtered if r["kind"] == "ordinary"]
hits = [int(search_outcome(r, _findings(r["push"]["admission"]["defects"])).hit) for r in positives]
point["estimates"] = dict(
recall=_rate(hits, [r["repo"] for r in positives], binary=True),
suspicions_per_push=_rate([len(r["push"]["admission"]["defects"]) for r in ordinary], [r["repo"] for r in ordinary]),
false_alarms_per_100_pushes=_rate(
[int(score.false_alarm(r)) for r in ordinary], [r["repo"] for r in ordinary], binary=True, scale=100
),
)
point["false_alarms_per_100_pushes"] = point["estimates"]["false_alarms_per_100_pushes"]["rate"]
high_recall = [p for p in curve if p["recall"] is not None and p["recall"] >= 0.9 and p["false_alarms_per_100_pushes"] is not None]
low_alarm = [
p
for p in curve
if p["false_alarms_per_100_pushes"] is not None and p["false_alarms_per_100_pushes"] < 10 and p["recall"] is not None
]
return curve, dict(
false_alarms_at_recall_90=min(high_recall, key=lambda p: p["false_alarms_per_100_pushes"]) if high_recall else None,
recall_under_10_false_alarms=max(low_alarm, key=lambda p: p["recall"]) if low_alarm else None,
)
def _precision(column: Any) -> float | None:
"""Reduce paired (correctly flagged, flagged) counts to push precision."""
flagged = sum(value[1] for value in column)
return sum(value[0] for value in column) / flagged if flagged else None
def _baseline_comparison(baselines: list[list[dict]], records: list[dict], families: list[str]) -> dict:
"""Pair every baseline repeat with the one accepted run, without inventing new repetitions."""
from benchmarks.unseen import score
from benchmarks.valid import metrics
units = [
dict(change=after, repeat=repeat, a=_outcome(before, before, 10), b=_outcome(after, after, 10))
for repeat, baseline in enumerate(baselines)
for before, after in zip(baseline, records, strict=True)
]
result = {}
for name in ["pooled", *families]:
family = None if name == "pooled" else name
recall, suspicions = _paired(units, family, seed=0, resamples=stats.RESAMPLES)
positives = [u for u in units if u["change"]["kind"] == "vulnerability" and (family is None or u["change"].get("family") == family)]
paired = dict(
search_recall=asdict(recall),
suspicions_per_push=asdict(suspicions),
mcnemar=asdict(stats.mcnemar_exact([u["a"]["hit"] for u in positives], [u["b"]["hit"] for u in positives])),
)
rows = {"recall": [], "false_alarms_per_100_pushes": [], "precision": []}
for baseline in baselines:
before = metrics.scoring_records(_family_records(baseline, family))
after = metrics.scoring_records(_family_records(records, family))
for a, b in zip(before, after, strict=True):
flags = [int(score.false_alarm(r)) for r in (a, b)]
hits = [int(bool(score.catches(r))) if r["kind"] == "vulnerability" else 0 for r in (a, b)]
key = "recall" if a["kind"] == "vulnerability" else "false_alarms_per_100_pushes"
values = hits if key == "recall" else [100 * v for v in flags]
rows[key].append(dict(repo=a["repo"], a=values[0], b=values[1]))
rows["precision"].append(dict(repo=a["repo"], a=(hits[0], flags[0]), b=(hits[1], flags[1])))
for metric, frame in rows.items():
paired[metric] = asdict(_estimate(frame, seed=0, resamples=stats.RESAMPLES, stat=_precision if metric == "precision" else None))
for metric in ("recall", "false_alarms_per_100_pushes"):
paired[metric + "_mcnemar"] = asdict(
stats.mcnemar_exact([bool(r["a"]) for r in rows[metric]], [bool(r["b"]) for r in rows[metric]])
)
result[name] = paired
return result
def _before(pilot_metrics: Mapping[str, Path]) -> dict:
"""Copy the two recorded metric files unchanged, with their source paths."""
if set(pilot_metrics) != {"raw", "filtered"}:
raise ValueError("pilot_metrics must map raw and filtered to their recorded JSON files")
return {name: dict(source=str(Path(path)), metrics=json.loads(Path(path).read_text())) for name, path in pilot_metrics.items()}
def _format(metric: Mapping | None) -> str:
"""Show the estimate, interval and count together, leaving missing measurements explicit."""
if not metric or metric.get("rate") is None:
return "not recorded" if not metric else f"not measured (n={metric.get('n', 0)})"
intervals = []
for key, label in (("ci", "cluster 95%"), ("cluster95", "cluster 95%"), ("wilson95", "Wilson 95%")):
ci = metric.get(key)
if ci and all(v is not None for v in ci):
intervals.append(f"{label} {ci[0]:.6g} to {ci[1]:.6g}")
return f"{metric['rate']:.6g}; {'; '.join(intervals)}; count={metric['count']}, n={metric['n']}"
def _notes(analysis: dict) -> str:
"""Write readable before-and-after tables and the evidence needed to interpret them."""
lines = ["# Hunter pilot gain", "", f"Program: `{analysis['program_id']}`", ""]
proof = analysis["instrument"]
lines += [
"## Instrument",
"",
f"{proof['failures']} instrument failures across {proof['changes']} changes.",
"Bytes per changed file and verified base and head are in instrument.json.",
"",
]
if not analysis["valid"]:
lines += [f"Run invalid: {analysis['reason']}. No performance numbers are quoted.", ""]
else:
lines += [
"## Before and after",
"",
"Before values are quoted as recorded; unavailable family or search values are not inferred.",
"Recall and precision are proportions. False alarms are per 100 ordinary pushes.",
"Push metrics exclude instrument failures as in the pilot. Search metrics and paired comparisons retain failures as misses.",
"The confidence curve describes the search output; it does not choose a threshold or change the classifier.",
"",
"| Family | Metric | Before raw | Before filtered | After |",
"|---|---|---|---|---|",
]
for family, summary in analysis["after"].items():
for stage, key, label in (
("search", "recall", "Search recall"),
("search", "suspicions_per_push", "Suspicions per ordinary push"),
("push", "recall", "Push recall"),
("push", "false_alarms_per_100_pushes", "False alarms per 100"),
("push", "precision", "Precision"),
):
before = [
analysis["before"][name]["metrics"].get(key) if family == "pooled" and stage == "push" else None
for name in ("raw", "filtered")
]
lines.append(f"| {family} | {label} | {_format(before[0])} | {_format(before[1])} | {_format(summary[stage][key])} |")
for name, recorded in analysis["before"].items():
lines += ["", f"Recorded {name} source: `{recorded['source']}`."]
if analysis.get("baseline"):
lines += [
"",
"## Baseline repeats",
"",
"Each repeat is paired with the single accepted run; intervals resample repositories.",
"",
"| Repeat | Family | Metric | Baseline | After |",
"|---|---|---|---|---|",
]
for repeat, baseline in enumerate(analysis["baseline"]):
if not baseline["valid"]:
lines += [f"Baseline repeat {repeat} is invalid; its performance numbers and paired gain are not quoted."]
continue
for family, summary in baseline["summary"].items():
for stage, keys in (
("search", ("recall", "suspicions_per_push")),
("push", ("recall", "false_alarms_per_100_pushes", "precision")),
):
for key in keys:
lines.append(
f"| {repeat} | {family} | {stage} {key} | {_format(summary[stage][key])} | "
f"{_format(analysis['after'][family][stage][key])} |"
)
if "paired" in analysis:
lines += [
"",
"Paired differences and exact McNemar results:",
"",
"```json",
json.dumps(analysis["paired"], indent=2),
"```",
]
lines += ["", "## Workload", ""]
for name, value in analysis["workload"].items():
lines.append(f"{name.replace('_', ' ')}: {_format(value)}.")
lines += ["", "## Gate distance", ""]
for name, point in analysis["gate_distance"].items():
label = (
"Lowest false alarms at recall at least 0.9"
if name == "false_alarms_at_recall_90"
else "Highest recall under 10 false alarms per 100"
)
lines.append(
f"{label}: "
+ (
"the curve never reaches this gate bound."
if point is None
else f"recall {_format(point['estimates']['recall'])}; "
f"false alarms {_format(point['estimates']['false_alarms_per_100_pushes'])}."
)
)
lines += ["", "## Acceptance comparison", "", "```json", json.dumps(analysis["comparison"], indent=2), "```", ""]
return "\n".join(lines)
def pilot_gain(
candidate: Candidate,
decision: accept.Decision,
*,
pilot_manifest: Path,
repos: Mapping[str, str],
training_runs: Sequence[Path],
out_root: Path,
lm: Any,
budget: Mapping[str, float],
baseline_runs: Sequence[Path] = (),
pilot_metrics: Mapping[str, Path],
tools_for: Any = None,
load_changes: Any = None,
) -> dict:
"""Run an accepted program once and write analysis.json, instrument.json and NOTES.md.
pilot_metrics maps raw and filtered to the original metric JSON files. Baseline runs are
single-repeat pilot record directories, each paired with this one accepted run. No command
line scorers or real model clients are constructed here. Budget exhaustion or more than five
percent instrument failures leaves an invalid measurement without performance numbers.
"""
import dspy
from benchmarks.unseen import score
from benchmarks.unseen.replay import load_slice
from .program import repository_tools
if not decision.accepted or decision.comparison.get("candidate_id") != candidate.program_id:
raise ValueError("pilot gain requires the accepted decision for this candidate")
training_runs = [Path(p) for p in training_runs]
if contamination.clean_runs(training_runs) != training_runs:
raise ValueError("contaminated training runs cannot report pilot gain")
before = _before(pilot_metrics)
program = _candidate_program(candidate, tools_for)
changes = list((load_changes or load_slice)(Path(pilot_manifest), "1"))
if not changes or len({c["id"] for c in changes}) != len(changes):
raise ValueError("pilot changes must be nonempty and have unique IDs")
directory = _reserve(Path(out_root), candidate.program_id)
with dspy.context(lm=lm, adapter=dspy.ChatAdapter()):
artifact = runner.run(
Path(pilot_manifest),
repos,
directory / "records",
program=program,
program_id=candidate.program_id,
mask=candidate.mask,
pilot_report=True,
only="all",
budget=budget,
tools_for=tools_for or repository_tools,
load_changes=lambda _path, _slice: changes,
versions={"dspy": dspy.__version__},
)
records = _records(directory / "records", changes)
proof = _instrument(records)
_write(directory / "instrument.json", proof)
analysis = dict(
program_id=candidate.program_id,
comparison=decision.comparison,
measurement_directory=directory.name,
valid=proof["valid"] and artifact is not None,
instrument={k: v for k, v in proof.items() if k != "records"},
)
if not analysis["valid"]:
analysis["reason"] = "more than 5% instrument failures" if not proof["valid"] else "runner budget exhausted"
else:
records = _clean(records)
# Run the same overall instrument gate and scorer as the pilot before quoting any scores.
score.score(records)
families = _families([dict(change=r, after=_outcome(r, r, 10)) for r in records], ("after",))
baseline_records = [_clean(_records(Path(path), changes)) for path in baseline_runs]
for baseline in baseline_records:
families = sorted(set(families) | set(_families([dict(change=r, before=_outcome(r, r, 10)) for r in baseline], ("before",))))
curve, distance = _curve(records)
counts = [search_outcome(r, _findings(r["push"]["admission"]["defects"])).suspicions for r in records]
analysis.update(
before=before,
after=_summaries(records, families),
curve=curve,
gate_distance=distance,
workload=dict(
suspicions_per_100_pushes=_rate(counts, [r["repo"] for r in records], scale=100),
flagged_pushes_per_100_pushes=_rate([int(n > 0) for n in counts], [r["repo"] for r in records], binary=True, scale=100),
),
)
if baseline_records:
analysis["baseline"] = []
for path, baseline in zip(baseline_runs, baseline_records, strict=True):
instrument = _instrument(baseline)
entry = dict(directory=str(path), valid=instrument["valid"], instrument=instrument)
if entry["valid"]:
entry["summary"] = _summaries(baseline, families)
analysis["baseline"].append(entry)
if all(row["valid"] for row in analysis["baseline"]):
analysis["paired"] = _baseline_comparison(baseline_records, records, families)
# Return the same JSON types that a reader of analysis.json receives.
analysis = json.loads(json.dumps(analysis))
_write(directory / "analysis.json", analysis)
(directory / "NOTES.md").write_text(_notes(analysis), encoding="utf-8")
return analysis