SNAPKITTYWEST commited on
Commit
fc2d127
·
verified ·
1 Parent(s): b0ece23

chore: convert from dataset to model repo

Browse files
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.