# PRE-REGISTRATION v2: Epoch crosswalk, batch 2: HLE within-question cue test

**Status: LOCKED 2026-10-28 06:15 MDT** (sha256 in `PREREG_HLE_B2_v2.md.sha256`; draft was c1ab898d2d2a170d5b3dbaf43a0f595a42ed7e53c977b695dc88e61269a0bb59). Written 2026-10-27 MDT by Grok Bot (executor) for Ford / Abe, for Kevin Russell / Honesty.tools (P42), after the v1 synthetic gate failed. It is locked by hash **only if** the v2 synthetic gate (§6) passes every criterion. If it fails, v2 is recorded NOT RUN and nothing is loosened.
No real HLE data has been built, opened or scored for batch 2, v1 or v2. Every v2 number below comes from synthetic data.

| Pinned input (read-only, never edited) | sha256 |
|---|---|
| v1 `PREREG_HLE_B2.md` (NOT LOCKED; batch-2 v1 = NOT RUN) | `4c34a85d07c92f062483bb03e2e08d30b97445463fb02ad2da644b830faf7df0` |
| v1 gate result `sim/B2_SIM_GATE.json` (FAILED at W) | `bca24958c511620a060ceeafa7abf43c29b3a82cfb7f3033b6631581f5bc7c2d` |
| v1 `b2_sim.py` / `b2_build.py` | `a4a70f6be60149dd011802782c7efa5ea5ea9a22868823c9e1e1bd08966d6c2c` / `dd0ab03773f83fa9632b71f36800e17ebe1683f8c49f51b8f5842d12dddf990c` |
| `nulltest.py` v1.4 / `nulltest_paired.py` 0.1 / `nulltest_grouped.py` 0.1 / `test_nulltest_grouped.py` | `0e103dc4…f46c` / `2fbbebca…37d3` / `dbef88df…0d69` / `e5042893…a382` (full hashes in `batch2/code/CODE.sha256`) |
| v1 tests record `logs/TESTS_OUTPUT.txt` | see `logs/TESTS_OUTPUT.txt.sha256` |
| v2 design pilot `pilot/b2v2_pilot.py` / `pilot/PILOT_SUMMARY.json` / `pilot/pilot_P.jsonl` | `b7ac77c063b2b626b25e1cd08b6fce8abbf1decbda57af0e3eec0b9cac3fae87` / `22e802ed6cf970059ad930945bd920fac3fe89aaa06f4e273103ad43e89ea52e` / `9c9a876289b2dfad1a30fee915102a35594f0d1a3c038fb48cdb40b2961be69f` |
| v2 `code/b2v2_sim.py` / `code/b2v2_build.py` | `92969fd8f505e7ad9ce98468c40b4e1635ed701860d2361b350e3d6d8ff5fc9f` / `654974d5d3a2892fd9789fc36304151216b5d2e6016d397696425f43986161aa` |

## F. Falsifier (written first; binding)

**F-gate (v2 itself).** v2 is NOT RUN, and no real HLE data is scored under it, if any one of the following holds in `b2v2_sim.py`'s output `v2/sim/B2V2_SIM_GATE.json`:
1. **R:** no p_Q level in {0.45, 0.60, 0.75} gives the batch-1 B1 command DISQUALIFIED in ≥ 25/50 null datasets.
2. **N1:** arm G or arm P is DISQUALIFIED in > 9/200 null datasets, at the reproduction level or at 0.75.
3. **N2:** arm G or arm P is DISQUALIFIED in > 9/200 planted-then-shuffled datasets, at either level.
4. **W:** at none of f = 0.30, 0.60, 0.75 do **both** arms reach ≥ 40/50 on the same 50 planted datasets.
Each threshold is v1's, unchanged. There is no fourth rung, no re-run with other seeds, and no v3 built from v2's W numbers by this drafter. A further version would need Abe's decision and its own pre-registration.

