Skip to content

Commit 4f591a1

Browse files
committed
W3 Step 5: rc_oracle_self_test.sh — falsifier validator
Push 44 W3 Step 5 (final): self-test script that validates the W3 R4 oracle's diagnostic capability via 3 falsifiers + synthetic injection. Per theologian 2026-04-22 02:30:08Z W3 spec falsifier: "inject a synthetic refcount bug into the C path — scripts/ rc_diff_oracle.sh produces non-empty output. If diff is empty under injection, oracle is non-functional and W3 has not delivered the diagnostic capability it promised." Script structure: --check mode: pre-conditions only (3 nm-based assertions) default: pre-conditions + Phase A (clean diff = empty) + Phase B (injected diff = non-empty) + post-restore verification FALSIFIERS validated: python#1 — production python has 0 rc_oracle symbols (RC_ORACLE undefined, dispatcher block ABSENT from compiled binary). VERIFIED via --check mode at HEAD a99db92: 'PASS: production python has 0 rc_oracle symbols'. python#2 — libphoenix_rc_oracle.a exports rc_oracle_run T-symbol. VERIFIED: 'PASS: scratch lib exports rc_oracle_run (C entry point)'. python#3 — python_rc_cpp has rc_oracle_run T-symbol. PENDING — operator must run out-of-band link via the recipe in scripts/build_oracle.sh tail (per supervisor 02:51:14Z option (c)). INJECTION mechanism: Phase B comments out the FIRST 'phx_rc_emit_incref' call site in Python/jit/hir/refcount_pass_c.c via sed. Rebuilds C path. Runs rc_diff_oracle.sh and asserts non-empty diff. Restores via backup + rebuild. Final verification: post-restore diff is empty. Injection target chosen for stability: phx_rc_emit_incref is a high-frequency call across all refcount_insertion paths; commenting one removes one Incref → guaranteed runtime divergence under Py_REF_DEBUG (under-count → leak) AND under PYDEBUG (use-after-free). Injection is reversible: cp $INJECT_TARGET.oracle_backup back + rebuild. trap EXIT ensures restore even on script error. Per supervisor 02:51:14Z option (c): out-of-band link of python_rc_cpp is operator-driven (not embedded in this script), since W3 is a one-shot oracle resurrection; no permanent Makefile.pre.in touch. Pre-commit verification: bash -n: SYNTAX OK scripts/rc_oracle_self_test.sh --check: pre-conditions python#1, python#2 PASS; python#3 expected to FAIL until operator runs the link recipe. Push 44 W3 batch is now 2 commits (per supervisor 02:51:14Z amended): a99db92 — W3 Steps 1-4 bundled (scratch lib + dispatcher + adapter) THIS COMMIT — Step 5 self-test ABBA cap 15 → 17. MANDATORY ABBA + auto-compile re-experiment after push 44 lands per pre-authorization. Process lesson applied (per supervisor 02:51:14Z): explicit 'git add scripts/rc_oracle_self_test.sh' (single file) + 'git diff --cached --stat' verification BEFORE commit, to avoid the over-broad staging that produced a99db92's bundled scope.
1 parent a99db92 commit 4f591a1

1 file changed

Lines changed: 192 additions & 0 deletions

File tree

