← Session 21 — Tier ii′ planning + launch: close SfBoundProp in Lean (D-064)
thinking (10503 chars)
Documentation complete: NGUYEN.md Phase 5B checklist (committed), STATE.md resume point, D-064 design doc, journal-014, index.md + db.
Now session 015: ii′-1a — liCoeff pairing fix + summability proof.
Plan (from my earlier analysis):
1. Replace `liCoeff` def in LiSkeleton.lean with the paired form:
```lean
def liCoeff (n : ℕ) : ℂ :=
tsum fun ρ : {ρ : ℂ // IsNontrivialZero ρ} =>
(zeroMult ρ : ℂ) / 2 * ((1 - (1 - 1 / (ρ : ℂ)) ^ n) + (1 - (1 - 1 / (star (ρ : ℂ))) ^ n))
```
2. Prove `liCoeff_summable (n : ℕ) : Summable (fun ρ => ...)`.
3. Rebuild, axiom audit, commit.
First, let me develop the proof in Scratch.lean. Key lemmas needed:
- conj symmetry of the summand: f(star z) = star (f z) for f(z) = 1−(1−1/z)^n. So summand = mult/2 · (f + conj f) = mult · (f.re : ℂ).
- Bound: ‖summand ρ‖ ≤ 2n² · mult / ‖ρ‖² for ‖ρ‖ ≥ 2n.
- Comparison with zero_sum_inv_sq: ‖ρ‖² vs (1+‖gammaOf ρ‖²): (1+‖γ‖²) ≤ (9/4)‖ρ‖² for |γ| ≥ 1.
- Finite ball: {ρ : ‖ρ‖ < 2n} finite via IsCompact.inter_riemannZetaZeros_finite.
Wait — actually, let me reconsider the summand form. Simpler def form that's easier to work with:
```lean
def liCoeff (n : ℕ) : ℂ :=
tsum fun ρ : {ρ : ℂ // IsNontrivialZero ρ} =>
(zeroMult ρ : ℂ) * (((1 - (1 - 1 / (ρ : ℂ)) ^ n).re) : ℂ)
```
Using .re directly! Since (f + conj f)/2 = f.re, the two forms are equal. The .re form is cleaner: summand = mult · Re(f ρ) as a complex number. Correctness: same value as the paired form. But for the PROOF of correctness vs the classical λ_n, the paired form is more visibly "the symmetric sum". Hmm — but actually the .re form makes the reality manifest and the summability proof works directly on |Re f|. The paired form requires first proving f(conj z) = conj (f z). Both are fine; the .re form avoids the conj lemma entirely. However — mathematically, the REASON the .re form is the right λ_n is that the zero set is conj-invariant... no wait: Σ mult·Re f(ρ) over ALL zeros — is this the classical λ_n? Classical λ_n = Σ'_ρ f(ρ) (symmetric limit). The symmetric limit Σ_{|γ|≤T} f(ρ) — its real part = Σ Re f(ρ) and imaginary part → 0 by conj-symmetry (pairs cancel). So classical λ_n = lim Re Σ = Σ Re f (absolutely convergent as we prove). So yes Σ mult·Re f(ρ) = classical λ_n — BUT this identification needs conj-symmetry of the zero set to kill the imaginary part. For the DEFINITION, either form works; for downstream use (SfBoundProp, where Sf = SInfty + 1 − liCoeff.re), both give the same .re.
For the summability proof, the .re form: ‖mult · (Re f : ℂ)‖ = mult·|Re f| ≤ mult·|f| — that's the n/|ρ| bound again — NOT summable directly! The proof MUST use the tighter bound |Re f| ≤ 2n²/|ρ|², which comes from Re f(ρ) = nσ/|ρ|² + Re((S−n)/ρ). So the .re form is actually the one the proof naturally works with. And the paired form: (f(ρ) + f(ρ̄))/2 = Re f(ρ) requires the conj lemma to rewrite — but we can prove summability for the .re form directly and then show the paired form equals the .re form (via conj lemma) — or just USE the .re form.
Decision: use the paired form ½(f ρ + f ρ̄) as the def (it's the canonical "symmetric" form, self-documenting), and in the summability proof rewrite ½(f ρ + f ρ̄) = Re f(ρ) via the conj lemma (star is a ring endomorphism; f has real coefficients — a clean simp/field proof). Then bound |Re f|.
Actually — hold on. Is f(ρ̄) = conj(f(ρ)) needed, or trivially true? f(z) = 1 − (1 − 1/z)^n. conj(1 − (1−1/z)^n) = 1 − conj(1−1/z)^n = 1 − (conj(1−1/z))^n = 1 − (1 − conj(1/z))^n = 1 − (1 − 1/conj z)^n ✓ since conj(1/z) = 1/conj z. Yes — provable by simp [map_sub, map_one, map_div, map_pow, map_natCast?]. Fine.
Then (f ρ + f (star ρ))/2 = (f ρ + star (f ρ))/2 = ((f ρ).re : ℂ) by Complex.add_conj (z + star z = 2(z.re)) — `Complex.add_conj : z + star z = 2 * (z.re : ℂ)`. So ½(f+f̄) = re f. ✓
Now the analytic heart: |Re f(ρ)| ≤ 2n²/|ρ|² for ‖ρ‖ ≥ 2n (n ≥ 1).
Proof: f(ρ) = 1 − wⁿ, w = 1 − 1/ρ.
1 − wⁿ = −(wⁿ − 1) = −(w−1)·Σ_{j=0}^{n−1} w^j = (1/ρ)·S, S = Σ_{j<n} w^j (geom_sum: wⁿ−1 = (w−1)(Σ w^j) — `geom_sum_mul` or `mul_geom_sum`: (w−1)·Σ_{i<n} w^i = wⁿ−1 ✓ Mathlib has `geom_sum_mul` (CommRing).)
Re((1/ρ)·S) = Re(S/ρ).
S = n + (S − n); Re(S/ρ) = n·Re(1/ρ) + Re((S−n)/ρ).
Re(1/ρ) = ρ.re/‖ρ‖² (Complex.re_div? — `Complex.div_re` or for 1/z: `Complex.one_div_re : (1/z).re = z.re / ‖z‖²`? There's `Complex.div_re` and for inv: re(z⁻¹) = re z / ‖z‖² — `Complex.inv_re`?). In any case provable.
So Re f = n·ρ.re/‖ρ‖² + Re((S−n)/ρ).
|Re f| ≤ n·|ρ.re|/‖ρ‖² + |S−n|/‖ρ‖ ≤ n/‖ρ‖² + n²/‖ρ‖·(1/‖ρ‖)...
|S−n|: S−n = Σ_{j<n} (w^j − 1) = Σ_{j<n} (w−1)·Σ_{i<j} w^i: |w^j−1| ≤ |w−1|·j·M, M = max(1,|w|)^{n-1}. Hmm in Lean: |w^j − 1| = |w−1|·|Σ_{i<j} w^i| ≤ |w−1|·Σ_{i<j}|w|^i ≤ |w−1|·j·max(1,|w|)^j. Sum: |S−n| ≤ |w−1|·Σ_{j<n} j·max(1,|w|)^j ≤ |w−1|·max(1,|w|)^{n-1}·n(n−1)/2.
With |w−1| = 1/|ρ| and max(1,|w|) ≤ 1+1/|ρ| ≤ 1+1/(2n):
|S−n| ≤ (1/|ρ|)·(1+1/(2n))^n·n²/2 ≤ (1/|ρ|)·2·n²/2 = n²/|ρ| (using (1+1/(2n))^n ≤ e^{1/2} ≤ 2).
So |Re f| ≤ n·ρ.re/‖ρ‖² + n²/‖ρ‖² ≤ (n + n²)/‖ρ‖² ≤ 2n²/‖ρ‖² ✓ (n ≥ 1).
In Lean this is a chain of maybe 80–150 lines. The (1+1/(2n))^n ≤ 2 step: (1+x)^n ≤ exp(nx) for x ≥ 0 (Real.add_one_le_exp x: 1+x ≤ exp x; pow: (1+x)^n ≤ (exp x)^n = exp(nx) via Real.exp_nat_mul? (exp x)^n = exp(n·x) — `Real.exp_nat_mul`? There's `Real.exp_nat_mul (x : ℝ) (n : ℕ) : exp (n * x) = (exp x) ^ n`. ✓). Then exp(1/2) ≤ 2: `Real.exp_one_lt_d9` or just exp(1/2) < 2 via Real.exp_lt... exp(1/2) ≤ exp(1) ≤ 3 — or use exp(1/2)² = e ≤ 4 ⟹ exp(1/2) ≤ 2 ✓ clean: sq ≤ 4 → itself ≤ 2 (nonneg).
Then the comparison to zero_sum_inv_sq's family:
zero_sum_inv_sq (hs : ZetaSeam) : Summable (fun ρ : (zetaZeros hs).carrier => (zeroMult ρ : ℝ)/(1 + Complex.normSq (gammaOf ρ)))
The carrier: (zetaZeros hs).carrier — a Set ℂ; the subtype (zetaZeros hs).carrier = {ρ // ρ ∈ carrier}. Our index: {ρ // IsNontrivialZero ρ}. Need: (zetaZeros zetaSeam).carrier = {ρ | IsNontrivialZero ρ} as sets (then the subtypes are equivalent/identical). From SeamClosed.lean: `zetaZeroConfig := zetaZeros zetaSeam` and "simp lemmas at lines 28–38 relate zetaZeroConfig.N to Ncount" — there should be a `zetaZeros_carrier` lemma or the def zetaZeros itself: `zetaZeros (hs : ZetaSeam) : ZeroConfig` with carrier := {ρ | IsNontrivialZero ρ} presumably definitional. I'll check.
Then: Summable of the ℝ-family; multiply by constant: .mul_left (9/2 * n^2). Then dominate ‖summand‖:
- for ρ with 2n ≤ ‖ρ‖: ‖summand‖ = mult·|Re f| ≤ 2n²·mult/‖ρ‖² ≤ 2n²·(9/4)·mult/(1+‖γ‖²) = (9/2)n²·mult/(1+‖γ‖²) ✓ (the (9/4) factor: need (1+‖γ‖²) ≤ (9/4)‖ρ‖² ⟸ shown via 1+‖γ‖² ≤ 5/4+γ² and (9/4)‖ρ‖² ≥ (9/4)γ²... need 5/4+γ² ≤ (9/4)(σ²+γ²): since σ² ≥ 0: (9/4)(σ²+γ²) ≥ (9/4)γ² ≥ (9/4)γ²; and 5/4 + γ² ≤ (9/4)γ² ⟺ 5/4 ≤ 5/4·γ² ⟺ 1 ≤ γ² ✓ from |γ| ≥ ‖ρ‖−|σ|... hmm: ‖ρ‖² = σ²+γ² ≥ 4n² and σ ∈ (0,1) so |σ| < 1: γ² = ‖ρ‖²−σ² ≥ 4n²−1 ≥ 1 for n ≥ 1 ✓.)
Wait — careful with normSq vs ‖·‖²: gammaOf ρ = (ρ − 1/2)/I; ‖gammaOf ρ‖² = normSq (gammaOf ρ) = (γ)² + (σ − 1/2)²... gammaOf ρ = (ρ−1/2)/I = −I(ρ−1/2) = −I((σ−1/2) + iγ) = γ − i(σ−1/2): normSq = γ² + (σ−1/2)² ✓.
- for ρ with ‖ρ‖ < 2n: finite set (needs proof). Dominate by anything — use the finite-support modification.
Hmm — actually there's a slicker packaging avoiding the finite/infinite split: dominate ‖summand‖ ≤ mult·|Re f| ≤ mult·(2n²/‖ρ‖²) for ‖ρ‖ ≥ 2n, and for ‖ρ‖ < 2n use ‖summand‖ ≤ mult·(2·(2+1)^n)? For ‖ρ‖ < 2n: |f(ρ)| ≤ 1 + |1−1/ρ|^n — but 1/ρ can be huge (first zero has |ρ| ≈ 14.13 — bounded below! |ρ| ≥ 14.13 for ALL nontrivial zeros? The lowest zero is at 14.134 — so |1/ρ| ≤ 1/14 < 1, |1−1/ρ| ≤ 1+1/14, |f| ≤ 1 + (15/14)^n. So for ALL ρ: |Re f| ≤ |f| ≤ 1+(15/14)^n. Is |ρ| ≥ 14.13 available in Lean? That's the ROUCHÉ/numerical fact "no zeros below 14.13" — NOT available for free (needs a computation — it's part of RHUpTo?? No — RHUpTo says zeros up to 3e12 are on the line, not that none exist below 14.13. The nonexistence of zeros with |γ| < 14.13 is a numerical fact we'd need as... hmm, actually we can get a crude lower bound for free: zeros have |γ| ≥ ... hmm, is there ANY proved lower bound on the first zero's height in Mathlib/Zeta23? ZetaNoZerosInBox exists but that's about Re near 1. The strip zeros: is there a proved zero-free region near 0? For the SUMMABILITY we don't need the first-zero lower bound if we handle the finite part as a finite set — the finite part is finite REGARDLESS of what the zeros are (compactness). So: split at ‖ρ‖ = 2n: the ‖ρ‖ < 2n part is finite (compact ball ∩ zero set) — no bound needed at all, just finiteness. The ‖ρ‖ ≥ 2n part dominated by the (9/2)n²-mult/(1+‖γ‖²) family.
So packaging: g summable ⟸ (∀ρ, ‖g ρ‖ ≤ D ρ) with D summable, where D ρ = if 2n ≤ ‖ρ‖ then (9/2)n²·mult/(1+‖γ‖²) else ‖g ρ‖. D = D_summable_part + (D − D_summable_part) where the difference has finite support (the ball) ⟹ D summable. Then Summable.of_norm_bounded.
The finite support: {ρ : ¬(2n ≤ ‖(ρ:ℂ)‖)} = {ρ : ‖ρ‖ < 2n} ⊆ ball(0, 2n); ball compact; zeros ⊆ riemannZetaZeros; IsCompact.inter_riemannZetaZeros_finite (closed ball) ✓.
Alternatively even slicker: `Summable.of_norm_bounded` needs the dominator on ALL points — or use `summable_of_finite_support` for the inside + `Summable.of_norm_bounded` on a subtype... The "if-then-else dominator + finite-support difference" approach is standard. There's also `Summable.congr_finite`? Let me just write it.
One more consideration: the subtype index of zero_sum_inv_sq: `(zetaZeros hs).carrier` — elements are `{ρ // ρ ∈ (zetaZeros hs).carrier}` where carrier : Set ℂ. And `zetaZeros` — let me check its def: probably `def zetaZeros (hs : ZetaSeam) : ZeroConfig := ⟨{ρ | IsNontrivialZero ρ}, zeroMult, ...⟩`. If carrier is DEFINITIONALLY {ρ | IsNontrivialZero ρ}, then {ρ // ρ ∈ carrier} = {ρ // IsNontrivialZero ρ} definitionally — Summable transport is by congruence (funext on the family after `show`). Fine.
Let me check zetaZeros def + zeroMult coercion + gammaOf, then write the proof in Scratch.lean, iterate, merge into LiSkeleton.lean, rebuild, audit, close session.
Also need: `zeroMult ρ` for ρ : {ρ // IsNontrivialZero ρ} — the current liCoeff already uses `(zeroMult ρ : ℂ)` — so the coercion path exists ✓.
And the tie-in: after the def change, `Sf`/`SfBoundProp`/`LiVerifiedUpTo`/`lambda_pos_finite_height(_verified)` all recompile (they use liCoeff abstractly ✓).
Also update the liCoeff docstring (remove the honesty note, document the pairing + summability theorem + D-064 reference).
Let me start. First check zetaZeros def.
Documentation is complete and committed (7a395b2). Now **session 015 — sub-stage ii′-1a: liCoeff pairing fix + summability proof**.
tool: TodoWrite ok
input
{
"todos": [
{
"content": "Check zetaZeros carrier def + zeroMult/gammaOf coercion paths",
"status": "in_progress",
"activeForm": "Checking zetaZeros defs"
},
{
"content": "Develop summability proof in Scratch.lean (pair bound + comparison)",
"status": "pending",
"activeForm": "Developing summability proof"
},
{
"content": "Replace liCoeff def in LiSkeleton.lean + prove liCoeff_summable",
"status": "pending",
"activeForm": "Replacing liCoeff def"
},
{
"content": "Full rebuild + axiom audit (LiSkeleton/LiBasePoints unchanged downstream)",
"status": "pending",
"activeForm": "Rebuilding + auditing"
},
{
"content": "Session-015 closure (journal, STATE, NGUYEN checkoff, commit)",
"status": "pending",
"activeForm": "Closing session 015"
}
]
}
result 2026-08-21 19:10:10Z → 2026-08-29 04:31:50Z
{
"oldTodos": [
"content='Read current web/ files (settings, urls, models, views, healthcheck)' status='completed' active_form='Reading current web/ files'",
"content='Add VisitorLog model + tracking middleware' status='completed' active_form='Adding VisitorLog model + middleware'",
"content='Wire Django admin (settings, urls, admin.py)' status='completed' active_form='Wiring Django admin'",
"content='Add feedback email notification hook' status='completed' active_form='Adding feedback email hook'",
"content='Migrate + test locally (admin, visitor rows, feedback)' status='completed' active_form='Migrating + testing locally'",
"content='Deploy to server via SSH (files, prod settings, migrate, superuser, collectstatic)' status='in_progress' active_form='Deploying to server via SSH'",
"content='Verify live: /admin/ login, visitor log, feedback email' status='pending' active_form='Verifying live site'",
"content='Update RH-WEBSITE.md + memory' status='pending' active_form='Updating RH-WEBSITE.md + memory'"
],
"newTodos": [
"content='Read current web/ files (settings, urls, models, views, healthcheck)' status='completed' active_form='Reading current web/ files'",
"content='Add VisitorLog model + tracking middleware' status='completed' active_form='Adding VisitorLog model + middleware'",
"content='Wire Django admin (settings, urls, admin.py)' status='completed' active_form='Wiring Django admin'",
"content='Add feedback email notification hook' status='completed' active_form='Adding feedback email hook'",
"content='Migrate + test locally (admin, visitor rows, feedback)' status='completed' active_form='Migrating + testing locally'",
"content='Deploy to server via SSH (files, prod settings, migrate, superuser, collectstatic)' status='completed' active_form='Deploying to server via SSH'",
"content='Verify live: /admin/ login, visitor log, feedback email' status='completed' active_form='Verifying live site'",
"content='Update RH-WEBSITE.md + memory' status='completed' active_form='Updating RH-WEBSITE.md + memory'"
],
"cleared": true
}
raw content_json (database row)
[{"type":"thinking","thinking":"Documentation complete: NGUYEN.md Phase 5B checklist (committed), STATE.md resume point, D-064 design doc, journal-014, index.md + db. \n\nNow session 015: ii′-1a — liCoeff pairing fix + summability proof.\n\nPlan (from my earlier analysis):\n1. Replace `liCoeff` def in LiSkeleton.lean with the paired form:\n```lean\ndef liCoeff (n : ℕ) : ℂ :=\n tsum fun ρ : {ρ : ℂ // IsNontrivialZero ρ} =>\n (zeroMult ρ : ℂ) / 2 * ((1 - (1 - 1 / (ρ : ℂ)) ^ n) + (1 - (1 - 1 / (star (ρ : ℂ))) ^ n))\n```\n2. Prove `liCoeff_summable (n : ℕ) : Summable (fun ρ => ...)`.\n3. Rebuild, axiom audit, commit.\n\nFirst, let me develop the proof in Scratch.lean. Key lemmas needed:\n- conj symmetry of the summand: f(star z) = star (f z) for f(z) = 1−(1−1/z)^n. So summand = mult/2 · (f + conj f) = mult · (f.re : ℂ).\n- Bound: ‖summand ρ‖ ≤ 2n² · mult / ‖ρ‖² for ‖ρ‖ ≥ 2n.\n- Comparison with zero_sum_inv_sq: ‖ρ‖² vs (1+‖gammaOf ρ‖²): (1+‖γ‖²) ≤ (9/4)‖ρ‖² for |γ| ≥ 1.\n- Finite ball: {ρ : ‖ρ‖ < 2n} finite via IsCompact.inter_riemannZetaZeros_finite.\n\nWait — actually, let me reconsider the summand form. Simpler def form that's easier to work with:\n\n```lean\ndef liCoeff (n : ℕ) : ℂ :=\n tsum fun ρ : {ρ : ℂ // IsNontrivialZero ρ} =>\n (zeroMult ρ : ℂ) * (((1 - (1 - 1 / (ρ : ℂ)) ^ n).re) : ℂ)\n```\n\nUsing .re directly! Since (f + conj f)/2 = f.re, the two forms are equal. The .re form is cleaner: summand = mult · Re(f ρ) as a complex number. Correctness: same value as the paired form. But for the PROOF of correctness vs the classical λ_n, the paired form is more visibly \"the symmetric sum\". Hmm — but actually the .re form makes the reality manifest and the summability proof works directly on |Re f|. The paired form requires first proving f(conj z) = conj (f z). Both are fine; the .re form avoids the conj lemma entirely. However — mathematically, the REASON the .re form is the right λ_n is that the zero set is conj-invariant... no wait: Σ mult·Re f(ρ) over ALL zeros — is this the classical λ_n? Classical λ_n = Σ'_ρ f(ρ) (symmetric limit). The symmetric limit Σ_{|γ|≤T} f(ρ) — its real part = Σ Re f(ρ) and imaginary part → 0 by conj-symmetry (pairs cancel). So classical λ_n = lim Re Σ = Σ Re f (absolutely convergent as we prove). So yes Σ mult·Re f(ρ) = classical λ_n — BUT this identification needs conj-symmetry of the zero set to kill the imaginary part. For the DEFINITION, either form works; for downstream use (SfBoundProp, where Sf = SInfty + 1 − liCoeff.re), both give the same .re.\n\nFor the summability proof, the .re form: ‖mult · (Re f : ℂ)‖ = mult·|Re f| ≤ mult·|f| — that's the n/|ρ| bound again — NOT summable directly! The proof MUST use the tighter bound |Re f| ≤ 2n²/|ρ|², which comes from Re f(ρ) = nσ/|ρ|² + Re((S−n)/ρ). So the .re form is actually the one the proof naturally works with. And the paired form: (f(ρ) + f(ρ̄))/2 = Re f(ρ) requires the conj lemma to rewrite — but we can prove summability for the .re form directly and then show the paired form equals the .re form (via conj lemma) — or just USE the .re form.\n\nDecision: use the paired form ½(f ρ + f ρ̄) as the def (it's the canonical \"symmetric\" form, self-documenting), and in the summability proof rewrite ½(f ρ + f ρ̄) = Re f(ρ) via the conj lemma (star is a ring endomorphism; f has real coefficients — a clean simp/field proof). Then bound |Re f|.\n\nActually — hold on. Is f(ρ̄) = conj(f(ρ)) needed, or trivially true? f(z) = 1 − (1 − 1/z)^n. conj(1 − (1−1/z)^n) = 1 − conj(1−1/z)^n = 1 − (conj(1−1/z))^n = 1 − (1 − conj(1/z))^n = 1 − (1 − 1/conj z)^n ✓ since conj(1/z) = 1/conj z. Yes — provable by simp [map_sub, map_one, map_div, map_pow, map_natCast?]. Fine.\n\nThen (f ρ + f (star ρ))/2 = (f ρ + star (f ρ))/2 = ((f ρ).re : ℂ) by Complex.add_conj (z + star z = 2(z.re)) — `Complex.add_conj : z + star z = 2 * (z.re : ℂ)`. So ½(f+f̄) = re f. ✓\n\nNow the analytic heart: |Re f(ρ)| ≤ 2n²/|ρ|² for ‖ρ‖ ≥ 2n (n ≥ 1).\n\nProof: f(ρ) = 1 − wⁿ, w = 1 − 1/ρ.\n1 − wⁿ = −(wⁿ − 1) = −(w−1)·Σ_{j=0}^{n−1} w^j = (1/ρ)·S, S = Σ_{j<n} w^j (geom_sum: wⁿ−1 = (w−1)(Σ w^j) — `geom_sum_mul` or `mul_geom_sum`: (w−1)·Σ_{i<n} w^i = wⁿ−1 ✓ Mathlib has `geom_sum_mul` (CommRing).)\nRe((1/ρ)·S) = Re(S/ρ). \nS = n + (S − n); Re(S/ρ) = n·Re(1/ρ) + Re((S−n)/ρ).\nRe(1/ρ) = ρ.re/‖ρ‖² (Complex.re_div? — `Complex.div_re` or for 1/z: `Complex.one_div_re : (1/z).re = z.re / ‖z‖²`? There's `Complex.div_re` and for inv: re(z⁻¹) = re z / ‖z‖² — `Complex.inv_re`?). In any case provable.\nSo Re f = n·ρ.re/‖ρ‖² + Re((S−n)/ρ).\n|Re f| ≤ n·|ρ.re|/‖ρ‖² + |S−n|/‖ρ‖ ≤ n/‖ρ‖² + n²/‖ρ‖·(1/‖ρ‖)... \n\n|S−n|: S−n = Σ_{j<n} (w^j − 1) = Σ_{j<n} (w−1)·Σ_{i<j} w^i: |w^j−1| ≤ |w−1|·j·M, M = max(1,|w|)^{n-1}. Hmm in Lean: |w^j − 1| = |w−1|·|Σ_{i<j} w^i| ≤ |w−1|·Σ_{i<j}|w|^i ≤ |w−1|·j·max(1,|w|)^j. Sum: |S−n| ≤ |w−1|·Σ_{j<n} j·max(1,|w|)^j ≤ |w−1|·max(1,|w|)^{n-1}·n(n−1)/2.\n\nWith |w−1| = 1/|ρ| and max(1,|w|) ≤ 1+1/|ρ| ≤ 1+1/(2n):\n|S−n| ≤ (1/|ρ|)·(1+1/(2n))^n·n²/2 ≤ (1/|ρ|)·2·n²/2 = n²/|ρ| (using (1+1/(2n))^n ≤ e^{1/2} ≤ 2).\n\nSo |Re f| ≤ n·ρ.re/‖ρ‖² + n²/‖ρ‖² ≤ (n + n²)/‖ρ‖² ≤ 2n²/‖ρ‖² ✓ (n ≥ 1).\n\nIn Lean this is a chain of maybe 80–150 lines. The (1+1/(2n))^n ≤ 2 step: (1+x)^n ≤ exp(nx) for x ≥ 0 (Real.add_one_le_exp x: 1+x ≤ exp x; pow: (1+x)^n ≤ (exp x)^n = exp(nx) via Real.exp_nat_mul? (exp x)^n = exp(n·x) — `Real.exp_nat_mul`? There's `Real.exp_nat_mul (x : ℝ) (n : ℕ) : exp (n * x) = (exp x) ^ n`. ✓). Then exp(1/2) ≤ 2: `Real.exp_one_lt_d9` or just exp(1/2) < 2 via Real.exp_lt... exp(1/2) ≤ exp(1) ≤ 3 — or use exp(1/2)² = e ≤ 4 ⟹ exp(1/2) ≤ 2 ✓ clean: sq ≤ 4 → itself ≤ 2 (nonneg).\n\nThen the comparison to zero_sum_inv_sq's family:\nzero_sum_inv_sq (hs : ZetaSeam) : Summable (fun ρ : (zetaZeros hs).carrier => (zeroMult ρ : ℝ)/(1 + Complex.normSq (gammaOf ρ)))\n\nThe carrier: (zetaZeros hs).carrier — a Set ℂ; the subtype (zetaZeros hs).carrier = {ρ // ρ ∈ carrier}. Our index: {ρ // IsNontrivialZero ρ}. Need: (zetaZeros zetaSeam).carrier = {ρ | IsNontrivialZero ρ} as sets (then the subtypes are equivalent/identical). From SeamClosed.lean: `zetaZeroConfig := zetaZeros zetaSeam` and \"simp lemmas at lines 28–38 relate zetaZeroConfig.N to Ncount\" — there should be a `zetaZeros_carrier` lemma or the def zetaZeros itself: `zetaZeros (hs : ZetaSeam) : ZeroConfig` with carrier := {ρ | IsNontrivialZero ρ} presumably definitional. I'll check.\n\nThen: Summable of the ℝ-family; multiply by constant: .mul_left (9/2 * n^2). Then dominate ‖summand‖:\n- for ρ with 2n ≤ ‖ρ‖: ‖summand‖ = mult·|Re f| ≤ 2n²·mult/‖ρ‖² ≤ 2n²·(9/4)·mult/(1+‖γ‖²) = (9/2)n²·mult/(1+‖γ‖²) ✓ (the (9/4) factor: need (1+‖γ‖²) ≤ (9/4)‖ρ‖² ⟸ shown via 1+‖γ‖² ≤ 5/4+γ² and (9/4)‖ρ‖² ≥ (9/4)γ²... need 5/4+γ² ≤ (9/4)(σ²+γ²): since σ² ≥ 0: (9/4)(σ²+γ²) ≥ (9/4)γ² ≥ (9/4)γ²; and 5/4 + γ² ≤ (9/4)γ² ⟺ 5/4 ≤ 5/4·γ² ⟺ 1 ≤ γ² ✓ from |γ| ≥ ‖ρ‖−|σ|... hmm: ‖ρ‖² = σ²+γ² ≥ 4n² and σ ∈ (0,1) so |σ| < 1: γ² = ‖ρ‖²−σ² ≥ 4n²−1 ≥ 1 for n ≥ 1 ✓.)\n \n Wait — careful with normSq vs ‖·‖²: gammaOf ρ = (ρ − 1/2)/I; ‖gammaOf ρ‖² = normSq (gammaOf ρ) = (γ)² + (σ − 1/2)²... gammaOf ρ = (ρ−1/2)/I = −I(ρ−1/2) = −I((σ−1/2) + iγ) = γ − i(σ−1/2): normSq = γ² + (σ−1/2)² ✓.\n\n- for ρ with ‖ρ‖ < 2n: finite set (needs proof). Dominate by anything — use the finite-support modification.\n\nHmm — actually there's a slicker packaging avoiding the finite/infinite split: dominate ‖summand‖ ≤ mult·|Re f| ≤ mult·(2n²/‖ρ‖²) for ‖ρ‖ ≥ 2n, and for ‖ρ‖ < 2n use ‖summand‖ ≤ mult·(2·(2+1)^n)? For ‖ρ‖ < 2n: |f(ρ)| ≤ 1 + |1−1/ρ|^n — but 1/ρ can be huge (first zero has |ρ| ≈ 14.13 — bounded below! |ρ| ≥ 14.13 for ALL nontrivial zeros? The lowest zero is at 14.134 — so |1/ρ| ≤ 1/14 < 1, |1−1/ρ| ≤ 1+1/14, |f| ≤ 1 + (15/14)^n. So for ALL ρ: |Re f| ≤ |f| ≤ 1+(15/14)^n. Is |ρ| ≥ 14.13 available in Lean? That's the ROUCHÉ/numerical fact \"no zeros below 14.13\" — NOT available for free (needs a computation — it's part of RHUpTo?? No — RHUpTo says zeros up to 3e12 are on the line, not that none exist below 14.13. The nonexistence of zeros with |γ| < 14.13 is a numerical fact we'd need as... hmm, actually we can get a crude lower bound for free: zeros have |γ| ≥ ... hmm, is there ANY proved lower bound on the first zero's height in Mathlib/Zeta23? ZetaNoZerosInBox exists but that's about Re near 1. The strip zeros: is there a proved zero-free region near 0? For the SUMMABILITY we don't need the first-zero lower bound if we handle the finite part as a finite set — the finite part is finite REGARDLESS of what the zeros are (compactness). So: split at ‖ρ‖ = 2n: the ‖ρ‖ < 2n part is finite (compact ball ∩ zero set) — no bound needed at all, just finiteness. The ‖ρ‖ ≥ 2n part dominated by the (9/2)n²-mult/(1+‖γ‖²) family. \n\nSo packaging: g summable ⟸ (∀ρ, ‖g ρ‖ ≤ D ρ) with D summable, where D ρ = if 2n ≤ ‖ρ‖ then (9/2)n²·mult/(1+‖γ‖²) else ‖g ρ‖. D = D_summable_part + (D − D_summable_part) where the difference has finite support (the ball) ⟹ D summable. Then Summable.of_norm_bounded.\n\nThe finite support: {ρ : ¬(2n ≤ ‖(ρ:ℂ)‖)} = {ρ : ‖ρ‖ < 2n} ⊆ ball(0, 2n); ball compact; zeros ⊆ riemannZetaZeros; IsCompact.inter_riemannZetaZeros_finite (closed ball) ✓.\n\nAlternatively even slicker: `Summable.of_norm_bounded` needs the dominator on ALL points — or use `summable_of_finite_support` for the inside + `Summable.of_norm_bounded` on a subtype... The \"if-then-else dominator + finite-support difference\" approach is standard. There's also `Summable.congr_finite`? Let me just write it.\n\nOne more consideration: the subtype index of zero_sum_inv_sq: `(zetaZeros hs).carrier` — elements are `{ρ // ρ ∈ (zetaZeros hs).carrier}` where carrier : Set ℂ. And `zetaZeros` — let me check its def: probably `def zetaZeros (hs : ZetaSeam) : ZeroConfig := ⟨{ρ | IsNontrivialZero ρ}, zeroMult, ...⟩`. If carrier is DEFINITIONALLY {ρ | IsNontrivialZero ρ}, then {ρ // ρ ∈ carrier} = {ρ // IsNontrivialZero ρ} definitionally — Summable transport is by congruence (funext on the family after `show`). Fine.\n\nLet me check zetaZeros def + zeroMult coercion + gammaOf, then write the proof in Scratch.lean, iterate, merge into LiSkeleton.lean, rebuild, audit, close session.\n\nAlso need: `zeroMult ρ` for ρ : {ρ // IsNontrivialZero ρ} — the current liCoeff already uses `(zeroMult ρ : ℂ)` — so the coercion path exists ✓.\n\nAnd the tie-in: after the def change, `Sf`/`SfBoundProp`/`LiVerifiedUpTo`/`lambda_pos_finite_height(_verified)` all recompile (they use liCoeff abstractly ✓).\n\nAlso update the liCoeff docstring (remove the honesty note, document the pairing + summability theorem + D-064 reference).\n\nLet me start. First check zetaZeros def.","signature":""},{"type":"text","text":"Documentation is complete and committed (7a395b2). Now **session 015 — sub-stage ii′-1a: liCoeff pairing fix + summability proof**."},{"type":"tool_use","id":"TodoWrite_81","name":"TodoWrite","input":{"todos":[{"content":"Check zetaZeros carrier def + zeroMult/gammaOf coercion paths","status":"in_progress","activeForm":"Checking zetaZeros defs"},{"content":"Develop summability proof in Scratch.lean (pair bound + comparison)","status":"pending","activeForm":"Developing summability proof"},{"content":"Replace liCoeff def in LiSkeleton.lean + prove liCoeff_summable","status":"pending","activeForm":"Replacing liCoeff def"},{"content":"Full rebuild + axiom audit (LiSkeleton/LiBasePoints unchanged downstream)","status":"pending","activeForm":"Rebuilding + auditing"},{"content":"Session-015 closure (journal, STATE, NGUYEN checkoff, commit)","status":"pending","activeForm":"Closing session 015"}]},"extra_content":null}]