137 lines
5.6 KiB
Bash
137 lines
5.6 KiB
Bash
#!/usr/bin/env bash
|
|
# CHECK-q148 -- the baseline re-take tool, and the re-take it performed.
|
|
#
|
|
# Q148 (2026-11-01): `check_entry_baseline.tsv` fails in the direction nobody
|
|
# automates -- a row whose entry point has since been repaired reads IMPROVED in
|
|
# the sweep, and the row is re-taken by hand (Q145, Q146, Q147 each did it once).
|
|
# `wizard-work/volt/q143-check-sweep/retake.py` measures named rows with the
|
|
# sweep's own `run_entry`/`classify`, reports the codes that moved, and rewrites
|
|
# only those rows behind `--write`, with a provenance comment.
|
|
#
|
|
# leg 1 the tool's 12-cell selftest
|
|
# leg 2 two rows the sweep recorded green still read green from the tool
|
|
# leg 3 a copy of the baseline with one row's code moved is named, written
|
|
# back, and reads clean on a second take (the tool's own contract)
|
|
# leg 4 the baseline on disk carries this tick's provenance block and still
|
|
# parses under the sweep's own reader
|
|
# leg 5 no row in the baseline names evidence the tree does not have
|
|
# (the MISSING direction; the NEW direction is another lane's row)
|
|
#
|
|
# rc 0 all legs pass, rc 1 a leg faulted, rc 2 could not grade.
|
|
set -u
|
|
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" || { echo "CANNOT GRADE: no directory"; exit 2; }
|
|
ROOT="$(git -C "$HERE" rev-parse --show-toplevel 2>/dev/null)" || { echo "CANNOT GRADE: not a git repository"; exit 2; }
|
|
SWEEP="$ROOT/wizard-work/volt/q143-check-sweep"
|
|
TOOL="$SWEEP/retake.py"
|
|
BASE="$SWEEP/check_entry_baseline.tsv"
|
|
for f in "$TOOL" "$BASE" "$SWEEP/check_sweep.py"; do
|
|
[ -f "$f" ] || { echo "CANNOT GRADE: missing $f"; exit 2; }
|
|
done
|
|
PY="${PYTHON:-python3}"
|
|
WORK="$(mktemp -d "${TMPDIR:-/tmp}/q148.XXXXXX")" || exit 2
|
|
trap 'rm -rf "$WORK"' EXIT
|
|
|
|
# The baseline is a shared file: other ticks re-take rows in it, and a re-take is
|
|
# an atomic whole-file replace. Leg 3 grades the TOOL by mutating a copy and
|
|
# asking it to name the move, so it compares against a snapshot taken here, not
|
|
# against $BASE at compare time -- otherwise a lane that re-took a row between
|
|
# the copy and the compare reads as this tool writing the wrong row (measured:
|
|
# 2026-11-01 11:57Z and 12:14Z, FAIL beside a green tool selftest).
|
|
SNAP="$WORK/base.orig.tsv"
|
|
cp "$BASE" "$SNAP" 2>/dev/null && [ -s "$SNAP" ] \
|
|
|| { echo "CANNOT GRADE: cannot snapshot $BASE"; exit 2; }
|
|
|
|
faults=0
|
|
pass() { echo "PASS $1"; }
|
|
fail() { echo "FAIL $1"; faults=$((faults+1)); }
|
|
|
|
# leg 1
|
|
if out="$("$PY" "$TOOL" --selftest 2>&1)"; then
|
|
pass "selftest $(printf '%s' "$out" | tail -1 | sed 's/selftest: //')"
|
|
else
|
|
fail "selftest"; printf '%s\n' "$out" | tail -4
|
|
fi
|
|
|
|
# leg 2 -- two green rows, measured again
|
|
if out="$("$PY" "$TOOL" --repo "$ROOT" --path CHECK-q147 --path CHECK-q146 2>&1)"; then
|
|
pass "green-rows $(printf '%s' "$out" | tail -1 | sed 's/retake: //')"
|
|
else
|
|
fail "green-rows rc=$?"; printf '%s\n' "$out" | grep '^MOVED' | head -3
|
|
fi
|
|
|
|
# leg 3 -- the mutation: one row's code moved, named, written, re-read clean.
|
|
# The mutation is applied to the snapshot, so what is compared at the end is
|
|
# "the tool's rewrite vs the file it was handed".
|
|
"$PY" - "$SNAP" "$WORK/base.tsv" <<'PY'
|
|
import sys
|
|
src, dst = sys.argv[1], sys.argv[2]
|
|
lines = open(src, encoding="utf-8").read().split("\n")
|
|
out = []
|
|
for line in lines:
|
|
parts = line.split("\t")
|
|
if parts[0] == "CHECK-q147" and len(parts) > 2:
|
|
parts[1] = "1"
|
|
line = "\t".join(parts)
|
|
out.append(line)
|
|
open(dst, "w", encoding="utf-8", newline="\n").write("\n".join(out))
|
|
PY
|
|
out="$("$PY" "$TOOL" --baseline "$WORK/base.tsv" --repo "$ROOT" --path CHECK-q147 2>&1)"; rc=$?
|
|
if [ "$rc" -eq 1 ] && printf '%s' "$out" | grep -q '^MOVED CHECK-q147 1 -> 0'; then
|
|
wout="$("$PY" "$TOOL" --baseline "$WORK/base.tsv" --repo "$ROOT" --path CHECK-q147 --write 2>&1)"; wrc=$?
|
|
if [ "$wrc" -eq 0 ] && "$PY" "$TOOL" --baseline "$WORK/base.tsv" --repo "$ROOT" --path CHECK-q147 >/dev/null 2>&1; then
|
|
if "$PY" - "$SNAP" "$WORK/base.tsv" <<'PY'
|
|
import sys
|
|
def rows(p):
|
|
out = {}
|
|
for line in open(p, encoding="utf-8"):
|
|
if line.startswith("#") or not line.strip():
|
|
continue
|
|
parts = line.rstrip("\n").split("\t")
|
|
out[parts[0]] = (parts[1], parts[2] if len(parts) > 2 else "")
|
|
return out
|
|
a, b = rows(sys.argv[1]), rows(sys.argv[2])
|
|
bad = ["%s %s!=%s" % (k, a[k], b[k]) for k in a if a.get(k) != b.get(k)]
|
|
print("data rows: %d compared, %d differ" % (len(a), len(bad)))
|
|
sys.exit(1 if bad else 0)
|
|
PY
|
|
then
|
|
pass "mutation named, written, re-read clean, other rows identical"
|
|
else
|
|
fail "mutation reintroduced a difference in another row"
|
|
fi
|
|
else
|
|
fail "mutation write rc=$wrc or second take still moved"
|
|
fi
|
|
else
|
|
fail "mutation not named (rc=$rc)"; printf '%s\n' "$out" | tail -2
|
|
fi
|
|
|
|
# leg 4 -- the on-disk baseline carries this tick's provenance and still parses
|
|
if grep -q '^# row-level re-take (q148 via retake.py' "$BASE" \
|
|
&& "$PY" - "$BASE" <<'PY'
|
|
import sys
|
|
sys.path.insert(0, sys.argv[1].rsplit("/", 1)[0])
|
|
import check_sweep
|
|
rev, rows = check_sweep.read_baseline(sys.argv[1])
|
|
print("baseline parses: %d row(s), rev %s" % (len(rows), rev))
|
|
sys.exit(0 if rows and rev else 1)
|
|
PY
|
|
then
|
|
pass "provenance block present, baseline parses"
|
|
else
|
|
fail "provenance block missing or baseline does not parse"
|
|
fi
|
|
|
|
# leg 5 -- no MISSING row (evidence the baseline names and the tree lacks)
|
|
out="$("$PY" "$SWEEP/check_sweep.py" --repo "$ROOT" --paths 2>&1)"
|
|
if printf '%s' "$out" | grep -q '^FAIL: MISSING'; then
|
|
fail "baseline names a path the tree lacks"
|
|
printf '%s\n' "$out" | grep '^FAIL: MISSING' | head -3
|
|
else
|
|
pass "no MISSING row ($(printf '%s' "$out" | tail -1 | sed 's/paths: //'))"
|
|
fi
|
|
|
|
echo "q148: $((5-faults)) of 5 leg(s) passed"
|
|
[ "$faults" -eq 0 ] || exit 1
|
|
exit 0
|