Skip to content

Commit 93d60e8

Browse files
committed
docs: W25 §5.3 procedure correction — dual .h+.cpp mutation
Per theologian [chat 2026-04-22 19:26Z] methodology catch on e8b8c14: mutating only hir_c_api.h would fail in hir_c_api.cpp first (header-vs- impl mismatch) BEFORE any §1b consumer compiles. That outcome would prove Step A header-impl consistency is tight, NOT the §1b drift surface this test should expose. CORRECT METHODOLOGY: mutate BOTH hir_c_api.h decl AND hir_c_api.cpp impl together. With consistent .h+.cpp: - hir_c_api.cpp compiles (matches header) - §1a consumers see new sig from header → catch wrong-arg-count callers at compile time (proves §1a path is protected) - §1b consumers with local extern decls keep their OLD signature → callers in those TUs compile fine against local extern, then linker resolves to new-impl-signature → silent runtime UB (PROVES §1b is the unprotected drift surface — exactly what Step B closes) CHANGES (docs/w25-step-b-mutation-test.md): §1: explain dual-file requirement upfront, original + mutated sigs shown for both .h and .cpp §2: dual-sed procedure (.h decl + .cpp impl signature line both) verify both mutations applied + revert both files §4: post-Step-B procedure also dual-sed Authorization chain: - Theologian methodology catch: chat 2026-04-22 19:26Z - HALT message before testkeeper baseline run: this session - Doc supersedes e8b8c14 procedure (no amend per CLAUDE.md; next-commit correction)
1 parent e8b8c14 commit 93d60e8

1 file changed

Lines changed: 44 additions & 22 deletions

File tree

docs/w25-step-b-mutation-test.md

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,63 +14,83 @@ claim is theoretical.
1414

1515
## 1. Mutation choice
1616

17-
Modify `Python/jit/hir/hir_c_api.h` to ADD an extra parameter to a
18-
widely-used API function. Choice: `hir_block_id`.
17+
**CRITICAL methodology fix per theologian [chat 2026-04-22 19:26Z]:**
18+
mutate BOTH `hir_c_api.h` declaration AND `hir_c_api.cpp` impl
19+
together. Mutating only the header would fail in `hir_c_api.cpp` first
20+
(header-vs-impl mismatch) — would prove Step A header-impl consistency
21+
is tight, NOT the §1b drift surface this test should expose.
22+
23+
With dual-mutation (.h + .cpp consistent on new sig):
24+
- `hir_c_api.cpp` compiles fine (.h + .cpp agree)
25+
- §1a TUs that include `hir_c_api.h` see new sig → callers with
26+
wrong arg count fail to compile (proves §1a path is protected)
27+
- §1b TUs with local extern decls keep their OLD signature → callers
28+
in those TUs compile fine against the local extern, then linker
29+
resolves to the new-signature impl → silent runtime UB (PROVES §1b
30+
is the unprotected drift surface — exactly what Step B closes)
31+
32+
Mutation function choice: `hir_block_id`.
1933

2034
**Original signature** (post-Step-A at 3404a81192):
2135

2236
```c
37+
/* hir_c_api.h */
2338
int hir_block_id(struct HirBasicBlock *block);
39+
/* hir_c_api.cpp */
40+
int hir_block_id(struct HirBasicBlock *block) { ... }
2441
```
2542
26-
**Mutated signature** (W25 §5.3 baseline mutation):
43+
**Mutated signature** (W25 §5.3 baseline mutation, BOTH files):
2744
2845
```c
46+
/* hir_c_api.h */
2947
int hir_block_id(struct HirBasicBlock *block, int unused_drift_param);
48+
/* hir_c_api.cpp */
49+
int hir_block_id(struct HirBasicBlock *block, int unused_drift_param) { ... }
3050
```
3151

32-
The mutation introduces a parameter-count mismatch. Local extern decls
33-
in §1b TUs do NOT include the new parameter — every consuming TU has
34-
stale signature.
35-
3652
Why `hir_block_id`:
3753
- Called from at least 1 §1b TU (per `count_w25_b1b_tus.sh` survey).
3854
- Simple int parameter — no implicit-conversion masking.
39-
- ABI-incompatible mutation (extra arg) — cannot be silently linked
40-
because caller pushes wrong arg count.
41-
- BUT: in C, calling a function with a different signature than its
42-
declaration is undefined behavior, NOT a hard link error. The
43-
question §5.3 answers empirically is whether THIS specific mutation
44-
is caught by the build, the linker, or only at runtime.
55+
- ABI-incompatible mutation (extra arg) — caller pushes wrong arg
56+
count vs callee expects new arg → silent UB at runtime.
57+
- In C, calling a function with a different signature than its
58+
declaration is undefined behavior, NOT a hard link error. §5.3
59+
answers empirically what this UB looks like in our build.
4560