**F-claim (what would refute the batch-2 claim on real data, unchanged from v1 §9).**
- Either arm detects the planted cue in < 3 of 4 copies → that arm is INVALID → batch 2 INVALID.
- Either arm's within-question shuffle control is DISQUALIFIED → VOID ("control failed").
- Otherwise a DISQUALIFIED primary in either arm at alpha 0.025 → FAIL (cue detected). Both arms PASS → PASS (no within-question surface cue detected at this n, and at the validated sensitivity of §6.3, which is weaker than v1 intended).

## 0. Why v2, and what changes

The v1 gate (run 2026-10-27, 08:04–13:56 MDT) reproduced the batch-1 failure at p_Q = 0.60 (25/50) and kept every null at or below 9/200 (N1 0.60: G 0, P 5; N1 0.75: G 3, P 5; N2 0.60: G 1, P 6; N2 0.75: G 7, P 7). It **failed W**: at f = 0.30, G 3/50 and P 1/50; at f = 0.60, G 49/50 but **P 32/50** (40 needed). v1 is therefore NOT RUN and stays so; its file is not edited, loosened or reused.

**Diagnosis (from the v1 gate output, synthetic):** arm P scores 934 items (467 pairs) against arm G's 3,164. The appended `x` is seen almost only by the `lexicality` probe (character n-gram NB); in W at 0.60 P's worst cell was lexicality in 47/50, A*_pair 0.55–0.66, adj p 0.0067–0.26.

**Fix options considered:**
- **More items: not available.** The 467 questions are fixed by the pinned parquet and the batch-1 data gate, which v2 keeps. Drawing several wrong options per question in arm P would make pairs within a question dependent and break the sign-flip null and pair-grouped folds that `nulltest_paired.py` 0.1 assumes; doing it properly would be new scoring code, which arm P exists to avoid.
- **Larger effect floor: chosen.** One extra rung on the W ladder: **f = 0.75**. This changes only how strong a planted cue the method is shown to catch, not any null, threshold, seed, probe, alpha or arm.

**Simulation evidence for 0.75 (design pilot, exploratory, not a gate step).** Rule fixed in `PROGRESS.md` (15:25 MDT) before running: arm P only, p_Q 0.60, f ∈ {0.75, 0.90, 1.00}, 30 datasets each with seeds 20262900 + s (disjoint from every gate seed), choose the smallest f with P DISQUALIFIED in ≥ 27/30 (90%, a margin over the 80% gate). Result (DGX 14:24–14:27 MST = 15:24–15:27 MDT): **f 0.75: 29/30** (mean A*_pair 0.628); 0.90: 30/30 (0.663); 1.00: 30/30 (0.692); worst cell lexicality in all 90. Chosen **f = 0.75**. Arm G was not piloted; it reached 49/50 at 0.60 in v1, and the planted cue at 0.75 is a superset of the 0.60 cue in each dataset (same selection shuffle, more questions).

**Cost (binding in §8 and §15):** v2 is validated only for a cue present on the keyed option in **75%** of questions (v1 aimed at 30%, then 60%). A PASS under v2 says less: weaker within-question cues may be missed.

## 1–5. Scope, tools, grouped folds, analysis, option count

**Identical to v1 §1–§5** (`PREREG_HLE_B2.md` sha256 `4c34a85d…af7df0`), incorporated by reference word for word, with these substitutions only:
- In §2, `b2_sim.py` is joined by `v2/code/b2v2_sim.py` (gate driver, §6), and the role of `b2_build.py` is taken by `v2/code/b2v2_build.py`, which imports `b2_build.py` unchanged and differs only in its guard (DEVIATION D3).
- The wrapper tests §3.3 are not re-run for v2 (the code is unchanged and pinned); the v1 record `logs/TESTS_OUTPUT.txt` is cited by hash, and G1 re-checks all hashes on the DGX before any step.

## 6. Synthetic validity gate. **Must PASS before lock.**

