/machines/1RB0RE_1RC0RA_0LD0RB_1LA0LE_1LC1LF_0LC---/rocq-plan.md · raw

W5-5 halting proof: Rocq plan

Target: Lemma halt: halts tm c0. in machines/1RB0RE_1RC0RA_0LD0RB_1LA0LE_1LC1LF_0LC---/1RB0RE_1RC0RA_0LD0RB_1LA0LE_1LC1LF_0LC---.v, passing tools/check_kill.sh --halt (compile cap 1800 s, ulimit -v 8000000, coqchk cap 600 s). Written 2026-10-13 after a design pass with small prototypes (section 6).

Verdict

Feasible with one machine-specific lemma family (the round) and one generic engine (a verified run-length macro simulator). The cycle model is never trusted: the checker re-derives every eat and every dirty carry by simulating the TM itself, and only the clean increments are taken from a proved closed form.

The riskiest pieces were prototyped (section 6): the round lemma and the clean counter call compile with plain es; a Python mirror of the exact planned simulator + batch arithmetic, written from the TM table only, reproduces the model's words on all checked cycles and halts in cycle 611,577 after 7,434 complete rounds, as predicted.

1. Run facts the design rests on (all measured this stage)

quantity value source
cycles (K0 to K0) 611,578 (0..611,577, halt in the last) fastabs2, 8 s
oracle rounds (carry into a dirty digit) 2,096,689 (3.4 per cycle) instrumented fastabs2
TM steps inside the counter, oracle rounds 3.45e8 (2.36e8 left of the clean low part; max 89k in one round) same
eat steps not proportional to c 8.8e7 in all (max 3,623 per eat); bell work 41.8 c per eat same
macro steps per plain round (any b) 38 (36 single + 2 block rules) Python mirror
macro steps per eat mean 187, max 318 (681 sampled eats) Python mirror
macro steps per oracle round mean 75, max 653 (2,399 sampled) Python mirror
batches per cycle 4.5 Python mirror
checker iterations, whole run about 5.4M (0.61M eats + 2.1M oracles + 2.7M batches) extrapolated
macro steps, whole run about 2.7e8 (1.14e8 eats + 1.6e8 oracles) extrapolated

Block rules the machine needs (all 3-cell, found by brute force over window contexts, shift_rule_R/L form with a fixed context d next to the head): - zigzag right over the bell: B, d = 10, 001 -> 001, 9 steps per block; - left sweep over the bell: C/D/E on the three rotations (010 -> 100, 001 -> 010, 100 -> 001), 3 steps; - counter carry left through trailing 2s: C, 100 -> 010, 5 steps; through a dirty run: C, 010 -> 100, 3 steps; - counter return right: C, d = 1, 100 -> 001, 9 steps. The simulator does not hard-code these; it tries contexts of 0..2 cells and keeps a rule when the window run exits forward in the same state with the context unchanged.

2. (a) Tape representation and the proved lemmas

The round-start form and the counter call (Prop side)

bellw b c = [1;0;1] ++ [0;0;1]^^b ++ [0;0;0;1] ++ [0;0;1]^^c
K X b c   = X <* [0] {{E}}> bellw b c *> 0inf          (X: the counter, a left stream, low cell first)
callw X X' = forall r, X <{{C}} 0 >> r -->* X' {{B}}> 0 >> r

A round starts with E1 -> 1LF, F0 -> 0LC: the head enters the counter's low cell in C. The counter call ends with the head back on the boundary cell (still 0) in B. Only then does the bell part run (zigzag, defect move, left sweep), and it ends with D0 -> 1LA, A1 -> 0RE on the boundary and the 101 cell, never reading X.

Clean digits and the call by induction

dg = Dm | D0 | D1 | D2        (001 = -1, 000 = 0, 101 = 1, 100 = 2; near-first cells [y;0;x])
cells ds                      (LSB first)
inc : list dg -> option (list dg)   (D2 passes the carry, the first other digit absorbs; None = overflow)

Batch lemma (n rounds) and its arithmetic

Checker data (computed side)

krec = { w : list code (3-cell codes, LSB first, 8 values); b : N; c : N }
denote k = K (wcells (w k) *> 0inf) (N.to_nat (b k)) (N.to_nat (c k))

The macro simulator (generic, used for oracle rounds, eats and the halt)