46-
## 2. Baseline procedure (pre-Step-B, run NOW at HEAD 3404a81192)
61+
## 2. Baseline procedure (pre-Step-B, run at HEAD e8b8c149fe or later)
4762

4863
```bash
4964
# Step 1: capture baseline state
50-
git rev-parse HEAD # expect: 3404a811927d1fb1fce61ce7f1ab8763f988711e
65+
git rev-parse HEAD # expect: e8b8c149fe... (this commit) or its descendant
5166

52-
# Step 2: apply mutation
67+
# Step 2: apply DUAL mutation (.h + .cpp must stay consistent)
5368
cd /data/users/alexturner/phoenix/cpython
5469
git stash --include-untracked # stash any working-tree changes
70+
# Mutate header decl
5571
sed -i 's|int hir_block_id(struct HirBasicBlock \*block);|int hir_block_id(struct HirBasicBlock *block, int unused_drift_param);|' Python/jit/hir/hir_c_api.h
72+
# Mutate cpp impl signature line (preserves brace-on-same-line)
73+
sed -i 's|int hir_block_id(struct HirBasicBlock \*block) {|int hir_block_id(struct HirBasicBlock *block, int unused_drift_param) {|' Python/jit/hir/hir_c_api.cpp
5674

57-
# Verify mutation applied
75+
# Verify both mutations applied
5876
grep -A1 "hir_block_id" Python/jit/hir/hir_c_api.h | head -5
77+
grep -A1 "^int hir_block_id" Python/jit/hir/hir_c_api.cpp | head -3
5978

6079
# Step 3: try to build
6180
scripts/build_phoenix.sh > /tmp/w25-mutation-baseline-stdout.log 2>&1
6281
echo "BUILD_EXIT=$?" >> /tmp/w25-mutation-baseline-stdout.log
6382

6483
# Step 4: capture findings
65-
echo "=== BASELINE (pre-Step-B at 3404a81192) ===" > docs/w25-step-b-mutation-baseline.txt
84+
echo "=== BASELINE (pre-Step-B, dual-mutation .h+.cpp) ===" > docs/w25-step-b-mutation-baseline.txt
85+
echo "HEAD: $(git rev-parse HEAD)" >> docs/w25-step-b-mutation-baseline.txt
6686
grep -E "error:|warning:|BUILD_EXIT" /tmp/w25-mutation-baseline-stdout.log | tail -30 >> docs/w25-step-b-mutation-baseline.txt
6787

68-
# Step 5: revert
69-
git checkout -- Python/jit/hir/hir_c_api.h
88+
# Step 5: revert BOTH files
89+
git checkout -- Python/jit/hir/hir_c_api.h Python/jit/hir/hir_c_api.cpp
7090
git stash pop || true # restore stashed working tree
7191

7292
# Step 6: verify revert succeeded
73-
git diff Python/jit/hir/hir_c_api.h # expect: empty
93+
git diff Python/jit/hir/hir_c_api.h Python/jit/hir/hir_c_api.cpp # expect: empty
7494
```
7595

7696
## 3. Expected baseline outcome
@@ -98,10 +118,12 @@ hir_c_api.h):
98118
```bash
99119
# At post-Step-B HEAD
100120
git rev-parse HEAD # expect: <Step B's last commit hash>
121+
# Same DUAL mutation as §2 — keep .h + .cpp consistent
101122
sed -i 's|int hir_block_id(struct HirBasicBlock \*block);|int hir_block_id(struct HirBasicBlock *block, int unused_drift_param);|' Python/jit/hir/hir_c_api.h
123+
sed -i 's|int hir_block_id(struct HirBasicBlock \*block) {|int hir_block_id(struct HirBasicBlock *block, int unused_drift_param) {|' Python/jit/hir/hir_c_api.cpp
102124
scripts/build_phoenix.sh > /tmp/w25-mutation-poststepb-stdout.log 2>&1
103125
echo "BUILD_EXIT=$?" >> /tmp/w25-mutation-poststepb-stdout.log
104-
git checkout -- Python/jit/hir/hir_c_api.h
126+
git checkout -- Python/jit/hir/hir_c_api.h Python/jit/hir/hir_c_api.cpp
105127
```
106128

107129
**Expected post-Step-B outcome:** compile FAILS in every consuming TU

0 commit comments

Comments
 (0)