**Generator §6.1: identical to v1** (Q 467, batch-1 k multiset and categories, pseudo-word pools, band lengths, styles, uniform key, confound ladder p_Q ∈ {0.45, 0.60, 0.75}, planted `x` on the keyed option with selection `Random(20261033 + (s mod 4))`, arm-P pairs `Random(20261038)`, pooled primary at alpha 0.025, B 600). The functions are v1's, imported unchanged.

**Checks §6.2: identical to v1, seeds identical, except W's ladder.**
- **R:** v1 B1 command, 50 null datasets, seeds 20261100 + s, ≥ 25/50; first reproducing level used.
- **N1:** G and P, 200 null datasets, seeds 20261200 + s, at the reproduction level and 0.75; each arm ≤ 9/200.
- **N2:** 200 datasets, seeds 20261400 + s, `x` planted on the keyed option in 60% of questions (unchanged), then within-question shuffle seed 20261037 + s; each arm ≤ 9/200 at both levels.
- **W (changed, D1):** 50 datasets at the reproduction level, seeds 20261600 + s. Ladder **f = 0.30 → 0.60 → 0.75**. The first rung at which **both** arms reach ≥ 40/50 fixes f for §7.3 **for both arms**. If no rung qualifies, the gate FAILS (no usable power).
- Every step is recomputed from scratch into `v2/sim/` by `b2v2_sim.py`; no v1 output file is reused. Because the seeds and code are the same, R, N1, N2 and the W rungs 0.30 and 0.60 are expected to equal v1's exactly; any difference is reported, and the v2 numbers are the ones that count.
- **A gate failure means v2 is NOT RUN.** Thresholds are never loosened, and no real data is scored.

### 6.3 Gate result (filled in at lock, only on PASS)
`v2/sim/B2V2_SIM_GATE.json`, sha256 `e1932d45983e3d1e0345caa7c7aad5da9d491d93438d80c781c3c1317951b78a`. Result: **PASS**. Reproduction level p_Q = **0.6**. Planted fraction **f = 0.75** for §7.3.
| Step | DISQUALIFIED | Limit | Pass |
|---|---|---|---|
| R_0.45 | 21/50; kcount_auroc_mean 0.6149; unique_token_share_mean 0.4726 | >= 25/50 (first level that holds) | no |
| R_0.6 | 25/50; kcount_auroc_mean 0.6149; unique_token_share_mean 0.6225 | >= 25/50 (first level that holds) | yes |
| N1_0.6 | G 0/200, P 5/200 | <= 9/200 per arm | yes |
| N1_0.75 | G 3/200, P 5/200 | <= 9/200 per arm | yes |
| N2_0.6 | G 1/200, P 6/200 | <= 9/200 per arm | yes |
| N2_0.75 | G 7/200, P 7/200 | <= 9/200 per arm | yes |
| W_0.3 | G 3/50, P 1/50 | >= 40/50 per arm, both arms at one rung | no |
| W_0.6 | G 49/50, P 32/50 | >= 40/50 per arm, both arms at one rung | no |
| W_0.75 | G 50/50, P 49/50 | >= 40/50 per arm, both arms at one rung | yes |

## 7. Real-data procedure

**Identical to v1 §7**, with f from v2 §6.3, `b2v2_build.py --lock <v2 sha> --f <f>` in place of `b2_build.py`, and outputs under `batch2/v2/data/` with hashes in `v2/B2V2_DATA_MANIFEST.json`. HLE item files never leave the DGX; only aggregates do. At f = 0.75, round(0.75 · 467) = 350 questions are marked in each planted copy.

## 8. Data-reuse disclosure

**Identical to v1 §8**, plus, binding wherever a v2 result is shown:
- "Batch 2 was first pre-registered as v1, whose synthetic check failed (the keyed-versus-one-wrong test missed a cue planted in 60% of questions too often). v2 changed only the planted-cue strength the method must catch, to 75% of questions, after seeing that synthetic result. No real HLE result existed at either point."
- A v2 PASS is validated only against a cue on the keyed option in 75% of questions.

