feat(detection-core): migrate benchmark readiness and admission consumers

This commit is contained in:
Marius Ciepluch
2026-11-03 18:37:44 +01:00
parent e98d264f62
commit 11059c4cd4
41 changed files with 3223 additions and 862 deletions
+1 -166
View File
@@ -15,34 +15,22 @@ mutates or re-labels the manifest it consumes.
from __future__ import annotations
import hashlib
import json
import tomllib
from collections.abc import Callable, Sequence
from dataclasses import dataclass
from pathlib import Path
from typing import Any
from benchmarks.unseen.replay import canonical
from benchmarks.valid.admission_scoring import AdmissionCase, OrdinaryChange, admission_report, score_v2_admission
from benchmarks.valid.arm_regression import BundleDigests, _input_digest, _prove_one
from benchmarks.valid.admission_scoring import AdmissionCase, OrdinaryChange, score_v2_admission
from benchmarks.valid.population_custody import AdmissionSpendAuthority, GuardedPopulationCustodian, ReleaseReview
from benchmarks.valid.prover_admission import AdmissionManifest, validate_admission_manifest
from openultrasast.core.admission_case import AdmissionCaseResult
from openultrasast.core.admission_report import AdmissionReplay
from openultrasast.core.admission_spend import authorize_admission
from openultrasast.preprocess import detect_language
from openultrasast.source import canonical_language, ranges
__all__ = [
"admission_ordinary",
"admission_pair_cases",
"assemble_admission_report",
"coverage_share",
"fixed_side_change",
"load_admission_population",
"locate_function",
"run_admission",
"run_v2_admission",
"V2AdmissionRunInput",
"site_judgment",
@@ -225,156 +213,3 @@ def coverage_share(records: tuple[dict[str, Any], ...]) -> float:
return 0.0
covered = sum(1 for total in per_repository.values() if total > 0)
return covered / len(per_repository)
def load_admission_population(
payload: dict[str, object], pool_path: Path, freeze_path: Path
) -> tuple[tuple[dict[str, Any], ...], tuple[dict[str, Any], ...]]:
"""Validate the manifest and the reviewed freeze before opening labels (Req 12.1)."""
manifest = validate_admission_manifest(payload)
pool = tomllib.loads(Path(pool_path).read_text(encoding="utf-8"))
freeze = json.loads(Path(freeze_path).read_text(encoding="utf-8"))
digest = hashlib.sha256(canonical(pool)).hexdigest()
if digest != freeze.get("freeze_digest"):
raise ValueError(f"population: pool digest {digest[:12]} does not match the reviewed freeze")
if freeze.get("guard_result") != 0:
raise ValueError("guard: held-out guard failed for this population")
if manifest.population_digest != digest:
raise ValueError("population: manifest names a different population than the reviewed freeze")
changes = tuple(
{**change, "id": _change_identity(repository, change), "repo": str(repository["id"])}
for repository in pool.get("repository", [])
for change in repository.get("changes", [])
)
vulnerable = tuple(change for change in changes if change.get("kind") == "vulnerability")
ordinary = tuple(change for change in changes if change.get("kind") == "ordinary")
return vulnerable, ordinary
def _change_identity(repository: dict[str, Any], change: dict[str, Any]) -> str:
"""The pool's canonical change identity, as ``replay.load_slice`` derives it."""
payload = [repository["id"], change["kind"], change["base"], change["head"]]
return hashlib.sha256(canonical(payload)).hexdigest()
def assemble_admission_report(
manifest: AdmissionManifest,
vulnerable: tuple[dict[str, Any], ...],
fixed: tuple[dict[str, Any], ...],
ordinary: tuple[dict[str, Any], ...],
*,
criteria: dict[str, float] | None,
budget_seconds: float = 120.0,
) -> dict[str, Any]:
"""Bridge measured records to the paired admission report (Reqs 12.7, 12.8).
Every change is budget-gated: pairs by their combined seconds, ordinary
changes individually (design.md:370 "fails any change over 120 seconds").
"""
failures = sum(1 for record in (*vulnerable, *fixed, *ordinary) if record.get("status") == "instrument_failure")
report = admission_report(
manifest,
admission_pair_cases(vulnerable, fixed),
admission_ordinary(ordinary),
coverage=coverage_share((*vulnerable, *fixed, *ordinary)),
instrument_failures=failures,
budget_seconds=budget_seconds,
criteria=criteria,
)
overruns = [
f"budget:{record['id']}:{float(record.get('seconds', 0.0)):g}s>{budget_seconds:g}s"
for record in ordinary
if float(record.get("seconds", 0.0)) > budget_seconds
]
if overruns:
report["failed_gates"] = [*report["failed_gates"], *overruns]
report["decision"] = "NO-GO"
return report
def _resume_or_prove(
bundle: BundleDigests,
population: str,
change: dict[str, Any],
repo_path: Path,
side_dir: Path,
) -> dict[str, Any]:
from benchmarks.valid.prover_arm import _write_json
side_dir.mkdir(parents=True, exist_ok=True)
path = side_dir / f"{change['id']}.json"
if path.is_file():
previous: dict[str, Any] = json.loads(path.read_text(encoding="utf-8"))
if previous.get("input_digest") == _input_digest(change, ARM_NAME):
return previous
raise ValueError(f"existing record for {change['id']} does not match this arm's inputs")
record = _prove_one(bundle, ARM_NAME, population, change, repo_path)
_write_json(path, record)
return record
def run_admission(
*,
payload: dict[str, object],
pool_path: Path,
freeze_path: Path,
repos: dict[str, str],
bundle: BundleDigests,
out_dir: Path,
criteria: dict[str, float] | None,
budget_seconds: float = 120.0,
) -> dict[str, Any]:
"""Consume the reviewed manifest, prove the population, return GO/NO-GO."""
vulnerable, ordinary = load_admission_population(payload, pool_path, freeze_path)
manifest = validate_admission_manifest(payload)
out_dir.mkdir(parents=True, exist_ok=True)
vulnerable_records = tuple(
_resume_or_prove(bundle, manifest.population_digest, change, Path(repos[change["repo"]]).expanduser(), out_dir / "vulnerable")
for change in vulnerable
)
fixed_records = tuple(
_resume_or_prove(
bundle,
manifest.population_digest,
_fixed_side_change(Path(repos[change["repo"]]).expanduser(), change),
Path(repos[change["repo"]]).expanduser(),
out_dir / "fixed",
)
for change in vulnerable
)
ordinary_records = tuple(
_resume_or_prove(bundle, manifest.population_digest, change, Path(repos[change["repo"]]).expanduser(), out_dir / "ordinary")
for change in ordinary
)
return assemble_admission_report(
manifest, vulnerable_records, fixed_records, ordinary_records, criteria=criteria, budget_seconds=budget_seconds
)
def _fixed_side_change(repo_path: Path, change: dict[str, Any]) -> dict[str, Any]:
lines, operation = _fixed_site(repo_path, change)
return fixed_side_change(change, fixed_lines=lines, fixed_operation=operation)
def _fixed_site(repo_path: Path, change: dict[str, Any]) -> tuple[tuple[int, int] | None, str]:
"""(lines, operation) for the labelled function at the fixed revision.
A locator miss (the name is present but ``ranges`` could not name it) is
"missed" and can never become a clean judgment (design.md:371).
"""
from benchmarks.valid.catalog import local_git
git = local_git(repo_path)
text = git.runner(
["git", "-C", str(repo_path), "show", f"{change['base']}:{change['path']}"],
capture_output=True,
text=True,
check=True,
).stdout
name = str(change.get("function"))
try:
functions = ranges(str(change["path"]), text, canonical_language(detect_language(repo_path / change["path"])))
except ValueError:
functions = ()
lines = locate_function(functions, name=name)
return lines, classify_fixed_site(lines, name_in_text=name in text)
+15 -2
View File
@@ -10,12 +10,13 @@ indeterminate and never converted to clean results; ordinary changes whose
review found a real missing-authorization defect are refused before scoring.
"""
from __future__ import annotations
from collections.abc import Sequence
from dataclasses import dataclass
from typing import Any
from typing import Any, Protocol
from benchmarks.unseen import score
from benchmarks.valid.prover_admission import AdmissionManifest
from openultrasast.core import canonical
from openultrasast.core.admission_case import AdmissionCaseRelease, AdmissionCaseResult
from openultrasast.core.admission_context import AdmissionValidationContext
@@ -31,6 +32,18 @@ __all__ = ["AdmissionCase", "AdmissionScoringError", "OrdinaryChange", "admissio
_JUDGMENTS = ("unguarded", "discharged", "indeterminate")
class AdmissionManifest(Protocol):
"""Structural shape used only by the parked legacy scoring helpers."""
population_role: str
analyzer_revision: str
fact_set_digest: str
acquisition_record_digest: str
configuration_digest: str
population_digest: str
families: tuple[str, ...]
class AdmissionScoringError(ValueError):
"""Raised when a population cannot be scored; the message names the reason."""
+99 -63
View File
@@ -23,11 +23,18 @@ from typing import Any
from benchmarks.unseen.extract import InstrumentFailure
from benchmarks.unseen.replay import canonical
from benchmarks.valid.artifact_contract import read_benchmark_artifact, write_benchmark_artifact
from benchmarks.valid.catalog import local_git
from benchmarks.valid.development_runner import AnalyzerBundle, stage_funnel
from benchmarks.valid.prover_arm import _write_json
from openultrasast.core.legacy_v1 import InstrumentFailure as CoreInstrumentFailure
from openultrasast.core.legacy_v1 import check_reads
from openultrasast.core.coverage import (
InputManifest,
InputReadReceipt,
derive_input_manifest_digest,
validate_instrument,
)
from openultrasast.core.coverage import (
InstrumentFailure as CoreInstrumentFailure,
)
from openultrasast.hunt.producers import Context, _Absent, _safe_path
from openultrasast.hunt.prover import prove_change
@@ -119,25 +126,8 @@ def _population_digest(changes: tuple[dict[str, Any], ...]) -> str:
return hashlib.sha256(joined.encode()).hexdigest()[:12]
def _prove_one(
bundle: BundleDigests,
arm_name: str,
population: str,
change: dict[str, Any],
repo_path: Path,
) -> dict[str, Any]:
started = time.monotonic()
instrument: dict[str, Any] = dict(
hook_exit=0,
hook_bytes_read=0,
changed_bytes={},
file_bytes={},
head_verified=False,
base_verified=False,
suspect_fast=False,
failure=None,
)
record: dict[str, Any] = {
def _arm_record(bundle: BundleDigests, arm_name: str, population: str, change: dict[str, Any], instrument: dict[str, Any]):
return {
**change,
"arm": arm_name,
"analyzer_revision": bundle.analyzer_revision,
@@ -157,40 +147,71 @@ def _prove_one(
"stage_funnel": {},
"push": {"admission": {"defects": [], "dispositions": []}, "quick_tier": []},
}
def _apply_prover_result(record: dict[str, Any], result: Any, change: dict[str, Any], instrument: dict[str, Any]) -> None:
funnel = stage_funnel(result)
record.update(
findings=list(result.findings),
traces=list(result.traces),
coverage=asdict(result.coverage),
degradations=list(result.degradations),
stage_funnel=funnel,
)
record["complexity"] = {
"regions": len(change.get("files", ())),
"calls": sum(funnel.get("resolution", {}).values()),
"changed_bytes": sum(instrument.get("changed_bytes", {}).values()),
}
record["push"]["admission"]["defects"] = [
{**finding, "defect_id": finding["id"], "source": "prover", "locations": [[finding["path"], finding["line"]]]}
for finding in result.findings
]
def _prove_checkout(record: dict[str, Any], change: dict[str, Any], repo_path: Path, instrument: dict[str, Any]) -> None:
git = local_git(repo_path)
git.run("cat-file", "-e", change["base"] + "^{commit}")
instrument["base_verified"] = True
with tempfile.TemporaryDirectory(prefix="ousast-arm-") as temporary:
root = Path(temporary) / "head"
git.run("-c", "core.hooksPath=/dev/null", "worktree", "add", "--detach", str(root), change["head"])
try:
_verify_checkout(root)
ctx = Context(root, change)
ctx.verify_head()
instrument["head_verified"] = True
_instrument_reads(ctx, root, change, instrument)
result = prove_change(root, change, ctx, judgment_mode=True)
instrument["hook_bytes_read"] = sum(instrument["file_bytes"].values())
_apply_prover_result(record, result, change, instrument)
finally:
git.run("worktree", "remove", "--force", str(root))
def _prove_one(
bundle: BundleDigests,
arm_name: str,
population: str,
change: dict[str, Any],
repo_path: Path,
) -> dict[str, Any]:
started = time.monotonic()
instrument: dict[str, Any] = dict(
hook_exit=0,
hook_bytes_read=0,
changed_bytes={},
changed_digests={},
file_bytes={},
file_digests={},
head_verified=False,
base_verified=False,
suspect_fast=False,
failure=None,
)
record = _arm_record(bundle, arm_name, population, change, instrument)
try:
git = local_git(repo_path)
git.run("cat-file", "-e", change["base"] + "^{commit}")
instrument["base_verified"] = True
with tempfile.TemporaryDirectory(prefix="ousast-arm-") as temporary:
root = Path(temporary) / "head"
git.run("-c", "core.hooksPath=/dev/null", "worktree", "add", "--detach", str(root), change["head"])
try:
_verify_checkout(root)
ctx = Context(root, change)
ctx.verify_head()
instrument["head_verified"] = True
_instrument_reads(ctx, root, change, instrument)
result = prove_change(root, change, ctx, judgment_mode=True)
instrument["hook_bytes_read"] = sum(instrument["file_bytes"].values())
funnel = stage_funnel(result)
record.update(
findings=list(result.findings),
traces=list(result.traces),
coverage=asdict(result.coverage),
degradations=list(result.degradations),
stage_funnel=funnel,
)
record["complexity"] = {
"regions": len(change.get("files", ())),
"calls": sum(funnel.get("resolution", {}).values()),
"changed_bytes": sum(instrument.get("changed_bytes", {}).values()),
}
record["push"]["admission"]["defects"] = [
{**finding, "defect_id": finding["id"], "source": "prover", "locations": [[finding["path"], finding["line"]]]}
for finding in result.findings
]
finally:
git.run("worktree", "remove", "--force", str(root))
_prove_checkout(record, change, repo_path, instrument)
except Exception as error: # noqa: BLE001 - the record must survive any instrument failure
instrument.update(hook_exit=2, failure=type(error).__name__)
record.update(status="instrument_failure", findings=[])
@@ -223,12 +244,19 @@ def _instrument_reads(ctx: Context, root: Path, change: dict[str, Any], instrume
held = local_git(root).runner(["git", "-C", str(root), "cat-file", "-s", f"HEAD:{relative}"], capture_output=True, text=True)
if getattr(error, "reason", "") == "empty_source" and held.returncode == 0 and int(held.stdout.strip() or 0) == 0:
instrument["empty_files"] = instrument.get("empty_files", 0) + 1
continue
instrument["file_bytes"][relative] = 0
instrument["file_digests"][relative] = hashlib.sha256(b"").hexdigest()
if relative in changed:
instrument["changed_bytes"][relative] = 0
instrument["changed_digests"][relative] = instrument["file_digests"][relative]
raise InstrumentFailure("zero-byte read") from error
raise InstrumentFailure("unread tracked file") from error
size = len(text.encode("utf-8"))
instrument["file_bytes"][relative] = size
instrument["file_digests"][relative] = hashlib.sha256(text.encode("utf-8")).hexdigest()
if relative in changed:
instrument["changed_bytes"][relative] = size
instrument["changed_digests"][relative] = instrument["file_digests"][relative]
if not size:
raise InstrumentFailure("zero-byte read")
@@ -248,13 +276,13 @@ def run_arm(
for change in changes:
path = out_dir / f"{change['id']}.json"
if path.is_file():
previous = json.loads(path.read_text(encoding="utf-8"))
previous = read_benchmark_artifact(path, "development-arm-record")
if previous.get("input_digest") == _input_digest(change, arm_name):
records.append(previous)
continue
raise ValueError(f"existing record for {change['id']} does not match this arm's inputs")
record = _prove_one(bundle, arm_name, population, change, Path(repos[change["repo"]]).expanduser())
_write_json(path, record)
write_benchmark_artifact(path, "development-arm-record", record)
records.append(record)
return tuple(records)
@@ -263,17 +291,25 @@ def _masked(repo: str) -> str:
return hashlib.sha256(repo.encode()).hexdigest()[:12]
def _validate_record_instrument(instrument: dict[str, Any]) -> None:
sizes = {**instrument.get("file_bytes", {}), **instrument.get("changed_bytes", {})}
digests = {**instrument.get("file_digests", {}), **instrument.get("changed_digests", {})}
input_ids = tuple(sorted(sizes))
try:
manifest = InputManifest(input_ids, derive_input_manifest_digest(input_ids))
receipts = tuple(InputReadReceipt(path, path, True, int(sizes[path]), digests.get(path)) for path in input_ids)
validate_instrument(manifest, receipts)
except (CoreInstrumentFailure, TypeError, ValueError) as error:
raise InstrumentFailure(str(error)) from error
def summarize_arm(records: tuple[dict[str, Any], ...]) -> dict[str, Any]:
"""Aggregate one arm; refuse any zero-byte read, publish budget and masked coverage."""
judgment = {"unguarded": 0, "discharged": 0, "indeterminate": 0}
per_repository: dict[str, dict[str, Any]] = {}
for record in records:
instrument = record.get("instrument", {})
merged = {**instrument.get("file_bytes", {}), **instrument.get("changed_bytes", {})}
try:
check_reads(merged) # core instrument refusal: a zero-byte read invalidates the run
except CoreInstrumentFailure as error:
raise InstrumentFailure(str(error)) from error
_validate_record_instrument(instrument)
funnel = record.get("stage_funnel", {})
for kind, count in funnel.get("judgment", {}).items():
judgment[kind] += int(count)
+309
View File
@@ -0,0 +1,309 @@
"""Strict benchmark-owned persistence for canonical v2 artifacts."""
from __future__ import annotations
import fcntl
import json
import os
import tempfile
from collections.abc import Iterator, Mapping, Sequence
from contextlib import contextmanager
from pathlib import Path
from typing import TypeAlias, cast
from openultrasast.core.canonical import JsonValue, content_digest
BENCHMARK_ARTIFACT_SCHEMA = "openultrasast.benchmark-artifact.v2"
ArtifactPayload: TypeAlias = Mapping[str, JsonValue]
ArtifactRows: TypeAlias = Sequence[Mapping[str, JsonValue]]
_RESERVED = frozenset({"schema_version", "artifact_kind", "artifact_digest"})
_SEQUENCE_KEYS = frozenset({"artifact_mode", "sequence_count", "sequence_digest", "rows"})
_JSONL_HEADER_KEYS = frozenset({"artifact_mode", "sequence_count", "sequence_digest"})
_JSONL_ROW_KEYS = frozenset({"sequence_index", "sequence_count", "sequence_digest", "artifact"})
def _canonical_value(value: object) -> JsonValue:
if value is None or isinstance(value, (str, bool, int, float)):
return value
if isinstance(value, Mapping):
return {str(key): _canonical_value(item) for key, item in value.items()}
if isinstance(value, Sequence) and not isinstance(value, (str, bytes)):
return tuple(_canonical_value(item) for item in value)
raise ValueError(f"unsupported benchmark artifact value: {type(value).__name__}")
def _kind(kind: str) -> str:
if not isinstance(kind, str) or not kind:
raise ValueError("benchmark artifact kind must be nonempty text")
return kind
def _artifact_digest(kind: str, payload: Mapping[str, JsonValue]) -> str:
return content_digest(
{
"schema_version": BENCHMARK_ARTIFACT_SCHEMA,
"artifact_kind": kind,
"payload": _canonical_value(payload),
}
)
def benchmark_artifact(kind: str, payload: ArtifactPayload) -> dict[str, JsonValue]:
"""Create one v2 artifact from an unwrapped payload."""
kind = _kind(kind)
if not isinstance(payload, Mapping):
raise ValueError("benchmark artifact payload must be a mapping")
if _RESERVED.intersection(payload):
raise ValueError("benchmark artifact payload uses reserved metadata")
value = {str(key): _canonical_value(item) for key, item in payload.items()}
return {
**value,
"schema_version": BENCHMARK_ARTIFACT_SCHEMA,
"artifact_kind": kind,
"artifact_digest": _artifact_digest(kind, value),
}
def benchmark_payload(value: object, *, expected_kind: str) -> dict[str, JsonValue]:
"""Strictly validate one v2 artifact and return its domain payload."""
expected_kind = _kind(expected_kind)
if not isinstance(value, dict):
raise ValueError("benchmark artifact metadata is missing")
if _RESERVED.intersection(value) != _RESERVED:
raise ValueError("benchmark artifact metadata is missing or incomplete")
raw = {str(key): item for key, item in value.items() if key not in _RESERVED}
canonical_raw = cast(dict[str, JsonValue], _canonical_value(raw))
if (
value["schema_version"] != BENCHMARK_ARTIFACT_SCHEMA
or value["artifact_kind"] != expected_kind
or value["artifact_digest"] != _artifact_digest(expected_kind, canonical_raw)
):
raise ValueError("benchmark artifact metadata does not match payload")
return cast(dict[str, JsonValue], raw)
def encode_benchmark_artifact(kind: str, payload: ArtifactPayload, *, indent: int | None = 2) -> str:
"""Encode one canonical v2 artifact."""
return json.dumps(benchmark_artifact(kind, payload), sort_keys=True, indent=indent, ensure_ascii=False)
@contextmanager
def _target_lock(path: Path) -> Iterator[None]:
path.parent.mkdir(parents=True, exist_ok=True)
descriptor = os.open(path.with_name(f".{path.name}.lock"), os.O_CREAT | os.O_RDWR, 0o600)
try:
fcntl.flock(descriptor, fcntl.LOCK_EX)
yield
finally:
fcntl.flock(descriptor, fcntl.LOCK_UN)
os.close(descriptor)
def _write_locked(path: Path, content: bytes, *, replace: bool) -> None:
if path.exists():
existing = path.read_bytes()
if existing == content:
return
if not replace:
raise ValueError(f"benchmark artifact conflict: {path}")
temporary_name: str | None = None
try:
with tempfile.NamedTemporaryFile(mode="wb", dir=path.parent, prefix=f".{path.name}.", suffix=".tmp", delete=False) as temporary:
temporary_name = temporary.name
temporary.write(content)
temporary.flush()
os.fsync(temporary.fileno())
os.replace(temporary_name, path)
temporary_name = None
finally:
if temporary_name is not None:
Path(temporary_name).unlink(missing_ok=True)
def _write_bytes(path: Path, content: bytes, *, replace: bool) -> None:
path = Path(path)
with _target_lock(path):
_write_locked(path, content, replace=replace)
def write_benchmark_artifact(path: Path, kind: str, payload: ArtifactPayload, *, replace: bool = False) -> None:
"""Atomically create one artifact; identical writes are idempotent."""
_write_bytes(path, (encode_benchmark_artifact(kind, payload) + "\n").encode(), replace=replace)
def read_benchmark_artifact(path: Path, expected_kind: str) -> dict[str, JsonValue]:
"""Read and strictly validate one artifact from disk."""
try:
value = json.loads(Path(path).read_text())
except (OSError, json.JSONDecodeError) as error:
raise ValueError(f"benchmark artifact unreadable: {path}") from error
return benchmark_payload(value, expected_kind=expected_kind)
def _ordered_digest(artifacts: Sequence[Mapping[str, JsonValue]]) -> str:
return content_digest(
tuple(
{"sequence_index": index, "artifact_digest": cast(str, artifact["artifact_digest"])} for index, artifact in enumerate(artifacts)
)
)
def _sequence_artifact(kind: str, rows: ArtifactRows) -> dict[str, JsonValue]:
artifacts = tuple(benchmark_artifact(f"{kind}.item", row) for row in rows)
members: tuple[JsonValue, ...] = tuple({"sequence_index": index, "artifact": artifact} for index, artifact in enumerate(artifacts))
return benchmark_artifact(
kind,
{
"artifact_mode": "ordered-sequence",
"sequence_count": len(artifacts),
"sequence_digest": _ordered_digest(artifacts),
"rows": members,
},
)
def write_benchmark_sequence(path: Path, kind: str, rows: ArtifactRows, *, replace: bool = False) -> None:
"""Persist an exact ordered collection with count, indices, and aggregate digest."""
value = _sequence_artifact(_kind(kind), rows)
content = (json.dumps(value, sort_keys=True, indent=2, ensure_ascii=False) + "\n").encode()
_write_bytes(path, content, replace=replace)
def _sequence_payload(value: object, kind: str) -> tuple[dict[str, JsonValue], ...]:
payload = benchmark_payload(value, expected_kind=kind)
if set(payload) != _SEQUENCE_KEYS or payload.get("artifact_mode") != "ordered-sequence":
raise ValueError("benchmark sequence metadata does not match contract")
count = payload.get("sequence_count")
sequence_digest = payload.get("sequence_digest")
members = payload.get("rows")
if (
not isinstance(count, int)
or count < 0
or not isinstance(sequence_digest, str)
or not isinstance(members, Sequence)
or isinstance(members, (str, bytes))
):
raise ValueError("benchmark sequence metadata is invalid")
if len(members) != count:
raise ValueError("benchmark sequence count mismatch")
rows: list[dict[str, JsonValue]] = []
artifacts: list[dict[str, JsonValue]] = []
for index, member in enumerate(members):
if not isinstance(member, dict) or set(member) != {"sequence_index", "artifact"} or member.get("sequence_index") != index:
raise ValueError("benchmark sequence index mismatch")
artifact = member.get("artifact")
rows.append(benchmark_payload(artifact, expected_kind=f"{kind}.item"))
artifacts.append(cast(dict[str, JsonValue], artifact))
digests = tuple(cast(str, artifact["artifact_digest"]) for artifact in artifacts)
if len(set(digests)) != len(digests) or sequence_digest != _ordered_digest(artifacts):
raise ValueError("benchmark sequence digest mismatch or duplicate row")
return tuple(rows)
def read_benchmark_sequence(path: Path, expected_kind: str) -> tuple[dict[str, JsonValue], ...]:
"""Read and validate a complete ordered collection."""
try:
value = json.loads(Path(path).read_text())
except (OSError, json.JSONDecodeError) as error:
raise ValueError(f"benchmark sequence unreadable: {path}") from error
return _sequence_payload(value, _kind(expected_kind))
def _jsonl_bytes(kind: str, rows: ArtifactRows) -> bytes:
items = tuple(benchmark_artifact(f"{kind}.item", row) for row in rows)
sequence_digest = _ordered_digest(items)
header = benchmark_artifact(
f"{kind}.sequence",
{"artifact_mode": "ordered-jsonl", "sequence_count": len(items), "sequence_digest": sequence_digest},
)
encoded = [json.dumps(header, sort_keys=True, ensure_ascii=False)]
for index, artifact in enumerate(items):
encoded.append(
json.dumps(
benchmark_artifact(
f"{kind}.row",
{
"sequence_index": index,
"sequence_count": len(items),
"sequence_digest": sequence_digest,
"artifact": artifact,
},
),
sort_keys=True,
ensure_ascii=False,
)
)
return ("\n".join(encoded) + "\n").encode()
def _jsonl_rows(content: bytes, kind: str) -> tuple[dict[str, JsonValue], ...]:
try:
values = tuple(json.loads(line) for line in content.decode().splitlines())
except (UnicodeDecodeError, json.JSONDecodeError) as error:
raise ValueError("benchmark JSONL is unreadable") from error
if not values:
raise ValueError("benchmark JSONL metadata is missing")
header = benchmark_payload(values[0], expected_kind=f"{kind}.sequence")
if set(header) != _JSONL_HEADER_KEYS or header.get("artifact_mode") != "ordered-jsonl":
raise ValueError("benchmark JSONL metadata does not match contract")
count = header.get("sequence_count")
sequence_digest = header.get("sequence_digest")
if not isinstance(count, int) or count < 0 or not isinstance(sequence_digest, str) or len(values) != count + 1:
raise ValueError("benchmark JSONL count mismatch")
rows: list[dict[str, JsonValue]] = []
items: list[dict[str, JsonValue]] = []
for index, value in enumerate(values[1:]):
member = benchmark_payload(value, expected_kind=f"{kind}.row")
if set(member) != _JSONL_ROW_KEYS:
raise ValueError("benchmark JSONL row metadata does not match contract")
if (
member.get("sequence_index") != index
or member.get("sequence_count") != count
or member.get("sequence_digest") != sequence_digest
):
raise ValueError("benchmark JSONL sequence binding mismatch")
artifact = member.get("artifact")
rows.append(benchmark_payload(artifact, expected_kind=f"{kind}.item"))
items.append(cast(dict[str, JsonValue], artifact))
digests = tuple(cast(str, item["artifact_digest"]) for item in items)
if len(set(digests)) != len(digests) or sequence_digest != _ordered_digest(items):
raise ValueError("benchmark JSONL digest mismatch or duplicate row")
return tuple(rows)
def write_benchmark_jsonl(path: Path, kind: str, rows: ArtifactRows, *, replace: bool = False) -> None:
"""Atomically persist an ordered JSONL manifest and its bound rows."""
_write_bytes(path, _jsonl_bytes(_kind(kind), rows), replace=replace)
def read_benchmark_jsonl(path: Path, expected_kind: str) -> tuple[dict[str, JsonValue], ...]:
"""Read and validate a complete ordered JSONL artifact."""
try:
content = Path(path).read_bytes()
except OSError as error:
raise ValueError(f"benchmark JSONL unreadable: {path}") from error
return _jsonl_rows(content, _kind(expected_kind))
def append_benchmark_jsonl(path: Path, kind: str, row: ArtifactPayload) -> None:
"""Append one row under the target lock and rewrite the bound sequence atomically."""
path = Path(path)
kind = _kind(kind)
with _target_lock(path):
rows = _jsonl_rows(path.read_bytes(), kind) if path.exists() else ()
_write_locked(path, _jsonl_bytes(kind, (*rows, row)), replace=True)
__all__ = [
"BENCHMARK_ARTIFACT_SCHEMA",
"append_benchmark_jsonl",
"benchmark_artifact",
"benchmark_payload",
"encode_benchmark_artifact",
"read_benchmark_artifact",
"read_benchmark_jsonl",
"read_benchmark_sequence",
"write_benchmark_artifact",
"write_benchmark_jsonl",
"write_benchmark_sequence",
]
+2 -4
View File
@@ -22,6 +22,7 @@ from typing import TYPE_CHECKING, Any, TypeVar
if TYPE_CHECKING:
from openultrasast.hunt.prover import ProverResult
from benchmarks.valid.artifact_contract import write_benchmark_artifact
from benchmarks.valid.readiness_contract import require_stage_authorized
from benchmarks.valid.run_manifests import AnalyzerBundle
from openultrasast.core.readiness import AnalysisIdentity, ReadinessResult, ReadinessStage
@@ -115,10 +116,7 @@ def run_development(
seconds=seconds,
)
records.append(record)
(out_dir / f"{record.change_id}.json").write_text(
json.dumps(asdict(record), indent=2, sort_keys=True) + "\n",
encoding="utf-8",
)
write_benchmark_artifact(out_dir / f"{record.change_id}.json", "development-observation", asdict(record))
return tuple(records)
+306
View File
@@ -0,0 +1,306 @@
"""Explicit, non-mutating handoff from the hunt runner to benchmark v2 storage."""
from __future__ import annotations
import hashlib
import json
from collections.abc import Mapping, Sequence
from dataclasses import asdict, dataclass
from pathlib import Path
from typing import Any, cast
from benchmarks.unseen.replay import canonical
from benchmarks.valid.artifact_contract import (
read_benchmark_artifact,
write_benchmark_artifact,
write_benchmark_sequence,
)
from openultrasast.hunt.artifact import MAX_ATTEMPT_ORDINAL, RunArtifact
from openultrasast.hunt.runner import input_digest, record_path
HUNT_RUNNER_PRODUCER = "openultrasast.hunt.runner.v1"
_RESERVED = frozenset({"schema_version", "artifact_kind", "artifact_digest"})
_RECORD_REQUIRED = frozenset(
{"id", "done", "status", "instrument", "push", "rows", "program_id", "mask", "inputs_present", "seconds", "input_digest", "usd"}
)
_RECORD_OPTIONAL = frozenset({"parse_failed", "loop_parse_failed"})
@dataclass(frozen=True)
class HuntRunContext:
producer: str
program_id: str
mask: tuple[str, ...]
manifest_digest: str
freeze_digest: str
only: str
slice_id: str
artifact_ids: tuple[str, ...]
versions: tuple[tuple[str, str], ...]
def _hex_digest(value: object, field: str) -> str:
if not isinstance(value, str) or len(value) != 64 or any(character not in "0123456789abcdef" for character in value):
raise ValueError(f"hunt handoff {field} must be a full lowercase digest")
return value
def _validate_context(context: HuntRunContext) -> None:
if context.producer != HUNT_RUNNER_PRODUCER:
raise ValueError(f"unsupported hunt producer: {context.producer}")
_hex_digest(context.program_id, "program identity")
_hex_digest(context.manifest_digest, "manifest identity")
_hex_digest(context.freeze_digest, "freeze identity")
if tuple(sorted(set(context.mask))) != context.mask:
raise ValueError("hunt handoff mask must be sorted and unique")
if not context.only or not context.slice_id:
raise ValueError("hunt handoff runner context is incomplete")
if not context.artifact_ids or tuple(sorted(set(context.artifact_ids))) != context.artifact_ids:
raise ValueError("hunt handoff attempt identities must be nonempty, sorted, and unique")
for artifact_id in context.artifact_ids:
_hex_digest(artifact_id, "attempt identity")
if tuple(sorted(set(context.versions))) != context.versions:
raise ValueError("hunt handoff versions must be sorted and unique")
def _read_json(path: Path, label: str) -> object:
try:
data = path.read_bytes()
if not data:
raise ValueError(f"{label} is empty")
return json.loads(data)
except (OSError, json.JSONDecodeError) as error:
raise ValueError(f"{label} is unreadable") from error
def _has_reserved(value: object) -> bool:
if isinstance(value, Mapping):
return bool(_RESERVED.intersection(value)) or any(_has_reserved(item) for item in value.values())
if isinstance(value, Sequence) and not isinstance(value, (str, bytes)):
return any(_has_reserved(item) for item in value)
return False
def _expected_entries(changes: Sequence[Mapping[str, Any]], context: HuntRunContext) -> tuple[dict[str, Any], ...]:
if not changes or len({change.get("id") for change in changes}) != len(changes):
raise ValueError("hunt handoff changes must be nonempty with unique identities")
return tuple(
{
"item_id": change["id"],
"change": dict(change),
"input_digest": input_digest(change, context.program_id, context.mask),
}
for change in changes
if context.only == "all" or change.get("kind") == context.only
)
def _raw_entries(source: Path, expected: tuple[dict[str, Any], ...]) -> tuple[dict[str, Any], ...]:
value = _read_json(source / "inputs.json", "hunt input index")
if not isinstance(value, list) or _has_reserved(value):
raise ValueError("hunt input index has reserved metadata or an unsupported schema")
if not all(isinstance(row, dict) and set(row) == {"item_id", "change", "input_digest"} for row in value):
raise ValueError("hunt input index has an unsupported row shape")
rows = cast(tuple[dict[str, Any], ...], tuple(value))
if rows != expected[: len(rows)]:
raise ValueError("hunt input identity, ordering, or input digest mismatch")
return rows
def _artifact_paths(source: Path, record_names: set[str]) -> tuple[Path, ...]:
return tuple(sorted(path for path in source.glob("*.json") if path.name != "inputs.json" and path.name not in record_names))
def _artifact_projection(artifact: RunArtifact) -> tuple[object, ...]:
return (
artifact.schema_version,
artifact.program_id,
tuple(artifact.mask),
tuple(sorted(artifact.data_digests.items())),
tuple(json.dumps(value, sort_keys=True) for value in artifact.configurations),
tuple(sorted(artifact.versions.items())),
)
def _read_attempts(paths: Sequence[Path]) -> tuple[RunArtifact, ...]:
artifacts: list[RunArtifact] = []
for path in paths:
try:
artifact = RunArtifact.read(path)
except (OSError, TypeError, ValueError) as error:
raise ValueError("hunt runner context artifact is invalid") from error
if path.stem != artifact.artifact_id:
raise ValueError("hunt runner context artifact filename does not match its identity")
artifacts.append(artifact)
if not artifacts:
raise ValueError("hunt runner context artifact collection is empty")
ordinals = [artifact.attempt_ordinal for artifact in artifacts]
if any(type(ordinal) is not int or not 0 < ordinal <= MAX_ATTEMPT_ORDINAL for ordinal in ordinals) or len(set(ordinals)) != len(
ordinals
):
raise ValueError("hunt runner attempt ordinals must be positive and unique")
projection = _artifact_projection(artifacts[0])
if any(_artifact_projection(artifact) != projection for artifact in artifacts[1:]):
raise ValueError("hunt runner attempt invariant mismatch")
return tuple(artifacts)
def _validate_run_artifact(source: Path, context: HuntRunContext, expected: tuple[dict[str, Any], ...]) -> None:
record_names = {record_path(source, cast(str, entry["item_id"])).name for entry in expected}
artifacts = _read_attempts(_artifact_paths(source, record_names))
artifact = artifacts[0]
if tuple(sorted(item.artifact_id for item in artifacts)) != context.artifact_ids:
raise ValueError("hunt runner attempt identities do not match handoff context")
if artifact.schema_version != 1:
raise ValueError("hunt runner schema is unsupported")
if artifact.program_id != context.program_id or tuple(artifact.mask) != context.mask:
raise ValueError("hunt runner program identity does not match handoff context")
if artifact.data_digests != {"manifest": context.manifest_digest}:
raise ValueError("hunt runner manifest identity does not match handoff context")
expected_configuration = [{"only": context.only, "slice": context.slice_id, "changes": len(expected)}]
if artifact.configurations != expected_configuration:
raise ValueError("hunt runner configuration identity does not match handoff context")
if tuple(sorted(artifact.versions.items())) != context.versions:
raise ValueError("hunt runner version identity does not match handoff context")
def _raw_record(source: Path, entry: Mapping[str, Any], context: HuntRunContext) -> dict[str, Any] | None:
path = record_path(source, cast(str, entry["item_id"]))
if not path.exists():
return None
value = _read_json(path, "hunt record")
if not isinstance(value, dict) or _has_reserved(value):
raise ValueError("hunt record uses reserved metadata or an unsupported schema")
keys = frozenset(value)
if not _RECORD_REQUIRED.issubset(keys) or not keys.issubset(_RECORD_REQUIRED | _RECORD_OPTIONAL):
raise ValueError("hunt record has an unsupported shape")
if value["id"] != entry["item_id"]:
raise ValueError("hunt record identity mismatch")
if value["input_digest"] != entry["input_digest"]:
raise ValueError("hunt record input digest mismatch")
if value["program_id"] != context.program_id or tuple(value["mask"]) != context.mask:
raise ValueError("hunt record program or configuration identity mismatch")
if value["done"] is not True or not isinstance(value["instrument"], dict) or not isinstance(value["push"], dict):
raise ValueError("hunt record completion schema is invalid")
return value
def read_hunt_runner_records(
source: Path,
*,
context: HuntRunContext,
changes: Sequence[Mapping[str, Any]],
) -> tuple[dict[str, Any], ...]:
"""Validate a named raw hunt run and return normalized rows without writing to it."""
source = Path(source)
_validate_context(context)
expected = _expected_entries(changes, context)
_validate_run_artifact(source, context, expected)
entries = _raw_entries(source, expected)
rows: list[dict[str, Any]] = []
for entry in entries:
record = _raw_record(source, entry, context) or {}
change = cast(dict[str, Any], entry["change"])
rows.append({**change, **record, "id": change["id"]})
return tuple(rows)
def _handoff_payload(context: HuntRunContext, entries: Sequence[Mapping[str, Any]]) -> dict[str, Any]:
return {
**asdict(context),
"mask": list(context.mask),
"input_count": len(entries),
"input_sequence_digest": hashlib.sha256(canonical(entries)).hexdigest(),
}
def persist_hunt_runner_records(
source: Path,
destination: Path,
*,
context: HuntRunContext,
changes: Sequence[Mapping[str, Any]],
) -> tuple[dict[str, Any], ...]:
"""Copy a validated raw run into distinct benchmark-owned canonical v2 files."""
source, destination = Path(source), Path(destination)
if source.resolve() == destination.resolve():
raise ValueError("hunt producer and benchmark destination must be distinct")
rows = read_hunt_runner_records(source, context=context, changes=changes)
expected = _expected_entries(changes, context)
entries = _raw_entries(source, expected)
write_benchmark_artifact(destination / "handoff.json", "hunt-runner-handoff", _handoff_payload(context, entries))
write_benchmark_sequence(destination / "inputs.json", "benchmark-arm-inputs", entries)
for entry in entries:
record = _raw_record(source, entry, context)
if record is not None:
write_benchmark_artifact(record_path(destination, cast(str, entry["item_id"])), "benchmark-arm-record", record)
return rows
def read_hunt_handoff_context(path: Path) -> HuntRunContext:
"""Read the bound context of an already-normalized benchmark handoff."""
payload = read_benchmark_artifact(Path(path) / "handoff.json", "hunt-runner-handoff")
context = HuntRunContext(
producer=cast(str, payload["producer"]),
program_id=cast(str, payload["program_id"]),
mask=tuple(cast(Sequence[str], payload["mask"])),
manifest_digest=cast(str, payload["manifest_digest"]),
freeze_digest=cast(str, payload["freeze_digest"]),
only=cast(str, payload["only"]),
slice_id=cast(str, payload["slice_id"]),
artifact_ids=tuple(cast(Sequence[str], payload["artifact_ids"])),
versions=tuple(tuple(cast(Sequence[str], row)) for row in cast(Sequence[Sequence[str]], payload["versions"])),
)
_validate_context(context)
return context
def discover_hunt_runner_context(
source: Path,
manifest: Path,
*,
producer: str,
freeze_digest: str,
) -> HuntRunContext:
"""Resolve the content-addressed runner identity for a documented raw-run handoff."""
if producer != HUNT_RUNNER_PRODUCER:
raise ValueError(f"unsupported hunt producer: {producer}")
manifest_bytes = Path(manifest).read_bytes()
if not manifest_bytes:
raise ValueError("hunt handoff manifest is empty")
manifest_digest = hashlib.sha256(manifest_bytes).hexdigest()
paths: list[Path] = []
for path in Path(source).glob("*.json"):
value = _read_json(path, "hunt runner candidate")
if isinstance(value, dict) and "artifact_id" in value:
paths.append(path)
artifacts = _read_attempts(tuple(sorted(paths)))
artifact = artifacts[0]
if len(artifact.configurations) != 1:
raise ValueError("hunt runner configuration artifact is ambiguous")
if artifact.data_digests != {"manifest": manifest_digest}:
raise ValueError("hunt runner manifest identity does not match supplied manifest")
configuration = artifact.configurations[0]
context = HuntRunContext(
producer=producer,
program_id=artifact.program_id,
mask=tuple(artifact.mask),
manifest_digest=manifest_digest,
freeze_digest=freeze_digest,
only=cast(str, configuration.get("only")),
slice_id=cast(str, configuration.get("slice")),
artifact_ids=tuple(sorted(item.artifact_id for item in artifacts)),
versions=tuple(sorted(artifact.versions.items())),
)
_validate_context(context)
return context
__all__ = [
"HUNT_RUNNER_PRODUCER",
"HuntRunContext",
"discover_hunt_runner_context",
"persist_hunt_runner_records",
"read_hunt_handoff_context",
"read_hunt_runner_records",
]
+47 -28
View File
@@ -27,6 +27,12 @@ if __package__ in {None, ""}:
from benchmarks.unseen.extract import SHA, InstrumentFailure
from benchmarks.unseen.replay import canonical, load_slice
from benchmarks.unseen.score import load_records
from benchmarks.valid.artifact_contract import (
read_benchmark_artifact,
read_benchmark_sequence,
write_benchmark_artifact,
write_benchmark_sequence,
)
from benchmarks.valid.catalog import local_git
# These names describe findings, never benchmark labels. The taxonomy owns the
@@ -154,11 +160,12 @@ def finding_defect(finding, classification=None):
}
def _write_json(path, value):
path.parent.mkdir(parents=True, exist_ok=True)
temporary = path.with_suffix(".json.tmp")
temporary.write_text(json.dumps(value, sort_keys=True, indent=2) + "\n")
temporary.replace(path)
def _write_json(path, value, *, kind=None, replace=False):
kind = kind or ("benchmark-arm-inputs" if Path(path).name == "inputs.json" else "benchmark-arm-record")
if isinstance(value, list):
write_benchmark_sequence(path, kind, value, replace=replace)
else:
write_benchmark_artifact(path, kind, value, replace=replace)
def _record_path(out, identity):
@@ -167,7 +174,7 @@ def _record_path(out, identity):
def _inputs(out):
path = out / "inputs.json"
entries = json.loads(path.read_text()) if path.exists() else []
entries = list(read_benchmark_sequence(path, "benchmark-arm-inputs")) if path.exists() else []
for key in (lambda entry: entry["item_id"], lambda entry: entry["change"]["id"]):
if len({key(entry) for entry in entries}) != len(entries):
raise ValueError(f"duplicate ids in {path}")
@@ -277,21 +284,13 @@ def _hunt_change(change, repos, *, client, model, max_steps, no_classify=False):
return record
def run(
manifest, repos_path, out, *, slice_id="1", max_steps=tool_hunter.DEFAULT_MAX_STEPS, only="all", client_mode=None, no_classify=False
):
if max_steps < 1:
raise ValueError("max_steps must be positive")
changes = load_slice(manifest, slice_id)
if len({change["id"] for change in changes}) != len(changes):
raise ValueError("duplicate change ids")
changes = [change for change in changes if only == "all" or change["kind"] == only]
def _pending_hunter_entries(changes, out):
entries = _inputs(out)
indexed = {entry["change"]["id"]: entry for entry in entries}
pending = []
for change in changes:
path = _record_path(out, change["id"])
previous = json.loads(path.read_text()) if path.exists() else {}
previous = read_benchmark_artifact(path, "benchmark-arm-record") if path.exists() else {}
entry = indexed.get(change["id"])
if entry is None:
entry = {
@@ -306,31 +305,51 @@ def run(
print(f"{change['id']}: skipped (done)", flush=True)
continue
pending.append(entry)
if not pending:
_write_json(out / "inputs.json", entries)
return 0
return entries, pending
def _hunter_client(client_mode, out):
config_path = Path("openultrasast.toml")
config = load_config(config_path if config_path.exists() else None, dotenv=client_mode != "scripted")
model = resolve_models(config)[0]
client = tool_hunter.scripted_hunter_client() if client_mode == "scripted" else tool_hunter.resolve_hunter_client()
if client is None:
print("No hunter client resolved. Configure a hunter provider or use --client scripted for offline tests.", file=sys.stderr)
return 2
repos = json.loads(repos_path.read_text())
_write_json(out / "inputs.json", entries)
return client, model
def _run_hunter_entries(pending, repos, out, client, model, client_mode, max_steps, no_classify):
failed = False
for entry in pending:
# The built-in script is a finite sequence, so each change needs a fresh
# sequence. Live clients remain shared and are resolved only once.
if client_mode == "scripted":
client = tool_hunter.scripted_hunter_client()
record = _hunt_change(entry["change"], repos, client=client, model=model, max_steps=max_steps, no_classify=no_classify)
current_client = tool_hunter.scripted_hunter_client() if client_mode == "scripted" else client
record = _hunt_change(entry["change"], repos, client=current_client, model=model, max_steps=max_steps, no_classify=no_classify)
record["input_digest"] = entry["input_digest"]
_write_json(_record_path(out, entry["item_id"]), record)
failed |= record["status"] == "instrument_failure"
return 2 if failed else 0
def run(
manifest, repos_path, out, *, slice_id="1", max_steps=tool_hunter.DEFAULT_MAX_STEPS, only="all", client_mode=None, no_classify=False
):
if max_steps < 1:
raise ValueError("max_steps must be positive")
changes = load_slice(manifest, slice_id)
if len({change["id"] for change in changes}) != len(changes):
raise ValueError("duplicate change ids")
changes = [change for change in changes if only == "all" or change["kind"] == only]
entries, pending = _pending_hunter_entries(changes, out)
if not pending:
_write_json(out / "inputs.json", entries, kind="benchmark-arm-inputs", replace=True)
return 0
client, model = _hunter_client(client_mode, out)
if client is None:
return 2
repos = json.loads(repos_path.read_text())
_write_json(out / "inputs.json", entries, kind="benchmark-arm-inputs", replace=True)
return _run_hunter_entries(pending, repos, out, client, model, client_mode, max_steps, no_classify)
def _joined(out):
_inputs(out)
rows = load_records(out)
@@ -393,7 +412,7 @@ def combine(replay_out, hunter_out, out, *, keep_verdicts=None):
"b": right.get("status", "missing") if has_b else "missing",
}
combined.append(merged)
_write_json(out, combined)
_write_json(out, combined, kind="benchmark-arm-records", replace=True)
return combined
+64 -50
View File
@@ -19,6 +19,14 @@ import json
import time
from pathlib import Path
from benchmarks.valid.artifact_contract import (
append_benchmark_jsonl,
encode_benchmark_artifact,
read_benchmark_artifact,
read_benchmark_jsonl,
write_benchmark_artifact,
)
JUDGE_QUESTION = (
"A static analyzer flagged this code path as a possible access-control "
"vulnerability: an attacker-reachable entry point reaches a protected "
@@ -51,13 +59,13 @@ def _judge_input(repo: str, finding: dict) -> str:
"operation": finding.get("operation", {}),
"missing": finding.get("missing"),
}
return JUDGE_QUESTION + "\n\n" + json.dumps(payload, indent=2, default=str)
return JUDGE_QUESTION + "\n\n" + encode_benchmark_artifact("judge-pass-input", payload)
def _iter_findings(prover_out: Path):
"""Every finding of every completed prover record, with its push context."""
for path in sorted(prover_out.glob("[0-9a-f]*.json")):
record = json.loads(path.read_text())
record = read_benchmark_artifact(path, "benchmark-arm-record")
if not record.get("done"):
continue
for finding in record.get("findings") or []:
@@ -68,20 +76,19 @@ def _load_done(out: Path) -> dict:
done = {}
judged = out / "judgments.jsonl"
if judged.is_file():
for line in judged.read_text().splitlines():
if line.strip():
row = json.loads(line)
done[row["key"]] = row
for row in read_benchmark_jsonl(judged, "judge-pass"):
key = row["key"]
if key in done:
raise ValueError(f"duplicate judge key: {key}")
done[key] = row
return done
def run(args) -> int:
def _judge_program(out: Path):
import dspy
from openultrasast.hunt.program import build_lm
out = Path(args.out)
out.mkdir(parents=True, exist_ok=True)
lm = build_lm(cache_dir=out / "dspy-cache")
dspy.configure(lm=lm, adapter=dspy.ChatAdapter())
@@ -91,52 +98,59 @@ def run(args) -> int:
case: str = dspy.InputField()
answer: str = dspy.OutputField()
judge = dspy.Predict(Judge)
done = _load_done(out)
judgments_path = out / "judgments.jsonl"
return dspy, lm, dspy.Predict(Judge)
todo = 0
failures = []
started = time.monotonic()
for record, finding in _iter_findings(Path(args.prover_out)):
key = _finding_key(record["id"], finding.get("id") or "")
if key in done:
def _judgment_payload(record, finding, model):
return {
"key": _finding_key(record["id"], finding.get("id") or ""),
"record_id": record["id"],
"repo": record["repo"],
"kind": record.get("kind"),
"finding_id": finding.get("id"),
"path": finding.get("path"),
"line": finding.get("line"),
"model": model,
}
def _apply_judgment(payload, judge, record, finding):
result = judge(case=_judge_input(record["repo"], finding))
text = (result.answer or "").strip()
body = text.strip("`")
if body.lower().startswith("json"):
body = body[4:]
parsed = json.loads(body[body.index("{") : body.rindex("}") + 1])
if not isinstance(parsed.get("public"), bool):
raise ValueError("public is not a boolean")
payload.update(public=parsed["public"], confidence=parsed.get("confidence"), reason=parsed.get("reason"), status="ok")
def _judge_findings(prover_out, out, lm, judge, done):
todo, failures = 0, []
for record, finding in _iter_findings(prover_out):
payload = _judgment_payload(record, finding, lm.model)
if payload["key"] in done:
continue
todo += 1
payload = {
"key": key,
"record_id": record["id"],
"repo": record["repo"],
"kind": record.get("kind"),
"finding_id": finding.get("id"),
"path": finding.get("path"),
"line": finding.get("line"),
"model": lm.model,
}
try:
result = judge(case=_judge_input(record["repo"], finding))
text = (result.answer or "").strip()
# Tolerate a fenced JSON block, then parse strictly.
body = text.strip("`")
if body.lower().startswith("json"):
body = body[4:]
parsed = json.loads(body[body.index("{") : body.rindex("}") + 1])
if not isinstance(parsed.get("public"), bool):
raise ValueError("public is not a boolean")
payload["public"] = parsed["public"]
payload["confidence"] = parsed.get("confidence")
payload["reason"] = parsed.get("reason")
payload["status"] = "ok"
except Exception as error: # noqa: BLE001 (recorded, never swallowed silently)
payload["status"] = "judge_error"
payload["error_type"] = type(error).__name__
payload["error"] = str(error)[:500]
_apply_judgment(payload, judge, record, finding)
except Exception as error: # noqa: BLE001
payload.update(status="judge_error", error_type=type(error).__name__, error=str(error)[:500])
failures.append(payload)
with judgments_path.open("a") as handle:
handle.write(json.dumps(payload, default=str) + "\n")
append_benchmark_jsonl(out / "judgments.jsonl", "judge-pass", payload)
if not todo % 25:
print(f"{todo} judged, {len(failures)} failures", flush=True)
return todo, failures
def run(args) -> int:
out = Path(args.out)
out.mkdir(parents=True, exist_ok=True)
dspy, lm, judge = _judge_program(out)
done = _load_done(out)
started = time.monotonic()
todo, failures = _judge_findings(Path(args.prover_out), out, lm, judge, done)
seconds = time.monotonic() - started
meta = {
"model": lm.model,
@@ -147,7 +161,7 @@ def run(args) -> int:
"seconds": round(seconds, 1),
"note": "zero-shot: no examples, no thresholds; question fixed before any answer was seen",
}
(out / "run.json").write_text(json.dumps(meta, indent=2, default=str) + "\n")
write_benchmark_artifact(out / "run.json", "judge-pass-run", meta, replace=True)
print(json.dumps(meta))
return 2 if failures and todo else 0
@@ -203,10 +217,10 @@ def summarize(args) -> int:
"headline": (
f"Judge over prover findings: keeps {tp_kept}/{len(vuln)} true flags, "
f"drops {fa_dropped}/{fa_total} false flags "
f"(recall {rate(tp_kept, 23)*100:.1f}%, FA {(fa_total - fa_dropped) / 460 * 100:.1f}/100)"
f"(recall {rate(tp_kept, 23) * 100:.1f}%, FA {(fa_total - fa_dropped) / 460 * 100:.1f}/100)"
),
}
(out / "summary.json").write_text(json.dumps(summary, indent=2, default=str) + "\n")
write_benchmark_artifact(out / "summary.json", "judge-pass-summary", summary, replace=True)
print(json.dumps(summary, indent=2, default=str))
return 0
+3 -2
View File
@@ -7,6 +7,7 @@ import json
from pathlib import Path
from benchmarks.unseen import score
from benchmarks.valid.artifact_contract import read_benchmark_artifact, write_benchmark_artifact
def demonstrated(proof: dict) -> bool:
@@ -104,10 +105,10 @@ def main(argv=None):
args = parser.parse_args(argv)
result = summarize(
score.load_records(args.records),
scored=json.loads(args.scored.read_text()) if args.scored else None,
scored=read_benchmark_artifact(args.scored, "unseen-score") if args.scored else None,
proofs=json.loads(args.proofs.read_text()) if args.proofs else [],
)
args.out.write_text(json.dumps(result, sort_keys=True, indent=2) + "\n")
write_benchmark_artifact(args.out, "valid-benchmark-metrics", result, replace=True)
print(result["headline"])
return 0
+4 -20
View File
@@ -1,23 +1,7 @@
"""Admission manifest consumption for the access-control prover arm.
"""Retired benchmark v1 admission seam.
Task 12.5 of the access-control-prover specification (Reqs 12.1, 12.2, 12.3,
12.6, 12.8). The admission runner only CONSUMES manifests that valid-detection-benchmark
produces and reviews; it never produces, mutates or re-labels one.
Since detection-core task 4.1 this module is a thin compatibility wrapper: the
generalized, family-agnostic contract lives in ``openultrasast.core.admission``.
Live admission is exclusively ``admission_run.run_v2_admission``. Historical
v1 bytes remain readable only through ``openultrasast.core.legacy``.
"""
from openultrasast.core.admission import (
REPORT_SCHEMA_KEYS,
AdmissionManifest,
AdmissionManifestError,
validate_admission_manifest,
)
__all__ = [
"REPORT_SCHEMA_KEYS",
"AdmissionManifest",
"AdmissionManifestError",
"validate_admission_manifest",
]
__all__: list[str] = []
+81 -57
View File
@@ -16,16 +16,23 @@ from benchmarks.unseen import score
from benchmarks.unseen.extract import SHA, InstrumentFailure
from benchmarks.unseen.replay import canonical, load_slice
from benchmarks.valid import metrics
from benchmarks.valid.artifact_contract import (
read_benchmark_artifact,
read_benchmark_sequence,
write_benchmark_artifact,
write_benchmark_sequence,
)
from benchmarks.valid.catalog import local_git
from openultrasast.hunt.producers import Context, _Absent, _safe_path
from openultrasast.hunt.prover import prove_change
def _write_json(path, value):
path.parent.mkdir(parents=True, exist_ok=True)
temporary = path.with_suffix(".json.tmp")
temporary.write_text(json.dumps(value, sort_keys=True, indent=2) + "\n")
temporary.replace(path)
def _write_json(path, value, *, kind=None, replace=False):
kind = kind or ("benchmark-arm-inputs" if Path(path).name == "inputs.json" else "benchmark-arm-record")
if isinstance(value, list):
write_benchmark_sequence(path, kind, value, replace=replace)
else:
write_benchmark_artifact(path, kind, value, replace=replace)
def _record_path(out, identity):
@@ -144,7 +151,7 @@ def run(manifest, repos_path, out, *, slice_id="1", only="all", max_depth=3):
raise ValueError("duplicate change ids")
changes = [change for change in changes if only == "all" or change["kind"] == only]
index = out / "inputs.json"
entries = json.loads(index.read_text()) if index.exists() else []
entries = list(read_benchmark_sequence(index, "benchmark-arm-inputs")) if index.exists() else []
if len({entry["item_id"] for entry in entries}) != len(entries):
raise ValueError("duplicate inputs")
indexed = {entry["item_id"]: entry for entry in entries}
@@ -158,14 +165,14 @@ def run(manifest, repos_path, out, *, slice_id="1", only="all", max_depth=3):
if not previous_entry:
entries.append(entry)
path = _record_path(out, change["id"])
previous = json.loads(path.read_text()) if path.exists() else {}
previous = read_benchmark_artifact(path, "benchmark-arm-record") if path.exists() else {}
if previous and previous.get("input_digest") != digest:
raise ValueError("existing prover inputs do not match")
if previous.get("done"):
print(f"{change['id']}: skipped (done)", flush=True)
else:
pending.append(entry)
_write_json(index, entries)
_write_json(index, entries, kind="benchmark-arm-inputs", replace=True)
repos = json.loads(repos_path.read_text())
failed = False
for entry in pending:
@@ -176,84 +183,101 @@ def run(manifest, repos_path, out, *, slice_id="1", only="all", max_depth=3):
return 2 if failed else 0
def summarize(out, *, seed=0):
out = Path(out)
records = score.load_records(out)
def _summary_records(out):
records = score.load_records(Path(out))
if not records or len({row["id"] for row in records}) != len(records):
raise ValueError("missing or duplicate prover records")
for record in records:
instrument = record.get("instrument", {})
if any(size == 0 for field in ("changed_bytes", "file_bytes") for size in instrument.get(field, {}).values()):
raise ValueError("zero-byte read of a tracked file; summary refused")
result = metrics.summarize(records, seed=seed)
usable = [row for row in records if score.coverage(row) != "instrument_failure"]
locations = [
return records
def _target_locations(usable):
return [
bool(score.catches({**row, **target, "files": [{"path": target["path"], "head_lines": [target["function_lines"]]}]}))
for row in usable
if row["kind"] == "vulnerability"
for target in row.get("targets") or [row]
]
repositories = {}
framework_rows = {}
def _coverage_slot():
fields = ("entry_points", "reached", "unreached", "operations_checked", "operations_discharged")
return {
**dict.fromkeys(fields, 0),
"files_by_language": Counter(),
"frameworks_recognised": Counter(),
"unchecked_by_reason": Counter(),
"changes": 0,
}
def _add_coverage(target, coverage, fields):
target["changes"] += 1
for field in fields:
target[field] += coverage.get(field, 0)
for field in ("files_by_language", "frameworks_recognised", "unchecked_by_reason"):
if field in target:
target[field].update(coverage.get(field, {}))
def _coverage_tables(records):
fields = ("entry_points", "reached", "unreached", "operations_checked", "operations_discharged")
repositories, framework_rows = {}, {}
for row in records:
cov = row.get("coverage", {})
repository = repositories.setdefault(
row["repo"],
{
**dict.fromkeys(fields, 0),
"files_by_language": Counter(),
"frameworks_recognised": Counter(),
"unchecked_by_reason": Counter(),
"changes": 0,
},
)
repository["changes"] += 1
for field in fields:
repository[field] += cov.get(field, 0)
for field in ("files_by_language", "frameworks_recognised", "unchecked_by_reason"):
repository[field].update(cov.get(field, {}))
for framework, count in cov.get("frameworks_recognised", {}).items():
coverage = row.get("coverage", {})
_add_coverage(repositories.setdefault(row["repo"], _coverage_slot()), coverage, fields)
for framework, count in coverage.get("frameworks_recognised", {}).items():
table = framework_rows.setdefault(
framework, {"files": 0, "changes": 0, **dict.fromkeys(fields, 0), "unchecked_by_reason": Counter()}
)
table["files"] += count
table["changes"] += 1
for field in fields:
table[field] += cov.get(field, 0)
table["unchecked_by_reason"].update(cov.get("unchecked_by_reason", {}))
uncovered = sorted(repo for repo, cov in repositories.items() if not cov["frameworks_recognised"])
for repo, cov in repositories.items():
cov["status"] = "uncovered" if repo in uncovered else "covered"
_add_coverage(table, coverage, fields)
return repositories, framework_rows
def _annotate_repositories(repositories, usable):
uncovered = sorted(repo for repo, coverage in repositories.items() if not coverage["frameworks_recognised"])
for repo, coverage in repositories.items():
coverage["status"] = "uncovered" if repo in uncovered else "covered"
positives = [row for row in usable if row["repo"] == repo and row["kind"] == "vulnerability"]
cov["recall"] = score.rate([bool(score.catches(row)) for row in metrics.scoring_records(positives)])
coverage["recall"] = score.rate([bool(score.catches(row)) for row in metrics.scoring_records(positives)])
return uncovered
def _scope_recall(usable, uncovered, *, include_uncovered):
values = [
bool(score.catches(row))
for row in metrics.scoring_records(usable)
if row["kind"] == "vulnerability" and ((row["repo"] in uncovered) is include_uncovered)
]
return score.rate(values)
def summarize(out, *, seed=0):
out = Path(out)
records = _summary_records(out)
result = metrics.summarize(records, seed=seed)
usable = [row for row in records if score.coverage(row) != "instrument_failure"]
repositories, framework_rows = _coverage_tables(records)
uncovered = _annotate_repositories(repositories, usable)
seconds = [row["seconds"] for row in records]
result.update(
location_recall=score.rate(locations),
location_recall=score.rate(_target_locations(usable)),
per_repository=repositories,
per_framework=framework_rows,
uncovered_repositories=uncovered,
covered_recall=score.rate(
[
bool(score.catches(row))
for row in metrics.scoring_records(usable)
if row["kind"] == "vulnerability" and row["repo"] not in uncovered
]
),
uncovered_recall=score.rate(
[
bool(score.catches(row))
for row in metrics.scoring_records(usable)
if row["kind"] == "vulnerability" and row["repo"] in uncovered
]
),
covered_recall=_scope_recall(usable, uncovered, include_uncovered=False),
uncovered_recall=_scope_recall(usable, uncovered, include_uncovered=True),
instrument_failures=sum(score.coverage(row) == "instrument_failure" for row in records),
seconds_per_change=dict(n=len(seconds), mean=statistics.mean(seconds), median=statistics.median(seconds), maximum=max(seconds)),
changes_over_120_seconds=[{"id": row["id"], "seconds": row["seconds"]} for row in records if row["seconds"] > 120],
)
# This is a training pool; the generic metric headline refers to unseen repositories.
result["headline"] = result["headline"].replace("On unseen app repos:", "On the training pool:")
_write_json(out / "summary.json", result)
_write_json(out / "summary.json", result, kind="benchmark-arm-summary", replace=True)
return result
+15 -8
View File
@@ -35,6 +35,12 @@ if __package__ in {None, ""}:
from benchmarks.unseen.extract import SHA, InstrumentFailure
from benchmarks.unseen.replay import canonical, load_slice
from benchmarks.valid.artifact_contract import (
read_benchmark_artifact,
read_benchmark_sequence,
write_benchmark_artifact,
write_benchmark_sequence,
)
from benchmarks.valid.catalog import local_git
# Our language ids to Semgrep's. Groovy has no Semgrep parser: `generic` plus a path filter.
@@ -427,11 +433,12 @@ def result_defect(result):
}
def _write_json(path, value):
path.parent.mkdir(parents=True, exist_ok=True)
temporary = path.with_suffix(".json.tmp")
temporary.write_text(json.dumps(value, sort_keys=True, indent=2) + "\n")
temporary.replace(path)
def _write_json(path, value, *, kind=None, replace=False):
kind = kind or ("benchmark-arm-inputs" if Path(path).name == "inputs.json" else "benchmark-arm-record")
if isinstance(value, list):
write_benchmark_sequence(path, kind, value, replace=replace)
else:
write_benchmark_artifact(path, kind, value, replace=replace)
def _record_path(out, identity):
@@ -440,7 +447,7 @@ def _record_path(out, identity):
def _inputs(out):
path = out / "inputs.json"
entries = json.loads(path.read_text()) if path.exists() else []
entries = list(read_benchmark_sequence(path, "benchmark-arm-inputs")) if path.exists() else []
for key in (lambda entry: entry["item_id"], lambda entry: entry["change"]["id"]):
if len({key(entry) for entry in entries}) != len(entries):
raise ValueError(f"duplicate ids in {path}")
@@ -568,7 +575,7 @@ def run(manifest, repos_path, rules, out, *, slice_id="1", only="all", semgrep=N
pending = []
for change in changes:
path = _record_path(out, change["id"])
previous = json.loads(path.read_text()) if path.exists() else {}
previous = read_benchmark_artifact(path, "benchmark-arm-record") if path.exists() else {}
entry = indexed.get(change["id"])
if entry is None:
entry = {
@@ -583,7 +590,7 @@ def run(manifest, repos_path, rules, out, *, slice_id="1", only="all", semgrep=N
print(f"{change['id']}: skipped (done)", flush=True)
continue
pending.append(entry)
_write_json(out / "inputs.json", entries)
_write_json(out / "inputs.json", entries, kind="benchmark-arm-inputs", replace=True)
if not pending:
return 0
repos = json.loads(Path(repos_path).expanduser().read_text())