# Method changelog — the Patoshi audit

The complete, unedited change log of the classifier work, published as the
accountability receipt the article's method box refers to. Commitment receipt:
labels_frozen.tsv sha256 `196800166a09ea30376939842c9c4597b44b3f3c8e29f45fbe8bbb8dc790c2ea`,
committed 2026-09-01 16:41 UTC (git 96c05d48), BEFORE any block-level comparison
with public lists; `freeze.py` regenerates the file byte-identically. Files cited
below that are not in this folder are internal working receipts, retained in the
audit workspace and included in the code release when it is published.


## 2026-09-01 v1 first run (pre-registered params)
GAP_MAX=1000, RESID_ABS=30, RESID_SIGMA=3, SLOPE=[1,12], MIN_LEN=20, greedy online attach.
Result: **15,803** in-window (1–54,316); tiers high=26/med=5,448/low=10,329; 21,445 segments
(4,310 of them <20 length); ambiguity 53% (heights 1–20k); early range 1–13,200 → 7,896.
labels sha256 77d9d863…ad344. Logged in classifier_firstrun.txt (never overwritten).

## 2026-09-01 v2 (algorithmic change + sweep, BEFORE any diff vs external lists)
Deficiency diagnosed from INTERNAL signals only (segment-length histogram, ambiguity rate):
greedy attach fragments long runs; real Patoshi segments (resets ~every 100h) should span
hundreds of blocks. v2 = v1 greedy pass + collinear MERGE pass (adjacent segments joined if
gap ≤ GAP_MAX, extranonce continues ascending within BACKSLIP=50, merged slope in bounds,
merged RMSE ≤ MERGE_RMSE_CAP) + parameter sweep.

**Pre-registered selection criterion (fixed before the sweep ran):** the winning
configuration minimizes global BIC = Σ_seg[n_s·ln(max(RSS_s/n_s, 0.1))] + 3·k·ln(N) over
the full segmentation. Published aggregate counts (~22k etc.) are EXCLUDED from selection.
Sweep grid: RESID_ABS ∈ {30,100,300} × MERGE_RMSE_CAP ∈ {none,50,150} × SLOPE_LO ∈ {0.5,1}
× SLOPE_HI ∈ {12,20} × MIN_LEN ∈ {20,50}. All 72 results published as the B2 curve.

## 2026-09-01 sweep result + criterion amendment (logged before anchor test ran)
Sweep done (data/sweep.tsv). BIC is invariant to qualification params (slope bounds,
min_len) — it only selects the segmentation: (RESID_ABS=30, MERGE=None) wins, BIC 896,291.
v2 greedy differs from v1 (bootstrap slope window [0.25,40], strict best-candidate):
no-merge totals moved 15,803→16,231 at slope_lo=1.0 (recorded, not tuned to targets).
AMENDMENT: qualification params selected by recall/precision on the pre-registered anchor
set ONLY (SPEC B2: positives = block 9, 5326, Whale Alert's 19 spent blocks; negatives =
block 12, 3654), tie-break = fewest qualifying segments. Aggregate literature counts remain
excluded from selection.

## 2026-09-01 v3 (algorithmic change, logged before implementation ran)
Anchor test on v2 segmentation: best = 16/19 positives with 1 negative hit; min_len=50
collapses recall. Diagnosis: greedy online attach cannot separate interleaved miners.
v3 = windowed RANSAC: sliding 2,000-height windows (stride 1,000), iterative dominant-line
extraction (fixed seed 42), inliers |resid|<=TOL, line kept if longest contiguous run
(gap<=1,000) has >= 20 members; cross-window collinear merge. TOL swept {15,30,60}.
Selection: same amended criterion (anchor recall/precision, tie-break fewer segments).

## 2026-09-01 slope-floor amendment (FINDING, logged before retest)
v3 diagnosis: anchor misses are all LOW-SLOPE lines — the earliest Patoshi band (heights
1–1998, contains Finney block 9 and 688) fits slope ~0.18-0.24 extranonce/block; block 2485
on slope 0.17. Published slope prose (BitMEX "~4/block", range 1.1–10) describes post-mid-
2009 epochs only. This divergence is itself a reportable finding (SPEC §4 low-confidence
item). AMENDMENT: SLOPE_LO 0.15 (was 0.5/1.0), justified solely by pre-registered anchor
blocks; negative anchors (12, 3654) must remain excluded — if 3654 enters at 0.15 the
config is rejected per criterion.

## 2026-09-01 FREEZE (criterion-selected winner)
Winner by amended criterion (max anchor recall, 0 negative hits, tie-break fewest
qualifying lines): tol=60, slope [0.15, 12.0], min_len=50 → anchors 18/19 (missed: to be
reported), negatives excluded, in-window 23,466. The 19/19 config (ml=20) re-admits known-
negative 3654 → rejected. Range across all neg-0 configs: 17,708–23,466 (published as the
sensitivity curve). v1 first-run 15,803 published alongside per B-1.

## 2026-09-01 verification pass (26/27 VERIFIED, 1 REFUTED)
Adversarial workflow re-derived every headline number independently: all exact. REFUTED:
"nobody ever checked the Sep-2024 five" — Lopp tweeted the check same-day (tweet
1837139429153968543: "None of these blocks fall into the Patoshi Pattern"), echoed on
bitcointalk 5509946. Reframe: no publication/paper ran it; the only check leaned on the
public list; ours is the first independent re-derivation, and it flags 2455 (medium grade)
where Lopp's list-based call said clear — report as a disagreement-at-the-boundary, below
our positive bar. Verification report: verification-report.md.

## 2026-09-01 final-audit fixes (7-lens verdict: FIX-THEN-SHIP; all applied)
- B1 TIMEZONE: first export rendered spend_date in the build machine's local timezone
  rather than UTC, shifting 10,178
  CSV rows and 16 table cells one day late. Exporter now forces UTC (scripts/
  export_article_data.py, anchor-asserted); dataset + article regenerated.
- B2 SWEEP BOUND: published upper bound corrected 25,604→23,466. 25,604 came from a
  neg-1 config (re-admits anchor 3654) that the FREEZE entry above had already rejected;
  the published range is the committed neg-0 range 17,708–23,466, and the frozen set is
  the TOP of the range, not a centre. Full sweep TSV now ships with the article.
- TIER FORMULA AMENDMENT (logged, was silent): the frozen tier formula omits SPEC B2's
  draft "interior" clause. As implemented: high = qualifying line n>=200, resid<=30,
  height<20,000; medium = other qualifying <20,000; low = qualifying >=20,000. The exact
  formula is now stated in the article's method box and reproduced by scripts/freeze.py,
  which regenerates labels_frozen.tsv BYTE-IDENTICALLY (sha 1968001… verified).
- ANCHOR DISCLOSURE: 18/19 recall + the 15625 miss now in Table 1 and the method prose.
- Pre-registration language reworded to the defensible version; "fewer than anyone has
  published" superlative removed; Lopp no longer miscredited as list maintainer; the
  17 May 2010 story corrected (night, 11-of-12 on the list, two weeks AFTER the last
  attributed block 54,304); "almost all" → two-thirds; eleven not a dozen stragglers,
  with the high-grade 2577 flagged as the one genuine puzzle; docs links fixed;
  clear/cleared polarity split resolved; coin/BTC units standardized.
- External validation receipt saved (data/external-validation-receipt.tsv, fresh run).

## 2026-09-02 round-4 red-team fixes (10-lens; FIX-THEN-SHIP, all applied)
- B4-1: shipped classifier-sweep.tsv was the stale pre-amendment grid (no slope_lo=0.15
  rows). classifier3.py grid extended to (0.15, 0.5, 1.0), full 36-config rerun: frozen
  row reproduces exactly (tp=18, fp=0, in_window=23,466) and 23,466 is the true fp=0
  maximum. Published range selection rule (stated on-page): fp=0 AND anchor recall >=15
  of 19, which reproduces 17,708–23,466. anchors.tsv (19 pos + 2 neg) now published.
- M4-1 NOISE DISCLOSURE (new science, three mutually confirming tests): era-adjusted FP
  rate predicts 3,009–3,761 in-window false positives among non-list rule-A blocks vs
  3,538 observed ours-only additions (per-tier match: high 65 vs ~61, medium 528 vs
  ~511); extranonce shuffled within 5,000-block windows still yields 15,731 flags; all
  22 high+medium timestamp inversions occur at ours-only junctions (overlap-only
  0/14,397). CONCLUSION now on the page: additions beyond the list are candidates, never
  discoveries; defended core = the 19,928-block overlap; inversion claim scoped to the
  high grade with the ~66-expected null stated.
- M4-3 completed round-3's pre-registration fix (method box clause), disclosed the
  slope-floor amendment's size in prose, and reworded anchors as the threshold-SELECTION
  set ("tested", not "validated", for the out-of-loop checks).
- M4-4 Lopp: "re-audited since 2020" claim corrected (his 2022 essay carried an
  aggregate spent count); credit reworded. M4-5: 2577 reframed as a disagreement with
  Whale Alert's FP adjudication. M4-6: merged-refit residuals >60 explained (README +
  method box). M4-7: FAQ now visible on-page (mirrors JSON-LD). M4-8: Lerner-privacy
  paragraph added.