## 9. Gates, verdicts and locking

**Identical to v1 §9**, with: G0 = this v2 file locked by hash, mirrored to the DGX, and published by Abe with a matching hash; G2 = `v2/sim/B2V2_SIM_GATE.json` says PASS. **Locking:** this file plus `PREREG_HLE_B2_v2.md.sha256`, mirrored to the DGX with a verified match, then published by Abe. No public commit by the executor.

## 10. Seeds

**Identical to v1 §10.** Added: v2 design pilot 20262900 + s, s = 0..29 (exploratory; never used for the gate or real data). W uses 20261600 + s at each of f = 0.30, 0.60, 0.75.

## 11. DGX budget

**Identical to v1 §11** (nice 19, ionice -c3, CPU only, ≤ 16 cores, 24 h gate cap, 4 h real-run cap, 10 GB). The v2 gate runs 14 workers. P854, P1109, farm_dispatch and kram_terrain are left alone.

## 12–14. Outputs, decisions, pre-lock exposure

**Identical to v1 §12–§14**, adding to §12's published list: this file, `b2v2_sim.py`, `b2v2_build.py` with `CODE_V2.sha256`, `B2V2_SIM_GATE.json`, the pilot script and summary, and the v1 `B2_SIM_GATE.json` (the failure). Added to §14: everyone involved has seen the v1 gate result above; it is synthetic and contains no HLE statistic.

## 15. Public page wording

**Identical to v1 §15**, with these exact changes:
- The PASS text's sentence "Both tests found a planted one-character cue in at least 3 of 4 copies" becomes "Both tests found a one-character cue planted on the keyed answer in {f_pct}% of questions in at least 3 of 4 copies", and its last sentence becomes "It does not rule out a cue too small to detect at this n (the method was validated only on a cue present in {f_pct}% of questions), and it is not new evidence beyond batch 1's data."
- The opening line of every outcome adds: "This is version 2 of the batch-2 plan; version 1 was not run because it failed its own synthetic check."
- The third `{gate_reason}` reads: "On synthetic data, the {arm} test missed a planted one-character cue too often ({n} of 50 at 75% of questions; 40 needed)".
- `{f_pct}` = 100 · f from §6.3, as an integer.

## DEVIATION (departures from v1; each written before the step it affects)

- **D1. W ladder extended to (0.30, 0.60, 0.75).** v1 §6.2 / A7 allowed only 0.30 then 0.60. Reason: v1 P reached 32/50 at 0.60. Evidence: design pilot (§0), 29/30 at 0.75. The 40/50 threshold, the 50 datasets, the seeds and the same-f-for-both-arms rule are unchanged. Effect: weaker validated sensitivity, disclosed in §8 and §15.
- **D2. New gate driver `b2v2_sim.py`.** It imports v1 `b2_sim.py` unchanged (pin-checked) and reuses its generator, `run_job`, `run_batch` and `count`; it differs only in the W ladder, output dir `v2/sim/` and summary file `B2V2_SIM_GATE.json`. Default 14 workers (v1: 12), which changes wall-clock time only.
- **D3. New build guard `b2v2_build.py`.** v1 `b2_build.py` hard-wires the v1 prereg and v1 gate file, so it cannot be used for v2. The v2 script imports it unchanged and reuses every function and constant; only the guard (v2 prereg hash, v2 gate PASS with planted_f) and output paths differ.
- **D4. Design pilot.** An exploratory synthetic pilot (seeds 20262900 + s) chose the rung. It is not a gate step and is disclosed with its hashes.
- **D5. Wording.** §8 and §15 additions above, so that every display states the 75% validated sensitivity and that v1 failed.
- Not changed: R/N1/N2/W thresholds (25/50, 9/200, 9/200, 40/50), the N2 planted fraction (0.60), all seeds, both arms, alpha 0.025 each, B, probes, the real-data procedure and verdict table.
