mirror of
https://github.com/saymrwulf/proof-aware-crypto-tooling-agent.git
synced 2026-09-04 20:03:40 +00:00
Operator-found (and root-caused): the v0.11 card replace had silently no-opped on an invisible NBSP in 'vs.\xa0today' — the page said 23 pages and still carried the July-snapshot card one paragraph under the 'New in v0.11' sentence. Fixed by byte-anchored replace with post-assert; a source regression test now forbids the stale markers outright and check-paper.sh binds the page-count claim to pdfinfo. Executability (tested by actually running them): the printed curl had no scheme and returned empty through the redirect -> https form; the zero-install one-liner was missing its cd -> added; 'Standard-library Python only' contradicted the openssl requirement stated 20 lines earlier -> made honest; 'table above' pointed at a table that is below -> below; '~25 lines of Python' vs the 346-line fail-closed verify.py -> 'one-page core (paper Appendix C), shipped verify.py wraps it'. Comprehensibility (fresh-eyes audit, 28 findings triaged): first-use glosses for STH, axiom cones, certificates, pinning, split view, pins.json, trusted base, residual-risk list, R0-R5, signature tiers; Lean 4 linked; Merkle accumulator glossed; operator=provider declared; the ✗-leaves explained as the failed round 1 vs clean re-attest; the flagship self-reference gets a plain lead sentence; TOFU named and bounded; pacta install source at the first pacta command; coined verb 'machine-re-check' uncoined; pitch parenthetical trimmed (SLH detail lives in its own block). Suite 153 green (new: webdocs stale-claim regression test).
84 lines
4.1 KiB
Bash
Executable file
84 lines
4.1 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# check-paper.sh — the paper's form gate.
|
|
#
|
|
# Ports the book's check-book.sh lesson to the paper: the 2026-08-16
|
|
# socratic round found a ghost page (a fossil \clearpage) and a solid-set
|
|
# claim matrix whose badness-10000 warnings had printed in EVERY build,
|
|
# unread. This gate makes both classes of defect fail the build instead
|
|
# of shipping silently. It cannot replace the render-and-look eye pass —
|
|
# it renders the pages so the eye pass has no excuse.
|
|
#
|
|
# Usage: ./check-paper.sh build + all gates + render pages
|
|
# ./check-paper.sh --selftest exercise the gate parsers on
|
|
# known-bad and known-good log lines
|
|
set -euo pipefail
|
|
cd "$(dirname "$0")"
|
|
|
|
OVERFULL_LIMIT_PT=10
|
|
MIN_PAGE_CHARS=300 # calibrated 2026-08-16: real minimum was 922 (claim-matrix page)
|
|
PAGES_DIR=rendered-pages
|
|
|
|
fail() { echo "FAIL: $*" >&2; exit 1; }
|
|
|
|
# --- gate parsers (pure text -> verdict; selftestable) -------------------
|
|
overfull_violations() { # stdin: build log -> lines exceeding the limit
|
|
grep -i 'Overfull \\hbox' | grep -oP '\(\K[0-9.]+(?=pt too wide)' \
|
|
| awk -v lim="$OVERFULL_LIMIT_PT" '$1 > lim' || true
|
|
}
|
|
badness_violations() { # stdin: build log -> badness-10000 underfull lines
|
|
grep -i 'Underfull \\hbox (badness 10000)' || true
|
|
}
|
|
|
|
if [[ "${1:-}" == "--selftest" ]]; then
|
|
n=0
|
|
t() { n=$((n+1)); [[ "$2" == "$3" ]] && echo "selftest $n ok: $1" || fail "selftest $n: $1 (got '$3', want '$2')"; }
|
|
t "80pt overfull trips" "80.05" \
|
|
"$(echo 'warning: x.tex:1: Overfull \hbox (80.05pt too wide) in paragraph' | overfull_violations)"
|
|
t "3.4pt overfull passes" "" \
|
|
"$(echo 'warning: x.tex:1: Overfull \hbox (3.374pt too wide) in paragraph' | overfull_violations)"
|
|
t "badness 10000 trips" "1" \
|
|
"$(echo 'warning: x.tex:1: Underfull \hbox (badness 10000) in paragraph' | badness_violations | wc -l)"
|
|
t "badness 2913 passes" "0" \
|
|
"$(echo 'warning: x.tex:1: Underfull \hbox (badness 2913) in paragraph' | badness_violations | wc -l)"
|
|
echo "selftest: $n/$n ok"; exit 0
|
|
fi
|
|
|
|
# --- 1. build ------------------------------------------------------------
|
|
LOG=$(mktemp); trap 'rm -f "$LOG"' EXIT
|
|
tectonic ltl.tex 2>&1 | tee "$LOG" >/dev/null
|
|
grep -qi '^error' "$LOG" && fail "TeX errors in build log"
|
|
|
|
# --- 2. overfull gate ----------------------------------------------------
|
|
OV=$(overfull_violations <"$LOG")
|
|
[[ -z "$OV" ]] || fail "overfull hbox beyond ${OVERFULL_LIMIT_PT}pt: $OV"
|
|
|
|
# --- 3. loose-typesetting gate (the ignored-warnings class) --------------
|
|
BAD=$(badness_violations <"$LOG" | wc -l)
|
|
[[ "$BAD" -eq 0 ]] || fail "$BAD underfull badness-10000 lines (gappy table/paragraph)"
|
|
|
|
# --- 4. ghost-page gate (the fossil-clearpage class) ---------------------
|
|
NPAGES=$(pdfinfo ltl.pdf | awk '/^Pages:/{print $2}')
|
|
for p in $(seq 1 $((NPAGES-1))); do
|
|
chars=$(pdftotext -f "$p" -l "$p" ltl.pdf - 2>/dev/null | tr -d '[:space:]' | wc -c)
|
|
[[ "$chars" -ge "$MIN_PAGE_CHARS" ]] || fail "page $p is mostly blank ($chars chars) — ghost page"
|
|
done
|
|
|
|
# --- 5. content probes ---------------------------------------------------
|
|
VERSION=$(grep -oP '\\date\{[^}]*---\s*\Kv[0-9.]+' ltl.tex || true)
|
|
[[ -n "$VERSION" ]] || fail "cannot extract version from \\date{...} in ltl.tex"
|
|
pdftotext -f 1 -l 1 ltl.pdf - | grep -q "$VERSION" || fail "title page does not carry $VERSION"
|
|
! pdftotext ltl.pdf - | grep -q '??' || fail "unresolved ?? reference in PDF"
|
|
|
|
# --- 5b. site claim binding: the webdocs paper card's page count ---------
|
|
WEBDOCS=../provider/src/pacta_provider/webdocs.py
|
|
if [[ -f "$WEBDOCS" ]]; then
|
|
STATED=$(grep -oP '\(PDF, \K[0-9]+(?= pages)' "$WEBDOCS" || true)
|
|
[[ -n "$STATED" ]] || fail "webdocs paper card lost its '(PDF, N pages' claim"
|
|
[[ "$STATED" -eq "$NPAGES" ]] || fail "webdocs says $STATED pages, PDF has $NPAGES"
|
|
fi
|
|
|
|
# --- 6. render for the mandatory eye pass --------------------------------
|
|
rm -rf "$PAGES_DIR"; mkdir -p "$PAGES_DIR"
|
|
pdftoppm -png -r 110 ltl.pdf "$PAGES_DIR/p"
|
|
echo "OK: $VERSION, $NPAGES pages, no overfull>${OVERFULL_LIMIT_PT}pt, no badness-10000, no ghost pages, no ?? refs."
|
|
echo "NOW LOOK: the render-and-look law is not automated. Flip every page in $PAGES_DIR/."
|