lean-lockstep 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lean_lockstep-0.1.0.dist-info/METADATA +218 -0
- lean_lockstep-0.1.0.dist-info/RECORD +71 -0
- lean_lockstep-0.1.0.dist-info/WHEEL +5 -0
- lean_lockstep-0.1.0.dist-info/entry_points.txt +3 -0
- lean_lockstep-0.1.0.dist-info/licenses/LICENSE +22 -0
- lean_lockstep-0.1.0.dist-info/top_level.txt +1 -0
- lockstep/__init__.py +17 -0
- lockstep/__main__.py +3 -0
- lockstep/allowlist.py +40 -0
- lockstep/artifact_cache.py +515 -0
- lockstep/artifacts.py +185 -0
- lockstep/automation_schema.py +30 -0
- lockstep/build.py +468 -0
- lockstep/bundles.py +37 -0
- lockstep/cli.py +148 -0
- lockstep/commands/__init__.py +28 -0
- lockstep/commands/audit.py +46 -0
- lockstep/commands/automation.py +84 -0
- lockstep/commands/build.py +61 -0
- lockstep/commands/cache.py +58 -0
- lockstep/commands/check.py +81 -0
- lockstep/commands/claims.py +62 -0
- lockstep/commands/close.py +193 -0
- lockstep/commands/doctor.py +86 -0
- lockstep/commands/extract.py +169 -0
- lockstep/commands/falsify.py +108 -0
- lockstep/commands/index.py +16 -0
- lockstep/commands/jobs.py +188 -0
- lockstep/commands/layers.py +52 -0
- lockstep/commands/library.py +67 -0
- lockstep/commands/lock.py +58 -0
- lockstep/commands/log.py +132 -0
- lockstep/commands/node.py +429 -0
- lockstep/commands/note.py +76 -0
- lockstep/commands/probe.py +11 -0
- lockstep/commands/proof.py +31 -0
- lockstep/commands/ready.py +48 -0
- lockstep/commands/rules.py +61 -0
- lockstep/commands/search.py +37 -0
- lockstep/commands/status.py +172 -0
- lockstep/config.py +489 -0
- lockstep/context.py +33 -0
- lockstep/data/AuditCandidate.lean +18 -0
- lockstep/data/CacheArtifacts.lean +37 -0
- lockstep/data/Extract.lean.tmpl +362 -0
- lockstep/data/node.lean.tmpl +9 -0
- lockstep/delivery.py +45 -0
- lockstep/errors.py +28 -0
- lockstep/finalize.py +102 -0
- lockstep/gitutil.py +90 -0
- lockstep/hooks.py +143 -0
- lockstep/jobs.py +349 -0
- lockstep/layers.py +156 -0
- lockstep/lean.py +107 -0
- lockstep/library.py +188 -0
- lockstep/lock.py +68 -0
- lockstep/mcp_server.py +84 -0
- lockstep/metrics.py +12 -0
- lockstep/modules.py +197 -0
- lockstep/nodes.py +475 -0
- lockstep/operations.py +265 -0
- lockstep/output.py +45 -0
- lockstep/probes.py +72 -0
- lockstep/proofs.py +250 -0
- lockstep/resources.py +100 -0
- lockstep/shadow_index.py +47 -0
- lockstep/spec.py +36 -0
- lockstep/stage_runner.py +47 -0
- lockstep/storage.py +186 -0
- lockstep/store.py +338 -0
- lockstep/tags.py +84 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lean-lockstep
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Coordinate several agents on a Lean 4 formalization: state derived from the compiled environment, locked statements, recorded claims and memory-guarded jobs
|
|
5
|
+
Author: Gavin Litchfield
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/GLitchfield/lean-lockstep
|
|
8
|
+
Project-URL: Repository, https://github.com/GLitchfield/lean-lockstep
|
|
9
|
+
Project-URL: Issues, https://github.com/GLitchfield/lean-lockstep/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/GLitchfield/lean-lockstep/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: lean4,formalization,theorem-proving,blueprint,ai-agents,mcp
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
22
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Provides-Extra: mcp
|
|
27
|
+
Requires-Dist: mcp<3,>=2; extra == "mcp"
|
|
28
|
+
Provides-Extra: test
|
|
29
|
+
Requires-Dist: pytest; extra == "test"
|
|
30
|
+
Provides-Extra: research
|
|
31
|
+
Requires-Dist: numpy; extra == "research"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# lean-lockstep
|
|
35
|
+
|
|
36
|
+
A project harness for Lean 4 formalization work done by several agents at once: AI coding agents
|
|
37
|
+
of any kind (anything that can run a shell command or call an MCP tool) and people. It keeps the
|
|
38
|
+
state of the project (which statements are open, claimed, proved, and what depends on what)
|
|
39
|
+
derived from the compiled Lean environment, and it records who is doing what, why, and with how
|
|
40
|
+
much memory.
|
|
41
|
+
|
|
42
|
+
- **State comes from Lean, not from a document.** Each open statement is a *node*: a theorem
|
|
43
|
+
with a `sorry` in its own blueprint module, tagged in its docstring. `lockstep extract` reads the
|
|
44
|
+
compiled environment and reports each node as open, claimed or closed (sorry-free with
|
|
45
|
+
allowlisted axioms). There is no hand-kept status file that can drift.
|
|
46
|
+
- **Approved statements are locked.** `harness/statements.lock` records the type hash of every
|
|
47
|
+
approved statement. A proof that quietly weakens its statement shows up as a lock violation;
|
|
48
|
+
changing a statement takes `lockstep node restate`, which logs who approved it and why. This is the
|
|
49
|
+
failure mode that matters most when agents write the proofs.
|
|
50
|
+
- **Agents coordinate through the harness.** Claims expire and carry the intent (`--why`); every
|
|
51
|
+
release records an outcome; `lockstep log` and `lockstep journal` keep the trail; long commands run as
|
|
52
|
+
recorded, memory-capped jobs that every agent can see.
|
|
53
|
+
- **Audits scale.** The axiom audit is a per-module taint scan with a cache, which finishes on
|
|
54
|
+
projects where `#print axioms` does not.
|
|
55
|
+
- **No client or model is assumed.** Every command has a CLI and an MCP tool. A git pre-commit
|
|
56
|
+
hook guards commits for everyone; optional Claude Code hooks add a session banner and a guard
|
|
57
|
+
against compute launched outside the harness.
|
|
58
|
+
|
|
59
|
+
Status: experimental (0.1). Built and used in two research projects; expect rough edges outside
|
|
60
|
+
them. Linux first.
|
|
61
|
+
|
|
62
|
+
## Requirements
|
|
63
|
+
|
|
64
|
+
- Python 3.11 or newer. The core has no dependencies; extras: `mcp` (MCP server), `test`
|
|
65
|
+
(pytest), `research` (NumPy for research-library probes).
|
|
66
|
+
- Lean 4 through [elan](https://github.com/leanprover/elan), Lake, and git.
|
|
67
|
+
- The memory guard runs each `lake` invocation in a capped `systemd-run --user` scope, so it
|
|
68
|
+
needs Linux with a systemd user session. Elsewhere set `[build] guard = false`.
|
|
69
|
+
- `bwrap` (bubblewrap) for the sandboxed proof checks of the experimental automation layer.
|
|
70
|
+
|
|
71
|
+
## Try it
|
|
72
|
+
|
|
73
|
+
`examples/minimal` is a Lean-only Lake project (no Mathlib) with one core lemma and an empty
|
|
74
|
+
blueprint. From a checkout of this repository:
|
|
75
|
+
|
|
76
|
+
```console
|
|
77
|
+
cd examples/minimal
|
|
78
|
+
export LOCKSTEP_AGENT=me:demo # every claim, job and log entry is recorded under this id
|
|
79
|
+
../../bin/lockstep build core
|
|
80
|
+
../../bin/lockstep extract # writes harness/nodes.json, index.json, status.md
|
|
81
|
+
../../bin/lockstep node add --name double_succ --ws A --kind formalization \
|
|
82
|
+
--type "(n : Nat) : (n + 1) + (n + 1) = 2 * n + 2" \
|
|
83
|
+
--description "Doubling a successor." --depends double --dangling-ok "example"
|
|
84
|
+
../../bin/lockstep ready # Demo.double_succ is open and ready
|
|
85
|
+
../../bin/lockstep claim double_succ --why "rewrite with Demo.double, then omega"
|
|
86
|
+
# replace the `sorry` in DemoBlueprint/A/DoubleSucc.lean with `rw [double]; omega`
|
|
87
|
+
../../bin/lockstep check double_succ # sorry=False status=closed
|
|
88
|
+
../../bin/lockstep close double_succ # moves it into the core library, records the attempt
|
|
89
|
+
../../bin/lockstep audit && ../../bin/lockstep journal
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`tests/test_example_lifecycle.py` runs the same sequence whenever `lake` is installed. To start
|
|
93
|
+
over, run `git checkout -- . && git clean -fdx .` in `examples/minimal`.
|
|
94
|
+
|
|
95
|
+
## Installing
|
|
96
|
+
|
|
97
|
+
The harness writes Lean files into the project (the extractor, node modules) and its lock hashes
|
|
98
|
+
depend on the toolchain, so pin the version a project uses. Either:
|
|
99
|
+
|
|
100
|
+
- **From PyPI**, which puts `lockstep` and `lockstep-mcp` on the `PATH`:
|
|
101
|
+
```console
|
|
102
|
+
uv tool install "lean-lockstep[mcp]==0.1.0" # or: pipx install "lean-lockstep[mcp]==0.1.0"
|
|
103
|
+
```
|
|
104
|
+
Without PyPI access, install a tag from git instead:
|
|
105
|
+
`uv tool install "lean-lockstep[mcp] @ git+https://github.com/GLitchfield/lean-lockstep@v0.1.0"`.
|
|
106
|
+
- **As a git submodule**, pinned by commit and upgraded by bumping the pin, which suits a project
|
|
107
|
+
that also develops the harness:
|
|
108
|
+
```console
|
|
109
|
+
git submodule add https://github.com/GLitchfield/lean-lockstep tools/lockstep
|
|
110
|
+
uv venv tools/lockstep/.venv && uv pip install -e "tools/lockstep[mcp]"
|
|
111
|
+
```
|
|
112
|
+
`tools/lockstep/bin/lockstep` and `tools/lockstep/bin/lockstep-mcp` prefer that virtualenv and
|
|
113
|
+
fall back to the system `python3`.
|
|
114
|
+
|
|
115
|
+
The commands below write `lockstep`; with a submodule, that is `tools/lockstep/bin/lockstep`.
|
|
116
|
+
|
|
117
|
+
## Adopting it in a project
|
|
118
|
+
|
|
119
|
+
1. Give the Lake package two libraries: a core library (proved results only) and a blueprint
|
|
120
|
+
library whose root file imports every node module. `lockstep node add` maintains that root.
|
|
121
|
+
2. Copy `examples/minimal/harness/` and edit `harness/config.toml`: namespaces, layers, build
|
|
122
|
+
targets, memory caps. Start `statements.lock` as `{}` and `allowlist.json` as `[]`.
|
|
123
|
+
3. Ignore the harness state directory (`.lockstep/` with `[project] state_home = ".lockstep"`).
|
|
124
|
+
4. Write the agent rules into the files your clients read (`AGENTS.md`, `CLAUDE.md`, ...) and
|
|
125
|
+
list them under `[rules]`; `lockstep rules` checks that they carry the same rule list (cheap enough
|
|
126
|
+
for CI). `examples/minimal/AGENTS.md` is a starting point. Tell each agent to export a stable
|
|
127
|
+
`LOCKSTEP_AGENT` (for example `<client>:<session id>`); claims and logs are recorded under it.
|
|
128
|
+
5. Guard commits with the git hook, which works whoever commits:
|
|
129
|
+
```console
|
|
130
|
+
printf '#!/bin/sh\nexec lockstep hook pre-commit\n' > .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit
|
|
131
|
+
```
|
|
132
|
+
It refuses a commit that fails `lockstep layers`, `lockstep extract --check` (generated files out of date
|
|
133
|
+
or a locked statement changed) or `lockstep audit --changed`.
|
|
134
|
+
6. Register the MCP server with your client: command `lockstep-mcp` (or `tools/lockstep/bin/lockstep-mcp`), stdio,
|
|
135
|
+
no arguments. For example `.mcp.json`:
|
|
136
|
+
```json
|
|
137
|
+
{ "mcpServers": { "lockstep": { "command": "tools/lockstep/bin/lockstep-mcp", "args": [] } } }
|
|
138
|
+
```
|
|
139
|
+
7. Optionally, for Claude Code, add the session and shell hooks to `.claude/settings.json`:
|
|
140
|
+
```json
|
|
141
|
+
{ "hooks": {
|
|
142
|
+
"SessionStart": [{ "hooks": [{ "type": "command", "command": "tools/lockstep/bin/lockstep hook session-start" }] }],
|
|
143
|
+
"PreToolUse": [{ "matcher": "Bash", "hooks": [{ "type": "command", "command": "tools/lockstep/bin/lockstep hook pre-bash" }] }] } }
|
|
144
|
+
```
|
|
145
|
+
`session-start` prints the session's agent id and `lockstep status --brief`. `pre-bash` blocks a
|
|
146
|
+
bare `nohup`/`systemd-run` (compute goes through `lockstep job run`) and runs the commit guard
|
|
147
|
+
before `git commit`/`git push`. Any client whose hooks pass the same JSON on stdin can use them.
|
|
148
|
+
8. In CI, `python3 -m lockstep.lock BASE_LOCK HEAD_LOCK` (with `PYTHONPATH=tools/lockstep` for a submodule)
|
|
149
|
+
prints the log files a lock change must touch: `restatements.md` when an approved statement
|
|
150
|
+
changed or disappeared, `retired.md` for a refutation. New entries need none.
|
|
151
|
+
9. Optionally, `tools/lockstep/systemd/install.sh` (from a checkout) installs a `lockstep-nightly-<project
|
|
152
|
+
id>` user timer (03:00) that runs the guarded core build, `lockstep extract --check` and `lockstep audit`.
|
|
153
|
+
|
|
154
|
+
## Commands
|
|
155
|
+
|
|
156
|
+
| Area | Commands |
|
|
157
|
+
|---|---|
|
|
158
|
+
| State | `status`, `ready`, `node show`, `search`, `extract`, `extract --check`, `doctor` |
|
|
159
|
+
| Statements | `node add`, `node restate`, `node retire`, `lock refresh` (after a toolchain bump) |
|
|
160
|
+
| Work | `claim`, `release`, `check`, `close`, `falsify` (conjecture nodes) |
|
|
161
|
+
| Builds and jobs | `build core` / `blueprint` / `node`, `job run`, `job wait`, `job list`, `worker` |
|
|
162
|
+
| Trail | `log`, `journal`, `note` (weekly summary) |
|
|
163
|
+
| Integrity | `audit`, `layers`, `rules`, `hook pre-commit` |
|
|
164
|
+
| Client hooks | `hook session-start`, `hook pre-bash` |
|
|
165
|
+
|
|
166
|
+
Every command takes `--json`, and all but the hooks are also MCP tools. Node names may be
|
|
167
|
+
dotted relative to the declaration namespace (`--name List.foo` declares `theorem List.foo` in
|
|
168
|
+
it), and `--depends` lists the project declarations a node waits on (library lemmas belong in
|
|
169
|
+
the description).
|
|
170
|
+
|
|
171
|
+
### Experimental
|
|
172
|
+
|
|
173
|
+
These work in the projects they came from but are less general; see
|
|
174
|
+
[`docs/automation.md`](docs/automation.md):
|
|
175
|
+
|
|
176
|
+
- **Automation layer**: durable `operation …` workflows run by `lockstep worker`, a results `inbox`,
|
|
177
|
+
`proof capture|check|prove`, `node finish`, `probe run|replay`, `context`.
|
|
178
|
+
- **Research library**: `lib search|show|list` over a project catalog
|
|
179
|
+
(`harness/research/catalog.json`).
|
|
180
|
+
- **Certificate layers**: `[layers]` rules for generated proof-module families, and
|
|
181
|
+
`storage share` for their compiled artifacts.
|
|
182
|
+
|
|
183
|
+
## Things that cost hours to learn
|
|
184
|
+
|
|
185
|
+
- **Never `import` the project modules at the top of a `lake env lean --run` script that also
|
|
186
|
+
calls `importModules` on them.** The script's own import maps the oleans; the second load
|
|
187
|
+
cannot mmap at the same addresses and reads them into anonymous memory instead (37 GB and a
|
|
188
|
+
cgroup OOM kill on a project with large certificate modules). The extractor template imports
|
|
189
|
+
only `Lean`; `main` imports the project.
|
|
190
|
+
- **Never use `importAll := true`** for the extractor environment (30+ GB). A plain import
|
|
191
|
+
exposes every theorem value in `env.header.moduleData`.
|
|
192
|
+
- **Never run bare `lake build` on big targets.** Lake 5 has no `-j`; two dozen parallel
|
|
193
|
+
compilers exhaust a 20 GB guard. `lockstep build` builds Lake's out-of-date list one module per
|
|
194
|
+
guarded invocation first.
|
|
195
|
+
- **`#print axioms` does not finish on large generated proof families** (16 TB read in 3.5 h);
|
|
196
|
+
the extractor's module-order taint scan with a per-module cache is the audit path.
|
|
197
|
+
- **A module-system core root (`module` header) cannot import plain files.** When the core root
|
|
198
|
+
uses it, nodes are written in module form from the start, so a proof elaborates against the
|
|
199
|
+
same imports before and after `lockstep close`.
|
|
200
|
+
- **The elaborator moves parts of a proof into auxiliary declarations** (`foo._proof_1`), so a
|
|
201
|
+
dependency scan of a theorem's value alone reports the auxiliaries instead of the lemmas they
|
|
202
|
+
use. The extractor looks through a declaration's own auxiliaries.
|
|
203
|
+
|
|
204
|
+
## Development
|
|
205
|
+
|
|
206
|
+
```console
|
|
207
|
+
uv venv .venv && uv pip install -e ".[test,mcp,research]"
|
|
208
|
+
.venv/bin/python -m pytest
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Releases follow semantic versioning (0.x: minor versions may break). Changes are listed in
|
|
212
|
+
[`CHANGELOG.md`](CHANGELOG.md). To release, bump `__version__` in `lockstep/__init__.py`, add the
|
|
213
|
+
changelog entry, and push a `vX.Y.Z` tag: `.github/workflows/release.yml` builds the sdist and
|
|
214
|
+
wheel and publishes them to PyPI through trusted publishing.
|
|
215
|
+
|
|
216
|
+
## License
|
|
217
|
+
|
|
218
|
+
MIT; see [`LICENSE`](LICENSE).
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
lean_lockstep-0.1.0.dist-info/licenses/LICENSE,sha256=FRI9ysgFGRFWTgdRUuJ7EryPx7thYVvmRICme89SwHo,1133
|
|
2
|
+
lockstep/__init__.py,sha256=jnxyg-EVE_XpyYkgdpkgwerj1D2qImhto_QVByFS0L4,508
|
|
3
|
+
lockstep/__main__.py,sha256=Odn24AAjrNqQllq6d-xtA79UrYAx0ulq-sa6FFhInVY,56
|
|
4
|
+
lockstep/allowlist.py,sha256=g9YdlAlFEk8eBCJLzD3rBDFBd7dmt4owo5tsfhrJfEg,1309
|
|
5
|
+
lockstep/artifact_cache.py,sha256=YKUxb9XPlyKMknoRKYh3Vknq-_68sa5d796149alrCE,21870
|
|
6
|
+
lockstep/artifacts.py,sha256=2uA9vTelY4NbEfvhnYrPiTA0yBoRehsPaFWvJYKnWoE,8190
|
|
7
|
+
lockstep/automation_schema.py,sha256=KcSqxDMPLcvHdhF28hB5qANLhlYURvB-MSZMzp3Zbtk,2007
|
|
8
|
+
lockstep/build.py,sha256=sTJnA48apX0SLShqPCbgBpEDthgQe_4Jt6cDy9ODoTs,22999
|
|
9
|
+
lockstep/bundles.py,sha256=_qAWfO2VYjYzOVy2faujecuWNj9e-vbXlKzSWL5PQC8,2093
|
|
10
|
+
lockstep/cli.py,sha256=aZLpCAtREDTM9VOdjj8T92MgfTtkIYgsxqkTp2Ggfv4,6536
|
|
11
|
+
lockstep/config.py,sha256=9E9TOo-UMYFeMMGnaNV-2zckCbjj9bQ6Jh8-kuZZhIY,18487
|
|
12
|
+
lockstep/context.py,sha256=tLi8_DIwBpBANwcHRmVnWRexVsK899ZcvD10mTVmTps,816
|
|
13
|
+
lockstep/delivery.py,sha256=9KKK3dfdcpjP1ydHvVuWnvyYZxh3z7J2SN6nsjqfqp0,2295
|
|
14
|
+
lockstep/errors.py,sha256=m28f9pjQyUrn3gBmaxcMbR8H3jVmjohrgrwbFi1vOaI,597
|
|
15
|
+
lockstep/finalize.py,sha256=u5NknUm_GClpifJbyDPzbqdA86NMcm6UPgos2RbLXQI,6256
|
|
16
|
+
lockstep/gitutil.py,sha256=P4WbY8SlcgUAI1Oj1UeeOPs9AydAALCHU4H3sCzmKgs,3455
|
|
17
|
+
lockstep/hooks.py,sha256=FUkc81wSslX78Jq4LnTV4bLfQLrUpSWa5tO6Ubfner8,6501
|
|
18
|
+
lockstep/jobs.py,sha256=5alv4UCxo30jyQ1SKb6r2QNt0G4w2B8TQtAEAamG8Bw,17690
|
|
19
|
+
lockstep/layers.py,sha256=IeodoeIuz5DbpKKoLPENnRQz7C5ktkQHcBMbQbnE8-0,7153
|
|
20
|
+
lockstep/lean.py,sha256=Xm2_6-r_MknvM8ACnZ5XQ-WpzBSW4nMLtyqYQj7UIuk,4638
|
|
21
|
+
lockstep/library.py,sha256=dWTz0BUKtym_CgUh6cDMpGgQBjoleVtkF0r4wTZa4Hs,7520
|
|
22
|
+
lockstep/lock.py,sha256=MHFhI276l3_ykmUpFTucOQQc3Y2Z5G3lLwL4A_DhEZ8,2635
|
|
23
|
+
lockstep/mcp_server.py,sha256=Pr98jBYxdQ7SCTKLXYChyYQF8d5e554NWDxvOesMkSk,3277
|
|
24
|
+
lockstep/metrics.py,sha256=7HrVcjCGtrM_KbkfhVOVVPNfb47ALTIPAPctd5dZ69I,463
|
|
25
|
+
lockstep/modules.py,sha256=xIJyovRvA1cQCVjxYa_oUjm9QVda-EodHSKnTr_N5w0,6685
|
|
26
|
+
lockstep/nodes.py,sha256=-jT19FMYdAnF_-XMbFnlRL4u2dgqBBfRpl5EXxwqVas,19203
|
|
27
|
+
lockstep/operations.py,sha256=W7BKc-iGQrOi4_eDq2maILmE1Le3F__p7I2rlyFY9qk,18253
|
|
28
|
+
lockstep/output.py,sha256=TqYzKtCx8FLv_myo4NUEzz4C9N1OR9nEjci-uqF_rCQ,1393
|
|
29
|
+
lockstep/probes.py,sha256=MtUHZJiAVBFBQqVxoUlGEWpzbx93n7dtSPRltC64tVA,3260
|
|
30
|
+
lockstep/proofs.py,sha256=zyJVZJfJXmB7fAgqWdssrUtHPoh4HeqQwNNr8u2XpY8,13212
|
|
31
|
+
lockstep/resources.py,sha256=9uaPqa7rQtL1Kid473-bCKfJpeRW4ThaUSMF51Lp2aM,4677
|
|
32
|
+
lockstep/shadow_index.py,sha256=z626y8BNBIklAt7WFk7Ix-918-SfgFy67qRY8bVyukA,2723
|
|
33
|
+
lockstep/spec.py,sha256=h124-0IVxX23Yjj60Cnm5RVsRLUDdhlF7Wjr8lPNGj4,918
|
|
34
|
+
lockstep/stage_runner.py,sha256=Wu84Wu1JlELSxKuOiVw1IqGWpx9C8qQFjiNcQ8Op3As,1795
|
|
35
|
+
lockstep/storage.py,sha256=Iz74tWn6Mv6C_FjtI4lTOYxL8mXsWjzFIYK8YCc64Z0,6905
|
|
36
|
+
lockstep/store.py,sha256=MoXCDkKTTVGBFFg_ilEmPNK4DzmqPB9jZQWzqdL_9Xg,17071
|
|
37
|
+
lockstep/tags.py,sha256=x7vzm4FCE_1XF8XVwtScoib4e6ozP7fCWs0TxsGf-Vo,2837
|
|
38
|
+
lockstep/commands/__init__.py,sha256=ELPjq-vnW-KlU8JbmPGyoXlM3fHXJyp8dKIBYSLRT4g,403
|
|
39
|
+
lockstep/commands/audit.py,sha256=WNS5CKFw3uAYz6XVMd55XSLCkvmScgODNAMfd2ITBRk,2269
|
|
40
|
+
lockstep/commands/automation.py,sha256=yqWTo8id3FRBdUdEGyesbZjOqySk4hJUH-ITFEgN-dU,4913
|
|
41
|
+
lockstep/commands/build.py,sha256=LTQXLlc8mqnPxolpZ-81Khzw5kpXJxfLIctaZF_3ESY,2699
|
|
42
|
+
lockstep/commands/cache.py,sha256=4OXCGrL1TbGMBkCbHtDy4iBs_zTUl6PTlpgMmOHrX9w,2453
|
|
43
|
+
lockstep/commands/check.py,sha256=jtrG9JoTWW08xTZix7-uRPuqGM5AjBS3PonHd28DXYo,4261
|
|
44
|
+
lockstep/commands/claims.py,sha256=BLBN5wH_BKmstD6pX_aTzdEEyCQwKSGYk8B9z9k4JMA,3962
|
|
45
|
+
lockstep/commands/close.py,sha256=VvulasoNJu5fafYdUei8gw5quSx3_5qyIQ0TV_LBgdk,10617
|
|
46
|
+
lockstep/commands/doctor.py,sha256=TzmOxjXeEesbc4g9K2r71LL9bw137vwpR3UOh53qAk8,4902
|
|
47
|
+
lockstep/commands/extract.py,sha256=TtXMzNyX8OxqfVkfcjFig-R1gwcFubI2_YRUVyaZChQ,8456
|
|
48
|
+
lockstep/commands/falsify.py,sha256=wZDkDUiZIL3uwPSUDMbWAoOQAwaKxWA3JSaDKv61MQw,5557
|
|
49
|
+
lockstep/commands/index.py,sha256=un_w696UgxQPBdauvzn_NDiBpdgZCaPZSD8DW0HN4_o,831
|
|
50
|
+
lockstep/commands/jobs.py,sha256=tAOTY5mH1T1lCJHMZWf4tlhDnFyEy0IsFYJr_mAQlcQ,10797
|
|
51
|
+
lockstep/commands/layers.py,sha256=_qBX2iRFdtDZ4Q7Kn-Gkfbe5k5BVl0FdsN_o3tArYog,2297
|
|
52
|
+
lockstep/commands/library.py,sha256=Z2CiXTkoRvNIdzHNOqLDBZyw1Hx-0zFeIhPvuTQhZFg,2141
|
|
53
|
+
lockstep/commands/lock.py,sha256=YNCSn2xCBAZZokSEJGp0cuD8kW0wl07-GVBvn8h2Zt8,2844
|
|
54
|
+
lockstep/commands/log.py,sha256=1Z-55bfoNV7m1H4WWKBmS2rvuypTe7isKA6hGbi5JWw,6390
|
|
55
|
+
lockstep/commands/node.py,sha256=DprWQUtnvomd2Sc3Si3IeDOxqPvTYxpoXHa4yhl4Z6I,21592
|
|
56
|
+
lockstep/commands/note.py,sha256=6HO5P0e2i4JCiZCSaq6V2JdcCIqZeJrIvDTYgKxgEVg,4428
|
|
57
|
+
lockstep/commands/probe.py,sha256=kAHB5ML5du41rpSjxQ4PpxZPEw5oND1zpSEq0jfKqmM,731
|
|
58
|
+
lockstep/commands/proof.py,sha256=kgQh6AHd8_pjd2F461WmzzTaWpIa4HhgEjHLruVStGA,2506
|
|
59
|
+
lockstep/commands/ready.py,sha256=S4NkDvKLBrWdCjvqMIM-JP_R-5rj9SzLRNMEzs-3L5w,1596
|
|
60
|
+
lockstep/commands/rules.py,sha256=UpbPbINqRqK7fgIcSzbv_bkHHlwzCvDXhi6tzE71cug,2393
|
|
61
|
+
lockstep/commands/search.py,sha256=1z1zp8eJDgfVLpEhaIp9256UzpdIWmuhkfTdPXAZPaQ,1818
|
|
62
|
+
lockstep/commands/status.py,sha256=GOSNiqO7EKNkxLh2cN0Ifq-uHOx3SsnwY5JuaDXNSCs,7882
|
|
63
|
+
lockstep/data/AuditCandidate.lean,sha256=V7aXWsYgsiQA3U2T0cqgJsjkkS_dR3M3hgMGd5latlo,730
|
|
64
|
+
lockstep/data/CacheArtifacts.lean,sha256=hYOp3CJGrhMXagKagOEltwFrlcuF1CXW2iALJDJD_oA,1302
|
|
65
|
+
lockstep/data/Extract.lean.tmpl,sha256=HB68q0ZKqXWY2VYpmLnMdlz6dt_NzEBoAT1lqSJnv3o,16183
|
|
66
|
+
lockstep/data/node.lean.tmpl,sha256=Q_aIfa8-3BPqP1hvdWRMXybJMcgCbsgwL0_KMq3iwjY,140
|
|
67
|
+
lean_lockstep-0.1.0.dist-info/METADATA,sha256=25D-YVzjDILAv801PfdvkpI55_rM1UqGFa6qllrjt3M,12357
|
|
68
|
+
lean_lockstep-0.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
69
|
+
lean_lockstep-0.1.0.dist-info/entry_points.txt,sha256=vBNlVbHFrmlj8L6S_bUxPGfRK26ZmhBog90pMkSHkjw,87
|
|
70
|
+
lean_lockstep-0.1.0.dist-info/top_level.txt,sha256=QNoTwkeoY08NJpMS_9r_I9v1_ILr-ubzRM-tL-GAiAM,9
|
|
71
|
+
lean_lockstep-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Gavin Litchfield
|
|
4
|
+
Copyright (c) 2026 Matt Pocock (Wayfinder-derived portions)
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
lockstep
|
lockstep/__init__.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""lockstep: a blueprint harness whose project state is derived from the compiled Lean environment.
|
|
2
|
+
|
|
3
|
+
Nothing in this package may name a project-specific module, theorem, or path;
|
|
4
|
+
all of that comes from ``harness/config.toml`` in the project root.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
__version__ = "0.1.0"
|
|
10
|
+
|
|
11
|
+
# Lean templates and drivers shipped with the package (package data, so a wheel install works)
|
|
12
|
+
DATA = Path(__file__).resolve().parent / "data"
|
|
13
|
+
|
|
14
|
+
EXIT_OK = 0
|
|
15
|
+
EXIT_CHECK_FAILED = 1
|
|
16
|
+
EXIT_USAGE = 2
|
|
17
|
+
EXIT_LEAN = 3
|
lockstep/__main__.py
ADDED
lockstep/allowlist.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Axiom allowlist: which non-standard axioms may reach which declarations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import fnmatch
|
|
6
|
+
import json
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def read_allowlist(path: Path) -> list[dict]:
|
|
11
|
+
if not path.exists():
|
|
12
|
+
return []
|
|
13
|
+
data = json.loads(path.read_text() or "[]")
|
|
14
|
+
return data if isinstance(data, list) else []
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def write_allowlist(path: Path, entries: list[dict]) -> None:
|
|
18
|
+
path.write_text(json.dumps(entries, indent=2, ensure_ascii=False) + "\n")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def uncovered(entries: list[dict], name: str, axioms: list[str], standard: list[str]) -> list[str]:
|
|
22
|
+
"""Axioms of ``name`` (beyond the standard set) not covered by any allowlist entry."""
|
|
23
|
+
out = []
|
|
24
|
+
for ax in axioms:
|
|
25
|
+
if ax in standard:
|
|
26
|
+
continue
|
|
27
|
+
ok = False
|
|
28
|
+
for e in entries:
|
|
29
|
+
pat = str(e.get("axiom", ""))
|
|
30
|
+
# Lean 4.29 gives every `native_decide` its own auxiliary axiom
|
|
31
|
+
# (`<decl>._native.native_decide.ax_1_1`), so entries may be globs.
|
|
32
|
+
if pat != ax and not fnmatch.fnmatchcase(ax, pat):
|
|
33
|
+
continue
|
|
34
|
+
reaches = e.get("reaches", [])
|
|
35
|
+
if "*" in reaches or name in reaches:
|
|
36
|
+
ok = True
|
|
37
|
+
break
|
|
38
|
+
if not ok:
|
|
39
|
+
out.append(ax)
|
|
40
|
+
return out
|