tools (volt): verify.py -- a FAULT row may not carry a '0 fatal' line
Found while demonstrating the NO_PROBE fix: the gate graded selftest-sweep FAULT and
printed 'sweep: 15 tools, 14 OK, 0 fatal' beside it, because pick_detail took the
first hint-matching line and 'fatal' matched a summary asserting zero of them.
- pick_detail: zero-count summaries (' 0 fatal' / ' 0 fault') are second-pass only,
so a clean run keeps its sweep line and a red run names the red axis
- selftest 24 -> 26 cells: c13 a zero-fault summary is not a reason line,
c13b a clean run still gets its sweep line; both advertised counts updated
This commit is contained in:
1 parent
38b8a81678
commit
b9751c87fa
1 file changed
+30
-6
+30
-6
@@ -58,7 +58,7 @@ TOOLS ARE RESOLVED FROM --repo, NOT FROM THIS FILE'S DIRECTORY
|
||||
docs/queue-index.md) because `queue_append_audit` reads them with
|
||||
`git show <rev>:<path>`, which has no absolute-path form.
|
||||
|
||||
`--selftest` fixture corpus, 24 cells
|
||||
`--selftest` fixture corpus, 26 cells
|
||||
"""
|
||||
|
||||
import argparse
|
||||
@@ -92,11 +92,23 @@ HINTS = ("STALE:", "FAIL", "FAILED", "fatal", "cannot", "TIMEOUT", "NO_",
|
||||
|
||||
|
||||
def pick_detail(text, limit=150):
|
||||
"""First line that names a reason, else the last line that says anything."""
|
||||
"""First line that names a reason, else the last line that says anything.
|
||||
|
||||
A summary line that reports ZERO faults is not a reason: `selftest_sweep`
|
||||
prints `sweep: 15 tools, 15 OK, 0 fatal` even on the run where its input
|
||||
axes went red, and that line was being carried onto a FAULT row -- the row
|
||||
said FAULT beside the words "0 fatal". Zero-count summaries are therefore
|
||||
only reachable on the second pass (a clean run still gets its sweep line),
|
||||
and any line that names a real reason outranks them.
|
||||
"""
|
||||
lines = [ln.strip() for ln in text.splitlines() if ln.strip()]
|
||||
for ln in lines:
|
||||
if any(h in ln for h in HINTS):
|
||||
return ln[:limit]
|
||||
hinted = [ln for ln in lines if any(h in ln for h in HINTS)]
|
||||
reasons = [ln for ln in hinted
|
||||
if " 0 fatal" not in ln and " 0 fault" not in ln]
|
||||
if reasons:
|
||||
return reasons[0][:limit]
|
||||
if hinted:
|
||||
return hinted[0][:limit]
|
||||
return lines[-1][:limit] if lines else ""
|
||||
|
||||
|
||||
@@ -219,7 +231,7 @@ def main(argv=None):
|
||||
help="per-leg timeout in seconds (default 300)")
|
||||
ap.add_argument("--json", metavar="PATH", help="write the rows here")
|
||||
ap.add_argument("--quiet", action="store_true")
|
||||
ap.add_argument("--selftest", action="store_true", help="fixture corpus, 24 cells")
|
||||
ap.add_argument("--selftest", action="store_true", help="fixture corpus, 26 cells")
|
||||
a = ap.parse_args(argv)
|
||||
|
||||
if a.selftest:
|
||||
@@ -414,6 +426,18 @@ def selftest():
|
||||
check("12b and the skipped leg is not counted as a pass",
|
||||
obj.get("counts", {}).get(PASS), 2)
|
||||
|
||||
# 13. the detail line must not contradict the verdict: a row graded
|
||||
# FAULT beside "0 fatal" is the SILENT failure this gate exists to catch.
|
||||
check("13 a zero-fault summary is not a reason line",
|
||||
pick_detail("sweep: 15 tools, 15 OK, 0 fatal\n"
|
||||
"read-refusal: 20 probes, 19 ok, 1 fault (NO_PROBE)\n"
|
||||
"malformed-input: 18 probes, 17 ok, 1 fault (NO_PROBE)\n"),
|
||||
"read-refusal: 20 probes, 19 ok, 1 fault (NO_PROBE)")
|
||||
check("13b a clean run still gets its sweep line",
|
||||
pick_detail("sweep: 14 tools, 14 OK, 0 fatal\n"
|
||||
"read-refusal: 19 probes, 19 ok, 0 fault\n"),
|
||||
"sweep: 14 tools, 14 OK, 0 fatal")
|
||||
|
||||
print("selftest: %d cells, %d passed, %d failed" % (cells, passed, len(failures)))
|
||||
for f in failures:
|
||||
print(" FAIL %s" % f)
|
||||
|
||||
Reference in new issue
Block a user