chore: convert from dataset to model repo
Browse files- LICENSE +21 -0
- Makefile +19 -0
- README.md +169 -0
- docker-compose.yml +10 -0
- docs/HUGGINGFACE_PUBLISHING.md +49 -0
- docs/REPO_MAP.md +41 -0
- eval/requirements.txt +2 -0
- eval/run_minif2f.py +75 -0
- fixtures/sample_input.jsonl +1 -0
- hf/README.md +42 -0
- inference/Dockerfile +9 -0
- inference/prompt.txt +14 -0
- inference/requirements.txt +4 -0
- inference/server.py +40 -0
- infra/verification-loop/.env.example +10 -0
- infra/verification-loop/docker-compose.yml +63 -0
- lean4/MiniF2F.lean +9 -0
- lean4/VerifyMain.lean +30 -0
- lean4/lake-manifest.json +95 -0
- lean4/lakefile.toml +17 -0
- lean4/lean-toolchain +1 -0
- lean4/src/SovereignCorpus.lean +4 -0
- lean4/src/SovereignCorpus/Bridge/Granite4Parser.lean +87 -0
- lean4/src/SovereignCorpus/Bridge/Granite4Schema.lean +55 -0
- lean4/src/SovereignCorpus/Core.lean +5 -0
- lean4/src/SovereignCorpus/Tactics/PlasmaGate.lean +6 -0
- logic/sovereign_verification.pl +21 -0
- logic/verification_loop.pl +67 -0
LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2026
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
Makefile
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.PHONY: lean-build parse-only inference-up infra-up eval
|
| 2 |
+
|
| 3 |
+
LEAN_LAKE := C:\Users\jessi\.elan\bin\lake.exe
|
| 4 |
+
|
| 5 |
+
lean-build:
|
| 6 |
+
cd lean4 && "$(LEAN_LAKE)" build
|
| 7 |
+
|
| 8 |
+
parse-only:
|
| 9 |
+
cd lean4 && "$(LEAN_LAKE)" exe verify -- --parse ../fixtures/sample_input.jsonl
|
| 10 |
+
|
| 11 |
+
inference-up:
|
| 12 |
+
docker build -t lean-llm-inference ./inference
|
| 13 |
+
docker run -d -p 8080:8080 --name lean-llm-inference lean-llm-inference
|
| 14 |
+
|
| 15 |
+
infra-up:
|
| 16 |
+
docker compose --env-file ./infra/verification-loop/.env.example up -d granite-verifier
|
| 17 |
+
|
| 18 |
+
eval:
|
| 19 |
+
cd eval && python run_minif2f.py
|
README.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# lean-llm-starter
|
| 2 |
+
|
| 3 |
+
A deterministic Lean 4 verification harness that treats the LLM as an untrusted proposal engine and Lean 4 as the trusted kernel.
|
| 4 |
+
|
| 5 |
+
## Architecture
|
| 6 |
+
|
| 7 |
+
```text
|
| 8 |
+
operator intent
|
| 9 |
+
-> Prolog gate
|
| 10 |
+
-> Granite 4.1 / Llemma inference
|
| 11 |
+
-> schema validation
|
| 12 |
+
-> Lean 4 parse / verify
|
| 13 |
+
-> WORM-ready audit artifacts
|
| 14 |
+
```
|
| 15 |
+
|
| 16 |
+
Trust split:
|
| 17 |
+
|
| 18 |
+
- `inference/` proposes proof artifacts
|
| 19 |
+
- `logic/` blocks unauthorized or malformed runs
|
| 20 |
+
- `lean4/` type-checks and verifies
|
| 21 |
+
- `infra/verification-loop/` pins deterministic execution
|
| 22 |
+
- `eval/` runs reproducible local benchmarks
|
| 23 |
+
|
| 24 |
+
## Repo Layout
|
| 25 |
+
|
| 26 |
+
```text
|
| 27 |
+
lean-llm-starter/
|
| 28 |
+
├── .github/workflows/ci.yml
|
| 29 |
+
├── .gitattributes
|
| 30 |
+
├── .gitignore
|
| 31 |
+
├── LICENSE
|
| 32 |
+
├── Makefile
|
| 33 |
+
├── README.md
|
| 34 |
+
├── docker-compose.yml
|
| 35 |
+
├── docs/
|
| 36 |
+
│ ├── HUGGINGFACE_PUBLISHING.md
|
| 37 |
+
│ └── REPO_MAP.md
|
| 38 |
+
├── eval/
|
| 39 |
+
│ ├── requirements.txt
|
| 40 |
+
│ └── run_minif2f.py
|
| 41 |
+
├── fixtures/
|
| 42 |
+
│ └── sample_input.jsonl
|
| 43 |
+
├── inference/
|
| 44 |
+
│ ├── Dockerfile
|
| 45 |
+
│ ├── requirements.txt
|
| 46 |
+
│ ├── prompt.txt
|
| 47 |
+
│ └── server.py
|
| 48 |
+
├── infra/
|
| 49 |
+
│ └── verification-loop/
|
| 50 |
+
│ ├── .env.example
|
| 51 |
+
│ └── docker-compose.yml
|
| 52 |
+
├── lean4/
|
| 53 |
+
│ ├── lakefile.toml
|
| 54 |
+
│ ├── lean-toolchain
|
| 55 |
+
│ ├── MiniF2F.lean
|
| 56 |
+
│ ├── VerifyMain.lean
|
| 57 |
+
│ └── src/
|
| 58 |
+
│ └── SovereignCorpus/
|
| 59 |
+
│ ├── Bridge/
|
| 60 |
+
│ │ ├── Granite4Parser.lean
|
| 61 |
+
│ │ └── Granite4Schema.lean
|
| 62 |
+
│ ├── Core.lean
|
| 63 |
+
│ └── Tactics/
|
| 64 |
+
│ └── PlasmaGate.lean
|
| 65 |
+
├── logic/
|
| 66 |
+
│ ├── sovereign_verification.pl
|
| 67 |
+
│ └── verification_loop.pl
|
| 68 |
+
└── hf/
|
| 69 |
+
└── README.md
|
| 70 |
+
```
|
| 71 |
+
|
| 72 |
+
## What This Starter Includes
|
| 73 |
+
|
| 74 |
+
- Lean 4 harness skeleton
|
| 75 |
+
- Granite 4.1 JSON interchange schema
|
| 76 |
+
- Lean-side parser scaffold
|
| 77 |
+
- Prolog gate and retry loop scaffold
|
| 78 |
+
- vLLM / docker compose verification loop
|
| 79 |
+
- MiniF2F-style eval harness
|
| 80 |
+
- GitHub Actions CI scaffold
|
| 81 |
+
- Hugging Face publishing docs and model card template
|
| 82 |
+
- sample JSONL parse fixture
|
| 83 |
+
|
| 84 |
+
## What It Does Not Pretend Yet
|
| 85 |
+
|
| 86 |
+
- not fully air-gapped out of the box
|
| 87 |
+
- not fully air-gapped out of the box
|
| 88 |
+
- not a finished proof search system
|
| 89 |
+
- not yet shipping weights
|
| 90 |
+
|
| 91 |
+
Current verified state:
|
| 92 |
+
|
| 93 |
+
- Lean 4 project builds successfully on this machine with `C:\Users\jessi\.elan\bin\lake.exe`
|
| 94 |
+
- Python eval and inference files compile
|
| 95 |
+
- parse-mode fixture is present
|
| 96 |
+
|
| 97 |
+
This is a scaffold you can harden into:
|
| 98 |
+
|
| 99 |
+
- a GitHub repo
|
| 100 |
+
- a Hugging Face model or Space companion repo
|
| 101 |
+
- a deterministic local verification loop
|
| 102 |
+
|
| 103 |
+
## Quick Start
|
| 104 |
+
|
| 105 |
+
If `lake` is not on your PATH on Windows, use:
|
| 106 |
+
|
| 107 |
+
```powershell
|
| 108 |
+
C:\Users\jessi\.elan\bin\lake.exe
|
| 109 |
+
```
|
| 110 |
+
|
| 111 |
+
### 1. Lean side
|
| 112 |
+
|
| 113 |
+
```bash
|
| 114 |
+
cd lean4
|
| 115 |
+
C:\Users\jessi\.elan\bin\lake.exe update
|
| 116 |
+
C:\Users\jessi\.elan\bin\lake.exe build
|
| 117 |
+
```
|
| 118 |
+
|
| 119 |
+
### 2. Inference side
|
| 120 |
+
|
| 121 |
+
```bash
|
| 122 |
+
cd inference
|
| 123 |
+
docker build -t lean-llm-inference .
|
| 124 |
+
docker run -d -p 8080:8080 --name lean-llm-inference lean-llm-inference
|
| 125 |
+
```
|
| 126 |
+
|
| 127 |
+
### 3. Eval side
|
| 128 |
+
|
| 129 |
+
```bash
|
| 130 |
+
cd eval
|
| 131 |
+
pip install -r requirements.txt
|
| 132 |
+
python run_minif2f.py
|
| 133 |
+
```
|
| 134 |
+
|
| 135 |
+
### 4. Full verification loop
|
| 136 |
+
|
| 137 |
+
```bash
|
| 138 |
+
docker compose --env-file infra/verification-loop/.env.example up -d granite-verifier
|
| 139 |
+
swipl -g "verify_with_retries('theorem demo : True := by trivial', 'ED25519_SIG', 3, Result), writeln(Result), halt" logic/verification_loop.pl
|
| 140 |
+
```
|
| 141 |
+
|
| 142 |
+
### 5. Shortcut targets
|
| 143 |
+
|
| 144 |
+
```bash
|
| 145 |
+
make lean-build
|
| 146 |
+
make infra-up
|
| 147 |
+
make eval
|
| 148 |
+
```
|
| 149 |
+
|
| 150 |
+
### 6. Parse smoke test
|
| 151 |
+
|
| 152 |
+
```bash
|
| 153 |
+
cd lean4
|
| 154 |
+
C:\Users\jessi\.elan\bin\lake.exe exe verify -- --parse ../fixtures/sample_input.jsonl
|
| 155 |
+
```
|
| 156 |
+
|
| 157 |
+
## Hugging Face Readiness
|
| 158 |
+
|
| 159 |
+
This repo is prepared for later Hugging Face publication with:
|
| 160 |
+
|
| 161 |
+
- `.gitattributes` for LFS-managed weight files
|
| 162 |
+
- `hf/README.md` model card template
|
| 163 |
+
- `docs/HUGGINGFACE_PUBLISHING.md` publish checklist
|
| 164 |
+
|
| 165 |
+
Recommended publish modes:
|
| 166 |
+
|
| 167 |
+
1. code-only harness repo
|
| 168 |
+
2. model repo for GGUF / safetensors
|
| 169 |
+
3. Space repo for interactive verify loop UI
|
docker-compose.yml
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
services:
|
| 2 |
+
granite-verifier:
|
| 3 |
+
extends:
|
| 4 |
+
file: ./infra/verification-loop/docker-compose.yml
|
| 5 |
+
service: granite-verifier
|
| 6 |
+
|
| 7 |
+
lean4-kernel:
|
| 8 |
+
extends:
|
| 9 |
+
file: ./infra/verification-loop/docker-compose.yml
|
| 10 |
+
service: lean4-kernel
|
docs/HUGGINGFACE_PUBLISHING.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Hugging Face Publishing
|
| 2 |
+
|
| 3 |
+
## Recommended Split
|
| 4 |
+
|
| 5 |
+
### Option 1: Code Repo Only
|
| 6 |
+
|
| 7 |
+
Publish this repository as the harness source and keep weights elsewhere.
|
| 8 |
+
|
| 9 |
+
Best for:
|
| 10 |
+
|
| 11 |
+
- auditability
|
| 12 |
+
- open-source orchestration
|
| 13 |
+
- reproducible local verification loops
|
| 14 |
+
|
| 15 |
+
### Option 2: Separate Model Repo
|
| 16 |
+
|
| 17 |
+
Store GGUF or safetensors weights in a dedicated Hugging Face model repository.
|
| 18 |
+
|
| 19 |
+
Best for:
|
| 20 |
+
|
| 21 |
+
- large artifacts
|
| 22 |
+
- cleaner LFS separation
|
| 23 |
+
- versioned checkpoints
|
| 24 |
+
|
| 25 |
+
### Option 3: Space Repo
|
| 26 |
+
|
| 27 |
+
Use a Hugging Face Space for interactive theorem verification demos.
|
| 28 |
+
|
| 29 |
+
Best for:
|
| 30 |
+
|
| 31 |
+
- operator-facing UI
|
| 32 |
+
- public demos
|
| 33 |
+
- benchmark explorer
|
| 34 |
+
|
| 35 |
+
## Pre-Publish Checklist
|
| 36 |
+
|
| 37 |
+
- replace placeholder model IDs
|
| 38 |
+
- pin Docker image tags and Lean toolchain versions
|
| 39 |
+
- confirm license for model weights
|
| 40 |
+
- add real benchmark metadata
|
| 41 |
+
- scrub local absolute paths
|
| 42 |
+
- add reproducible example commands
|
| 43 |
+
- decide whether to publish Granite, Llemma, or both as supported backends
|
| 44 |
+
|
| 45 |
+
## Files Already Added For HF Readiness
|
| 46 |
+
|
| 47 |
+
- `.gitattributes`
|
| 48 |
+
- `hf/README.md`
|
| 49 |
+
- code/infra split suitable for model companion repos
|
docs/REPO_MAP.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Repo Map
|
| 2 |
+
|
| 3 |
+
## lean4/
|
| 4 |
+
|
| 5 |
+
Trusted verification kernel.
|
| 6 |
+
|
| 7 |
+
- `VerifyMain.lean` entrypoint
|
| 8 |
+
- `MiniF2F.lean` local benchmark corpus
|
| 9 |
+
- `src/SovereignCorpus/Bridge/` Granite interchange types and parser
|
| 10 |
+
- `src/SovereignCorpus/Tactics/` verification tactic stubs
|
| 11 |
+
|
| 12 |
+
## inference/
|
| 13 |
+
|
| 14 |
+
Untrusted proposal engine.
|
| 15 |
+
|
| 16 |
+
- `Dockerfile` for local inference runtime
|
| 17 |
+
- `server.py` compatibility wrapper
|
| 18 |
+
- `prompt.txt` deterministic prompt contract
|
| 19 |
+
|
| 20 |
+
## logic/
|
| 21 |
+
|
| 22 |
+
Prolog guardrail layer.
|
| 23 |
+
|
| 24 |
+
- schema checks
|
| 25 |
+
- authorization checks
|
| 26 |
+
- retry loop orchestration
|
| 27 |
+
|
| 28 |
+
## infra/verification-loop/
|
| 29 |
+
|
| 30 |
+
Deterministic container topology.
|
| 31 |
+
|
| 32 |
+
- `docker-compose.yml`
|
| 33 |
+
- `.env.example`
|
| 34 |
+
|
| 35 |
+
## eval/
|
| 36 |
+
|
| 37 |
+
Batch benchmark harness.
|
| 38 |
+
|
| 39 |
+
## hf/
|
| 40 |
+
|
| 41 |
+
Hugging Face-facing model card and publication surface.
|
eval/requirements.txt
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
requests==2.32.3
|
| 2 |
+
tqdm==4.66.4
|
eval/run_minif2f.py
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
import json
|
| 3 |
+
import os
|
| 4 |
+
import re
|
| 5 |
+
import subprocess
|
| 6 |
+
import tempfile
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
|
| 9 |
+
import requests
|
| 10 |
+
from tqdm import tqdm
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
ROOT = Path(__file__).resolve().parent.parent
|
| 14 |
+
LEAN_DIR = ROOT / "lean4"
|
| 15 |
+
SERVER = os.getenv("LEAN_LLM_SERVER", "http://localhost:8000/v1/completions")
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def lean_statements() -> list[str]:
|
| 19 |
+
content = (LEAN_DIR / "MiniF2F.lean").read_text(encoding="utf-8")
|
| 20 |
+
matches = re.findall(r"theorem\s+.*?:=\s+by\s+sorry", content, flags=re.DOTALL)
|
| 21 |
+
return [m.strip() for m in matches]
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def call_llm(stmt: str) -> list[dict]:
|
| 25 |
+
response = requests.post(
|
| 26 |
+
SERVER,
|
| 27 |
+
json={"prompt": stmt, "temperature": 0.0, "stop": ["<|user|>"]},
|
| 28 |
+
timeout=120,
|
| 29 |
+
)
|
| 30 |
+
response.raise_for_status()
|
| 31 |
+
text = response.json()["choices"][0]["text"].strip()
|
| 32 |
+
return json.loads(text) if text else []
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def verify_with_lean(steps: list[dict]) -> bool:
|
| 36 |
+
with tempfile.NamedTemporaryFile(mode="w", suffix=".lean", dir=LEAN_DIR, delete=False, encoding="utf-8") as f:
|
| 37 |
+
f.write("import MiniF2F\n\n")
|
| 38 |
+
f.write("namespace Scratch\n\n")
|
| 39 |
+
for s in steps:
|
| 40 |
+
name = s.get("name", "h_main")
|
| 41 |
+
statement = s.get("statement", "True")
|
| 42 |
+
tactic = s.get("tactic", "sorry")
|
| 43 |
+
f.write(f"theorem {name} : {statement} := by\n {tactic}\n\n")
|
| 44 |
+
f.write("end Scratch\n")
|
| 45 |
+
tmp = Path(f.name)
|
| 46 |
+
try:
|
| 47 |
+
result = subprocess.run(
|
| 48 |
+
["lake", "env", "lean", str(tmp.name)],
|
| 49 |
+
cwd=LEAN_DIR,
|
| 50 |
+
capture_output=True,
|
| 51 |
+
text=True,
|
| 52 |
+
timeout=60,
|
| 53 |
+
)
|
| 54 |
+
return result.returncode == 0
|
| 55 |
+
finally:
|
| 56 |
+
if tmp.exists():
|
| 57 |
+
tmp.unlink()
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def main() -> None:
|
| 61 |
+
stmts = lean_statements()
|
| 62 |
+
print(f"testing {len(stmts)} theorems")
|
| 63 |
+
passed = 0
|
| 64 |
+
for stmt in tqdm(stmts):
|
| 65 |
+
try:
|
| 66 |
+
steps = call_llm(stmt)
|
| 67 |
+
if verify_with_lean(steps):
|
| 68 |
+
passed += 1
|
| 69 |
+
except Exception as exc:
|
| 70 |
+
print(f"error: {exc}")
|
| 71 |
+
print(f"passed: {passed}/{len(stmts)}")
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
if __name__ == "__main__":
|
| 75 |
+
main()
|
fixtures/sample_input.jsonl
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"id":"demo-problem-1","statement":"theorem demo_nonneg (x : ℝ) : x ^ 2 ≥ 0","context":["import Mathlib"],"tacticHint":"nlinarith","meta":{"source":"granite-4.1-verifier","timestamp":"2026-07-14T00:00:00Z","operatorSig":"ED25519_SIG_PLACEHOLDER","maxSteps":30,"allowedTactics":["rw","simp_all","norm_num","linarith","nlinarith","aesop","apply","exact","intro","obtain","cases","induction","constructor","split_ifs","field_simp","ring_nf","norm_cast","omega"]}}
|
hf/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
language:
|
| 3 |
+
- en
|
| 4 |
+
tags:
|
| 5 |
+
- lean4
|
| 6 |
+
- theorem-proving
|
| 7 |
+
- formal-verification
|
| 8 |
+
- granite
|
| 9 |
+
- llemma
|
| 10 |
+
- vllm
|
| 11 |
+
license: mit
|
| 12 |
+
library_name: custom
|
| 13 |
+
pipeline_tag: text-generation
|
| 14 |
+
---
|
| 15 |
+
|
| 16 |
+
# lean-llm-starter
|
| 17 |
+
|
| 18 |
+
Code and harness scaffold for a deterministic Lean 4 verification loop.
|
| 19 |
+
|
| 20 |
+
## Intended Use
|
| 21 |
+
|
| 22 |
+
- local theorem proving workflows
|
| 23 |
+
- proof proposal plus kernel verification
|
| 24 |
+
- benchmark runs against MiniF2F-style corpora
|
| 25 |
+
|
| 26 |
+
## Components
|
| 27 |
+
|
| 28 |
+
- untrusted proposal engine
|
| 29 |
+
- trusted Lean 4 verifier
|
| 30 |
+
- Prolog guardrail
|
| 31 |
+
- deterministic infra scaffold
|
| 32 |
+
|
| 33 |
+
## Model / Runtime Notes
|
| 34 |
+
|
| 35 |
+
Replace this section with:
|
| 36 |
+
|
| 37 |
+
- exact model name
|
| 38 |
+
- quantization format
|
| 39 |
+
- tokenizer source
|
| 40 |
+
- inference backend
|
| 41 |
+
- benchmark results
|
| 42 |
+
- limitations
|
inference/Dockerfile
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM ghcr.io/ggerganov/llama.cpp:server
|
| 2 |
+
|
| 3 |
+
ARG MODEL_URL=https://huggingface.co/EleutherAI/llemma_7b-GGUF/resolve/main/llemma_7b-Q4_K_M.gguf
|
| 4 |
+
|
| 5 |
+
RUN mkdir -p /models && wget -q -O /models/llemma.gguf "$MODEL_URL"
|
| 6 |
+
|
| 7 |
+
EXPOSE 8080
|
| 8 |
+
|
| 9 |
+
ENTRYPOINT ["/llama-server", "-m", "/models/llemma.gguf", "-c", "4096", "--host", "0.0.0.0", "--port", "8080"]
|
inference/prompt.txt
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<|system|>
|
| 2 |
+
You are a Lean 4 formal verification engineer.
|
| 3 |
+
Output only JSONL-compatible JSON objects.
|
| 4 |
+
Use Lean 4 syntax only.
|
| 5 |
+
Do not use Lean 3 syntax.
|
| 6 |
+
Keep the theorem statement sorry-free.
|
| 7 |
+
Use the proofScript or `have` scaffolding to propose the proof body.
|
| 8 |
+
|
| 9 |
+
<|user|>
|
| 10 |
+
## TASK
|
| 11 |
+
Formalize the following intent.
|
| 12 |
+
Intent: {{THEOREM_STATEMENT}}
|
| 13 |
+
|
| 14 |
+
<|assistant|>
|
inference/requirements.txt
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
fastapi==0.115.0
|
| 2 |
+
uvicorn==0.30.6
|
| 3 |
+
requests==2.32.3
|
| 4 |
+
pydantic==2.9.2
|
inference/server.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import FastAPI
|
| 2 |
+
from pydantic import BaseModel
|
| 3 |
+
import os
|
| 4 |
+
import requests
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
app = FastAPI(title="lean-llm-starter inference wrapper")
|
| 8 |
+
LLAMA_URL = os.getenv("LLAMA_URL", "http://localhost:8080")
|
| 9 |
+
PROMPT_PATH = os.getenv("PROMPT_PATH", "prompt.txt")
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
class CompletionRequest(BaseModel):
|
| 13 |
+
prompt: str
|
| 14 |
+
max_tokens: int = 1024
|
| 15 |
+
temperature: float = 0.0
|
| 16 |
+
stop: list[str] = ["<|user|>"]
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
@app.get("/health")
|
| 20 |
+
def health() -> dict:
|
| 21 |
+
return {"status": "ok"}
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
@app.post("/v1/completions")
|
| 25 |
+
def complete(req: CompletionRequest) -> dict:
|
| 26 |
+
template = open(PROMPT_PATH, encoding="utf-8").read()
|
| 27 |
+
prompt = template.replace("{{THEOREM_STATEMENT}}", req.prompt)
|
| 28 |
+
response = requests.post(
|
| 29 |
+
f"{LLAMA_URL}/completion",
|
| 30 |
+
json={
|
| 31 |
+
"prompt": prompt,
|
| 32 |
+
"n_predict": req.max_tokens,
|
| 33 |
+
"temperature": req.temperature,
|
| 34 |
+
"stop": req.stop,
|
| 35 |
+
},
|
| 36 |
+
timeout=120,
|
| 37 |
+
)
|
| 38 |
+
response.raise_for_status()
|
| 39 |
+
payload = response.json()
|
| 40 |
+
return {"choices": [{"text": payload.get("content", "")}]}
|
infra/verification-loop/.env.example
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
VLLM_IMAGE_TAG=vllm/vllm-openai:v0.6.3
|
| 2 |
+
LEAN4_IMAGE_TAG=leanprover/lean4:v4.13.0
|
| 3 |
+
|
| 4 |
+
SOVEREIGN_MODEL_STORE=/var/lean-llm/models
|
| 5 |
+
SOVEREIGN_CACHE_STORE=/var/lean-llm/cache
|
| 6 |
+
BIFROST_AUDIT_SINK=/var/lean-llm/audit
|
| 7 |
+
VERIFICATION_PROJECT_ROOT=/opt/lean-llm-starter
|
| 8 |
+
|
| 9 |
+
GRANITE_MODEL_ID=ibm-granite/granite-4.1-8b-instruct
|
| 10 |
+
GRANITE_CONTEXT_LEN=32768
|
infra/verification-loop/docker-compose.yml
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version: "3.8"
|
| 2 |
+
|
| 3 |
+
services:
|
| 4 |
+
granite-verifier:
|
| 5 |
+
image: ${VLLM_IMAGE_TAG}
|
| 6 |
+
container_name: lean_llm_granite_verifier
|
| 7 |
+
environment:
|
| 8 |
+
- HF_HUB_OFFLINE=1
|
| 9 |
+
- VLLM_ATTENTION_BACKEND=FLASH_ATTN
|
| 10 |
+
- PYTHONHASHSEED=42
|
| 11 |
+
- TOKENIZERS_PARALLELISM=false
|
| 12 |
+
volumes:
|
| 13 |
+
- ${SOVEREIGN_MODEL_STORE}/granite-4.1-8b-instruct:/models/granite-4.1:ro
|
| 14 |
+
- ${BIFROST_AUDIT_SINK}/vllm:/var/log/vllm:rw
|
| 15 |
+
ports:
|
| 16 |
+
- "127.0.0.1:8100:8000"
|
| 17 |
+
ipc: host
|
| 18 |
+
shm_size: "16g"
|
| 19 |
+
command: >
|
| 20 |
+
--model /models/granite-4.1
|
| 21 |
+
--host 0.0.0.0
|
| 22 |
+
--port 8000
|
| 23 |
+
--max-model-len ${GRANITE_CONTEXT_LEN}
|
| 24 |
+
--max-num-seqs 8
|
| 25 |
+
--gpu-memory-utilization 0.92
|
| 26 |
+
--served-model-name sovereign-granite-4.1-verifier
|
| 27 |
+
--enforce-eager
|
| 28 |
+
healthcheck:
|
| 29 |
+
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
|
| 30 |
+
interval: 30s
|
| 31 |
+
timeout: 10s
|
| 32 |
+
retries: 3
|
| 33 |
+
start_period: 120s
|
| 34 |
+
restart: unless-stopped
|
| 35 |
+
|
| 36 |
+
lean4-kernel:
|
| 37 |
+
image: ${LEAN4_IMAGE_TAG}
|
| 38 |
+
container_name: lean_llm_lean4_kernel
|
| 39 |
+
user: "1000:1000"
|
| 40 |
+
read_only: true
|
| 41 |
+
security_opt:
|
| 42 |
+
- no-new-privileges:true
|
| 43 |
+
cap_drop:
|
| 44 |
+
- ALL
|
| 45 |
+
tmpfs:
|
| 46 |
+
- /tmp:exec,size=2g
|
| 47 |
+
volumes:
|
| 48 |
+
- ${VERIFICATION_PROJECT_ROOT}:/workspace/project:ro
|
| 49 |
+
- ${SOVEREIGN_CACHE_STORE}/lake:/home/lean/.lake:rw
|
| 50 |
+
- ${BIFROST_AUDIT_SINK}/lean4:/workspace/artifacts:rw
|
| 51 |
+
working_dir: /workspace/project/lean4
|
| 52 |
+
entrypoint: ["/bin/bash", "-c", "lake build && lake exe verify"]
|
| 53 |
+
deploy:
|
| 54 |
+
resources:
|
| 55 |
+
limits:
|
| 56 |
+
cpus: "4"
|
| 57 |
+
memory: 8G
|
| 58 |
+
|
| 59 |
+
networks:
|
| 60 |
+
default:
|
| 61 |
+
name: lean_llm_verification_loop
|
| 62 |
+
driver: bridge
|
| 63 |
+
internal: true
|
lean4/MiniF2F.lean
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
namespace MiniF2F
|
| 2 |
+
|
| 3 |
+
theorem demo_nonneg_square (x : ℝ) : x ^ 2 ≥ 0 := by
|
| 4 |
+
sorry
|
| 5 |
+
|
| 6 |
+
theorem demo_add_comm (a b : Nat) : a + b = b + a := by
|
| 7 |
+
sorry
|
| 8 |
+
|
| 9 |
+
end MiniF2F
|
lean4/VerifyMain.lean
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import SovereignCorpus.Bridge.Granite4Parser
|
| 2 |
+
import SovereignCorpus.Tactics.PlasmaGate
|
| 3 |
+
|
| 4 |
+
def parseOnlyMode (args : List String) : IO UInt32 := do
|
| 5 |
+
let path :=
|
| 6 |
+
match args.dropWhile (fun a => a != "--parse") with
|
| 7 |
+
| _ :: file :: _ => file
|
| 8 |
+
| _ => "artifacts/input.jsonl"
|
| 9 |
+
let problemsOrError ← SovereignCorpus.Bridge.Granite4Parser.loadProblems path
|
| 10 |
+
match problemsOrError with
|
| 11 |
+
| Except.ok problems =>
|
| 12 |
+
IO.println s!"parse_ok:{problems.length}"
|
| 13 |
+
pure 0
|
| 14 |
+
| Except.error err =>
|
| 15 |
+
IO.eprintln s!"parse_error:{err}"
|
| 16 |
+
pure 1
|
| 17 |
+
|
| 18 |
+
def fullVerificationMode : IO UInt32 := do
|
| 19 |
+
IO.println "verification harness scaffold: full verification mode not yet implemented"
|
| 20 |
+
pure 0
|
| 21 |
+
|
| 22 |
+
def main (args : List String) : IO UInt32 := do
|
| 23 |
+
let code ←
|
| 24 |
+
if args.contains "--parse" then
|
| 25 |
+
parseOnlyMode args
|
| 26 |
+
else
|
| 27 |
+
fullVerificationMode
|
| 28 |
+
if code != 0 then
|
| 29 |
+
IO.eprintln s!"verify failed with code {code}"
|
| 30 |
+
pure code
|
lean4/lake-manifest.json
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{"version": "1.1.0",
|
| 2 |
+
"packagesDir": ".lake/packages",
|
| 3 |
+
"packages":
|
| 4 |
+
[{"url": "https://github.com/leanprover-community/batteries",
|
| 5 |
+
"type": "git",
|
| 6 |
+
"subDir": null,
|
| 7 |
+
"scope": "leanprover-community",
|
| 8 |
+
"rev": "31a10a332858d6981dbcf55d54ee51680dd75f18",
|
| 9 |
+
"name": "batteries",
|
| 10 |
+
"manifestFile": "lake-manifest.json",
|
| 11 |
+
"inputRev": "main",
|
| 12 |
+
"inherited": true,
|
| 13 |
+
"configFile": "lakefile.toml"},
|
| 14 |
+
{"url": "https://github.com/leanprover-community/quote4",
|
| 15 |
+
"type": "git",
|
| 16 |
+
"subDir": null,
|
| 17 |
+
"scope": "leanprover-community",
|
| 18 |
+
"rev": "1357f4f49450abb9dfd4783e38219f4ce84f9785",
|
| 19 |
+
"name": "Qq",
|
| 20 |
+
"manifestFile": "lake-manifest.json",
|
| 21 |
+
"inputRev": "master",
|
| 22 |
+
"inherited": true,
|
| 23 |
+
"configFile": "lakefile.lean"},
|
| 24 |
+
{"url": "https://github.com/leanprover-community/aesop",
|
| 25 |
+
"type": "git",
|
| 26 |
+
"subDir": null,
|
| 27 |
+
"scope": "leanprover-community",
|
| 28 |
+
"rev": "5f934891e11d70a1b86e302fdf9cecfc21e8de46",
|
| 29 |
+
"name": "aesop",
|
| 30 |
+
"manifestFile": "lake-manifest.json",
|
| 31 |
+
"inputRev": "master",
|
| 32 |
+
"inherited": true,
|
| 33 |
+
"configFile": "lakefile.toml"},
|
| 34 |
+
{"url": "https://github.com/leanprover-community/ProofWidgets4",
|
| 35 |
+
"type": "git",
|
| 36 |
+
"subDir": null,
|
| 37 |
+
"scope": "leanprover-community",
|
| 38 |
+
"rev": "23268f52d3505955de3c26a42032702c25cfcbf8",
|
| 39 |
+
"name": "proofwidgets",
|
| 40 |
+
"manifestFile": "lake-manifest.json",
|
| 41 |
+
"inputRev": "v0.0.44",
|
| 42 |
+
"inherited": true,
|
| 43 |
+
"configFile": "lakefile.lean"},
|
| 44 |
+
{"url": "https://github.com/leanprover/lean4-cli",
|
| 45 |
+
"type": "git",
|
| 46 |
+
"subDir": null,
|
| 47 |
+
"scope": "leanprover",
|
| 48 |
+
"rev": "2cf1030dc2ae6b3632c84a09350b675ef3e347d0",
|
| 49 |
+
"name": "Cli",
|
| 50 |
+
"manifestFile": "lake-manifest.json",
|
| 51 |
+
"inputRev": "main",
|
| 52 |
+
"inherited": true,
|
| 53 |
+
"configFile": "lakefile.toml"},
|
| 54 |
+
{"url": "https://github.com/leanprover-community/import-graph",
|
| 55 |
+
"type": "git",
|
| 56 |
+
"subDir": null,
|
| 57 |
+
"scope": "leanprover-community",
|
| 58 |
+
"rev": "984d7ee170b75d6b03c0903e0b750ee2c6d1e3fb",
|
| 59 |
+
"name": "importGraph",
|
| 60 |
+
"manifestFile": "lake-manifest.json",
|
| 61 |
+
"inputRev": "main",
|
| 62 |
+
"inherited": true,
|
| 63 |
+
"configFile": "lakefile.toml"},
|
| 64 |
+
{"url": "https://github.com/leanprover-community/LeanSearchClient",
|
| 65 |
+
"type": "git",
|
| 66 |
+
"subDir": null,
|
| 67 |
+
"scope": "leanprover-community",
|
| 68 |
+
"rev": "7bedaed1ef024add1e171cc17706b012a9a37802",
|
| 69 |
+
"name": "LeanSearchClient",
|
| 70 |
+
"manifestFile": "lake-manifest.json",
|
| 71 |
+
"inputRev": "main",
|
| 72 |
+
"inherited": true,
|
| 73 |
+
"configFile": "lakefile.toml"},
|
| 74 |
+
{"url": "https://github.com/leanprover-community/plausible",
|
| 75 |
+
"type": "git",
|
| 76 |
+
"subDir": null,
|
| 77 |
+
"scope": "leanprover-community",
|
| 78 |
+
"rev": "d212dd74414e997653cd3484921f4159c955ccca",
|
| 79 |
+
"name": "plausible",
|
| 80 |
+
"manifestFile": "lake-manifest.json",
|
| 81 |
+
"inputRev": "main",
|
| 82 |
+
"inherited": true,
|
| 83 |
+
"configFile": "lakefile.toml"},
|
| 84 |
+
{"url": "https://github.com/leanprover-community/mathlib4",
|
| 85 |
+
"type": "git",
|
| 86 |
+
"subDir": null,
|
| 87 |
+
"scope": "leanprover-community",
|
| 88 |
+
"rev": "d7317655e2826dc1f1de9a0c138db2775c4bb841",
|
| 89 |
+
"name": "mathlib",
|
| 90 |
+
"manifestFile": "lake-manifest.json",
|
| 91 |
+
"inputRev": "v4.13.0",
|
| 92 |
+
"inherited": false,
|
| 93 |
+
"configFile": "lakefile.lean"}],
|
| 94 |
+
"name": "SovereignTransformer_Verification",
|
| 95 |
+
"lakeDir": ".lake"}
|
lean4/lakefile.toml
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name = "SovereignTransformer_Verification"
|
| 2 |
+
package = "sovereign_verification"
|
| 3 |
+
version = "0.1.0"
|
| 4 |
+
defaultTargets = ["SovereignCorpus", "verify"]
|
| 5 |
+
|
| 6 |
+
[[require]]
|
| 7 |
+
name = "mathlib"
|
| 8 |
+
scope = "leanprover-community"
|
| 9 |
+
rev = "v4.13.0"
|
| 10 |
+
|
| 11 |
+
[[lean_lib]]
|
| 12 |
+
name = "SovereignCorpus"
|
| 13 |
+
srcDir = "src"
|
| 14 |
+
|
| 15 |
+
[[lean_exe]]
|
| 16 |
+
name = "verify"
|
| 17 |
+
root = "VerifyMain"
|
lean4/lean-toolchain
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
leanprover/lean4:v4.13.0
|
lean4/src/SovereignCorpus.lean
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import SovereignCorpus.Core
|
| 2 |
+
import SovereignCorpus.Bridge.Granite4Schema
|
| 3 |
+
import SovereignCorpus.Bridge.Granite4Parser
|
| 4 |
+
import SovereignCorpus.Tactics.PlasmaGate
|
lean4/src/SovereignCorpus/Bridge/Granite4Parser.lean
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import Lean.Data.Json
|
| 2 |
+
import SovereignCorpus.Bridge.Granite4Schema
|
| 3 |
+
|
| 4 |
+
namespace SovereignCorpus.Bridge.Granite4Parser
|
| 5 |
+
|
| 6 |
+
open Lean
|
| 7 |
+
open SovereignCorpus.Bridge
|
| 8 |
+
|
| 9 |
+
inductive ParseError where
|
| 10 |
+
| jsonDecode (msg : String) (line : Nat)
|
| 11 |
+
| schemaViolation (field : String) (reason : String)
|
| 12 |
+
| lean3SyntaxDetected (pattern : String) (line : Nat)
|
| 13 |
+
| tacticForbidden (tactic : String) (line : Nat)
|
| 14 |
+
deriving Repr, Inhabited
|
| 15 |
+
|
| 16 |
+
def forbiddenPatterns : List String :=
|
| 17 |
+
[
|
| 18 |
+
"meta def",
|
| 19 |
+
"tactic.block",
|
| 20 |
+
"refine_struct",
|
| 21 |
+
"classical.by_contradiction",
|
| 22 |
+
"by_contra!",
|
| 23 |
+
"have! := by",
|
| 24 |
+
"sorryAx",
|
| 25 |
+
"prop_decidable",
|
| 26 |
+
"Classical.propDecidable"
|
| 27 |
+
]
|
| 28 |
+
|
| 29 |
+
def defaultAllowedTactics : List String :=
|
| 30 |
+
["rw", "simp_all", "norm_num", "linarith", "nlinarith", "aesop", "apply", "exact", "intro", "obtain", "cases", "induction", "constructor", "split_ifs", "field_simp", "ring_nf", "norm_cast", "omega"]
|
| 31 |
+
|
| 32 |
+
def containsText (haystack needle : String) : Bool :=
|
| 33 |
+
if needle.isEmpty then
|
| 34 |
+
true
|
| 35 |
+
else
|
| 36 |
+
(haystack.splitOn needle).length > 1
|
| 37 |
+
|
| 38 |
+
def containsForbiddenPattern (text : String) : Option String :=
|
| 39 |
+
forbiddenPatterns.find? (fun pattern => containsText text pattern)
|
| 40 |
+
|
| 41 |
+
def guardLean4Syntax (p : GraniteProblem) (line : Nat) : Except ParseError Unit := do
|
| 42 |
+
let haystack := p.statement ++ "\n" ++ String.intercalate "\n" p.context ++ "\n" ++ p.tacticHint.getD ""
|
| 43 |
+
match containsForbiddenPattern haystack with
|
| 44 |
+
| some pattern => throw <| ParseError.lean3SyntaxDetected pattern line
|
| 45 |
+
| none => pure ()
|
| 46 |
+
|
| 47 |
+
def guardTactics (p : GraniteProblem) (line : Nat) : Except ParseError Unit := do
|
| 48 |
+
match p.tacticHint with
|
| 49 |
+
| some hint =>
|
| 50 |
+
if p.meta.allowedTactics.contains hint || defaultAllowedTactics.contains hint then
|
| 51 |
+
pure ()
|
| 52 |
+
else
|
| 53 |
+
throw <| ParseError.tacticForbidden hint line
|
| 54 |
+
| none => pure ()
|
| 55 |
+
|
| 56 |
+
def guardStatement (p : GraniteProblem) : Except ParseError Unit := do
|
| 57 |
+
if containsText p.statement "sorry" then
|
| 58 |
+
throw <| ParseError.schemaViolation "statement" "target theorem statement must not contain sorry"
|
| 59 |
+
else
|
| 60 |
+
pure ()
|
| 61 |
+
|
| 62 |
+
def parseLine (line : String) (lineNum : Nat) : Except ParseError GraniteProblem := do
|
| 63 |
+
if line.trim.isEmpty then
|
| 64 |
+
throw <| ParseError.jsonDecode "empty line" lineNum
|
| 65 |
+
let json <- Json.parse line |>.mapError (fun err => ParseError.jsonDecode err lineNum)
|
| 66 |
+
let problem <- fromJson? json |>.mapError (fun err => ParseError.jsonDecode err lineNum)
|
| 67 |
+
guardLean4Syntax problem lineNum
|
| 68 |
+
guardTactics problem lineNum
|
| 69 |
+
guardStatement problem
|
| 70 |
+
pure problem
|
| 71 |
+
|
| 72 |
+
def loadProblems (path : String) : IO (Except String (List GraniteProblem)) := do
|
| 73 |
+
let content ← IO.FS.readFile path
|
| 74 |
+
let lines := content.splitOn "\n"
|
| 75 |
+
let parsed := lines.enum.filterMap (fun ⟨idx, line⟩ =>
|
| 76 |
+
if line.trim.isEmpty then
|
| 77 |
+
none
|
| 78 |
+
else
|
| 79 |
+
some <| parseLine line (idx + 1)
|
| 80 |
+
)
|
| 81 |
+
let errors := parsed.filterMap (fun r => match r with | .error e => some e | .ok _ => none)
|
| 82 |
+
if !errors.isEmpty then
|
| 83 |
+
pure <| Except.error s!"parse failures: {repr errors}"
|
| 84 |
+
else
|
| 85 |
+
pure <| Except.ok <| parsed.filterMap (fun r => match r with | .ok p => some p | .error _ => none)
|
| 86 |
+
|
| 87 |
+
end SovereignCorpus.Bridge.Granite4Parser
|
lean4/src/SovereignCorpus/Bridge/Granite4Schema.lean
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import Lean.Data.Json.FromToJson
|
| 2 |
+
|
| 3 |
+
namespace SovereignCorpus.Bridge
|
| 4 |
+
|
| 5 |
+
open Lean
|
| 6 |
+
|
| 7 |
+
structure ProblemMeta where
|
| 8 |
+
source : String
|
| 9 |
+
timestamp : String
|
| 10 |
+
operatorSig : String
|
| 11 |
+
maxSteps : Nat
|
| 12 |
+
allowedTactics : List String
|
| 13 |
+
deriving Repr, Inhabited, Lean.FromJson, Lean.ToJson
|
| 14 |
+
|
| 15 |
+
structure GraniteProblem where
|
| 16 |
+
id : String
|
| 17 |
+
statement : String
|
| 18 |
+
context : List String
|
| 19 |
+
tacticHint : Option String
|
| 20 |
+
meta : ProblemMeta
|
| 21 |
+
deriving Repr, Inhabited, Lean.FromJson, Lean.ToJson
|
| 22 |
+
|
| 23 |
+
inductive ResponseStatus where
|
| 24 |
+
| proposed
|
| 25 |
+
| corrected
|
| 26 |
+
| failed
|
| 27 |
+
deriving Repr, Inhabited, Lean.FromJson, Lean.ToJson
|
| 28 |
+
|
| 29 |
+
inductive DiagnosticSeverity where
|
| 30 |
+
| info
|
| 31 |
+
| warning
|
| 32 |
+
| error
|
| 33 |
+
deriving Repr, Inhabited, Lean.FromJson, Lean.ToJson
|
| 34 |
+
|
| 35 |
+
structure Span where
|
| 36 |
+
startLine : Nat
|
| 37 |
+
startCol : Nat
|
| 38 |
+
endLine : Nat
|
| 39 |
+
endCol : Nat
|
| 40 |
+
deriving Repr, Inhabited, Lean.FromJson, Lean.ToJson
|
| 41 |
+
|
| 42 |
+
structure Diagnostic where
|
| 43 |
+
severity : DiagnosticSeverity
|
| 44 |
+
message : String
|
| 45 |
+
span : Option Span
|
| 46 |
+
deriving Repr, Inhabited, Lean.FromJson, Lean.ToJson
|
| 47 |
+
|
| 48 |
+
structure GraniteResponse where
|
| 49 |
+
problemId : String
|
| 50 |
+
status : ResponseStatus
|
| 51 |
+
proofScript : String
|
| 52 |
+
diagnostics : List Diagnostic
|
| 53 |
+
deriving Repr, Inhabited, Lean.FromJson, Lean.ToJson
|
| 54 |
+
|
| 55 |
+
end SovereignCorpus.Bridge
|
lean4/src/SovereignCorpus/Core.lean
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
namespace SovereignCorpus
|
| 2 |
+
|
| 3 |
+
def version : String := "0.1.0"
|
| 4 |
+
|
| 5 |
+
end SovereignCorpus
|
lean4/src/SovereignCorpus/Tactics/PlasmaGate.lean
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
namespace SovereignCorpus.Tactics
|
| 2 |
+
|
| 3 |
+
def verify (_statement : String) : IO Unit := do
|
| 4 |
+
pure ()
|
| 5 |
+
|
| 6 |
+
end SovereignCorpus.Tactics
|
logic/sovereign_verification.pl
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
% Deterministic pre-flight checks for the verification harness.
|
| 2 |
+
|
| 3 |
+
file_exists_or_fail(File) :-
|
| 4 |
+
exists_file(File), !.
|
| 5 |
+
file_exists_or_fail(File) :-
|
| 6 |
+
throw(error(missing_file(File), _)).
|
| 7 |
+
|
| 8 |
+
verify_granite_output(File) :-
|
| 9 |
+
file_exists_or_fail(File).
|
| 10 |
+
|
| 11 |
+
verify_lean_corpus(ProjectRoot) :-
|
| 12 |
+
atom_concat(ProjectRoot, '/lean4/lakefile.toml', Lakefile),
|
| 13 |
+
file_exists_or_fail(Lakefile).
|
| 14 |
+
|
| 15 |
+
authorized_verification_run(_Operator, _Project) :-
|
| 16 |
+
true.
|
| 17 |
+
|
| 18 |
+
run_verification_loop(Operator, ProjectRoot) :-
|
| 19 |
+
authorized_verification_run(Operator, ProjectRoot),
|
| 20 |
+
verify_lean_corpus(ProjectRoot),
|
| 21 |
+
format("preflight_ok(~w, ~w)~n", [Operator, ProjectRoot]).
|
logic/verification_loop.pl
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
:- consult('sovereign_verification.pl').
|
| 2 |
+
|
| 3 |
+
generate_problems(Intent, MathlibCtx, OperatorSig, OutputFile) :-
|
| 4 |
+
setup_call_cleanup(
|
| 5 |
+
open(OutputFile, write, Stream),
|
| 6 |
+
json_write_dict(Stream, _{
|
| 7 |
+
id:"demo-problem-1",
|
| 8 |
+
statement:Intent,
|
| 9 |
+
context:MathlibCtx,
|
| 10 |
+
tacticHint:"aesop",
|
| 11 |
+
meta:_{
|
| 12 |
+
source:"granite-4.1-verifier",
|
| 13 |
+
timestamp:"2026-07-14T00:00:00Z",
|
| 14 |
+
operatorSig:OperatorSig,
|
| 15 |
+
maxSteps:30,
|
| 16 |
+
allowedTactics:["rw","simp_all","norm_num","linarith","nlinarith","aesop","apply","exact","intro","obtain","cases","induction"]
|
| 17 |
+
}
|
| 18 |
+
}, [width(0)]),
|
| 19 |
+
close(Stream)
|
| 20 |
+
).
|
| 21 |
+
|
| 22 |
+
call_granite(InputFile, OutputFile) :-
|
| 23 |
+
setup_call_cleanup(
|
| 24 |
+
open(InputFile, read, In),
|
| 25 |
+
read_string(In, _, Content),
|
| 26 |
+
close(In)
|
| 27 |
+
),
|
| 28 |
+
setup_call_cleanup(
|
| 29 |
+
open(OutputFile, write, Out),
|
| 30 |
+
format(Out, "{\"problemId\":\"demo-problem-1\",\"status\":\"proposed\",\"proofScript\":\"~w\",\"diagnostics\":[]}~n", [Content]),
|
| 31 |
+
close(Out)
|
| 32 |
+
).
|
| 33 |
+
|
| 34 |
+
parse_and_validate(JsonlFile, success(JsonlFile)).
|
| 35 |
+
|
| 36 |
+
%% Shell out to `lake exe verify -- --parse <file>` and capture exit code.
|
| 37 |
+
%% Requires SWI-Prolog shell/2. Lake must be on PATH or LAKE_BIN env set.
|
| 38 |
+
execute_verification(JsonlFile, Result) :-
|
| 39 |
+
( getenv('LAKE_BIN', Lake) -> true ; Lake = 'lake' ),
|
| 40 |
+
atomic_list_concat([Lake, ' exe verify -- --parse ', JsonlFile], Cmd),
|
| 41 |
+
( shell(Cmd, 0) ->
|
| 42 |
+
Result = result(0, verified)
|
| 43 |
+
;
|
| 44 |
+
Result = result(1, parse_failed)
|
| 45 |
+
).
|
| 46 |
+
|
| 47 |
+
verify_with_retries(Intent, OperatorSig, MaxRetries, FinalResult) :-
|
| 48 |
+
verify_loop(Intent, OperatorSig, 0, MaxRetries, FinalResult).
|
| 49 |
+
|
| 50 |
+
verify_loop(Intent, OperatorSig, Attempt, MaxRetries, FinalResult) :-
|
| 51 |
+
Attempt < MaxRetries,
|
| 52 |
+
generate_problems(Intent, ["import Mathlib"], OperatorSig, 'input.jsonl'),
|
| 53 |
+
call_granite('input.jsonl', 'granite_response.jsonl'),
|
| 54 |
+
parse_and_validate('granite_response.jsonl', ParseRes),
|
| 55 |
+
( ParseRes = success(_) ->
|
| 56 |
+
execute_verification('granite_response.jsonl', KernelResult),
|
| 57 |
+
( KernelResult = result(0, _) ->
|
| 58 |
+
FinalResult = success(KernelResult)
|
| 59 |
+
; NextAttempt is Attempt + 1,
|
| 60 |
+
verify_loop(Intent, OperatorSig, NextAttempt, MaxRetries, FinalResult)
|
| 61 |
+
)
|
| 62 |
+
; NextAttempt is Attempt + 1,
|
| 63 |
+
verify_loop(Intent, OperatorSig, NextAttempt, MaxRetries, FinalResult)
|
| 64 |
+
).
|
| 65 |
+
|
| 66 |
+
verify_loop(_, _, Attempt, MaxRetries, fail(max_retries_exceeded)) :-
|
| 67 |
+
Attempt >= MaxRetries.
|