[{"data":1,"prerenderedAt":4},["ShallowReactive",2],{"Qkm8WIzdMN":3},"```\n╔════════════════════════════════════════════════════════════════════════════╗\n║                                                                            ║\n║    ██████╗  ██████╗ ███╗   ██╗███████╗ █████╗ ██╗      ██████╗  ██████╗    ║\n║   ██╔════╝ ██╔═══██╗████╗  ██║╚══███╔╝██╔══██╗██║     ██╔════╝ ██╔═══██╗   ║\n║   ██║  ███╗██║   ██║██╔██╗ ██║  ███╔╝ ███████║██║     ██║  ███╗██║   ██║   ║\n║   ██║   ██║██║   ██║██║╚██╗██║ ███╔╝  ██╔══██║██║     ██║   ██║██║   ██║   ║\n║   ╚██████╔╝╚██████╔╝██║ ╚████║███████╗██║  ██║███████╗╚██████╔╝╚██████╔╝   ║\n║    ╚═════╝  ╚═════╝ ╚═╝  ╚═══╝╚══════╝╚═╝  ╚═╝╚══════╝ ╚═════╝  ╚═════╝    ║\n║                                                                            ║\n║               where does a formal library spend its axioms?                ║\n║                                                                            ║\n╚════════════════════════════════════════════════════════════════════════════╝\n```\n\n[![PyPI](https://img.shields.io/pypi/v/gonzalgo)](https://pypi.org/project/gonzalgo/)\n[![Python](https://img.shields.io/pypi/pyversions/gonzalgo)](https://pypi.org/project/gonzalgo/)\n[![License](https://img.shields.io/pypi/l/gonzalgo)](LICENSE)\n[![DOI](https://img.shields.io/badge/DOI-10.5281%2Fzenodo.21769846-blue)](https://doi.org/10.5281/zenodo.21769846)\n\n\u003C!-- mcp-name: io.github.zengineco/gonzalgo -->\n\u003C!-- ^ how the MCP Registry verifies this PyPI package belongs to that server\n     name. It reads the package description, which is this README. Removing the\n     line makes the next `mcp-publisher publish` fail package validation. -->\n\n\n`#print axioms` tells you whether *one* theorem depends on an axiom. It cannot\ntell you where an axiom is **spent** rather than inherited, how far that spending\nreaches, how much of it could be avoided, or — for a given theorem — **which step\nintroduced it**. This does.\n\nWorks on **Lean 4 / Mathlib** and on **Metamath** databases (`set.mm`,\n`iset.mm`, `nf.mm`), by one program, so two foundations are compared under\nidentical definitions rather than by analogy.\n\n```console\n$ pip install gonzalgo\n$ gonzalgo index\n\n  THE KERNEL INDEX  (2026-08-05)   what formal libraries rest on\n  library             system      theorems  unfinished  compiler   choice\n  -----------------------------------------------------------------------\n  Mathlib             Lean 4       437,429           0         0   66.62%\n  Lean core (Init)    Lean 4        45,051           0         0   23.91%\n  Std                 Lean 4        34,510           0         0   56.66%\n  Batteries           Lean 4         5,249           0         0   32.63%\n  set.mm              Metamath      47,621           0         -    1.22%\n  ...\n  14 libraries, 603,703 theorems, 0 resting on an unfinished proof.\n```\n\nThat runs the moment it's installed — no Lean, no build, no files. Everything\nbelow needs a Lean project.\n\nPure Python. macOS, Windows, Linux. `numpy` is the only dependency.\n\n---\n\n## Questions this answers\n\n**How do I know if my Lean proof depends on a `sorry`?**\nLean warns once, on the line you typed it. It does not warn you about the theorem\nthree files later that uses that lemma and is therefore not proved either. Run\n`gonzalgo trust` and it reports every theorem that reaches a `sorry` anywhere\nupstream, however far.\n\n**How do I find a `sorry` I inherited from a dependency?**\nSame command. The audit is over the whole environment, so a `sorry` in a library\nyou import is reported exactly like one in your own file.\n\n**Does my project use `native_decide` anywhere?**\n`native_decide` results are obtained by compiling and running code and believing\nthe answer — the compiler and runtime are trusted, not the kernel, and soundness\nbugs have been found there. `gonzalgo trust` reports `Lean.ofReduceBool` and\n`Lean.ofReduceNat`, the axioms it emits, and how many theorems inherit them.\n\n**What axioms does this Lean theorem actually depend on, and why?**\n`#print axioms` tells you *whether*. `gonzalgo why \u003Cdecl> -a \u003Caxiom>` gives the\nshortest path from the theorem to the axiom, labelling each step as a statement\ndependency or a proof dependency — so you can see which step introduced it and\nwhether it is reroutable.\n\n**Can I fail CI when a proof rests on something unfinished?**\nYes. `--fail-on-trust`, or the GitHub Action below.\n\n**If I change this definition, what breaks?**\n`gonzalgo impact` splits dependents into those that name it in a *statement* —\nwhose meaning changes with it — and those that only use it in a *proof*, which\nmerely rebuild.\n\n**kernel > sorry**\n\n## What it found\n\nPointed at Lean 4.32.1 with Mathlib — 790,171 declarations, 30 million\ndependency edges — the funnel from \"the whole library\" down to \"provably\nremovable\" runs like this:\n\n```\n   532,605   theorems in Mathlib\n  ─────────────────────────────────────────────────────────────────────\n   324,808   ██████████████████████████████░░░░░░░░░░  depend on Classical.choice   61.0%\n       144   ▏                                         actually SPEND it (entry points)\n  ─────────────────────────────────────────────────────────────────────\n    69,571   ██████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░  could be stated without it   13.1%\n                                                       └─ a ceiling, not an estimate\n  ─────────────────────────────────────────────────────────────────────\n       805   substitutable sites — a choice-free instance existed, unused\n       280   declarations whose ONLY route to the axiom runs through one\n       276   ▏ attributable to a single tactic  ────────────────────┐\n       275   ▏ kernel-verified choice-free after substitution       │\n         4   ▏ kernel REJECTED — and they are exactly the 4 NOT ────┘\n             ▏ attributable to that tactic. The partition was not designed.\n```\n\nThat single tactic is **`omega`**, which supplies the `Decidable` arguments of\nsix helper lemmas as a hardcoded `Classical.propDecidable` and never attempts\ninstance synthesis — so proofs as elementary as `a - b = 0 ↔ a ≤ b` over `Nat`\nrest on the axiom of choice with no need. Filed upstream; the fix is one file.\n\n---\n\n## Let a language model call it\n\n```console\n$ pip install \"gonzalgo[mcp]\"\n```\n\nAdd to your MCP client's configuration:\n\n```json\n{\n  \"mcpServers\": {\n    \"gonzalgo\": { \"command\": \"gonzalgo-mcp\" }\n  }\n}\n```\n\nTen tools: `audit_trust`, `why`, `impact`, `axiom_reach`, `metamath_audit`,\n`kernel_index`, plus the plumbing to produce a dump from a project.\n\nThere's also a `scope` tool that reports what gonzalgo can't do — read a paper,\nmark homework, judge whether text is any good. It's there so a model asked \"is\nthis proof correct?\" about a page of prose doesn't grab the nearest proof-shaped\ntool and return something meaningless. Every other tool restates the\nprecondition in its description.\n\nThe case it's built for: a generated Lean proof that fails to compile is easy to\nspot. One that compiles while resting on a `sorry` three lemmas upstream isn't,\nand Lean only mentions it once, in a warning, at the site.\n\n`kernel_index` runs with no files and no network, so a model can call it cold for\nfigures on known libraries.\n\n## Put it in CI, get a badge\n\nThree lines in any Lean 4 project. Every commit is checked for theorems resting\non an unfinished proof or on trusting the compiler rather than the kernel.\n\n```yaml\n# .github/workflows/kernel-clean.yml\nname: kernel-clean\non: [push, pull_request]\njobs:\n  audit:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: zengineco/gonzalgo@v1\n        with:\n          module: MyProject\n```\n\nThen the badge, which is just the workflow's own status — no extra service:\n\n```markdown\n![kernel-clean](https://github.com/YOU/REPO/actions/workflows/kernel-clean.yml/badge.svg)\n```\n\n**What the badge actually certifies.** Not that the proofs are correct — Lean\nalready checks that. That no theorem in the project is standing on a `sorry`\nsomewhere upstream, and that none of them were decided by compiling and running\ncode instead of by the kernel.\n\nLean warns about the `sorry` you just typed. It says nothing about the theorem\nthree files later that quietly inherits it. In the worked example under\n`examples/dirty`, Lean reports **one** warning and the audit finds **two**\ncontaminated theorems.\n\n## How it fits together\n\n```\n        your Lean project\n               │\n               │  gonzalgo lean-files ./scripts\n               │  lake env lean scripts/Split.lean\n               ▼\n     ┌───────────────────────┐\n     │   dependency graph    │   one row per declaration:\n     │  statement │ proof    │   KIND · NAME · stmt-deps · proof-deps\n     └───────────┬───────────┘\n                 │\n                 │  gonzalgo check      ← refuses a dump with no proof terms\n                 ▼\n     ┌───────────────────────────────────────────────────┐\n     │                                                   │\n     ▼                  ▼                ▼               ▼\n  amplify           eligible            why            audit\n  ───────           ────────            ───            ─────\n  where is the      how much is         which step     which sites are\n  axiom spent,      even eligible       introduced     substitutable, and\n  and how far       for removal?        it?            which declarations\n  does it reach?    (the ceiling)                      go clean if you fix\n                                                       every one\n                                                            │\n                                                            ▼\n                                                   lake env lean Rewrite.lean\n                                                   ───────────────────────────\n                                                   swap the instance in and ask\n                                                   the KERNEL if the proof holds\n```\n\nNothing above the kernel step is trusted on my say-so: `Substitute.lean` decides\nsubstitutability with `collectAxioms`, and `Rewrite.lean` submits the rewritten\nproof term to `addDecl`. A name-based screen was tried first and measured 41.5%\nprecision, which is why none of this reads names.\n\n---\n\n## Quickstart\n\nGenerate a dump from your own Lean project, then ask questions of it.\n\n```console\n$ gonzalgo lean-files ./scripts        # writes the Lean extractors\n$ cd my-lean-project\n$ lake env lean scripts/Split.lean     # -> mathlib_split.tsv\n$ gonzalgo check mathlib_split.tsv     # verify it actually contains proofs\n```\n\n**Why does this theorem need choice?**\n\n```console\n$ gonzalgo why mathlib_split.tsv Int.mem_box\n\n  Int.mem_box\n    Int.mem_box\n      --proof-->  Int.mem_box._proof_1_5\n        --proof-->  Classical.propDecidable\n          --proof-->  Classical.choice\n```\n\nEvery hop is labelled `stmt` or `proof`, and that label is the point: a proof\nedge can often be rerouted by changing a tactic, a statement edge cannot be\ntouched without changing what the theorem says. A path made only of proof edges\nis what makes a declaration worth patching at all.\n\n**If I change this, what breaks?**\n\n```console\n$ gonzalgo impact mathlib_split.tsv Nat.decLe\n\n  Nat.decLe\n    reached transitively    398,968   (295,411 of them theorems)\n    ── direct ──\n    in a STATEMENT              626   API surface: changing the\n                                      type changes their meaning\n    in a PROOF only           4,225   insulated: a type-preserving\n                                      change costs a recompile\n```\n\n`why` run backwards. The statement/proof split is the value: a declaration whose\n*type* mentions the target has the target in its API, so its meaning moves when\nthe target moves and its own users may need rewriting. One that merely calls it\ninside a proof needs nothing but a rebuild. A plain \"who uses this\" cannot tell\nthem apart, which is why it can't tell you whether a change is safe.\n\n**How far does an axiom reach, and where is it spent?**\n\n```console\n$ gonzalgo amplify mathlib_split.tsv\n\n  axiom            Classical.choice\n  theorems              532,605\n  dependents            324,808   reach 61.0%\n  entry points              144   2.704e-04 per theorem\n  amplification           2,256x\n```\n\n**How much of that could even in principle be removed?**\n\n```console\n$ gonzalgo eligible mathlib_split.tsv\n\n  statement CHOICE-FREE, proof dep    69,571   13.1%   \u003C- eligible\n  ...\n  ceiling on removable classical dependence: 13.1%\n```\n\nA theorem whose *statement* mentions something choice-dependent cannot be made\nchoice-free however it is proved. Only the rest are candidates, and that figure\nis a ceiling, not an estimate.\n\n**Metamath, same measurements:**\n\n```console\n$ gonzalgo mm set.mm iset.mm nf.mm\n\n  set.mm\n    theorems                     47,621\n    logical axioms (|-)           1,561   used 1447\n    median entries per axiom        2.0\n    overall amplification         292.1x\n```\n\n---\n\n## Kernel Trust Profile\n\n`gonzalgo profile` writes what a library rests on as JSON, meant to be committed\nand read by other programs:\n\n```\n$ lake exe gonzalgo MyProject myproject.tsv\n$ gonzalgo profile myproject.tsv --name MyProject -o kernel-trust.json\n```\n\n```json\n{\n  \"ktp_version\": \"0.1\",\n  \"subject\": { \"name\": \"Lean core + Std\", \"revision\": \"…\", \"system\": \"Lean 4\" },\n  \"counts\": { \"theorems\": 88842 },\n  \"unfinished\":       { \"theorems_reaching\": 0, \"axioms\": [\"sorryAx\"] },\n  \"compiler_trusted\": { \"theorems_reaching\": 0 },\n  \"assumptions\": [\n    { \"name\": \"Classical.choice\", \"kind\": \"optional\",\n      \"entry_points\": 24, \"reach\": { \"theorems\": 31516, \"fraction\": 0.3548 },\n      \"via\": \"both\" }\n  ]\n}\n```\n\nTwo rules do most of the work. **An unmeasured field is `null`, never `0`** —\nMetamath has no `native_decide`, so its `compiler_trusted` count is\nnot-applicable rather than zero, and writing zero would be a claim nobody made.\nAnd **`revision` is refused on a dirty tree**, because a profile whose commit\ndoes not describe what was measured cannot be reproduced by anyone else.\n\nThere is no summary score, deliberately. A theorem either reaches an unfinished\nproof or it does not; averaging that against anything else invents precision the\nmeasurement does not have.\n\nFull specification: [`ktp/SPEC.md`](https://github.com/zengineco/universal-cover/blob/main/ktp/SPEC.md).\nA sample is in [`examples/lean-core-kernel-trust.json`](examples/lean-core-kernel-trust.json).\n\n---\n\n## Reach versus amplification\n\nUnder inlining and factoring — operations that change how a library is written,\nnot what it proves — the set of *dependents* is invariant while the set of\n*entry points* is not. Rerouting every use of an axiom through one gateway\nlemma, or inlining that lemma, moves amplification anywhere between 1 and the\nnumber of dependents without changing a single theorem.\n\nSo **reach bears comparison between libraries; amplification describes one\nlibrary's factorisation.** The tool reports both and this README says which is\nwhich, because the distinction is easy to lose and expensive to lose.\n\n---\n\n## One hazard worth knowing about\n\nIn Lean 4.32, `ConstantInfo.value?` returns `none` for **theorems** unless\ncalled as `value? (allowOpaque := true)`, and this has changed across releases.\nAn extractor written the obvious way records no proof terms at all: every\ntheorem's value comes back empty, the analysis silently measures statements, and\nreports them as proofs. Nothing about the output looks wrong — the library just\nappears cleaner than it is.\n\n`gonzalgo check` exists for this, and every subcommand runs it before trusting a\ndump:\n\n```console\n$ gonzalgo check bad_dump.tsv\nERROR: bad_dump.tsv: 532,605 theorems, none carrying a proof term.\nThe extractor called `ConstantInfo.value?` without `(allowOpaque := true)` ...\n```\n\nIt raises rather than warns. A dump with no proof terms does not produce\nslightly worse numbers; it produces confidently wrong ones.\n\n---\n\n## Library use\n\n```python\nfrom pathlib import Path\nfrom gonzalgo import lean\n\ndump = Path(\"mathlib_split.tsv\")\nlean.check_dump(dump)\ng = lean.load(dump)\n\ng.path_to(\"Int.mem_box\", lean.AXIOM)      # why\ng.entry_points(lean.AXIOM, among=\"T\")     # where it is spent\ng.dependents(lean.AXIOM)                  # boolean mask over all nodes\nlean.eligibility(dump, g).ceiling         # what fraction could be removed\n```\n\n---\n\n## As a Lake package\n\nThis repository is also a Lean library, so the extractor can be a dependency\nrather than a file you copy and edit. Add to your `lakefile.toml`:\n\n```toml\n[[require]]\nname = \"gonzalgo\"\ngit = \"https://github.com/zengineco/gonzalgo\"\n```\n\nThen no scratch file at all — it imports the target module at runtime:\n\n```\n$ lake exe gonzalgo MyProject myproject.tsv\nimporting MyProject ...\ndeclarations written: 204543\nnow run:  gonzalgo check myproject.tsv\n```\n\nEverything the module imports is included, and the fifth output column records\nwhich module each declaration came from, which is what separates your project\nfrom its dependencies afterwards.\n\nIf you would rather call it from inside a file, the library is two lines:\n\n```lean\nimport Gonzalgo\n#eval Gonzalgo.dumpSplit \"myproject.tsv\"\n```\n\nThe library requires Lean only — no Mathlib dependency, deliberately, since\npinning a Mathlib revision here would force one on every project being measured.\n\nRun against Lean core and Std alone, that gives:\n\n```\naxiom                  declared  direct  theorems\nsorryAx                     yes       0         0\nLean.ofReduceBool           yes       0         0\nClassical.choice            yes      32    31,516\npropext                     yes  13,246    70,150\n\nCLEAN: no theorem here rests on an unfinished proof or on the compiler.\n```\n\n88,842 theorems, and 32 declarations spend `Classical.choice` where 31,516\ninherit it.\n\n---\n\n## Shipped Lean sources\n\n`gonzalgo lean-files` writes these into a directory of your choosing. Prefer the\nLake package above for `Split.lean`'s job; these are for the analyses that go\nbeyond extraction, and for projects not using Lake.\n\n| file | what it does |\n|---|---|\n| `Split.lean` | declaration graph, statement and proof deps in separate columns |\n| `Substitute.lean` | re-synthesizes each classical-decidability site, classifies by `collectAxioms` |\n| `Rewrite.lean` | rewrites proof terms and kernel-checks the substitution |\n| `OmegaFix.lean` | a patched `omega` frontend — demonstration only, see below |\n| `Extract.lean` | earlier graph dump, superseded by `Split.lean` |\n\n`Substitute.lean` decides substitutability with the kernel's own bookkeeping\nrather than by name. A name-based screen measured 41.5% precision on `set.mm`;\nits characteristic failure is a lemma that relocates choice into an antecedent\ninstead of discharging it, which looks like progress and is not.\n\n---\n\n## Background\n\nThis package is the tooling behind *Where Formal Libraries Spend Their Axioms:\nA Cross-Foundation Measurement, and an Avoidable Classical Dependency in Lean's\n`omega`* — [10.5281/zenodo.21769846](https://doi.org/10.5281/zenodo.21769846).\n\nApplied to Lean 4.32.1 with Mathlib (790,171 declarations, 30M dependency\nedges), it finds 280 declarations whose only route to `Classical.choice` runs\nthrough a substitutable site, 276 of them attributable to a single cause in the\n`omega` decision procedure. Rewriting all 280 proof terms and submitting them to\nthe kernel: 276 accepted, 4 rejected, 275 left free of `Classical.choice`.\n\n---\n\n## Who wrote this, and how to cite it\n\n**Vince Gonzalez** — [ORCID 0009-0005-3640-014X](https://orcid.org/0009-0005-3640-014X)\n· [f-keys.com/gonzalgo](https://f-keys.com/gonzalgo/)\n\n```bibtex\n@software{gonzalgo,\n  author  = {Gonzalez, Vince},\n  title   = {gonzalgo: axiom provenance for Lean 4 and Metamath},\n  year    = {2026},\n  url     = {https://github.com/zengineco/gonzalgo},\n  doi     = {10.5281/zenodo.21769846},\n  license = {Apache-2.0}\n}\n```\n\nArchived at Software Heritage:\n`swh:1:snp:b2955af0bc594c5972fcaf7689365c9243d3b9fb`, which resolves whether or\nnot this repository does.\n\n**Papers.** Both CC-BY, both with archives that regenerate every figure from the\nshipped data with one command.\n\n- *Where Formal Libraries Spend Their Axioms* —\n  [10.5281/zenodo.21769846](https://doi.org/10.5281/zenodo.21769846)\n- *Why Tactic-Level Rates Cannot Attribute Classical Dependencies in Lean* —\n  [10.5281/zenodo.21853489](https://doi.org/10.5281/zenodo.21853489)\n\n## Licence\n\nApache-2.0. See `LICENSE` and `NOTICE`.\n\n`OmegaFix.lean` is a **modified copy** of Lean 4's\n`src/Lean/Elab/Tactic/Omega/Frontend.lean`, Copyright (c) 2023 Lean FRO, LLC,\nused under Apache-2.0. Its modifications are listed in a notice at the top of\nthat file. It exists to demonstrate that a proposed fix compiles and produces\nchoice-free proofs; **it is not a replacement for `omega` and should not be used\nas one.**\n\nNot affiliated with or endorsed by the Lean FRO or the Mathlib community.\n",1786349538923]