benchmarksPublic
benchmarksPublic
Commit 76308956
M
scripts/oakbench/conformance_gate.py
@@ -26,7 +26,14 @@
2626
measured behaviours are UNMEASURED. publish_gate additionally requires a2727
recorded profile;2828
- harness errors, reader-unmeasured legs and required behaviours with no row29-
make the result UNMEASURED.29+
make the result UNMEASURED;30+
- error patterns must be specific: the loader rejects any pattern that matches31+
the empty string, matches a nonsense/generic sentinel string (``panicked``,32+
``corrupt``, random text ...) or contains no literal character at all33+
(only wildcards/classes), because such a pattern would hide any error34+
under the expected failure;35+
- ``pending:`` tickets are listed in every summary; publish_gate refuses any36+
entry that still carries one (devloop only notes them).3037
3138
Only the gated subject (Oak) is judged; Git rows are the reference arm.3239
"""@@ -34,8 +41,15 @@
3441
3542
import json3643
from pathlib import Path44+
import random3745
import re46+
import string3847
48+
try: # Python >= 3.1149+
import re._parser as _sre_parse # type: ignore[import-not-found]50+
except ImportError: # pragma: no cover - Python < 3.1151+
import sre_parse as _sre_parse # type: ignore[no-redef]52+
3953
ROOT = Path(__file__).resolve().parents[2]4054
EXPECTED_FAILURES = ROOT / "config" / "conformance_expected_failures.json"4155
SCHEMA_VERSION = 2@@ -52,6 +66,75 @@
5266
"non_utf8_names"})5367
5468
69+
# A legitimate expected-failure pattern pins one concrete error; it must match70+
# none of these. They cover generic failure words (so "panicked"/"corrupt"71+
# cannot hide under an xfail), the kind of text a catch-all pattern swallows,72+
# and deterministic random noise.73+
_rng = random.Random(0x0A4B)74+
SENTINELS = ("", " ", "\n", "x", "panicked", "corrupt", "error", "failed", "zzz-sentinel",75+
"thread 'main' panicked at src/main.rs:1:1", "database disk image is malformed",76+
"internal error", "HTTP 500 Internal Server Error", "Segmentation fault: 11",77+
"zzz-sentinel: no such behaviour exited 99",78+
*("".join(_rng.choice(string.ascii_letters + string.digits + string.punctuation + " ")79+
for _ in range(_rng.randint(1, 60))) for _ in range(24)))80+
del _rng81+
# Subject-shaped sentinels: real conformance leg details look like82+
# "oak <cmd> exited N: error: ..." (legacy: "command (...) failed (N): b'...'"),83+
# so a pattern like `oak .* exited \d+: .*` or `.*error: .*` would swallow a panic,84+
# a corrupt store or a server 500 in that exact shape. None may match.85+
_BAD_ERRORS = ("thread 'main' panicked at src/main.rs:1:1", "error: corrupt object 0123abcd",86+
"error: Database error: database disk image is malformed",87+
"error: Server error: HTTP 500 Internal Server Error: internal error",88+
"error: Database error: unable to open database file", "fatal: bad object HEAD")89+
_COMMANDS = ("oak commit --no-verify", "oak push --repo", "oak clone conformance/r1-2", "oak pull", "oak status",90+
"git commit -q", "git push -q", "git clone -q", "git pull -q")91+
SUBJECT_SENTINELS = tuple(92+
[f"{cmd} exited {rc}: {err}" for cmd in _COMMANDS for rc in (1, 2, 6, 101, 128) for err in _BAD_ERRORS]93+
+ [f"command ('commit', '--no-verify') failed ({rc}): b\"{err}\\n\"" for rc in (1, 2, 101)94+
for err in _BAD_ERRORS]95+
+ [f"command ('commit', '--no-verify') failed ({rc}): b'{err}\\n'" for rc in (1, 2, 101)96+
for err in _BAD_ERRORS if "'" not in err]97+
+ [err for err in _BAD_ERRORS] + [f"oak: {err}" for err in _BAD_ERRORS])98+
SENTINELS = SENTINELS + SUBJECT_SENTINELS99+
del _BAD_ERRORS, _COMMANDS100+
101+
102+
def _has_literal(parsed) -> bool:103+
"""True if the parsed regex contains a literal character outside a character class."""104+
for op, arg in parsed:105+
name = str(op)106+
if name == "LITERAL":107+
return True108+
if name in ("NOT_LITERAL", "IN", "ANY", "AT", "CATEGORY", "GROUPREF", "GROUPREF_EXISTS"):109+
continue110+
if name == "SUBPATTERN":111+
if _has_literal(arg[-1]):112+
return True113+
elif name in ("MAX_REPEAT", "MIN_REPEAT", "POSSESSIVE_REPEAT"):114+
low, _high, sub = arg115+
if low > 0 and _has_literal(sub):116+
return True117+
elif name == "BRANCH":118+
# every alternative must carry a literal for the branch to count119+
if all(_has_literal(alt) for alt in arg[1]):120+
return True121+
elif name == "ATOMIC_GROUP":122+
if _has_literal(arg):123+
return True124+
return False125+
126+
127+
def pattern_too_broad(pattern: str) -> str | None:128+
"""Why an expected-failure error pattern is a catch-all, or None if it is specific."""129+
compiled = re.compile(pattern, re.S)130+
for sentinel in SENTINELS:131+
if compiled.fullmatch(sentinel):132+
return f"matches the sentinel {sentinel!r}"133+
if not _has_literal(_sre_parse.parse(pattern, re.S)):134+
return "has no required literal text (wildcards/classes only)"135+
return None136+
137+
55138
def fs_dependent_skip_allowed(behaviour: str) -> bool:56139
from oakbench.conformance_matrix import BY_ID57140
spec = BY_ID.get(behaviour)@@ -78,6 +161,13 @@
78161
for leg, pattern in legs.items():79162
if not isinstance(pattern, str) or not pattern:80163
raise ValueError(f"conformance expected-failures: {behaviour}/{leg} needs an error pattern")164+
try:165+
broad = pattern_too_broad(pattern)166+
except re.error as exc:167+
raise ValueError(f"conformance expected-failures: {behaviour}/{leg} pattern invalid: {exc}")168+
if broad:169+
raise ValueError(f"conformance expected-failures: {behaviour}/{leg} pattern {pattern!r} is a "170+
f"catch-all ({broad}); pin the concrete error")81171
compiled[leg] = re.compile(pattern, re.S)82172
profiles = entry.get("fs_profiles")83173
if profiles is not None and (not isinstance(profiles, list) or not profiles):@@ -89,6 +179,12 @@
89179
return {"subject": data.get("subject", "oak"), "entries": entries, "coverage": coverage}90180
91181
182+
def pending_tickets(expected: dict) -> list:183+
"""[(behaviour, ticket, outcome)] for entries whose ticket is still pending:<slug>."""184+
return sorted((behaviour, entry["ticket"], entry["outcome"]) for behaviour, entry in expected["entries"].items()185+
if str(entry["ticket"]).startswith("pending:"))186+
187+
92188
def row_failed_legs(row: dict) -> dict:93189
"""{failed leg: detail} for a failing row (legacy rows: {'behaviour': failure})."""94190
legs = row.get("legs")
M
scripts/publish_gate.py
Loading diff…
M
suites/merge/README.md
Loading diff…
M
suites/merge/mergesuite/classify.py
Loading diff…
M
suites/merge/mergesuite/runner.py
Loading diff…
M
suites/merge/run_merge_suite.py
Loading diff…
M
suites/robustness/README.md
Loading diff…
M
suites/robustness/robustness/__init__.py
Loading diff…
M
suites/robustness/robustness/adapters.py
Loading diff…
M
suites/robustness/robustness/engine.py
Loading diff…
M
suites/robustness/robustness/envfaults.py
Loading diff…
M
suites/robustness/run_robustness.py
Loading diff…
M
tests/test_conformance_gate.py
Loading diff…
M
tests/test_merge_suite.py
Loading diff…
M
tests/test_robustness_invariants.py
Loading diff…