sd  = list (list Sym * N)          runs (block, count), near-first, then 0inf
cfg = Q * sd * sd * dn             dn = DL | DR: the head is on the first cell of L or of R

3. (b) Executing the 611,577 cycles inside Coq

next k := if b k = 0 then eat k                          (urun from kcfg k to the first K-form with b >= 1)
          else match batch k with Some k' => inl k'
               | None => oracle k end                     (urun from kcfg k to the next K-form)

4. (c) Opening and endgame

5. (d) Compile-time and memory

6. Prototype results (this stage)

Files: rocq/proto/round.v, rocq/proto/perf.v (compiled from a temp dir with the standard flags, ulimit -v 8000000; logs rocq/proto/*_out.txt), rocq/mirror/ (Python mirror and C instrumentation).

piece content result
round.v bellpart (bell part of a round, symbolic b and c) by plain es; round (two steps, follow H, evstep_refl); absm/abs0/abs1 by es; pass2 (do 5 step1. follow H. es.); callw_inc by list induction; round_inc all Qed, 1.9 s, Closed under the global context
perf.v executable part of the macro simulator in Coq (pop with rotation, push with merge, take, wsim, try_k contexts 0..2, mstep, run-aware isK, early-exit urun), run on the real K0 of cycle 611,000 (c = 1,217,710) returns b' = 1,217,710, the same as the Python mirror (181 macro steps); 2,000 such eats: 0.80 s vm_compute (2.2 µs per macro step), 0.32 s user with native_compute
mirror/macro.py + measure.py (needs fast2_all.txt from fastabs2 - 2 611578 40 1 in the working dir) the same algorithm in Python plus the batch arithmetic (no model input except the batch sizes) matches fastabs2's K0 word and c on 681 cycles (103 sampled from 1e5..6.1e5 and the last 578), and halts in cycle 611,577 after 7,434 complete rounds
mirror/shiftrules.py brute-force list of 3-cell shift rules with context 0..2 the rules in section 1
mirror/fa.c, fc.c fastabs2 instrumented: eat cost split, oracle counts, steps inside the dirty part the numbers in section 1

Extrapolated run cost: 2.7e8 macro steps at 2.2 µs is about 10 minutes of vm_compute (about 4 with native_compute), plus 2.7M batches of digit arithmetic. That leaves the 1800 s compile cap a 3x margin; the counter-only oracle variant (section 3) would cut it by about 30%.

Not prototyped: the simulator soundness proofs (routine but the largest piece), the batch arithmetic lemmas, chunking, and coqchk memory per chunk.

7. Work order (stages are non-blocking, about 2 h each)

  1. proof.md (CLAUDE.md: before the .v): K-form, round, clean increments, the checked-simulation argument for eats and dirty carries, the final halting round. Short, since the eat needs no closed form.
  2. Simulator + soundness (rocq/dev/macro.v): pop/push/take/wsim/try_rule/mstep/isK/urun and their specs. Test on the opening and on one real eat (urun result equals the extraction's).
  3. Batch (rocq/dev/batch.v): val, inc_val, inc_some, val_inj, rounds, padding/trim lemmas, batch.
  4. Checker, extraction, chunk generator: next, next_spec, run_ok, run_halt; extract, run all cycles, write k_i literals; smoke-test a prefix (c0 -->* denote k_100) under check_kill-like flags.
  5. Full file and check_kill --halt; then status.json, STATUS.md and the Eqv_v2 TM291 partner note.

8. Risks, most serious first

  1. Total VM time: about 600 s estimated (2.7e8 macro steps from the mirror times 2.2 µs measured in Coq). The margin to the 1800 s cap is about 3x; a slower real next (soundness-friendly data structures) eats into it. Mitigations: the counter-only oracle variant (-30%), native casts in a few large chunks, or check_kill --timeout, which needs Dennis's OK because the task names the default command.
  2. coqchk OOM on the first chunks: measure RSS early; shrink the chunks if needed (timeout is fine).
  3. Simulator soundness proofs: rotation, merging and the run-aware K parser are the fiddly stream equalities. Keep pop/push minimal and prove each against sdn with list lemmas only.
  4. Unhandled shapes make urun run long but never unsound. A fuel-out shows up in the extraction run before any Coq compile.
  5. Model trust is not a risk to soundness: the cycle model only supplies the batch sizes. If the model were wrong, the extraction run would not halt and nothing would be claimed.