Files

98 lines
8.2 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# delever_cycle.sh — the Phase-36 batch cycle, mechanised (T3/T4). For each batch k in [START..END]:
# 1. the tree must be clean (src/ + config/); the oracle's calibration is refreshed (2–3 s: it is keyed to HEAD, every commit stales it);
# 2. `delever.py --apply --batch N --label <mode>k` judges every drawable body of the next N files and leaves the winning texts in place
# (the census is regenerated by the tool when its src stamp is stale); the tool's exit code and its `final X/X identical` are read (R97/R66);
# 3. the outer gate: the CLEAN fleet run (make clean && extract-all && check-all -> `218 passed, 0 failed of 218`, R22) — it also refreshes
# build/, the oracle's baseline objects;
# 4. the census is rerun on the new tree (the commit line quotes it), the phase log gets the batch's entry, the 🛑 headline is refreshed (R101),
# and src/ + the ledger/batch record/log + the census + the phase log are committed (R42).
# Stops on the first red (a non-zero tool exit, a final N/M with N != M, a fleet run that is not 218/218) — the batch's files are then
# still in place: inspect, then `tools/delever.py --restore` (never git checkout, R102). Stops cleanly when nothing is drawable.
# Usage: [LABEL_PREFIX=t3_] [TASK=T4] [REDRAW="REFUSED NOTHING-USABLE"] tools/delever_cycle.sh START END [BATCH=300] [MODE=tus|headers|gte] [ONLY="alias1 alias2 …"]
# RUN IT DETACHED from the Claude Code harness (its low-memory guard kills a long BACKGROUND task — batch tus3 died mid-apply, S98):
# setsid nohup bash -c 'TASK=T4 tools/delever_cycle.sh 3 12 300 tus; echo "cycle exit=$?"' > .run/P36/delever/cycle_<x>.log 2>&1 &
# and watch the log (a tiny waiter: `until grep -q 'cycle exit=' <log>; do sleep 60; done`). A killed batch: `tools/delever.py --restore`.
# FINISH=<label> START END …: a batch whose apply and fleet run were green but whose census/commit step failed (an instrument fault) is
# finished from its own logs — census → log entry → commit — without redoing the work.
# size a call so one batch stays < 10 min: TUs ≈ 8 s each single-threaded / 12 workers; a header ≈ 4 s (serial, includers in parallel).
set -o pipefail
cd "$(dirname "$0")/.." || exit 2
START=$1; END=$2; BATCH=${3:-300}; MODE=${4:-tus}; ONLY=${5:-}
[ -n "$START" ] && [ -n "$END" ] || { echo "usage: $0 START END [BATCH] [tus|headers] [ONLY]"; exit 2; }
case "$MODE" in
tus) HFLAG=""; TOOL="tools/delever.py --apply"; VPAT='delever: batch .*';;
headers) HFLAG="--headers"; TOOL="tools/delever.py --apply"; VPAT='delever: batch .*';;
gte) HFLAG=""; TOOL="tools/gte_consolidate.py --apply"; VPAT='gte_consolidate: batch .*';; # T5: the GTE consolidation per file
*) echo "MODE must be tus, headers or gte"; exit 2;;
esac
ONLYFLAG=""; [ -n "$ONLY" ] && ONLYFLAG="--only $ONLY"
REDRAWFLAG=""; [ -n "${REDRAW:-}" ] && REDRAWFLAG="--redraw $REDRAW" # e.g. REDRAW="REFUSED NOTHING-USABLE" after a tool fix
FLEET=$(ls config/check.*.sha | wc -l)
PY=.venv/bin/python
MARKER='## 🛑 SESSION CHECKPOINT' # the Log section ends at the checkpoint block: entries go right before it
for k in $(seq "$START" "$END"); do
label="${LABEL_PREFIX:-}${MODE}${k}"
log=.run/P36/delever/run_${label}.log
r22=.run/P36/baseline/r22_${label}.log
if [ -n "${FINISH:-}" ]; then
# FINISH=1: the batch's apply and fleet run already ran green (their logs exist) and the cycle stopped after them (a census
# instrument fault, a lost commit): redo only the census → log entry → commit steps, from the same logs
[ "$FINISH" = "$label" ] || { echo "cycle: FINISH=$FINISH does not name batch $label"; exit 2; }
[ -s "$log" ] && [ -s "$r22" ] || { echo "cycle: FINISH=$label — no apply/R22 logs to finish from"; exit 2; }
echo "cycle: finishing batch $label from its logs (census → log entry → commit)"
else
[ -z "$(git status --short -- src config)" ] || { echo "cycle: src/ or config/ is dirty — commit, or tools/delever.py --restore (R42/R102)"; exit 3; }
[ -z "$(git status --short --porcelain src | grep '^??')" ] || { echo "cycle: untracked files under src/ (a dotfile probe?) — sweep them first"; exit 3; }
$PY tools/delever_oracle.py --status >/dev/null 2>&1 || $PY tools/delever_oracle.py --calibrate ov_SC04_011 ov_SC03_015 ov_SC03_014 main -j 16 > .run/P36/delever/calibrate_${label}.log 2>&1 \
|| { echo "cycle: calibration FAILED"; tail -5 .run/P36/delever/calibrate_${label}.log; exit 1; }
{ /usr/bin/time -f "$label wall=%e s" $PY $TOOL --batch "$BATCH" --label "$label" $HFLAG $ONLYFLAG $REDRAWFLAG -j 12; echo "exit=$?"; } > "$log" 2>&1
fi
grep -q '^exit=0$' "$log" || { echo "cycle: batch $label — delever exited non-zero"; tail -4 "$log"; exit 1; }
if grep -qE 'nothing to do' "$log"; then echo "cycle: nothing drawable at $label — done"; exit 0; fi
vline=$(grep -oE "$VPAT" "$log" | tail -1)
[ -n "$vline" ] || { echo "cycle: batch $label — no verify line in $log (R32: an empty line is not a pass)"; tail -3 "$log"; exit 1; }
final=$(echo "$vline" | grep -oE 'final [0-9]+/[0-9]+' | grep -oE '[0-9]+/[0-9]+')
[ -n "$final" ] && [ "${final%/*}" = "${final#*/}" ] || { echo "cycle: batch $label — $vline"; exit 1; }
if [ "$(echo "$vline" | grep -oE 'written [0-9]+' | grep -oE '[0-9]+')" = "0" ]; then echo "cycle: batch $label wrote no file — $vline"; fi
if [ -z "${FINISH:-}" ]; then
{ /usr/bin/time -f "wall=%e s user=%U s sys=%S s" bash -c 'set -o pipefail; make clean && make extract-all JOBS=16 && make check-all JOBS=16'; echo "exit=$?"; } > "$r22" 2>&1
fi
line=$(grep -oE "check-all: [0-9]+ passed, [0-9]+ failed of [0-9]+" "$r22")
if ! grep -q '^exit=0$' "$r22" || [ "$line" != "check-all: $FLEET passed, 0 failed of $FLEET" ]; then echo "cycle: R22 RED after batch $label — $line (the batch's files are in place: inspect, then tools/delever.py --restore)"; exit 1; fi
$PY tools/lever_census.py --sites -j 16 > .run/P36/census/census_${label}.log 2>&1 || { echo "cycle: the census FAILED after batch $label"; tail -3 .run/P36/census/census_${label}.log; exit 1; }
cline=$(grep -oE "THE PHASE'S NUMBER.*" .run/P36/census/lever_census.txt | head -1)
[ -n "$cline" ] || { echo "cycle: the census table carries no PHASE'S NUMBER line after batch $label"; exit 1; }
TASK=${TASK:-T4} $PY - "$label" "$vline" "$line" "$cline" "$(grep -oE 'wall=[0-9.]+ s' "$r22" | head -1)" "$MARKER" <<'EOF' || exit 1
import os, pathlib, re, sys, time, subprocess
label, vline, r22line, cline, wall, marker = sys.argv[1:7]
task = os.environ.get("TASK", "T4")
p = pathlib.Path("phase-ends/CURRENT_PHASE.md"); t = p.read_text()
head = subprocess.run(["git", "rev-parse", "--short", "HEAD"], capture_output=True, text=True).stdout.strip()
entry = (f"\n- **{time.strftime('%Y-%m-%d')} — {task} batch `{label}`** (`.run/P36/delever/run_{label}.log`, `batch_{label}.json`): `{vline}` → R22 "
f"(`.run/P36/baseline/r22_{label}.log`) **`{r22line}`** (`{wall}`) → census `{cline}`.")
assert ("\n" + marker) in t, "phase log marker (the checkpoint heading) not found"
t = t.replace("\n" + marker, entry + "\n\n" + marker, 1)
# the 🛑 headline (R101): every task-advancing commit refreshes it
lines = t.split("\n")
for i, l in enumerate(lines):
if l.startswith("## 🛑 SESSION CHECKPOINT"):
base = re.sub(r"\s*\|\s*last batch.*$", "", l)
lines[i] = f"{base} | last batch `{label}` on {head}: {cline}"
break
p.write_text("\n".join(lines))
print("log:", label, cline)
EOF
# the index lock: wait out a transient holder (a harness hook's git status), clear a STALE one (no git process alive) — batch tus2
# lost its commit to a lock created during its own fleet run with no holder left (S98)
for i in 1 2 3 4 5 6; do
[ -e .git/index.lock ] || break
if [ -z "$(ps -eo cmd | grep -E '^git |/git ' | grep -v grep)" ]; then echo "cycle: stale .git/index.lock (no git process) — removed"; rm -f .git/index.lock; break; fi
sleep 10
done
git add -A src && git add .run/P36/delever .run/P36/census .run/P36/baseline phase-ends/CURRENT_PHASE.md || exit 1
git commit -q -m "src(phase-36): ${TASK:-T4} batch $label — $vline | R22 $line | census: $cline (delever_cycle)" || exit 1
echo "cycle: batch $label committed $(git log --oneline -1 | cut -c1-9) — $vline | $line"
done
echo "cycle: batches $START..$END done"