scripts/rc_oracle_self_test.sh

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
#!/bin/bash
2+
# rc_oracle_self_test.sh — W3 R4 oracle self-test (Step 5)
3+
#
4+
# Validates the oracle's diagnostic capability: synthetic refcount
5+
# divergence injection must produce non-empty diff (oracle WORKS), and
6+
# clean run must produce empty diff (oracle is NOT noisy).
7+
#
8+
# Per theologian 2026-04-22 02:30:08Z W3 spec falsifier:
9+
# "inject a synthetic refcount bug into the C path (e.g., remove an
10+
# Incref or add an extra Decref after CheckField) — scripts/
11+
# rc_diff_oracle.sh produces non-empty output (showing the divergence).
12+
# If diff is empty under injection, oracle is non-functional and W3
13+
# has not delivered the diagnostic capability it promised."
14+
#
15+
# Per supervisor 2026-04-22 02:51:14Z option (c): out-of-band link of
16+
# python_rc_cpp via the recipe documented in scripts/build_oracle.sh.
17+
# This script does NOT invoke the link itself — it verifies the
18+
# pre-conditions and exercises the oracle once the operator has built
19+
# both binaries.
20+
#
21+
# Usage:
22+
# scripts/rc_oracle_self_test.sh # full self-test
23+
# scripts/rc_oracle_self_test.sh --check # pre-conditions only
24+
#
25+
# Exit code: 0 = self-test PASS, non-zero = FAIL with diagnostic
26+
27+
set -euo pipefail
28+
29+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
30+
CPYTHON_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
31+
SCRATCH_DIR="$CPYTHON_ROOT/docs/oracle_scratch"
32+
PROD_PYTHON="$CPYTHON_ROOT/python"
33+
RC_PYTHON="$SCRATCH_DIR/python_rc_cpp"
34+
DIFF_DRIVER="$SCRIPT_DIR/rc_diff_oracle.sh"
35+
INJECT_TARGET="$CPYTHON_ROOT/Python/jit/hir/refcount_pass_c.c"
36+
37+
CHECK_ONLY=0
38+
for arg in "$@"; do
39+
case "$arg" in
40+
--check) CHECK_ONLY=1 ;;
41+
*) echo "Unknown flag: $arg"; exit 4 ;;
42+
esac
43+
done
44+
45+
# ---- Pre-condition #1: production python exists + has NO rc_oracle symbols ----
46+
47+
echo "=== rc_oracle_self_test ==="
48+
echo ""
49+
echo "--- Pre-condition #1: production python free of rc_oracle symbols ---"
50+
if [ ! -x "$PROD_PYTHON" ]; then
51+
echo "FAIL: $PROD_PYTHON does not exist or is not executable" >&2
52+
echo " Run scripts/build_phoenix.sh first" >&2
53+
exit 1
54+
fi
55+
56+
PROD_NM_HITS=$(nm "$PROD_PYTHON" 2>/dev/null | grep -c rc_oracle || true)
57+
if [ "$PROD_NM_HITS" -ne 0 ]; then
58+
echo "FAIL: production python contains $PROD_NM_HITS rc_oracle symbol(s)" >&2
59+
echo " Falsifier triggered: build system accidentally enabled RC_ORACLE" >&2
60+
nm "$PROD_PYTHON" | grep rc_oracle | head -5 >&2
61+
exit 1
62+
fi
63+
echo "PASS: production python has 0 rc_oracle symbols (RC_ORACLE undefined)"
64+
65+
# ---- Pre-condition #2: scratch lib exists ----
66+
67+
echo ""
68+
echo "--- Pre-condition #2: libphoenix_rc_oracle.a exists ---"
69+
SCRATCH_LIB="$SCRATCH_DIR/build/libphoenix_rc_oracle.a"
70+
if [ ! -f "$SCRATCH_LIB" ]; then
71+
echo "FAIL: $SCRATCH_LIB does not exist" >&2
72+
echo " Run scripts/build_oracle.sh to build the scratch lib" >&2
73+
exit 1
74+
fi
75+
LIB_HITS=$(nm "$SCRATCH_LIB" 2>/dev/null | grep -c ' T rc_oracle_run' || true)
76+
if [ "$LIB_HITS" -lt 1 ]; then
77+
echo "FAIL: $SCRATCH_LIB does not export rc_oracle_run T-symbol" >&2
78+
exit 1
79+
fi
80+
echo "PASS: scratch lib exports rc_oracle_run (C entry point)"
81+
82+
# ---- Pre-condition #3: python_rc_cpp exists + HAS rc_oracle symbols ----
83+
84+
echo ""
85+
echo "--- Pre-condition #3: python_rc_cpp built with RC_ORACLE active ---"
86+
if [ ! -x "$RC_PYTHON" ]; then
87+
echo "FAIL: $RC_PYTHON does not exist or is not executable" >&2
88+
echo " Out-of-band link required (see build_oracle.sh tail for recipe)" >&2
89+
echo " Per supervisor 02:51:14Z option (c): operator runs link manually." >&2
90+
exit 1
91+
fi
92+
93+
RC_NM_HITS=$(nm "$RC_PYTHON" 2>/dev/null | grep -c ' T rc_oracle_run' || true)
94+
if [ "$RC_NM_HITS" -lt 1 ]; then
95+
echo "FAIL: python_rc_cpp does not contain rc_oracle_run T-symbol" >&2
96+
echo " Either RC_ORACLE was not defined OR libphoenix_rc_oracle.a not linked" >&2
97+
exit 1
98+
fi
99+
echo "PASS: python_rc_cpp has rc_oracle_run T-symbol (RC_ORACLE defined + lib linked)"
100+
101+
if [ "$CHECK_ONLY" -eq 1 ]; then
102+
echo ""
103+
echo "=== --check complete: all pre-conditions PASS ==="
104+
exit 0
105+
fi
106+
107+
# ---- Phase A: clean run (no injection) — diff MUST be empty ----
108+
109+
echo ""
110+
echo "--- Phase A: clean run, expect empty diff ---"
111+
if "$DIFF_DRIVER"; then
112+
echo "PASS: clean oracle run produces empty diff (C and C++ refcount sequences match)"
113+
else
114+
echo "FAIL: clean oracle run produces non-empty diff (PRE-EXISTING DIVERGENCE)" >&2
115+
echo " Either C path has a real bug or pre/post pass conflation (invariant #6)" >&2
116+
exit 1
117+
fi
118+
119+
# ---- Phase B: synthetic injection — diff MUST be non-empty ----
120+
121+
echo ""
122+
echo "--- Phase B: synthetic refcount-bug injection, expect non-empty diff ---"
123+
124+
if [ ! -f "$INJECT_TARGET" ]; then
125+
echo "FAIL: injection target $INJECT_TARGET does not exist" >&2
126+
echo " Self-test cannot prove the oracle catches injected divergence" >&2
127+
exit 1
128+
fi
129+
130+
# Synthetic defect: comment out one Incref call in refcount_pass_c.c.
131+
# This produces a real refcount divergence (under-count → leak under
132+
# Py_REF_DEBUG OR use-after-free under PYDEBUG).
133+
INJECT_BACKUP="$INJECT_TARGET.oracle_backup"
134+
cp "$INJECT_TARGET" "$INJECT_BACKUP"
135+
trap 'cp "$INJECT_BACKUP" "$INJECT_TARGET" 2>/dev/null; rm -f "$INJECT_BACKUP"' EXIT
136+
137+
# Find the FIRST 'phx_rc_emit_incref' call site and comment it.
138+
# (Pattern is stable across the C port per Phase 0 audit.)
139+
INCREF_LINE=$(grep -n 'phx_rc_emit_incref' "$INJECT_TARGET" | head -1 | cut -d: -f1 || true)
140+
if [ -z "$INCREF_LINE" ]; then
141+
echo "FAIL: no phx_rc_emit_incref call site found in $INJECT_TARGET" >&2
142+
echo " Refactor self-test to use a different injection target" >&2
143+
exit 1
144+
fi
145+
146+
echo "Injecting at $INJECT_TARGET:$INCREF_LINE (commenting out first phx_rc_emit_incref)"
147+
sed -i "${INCREF_LINE}s|^|//RC_ORACLE_INJECT://|" "$INJECT_TARGET"
148+
149+
# Rebuild the C path.
150+
echo "Rebuilding C path with injected defect..."
151+
( cd "$CPYTHON_ROOT" && cmake --build Python/jit_build/build --target phoenix_jit -- -j32 ) >/dev/null
152+
( cd "$CPYTHON_ROOT" && make -j32 python ) >/dev/null
153+
154+
# Run the diff driver. Expect NON-empty (exit 1).
155+
echo "Running diff driver under injection..."
156+
if "$DIFF_DRIVER"; then
157+
echo "FAIL: oracle produced empty diff under injection" >&2
158+
echo " The injected defect was NOT caught — oracle is non-functional" >&2
159+
exit 1
160+
fi
161+
echo "PASS: oracle produces non-empty diff under injection (oracle WORKS)"
162+
163+
# Trap will restore the file. Rebuild after restore.
164+
cp "$INJECT_BACKUP" "$INJECT_TARGET"
165+
rm -f "$INJECT_BACKUP"
166+
trap - EXIT
167+
echo "Restoring C path + rebuilding..."
168+
( cd "$CPYTHON_ROOT" && cmake --build Python/jit_build/build --target phoenix_jit -- -j32 ) >/dev/null
169+
( cd "$CPYTHON_ROOT" && make -j32 python ) >/dev/null
170+
171+
# Final verification: clean run after restore must again produce empty diff.
172+
echo "Final verification: post-restore diff must be empty..."
173+
if "$DIFF_DRIVER"; then
174+
echo "PASS: post-restore oracle produces empty diff (restore successful)"
175+
else
176+
echo "FAIL: post-restore diff non-empty — RESTORE LEFT C PATH BROKEN" >&2
177+
echo " git checkout $INJECT_TARGET to recover" >&2
178+
exit 1
179+
fi
180+
181+
echo ""
182+
echo "=== rc_oracle_self_test PASS ==="
183+
echo ""
184+
echo "Falsifier evidence:"
185+
echo " - Pre-condition #1: production python has 0 rc_oracle symbols"
186+
echo " - Pre-condition #3: python_rc_cpp has rc_oracle_run T-symbol"
187+
echo " - Phase A: clean diff is empty"
188+
echo " - Phase B: injection produces non-empty diff (oracle WORKS)"
189+
echo " - Post-restore: diff is empty (restore clean)"
190+
echo ""
191+
echo "W3 R4 oracle is OPERATIONAL and DIAGNOSTIC."
192+
exit 0

0 commit comments

Comments
 (0)