feat: judge recorded runs again offline

core_probe rejudge appends, for each live record the oracle now judges otherwise, a record with the same runs judged again: verdicts, bios_used and inputs.oracle recomputed, supersedes the earlier one, judged_at and judged_by beside recorded_at. Records of another probe are left to it. The campaign reads a superseded record as its successor, and a file the log shows refused or loaded settles validation with no BIOS screen.
This commit is contained in:
Abdessamad Derraz committed 2026-10-28 05:22:06 +01:00
1 parent 05192f43c7
commit ad7dc0ea17
5 files changed
+166 -8

No files matched your search

+10 -4
View File
@@ -1281,15 +1281,21 @@ class Campaign:
self.settle(unit.emulator, content, core, index, entry, [verdict])
def read_record(self, emulator: str, rid: str | None) -> dict | None:
"""A record by its id, or the record that supersedes it: a run
judged again offline is read as judged last."""
if not rid:
return None
path = self.paths.root / mr.records_path(emulator)
if not path.is_file():
return None
for line in path.read_text(encoding="utf-8").splitlines():
if f'"id":"{rid}"' in line:
return json.loads(line)
return None
records = [json.loads(line) for line in path.read_text(encoding="utf-8").splitlines()]
by_id = {r["id"]: r for r in records}
successor = {r["supersedes"]: r["id"] for r in records if r.get("supersedes")}
seen = set()
while rid in successor and rid not in seen:
seen.add(rid)
rid = successor[rid]
return by_id.get(rid)
def judged(self, emulator: str, rid: str) -> bool:
"""True for a record the boot oracle judged: only those prove a field."""
+13 -4
View File
@@ -25,8 +25,9 @@ name (zeros of its size, its first half, another region's dump).
copies of one file that boot and fail - queued
"Fails" is bios_error, crash or hang. A wrong file is refused when the
core reports a BIOS error, or when it boots without the BIOS screens the
right file shows (it fell back to a built-in BIOS). It is used when it
core reports a BIOS error, when its log says it ran its built-in BIOS
(bios_used builtin), or when it boots without the BIOS screens the right
file shows. It is used when the log names the file it loaded. It is used when it
turns the run into a hang or a crash that the run without any file does not
show. Anything else settles nothing. Of validation, the table writes only a
missing `size`. A contradicted content check goes to review: which hash a
@@ -64,6 +65,7 @@ class Run:
record_id: str
label: str
stages: tuple[str, ...] = ()
bios_used: str = "unknown"
@property
def shows_bios(self) -> bool:
@@ -101,7 +103,8 @@ def run_of(record: dict, label: str) -> Run:
oracle has none, and reads as unknown."""
item = variant(record, label)
evidence = item.get("verdict_evidence") or {}
return Run(item.get("verdict", UNKNOWN), record["id"], label, tuple(evidence.get("stages") or ()))
return Run(item.get("verdict", UNKNOWN), record["id"], label, tuple(evidence.get("stages") or ()),
item.get("bios_used", "unknown"))
def ids(*runs: Run) -> tuple[str, ...]:
@@ -138,8 +141,9 @@ def rule_need(none: Run, present: Run, entry: dict, used: bool = True) -> list[V
if none.verdict == BOOTS and not used:
return []
if none.verdict == BOOTS:
on = " on its built-in BIOS" if none.bios_used == "builtin" else ""
out = [Verdict("boots_without_file", "hle_fallback", True,
f"the core boots the content with no BIOS at all, {name} included",
f"the core boots the content{on} with no BIOS at all, {name} included",
ids(none), True)]
if entry.get("required") is True:
out.append(Verdict(
@@ -167,6 +171,11 @@ def file_use(wrong: Run, none: Run, present: Run) -> str | None:
return None
if wrong.verdict == BIOS_ERROR:
return REFUSED
# The log names the BIOS the core ran: that settles it before any screen.
if wrong.verdict == BOOTS and wrong.bios_used == "builtin":
return REFUSED
if wrong.verdict == BOOTS and wrong.bios_used.startswith("staged:"):
return USED
if wrong.verdict == BOOTS:
if wrong.shows_bios:
return USED
+91
View File
@@ -1110,6 +1110,16 @@ def build_parser() -> argparse.ArgumentParser:
check.add_argument("--claim", required=True, help="the statement under test")
check.add_argument("--method", required=True, help="how the run tests it")
check.add_argument("--repeat", type=int, default=2, help="runs of each variant, each in a fresh process")
rejudge = sub.add_parser("rejudge", help="judge recorded runs again against the current oracle, "
"offline: no core runs")
rejudge.add_argument("--record", metavar="DIR", default=str(ROOT),
help="the checkout whose measurements/ are judged again (default: this one)")
rejudge.add_argument("--emulator", action="append", default=[],
help="only these emulators' records (default: every one)")
rejudge.add_argument("--oracle", default=None, metavar="FILE",
help="the oracle to judge against (default: tests/campaign/oracle.yml)")
rejudge.add_argument("--dry-run", action="store_true",
help="print what would be appended, write nothing")
worker = sub.add_parser("_worker", help="internal: one run in this process, started by the others")
worker.add_argument("spec", help="JSON file describing the run")
worker.add_argument("out", help="JSON file the result is written to")
@@ -1582,8 +1592,89 @@ def _ensure(path: Path) -> Path:
return path
def rejudged(record: dict, data: dict, identity: dict | None, now: str) -> dict | None:
"""The record judged again from its own runs, superseding it, or None
when the judgement it carries is the one the oracle gives now.
Nothing of the runs changes: logs, frames, files and timings are the
record's. The verdicts, their evidence, bios_used and inputs.oracle are
computed again, and judged_at and judged_by say when and by what.
"""
import copy # noqa: PLC0415
# Another probe (standalone_probe, pack_probe) judges with its own rules.
if record.get("record_version", 0) < 4 or record["frontend"].get("script") != "scripts/core_probe.py":
return None
out = copy.deepcopy(record)
content_sha1 = ((out["inputs"].get("content") or {}).get("sha1"))
for variant in out["variants"]:
for rep in variant["repetitions"]:
judge_repetition(rep, oracle_for(data, content_sha1, rep.get("library_name")))
judge_variant(variant)
first = out["variants"][0]["repetitions"][0]
out["inputs"]["oracle"] = ({**identity, **oracle_for(data, content_sha1, first.get("library_name"))}
if identity else None)
if out.get("check"):
out["check"]["result"]["verdicts"] = {v["label"]: v["verdict"] for v in out["variants"]}
def judgement(item: dict) -> list:
return [[v.get("verdict"), v.get("verdict_evidence"), v.get("bios_used"),
[[r.get("verdict"), r.get("verdict_evidence"), r.get("bios_used")] for r in v["repetitions"]]]
for v in item["variants"]]
if record.get("record_version") == RECORD_VERSION_NOW() and judgement(out) == judgement(record):
return None
for key in ("id", "migrated_from_version"):
out.pop(key, None)
out["record_version"] = RECORD_VERSION_NOW()
out["supersedes"] = record["id"]
out["judged_at"] = now
ident = frontend_identity()
out["judged_by"] = {"script": ident["script"], "commit": ident["commit"],
"script_sha256": ident["script_sha256"]}
return out
def RECORD_VERSION_NOW() -> int: # noqa: N802
from measurement_records import RECORD_VERSION # noqa: PLC0415
return RECORD_VERSION
def rejudge_records(args: argparse.Namespace) -> int:
"""Append, for each live record whose judgement the oracle now gives
otherwise, the record judged again, superseding it."""
from measurement_records import line_text, live, read_records, records_path, seal # noqa: PLC0415
root = Path(args.record)
data, identity = load_oracle(Path(args.oracle) if args.oracle else DEFAULT_ORACLE)
now = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat()
stored = read_records(root)
alive = {r["id"] for r in live(s.record for s in stored)}
written = 0
for entry in stored:
if entry.record["id"] not in alive or (args.emulator and entry.emulator not in args.emulator):
continue
new = rejudged(entry.record, data, identity, now)
if new is None:
continue
sealed = seal(new)
before = {v["label"]: v.get("verdict") for v in entry.record["variants"]}
after = {v["label"]: f"{v['verdict']} ({v['bios_used']})" for v in sealed["variants"]}
print(json.dumps({"emulator": entry.emulator, "supersedes": entry.record["id"], "id": sealed["id"],
"before": before, "after": after}))
written += 1
if not args.dry_run:
with (root / records_path(entry.emulator)).open("a", encoding="utf-8") as handle:
handle.write(line_text(sealed) + "\n")
print(f"{written} records judged again" + (" (dry run, nothing written)" if args.dry_run else ""),
file=sys.stderr)
return 0
def main(argv: Sequence[str] | None = None) -> int:
args = build_parser().parse_args(argv)
if args.mode == "rejudge":
return rejudge_records(args)
if args.mode == "_worker":
spec = json.loads(Path(args.spec).read_text(encoding="utf-8"))
Path(args.out).write_text(json.dumps(run_worker(spec)), encoding="utf-8")