Skip to content

Put the deposit inside the gap it is meant to prove - #30

Merged
Wired4ncer merged 1 commit into
mainfrom
fix/proof-window-off-by-one
Aug 9, 2026
Merged

Wired4ncer merged 1 commit into
mainfrom
fix/proof-window-off-by-one

Conversation

@Wired4ncer

Copy link
Copy Markdown
Owner

The first real run of tools/induced_gap_proof.py reported a failure that was not one — the failure mode a proof script can least afford, since it points the finger at the code it is supposed to be checking.

What happened

found a coin created at height 961769 and spent at 961770 — watching it
follower starts at 961769

  FAIL  the deposit was seen (INCOMING)  (directions [])
  FAIL  the spend raised the alarm (OUTGOING)  (directions [])

A follower treats its own tip as already applied. The script chose that tip with max(created_index - 1, 0), so when the coin turned out to be in the first block of the window — which is what the chain handed us on the very first try — the clamp put the tip on the deposit's own block.

The deposit was therefore never inside the induced gap, never applied, and the spend that followed matched nothing. Two FAILs that look exactly like a broken reconciler and are nothing of the kind.

It now starts on the block before the window in that case, and reports clearly if that block cannot be read.

A check that passed for the wrong reason

The same run exposed this:

  PASS  the coin left the record when spent

…on a run where the coin was never in the record at all. An empty outpoint set is also what you get when nothing was ever added, so the check was vacuous precisely when it mattered most. It is now conditioned on the deposit having been seen.

What the run did prove

Worth recording, because this is the half no fixture can reach:

  • 34,247 real mainnet transactions parsed, zero malformed. Until now the parser had only ever seen synthetic fixtures; this is real taproot, real multisig, real everything.
  • Catch-up refetched exactly the five missed blocks, applied them in order, and landed on the tip.
  • 29,402 transactions folded into the record without incident.

The repair machinery worked. It was handed a gap with nothing in it.

Regression test

test_a_coin_in_the_first_block_of_the_window_is_still_inside_the_gap builds exactly that shape and requires a pass. It fails against the old clamp.

One test was written and then deleted rather than kept: an attempt to assert the vacuous-pass case through run() turned out to be unreachable, because the script only proceeds when it has found a deposit and spend inside the window. The conditioned check stays as defence in depth, with the reasoning in a comment where the condition is; a test asserting an unreachable state is noise that later readers have to disprove.

Checks

194 tests, ruff clean. Issue #24 stays open until a run passes end to end.

Refs #24

🤖 Generated with Claude Code

The first real run reported a failure that was not one, which is the failure
mode a proof script can least afford.

A follower treats its own tip as already applied. The script set that tip to
`max(created_index - 1, 0)`, so when the coin turned out to be in the *first*
block of the window -- which is what the chain handed us on the first try -- the
clamp put the follower's tip on the deposit's own block. The deposit was
therefore never inside the induced gap, never applied, and the spend that
followed matched nothing. Output: two FAILs that looked exactly like a broken
reconciler and were nothing of the kind.

It now starts on the block before the window when the coin is in the first one,
and says so if that block cannot be read.

The same run exposed a check that passed for the wrong reason. "The coin left
the record when spent" asserted an empty outpoint set, which is also what you
get when nothing was ever added -- so it printed PASS on the one run where the
deposit was never seen. It is now conditioned on the deposit having been seen.

Worth recording what the run did prove, because it is the part no fixture can:
34,247 real mainnet transactions parsed with zero malformed, and catch-up
refetched exactly the missed blocks and landed on the tip. The machinery worked;
it was handed a gap with nothing in it.

Refs #24

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Wired4ncer
Wired4ncer merged commit 5096805 into main Aug 9, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant