/teal-sea
teal-sea / zeta-labstate of record · compiled 02 Nov 2026 · revision b09fa4dd · source

Library · hunts/rung3_ball_production/RESULTS.md

RESULTS: rung 3, the Davenport-Heilbronn zero off the critical line, kernel-checked

4,002 words · 395 lines · source

Hunt #145, closed 2026-10-26. Grade: kernel-checked (Lean 4 v4.35.0-rc2, Mathlib 065356127b1d, zero sorry, only propext, Classical.choice and Quot.sound), pending external verification. The details below are in PILOT.md sections 9 to 13, RUNS.md and the production section of pilot.json. The result says nothing about RH (docs/08). On 2026-10-27 Lean's own kernel replayed the whole assembled closure into an empty environment and accepted it (leanchecker --fresh, section 3). That is a same-kernel replay, not an independent check, and it leaves the grade where it was. The same day a second kernel, con-ron --verified (different code), checked the closure split site by site on a fleet of cloud VMs: accepted by an independent checker on a site-wise split, with coverage shown (door 1, Stage B, section 3). That does not move the grade either: the ladder ends at kernel-checked, and no person has reviewed the result.

1. The theorems, exactly as compiled

What carries the result is one theorem, davenport_heilbronn_strip: some entire function with the Davenport-Heilbronn Dirichlet series for Re s > 1 and its functional equation has a zero in the open critical strip, off the line. It was added on 2026-10-26 (door 2 of section 6) in a module of its own, by a re-assembly of the same 215 site oleans. Before it, the result was two theorems read together: dh_separation_hundred (below height 100, DH has a zero in the open strip off the line, and Mathlib's riemannZeta has none there) and dh_zero_located (a zero of DH in the plan's closed square), with dh_analytic_half (lean/ZetaLean/DHAnalytic.lean: DH is entire, has the series for Re s > 1 and satisfies the functional equation). All of them have the grade above: kernel-checked, pending external verification. dh_separation_hundred still says more than the bundled theorem, since it adds the comparison with riemannZeta. The assembly's davenport_heilbronn is weaker than its name: the statement it proves is also met by the trivial zero s = -1, as the paragraphs after the second listing say.

In ZetaLean.DH.Rung3Assembly.Plan2 (module Rung3Assembly.Strip, emitted by assembly.py, SHA-256 c763fa289c8b7285... pinned in pilot.json assembly_emitted; it imports Rung3Assembly.Assembly alone, so it lies outside the sites' import closure, which ends at ZetaLean.BallCertSupport):

theorem davenport_heilbronn_strip :
    ∃ (f : ℂ → ℂ) (s : ℂ), Differentiable ℂ f ∧ dh_series_rep f ∧ dh_functional_eq f ∧
      f s = 0 ∧ 0 < s.re ∧ s.re < 1 ∧ s.re ≠ 1/2

The witness is f = DH and s is the zero of dh_zero_located, whose real part lies in [380821/500000, 26731/31250] = [0.761642, 0.855392]; linarith and norm_num give the three strip conditions from those two bounds. dh_analytic_half states only ∃ f, Differentiable ℂ f ∧ dh_series_rep f ∧ dh_functional_eq f and so hides its witness; the proof uses the three theorems it bundles (DH_differentiable, DH_series_rep, DH_functional_eq), as dh_analytic_half's own proof term does.

In ZetaLean.DH.Rung3Assembly.Plan2 (module Rung3Assembly.Assembly, emitted by assembly.py from lean/cert/rung3_plan2.json, SHA-256 5ae46eb4a6030349... pinned in pilot.json assembly_emitted):

theorem davenport_heilbronn : davenport_heilbronn_statement

theorem dh_zero_located : ∃ z : ℂ, DH z = 0 ∧
    z.re ∈ Icc ((808517/1000000 - 3/64 : ℚ) : ℝ) ((808517/1000000 + 3/64 : ℚ) : ℝ) ∧
    z.im ∈ Icc ((21424837/250000 - 3/64 : ℚ) : ℝ) ((21424837/250000 + 3/64 : ℚ) : ℝ)

theorem dh_zero_located' : ∃ z : ℂ, DH z = 0 ∧
    ((380821/500000 : ℚ) : ℝ) ≤ z.re ∧ |z.im - ((21424837/250000 : ℚ) : ℝ)| ≤ ((3/64 : ℚ) : ℝ)

dh_zero_located puts a zero of DH in the closed square of half-width 3/64 about 0.808517 + 85.699348 i. That is the plan's exact square; the task's rounded bounds (Re s ≥ 0.7619) do not follow from it.

davenport_heilbronn_statement (lean/ZetaLean/DavenportHeilbronn.lean, line 129) says: some entire function has the Davenport-Heilbronn Dirichlet series for Re s > 1, satisfies its functional equation, and has a zero s with Re s ≠ 1/2. As defined, it is also met by the trivial zero s = -1: DH combines the L-functions of two odd characters mod 5, which vanish at s = -1, -3, -5, …, so davenport_heilbronn_statement_of_trivial_zero (lean/ZetaLean/DHTrivialZero.lean) proves it from DH (-1) = 0 and dh_analytic_half alone, with none of the 215 sites. The same statement for riemannZeta holds at s = -2. The adversarial review of PR #353 found this on 2026-10-26. So davenport_heilbronn is a true theorem that carries none of the result; the definition stays as it is because the site oleans were compiled against its module.

In module Rung3Assembly.Separation:

theorem dh_separation_hundred :
    (∃ s : ℂ, DH s = 0 ∧ 0 < s.re ∧ s.re < 1 ∧ 0 < s.im ∧ s.im ≤ 100 ∧ s.re ≠ 1 / 2) ∧
      ∀ ρ : ℂ, riemannZeta ρ = 0 → 0 < ρ.re → ρ.re < 1 → 0 < ρ.im → ρ.im ≤ 100 →
        ρ.re = 1 / 2 :=
  dh_separation_of RHHeight100.rh_height_hundred

That is: below height 100, DH has a zero off the line in the open strip, and Mathlib's riemannZeta has none (hunt #137). Both functions satisfy a functional equation of the same shape; only one obeys RH there.

2. The axioms, verbatim

#print axioms of all 17 final declarations, from the on-box assembly (production.py assemble, log kept in the receipts):

'ZetaLean.DH.Rung3Assembly.Plan2.big_bottom' depends on axioms: [propext, Classical.choice, Quot.sound]
'ZetaLean.DH.Rung3Assembly.Plan2.big_top' depends on axioms: [propext, Classical.choice, Quot.sound]
'ZetaLean.DH.Rung3Assembly.Plan2.big_left' depends on axioms: [propext, Classical.choice, Quot.sound]
'ZetaLean.DH.Rung3Assembly.Plan2.big_right' depends on axioms: [propext, Classical.choice, Quot.sound]
'ZetaLean.DH.Rung3Assembly.Plan2.big_frontier' depends on axioms: [propext, Classical.choice, Quot.sound]
'ZetaLean.DH.Rung3Assembly.Plan2.deriv_bound_small' depends on axioms: [propext, Classical.choice, Quot.sound]
'ZetaLean.DH.Rung3Assembly.Plan2.small_bottom' depends on axioms: [propext, Classical.choice, Quot.sound]
'ZetaLean.DH.Rung3Assembly.Plan2.small_top' depends on axioms: [propext, Classical.choice, Quot.sound]
'ZetaLean.DH.Rung3Assembly.Plan2.small_left' depends on axioms: [propext, Classical.choice, Quot.sound]
'ZetaLean.DH.Rung3Assembly.Plan2.small_right' depends on axioms: [propext, Classical.choice, Quot.sound]
'ZetaLean.DH.Rung3Assembly.Plan2.small_frontier' depends on axioms: [propext, Classical.choice, Quot.sound]
'ZetaLean.DH.Rung3Assembly.Plan2.centre_small' depends on axioms: [propext, Classical.choice, Quot.sound]
'ZetaLean.DH.Rung3Assembly.Plan2.dh_zero_located' depends on axioms: [propext, Classical.choice, Quot.sound]
'ZetaLean.DH.Rung3Assembly.Plan2.dh_zero_located'' depends on axioms: [propext, Classical.choice, Quot.sound]
'ZetaLean.DH.Rung3Assembly.Plan2.davenport_heilbronn' depends on axioms: [propext, Classical.choice, Quot.sound]
'ZetaLean.DH.Rung3Assembly.Plan2.dh_separation_of' depends on axioms: [propext, Classical.choice, Quot.sound]
'ZetaLean.DH.Rung3Assembly.Plan2.dh_separation_hundred' depends on axioms: [propext, Classical.choice, Quot.sound]

Each of the 215 site theorems (upper_<id>, beta_<id>, centre_lt_centre) printed the same three axioms, in the per-job audit of rung3-production.yml.

The strip re-assembly (section 3) printed the same 17 lines, and this one for the new theorem (pilot.json production.strip_assembly, log in its receipts):

'ZetaLean.DH.Rung3Assembly.Plan2.davenport_heilbronn_strip' depends on axioms: [propext, Classical.choice, Quot.sound]

3. How it was built

Every receipt cited below as <cache>/rung3-ball-production-full/... or <cache>/rung3-conron-fleet-20261027 is in receipts/ under the same name (added 2026-10-30, home paths scrubbed, large files kept as digests; receipts/README.md). The site oleans' GitHub artifacts expire on 2026-11-25.

originconstantsin the closure of the 18in an accepted shard
the 215 sites761,387583,346761,387
Mathlib580,69061,25261,252
Lean's core182,9647,8697,869
dependencies19,389192192
hunt #13724,31122,28822,288
ZetaLean733411411
the assembly313012 (and the 18 final declarations through Rung3Glue)
all1,569,505675,388853,411

Every site constant is in an accepted shard, the 178,041 outside the closure included. Outside the sites the shards hold exactly the closure; the 716,076 constants in no shard are all outside it (Mathlib 519,438, core 175,095, dependencies 19,197, hunt #137 2,023, ZetaLean 322, the assembly 1), and Stage A's replay covered them with Lean's kernel. The planted one-byte fault, exported as a whole site shard, was rejected on both providers (section 4). Wall: the first VM at 15:07, the last deleted at 19:12, set by the centre, whose shard took 3.2 hours on 8 cores (24.8 core-hours, 14.8 GB peak RSS); 834 core-hours of con-ron in all. Cost: InstaBox USD 8.25 (its usage API, per machine), Novita USD 0.68 at list price; 222 VM creations in vms.jsonl (pilot.json counts 220, because its record skips creations with no provider id), none left on either provider. Receipts: <cache>/rung3-conron-fleet-20261027 (the state files, the VM registry, every receipt, manifest and log); record: pilot.json production.replay.stage_b_fleet; RUNS.md has the run.

4. What the kernel refused

All on production output, recorded in pilot.json production.box_faults and production.fault_run:

planted faultrefused at
a prime tower's radius one unit of 2^-64 low (runner, run 40372531479)Prime_B_right_06_2.ev_whole
the same, on this box against the downloaded oleansPrime_B_right_06_2.ev_whole
the tail radius just under its boundZetaLean.DH.Cert.enc_B_right_06
M just under the enclosure's boundZetaLean.DH.Cert.upper_B_right_06
the centre's eps' at the bound, and at 1/4000centre_lt_centre (the probe of its last step)
the tower radius one unit low, one byte of a scratch CB_right_06/Primes.olean, exported as a whole site shard and checked by con-ron --verified on InstaBox and on Novita (door 1, Stage B)Prime_B_right_06_2.ev_whole._proof_1_1, "application type mismatch", on both

The eps' bracket holds: the probe is accepted at 1/2000 and at the next multiple of 2^-64 above the bound, and refused at the bound and at 1/4000.

On the strip theorem, two faults were planted in scratch copies of Strip.lean, compiled against the re-assembled environment (production.py strip-faults; pilot.json production.strip_assembly.strip_faults). Lean refused both at davenport_heilbronn_strip, in its tactics, before any proof term reached the kernel:

planted fault in the statementLean's error
s.re < 19/25 (0.76, just left of the square's edge 0.761642) for s.re < 1linarith failed to find a contradiction
s.re ≠ 4/5 (a line through the square) for s.re ≠ 1/2unsolved goals

The unchanged copy, compiled the same way, was accepted.

For door 1 a fault went into a compiled olean itself (pilot.json production.replay.olean_fault). In a scratch copy of the downloaded CB_right_06/Primes.olean, the radius literal of Prime_B_right_06_2.Sq_10, 36391283805789411/2^63, was lowered by one unit: one byte of the file, the literal's only occurrence. leanchecker CB_right_06.Primes accepts the unchanged olean and refuses the copy at Prime_B_right_06_2.ev_whole._proof_1_1 with "(kernel) application type mismatch", the decision no longer evaluating to true. Exported, the two differ in one record, and con-ron --verified accepts the clean export and rejects the planted one at the same declaration, with the same error.

The standing test tests/test_epstein.py::test_no_offline_zero_below_the_pinned_one passes. It is measured, not rigorous: the mpmath argument principle at 20 digits counts no zero with Re s in [0.55, 2] and 0.3 < Im s < 80.3, and one with 80.3 < Im s < 90.3. Within that range, which covers non-trivial zeros only and leaves out 1/2 < Re s < 0.55 and 0 < Im s ≤ 0.3, no off-line zero lies below this one, so the target was forced there, not chosen.

5. What this is and is not

6. The doors

This hunt priced a production and then ran it; the ceiling it measured is the cost of the kernel check. Active constraints at the optimum, by measured cost share:

  1. The non-tower work dominates now: on the pilot site, composites, terms and root are 112 of 164 CPU-s in whole mode (PILOT.md section 9); other sites were not split.
  2. The per-module import, 11 CPU-s on the box, is the floor of every module.
  3. Peak RSS of the centre (11.3 GB) is the constraint that fixes one Lean process per runner.

The tower cost, 416 projected core-hours staged, is no longer binding at 16 runner core-hours.

The frozen-constant inventory (chosen, not optimized):

Of these, two have genuine trade shape. The decision procedure for composites and terms (measured 0.5 CPU-s against 1.8 for one kappa product, PILOT section 7) trades a generator change for most of the remaining cost. The plan's square (w, eps') trades the number of sites against K.

The information class of each door:

  1. An independent kernel replay of the assembled environment, which reads more: the same oleans in another checker. Stage A done, 2026-10-27: the same-kernel fresh replay (section 3) accepted the closure of all 18 final declarations; it is not the independent half. Stage B done, 2026-10-27, site by site (section 3): accepted by an independent checker on a site-wise split, with coverage shown; 834 core-hours of con-ron on cloud VMs, USD 8.93. The pricing that came first, for one run over the whole closure: on samples, con-ron accepted the exported closure of upper_B_right_06 (61,782 declarations, 690 s, 2.2 GB) and of the centre's towers for p = 2, 401 and 1801 (26,575 declarations), and rejected the one-byte olean fault at Prime_B_right_06_2.ev_whole (section 4). Those are second-kernel acceptances of samples, not of the theorem. The whole closure would be an export of 14 to 15 GB (20 to 30 minutes at 30 to 40 GB, by the samples) and a con-ron run at 56 to 102 GB of peak RSS whose 15,608 whole-tower decisions alone cost about 1,300 core-hours: each took 16 s at p = 2, 400 s at p = 401 and 648 s at p = 1801, against about 1 s in Lean's kernel. That is 81 hours of wall at 16 workers, past this box's 24-hour and memory bounds, so it waits for a machine of about 128 GB and 64 cores (about 20 hours). Exporting site by site would hold con-ron to about 4 GB a run but not cut the CPU, and would leave the assembly's own closure to check apart. That is what ran: the VMs' cores did a tower in about half the time this box's did, and the assembly's closure became the glued top shard. RUNS.md has the samples and the run.
  2. Done, 2026-10-26. A bundled strip statement, inside the data the current family reads. The theorem, in module Rung3Assembly.Strip, emitted by assembly.py (STRIP_STATEMENT, pinned by the hunt test) and importing Rung3Assembly.Assembly alone, outside the sites' import closure: theorem davenport_heilbronn_strip : ∃ (f : ℂ → ℂ) (s : ℂ), Differentiable ℂ f ∧ dh_series_rep f ∧ dh_functional_eq f ∧ f s = 0 ∧ 0 < s.re ∧ s.re < 1 ∧ s.re ≠ 1/2. It compiled by re-running production.py collect and assemble on the box, and it prints propext, Classical.choice and Quot.sound only (section 2). Both planted faults in the strip condition were refused (section 4). It replaces the reading-together of dh_separation_hundred and dh_analytic_half, and davenport_heilbronn_statement, which the trivial zero s = -1 meets. Cost: 116.8 CPU-s for collect and 114.4 CPU-s of Lean for assemble, against 106 and 118 the first time. Receipts: <cache>/rung3-ball-production-full/receipts-strip-20261026 (the zips' SHA-256 in collected.json, the 215 root and the assembly oleans' SHA-256, the ZetaLean build's SHA-256 before and after, the emitted sources, the fault copies and every log).
  3. Composites and terms by decide +kernel, inside the data the current family reads.
  4. A smaller square or a different eps', inside the same data, but it needs a new plan and mirror validation.
  5. The next off-line zeros (Spira's 114.16, 166.48, 176.70), which read more: new plans. Allocation among these is the owner's.

Doors 1 and 2 are cheapest before the site oleans' GitHub artifacts expire, about 2026-11-25 (30-day retention from run 40353536947). The box kept only their SHA-256 and the logs, so after that date both need the 215 sites compiled again, 16.1 runner core-hours at the measured rate. Doors 1 and 2 are both done, so the deadline binds neither now; the exports' SHA-256 and manifests are kept, not the exports.