Lean → Dafny · round integ5 (2026-10-02/03) · 101 theorems · 499 failing lines

Missing Lean proofs

For each line Dafny fails on in the integ5 translations, the Lean step it translates and the part of that step's proof left to Z3. Click a line in the browser below to see the failing Dafny line, the Lean step with Lean's recorded goal, the extracted subgoal lemma (original and trimmed) and the reviewers' consensus.

Round integ5 (2026-10-02/03): candidate translator (every Lean tactic's before-goal stated, cites as Lean recorded them)

33,014obligations verified
174errors
341out of resource
38clean of 101
imo_1966_p5 timed out
499failing lines, labelled by three reviewers
220 translator · 117 library · 151 solver · 11 harvest (reviewers' counts; for the 267 lines missing 1–3 Lean lines the gap analysis finds solver 87 → 10, library 73 → 137)
Go to the integ5 section (below; size of the missing Lean block · systematic gaps of the 1–3-line lines): per-label and per-task tables, the ranked fix list, and every failing line with its Dafny context, Lean text, subgoal lemma and consensus.

Round integ5: the candidate translator's failing lines, labelled by three reviewers

Round integ5 (2026-10-02/03) is the candidate translator that states every Lean tactic's recorded before-goal as a Dafny statement (// @tac), Lean's rewritten hypotheses (// @tac-hyp), and only the lemma applications Lean recorded at each step, with Lean's arguments. All 101 theorems were verified once with the same bar as before (dafny verify --isolate-assertions --resource-limit 1000000 --allow-warnings --cores 2, Dafny 4.11). Each failing line was extracted from the integ5 output files as one subgoal lemma (encode-only, then trimmed statically by simple_trim v3), each lemma checked standalone once as extracted and once trimmed, and labelled independently by three reviewers (A, B, C) with the T/S/R gap taxonomy plus a fix task (who has to act). Where they disagreed on the primary label or the fix task, an adjudicator re-read the evidence (≤ 3 standalone Dafny checks per line) and decided; the decision and its reason are shown on the line.

33,014obligations verified
174errors
341out of resource
38clean files of 101
51 with errors · 12 only OOR
499failing lines (175 error · 324 OOR) in 63 theorems
100 files produced a Dafny summary; imo_1966_p5 timed out (1200 s) — its 2 failing lines are the ones reported before the timeout. Obligation counts are Dafny's (one source line can hold several obligations); the line counts are distinct source lines.

Primary label, error vs out of resource

Primary = the fix that would unblock the line first. “any role” counts contributing labels too.
labelerrorOORtotalany role
T-FAITHFUL2138
T-SORT31422
T-BACKWARD2·23
T-CITE32427498
T-LIBRARY16294569
S-RELEVANCE18140158245
S-INSTANTIATE3744156
S-COMPUTE1794111281
R-NONLINEAR371148147
R-FIELD11·1134
R-TRANSCENDENTAL···31
R-BINDER·1122
R-INDUCTION···2
R-CASES·116
total175324499

The tasks: who has to act

Corrected by the gap analysis: these are the three reviewers' fix tasks. The systematic-gap analysis below re-examined the 267 lines that miss only 1–3 Lean lines and re-assigned many of them: on those lines SOLVER drops from 87 to 10 and LIBRARY rises from 73 to 137 (TRANSLATOR 98 → 97, HARVEST 9 → 23), mostly because the library's pow encoding, not Z3, is the cause (lines that moved).
fix taskerrorOORtotal
TRANSLATOR
the emitter must change (a named change)
112108220
LIBRARY
a Mathlib fact must be added to / restated in the Dafny library
2988117
HARVEST
Lean's records are missing or misattributed, so the fact could not be stated
7411
SOLVER
true, faithfully stated, facts present — Z3 cannot do it (no translator fix)
27124151
AUDIT-KNOWN
matches a confirmed audit5 finding
···

Primary label × fix task

primaryTRANSLIBRAHARVESOLVEAUDITtotal
T-FAITHFUL2·1··3
T-SORT4····4
T-BACKWARD2····2
T-CITE6347··74
T-LIBRARY·45···45
S-RELEVANCE366·116·158
S-INSTANTIATE3641··41
S-COMPUTE3954117·111
R-NONLINEAR32·115·48
R-FIELD44·3·11
R-BINDER1····1
R-CASES1····1

Ranked fix list — TRANSLATOR and LIBRARY changes

Each concrete change the reviewers / adjudicator named, with the failing lines it is meant to unblock (an upper bound: other labels on a line may still block it after the fix). Click “show” to filter the lines below. This list counts the reviewers' named changes over all 499 lines; the ranked action list of the gap analysis re-ranks the fixes for the 267 few-line gaps with standalone test evidence.
#taskchangeerrorOORlinestheorems (lines)
1LIBRARYLIBRARY: stop the MathPrelude pow matching loop (opaque pow with explicit PowSucc/PowAdd/PowMul lemmas instead of the recursive ensures)45357numbertheory_fxeq4powxp6powxp9powx_f2powmdvdf2pown (17), imo_1966_p4 (9), amc12a_2009_p15 (8), imo_1964_p1_2 (7), algebra_apbon2pownleqapownpbpowon2 (5), numbertheory_3pow2pownm1mod2pownp3eq2pownp2 (5), imo_1964_p1_1 (4), amc12a_2021_p14 (1), mathd_numbertheory_175 (1)show
2TRANSLATORTRANSLATOR: in interval_cases/norm_num branches state the evaluated h0 instance p(k)==v and norm_num's isNat_gcd result gcd(x,y)==z72532mathd_numbertheory_618 (32)show
3TRANSLATORTRANSLATOR: hoist inline guarded nlinarith certificate pieces (mul_zero_eq/zero_mul_eq/sq_nonneg) into context-free cert_piece lemmas42529imo_1965_p1 (19), imo_1973_p3 (6), amc12a_2021_p22 (3), algebra_apbpceq2_abpbcpcaeq1_aleq1on3anbleq1ancleq4on3 (1)show
4TRANSLATORTRANSLATOR: emit quantified hypothesis bodies (∀, ∃, ∀-iff) through named ghost predicates/functions so they have matchable triggers22·22amc12a_2003_p25 (19), algebra_apbon2pownleqapownpbpowon2 (1), amc12a_2021_p19 (1), numbertheory_fxeq4powxp6powxp9powx_f2powmdvdf2pown (1)show
5LIBRARYLIBRARY: add Mathlib Rat.cast_injective / Rat.cast_inj with Rat.cast_neg and Rat.cast_intCast (ℚ→ℝ)41216aime_1984_p1 (12), aime_1999_p11 (2), amc12a_2009_p2 (2)show
6TRANSLATORTRANSLATOR: emit cert_piece bodies with let-bound factors, the MulPos call, and an explicit product-equality assert12·12imo_1974_p5 (8), amc12a_2021_p22 (2), imo_1966_p5 (2)show
7TRANSLATORTRANSLATOR: cite IntMulNonneg for ℕ products passed to nat parameters·1111numbertheory_3pow2pownm1mod2pownp3eq2pownp2 (10), amc12_2001_p5 (1)show
8TRANSLATORTRANSLATOR: generalise cert_piece factors (compound products, cast atoms, Real.pow atoms) to lemma parameters instantiated at the call site819algebra_abpbcpcageq3_sumaonsqrtapbgeq3onsqrt2 (3), aime_1999_p11 (2), algebra_apbon2pownleqapownpbpowon2 (2), amc12_2000_p20 (2)show
9TRANSLATORTRANSLATOR: instantiate named simp/norm_num hint lemmas with no recorded instance by matching their LHS against the before-goal729amc12b_2020_p21 (6), aime_1999_p11 (1), mathd_numbertheory_175 (1), mathd_numbertheory_84 (1)show
10TRANSLATORTRANSLATOR: emit argument-free trig special-value lemmas (RealSin/CosZero, RealSin/CosPiDivTwo) for ground terms in norm_num/simp goals448amc12a_2021_p19 (8)show
11LIBRARYLIBRARY: add Mathlib Complex.re_sum / Complex.im_sum (with ℂ Finset.sum_singleton)·77amc12a_2009_p15 (7)show
12TRANSLATORTRANSLATOR: emit Dvd-iff-mod cite with Lean's witness for ∃-form divisibility proofs (use w / exact ⟨w, _⟩ / Dvd.intro)·77numbertheory_3pow2pownm1mod2pownp3eq2pownp2 (5), aime_1987_p5 (1), numbertheory_fxeq4powxp6powxp9powx_f2powmdvdf2pown (1)show
13TRANSLATORTRANSLATOR: map recorded Real.logb.eq_1 (and ground logb terms in simp/field_simp) to RealLogbUnfold426amc12a_2021_p14 (6)show
14TRANSLATORTRANSLATOR: ring-normalise cert_identity summands into monomials·66imo_1992_p1 (6)show
15TRANSLATORTRANSLATOR: add {:trigger f(n)} to ∀ recurrence hypotheses (or emit the instance's parity/tsub side facts)5·5amc12a_2017_p7 (5)show
16LIBRARYLIBRARY: add Mathlib Finset.sum_singleton for ℕ-indexed/generic sets (Real.sum)224aime_1999_p11 (1), algebra_sum1onsqrt2to1onsqrt10000lt198 (1), amc12a_2021_p14 (1), imo_1966_p4 (1)show
17TRANSLATORTRANSLATOR: bridge %-based Dvd hypotheses to ∃-form preconditions and back (IntDvdIffEmodEqZero / NatModAddDiv glue)134aime_1987_p5 (2), numbertheory_2pownm1prime_nprime (2)show
18TRANSLATORTRANSLATOR: emit ∀-have instances as calls of a hoisted lemma (or its proving induction helper) with Lean's arguments134numbertheory_fxeq4powxp6powxp9powx_f2powmdvdf2pown (2), aime_1999_p11 (1), algebra_absapbon1pabsapbleqsumabsaon1pabsa (1)show
19TRANSLATORTRANSLATOR: map recorded Set.InjOn.eq_iff (cos on Icc 0 π, tan on Ioo) to RealInjOnCosEqIff / RealInjOnTanEqIff224amc12a_2021_p19 (3), aime_1999_p11 (1)show
20LIBRARYLIBRARY: add Mathlib Nat.pow_le_pow_right (Int.pow, nat exponent)·33numbertheory_2pownm1prime_nprime (3)show
21LIBRARYLIBRARY: make MathPrelude Real.sqrt ensures-free/opaque (facts via cited Real.sq_sqrt / Real.sqrt_nonneg)3·3aime_1983_p3 (3)show
22TRANSLATORTRANSLATOR: do not re-assert trigger-less ∀/∃ hypotheses at exact/obtain; assert the instance or bind the witness directly213numbertheory_fxeq4powxp6powxp9powx_f2powmdvdf2pown (2), numbertheory_3pow2pownm1mod2pownp3eq2pownp2 (1)show
23TRANSLATORTRANSLATOR: emit cert pieces with compound-product factors without the MulPos/MulNonneg call (empty body), and state order-lemma conclusions directly3·3algebra_bleqa_apbon2msqrtableqambsqon8b (2), mathd_algebra_362 (1)show
24TRANSLATORTRANSLATOR: emit rw / ring_nf congruence steps as explicit before==after (argument) equalities213algebra_bleqa_apbon2msqrtableqambsqon8b (1), imo_1960_p2 (1), numbertheory_aoddbdiv4asqpbsqmod8eq1 (1)show
25TRANSLATORTRANSLATOR: emit ℚ literal norm_num helpers (RatMulOfIntOfInt / RatMulDivOfIntCancel) for Rat literal products213amc12a_2021_p18 (3)show
26TRANSLATORTRANSLATOR: render squares uniformly (x*x vs Real.pow/Int.pow(x,2)) or emit the pow-two bridge after cites213algebra_bleqa_apbon2msqrtableqambsqon8b (1), amc12a_2021_p14 (1), amc12b_2020_p13 (1)show
27LIBRARYLIBRARY: add Mathlib Nat.gcd_self_add_right (nat gcd)·22imo_1959_p1 (1), mathd_numbertheory_618 (1)show
28LIBRARYLIBRARY: add Mathlib Nat.prime_def_lt'' (PrimeOfNoDivisor) for decide on Nat.Prime literals2·2amc12a_2021_p18 (2)show
29LIBRARYLIBRARY: add Mathlib add_div and div_self (Real.div)2·2amc12b_2020_p13 (2)show
30LIBRARYLIBRARY: add Mathlib div_add_div / div_add' / add_div' (Real.div)2·2imo_1974_p5 (2)show
31LIBRARYLIBRARY: add Mathlib div_eq_iff (real, Real.div form)2·2aime_1983_p1 (1), mathd_algebra_598 (1)show
32LIBRARYLIBRARY: add pointwise (h-form) Finset.sum_add_distrib at ℚ (FinsetSumAddDistribRatH)·22aime_1984_p1 (2)show
33LIBRARYLIBRARY: add ℚ nsmul_eq_mul and h-form Finset.sum_const at ℚ·22aime_1984_p1 (2)show
34TRANSLATORTRANSLATOR: compose ∣-calc chains with NatDvdTrans·22numbertheory_3pow2pownm1mod2pownp3eq2pownp2 (2)show
35TRANSLATORTRANSLATOR: emit `tac at h ⊢` / ring_nf @tac-hyp haves as context-free helper lemmas requiring only the named hypotheses·22imo_1984_p2 (1), imo_1992_p1 (1)show
36TRANSLATORTRANSLATOR: emit at-hypothesis rewrite instances at the @tac-hyp line and bind literal-exponent Real.pow terms to a name2·2amc12b_2003_p17 (2)show
37TRANSLATORTRANSLATOR: emit log-positivity unguarded and the `/`-form of field_simp goals over Real.div2·2amc12b_2021_p9 (2)show
38TRANSLATORTRANSLATOR: emit refine' lt_of_sub_pos sub-goal before the LtOfSubPosReal precondition2·2imo_1974_p5 (2)show
39TRANSLATORTRANSLATOR: hoist the whole nlinarith closing step (sub-goal + pieces + cert_identity) into a lemma requiring only its premises2·2algebra_apbpceq2_abpbcpcaeq1_aleq1on3anbleq1ancleq4on3 (1), imo_1973_p3 (1)show
40TRANSLATORTRANSLATOR: map Finset.mul_sum over ℕ-indexed sets to FinsetMulSumPointwise<T>112aime_1999_p11 (1), amc12a_2021_p14 (1)show
41TRANSLATORTRANSLATOR: map Int.card_Icc to IntIccCard (recorded instance or literal-bounded rfl/decide card goals)2·2amc12b_2021_p1 (1), mathd_algebra_170 (1)show
42TRANSLATORTRANSLATOR: prove rewritten ∀ @tac-hyp restatements with a forall-statement body (instance / FinsetMemIccNat guard lemma)2·2algebra_sum1onsqrt2to1onsqrt10000lt198 (1), amc12a_2009_p9 (1)show
43TRANSLATORTRANSLATOR: state field_simp rewrites (goal before==after, internal div_pow instances) as explicit equalities over the literal terms2·2algebra_9onxpypzleqsum2onxpy (1), algebra_abpbcpcageq3_sumaonsqrtapbgeq3onsqrt2 (1)show
44LIBRARYLIBRARY: add Complex Finset.sum_Icc_succ_top over ℤ-Icc and a root-of-unity inverse lemma1·1amc12a_2019_p21 (1)show
45LIBRARYLIBRARY: add Complex.sum ℤ-Icc ↔ ℕ-IccN reindexing lemma (Finset.sum_nbij along Nat.cast)1·1amc12a_2019_p21 (1)show
46LIBRARYLIBRARY: add IntDvd-form (%-based) Mathlib dvd_add_right·11aime_1987_p5 (1)show
47LIBRARYLIBRARY: add Mathlib Finset.prod_div_distrib (Real.prod, h-form)1·1amc12a_2008_p4 (1)show
48LIBRARYLIBRARY: add Mathlib Nat.card_Icc for IccN·11amc12a_2021_p14 (1)show
49LIBRARYLIBRARY: add Mathlib Nat.cast_prod (Int.prod cast to Real.prod)1·1amc12a_2008_p4 (1)show
50LIBRARYLIBRARY: add Mathlib Nat.gcd_mul_right_add_right / Nat.gcd_add_self_right / Nat.gcd_one_left (nat gcd)·11imo_1959_p1 (1)show
51LIBRARYLIBRARY: add Mathlib div_eq_div_iff (real, Real.div form)1·1amc12a_2013_p4 (1)show
52LIBRARYLIBRARY: add Mathlib div_sub_div_same (Real.div)1·1amc12b_2021_p9 (1)show
53LIBRARYLIBRARY: add Mathlib mul_div_assoc' (Real.div form)1·1algebra_sum1onsqrt2to1onsqrt10000lt198 (1)show
54LIBRARYLIBRARY: add Mathlib one_pow at ℂ (ComplexOnePow)·11amc12a_2009_p15 (1)show
55LIBRARYLIBRARY: add RealRpowMul variant with explicit exponent-product argument (Mathlib Real.rpow_mul)1·1amc12a_2009_p6 (1)show
56LIBRARYLIBRARY: restate ExistsDvdOfNotPrime2 with NatDvd in its ensures·11numbertheory_2pownm1prime_nprime (1)show
57TRANSLATORTRANSLATOR: assert the induction-helper postcondition at the end of each branch·11amc12a_2009_p15 (1)show
58TRANSLATORTRANSLATOR: cite ComplexSumEmpty and state ground Complex.mul intermediates in the induction base case·11amc12a_2009_p15 (1)show
59TRANSLATORTRANSLATOR: constant-fold Nat-literal casts into real literals (Nat.cast_ofNat)1·1amc12a_2009_p6 (1)show
60TRANSLATORTRANSLATOR: emit Finset.sum summand lambdas as named ghost functions·11imo_1966_p4 (1)show
61TRANSLATORTRANSLATOR: emit NotIrrationalNatCast / Irrational-definition instance for anonymous-constructor proofs on Irrational1·1algebra_others_exirrpowirrrat (1)show
62TRANSLATORTRANSLATOR: emit Real.div == `/` bridge at `/`-form division-lemma cites (LeDivIff)1·1algebra_abpbcpcageq3_sumaonsqrtapbgeq3onsqrt2 (1)show
63TRANSLATORTRANSLATOR: emit Set.ext_iff steps as pointwise forall with explicit iset membership asserts1·1amc12a_2003_p25 (1)show
64TRANSLATORTRANSLATOR: emit an execution's recorded cites before its @tac-hyp asserts1·1algebra_sum1onsqrt2to1onsqrt10000lt198 (1)show
65TRANSLATORTRANSLATOR: emit cert_identity over unevaluated pow atoms instead of norm_num-evaluated huge numerals1·1amc12a_2013_p4 (1)show
66TRANSLATORTRANSLATOR: emit interval_cases as an if/else-if chain on n == k·11mathd_numbertheory_618 (1)show
67TRANSLATORTRANSLATOR: map isNat_rpow_pos (real base, numeral exponent) to RealRpowNatCast1·1mathd_algebra_756 (1)show
68TRANSLATORTRANSLATOR: map recorded Finset.prod_pair to FinsetProdPair1·1aime_1983_p3 (1)show
69TRANSLATORTRANSLATOR: map recorded Finset.sum_singleton over range 1 to FinsetSumRangeSucc/FinsetSumRangeZero1·1mathd_algebra_342 (1)show
70TRANSLATORTRANSLATOR: map recorded Nat.mod_mod_of_dvd to NatModMod (with IntPowPos precondition)·11numbertheory_3pow2pownm1mod2pownp3eq2pownp2 (1)show
71TRANSLATORTRANSLATOR: map recorded orderOf_eq_iff on ZMod n to OrderOfEqIff·11imo_1964_p1_1 (1)show
72TRANSLATORTRANSLATOR: restate the cases-succ branch conclusion over the outer binder (IccN/pow argument bridges for the predecessor var)·11imo_1966_p4 (1)show
73TRANSLATORTRANSLATOR: split capped interval_cases enumerations into per-value helper lemmas·11imo_1984_p2 (1)show

What kind of statement fails

integ5 classification of the failing statement.
statement kinderrorOORtotal
sub-goal (Lean tactic state)43117160
have / step assertion6184145
hypothesis after tactic (@tac-hyp)173754
cert (lemma application in a certificate)82937
cert piece28129
instance of a hypothesis51318
cert identity31215
contract (ensures/requires)·1212
precondition (asserted lemma precondition)3710
cite (library lemma call)189
lemma call (precondition)224
such-that (:|) existence2·2
other·22
contradiction closing a branch1·1
postcondition at return point1·1

Agreement

Primary label: all three agree on 417 lines, two on 71, none on 11 (Fleiss κ 0.855). Fix task: 285 / 197 / 17 (κ 0.546). Pairwise primary agreement AB 89%, AC 88%, BC 88%. 257 lines unanimous on both; 240 adjudicated (165 majority-confirmed, 57 minority-adopted, 18 new-reading).

Standalone check of the subgoal lemma

Each line's extracted lemma checked once as extracted and once after the static trim (same flags): closed 160 / 162 of 499. A lemma that closes standalone means the needed facts are in scope and the cost is the surrounding procedure.

Size of the missing Lean block

For each failing Dafny line: how many Lean source lines it stands for that the translator did not turn into Dafny statements of their own — the part of the Lean proof Z3 has to rediscover. The line browser below marks these Lean lines with ».

Why the raw » count overstated large blocks. The » marks are made from the Lean tactic tags (// @tac) attached to the Dafny line, each with the byte range of its Lean source. Two things inflate a plain count of » lines: (1) one Dafny statement can carry the tags of several consecutive haves, and (2) a have tag's byte range spans the whole nested by proof of that have — but that nested proof is translated separately, as its own Dafny statements, so it is not missing at this line. Example: imo_1966_p4-86 carries ten tags, four of them multi-line haves (base_case, inductive_step, apply_induction, final_conclusion); the raw count is 70 » lines, the corrected count 10. Corrected count: a have/obtain/show with a nested proof counts as its statement line only; every other tactic counts its source lines (recount() in classify5/gapset.py).

26 → 8lines in the 11+ bucket (raw → corrected)
3.81 → 2.32mean missing Lean lines over the 331 lines with a » mark
81 → 19largest block (median 1 either way)
26lines change bucket (34 change count); none moves up
267lines miss 1–3 Lean lines (209 · 32 · 26): the set analysed below
Bucket moves (raw → corrected): 11+ → 3-5: 10 · 6-10 → 3-5: 5 · 11+ → 6-10: 4 · 11+ → 2: 4 · 3-5 → 2: 2 · 6-10 → 2: 1. Still 11+ after correction: aime_1999_p11-1161 (19), amc12a_2009_p15-201 (15), numbertheory_3pow2pownm1mod2pownp3eq2pownp2-59 (15), aime_1999_p11-346 (13), mathd_numbertheory_618-139 (13), amc12a_2021_p14-357 (12), amc12a_2009_p15-586 (11), numbertheory_fxeq4powxp6powxp9powx_f2powmdvdf2pown-148 (11). The raw 11+ bucket looked easy (15 of 26 close standalone, 57%) because most of its lines were really small blocks; the corrected 11+ bucket closes 1 of 8.
missing Lean lineslines, raw » countlines, correctederrorOORcloses standalone (as extracted)closes trimmedTRANSLATORLIBRARYSOLVERHARVEST
0 (no » mark)168168739586 (51%)869925422
12092095715240 (19%)418260589
22532112111 (34%)1298150
3-54760253518 (30%)172112270
6-1024229134 (18%)57780
11+268081 (12%)12510
all499499175324160 (32%)16222011715111
Columns error … HARVEST use the corrected buckets; “closes standalone” = the line's extracted subgoal lemma verified on its own (one Dafny check, same flags); fix task = the three-reviewer consensus.

By block size: what fails, who has to act, and the fixes

All 499 failing lines, corrected count, with the 1–3-line blocks split (1, 2, 3) because they are the set the systematic-gap analysis re-examined. “Fix task (after gap analysis)” exists only for those 267 lines; the analysis moved most “solver” lines to library (the pow encoding) and some to translator/harvest. Labels and named fixes are the three-reviewer consensus.
missing Lean lineslineserror / OORcloses standalonefix task (reviewers)fix task (after gap analysis)top primary labelsmost common Lean tactic left to Z3top named fixes (lines)
0 (no Lean line)16873 / 9586 (51%)translator 99 · library 25 · solver 42 · harvest 2—S-RELEVANCE 63 R-NONLINEAR 39 S-INSTANTIATE 27—hoist inline guarded nlinarith certificate pieces (mul_zero_eq/zero_mul_eq/sq_nonneg) into context-free cert_piece lemmas (29)
emit quantified hypothesis bodies (∀, ∃, ∀-iff) through named ghost predicates/functions so they have matchable triggers (16)
emit cert_piece bodies with let-bound factors, the MulPos call, and an explicit product-equality assert (12)
120957 / 15240 (19%)translator 82 · library 60 · solver 58 · harvest 9translator 81 · library 105 · solver 6 · harvest 17S-COMPUTE 75 S-RELEVANCE 55 T-CITE 34norm_num 51 · simp_all 28 · simp 24stop the MathPrelude pow matching loop (opaque pow with explicit PowSucc/PowAdd/PowMul lemmas instead of the recursive ensures) (35)
in interval_cases/norm_num branches state the evaluated h0 instance p(k)==v and norm_num's isNat_gcd result gcd(x,y)==z (32)
emit argument-free trig special-value lemmas (RealSin/CosZero, RealSin/CosPiDivTwo) for ground terms in norm_num/simp goals (8)
23211 / 2111 (34%)translator 9 · library 8 · solver 15translator 7 · library 19 · solver 2 · harvest 4S-RELEVANCE 15 S-COMPUTE 7 T-CITE 5have 9 · norm_num 6 · rw 5stop the MathPrelude pow matching loop (opaque pow with explicit PowSucc/PowAdd/PowMul lemmas instead of the recursive ensures) (5)
instantiate named simp/norm_num hint lemmas with no recorded instance by matching their LHS against the before-goal (2)
add ℚ nsmul_eq_mul and h-form Finset.sum_const at ℚ (1)
3267 / 1911 (42%)translator 7 · library 5 · solver 14translator 9 · library 13 · solver 2 · harvest 2S-RELEVANCE 12 T-CITE 7 S-COMPUTE 5have 19 · rw 2 · apply 2stop the MathPrelude pow matching loop (opaque pow with explicit PowSucc/PowAdd/PowMul lemmas instead of the recursive ensures) (3)
map recorded Set.InjOn.eq_iff (cos on Icc 0 π, tan on Ioo) to RealInjOnCosEqIff / RealInjOnTanEqIff (2)
add IntDvd-form (%-based) Mathlib dvd_add_right (1)
4–53418 / 167 (20%)translator 14 · library 7 · solver 13—T-CITE 12 S-RELEVANCE 6 R-NONLINEAR 5have 9 · norm_num 7 · rw 6map recorded Real.logb.eq_1 (and ground logb terms in simp/field_simp) to RealLogbUnfold (5)
instantiate named simp/norm_num hint lemmas with no recorded instance by matching their LHS against the before-goal (4)
add Mathlib div_eq_iff (real, Real.div form) (2)
6–10229 / 134 (18%)translator 7 · library 7 · solver 8—S-RELEVANCE 6 T-CITE 4 R-FIELD 4have 9 · simp 3 · norm_num 2stop the MathPrelude pow matching loop (opaque pow with explicit PowSucc/PowAdd/PowMul lemmas instead of the recursive ensures) (3)
map recorded Finset.prod_pair to FinsetProdPair (1)
map recorded Set.InjOn.eq_iff (cos on Icc 0 π, tan on Ioo) to RealInjOnCosEqIff / RealInjOnTanEqIff (1)
11+80 / 81 (12%)translator 2 · library 5 · solver 1—S-COMPUTE 4 T-LIBRARY 2 T-CITE 1have 5 · norm_num 1 · norm_cast 1stop the MathPrelude pow matching loop (opaque pow with explicit PowSucc/PowAdd/PowMul lemmas instead of the recursive ensures) (3)
add Mathlib Finset.sum_singleton for ℕ-indexed/generic sets (Real.sum) (1)
add Mathlib Rat.cast_injective / Rat.cast_inj with Rat.cast_neg and Rat.cast_intCast (ℚ→ℝ) (1)
Reading: most failures are small — 267 of 499 lines miss 1–3 Lean lines, 209 of them exactly one step. On those the reviewers saw 87 “solver” lines; after the analysis only 10 remain, the rest is the library's pow encoding (library) or missing translator statements. Lines with no Lean line (certificate pieces, instances, preconditions) close standalone half the time: the fact is fine, the surrounding query is too large. Blocks of 4+ lines close standalone rarely (12–20%), but there are only 64 of them.

Why Lean does not need these steps while Dafny does — the information kinds

For every failing line, its extracted standalone lemma was re-checked with one kind of information Lean had added back (from Lean’s own records; ~1,810 Dafny checks, each under 30 s, never whole files). Then the smallest edit that makes Dafny prove the line was recorded. Two review passes re-ran 34 lines with controls (33 reproduced) and corrected the counts. Use the filters information kind, closing result and simplest close in the line browser below; each line’s panel shows its kinds and recipe. Strict closed versions. Every line was rebuilt as an honest standalone lemma — hypotheses = the facts Z3 had at the line minus the goal itself and minus what the step's own block (or helper lemma body) derives; proof = the file’s own proof body; then each ablation variant's additions were re-applied on top, a variant may drop hypotheses but never add one. 410 of 499 close (an earlier count of 426 included 33 lemmas whose two-line goal had been cut to its first conjunct by the builder; rebuilt with the full goal, 19 still close). In-file check. Every closed lemma was then put back into the source file at its failing line, each hypothesis re-asserted and the lemma called, and Dafny run on exactly those lines in the real context: see infile/ for the per-line table. The files are in closed/ (one per line, closed or not). Each line’s panel below shows its closed version and its in-file result. Sources: classify5/kinds/CONCLUSION.md, GUIDE.md, kinds_by_line.jsonl.

410of 499 lines have a CLOSED version (strict: same goal, no added hypothesis, Dafny 0 errors in 30 s)
93close as their own lemma with the file’s own proof, nothing added (locality)
283close with one kind of added information (K1/K2/K4/K5)
34close with a combination or the simplest-close edit
148closed in a second pass by an agent (proof written by hand under the same rules; additions highlighted)
89not closed (file shows the honest base attempt)
253in-file check CONFIRMED: closed lemma put back at the failing line, hypotheses provable there, line verifies
68in-file: lemma proves the line, but a hypothesis cannot be re-asserted at that point (spelling, by-block placement, or out of resource)
39in-file: line still fails (out of resource in that context, or the goal in Z3 spelling)
49in-file: not checkable (lemma parameters with no name at the line)
kind of information Lean hadwhat it iscloses alone (discriminating, sound)judged a causejudged primary
K3 localityLean’s step sees one goal and a few hypotheses; Dafny checks the line against the whole method’s context93223161
K2 computationLean computes / normalises (norm_num, ring_nf, kernel); Z3 has incomplete nonlinear arithmetic and fuel-bounded unfolding53213149
K5 automation lemmasimp / norm_num / field_simp apply library lemmas silently; Z3 knows only the lemmas cited429758
K1 instanceLean names the instance of a ∀/∃ fact; Z3 must find it by trigger matching278571
K4 typesℕ ≥ 0, casts, ∣ ↔ % come from Lean’s types; in Dafny they are side conditions or lemmas134731
K0 none / true limitnone of the above: a true solver limit, or not about missing information—3629
“Closes alone” = lines whose strict closed version was obtained by adding only that kind (K3 = closes as its own lemma with the file’s own proof and nothing added); the earlier ablation counts were higher because some closes had assumed a hypothesis or had the goal among the hypotheses; kinds overlap (167 lines carry two or more). Simplest closing action over the 499 lines: split 200 · library 92 · cite 89 · assert 53 · none 9 · render 6.
Practical guide: how to prove competition mathematics in Dafny without working blindly (9 rules, ranked)

*Rules measured on 499 failing lines of Lean→Dafny translations of competition proofs (integ5, 63 theorems; Dafny 4.11,

verify --isolate-assertions --resource-limit 1000000 --allow-warnings, every check in a 30 s budget). Stage k_SYNTH,

2026-10-03. Numbers: kinds/synth/tables.md, kinds/synth/greedy.txt, per line kinds/kinds_by_line.jsonl.

Analysis and caveats: kinds/CONCLUSION.md (§7 threats to validity, §9–§10 corrections after review).

Numbers were corrected after the second review (k_SKEPTIC): they count only discriminating sound closes, on lines whose lemma did not already verify unchanged. Pre-review figures are in brackets.*

Why a Dafny proof needs more steps than a Lean proof

A Lean proof term records five kinds of information that Z3 has to rediscover:

  • K3 Locality. Each Lean step sees one goal and a few named hypotheses. Dafny checks each line against the
  • whole method's context.

  • K2 Computation. norm_num, decide, ring_nf and the kernel evaluate and normalise. Z3 has incomplete
  • nonlinear arithmetic and unfolds recursive functions only up to a fuel bound.

  • K5 Automation lemmas. simp, norm_num and field_simp apply lemmas from their databases without naming them.
  • Z3 knows only the lemmas you call.

  • K1 Instances. Lean names the instance it uses (h 0, obtain ⟨x, hx⟩). Z3 must find instances by trigger
  • matching (E-matching).

  • K4 Types. Lean gets ℕ ≥ 0, casts and ∣ = ∃ from its type system. In Dafny these facts must be stated as
  • side conditions or proved with lemmas.

    The rules below supply each kind of information explicitly. They are ranked by lines recovered per unit of effort.

    How to read the evidence. "Closes" means the failing line's extracted lemma verified after the change.

    "Of tried" is the share of lines where that change was tried. All checks are standalone lemmas, never whole files.

    ---

    Rule 1 — Keep every query small: prove each step as its own lemma over only the facts it needs (K3)

    Evidence.

  • 149 failing lines verify unchanged once cut out of their method into a standalone lemma with the same facts,
  • under the resource criterion. 142 of them also finish within 30 s on one core: 3 time out in re-runs and 4 more took

    over 30 s in the dossier.

  • 34 more verify when the lemma keeps only the facts the Lean step used.
  • In total that is 176/499 lines [182]. It is the largest single effect, and it dominates out-of-resource failures:
  • 142 of the 324 OOR lines close this way.

  • nlinarith certificate lines: 52 of 79 close this way.
  • Cost. Mechanical: one lemma per step plus one call. The requires are the step's hypotheses, which Lean records as

    the tactic's before-state or have_deps.

    Before (aime_1983_p1, line 507, fails inside a method of about 260 obligations):

    assert Real.log((x as real) * (y as real)) == Real.log(x as real) + Real.log(y as real) by {
      RealLogMul(x as real, y as real);
    }
    

    After (schematic: the extracted lemma that verified at 5,057 resource units carries the 23 in-scope facts as

    requires, or 13 after static trimming; shown here with the two positivity facts the Lean step used):

    lemma Step507(x: nat, y: nat)
      requires 0.0 < x as real
      requires 0.0 < y as real
      ensures Real.log((x as real) * (y as real)) == Real.log(x as real) + Real.log(y as real)
    { RealLogMul(x as real, y as real); }
    // in the method:  Step507(x, y);
    

    Do not rely on --isolate-assertions to provide locality. It splits obligations, but each one still carries the

    whole path's facts.

    Rule 2 — Never give pow (or any recursive function) a recursive postcondition; make it opaque and call unfolding lemmas (K2, encoding)

    Evidence.

  • 57 lines close when the library's Real.pow/Int.pow keeps its body but drops ensures … p == b * pow(b, k-1),
  • or when pow/ℂ is made opaque [83]. The other 26 of the 83 either already verified standalone with nothing added

    (22; there the in-file effect is plausible but not discriminated), or needed other fixes as well.

  • These lines come from 12 theorems: imo_1966_p4 (22), numbertheory_3pow2pownm1… (14), numbertheory_fxeq… (12), and others.
  • Typical effect: imo_1966_p4-291 goes from OOR at 1,013,371 resource units to verified at 123,803.
  • Cost. One library change, plus explicit PowSucc/PowAdd/PowMul calls wherever an unfolding is actually needed.

    Before (library/MathPrelude.dfy):

    function pow(b: real, k: nat): (p: real)
      ensures if k == 0 then p == 1.0 else p == b * pow(b, k - 1)   // re-triggers on every pow term: a matching loop
    { if k == 0 then 1.0 else b * pow(b, k - 1) }
    

    After (recommended shape; the measured variant kept the body and only removed the recursive ensures,

    kinds/work/*/_lib_nopow/_k2pow copies):

    function {:opaque} pow(b: real, k: nat): real { if k == 0 then 1.0 else b * pow(b, k - 1) }
    lemma PowSucc(b: real, k: nat) ensures pow(b, k + 1) == b * pow(b, k) { reveal pow(); }
    

    General rule. A postcondition that mentions the function at a new argument is a trigger generator. Keep

    recursive facts in lemmas you call. The same applies to transparent Complex.add/mul bodies, which flooded the

    amc12a_2009_p15 queries.

    Rule 3 — Call the lemma the automation would have used, including argument-free facts (K5)

    Evidence.

  • 54 lines close by one explicit lemma call (30% of the 183 lines where this was tried) [81, 44%]. The pre-review count
  • included 15 lines that already verified, 10 vacuous closes in amc12a_2003_p25 (inconsistent hypotheses) and 2

    multi-fix closes.

  • 47 distinct lemmas are involved. The most frequent are Real.sqrt_nonneg (×10), Linarith.mul_zero_eq (×8),
  • Real.le_sqrt (×6), sin_pi_div_two/sin_zero/cos_zero/cos_pi_div_two (×10 together), div_eq_iff,

    add_div' and Finset.sum_singleton.

  • For norm_num steps the information is genuinely missing: only 2 of 72 such lines verify standalone, and 27 close
  • with the lemma call.

    Cost. One library entry if the lemma is missing (state the exact Mathlib theorem), plus one call per use.

    Before (amc12a_2021_p19, line 1726, OOR; Lean: norm_num):

    assert Real.sin(Real.pi() / 2.0) == 1.0;
    

    After (verifies):

    RealSinPiDivTwo();   // Mathlib Real.sin_pi_div_two, in norm_num's simp set
    assert Real.sin(Real.pi() / 2.0) == 1.0;
    

    For denominators, field_simp's work is div_eq_iff. On aime_1983_p1-1057, DivEqIffReal(24.0L, 2.0/5.0L, 60.0)

    closes a line that fails even when the cleared equation is already in scope.

    Rule 4 — Compute ground values and polynomial normal forms outside the solver, then assert them (K2, values)

    Evidence.

  • 28 lines close when the value or normal form that Lean computed is asserted [40; 12 of those already verified
  • unchanged]. Examples: gcd(83, 14) = 1, 2^2012 as a numeral chain, (4k)^2 = k^2·16, Icc(-3,7) = {-3,…,7}.

  • Together with Rule 2, computation is judged a cause on 213 lines (43%).
  • It is the dominant kind when a single norm_num/ring_nf/decide call is missing: 124 of the 209 lines with one
  • missing Lean line.

    Cost. Per line. Take the value from Lean's records (IsNat/IsRat evaluation records, the ring_nf before- and

    after-states) and assert it as a checked fact.

    Before (numbertheory_aoddbdiv4asqpbsqmod8eq1, line 184, OOR even in a minimal lemma):

    assert NatDvd(8, (4 * k) * (4 * k));
    

    After (verifies):

    assert 4 * k * (4 * k) == k * k * 16;   // Lean ring_nf: (4k)^2 = k^2*16
    assert NatDvd(8, (4 * k) * (4 * k));
    

    In a case split, also assert the evaluated instance. In mathd_numbertheory_618 branch n = 7, either

    assert p(7) == 83 or assert gcd(83, 14) == 1 closes assert false. Dafny's gcd unfolds only on literals.

    Rule 5 — State the instance you need; never rely on E-matching for ∀-facts over arithmetic (K1)

    Evidence.

  • 42 lines close soundly with the instance stated (26% of the 159 lines where it was tried) [56, 36%]. Three
  • pre-review "K1" closes were in fact the ghost-trigger rendering of Rule 8.

  • Instances appear in another 31 lines that need a combination of fixes.
  • The failure shows up as an error, not OOR: 34 of the 58 K1 closes are on ERR lines.
  • A ∀ whose body has no uninterpreted function application has no trigger, so Z3 never instantiates it.
  • Cost. Per line. Lean's inst records and hint lists (linarith [h₅ 0, h₅ 1]) give the arguments.

    Before (amc12a_2009_p9, line 388, fails although forall x :: xx3.0 + x(18.0+b) + (27.0+3.0b+c) == … is in

    scope; Lean: linarith [h₅ 0, h₅ 1, h₅ 2, h₅ 3]):

    assert 3.0 * 6.0 + b == 7.0;
    

    After (verifies):

    assert 0.0*0.0*3.0 + 0.0*(3.0*6.0 + b) + (3.0*9.0 + b*3.0 + c) == 0.0*0.0*3.0 + 0.0*7.0 + 4.0;  // h₅ 0
    assert 1.0*1.0*3.0 + 1.0*(3.0*6.0 + b) + (3.0*9.0 + b*3.0 + c) == 1.0*1.0*3.0 + 1.0*7.0 + 4.0;  // h₅ 1
    // … h₅ 2, h₅ 3
    assert 3.0 * 6.0 + b == 7.0;
    

    Rule 6 — Make types explicit: cast injectivity, ℕ non-negativity, ∣ ↔ % (K4)

    Evidence.

  • 31 lines close (40% of the 77 lines where this was tried) [33, 44%]. Nine lemmas cover all of them.
  • The lemmas are RatCastInjective (×12, ℚ→ℝ), IntMulNonneg/MulNonnegInt (×9, ℕ products in int slots),
  • RatCastNeg (×5), IntDvdIffEmodEqZero (×3) and others.

    Cost. A handful of library lemmas, each called where a cast or divisibility form changes.

    Before (aime_1987_p5, line 594; h : (3(xx)+1) % 507 == 0 is in scope):

    assert exists k: int :: 507 == (3 * (x * x) + 1) * k;   // fails
    

    After (verifies):

    IntDvdIffEmodEqZero(3 * (x * x) + 1, 507);   // Mathlib Int.dvd_iff_emod_eq_zero: in Lean ∣ *is* the ∃
    assert exists k: int :: 507 == (3 * (x * x) + 1) * k;
    

    Pick one representation for each Lean term. k^2 rendered both as Int.pow(k,2) and as k*k without a bridge

    broke 4 lines.

    Rule 7 — Pass simple variables, not compound terms, to lemmas; assert the conclusion at the call site (encoding, K0)

    Evidence.

  • 16 lines fail even though the called lemma is exactly Lean's step: its preconditions are literally in scope, or its
  • ensures is literally the goal, but the arguments are compound nonlinear terms.

  • These are MulPos(xx, yy), SqPosOfNeZero(x-y) and mul_pos_of_neg_of_neg at 2x-3.
  • The same fact as a plain assert, or as a requires, verifies.
  • Before (algebra_bleqa_apbon2msqrtableqambsqon8b, line 33; standalone: "a precondition for this call could not be

    proved", twice):

    lemma Piece(x: real, y: real) requires 0.0 < x * x  requires 0.0 < y * y  ensures 0.0 < (x * x) * (y * y)
    { MulPos(x * x, y * y); }
    

    After (verifies):

    lemma Piece(x: real, y: real) requires 0.0 < x * x  requires 0.0 < y * y  ensures 0.0 < (x * x) * (y * y)
    { }
    

    Alternatively, bind the compound term to a variable (var u := xx; var v := yy; MulPos(u, v);) and state the lemma's

    conclusion about u, v.

    Rule 8 — Give arithmetic ∃/∀ bodies a trigger by wrapping them in a named ghost function (encoding, K1/K0)

    Evidence.

  • 10 lines close by rendering alone. Seven are amc12a_2003_p25 ×5 and aime_1983_p3 ×2 (an ensures-free sqrt);
  • amc12a_2003_p25's own hypotheses are inconsistent, so its non-vacuity rests on the reviewers' minimal lemmas. The

    other three are numbertheory_fxeq…-407/-413/-442, re-filed here from K1.

  • A restated ∃ that is identical to a hypothesis cannot be proved from it when its body is pure arithmetic.
  • Before (numbertheory_fxeq4powxp6powxp9powx_f2powmdvdf2pown, line 413; fails even with the witness asserted):

    ensures exists t: nat :: n == m + t
    { assert 0 <= tsub(n, m) && n == m + tsub(n, m); }
    

    After (verifies):

    ghost function NatId(x: nat): nat { x }   // identity: gives the body a trigger term
    ensures exists t: nat :: n == m + NatId(t)
    { assert n == m + NatId(tsub(n, m)); }
    

    Rule 9 — Know what not to attempt (true limits; K0 and unclosed K2)

    About 9 lines judged K0, plus up to 28 lines judged computation or lemma whose every augmentation stayed failed or

    OOR, involve the following:

  • Degree ≥ 4 real arithmetic over √/trig atoms. imo_1965_p1-1093: Z3 does not refute
  • 0≤c, u<0, c·u≤0, 0<u·u, 4cu−u² = 0.

  • Field identities with symbolic trig/pow denominators. imo_1966_p4-196/-286/-329.
  • Quantified nonlinear trig bodies. These fail even with the instance supplied (aime_1999_p11-335).
  • Kernel-size evaluation. Examples are 10000! % (2^5000·5000!) = 0 (amc12_2001_p5-18) and complex power sums
  • (amc12a_2009_p15).

    Do not spend solver time on these. Transfer Lean's result as checked facts small enough for Z3: the normal form,

    the evaluated value, or the two Positivstellensatz products as separate asserts. imo_1965_p1-833 closed this way,

    with normal-form asserts plus a mul_eq_zero lemma. Otherwise leave an honest, marked gap. Never write assume.

    ---

    Ranking (lines recovered per unit of effort)

    rankrulelines (discriminating closes alone) [pre-review]marginal in greedy ordereffort
    1Rule 2: non-recursive / opaque pow57 [83]+51one library edit
    2Rule 1: one lemma per step, only its facts176 [182]+176mechanical, per step
    3Rule 6: type bridges31 [33]+269 lemmas + calls
    4Rule 3: automation lemmas54 [81]+6347 lemmas + calls
    5Rule 7: simple lemma arguments16 (recovered by a plain assert)—rendering rule
    6Rule 8: ghost-function triggers10 [7]+10rendering rule
    7Rule 4: computed values / normal forms28 [40]+52per line, needs Lean's values
    8Rule 5: explicit instances42 [56]+35per line, needs Lean's arguments

    Applying rules 1–8 together recovers 413 of 499 lines (83%) in standalone checks (sound closes only; after

    the second review, CONCLUSION §10; 428 before it). That result is not yet confirmed

    in-file. Rules 2, 6, 7 and 8 are one-time library or rendering decisions. Rules 3, 4 and 5 need per-line information,

    which an ITP proof already contains: its tactic records.

    Systematic gaps of the lines that miss 1–3 Lean lines

    The 267 integ5 failing lines whose corrected missing Lean block (above) is 1–3 lines were grouped into 37 clusters; for each, two independent analysts asked “why does it fail?” and “what closes it?”, one synthesis per fix task followed, and two skeptic passes per task tried to refute it. Only mechanisms the skeptics confirmed or partly confirmed are kept. Every “closes” below is a standalone Dafny check of an extracted line lemma (or a hand-built equivalent) under the corpus flags; no theorem file was re-verified, so no fix has an in-file result yet. Source: classify5/gaps/GAPS_REPORT.md (stage g3_report, 2026-10-03), shown here with its section numbers.

    Scope, how the report was produced, terms used

    Scope. integ5 has 499 failing Dafny lines. This report covers the 267 of them where the Lean proof skips only 1–3 source lines at that point (gaps/lines.jsonl: 209 lines miss 1 Lean line, 32 miss 2, 26 miss 3; 192 out-of-resource, 75 errors). Three reviewers had assigned each line a fix task:

    tasklinesmeaning
    TRANSLATOR98the Lean→Dafny translator should emit something different
    SOLVER87the facts are there, but Z3 cannot use them
    LIBRARY73the Dafny library (MathPrelude.dfy / library_new.dfy) is missing a lemma or encodes something badly
    HARVEST9the Lean-side record of what each tactic did is missing a fact

    How this report was produced (details in §5):

    1. The lines were grouped into 37 clusters (c001–c037).
    2. Two independent analysts studied each cluster: ROOT asked "why does it fail?" and FIX asked "what closes it?" (gaps/out/*.json, ~2,600 Dafny outputs under gaps/work/).
    3. One synthesis per task (gaps/task/<TASK>.md).
    4. Two skeptic passes per task tried to refute each synthesis (gaps/task/<TASK>.skeptic*.md).

    This report keeps only the mechanisms that the skeptics confirmed or partly confirmed, and says where they corrected something.

    Terms used below

    • Line lemma. One failing Dafny line cut out of its theorem file into a standalone lemma with the same hypotheses (requires) and goal (ensures). The "trimmed" version keeps only the hypotheses a static trimmer judged relevant.
    • Closes. Dafny verifies the line lemma, or a hand-built equivalent, under the corpus flags. Every "closes" in this report is a standalone check. No theorem file was re-verified.
    • OOR (out of resource). Z3 used up its budget of 1,000,000 resource units before finishing.
    • Matching loop. A universally quantified fact that, each time Z3 uses it, creates a new term that triggers it again. Z3 keeps instantiating it until the budget is gone.
    • Trigger. The term pattern Z3 waits to see before it uses a "for all" fact. With no usable trigger, the fact is never used.
    • Harvest record. The per-tactic log extracted from Lean's proof term: which lemma was applied, with which arguments. The translator only cites lemmas that a record backs (the "record-only policy").

    1. The answer in one paragraph

    Most of the 267 lines are not hard for the solver. They fail because of a small number of systematic defects, and nearly all of them were closed in standalone experiments by fixing the defect without touching the goal.

    The biggest single cause is the library's encoding of powers. This is LIBRARY.

    • What is wrong: Int.pow/Real.pow restate their own recursion as a postcondition, which makes Z3 unfold 2^n → 2^(n-1) → … endlessly. Dafny's fuel mechanism also writes the same 2^m as two different SMT terms. A second, smaller library defect: the bodies of Complex add/mul are visible, which floods the query.
    • Size: 60 of the 87 "SOLVER" lines and 43 of the 73 "LIBRARY" lines are really this power defect. Together with imo_1966_p4-174 this is about 104 of the 267; counting the Complex defect too, about 115.
    • Evidence: replaying Dafny's own in-file queries with the recursive postcondition removed closes 104 of all 499 failing lines.

    TRANSLATOR (98 lines). About 86 are genuine translator gaps:

    • Lean computed a number (for example gcd 691 52 = 1) and the translator wrote only a comment: 35 lines.
    • Lean applied a lemma, it was recorded, and the translator still dropped it: 10.
    • The same object is written in two incompatible Dafny forms with no bridge between them: 15.
    • A rewrite is stated without the equality that justifies it: 9.
    • A "for all" fact is rendered with no usable trigger: 12.
    • A local step is checked against the whole theorem's context: 5.

    The other 12 are not translator problems: 11 are harvest gaps and 1 is the power defect.

    HARVEST (9 lines; really 23). The Lean harvester never records lemmas used as bare constants (Real.cos_zero) or wrapped by simp (_auxLemma), and it drops class-field aliases. Those three code defects explain 3 of the 9 HARVEST lines plus 12 lines labelled TRANSLATOR/LIBRARY. One added translator call closes each of them.

    SOLVER (87 lines; really 10). After analysis only 10 lines are still SOLVER: true solver limits or unresolved cases.

    Corrected task count: TRANSLATOR 97, LIBRARY 137, HARVEST 23, SOLVER 10 (§3).


    2. Mechanisms per task

    Every mechanism below was confirmed or partly confirmed by the skeptics. "Corrected" marks a skeptic correction. Line ids are theorem-DafnyLine. "Gap set" means the 267 lines; "corpus" means all 499 failing lines or all 101 outputs.

    2.1 TRANSLATOR — mechanisms, examples, fixes
    idmechanismgap linesclosed in testsskeptic verdict
    T1norm_num evaluations written as comments3535holds
    T2recorded lemma applications that never become a call108 record-backed (+285 by goal pattern, +32 half)partly
    T3lemma never recorded → moved to HARVEST1212holds (root is HARVEST)
    T4one object, two encodings, no bridge1513 (452 corrected)partly
    T5rewrite stated without its justifying equality96 by instance + 3 by "ghost Mul" renderingpartly
    T6quantifier with no usable trigger1211holds
    T7local step checked in the whole context53 (+1 partial)partly
    T1 — Lean's computed values are reduced to a comment (35 lines: mathd_numbertheory_618 ×32, amc12a_2021_p18 ×3)
    • What is missing. The numeric fact Lean computed, for example Nat.gcd 691 52 = 1 or (5:ℚ)*5 = 25.
    • Why.
      • The harvest has the record, with the numbers. For example isNat_gcd at exec 479 has x=691, y=52, z=1.
      • The translator's loader keeps only the lemma's name for these "internal" norm_num records, throws the arguments away, and prints // UNCITED-APPLIED internal ×N.
      • Dafny can evaluate gcd(691, 52) itself, but only when every argument is a literal. In the file it sees gcd(p(26), 2*26), where p is a local function.
      • For ℚ there is a second problem: Dafny knows two ℚ values have the same real value, but nothing says that makes them equal.
    • Where. dafny_emit_v2.py:3005-3024 (the loader drops the arguments and continues); drop_sweep.py:247,636 (writes the comment); the library has no Rat.cast_injective.
    • Example. mathd_numbertheory_618-315, the branch n = 26 of an interval_cases:
      Dafny  : assert false;  // sub-goal of norm_num
               (under the guard 1 < gcd(p(26), 2*26), with requires forall x :: p(x) == tsub(x*x,x)+41)
      Lean 45: interval_cases n <;> norm_num [h₀, Nat.gcd_eq_right, …] at h₄ ⊢      -- goal: False
      record : Tactic.NormNum.isNat_gcd (691, 52, z = 1)
      fix    : assert gcd(691, 52) == 1;   // norm_num evaluation (Lean exec 479)
    • General fix. Transcribe the numerals that are already in the record into a checked assert <term> == <value>;. Use this only where Dafny cannot evaluate the term itself. For ℚ, add the axiom RatCastInj (= Mathlib Rat.cast_injective) and call it for each isNat_mul/isRat_mul record.
    • Correction (skeptic). The fix must transcribe the record's own numerals. It must not fold constants in the translator: gcd(691, 2*26) is OOR, while gcd(691, 52) verifies (runs s01/s02).
    • Tests.
      • All 32 branches of 618 close as minimal lemmas, and on the verbatim 40-branch block (669 verified).
      • The skeptic built its own control for n = 38: it fails without the assert and verifies with it.
      • The 3 lines of p18 close with RatCastInj.
      • Caveat: the minimal lemmas for 618-183 and 618-189 also close without the fix, so those two are partly a context effect.
    • Corpus.
      • 618-139, the outer by_contra, stays OOR even after the fix.
      • 63 of the 499 failing lines carry IsNat/IsInt/IsRat records. That is an upper bound, and it is untested.
    • Effort and risk. Small to medium. Soundness: none, since the asserts are checked. The only new axiom is RatCastInj, which is exact Mathlib and was Lean-checked by the analysts (needs approval).
    T2 — Recorded lemma applications that never become a call (10 lines)
    • What is missing. A lemma call that Lean made and the harvest recorded. The library has the lemma.
    • Why. There are two routes:
      • (a) The loader discards records whose name is not a key of the citation table, before they reach the citation path. The specialised mapping injOn_cos.eq_iff → RealInjOnCosEqIff is therefore dead code. The same filter drops Nat.mod_mod_of_dvd, Int.card_Icc and Finset.Icc_eq_empty_of_lt.
      • (b) The record's arguments do not fit the Dafny signature. In orderOf_eq_iff the ZMod modulus is inside a type. Finset.mul_sum is over a set<nat>.
    • Where. dafny_emit_v2.py:3009-3024 (loader); _cite_state_args :5609 / :5543 (projection).
    • Example. amc12a_2021_p19-1352:
      Dafny  : assert (x == (Real.pi() / 2.0)) by {…}
               // UNCITED-APPLIED Set.InjOn.eq_iff …: library counterpart RealInjOnCosEqIff … exists
      Lean 126: apply (injOn_cos.eq_iff ⟨…⟩ ⟨…⟩).1        -- goal: x = π/2
      record : Set.InjOn.eq_iff(Icc 0 π, cos, x, π/2), in_table = false (exec 1563)
    • General fix.
      • Admit records at load time: re-key them to the specialised entries, and add an alias table from internal names to existing exact lemmas (Nat.mod_mod_of_dvd → NatModModTotal, …).
      • Add argument adapters: take the ZMod modulus from the type; map mul_sum to FinsetMulSumPointwise.
    • Tests. Closed: 855, 1352, 1564, 545, 366, 40, 224 (both lenses). 32 is closed only half record-backed (s06). 197 is not closed: the cite is right, but the context is still OOR.
    • Corrections (skeptic).
      • mathd_algebra_170-285 has no record: its Lean step is a kernel rfl. Its fix (IntIccCard) is a goal-pattern guess, so it is not T2.
      • imo_1959_p1-32 (labelled LIBRARY) is blocked by the same loader gate. The synthesis did not list it.
    • Corpus. The harvest has 12,827 internal, not-in-table records; most are glue.
    • Effort and risk. Small (loader, table) to medium (adapters). Sound when existing exact lemmas are used. IntIccCard is a derived axiom, not literal Mathlib. The new Real.div lemmas (div_div, div_mul_eq_mul_div, mul_div_assoc') were Lean-checked. Both need approval.
    T4 — One Lean object, two Dafny encodings, and no bridge between them (15 lines)
    • What is missing. A trivial fact saying that two Dafny spellings of the same Lean object agree.
    • Where the seams are.
      seamDafny sidelines
      ℕ product rendered as an intDafny then asks to prove 0 <= k*Int.pow(2,n+4), which has no Lean counterpart (lean_expr_ir.py:218, _need_cast)amc12_2001_p5-11, 3pow… 124/146/177/261/283/314
      use w on a divisibility goaluse w only states b == a*w; Dafny's IntDvd is %-based and there is no Dvd.intro516 (452: see correction)
      x*x vs Real.pow(x,2)statements unroll literal exponents to products, but cite arguments and library postconditions keep Real.pow(·,2)222, 530
      Real.div vs /LeDivIff is stated with /, the goal uses Real.div949
      Irrationalthe predicate is opaque; exact h ⟨2, _⟩ becomes a GAP comment198
      Icc membership vs boundsa ∀ restatement guards with k in IccN(a,b), the facts use a <= k <= b212
      numeral cast not foldedrpow(2.0, (2 as real)*(m*n)) vs rpow(2.0, 2.0*(m*n)) are different terms137
    • Example. numbertheory_3pow2pownm1mod2pownp3eq2pownp2-124:
      Dafny  : assert NatDvd(Int.pow(2, (n + 4)), (k * Int.pow(2, (n + 4)))) by {…}
               -- the failing check is the hidden "is k*Int.pow(2,n+4) a nat?"
      Lean 52: exact ⟨k, by ring⟩          -- in ℕ, so there is no sign obligation
      fix    : IntMulNonneg(k, Int.pow(2, n+4));   -- verified 51/0
    • General fix. One rule: never emit the two sides of a step in different encodings without a bridge.
      • Use IntMulNonneg for ℕ products.
      • Add IntDvdIntro/NatDvdIntro (= Mathlib Dvd.intro).
      • Use one renderer for squares.
      • Restate LeDivIff and its 15 siblings over Real.div.
      • Use NotIrrationalNatCast.
      • Fold numeral casts.
      • Longer term: a nat-valued pow.
    • Tests. 13 confirmed closes (516, 198, 137, 11 re-run by the skeptics).
    • Corrections (skeptic).
      • aime_1987_p5-452 is not a missing bridge. Its untrimmed line lemma already verifies without any fix. The trimmed lemma fails only because the static trimmer dropped Lean's hypothesis h₂₁₂. In the file it is OOR, so it is a context line.
      • 949 likewise closes standalone without a fix.
      • The fix is a family of seven small rules, not one rule.
    • Corpus. 459 non-literal products passed to nat slots in 11 files; 14 failing lines with this nat-subset check.
    • Effort and risk. Medium. The new axioms (Dvd.intro, Irrational.ne_rat, le_div_iff over Real.div) are exact Mathlib and were Lean-checked. They need approval.
    T5 — A rewrite step is stated without the equality that justifies it (9 lines)
    • What is missing. rw, ring_nf or field_simp rewrote inside a function (under √, %, /, or in a hypothesis). Dafny states the result but not the argument equality, and Z3 never connects F(e) with F(e').
    • Where.
      • The recorded congrArg is dropped as "no library counterpart" (dafny_emit_v2.py:1402-1406; 1,431–1,433 such comments in 80 files, depending on the grep).
      • @tac-hyp restatements are emitted before the execution's cites (:11747-11823).
    • Example. numbertheory_aoddbdiv4asqpbsqmod8eq1-184:
      Dafny  : assert NatDvd(8, ((4 * k) * (4 * k))) by {…}
      Lean 38: ring_nf at *                     -- goal: 8 ∣ (4k)^2
      fix    : assert (4*k)*(4*k) == k*k*16;    -- verified 12/0 (skeptic re-run)
    • General fix.
      • Diff Lean's recorded before/after goals and assert each changed argument equality, on literal terms.
      • Emit cites before @tac-hyp asserts.
      • State instances of "for all" hypotheses inside forall-statements.
    • Tests. Closed: 192, 415, 184, 945, 213 (which also needs the unrecorded Real.sqrt_one), 181.
    • Correction (skeptic). For amc12b_2003_p17-101/-102 and amc12b_2021_p9-412 the instance is present and still useless. They close only when products under functions are rendered through one transparent ghost Mul(a,b), so they are really an encoding seam (T4 family). The ghost-Mul rule changes how library postconditions are rendered. Its effect on the 33,014 obligations that verify today is untested. This is the largest unquantified risk in the TRANSLATOR fixes.
    • Effort and risk. Medium to high. Sound, because the asserts are checked and Mul is transparent.
    T6 — Quantifiers rendered with nothing for Z3 to match (12 lines)
    • What is missing. Nothing is missing as a fact. A "there exists" or "for all" fact is in scope, but its bound variable occurs only inside arithmetic, which Dafny will not use as a trigger. Alternatively, Dafny rejects the natural trigger f(n) as a possible loop, and the side-terms it picks instead never occur at the line.
    • Where. lean_expr_dafny.py:556-632 (the ∃ branch never emits a trigger) and expr_render._render_quant :626-674. verify5 reports "Could not find a trigger" on each amc12a_2003_p25 line.
    • Example. amc12a_2003_p25-43:
      Dafny  : assert (exists x: real :: (Real.sqrt(((a * (x * x)) + (b * x))) == 0.0));
               // hypothesis h₄ after simp
      Lean 21: simp at h₄ h₅ h₆ h₇ h₈          -- only removes `True ↔` / `True ∧`
      The skeptic's minimal pair, with identical bodies:
      • plain: fails;
      • with the arithmetic body lifted into a transparent ghost function: verifies.
    • General fix.
      • (a) Lift each arithmetic subterm that contains a bound variable into a transparent ghost function, named by its structure, so hypothesis, restatement and goal share one name.
      • (b) For shifted recurrences f(n) = f(n-1)+1, assert Lean's instance at each ground f(t) (rule I).
      • Do not pin {:trigger f(n)}: run s08 went OOR.
    • Tests. 43–47, 413 and amc12a_2017_p7-28/48/54/67/74 close. Rule I passes 81/0 on the whole helper. Not closed: amc12a_2003_p25-26.
    • Corpus. 84 no-trigger warnings in 17 files; 41 loop-rejected triggers in 7 files.
    • Effort and risk. Medium. Sound.
    T7 — A local step checked against the whole theorem (5 lines; much larger corpus-wide)
    • What is missing. Nothing is missing. Lean proves the step from a few named hypotheses. Dafny checks it with every earlier fact of the theorem in scope, and Z3 drowns.
    • Where. The v2 emitter inlines every have/@tac-hyp (dafny_emit_v2.py:7745, :11818). Lean's per-step dependency record (have_deps) is harvested for 102 theorems, but v2 never reads it. Only the rules emitter does, opt-in (KMAX_TRIM).
    • Example. imo_1992_p1-5471:
      Dafny   : assert (-(1) + p*q*r) == … ;  // hypothesis hk after ring_nf
      Lean 391: ring_nf at hk ⊢
      fix     : a helper lemma that requires only hk, called in place — verified 7/0
    • Tests. Closed: 488, 5471. 564 is partial.
    • Corrections (skeptic).
      • imo_1984_p2-1725 is only partly closed: its helper is still OOR because of the power loop (L1). That is the same reason imo_1966_p4-174 was moved to LIBRARY.
    • Corpus.
      • 160 of 499 failing lines (62 in the gap set) close standalone, so context is a large residual cause.
      • About 60 consensus lines outside the gap set ask for the same isolation.
    • Effort and risk. High: a new emission shape. Sound, because helper preconditions are re-checked at the call. The completeness cost was measured on the rules track: KMAX_TRIM took strict-clean files from 29 to 18.
    2.2 LIBRARY — mechanisms, examples, fixes
    idmechanismgap linesclosed in testsverdict
    L1power encoding (matching loop, fuel split, transparent ℂ ops)43 (+64–70 from SOLVER)30 by some variant; 15/17 under the recommended U2mechanism holds; fix and count partly
    L2ℚ: no cast injectivity; always-on nonlinear to_real55holds
    L3recorded instance has no library lemma at that type187 by new lemmas alone; +6 that also need L1c and translator work; +1 existing lemmapartly
    L4library conclusion shaped so Z3 cannot match the goal55, but cleanly library only for 2partly
    L1 — The library's pow makes Z3 loop (the largest mechanism in the report)
    • What is wrong. Nothing is missing. Lean treats 2^n as an opaque value. The library defines Int.pow/Real.pow recursively and repeats the recursion as a postcondition:
      ensures if k == 0 then p == 1 else p == b * pow(b, k - 1)      // MathPrelude.dfy:52-56, :90-96
      This causes three problems:
      • Matching loop. Z3 may apply the postcondition without bound: pow(2,n) produces pow(2,n-1), then pow(2,n-2), and so on, until the budget is gone.
      • Fuel split. Dafny writes the same pow(2,m) as two different SMT terms, one in the goal and one in the facts. Inside cos(pow(2,m)*x), Z3 cannot see that the goal is a fact it already has.
      • Transparent ℂ arithmetic. The ℂ add/mul/of_real bodies are visible and get expanded everywhere.
    • Where. Generated from symbol_table.py:117-123, :183-191 and :540-543. The translator's use of ^ → pow is faithful.
    • Examples.
      imo_1964_p1_2-95 (OOR)
        Dafny: assert !(((Int.pow(2, n) + 1) % 7) == 0);
               -- linear over the atom 2^n, with 2^n % 7 = 1 in scope
        Lean : a simp step
        Result: closes once the recursive postcondition is replaced.
      
      numbertheory_3pow2pownm1mod2pownp3eq2pownp2-510 (OOR)
        Dafny: assert NatMod(Int.pow(2,n+2) + k*Int.pow(2,n+3), Int.pow(2,n+3))
                      == NatMod(Int.pow(2,n+2), Int.pow(2,n+3)) by {…}
        Lean 141-142: have h₂ … whose nested h₃ is the identical statement
        Result: Dafny's own in-file query with only the recursive conjunct removed is unsat at 53,865
                (base: unknown at 1,008,025).
    • Size.
      • Gap set: 43 LIBRARY lines, plus 60 lines filed as SOLVER M1, plus 11 SOLVER Complex lines (M2).
      • Corpus: the recursive-conjunct ablation closes 104 of 499 failing lines; fuel normalisation flips 30 of 45 imo_1966_p4 lines; 191 failing lines sit in procedures with a symbolic-exponent pow.
    • The fix is not settled. Three syntheses recommend three different variants:
      variantwhat it isknown goodknown bad
      U2 (LIBRARY synthesis)closed forms for k ≤ 6 + {:fuel 1,1}hoisted imo_1966_p4 block 121/123leaves imo_1964_p1_1-27 and imo_1966_p4-190 OOR (skeptic); fails pow(x,8)=pow(x,4)^2
      F33 (SOLVER synthesis){:fuel 3,3} + k==0 ⇒ p==10 of 12 regression probes failleaves amc12a_2021_p14-542/-548 and in-file 329/364 OOR
      W33 (preferred by the SOLVER skeptic)non-recursive wrapper over a {:fuel 3,3} recursive powcloses 542, 548, 535, 175-1071 probe regression (x^3, symbolic base); untested on the imo_1966_p4 block
      All three variants are sound: they only remove a postcondition that Dafny proves, or change fuel. No axiom and no assume. Recommendation. Remove the recursive postcondition, adopt W33 or F33 plus emitting the existing PowSucc/IntPowSucc cites where Lean's ring normal form has pow(b,k+1), then decide by a whole-corpus run. A whole-corpus run is the only way to measure regressions, and it was not allowed here.
    • Library integrity finding. The shipped MathPrelude does not prove its own Real.pow postcondition: a standalone check gives 136 verified and 1 error at :55. Nobody sees this, because included files are not verified. Both skeptics confirmed it.
    • Complex part (SOLVER M2, 11 lines).
      • Cause: the visible bodies of Complex.add/mul/of_real, not Complex.pow (refuted in three lenses).
      • Fix: opaque Complex operations with proved field postconditions.
      • Tests: 7 closed, 3 partial, 1 untestable.
      • Corpus: 10 more failing lines outside the gap set close in raw replay with only the mul body removed.
    • Effort and risk. About 6–15 lines in symbol_table.py plus ~30 for ℂ. Needs the user's corpus re-verify before adoption.
    L2 — ℚ cannot conclude equality from equal values (5 lines; +12 with the same axiom)
    • What is missing. Mathlib Rat.cast_injective. Dafny's ℚ operations are known only through their real value. A second layer: an always-on nonlinear postcondition to_real == num/denom on every ℚ term.
    • Example. aime_1984_p1-35:
      Dafny  : assert (u(0) == Rat.add(u(0), Rat.of_int(0)))
      Lean 16: norm_num          -- internally add_zero
      It closes with RatCastInj.
    • Fix (libB2, tested).
      • Add the axiom RatCastInj.
      • Drop the always-on to_real postcondition.
      • Make Rat.of_int/Rat.neg axiom functions with the exact Mathlib statements. Seven statements were Lean-checked (rc 0).
      • Translator: emit RatCastInj(lhs, rhs) before each ℚ equality, and make the ring-identity exemption sort-aware.
    • Tests. All 5 close. The skeptic re-ran 35 and 1170 under libB2 as well. 12 more lines close with RatCastInj alone (aime_1984_p1 ×6, aime_1999_p11-1161, amc12a_2009_p2 ×2, amc12a_2021_p18 ×3).
    • Corrections (skeptic).
      • The analysts' first version (libB) had 2 postconditions Dafny cannot prove. libB2 fixes that.
      • Unmeasured: the cost to ℚ order facts once to_real's postcondition is gone.
    • Effort and risk. About 20 library lines plus one emitter rule. Axioms → needs approval.
    L3 — The lemma Lean used exists in the library only at another type (18 lines)
    • What is missing. A library lemma at the right type. For example, Finset.sum_singleton exists only for ℝ and ℤ, but every recorded use is at ℕ. Also missing: Nat.gcd_self_add_right, and Complex.re_sum/im_sum/ofReal_mul.
    • Example. algebra_sum1onsqrt2to1onsqrt10000lt198-167:
      Dafny: assert Real.sum(IccN(2,2), k => 2.0*(Real.sqrt(k as real) - …))
                    == 2.0*(Real.sqrt(2 as real) - Real.sqrt(1.0))
      Lean : norm_num, internally Finset.Icc_self + Finset.sum_singleton at ℕ
      Adding FinsetSumSingletonNat closes it (trimmed 8/0, original 14/0).
    • Fix. Exact Mathlib axioms at the missing type, registered in the citation table. Decide in_table at emit time instead of freezing it at harvest time.
    • Correction (skeptic). Of the "14 closed":
      • 7 close with new lemmas alone.
      • 1 (462) closes with an existing lemma, so it is a translator cite gap.
      • 6 (amc12a_2009_p15) close only together with hiding Complex ops (L1c) and a translator restructuring.
      • 4 are not closed (546, 1801, p15-45, p15-183 → SOLVER).
    • Effort and risk. Small per lemma. Axioms → needs approval.
    L4 — A library conclusion built in a shape Z3 cannot match (5 lines)
    • What is wrong. A lemma builds a term inside its conclusion that Z3 cannot identify with the goal's spelling of it. For example, FinsetSumAddDistribRat concludes about the lambda x => Rat.add(f(x),g(x)), and Dafny lambdas are not extensional.
    • Example. aime_1984_p1-175:
      Dafny  : assert Rat.sum(range(98), k => Rat.add(u(0), …)) == Rat.add(Rat.sum(range(98), k => u(0)), …)
      Lean 43: rw [Finset.sum_add_distrib]
      fix    : the proved twin FinsetSumAddDistribRatH(s, h, f, g), called with the goal's own lambda — closes
    • Fix. Proved "argument-form" twins. The skeptic verified all four twins: they need no new axiom.
    • Correction (skeptic). The library-shape diagnosis holds cleanly for 175 and 466 only:
      • 22 and 495 also need new axioms;
      • amc12a_2009_p6-28 closes standalone in base, so it is not a library gap.
    • Effort and risk. Moderate (about 10 twins plus one argument kind). Low risk.

    Do not adopt as written. The skeptic found that the analyst axiom NatAddMulModSelfLeft is ill-formed: it is a possible division by zero. Nobody saw this, because included files are not checked. It is not in any recommended fix.

    2.3 SOLVER — mechanisms, examples, fixes

    The SOLVER label turned out to be mostly a symptom label. In 81 of the 87 lines Z3 is not missing a fact; a library or translator defect makes the query expensive.

    idmechanismlineswhere it really belongstested
    S-M1power encoding (= L1)62LIBRARY (60; 156/187 stay SOLVER)57 shown closed, by Dafny or in-file replay (skeptic: not 58; fxeq-318 timed out under F33)
    S-M2transparent Complex arithmetic (= L1c)11LIBRARY7 closed, 3 partial, 1 untestable
    S-M3a cite's conclusion is stated over call temporaries3 → 2TRANSLATOR2; 803 corrected → S-M4
    S-M4monolithic procedure (= T7)0 → 1 primary (803)TRANSLATORtested alternative fix for 9 more
    S-M5ground evaluation Lean did by kernel/simprocs6LIBRARY+TRANSLATOR (4), none (2)4
    S-M6output shape hides in-scope facts (if-guarded cert pieces)3TRANSLATOR569/656 standalone; 698 only as a hand-placed cite
    S-M7genuine solver residue2SOLVER0

    Skeptic corrections.

    • (a) For 44 of the 62 power lines, the unchanged library's line lemma already closes standalone. For those lines the evidence for S-M1 is only the in-file query replay. So "context size" and "power loop" are both sufficient explanations, and neither is necessary. The power fix is still the better one: a single library edit with no per-line scoping.
    • (b) Some "symbolic-exponent" lines actually involve literal pows such as Int.pow(16,502).
    • (c) The recommended fix should be W33 or reopened (see L1).
    • (d) S-M6's 698 closed only with the cite placed by hand. The analyst's translator variant did not close it.

    S-M3 example. algebra_abpbcpcageq3_sumaonsqrtapbgeq3onsqrt2-1725:

    Dafny      : assert (2.0*Real.sqrt(2.0)) * (…sum…) >= (2.0*Real.sqrt(2.0)) * (3.0/4.0) by {…gcongr…}
    Lean 146-148: gcongr <;> linarith
    • The in-file call gcongr_mul_le_mul_left(3/4, S, 2*sqrt 2) fails, even though its conclusion is the goal verbatim. Dafny binds the arguments to temporaries, so the conclusion is "temp × temp". Dafny 4.11 also forces Z3's legacy arithmetic solver.
    • Stating the same lemma as a ghost-function postcondition verifies 14/14.
    • Corpus: 566 cite sites in 55 files have this shape. Inlining the temporaries in raw replay closes 36 failing lines.

    S-M6 example. amc12b_2020_p21-569:

    Dafny  : assert ((k as real)+15.0)*((k as real)+15.0) <= (n as real)
    Lean 74-75: nlinarith [Real.sq_sqrt …, h₉]
    • Lean's certificate pieces are called only under if (premise), even though the premise is a hypothesis.
    • Asserting the guard and calling unconditionally: 14/14; without that change the same lemma fails.
    • Corpus: 466 guarded calls in 37 outputs.
    2.4 HARVEST — mechanisms, examples, fixes
    idmechanismgap linesclosed firmlyverdict
    H1class-field aliases (eq_zero_or_eq_zero_of_mul_eq_zero) dropped by the projection filter32 (205 already closes without the cite)holds
    H2hypothesis-side rewrites not in the record files (90 of 100 predate harvest4)51 (756, and only with a translator reorder)partly
    H3instances of a "for all" hypothesis hidden behind Eq.mp casts11holds (single line; the walker miss is inferred)
    H4bare theorem constants (Real.cos_zero) never recorded87 (+1733 in a hand-built lemma)holds (strongest)
    H5simp _auxLemma wrappers of hint lemmas dropped as internal3 → 42 (+1485 own lemma; +495 with LIBRARY)holds, under-counted
    H4 — Lemmas used as bare constants are never recorded (8 lines, all amc12a_2021_p19)
    • What is missing. cos 0 = 1, sin 0 = 0, cos(π/2) = 0, sin(π/2) = 1. The library has all of them (RealCosZero(), …), but they are called 0 times in all 101 outputs.
    • Why. In Lean's proof term these theorems appear as bare constants, not applications. The harvester's walker ignores every node that is not an application.
    • Where. harvest_goal_states.py:631: the catch-all | _ => pure ().
    • Example. amc12a_2021_p19-1556:
      Dafny   : assert (Real.cos(x) == Real.cos(0.0));
      Lean 154: norm_num [h₅₁₅₄]        -- goal: cos x = cos 0; the proof term contains bare Real.cos_zero
      fix     : RealCosZero();          -- 29/0; without it: 28 verified, 1 error
    • Skeptic controls.
      • The wrong constant (RealSinPiDivTwo() on line 1722) does not close the line. The fix is specific, not "any extra axiom".
      • On line 1668, a goal-pattern rule fails, because sin(π/2) appears only after rewriting. That is why the fix belongs in the harvest, not in a translator guess.
    • Fix. A .const case in walkT that emits a zero-argument record. The existing translator path then cites it.
    • Effort and risk. Small, plus a re-harvest. No new axiom.
    H5 — simp's _auxLemma hides the user's hint lemma
    • Example. amc12b_2020_p21-1245:
      Dafny   : assert (20 as real) <= Real.sqrt(400.0)
      Lean 258: norm_num [Real.le_sqrt, Real.sqrt_lt]
                -- simp wraps the hint as _auxLemma.1 := propext (Real.le_sqrt …)
      fix     : RealLeSqrt(20.0, 400.0)   -- 8/0; control: 1 error
    • Skeptic addition. A Lean probe shows that aime_1987_p5-495 (labelled LIBRARY) is the same mechanism. Its _auxLemmas come from dvd_add_right and from a Mathlib-module simp lemma (dvd_mul_left). So the fix must also unfold Mathlib-module _auxLemmas, not only the user's hints.
    • Corpus. 4 more lines of amc12b_2020_p21 outside the gap set close the same way. There are 898 "arguments unknown" comments in 63 files.
    • Fix. When the head is _auxLemma.N, unfold it to the underlying theorem with its arguments.
    • Effort and risk. Small, plus a re-harvest.
    H1 — class-field aliases are dropped (mathd_algebra_156-251, -313; aime_1990_p4-205)
    Dafny: assert ((x*x-2.0)==0.0) || ((x*x-3.0)==0.0)
    Lean : apply eq_zero_or_eq_zero_of_mul_eq_zero h₇₂
    • Why. The Lean constant is the class field NoZeroDivisors.eq_zero_or_eq_zero_of_mul_eq_zero, which the harvester filters as a "projection".
    • Fix. Map table keys to their resolved constants (an alias map). The FIX lens ran the patched harvest through the unmodified translator, and exactly these 3 lines gained the call.
    • Tests. Controls fail without the call and verify with it. 205 already verifies standalone, so for that line the fix is plausible but unproven.
    H2 — hypothesis-side records missing (5 lines)

    Facts.

    • Only 10 of 100 record files were made by harvest4, the version that records hypothesis rewrites. amc12a_2019_p21 has no record at all.
    • There are 2,795 @tac-hyp asserts and 54 failing @tac-hyp lines.

    Re-harvesting alone closes none of the 5 lines.

    • mathd_algebra_756-231:
      Dafny: assert (a*Real.log(2.0)) == Real.log(32.0);  // h₄ after rw
      Lean : rw [Real.log_rpow …] at h₄
      The cite is in the file, 3 lines too late. The skeptic found that the record is mis-attributed to a later execution, not absent. Closing the line also needs a translator rule: emit cites before the @tac-hyp restatement.
    • The 4 amc12a_2009_p15 lines also need term-bound ∀ instances (TRANSLATOR) and the Complex fix (LIBRARY).
    H3 — one line (amc12a_2009_p9-388)
    • linarith [h₅ 0, h₅ 1, …] after simp_all produces Eq.mp … h₅ 0. The harvester's instance test needs a bare hypothesis head, so nothing is recorded.
    • Asserting h₅ 0 and h₅ 1 closes the line.

    3.1 Lines that moved between tasks (consensus task → corrected task)
    3.1 Lines that moved between tasks

    The script gaps/g3_corrected_tasks.py writes gaps/corrected_tasks.jsonl (one row per line, with the reason). Every move comes from a synthesis or skeptic finding cited above.

    consensus ↓ / corrected →TRANSLATORLIBRARYSOLVERHARVESTtotal
    TRANSLATOR861 (imo_1966_p4-174, power loop)011 (H4 ×8, H5 ×3)98
    LIBRARY4 (p18-140/192 existing lemma; 462 existing lemma; p6-28)624 (1801, 546, p15-45, p15-183)3 (p15-496/537, 495)73
    SOLVER7 (507, 1725, 803, 569, 656, 698, 175-93)74 (60 power, 11 Complex, 31, 192, 484)6087
    HARVEST00099
    corrected total971371023267

    Lines needing more than one task. Primary task first, with the co-fix in brackets.

    • LIBRARY [+TRANSLATOR] ×5: imo_1966_p4-174, -196, amc12_2001_p5-31, aime_1984_p1-192/-484.
    • HARVEST [+LIBRARY] ×3: p15-496, -537, aime_1987_p5-495.
    • SOLVER [+other] ×2: 546, p15-183.
    • The 5 H2 lines need HARVEST plus a translator reorder, and for p15 also the Complex library fix.
    • Context-modulated lines are kept under their stated task, but scoping (T7) may be what actually decides them in-file: 452, 949, 564, 618-183/-189, aime_1990_p4-205.

    Interpretation. The consensus over-counted SOLVER by a factor of almost 9. Most "Z3 gives up" lines were caused by the library's power encoding. LIBRARY becomes the largest task, but it is dominated by one edit.

    3.2 Ranked action list

    (The reviewers' change list for all 499 lines is the ranked fix list above.) Ranked by lines closed with evidence ÷ effort. "Approval" is needed for every new axiom and for any change whose regression risk can only be measured by a whole-corpus re-verify (which this stage was not allowed to run).

    #fix (task)gap lines it addressesevidence of closing (standalone)corpus beyond the gap seteffortneeds user approval?
    1Remove the recursive pow postcondition, equalise fuel (W33 or F33), and emit PowSucc cites (LIBRARY)≈ 104 (43 L1 + 60 S-M1 + 174; overlaps with others)57/62 S-M1 + 30/43 L1, by some variant; the best single variant is not yet known104/499 close in in-file replaysmall edit + corpus re-verifyyes: corpus re-verify; variant choice
    2Transcribe norm_num evaluation records as checked asserts, + RatCastInj (TRANSLATOR T1 + LIBRARY L2)35 + 5 + 12 related35/35; L2 5/5; +12 with RatCastInj≤ 63 lines carry such records (untested)small–mediumyes for RatCastInj (exact Mathlib, Lean-checked)
    3Harvester: record bare constants, unfold _auxLemma, alias map (HARVEST H4, H5, H1)8 + 4 + 3 = 157 + 2(+2 caveat) + 2 firm+4 amc12b_2020_p21; 96 nullary notes; 898 "arguments unknown"small + re-harvestno (existing exact axioms)
    4Opaque Complex add/mul/of_real with proved postconditions + reveal rule (LIBRARY)11 (+6 L3 lines that need it)7 closed, 3 partial10 more close in replaysmallyes: corpus re-verify
    5Ghost-function lifting of quantifier bodies + Lean-instance rule I (TRANSLATOR T6)121184 no-trigger warnings / 17 filesmediumno
    6Encoding bridges at the seven seams (TRANSLATOR T4)15 (13 genuine)13459 nat-slot products, 14 failing linesmediumyes: Dvd.intro, Irrational.ne_rat, Real.div-form lemmas
    7Loader admits recorded internal/aliased lemmas + argument adapters (TRANSLATOR T2)10 (+imo_1959_p1-32)812,827 dropped internal records (most glue)small–mediumyes: IntIccCard, Real.div lemmas
    8New library lemmas at the missing types (LIBRARY L3) + proved twins (L4)18 + 57 alone (+6 with #4); L4 59 not-expressible sum_singleton commentssmall eachyes (axioms); twins no
    9Rewrite-step equalities, cites before @tac-hyp, ∀-instances (TRANSLATOR T5)96 (+3 needing ghost Mul)1,431–1,433 dropped congrArg commentsmediumghost Mul: yes, corpus re-verify
    10Unconditional cert pieces, norm_cast cites, cites as function postconditions (TRANSLATOR, ex-SOLVER M3/M6)2 + 3569, 656, 1725, 507 (contested)466 guarded calls / 37 files; 566 temp-bound citessmall–mediumno
    11Lean-footprint scoped emission, have_deps → helper lemmas (TRANSLATOR T7 / S-M4)5 + 803 + context lines488, 5471, 803; alternative fix for 9 c013 lines160 failing lines close standalonelargeyes: completeness cost (29→18 on the rules track)
    12Re-run harvest4 on 90 theorems + record for amc12a_2019_p21 + cite ordering (HARVEST H2)5 (+~10 needing it)1 (756 with reorder)≈ 60 lines with a harvest-blind note~1 rack-hour + small translator changeno
    13ℚ sum_range_succ + isolated per-step replay; goal-matched NatPowMod (ex-SOLVER M5)3192, 484, 9318 lines with large numeral sumssmallyes (axioms; 93 is goal-matched, not record-backed)

    Fix before anything else (infrastructure).

    • (a) One MathPrelude postcondition is not re-proved under the corpus flags: the Real.pow postcondition at :55 fails under --isolate-assertions (136 verified, 1 error), while the prelude verifies with Dafny's default flags (51 verified, 0 errors). The postcondition is true, so this is a proof-checking gap, not a false axiom. Fix #1 removes that postcondition.
    • (b) Line-lemma extraction is unreliable in places. These defects lose evidence; they do not cause failures.
      • 136 of 998 stored line-lemma files do not parse: a multi-line Lean goal in the header is not commented out.
      • About 10 lemmas carry false /*VC_GAP*/.
      • vc_extract --names source renames call temporaries, which hides S-M3.
      • The static trimmer dropped the decisive hypothesis for aime_1987_p5-452 and aime_1984_p1-62.

    4. What is genuinely beyond the pipeline

    The 10 lines left as SOLVER:

    linewhy it staysis it a true solver limit?
    amc12_2001_p5-18, -53Lean's rfl makes the kernel evaluate 10000! mod (2^5000·5000!) and a product of 5000 odd numbers. Dafny/Z3 has no faithful way to do that computation.yes: kernel evaluation of a huge ground term
    imo_1966_p4-156, -187With the power fix, the in-file query turns from OOR into a fast incomplete (theory arithmetic). Nothing tested closes them in-file.yes, probably: nonlinear residue (they close standalone in every library)
    imo_1974_p5-1801All 12 recorded field_simp instances supplied: still OORprobably: products in divisors
    amc12b_2021_p9-546Recorded sub_div' instances fail; only an unrecorded div_sub_div_same matched by goal shape closes itsolver limit for Lean's route; a translator goal-shape rule would close it at the cost of record-faithfulness
    amc12a_2009_p15-45ℂ equation goal; needs a ℂ "peel" Lean did not record as suchopen
    amc12a_2009_p15-183OOR with all ℂ facts until the mod identity is a separate helperpartly context; open
    amc12b_2020_p13-452needs √a·√b = 1 by a degree-4 argument; a non-Lean assert chain closes it, but that would be inventednot established: the skeptic found Lean's nlinarith certificate only partly emitted (some pieces "not stated", the rest under if). Emitting all recorded pieces is untested
    imo_1984_p2-1685one lens closes it in place with {:fuel 1,1}; the other finds its raw query unsat aloneunknown: the in-file failure is not reproducible from the query

    Cross-cutting solver setting.

    • Dafny 4.11 forces Z3's legacy arithmetic solver (smt.arith.solver 2) and drops a user override.
    • Replaying the 502 failing raw queries with arith.solver 6 flips 202; 104 lines close fully (18 of them task lines); 21 queries regress.
    • This is not adoptable under the fixed flag set. It is recorded only as evidence that the legacy solver is the proximate failure for S-M3 and S-M7.

    Bottom line. About 4–6 of the 267 lines (2%) look like real solver limits. The rest are pipeline defects with tested repairs.


    5. Method and limits

    What was done.

    • 37 clusters, each with two analysts (ROOT, FIX), except c006 (FIX output missing): 73 analyses.
    • 4 syntheses (TRANSLATOR, LIBRARY, SOLVER, HARVEST).
    • 2 skeptic passes per task.
    • About 2,600 Dafny outputs stored under gaps/work/ and gaps/task/*runs*.

    Flags. Every Dafny check used dafny verify --isolate-assertions --resource-limit 1000000 --allow-warnings --cores 2 with Dafny 4.11 (~/opt/dafny/dafny), the corpus flag set. Some checks also used --filter-symbol.

    Skeptic run counts.

    taskskeptic Dafny runsother checks
    TRANSLATOR12 + 20contract_diff check
    LIBRARY20
    SOLVER10 + 18
    HARVEST14 + 101 Lean proof-term probe

    What "closes" means here. One standalone Dafny check of a line lemma (original or trimmed), a hand-built minimal lemma, or a hoisted helper.

    • Fixes add only calls or checked asserts.
    • A contract-diff check over about 100 TRANSLATOR fix files found the requires/ensures identical to the extracted lemma. Two variants removed requires, which only weakens the hypotheses and stays sound.
    • No fix weakens a goal or strengthens a hypothesis.
    • No assume was used.
    • New axioms were Lean-checked by the analysts (lake env lean in ~/mathlib410). They were not re-checked in this stage.

    What was NOT done, by rule or for lack of budget.

    • No theorem file was re-verified. So no fix has an in-file result, and no regression on the ~33,000 obligations that verify today was measured. This matters most for the power fix (#1), Complex opacity (#4), ghost Mul (#9), ℚ libB2 (#2) and scoped emission (#11).
    • No translator, library or harvester source was changed. Fixes were simulated by editing extracted lemmas or copied libraries.
    • No re-harvest was run for H1, H3, H4 or H5. The FIX lens patched and ran the harvest for H1 only.
    • Some in-file evidence is a raw SMT replay of Dafny's own query with one axiom conjunct removed (c018–c020), not a Dafny run. fxeq-318 is the case where the Dafny-level check timed out (2400 s).
    • The power-fix variant (U2, F33 or W33) was not decided. Each has known lines it misses.

    Why "closes standalone" is weaker than it sounds.

    • 160 of 499 failing lines (62 in the gap set) close standalone without any fix. For those lines a standalone "closes with fix" proves nothing.
    • The syntheses and skeptics flagged these cases:
      • 452 and 949: base closes;
      • 205: closes without the cite;
      • 44 of the 62 power lines: the base line lemma already closes.

    Open contradictions (carried, not resolved here).

    • The power-fix variant.
    • aime_1983_p1-507: two different roots (call temporaries vs cast products); both fixes close it.
    • imo_1984_p2-1685: reproducibility.
    • fxeq-189/-229: the c019 replay says still failing; c020 says closed.

    Files.

    • gaps/GAPS_REPORT.md (this file) and gaps/GAPS_REPORT.html (same content, self-contained, not published).
    • gaps/corrected_tasks.jsonl, written by gaps/g3_corrected_tasks.py.
    • Inputs: gaps/task/*.md|json, gaps/out/*.json, gaps/lines.jsonl, SUMMARY.md, BLOCKSIZE*.md.
    solving method (tick any; closed lines appear under the method that closed them, not-closed lines under every method tried on them; the panel shows the closing code or the failed attempts):
    result (tick any):
    theoremlinekindstatementprimary (votes)taskmissing Lean linesLean had (kind)closed by (strict)
    Select an integ5 line.