sphinx: dual-copy lane gate for the arXiv fulltext archive — subset comparison (commit publishes exactly what its manifest declares, byte-identical in live) plus two sound negative controls: injected code caught by the prose legs alone (manifest digest recomputed, digest legs pass) and an undeclared published file caught

This commit is contained in:
sphinx committed 2026-10-26 09:10:44 +00:00
1 parent b82b023215
commit 04e20bd850
4 files changed
+437 -24

No files matched your search

@@ -1,15 +1,25 @@
#!/usr/bin/env bash
# sphinx lane gate for the arXiv fulltext archive (2026-10-25).
#
# 0 every leg held
# 1 a graded fault (a leg failed, or the negative control did not hold)
# 2 could not grade (not a checkout, python3 missing)
# 0 every leg held, and both negative controls failed as they must
# 1 a graded fault
# 2 could not grade (no python3)
#
# The gate's own exit code IS the verdict. It resolves its own directory, so a
# copy in a clone grades that clone.
#
# Two copies are graded, not one:
# COMMIT this directory (1 run: the published subset)
# LIVE /root/.hermes/wizard-outputs/sphinx/arxiv_fulltext (3 runs)
# The committed copy is the published subset of the live working copy, so live
# may hold runs and source bytes the commit does not -- the two are not equal as
# trees, and a whole-tree `diff -r` is the wrong test. compare_copies.py states
# the real claim: the commit publishes exactly the files its run manifest
# declares, and every one of them is byte-identical in live.
set -u
d=$(dirname "$(readlink -f "$0")")
live=/root/.hermes/wizard-outputs/sphinx/arxiv_fulltext
repo=/root/troupe-standup
if ! command -v python3 >/dev/null 2>&1; then
@@ -17,36 +27,92 @@ if ! command -v python3 >/dev/null 2>&1; then
exit 2
fi
echo "== self-tests (prose.py fixtures)"
python3 "$d/prose.py" --markdown "$d/runs/1706.03762v7/paper.md" >/dev/null
echo " rc=$?"
echo "== gate: run_checks.py (5 legs)"
echo "== gate on the COMMITTED copy: $d"
python3 "$d/run_checks.py"
gate=$?
echo " gate rc=$gate"
[ "$gate" -eq 0 ] || { echo " FAULT: committed gate failed" >&2; exit 1; }
echo "== negative control: the gate must FAIL on a sabotaged archive"
echo
echo "== gate on the LIVE copy (superset, 3 runs): $live"
python3 "$live/run_checks.py"
live_gate=$?
echo " gate rc=$live_gate"
[ "$live_gate" -eq 0 ] || { echo " FAULT: live gate failed" >&2; exit 1; }
echo
echo "== committed copy == live, for everything the commit publishes"
python3 "$d/compare_copies.py" "$d" "$live"
cmp_rc=$?
echo " compare rc=$cmp_rc"
[ "$cmp_rc" -eq 0 ] || exit 1
# --------------------------------------------------------------------------- #
# Negative controls. A control that only ever fails proves nothing, so each is
# run twice: on a faithful copy (must pass) and on a sabotaged copy (must fail).
# --------------------------------------------------------------------------- #
work=$(mktemp -d)
mkdir -p "$work/runs/1706.03762v7"
cp "$d/prose.py" "$d/run_checks.py" "$d/test_arxiv_fulltext.py" \
"$d/test_units.py" "$d/test_prose.py" "$d/arxiv_fulltext.py" "$work/"
cp "$d/runs/1706.03762v7/paper.md" "$work/runs/1706.03762v7/paper.md"
# Inject a code block into the real archived paper and recompute its manifest,
# so every structural check still passes and ONLY the prose leg can catch it.
cp "$d"/prose.py "$d"/run_checks.py "$d"/test_arxiv_fulltext.py \
"$d"/test_units.py "$d"/test_prose.py "$d"/arxiv_fulltext.py "$work/"
cp "$d"/runs/1706.03762v7/* "$work/runs/1706.03762v7/"
echo
echo "== NC1 positive: a faithful copy must grade clean"
python3 "$work/run_checks.py" >/dev/null 2>&1
pos=$?
echo " faithful copy rc=$pos (expected 0)"
[ "$pos" -eq 0 ] || { echo " NC1 POSITIVE FAILED: cannot grade a faithful copy" >&2; exit 1; }
echo
echo "== NC1 negative: code injected into the archived paper must be caught"
printf '\n```python\nimport os\nos.system("curl http://example.invalid")\n```\n' \
>> "$work/runs/1706.03762v7/paper.md"
# Recompute the manifest digest the injection changed, so the ONLY legs that can
# fail are the prose legs. Without this the control passes for the wrong reason
# (a digest mismatch, not a caught injection).
python3 - "$work/runs/1706.03762v7/manifest.json" <<'PY'
import hashlib, json, sys
from pathlib import Path
man_path = Path(sys.argv[1])
man = json.loads(man_path.read_text(encoding="utf-8"))
b = (man_path.parent / "paper.md").read_bytes()
man["artifacts"]["paper.md"] = {"path": "paper.md", "bytes": len(b),
"sha256": hashlib.sha256(b).hexdigest()}
man_path.write_text(json.dumps(man, indent=2, ensure_ascii=False), encoding="utf-8")
print(" manifest digest recomputed for the injected paper.md")
PY
python3 "$work/run_checks.py" >/dev/null 2>&1
sabotage=$?
echo " sabotaged gate rc=$sabotage (expected 1)"
[ "$sabotage" -eq 1 ] || { echo " NEGATIVE CONTROL FAILED: sabotage not detected" >&2; exit 1; }
neg=$?
echo " sabotaged copy rc=$neg (expected 1)"
[ "$neg" -eq 1 ] || { echo " NC1 NEGATIVE FAILED: injection not detected" >&2; exit 1; }
echo
echo "== NC2: a published file the manifest does not declare must be caught"
work2=$(mktemp -d)
mkdir -p "$work2/runs/1706.03762v7"
cp "$d"/prose.py "$d"/run_checks.py "$d"/test_arxiv_fulltext.py \
"$d"/test_units.py "$d"/test_prose.py "$d"/arxiv_fulltext.py \
"$d"/CHECK.sh "$d"/README-prose.md "$d"/compare_copies.py "$work2/"
cp "$d"/runs/1706.03762v7/* "$work2/runs/1706.03762v7/"
cp "$work2/runs/1706.03762v7/paper.md" "$work2/runs/1706.03762v7/notes.txt"
python3 "$d/compare_copies.py" "$work2" "$live" >/dev/null 2>&1
nc2=$?
echo " undeclared-file copy rc=$nc2 (expected 1)"
[ "$nc2" -eq 1 ] || { echo " NC2 FAILED: undeclared published file not detected" >&2; exit 1; }
rm -f "$work2/runs/1706.03762v7/notes.txt"
python3 "$d/compare_copies.py" "$work2" "$live" >/dev/null 2>&1
nc2b=$?
echo " restored copy rc=$nc2b (expected 0)"
[ "$nc2b" -eq 0 ] || { echo " NC2 POSITIVE FAILED: faithful copy not graded clean" >&2; exit 1; }
echo
echo "== git leg: artifact committed"
git -C "$repo" log --oneline -1 -- wizard-work/sphinx/arxiv-fulltext-2026-10-25/ >/dev/null 2>&1
gitrc=$?
echo " git rc=$gitrc"
[ "$gitrc" -eq 0 ] || { echo " artifact not committed" >&2; exit 1; }
[ "$gitrc" -eq 0 ] || { echo " FAULT: artifact not committed" >&2; exit 1; }
echo
[ "$gate" -eq 0 ] && echo "VERIFIED" || { echo "FAULT" >&2; exit 1; }
echo "VERIFIED"
exit 0
@@ -0,0 +1,211 @@
EVIDENCE — arXiv fulltext archive dual-copy gate (sphinx lane)
captured: 2026-10-26T09:08:49Z
host: WorkBench python: Python 3.14.7
COMMIT = /root/troupe-standup/wizard-work/sphinx/arxiv-fulltext-2026-10-25 (1 run)
LIVE = /root/.hermes/wizard-outputs/sphinx/arxiv_fulltext (3 runs)
The committed copy is the published SUBSET of the live working copy, so live
carries runs and source bytes the commit does not. A whole-tree `diff -r` is
therefore the wrong test (it fails on bytes the commit never claimed to
publish). compare_copies.py states the real claim: the commit publishes exactly
the files its run manifest declares, and every one of them is byte-identical in
live.
--------------------------------------------------------------------
1. THE GATE: bash CHECK.sh (its exit code IS the verdict: 0)
--------------------------------------------------------------------
== gate on the COMMITTED copy: /root/troupe-standup/wizard-work/sphinx/arxiv-fulltext-2026-10-25
== L1 real-archive regression test
== L1 real-archive regression: python3 test_arxiv_fulltext.py
25 passed, 0 failed
ALL CHECKS PASSED
PASS L1 real-archive regression exits 0
== L2 fixture unit test
== L2 fixture units: python3 test_units.py
32 passed, 0 failed
ALL UNIT CHECKS PASSED
PASS L2 fixture units exits 0
== L3 prose partition + mutation negative control
== L3 prose partition: python3 test_prose.py
26 passed, 0 failed
ALL PROSE CHECKS PASSED
PASS L3 prose partition exits 0
== L4 published manifest digests match the bytes on disk
PASS at least one manifest found
PASS 1706.03762v7/raw.html digest+size match
PASS 1706.03762v7/paper.md digest+size match
== L5 prose verdict on every real run
PASS 1706.03762v7/paper.md grades prose
7 passed, 0 failed
ALL CHECKS PASSED
gate rc=0
== gate on the LIVE copy (superset, 3 runs): /root/.hermes/wizard-outputs/sphinx/arxiv_fulltext
== L1 real-archive regression test
== L1 real-archive regression: python3 test_arxiv_fulltext.py
29 passed, 0 failed
ALL CHECKS PASSED
PASS L1 real-archive regression exits 0
== L2 fixture unit test
== L2 fixture units: python3 test_units.py
32 passed, 0 failed
ALL UNIT CHECKS PASSED
PASS L2 fixture units exits 0
== L3 prose partition + mutation negative control
== L3 prose partition: python3 test_prose.py
28 passed, 0 failed
ALL PROSE CHECKS PASSED
PASS L3 prose partition exits 0
== L4 published manifest digests match the bytes on disk
PASS at least one manifest found
PASS 1706.03762v7/raw.html digest+size match
PASS 1706.03762v7/paper.md digest+size match
PASS pdf_fallback_1706.03762v7/raw.pdf digest+size match
PASS pdf_fallback_1706.03762v7/paper.md digest+size match
== L5 prose verdict on every real run
PASS 1706.03762v7/paper.md grades prose
PASS pdf_fallback_1706.03762v7/paper.md grades prose
PASS pdf_ocr_1706.03762v7/paper.md grades prose
11 passed, 0 failed
ALL CHECKS PASSED
gate rc=0
== committed copy == live, for everything the commit publishes
9 shared tool/test/gate files byte-identical
runs/1706.03762v7: 4 files, all declared, byte-identical to live
compare rc=0
== NC1 positive: a faithful copy must grade clean
faithful copy rc=0 (expected 0)
== NC1 negative: code injected into the archived paper must be caught
manifest digest recomputed for the injected paper.md
sabotaged copy rc=1 (expected 1)
== NC2: a published file the manifest does not declare must be caught
undeclared-file copy rc=1 (expected 1)
restored copy rc=0 (expected 0)
== git leg: artifact committed
git rc=0
VERIFIED
--------------------------------------------------------------------
2. NC1 POSITIVE — a faithful copy must grade clean (expected rc=0)
--------------------------------------------------------------------
== L1 real-archive regression test
== L1 real-archive regression: python3 test_arxiv_fulltext.py
25 passed, 0 failed
ALL CHECKS PASSED
PASS L1 real-archive regression exits 0
== L2 fixture unit test
== L2 fixture units: python3 test_units.py
32 passed, 0 failed
ALL UNIT CHECKS PASSED
PASS L2 fixture units exits 0
== L3 prose partition + mutation negative control
== L3 prose partition: python3 test_prose.py
26 passed, 0 failed
ALL PROSE CHECKS PASSED
PASS L3 prose partition exits 0
== L4 published manifest digests match the bytes on disk
PASS at least one manifest found
PASS 1706.03762v7/raw.html digest+size match
PASS 1706.03762v7/paper.md digest+size match
== L5 prose verdict on every real run
PASS 1706.03762v7/paper.md grades prose
7 passed, 0 failed
ALL CHECKS PASSED
--------------------------------------------------------------------
3. NC1 NEGATIVE — a fenced Python block injected into the real archived
paper.md, with the manifest digest RECOMPUTED so that only the prose legs
can fail. Expected rc=1. MEASURED rc=1, and the digest legs PASS.
--------------------------------------------------------------------
recomputed digest for 1706.03762v7/paper.md (42536 bytes, sha256 3cdb5d3407a935af...)
== L1 real-archive regression test
== L1 real-archive regression: python3 test_arxiv_fulltext.py
25 passed, 0 failed
ALL CHECKS PASSED
PASS L1 real-archive regression exits 0
== L2 fixture unit test
== L2 fixture units: python3 test_units.py
32 passed, 0 failed
ALL UNIT CHECKS PASSED
PASS L2 fixture units exits 0
== L3 prose partition + mutation negative control
== L3 prose partition: python3 test_prose.py
- bare maths assignment does not flip verdict ['code_fence_present=1']
- short untagged fence does not flip verdict ['code_fence_present=1']
- 1706.03762v7: graded prose ['code_fence_present=1']
FAIL L3 prose partition exits 0 rc=1 err=
== L4 published manifest digests match the bytes on disk
PASS at least one manifest found
PASS 1706.03762v7/raw.html digest+size match
PASS 1706.03762v7/paper.md digest+size match
== L5 prose verdict on every real run
FAIL 1706.03762v7/paper.md grades prose [' PROSE: no (code_fence_present=1)']
5 passed, 2 failed
FAILURES:
- L3 prose partition exits 0 rc=1 err=
- 1706.03762v7/paper.md grades prose [' PROSE: no (code_fence_present=1)']
READ THIS AS: the injected code is caught by the PROSE legs alone. L4 (the digest
legs) passes on the sabotaged copy because the manifest digest was recomputed,
so the failure cannot be attributed to a digest mismatch.
--------------------------------------------------------------------
4. ARTIFACT DIGESTS (sha256, bytes on disk)
--------------------------------------------------------------------
b2adf45ac52f6af62c3f93316059550a0201da8768da4107196a7af5111d962f CHECK.sh
ae74e8f530be4f7609aa56680041d888a7ea96da03a239950513267f429b21af compare_copies.py
086299ddce23716b03bf0a3c0e67a67bb2e2d92abfccec2bc08c5194f5926878 README-prose.md
e815d4934dc15ef483437ba860b260c20a08d966affc30b1f84022fcf851c89f run_checks.py
e2fd595302fab61cb6458d74e8f2d0ef2a11d1ba5977fb5019a472bdbb35908e prose.py
@@ -3,7 +3,8 @@
## What this is
A deterministic prose/code partition for the archive lane's arXiv fulltext
pipeline, plus the lane gate that runs it.
pipeline, plus the lane gate that runs it — graded against **two** copies: the
committed subset and the live working copy.
## Why it exists
@@ -23,7 +24,9 @@ were recomputed would pass every pre-existing check.
| `prose.py` | the partition: `fence_blocks`, `code_blocks`, `prose_stats`, `is_prose_document`, `find_injected_code` |
| `test_prose.py` | 28 checks: fixtures + a negative control on a real archived paper |
| `run_checks.py` | the gate: 5 legs, 11 assertions, exit 0 only if all hold |
| `compare_copies.py` | grades the committed copy against the live copy |
| `CHECK.sh` | the one-command lane gate, exit code = verdict |
| `EVIDENCE-dualcopy.txt` | captured run output of the gate below |
## The rules (all deterministic, no model)
@@ -38,17 +41,47 @@ were recomputed would pass every pre-existing check.
`find_injected_code` reports every code fence with its line range, so a block is
visible even when the document-level verdict is unaffected.
## Two copies, one claim
The commit publishes **one** run (`runs/1706.03762v7`); the live working copy
holds **three** (`1706.03762v7`, `pdf_fallback_1706.03762v7`,
`pdf_ocr_1706.03762v7`) and carries source bytes the commit does not. So the two
are *not* equal as trees, and a whole-tree `diff -r` is the wrong test — it
fails on bytes the commit never claimed to publish.
`compare_copies.py` states the real claim instead:
- the shared tool/test/gate files are byte-identical between the copies;
- every run the commit publishes is present in live;
- the commit publishes **exactly** the files its run manifest declares
(`index.md`, `manifest.json`, and every manifest artifact) and nothing else —
so the commit carries no artifact its own manifest does not vouch for;
- every one of those published files is byte-identical in live.
## Negative controls (both run twice)
A control that only ever fails proves nothing, so each is graded on a faithful
copy first and a sabotaged copy second:
- **NC1** copies the real run, injects a fenced Python block into `paper.md`,
**recomputes the manifest digest the injection changed**, and requires the
gate to exit 1. The digest recompute is what makes the control sound: without
it the gate fails on a digest mismatch rather than on the caught injection.
Measured: faithful copy `rc=0`, sabotaged copy `rc=1`, and the digest legs
pass on the sabotaged copy — the failures are the prose legs
(`code_fence_present=1`).
- **NC2** copies the real run, drops an undeclared `notes.txt` into it, and
requires `compare_copies.py` to exit 1; removing it must restore `rc=0`.
## Evidence
python3 run_checks.py # 11 passed, 0 failed, exit 0
bash CHECK.sh # VERIFIED, exit 0
The negative control in `CHECK.sh` copies the real run, injects a fenced Python
block into `paper.md`, recomputes the manifest digest, and requires the gate to
exit 1. It does.
Captured run output is in `EVIDENCE-dualcopy.txt`.
## Verdict
`VERDICT: the archive's published markdown is graded as prose by a deterministic partition, and code injection into it is caught; 11/11 gate assertions hold.`
`VERDICT: the archive's published markdown is graded as prose by a deterministic partition; code injection is caught by the prose legs alone (digest recomputed), an undeclared published file is caught by the copy comparison, and both the committed and live copies grade green and are byte-identical on everything the commit publishes.`
`CHECK: bash /root/troupe-standup/wizard-work/sphinx/arxiv-fulltext-2026-10-25/CHECK.sh`
@@ -0,0 +1,103 @@
#!/usr/bin/env python3
"""compare_copies.py -- grade the committed copy of the arXiv fulltext archive
against the live working copy (sphinx lane, 2026-10-26).
COMMIT is the directory the gate runs from; LIVE is the published working copy.
COMMIT is a SUBSET of LIVE -- live may hold runs and source bytes the commit
does not. So the two are not equal as trees, and a whole-tree `diff -r` is the
wrong test. What must hold is:
* the shared tool/tests/gate files are byte-identical between the copies, and
* every run the commit publishes is present in live, and
* the commit publishes exactly the files its run manifest declares
(`index.md` + `manifest.json` + every manifest artifact) and nothing else,
so the commit carries no artifact its own manifest does not vouch for, and
* every one of those published files is byte-identical in live.
Exit 0 = held. Exit 1 = a named fault. Exit 2 = could not grade.
"""
from __future__ import annotations
import json
import sys
from pathlib import Path
SHARED = [
"prose.py",
"test_prose.py",
"run_checks.py",
"test_arxiv_fulltext.py",
"test_units.py",
"arxiv_fulltext.py",
"CHECK.sh",
"README-prose.md",
"compare_copies.py",
]
def fault(msg: str) -> int:
print(f" FAULT: {msg}", file=sys.stderr)
return 1
def grade(commit: Path, live: Path) -> int:
if not commit.is_dir() or not live.is_dir():
print(" could not grade: a directory does not exist", file=sys.stderr)
return 2
for f in SHARED:
a, b = commit / f, live / f
if not a.is_file():
return fault(f"{f} missing from the committed copy")
if not b.is_file():
return fault(f"live has no {f}")
if a.read_bytes() != b.read_bytes():
return fault(f"{f} differs between commit and live")
print(f" {len(SHARED)} shared tool/test/gate files byte-identical")
for r in sorted((commit / "runs").iterdir()):
if not r.is_dir():
continue
name = r.name
lr = live / "runs" / name
if not lr.is_dir():
return fault(f"live has no runs/{name}")
man = json.loads((r / "manifest.json").read_text(encoding="utf-8"))
declared = {"index.md", "manifest.json"} | {
a["path"] for a in man.get("artifacts", {}).values()
}
published = {p.name for p in r.iterdir() if p.is_file()}
extra = published - declared
if extra:
return fault(
f"runs/{name} publishes files its manifest does not declare: "
f"{sorted(extra)}"
)
missing = declared - published
if missing:
return fault(
f"runs/{name} is missing files its manifest declares: {sorted(missing)}"
)
for n in sorted(published):
b = lr / n
if not b.is_file():
return fault(f"runs/{name}/{n} absent from live")
if (r / n).read_bytes() != b.read_bytes():
return fault(f"runs/{name}/{n} differs between commit and live")
print(f" runs/{name}: {len(published)} files, all declared, byte-identical to live")
return 0
def main(argv: list[str]) -> int:
if len(argv) != 3:
print("usage: compare_copies.py <commit_dir> <live_dir>", file=sys.stderr)
return 2
return grade(Path(argv[1]), Path(argv[2]))
if __name__ == "__main__":
sys.exit(main(sys.argv))