- Minors: CSV spend_txid lowercased; Table-3 "beyond list coverage" marker; tier-formula
  height wording; "measured and reported here"; repeated waves; Fig-4 caption
  (Chain.info check, "meets the bar", Lerner's data not "the public list"); Lerner 550
  quoted precisely ("paid to other people as donations"); co-spend + line-diagnostic
  sentences added to §04; README 50-BTC line and resid notes; unused agreement fields
  dropped from the data JSON.
- SPEC deltas logged: C4 destination tracing covered first hops only (all 28 awakened
  coins; no exchange labels found), summarized in one sentence in the article. No deeper
  tracing was performed, per the audit's privacy rules. E4 public code repo DEFERRED pending maintainer approval — freeze.py + classifier3.py reproduce the frozen file
  byte-identically in the meantime.
- Round-4 confirmations: 189/189 external spend-status checks clean; fresh cluster
  census exact (27,625 spends); zero era-coin movements after the as-of through block
  965,063; freeze-before-diff git receipt verified.

## 2026-09-02 addendum to the FREEZE entry (do not edit history above)
Under the corrected 36-row sweep (slope_lo grid now 0.15/0.5/1.0), configurations with
anchor_fp=0 alone reach as low as 15,880 in-window blocks, at anchor recall 10/19. The
published range 17,708–23,466 applies the full stated rule: anchor_fp=0 AND anchor
recall >= 15 of 19, which reproduces both endpoints exactly against the shipped file.

## 2026-09-02 round-5 meta-audit fixes (6 lenses; SHIP AFTER FIX LIST — all applied)
- B1 standfirst "since 2022" falsified by the Feb/Apr-2022 awakenings → mirrors the body.
- B2 the C4 log entry above corrected (was claiming published destination content that
  did not exist); a first-hop summary sentence now actually appears in §04.
- B3 the external spend-status receipt was 181 rows against a "189/189" claim; the 8
  spent ours-only outputs (incl. all 3 borderline blocks 2455/27742/27693) were checked
  against mempool.space and appended: 8/8 match. 189/189 is now fully receipted.
- B4 export_article_data.py now writes the method-changelog commitment preamble
  programmatically (a re-run previously clobbered it).
- B5 the E0/E-M1 post-publish per-output monitor: DEFERRED as an explicit decision —
  planned but not yet built; to be stood up at publication or logged dead.
- M1/M2 FAQ relocated below the method box and deduplicated against §05/Glance;
  restraint paragraph now closes §05. M3 exposure sentence added: candidates hold
  28,200 BTC of the unmoved 1,023,352; the agreed core alone holds 995,152 (97.2%).
- M4 ours-only junction inversions restated honestly: ~2x the background rate (22/1,112
  = 1.98% vs 0.92%), not "close to" it. M5 Table-1 inversion row now computed (5,836
  height-adjacent pairs, 8,328 successive, both 0) and labelled.
- Wording: "same hour" → "within three quarters of an hour"; 2577/Whale-Alert sentence
  hedged (WA's discard pool is unpublished — "a sieve this block would have fallen
  into"); record-box 2455 line; tracker-positioning sentence added to §01.
- Deltas now logged rather than silent: C5 reduced to the FPR measurement plus a
  minimum-detectable-operation sentence (an operation under ~50 blocks on one line is
  invisible); Rule A' (Whale Alert's time-varying nonce bands) DROPPED — the refined
  ranges are partially unpublished prose and cannot be reproduced faithfully; the B3
  spacing-cliff out-of-sample check DROPPED (inversions + spend-gradient + list
  agreement carry the validation); D-M2 single quotable sentence folded into §05's
  closing lines; A0 engine details recorded in the internal workspace notes; E-M2 Whale
  Alert list check: still unreleased as of 2026-09-02; FAQ maintained in two synced
  copies (visible + JSON-LD) by hand; BIP30 twins sit outside the era window.
- Provenance hardening: bensig repo commit pinned in README; as-of block hash for
  965,051 recorded; satoshiblocks.info/about.html archived to the Wayback Machine;
  scripts/__pycache__ removed from git. An article-local universal-negative guard was
  added to build-satoshi-audit.js instead of widening the site-wide editorial gate.
- Per-grade expected-FP figures in the round-4 entry are model-variant dependent
  (high 61–64, medium 511–537); all variants sit inside the stated 3,009–3,761 band.
- Clarification: the anchor set is 21 blocks total — 19 positives (Whale Alert's
  spent-block list, which includes 9 and 5326) plus 2 negatives (12, 3654).
- Provenance pins: bensig/patoshi-addresses at commit 414637ce52aa (2025-07-15); block
  965,051 hash 0000000000000000000036235ce11301afd8500998c9eb05375301d6ff40cab6.

- Publication hygiene (2026-09-02): the published changelog's commitment timestamp is
  now stated in UTC, and one local-timezone mention was generalized; no method content
  changed.

## 2026-09-02 pre-merge editorial + opsec pass (all applied)
- Leak scan (2 lenses): no endpoints, credentials, personal data, EXIF, or addresses in
  any published byte; the changelog's local-timezone tells removed, the internal tracing
  filename and infrastructure-shape wording dropped, internal receipt citations labelled.
- Whole-piece AI-cadence pass (hostile reviewer + house-checklist editor): removed twin
  verbless triads, the "honest/honesty" tic (6→1), personified abstractions, hedge
  stacks, announce-then-demonstrate openers and the signpost sentence; contamination
  paragraph rewritten in plain language; "coinbase" defined at first use; "widely
  believed" replaced with the attributed chain of researchers; FAQ deduplicated against
  Glance; keyword placed naturally in §05. No number changed.
