lean-runtime 2.0.9__tar.gz → 2.1.1__tar.gz

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.
Files changed (152) hide show
  1. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/CHANGELOG.md +63 -1
  2. {lean_runtime-2.0.9/lean_runtime.egg-info → lean_runtime-2.1.1}/PKG-INFO +19 -1
  3. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/README.md +18 -0
  4. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/docs/cli.md +36 -3
  5. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/docs/development.md +23 -0
  6. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/docs/getting-started.md +12 -2
  7. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/docs/python-api.md +23 -2
  8. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/docs/standalone-files.md +25 -4
  9. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/docs/trust-and-limitations.md +1 -1
  10. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/cli.py +34 -1
  11. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/diagnostics.py +22 -0
  12. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/discovery/__init__.py +2 -1
  13. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/discovery/engine.py +103 -84
  14. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/discovery/policy.py +11 -1
  15. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/discovery/probe.py +46 -6
  16. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/environments.py +20 -5
  17. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/facade.py +8 -3
  18. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/models.py +48 -0
  19. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/oci.py +27 -5
  20. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/references.py +14 -0
  21. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/run_cli.py +55 -9
  22. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/runtime.py +37 -6
  23. lean_runtime-2.1.1/lean_runtime/toolchain_slim.py +209 -0
  24. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/toolchains.py +127 -3
  25. {lean_runtime-2.0.9 → lean_runtime-2.1.1/lean_runtime.egg-info}/PKG-INFO +19 -1
  26. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime.egg-info/SOURCES.txt +5 -0
  27. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/pyproject.toml +1 -1
  28. lean_runtime-2.1.1/scripts/announcement_gate.py +188 -0
  29. lean_runtime-2.1.1/scripts/registry_preflight.py +156 -0
  30. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/discovery/test_engine.py +143 -8
  31. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_bundles.py +51 -0
  32. lean_runtime-2.1.1/tests/test_diagnostics.py +36 -0
  33. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_facade.py +17 -0
  34. lean_runtime-2.1.1/tests/test_models.py +61 -0
  35. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_references.py +16 -0
  36. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_run_cli.py +36 -0
  37. lean_runtime-2.1.1/tests/test_toolchain_slim.py +125 -0
  38. lean_runtime-2.0.9/tests/test_diagnostics.py +0 -18
  39. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/LICENSE +0 -0
  40. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/MANIFEST.in +0 -0
  41. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/catalog/environments.toml +0 -0
  42. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/catalog/locks/core-v4.32.2.lock.json +0 -0
  43. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/catalog/locks/mathlib-v4.30.0.lock.json +0 -0
  44. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/catalog/locks/mathlib-v4.31.0.lock.json +0 -0
  45. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/catalog/locks/mathlib-v4.32.2.lock.json +0 -0
  46. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/compatibility/README.md +0 -0
  47. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/compatibility/mathlib-4.32.2.json +0 -0
  48. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/compatibility/mathlib-4.32.2.toml +0 -0
  49. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/docs/architecture.md +0 -0
  50. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/docs/captures.md +0 -0
  51. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/docs/case-study-v1.md +0 -0
  52. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/docs/environments.md +0 -0
  53. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/docs/index.md +0 -0
  54. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/docs/local-projects.md +0 -0
  55. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/docs/portable-copies.md +0 -0
  56. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/docs/ready-programs.md +0 -0
  57. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/docs/v1-precision.md +0 -0
  58. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/examples/mathlib.toml +0 -0
  59. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/__init__.py +0 -0
  60. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/__main__.py +0 -0
  61. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/_git.py +0 -0
  62. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/_paths.py +0 -0
  63. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/backends.py +0 -0
  64. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/bundles.py +0 -0
  65. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/comparison.py +0 -0
  66. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/decisions.py +0 -0
  67. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/discovery/analyzer.py +0 -0
  68. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/discovery/api.py +0 -0
  69. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/discovery/candidate.py +0 -0
  70. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/discovery/catalog.py +0 -0
  71. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/discovery/catalog_build.py +0 -0
  72. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/discovery/catalog_cli.py +0 -0
  73. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/discovery/catalog_manifest.py +0 -0
  74. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/discovery/data/catalog.json +0 -0
  75. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/discovery/defaults.py +0 -0
  76. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/discovery/errors.py +0 -0
  77. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/discovery/module_inventory.py +0 -0
  78. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/discovery/planner.py +0 -0
  79. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/discovery/py.typed +0 -0
  80. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/discovery/result.py +0 -0
  81. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/discovery/schema_resources.py +0 -0
  82. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/discovery/schemas/catalog-v1.schema.json +0 -0
  83. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/discovery/schemas/plan-v1.schema.json +0 -0
  84. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/discovery/schemas/result-v1.schema.json +0 -0
  85. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/errors.py +0 -0
  86. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/events.py +0 -0
  87. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/frontmatter.py +0 -0
  88. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/health.py +0 -0
  89. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/lake.py +0 -0
  90. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/lockfiles.py +0 -0
  91. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/locking.py +0 -0
  92. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/matrix.py +0 -0
  93. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/policies.py +0 -0
  94. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/profiling.py +0 -0
  95. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/programs.py +0 -0
  96. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/projects.py +0 -0
  97. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/publisher_verification.py +0 -0
  98. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/py.typed +0 -0
  99. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/resolver.py +0 -0
  100. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/schema_resources.py +0 -0
  101. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/serialization.py +0 -0
  102. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/specs.py +0 -0
  103. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/store.py +0 -0
  104. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/timings.py +0 -0
  105. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/verification.py +0 -0
  106. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime/wire.py +0 -0
  107. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime.egg-info/dependency_links.txt +0 -0
  108. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime.egg-info/entry_points.txt +0 -0
  109. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime.egg-info/requires.txt +0 -0
  110. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/lean_runtime.egg-info/top_level.txt +0 -0
  111. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/mkdocs.yml +0 -0
  112. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/schemas/cleanup-v1.schema.json +0 -0
  113. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/schemas/comparison-v1.schema.json +0 -0
  114. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/schemas/execution-v1.schema.json +0 -0
  115. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/schemas/inspect-v1.schema.json +0 -0
  116. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/schemas/matrix-v1.schema.json +0 -0
  117. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/schemas/profile-v1.schema.json +0 -0
  118. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/schemas/verify-v1.schema.json +0 -0
  119. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/scripts/run_compatibility.py +0 -0
  120. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/scripts/run_v1_case_study.py +0 -0
  121. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/scripts/smoke_wheel.py +0 -0
  122. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/setup.cfg +0 -0
  123. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/conftest.py +0 -0
  124. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/discovery/e2e/test_real_discovery.py +0 -0
  125. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/discovery/test_analyzer.py +0 -0
  126. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/discovery/test_catalog.py +0 -0
  127. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/discovery/test_catalog_build.py +0 -0
  128. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/discovery/test_discovery_schema_resources.py +0 -0
  129. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/discovery/test_planner.py +0 -0
  130. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/discovery/test_policy.py +0 -0
  131. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_backend.py +0 -0
  132. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_cli.py +0 -0
  133. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_environment_integration.py +0 -0
  134. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_events_health.py +0 -0
  135. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_frontmatter.py +0 -0
  136. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_git.py +0 -0
  137. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_interactive.py +0 -0
  138. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_lockfiles.py +0 -0
  139. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_multifile.py +0 -0
  140. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_paths.py +0 -0
  141. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_prebuilt_policy.py +0 -0
  142. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_programs.py +0 -0
  143. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_projects.py +0 -0
  144. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_runtime.py +0 -0
  145. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_schema_resources.py +0 -0
  146. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_schemas.py +0 -0
  147. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_signatures.py +0 -0
  148. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_specs.py +0 -0
  149. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_store.py +0 -0
  150. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_toolchains.py +0 -0
  151. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_v1_precision.py +0 -0
  152. {lean_runtime-2.0.9 → lean_runtime-2.1.1}/tests/test_verification_inventory.py +0 -0
@@ -1,6 +1,68 @@
1
1
  # Changelog
2
2
 
3
- ## Unreleased
3
+ ## 2.1.1 - 2026-08-12
4
+
5
+ - The discovery search budget now gates starting additional candidates and
6
+ no longer kills an in-flight authoritative check, which is bounded by its
7
+ own per-candidate timeout. A slow machine's first Mathlib check can outlive
8
+ the remaining search budget legitimately.
9
+ - OCI blob downloads keep partials on truncated transfers and resume with a
10
+ Range request, retry transport errors mid-stream, and attempt four times.
11
+ - Add `build-and-publish --accelerate`: hydrate artifacts from known package
12
+ caches (Mathlib's `lake exe cache get`) for locked packages that carry no
13
+ artifact command of their own. Acceleration is keyed by exact canonical
14
+ package URL, never changes the lock identity, is recorded in the hydration
15
+ report, and the built environment is still probe-verified before
16
+ publication. The public-cache workflow uses it, turning multi-hour Mathlib
17
+ source builds into minutes.
18
+ - Add a fail-closed release toolkit: `scripts/registry_preflight.py` verifies
19
+ every bundled catalog entry is anonymously downloadable, and the
20
+ announcement-gate workflow runs the advertised PyPI journeys on clean
21
+ unauthenticated Linux and macOS runners (dispatch + daily canary).
22
+ - `lean-run` now warns loudly when a downloadable environment is unavailable
23
+ and states that source builds can take 30+ minutes, with a
24
+ `--no-source-build` hint, instead of falling back silently.
25
+
26
+ ## 2.1.0 - 2026-08-11
27
+
28
+ - Add `lean-runtime toolchain-slim` and
29
+ `ToolchainManager.materialize_slim()`: a verified check-profile toolchain
30
+ copy that drops editor indexes, static libraries, bundled LLVM/clang, and
31
+ sources (about 2.6 GB → 2.1 GB for v4.32.2 once `--prune-original` removes
32
+ the full Elan copy). Materialization hardlinks files, verification runs a
33
+ capability corpus with the slim copy's own `lean`, and checking transparently
34
+ routes through the slim copy when the full toolchain is absent. Lean v4.32
35
+ requires all `.olean` facets and per-module IR for ordinary elaboration, so
36
+ those remain; source builds of new environments still need the full
37
+ toolchain.
38
+
39
+ - Exempt environment acquisition (downloads, toolchain installs, source
40
+ builds) from the discovery search budget: a slow first-time download can no
41
+ longer expire an otherwise healthy search. Acquisition is bounded separately
42
+ by `DiscoveryPolicy.acquisition_timeout_seconds` and `lean-run
43
+ --acquire-timeout`; `--search-timeout` and `--check-timeout` name the
44
+ remaining budgets, with `--discovery-timeout` and `--timeout` kept as
45
+ deprecated aliases.
46
+ - Split the candidate probe into `acquire` and `check` phases and announce
47
+ first-time toolchain installation through a `toolchain.install_started`
48
+ event and a `lean-run` progress line. `CandidateProbe` implementers must now
49
+ provide both methods; `acquire` returns the newly exported
50
+ `AcquiredCandidate`, and its acquisition budget is forwarded to
51
+ `open_exact(build_timeout=...)` so `--acquire-timeout` governs source
52
+ builds.
53
+ - Add `ExecutionResult.errors`, `.warnings`, and `.first_error` severity views,
54
+ a `Diagnostic.location` property, and compact `repr` output for both types.
55
+ `to_dict()` payloads are unchanged.
56
+ - Report structured diagnostics against the caller's logical input names
57
+ (for example `Main.lean`) instead of staged sandbox paths, and rewrite the
58
+ staged entrypoint path back to the user's file in `lean-run` text output.
59
+ Raw `stdout`/`stderr` remain authoritative and unmodified in results.
60
+ - Add `lean.setup(toolchain="v4.32.2")` and `Runtime.open_toolchain()` for
61
+ reusable core-only environments; the empty-`deps` error now teaches the
62
+ toolchain form.
63
+ - Accept an exact lock path anywhere `lean-runtime profile` previously
64
+ required an environment name (`Runtime.subject_environment`); a path that
65
+ exists on disk always wins over an environment name.
4
66
 
5
67
  ## 2.0.9 - 2026-08-10
6
68
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lean-runtime
3
- Version: 2.0.9
3
+ Version: 2.1.1
4
4
  Summary: Run Lean 4 proofs from Python or standalone files
5
5
  Author: Alejandro Radisic
6
6
  License-Expression: Apache-2.0
@@ -131,6 +131,24 @@ result = env.check(
131
131
  result.raise_for_error()
132
132
  ```
133
133
 
134
+ Rejected proofs carry parsed diagnostics:
135
+
136
+ ```python
137
+ result = env.check(broken_proof)
138
+
139
+ for error in result.errors:
140
+ print(error.file, error.line, error.message)
141
+
142
+ result.raise_for_error() # raises LeanCheckError with the same detail
143
+ ```
144
+
145
+ Core-only work does not need a dependency:
146
+
147
+ ```python
148
+ core = lean.setup(toolchain="v4.32.2")
149
+ core.check("example : 2 + 2 = 4 := rfl").raise_for_error()
150
+ ```
151
+
134
152
  Batch and asyncio APIs reuse that prepared environment:
135
153
 
136
154
  ```python
@@ -96,6 +96,24 @@ result = env.check(
96
96
  result.raise_for_error()
97
97
  ```
98
98
 
99
+ Rejected proofs carry parsed diagnostics:
100
+
101
+ ```python
102
+ result = env.check(broken_proof)
103
+
104
+ for error in result.errors:
105
+ print(error.file, error.line, error.message)
106
+
107
+ result.raise_for_error() # raises LeanCheckError with the same detail
108
+ ```
109
+
110
+ Core-only work does not need a dependency:
111
+
112
+ ```python
113
+ core = lean.setup(toolchain="v4.32.2")
114
+ core.check("example : 2 + 2 = 4 := rfl").raise_for_error()
115
+ ```
116
+
99
117
  Batch and asyncio APIs reuse that prepared environment:
100
118
 
101
119
  ```python
@@ -18,9 +18,14 @@ lean-run Main.lean --offline
18
18
 
19
19
  Without explicit context or a pinned Lake project, `lean-run` automatically
20
20
  searches its bundled exact-environment catalog. Use `--lock-out` to retain the
21
- successful lock, `--no-discover` to require explicit context,
22
- `--catalog PATH` to override the catalog, and `--max-candidates` plus
23
- `--discovery-timeout` to bound search. See
21
+ successful lock, `--no-discover` to require explicit context, and
22
+ `--catalog PATH` to override the catalog. Three budgets bound the work:
23
+ `--search-timeout` covers ranking and compiler probes, `--check-timeout`
24
+ covers each Lean invocation, and `--acquire-timeout` independently bounds
25
+ downloading, installing, or building one candidate environment, so a slow
26
+ first-time download cannot expire the search. `--discovery-timeout` and
27
+ `--timeout` remain as deprecated aliases of `--search-timeout` and
28
+ `--check-timeout`. See
24
29
  [Standalone Lean files](standalone-files.md) for routing and policy details.
25
30
 
26
31
  ## `lean-runtime`
@@ -79,6 +84,34 @@ identity, package Git trees, computer compatibility, and Lean probe before
79
84
  making the environment available. See [Portable copies and environment
80
85
  libraries](portable-copies.md) for its trust boundary.
81
86
 
87
+ ## Slim toolchains
88
+
89
+ The official Lean toolchain is roughly 2.6 GB installed. Proof checking does
90
+ not need all of it: editor indexes, static libraries, the bundled LLVM/clang,
91
+ and toolchain sources are only used by editors and native compilation.
92
+
93
+ ```bash
94
+ lean-runtime toolchain-slim v4.32.2
95
+ lean-runtime toolchain-slim v4.32.2 --prune-original
96
+ ```
97
+
98
+ `toolchain-slim` materializes a separate check-profile copy by hardlinking the
99
+ kept files (near-zero extra disk), then verifies it against a capability
100
+ corpus — elaboration, core tactics, `decide`, `#eval`, metaprogramming, and
101
+ `Std` imports — using the slim copy's own `lean`. A copy that fails any probe
102
+ is removed and reported.
103
+
104
+ `--prune-original` uninstalls the full Elan toolchain after verification,
105
+ reducing the v4.32.2 footprint from about 2.6 GB to about 2.1 GB. All checking
106
+ continues through the slim copy. Lean v4.32 loads every `.olean` facet and
107
+ per-module IR during ordinary elaboration, so those artifact classes must
108
+ stay; larger reductions require upstream facet-loading changes.
109
+
110
+ After pruning, source builds of *new* environments and native compilation
111
+ need the full toolchain again; reinstall it with `lean-runtime install`.
112
+ Downloads are unaffected: first-time installation still transfers the full
113
+ official release before a slim copy can be derived from it.
114
+
82
115
  ## Replay
83
116
 
84
117
  ```bash
@@ -78,3 +78,26 @@ a normal publisher and creates the PyPI project.
78
78
  PyPI does not permit replacing files for an already published version. If a
79
79
  release needs a correction, increment the version rather than recreating the
80
80
  tag.
81
+
82
+ ## Release and announcement protocol
83
+
84
+ Catalog entries are public claims that a prebuilt environment is
85
+ downloadable. The protocol below makes those claims fail-closed:
86
+
87
+ 1. Publish downloadable environments for every catalog entry and platform
88
+ (`public-cache.yml`) **before** shipping a wheel that references them, and
89
+ make the GHCR package publicly pullable.
90
+ 2. Run `python scripts/registry_preflight.py` — it verifies, anonymously,
91
+ that every catalog lock resolves to an index, platform manifests, and
92
+ readable blobs. CI-cheap; run it on every release.
93
+ 3. After publishing to PyPI, dispatch the **Announcement gate** workflow
94
+ (`announcement-gate.yml`). It installs from PyPI on clean unauthenticated
95
+ Linux and macOS runners and runs the advertised journeys from
96
+ `acceptance/`: a cold check with `--no-source-build` (fail-closed: a
97
+ broken registry fails in seconds instead of hiding behind a source
98
+ build), a warm re-check, a failing proof with logical diagnostic paths, a
99
+ lock round-trip, and the Python batch API. Release titles use `vX.Y.Z`,
100
+ matching the tag.
101
+ 4. Announce only after the gate is green. The same workflow runs daily as a
102
+ canary: registry permissions and docs deployments can break without any
103
+ code change.
@@ -75,17 +75,27 @@ result.raise_for_error()
75
75
  `setup()` resolves and ensures the environment once. Further checks reuse that
76
76
  handle, including batch and asynchronous calls.
77
77
 
78
- The same entry point opens local projects, exact locks, and previously named
79
- environments:
78
+ The same entry point opens local projects, exact locks, previously named
79
+ environments, and core-only toolchains:
80
80
 
81
81
  ```python
82
82
  project = lean.setup(project="./my-project")
83
83
  locked = lean.setup(lock="environment.lock.json")
84
84
  existing = lean.setup(environment="research-stack")
85
+ core = lean.setup(toolchain="v4.32.2")
85
86
  ```
86
87
 
87
88
  Exactly one context must be supplied.
88
89
 
90
+ Rejected checks expose parsed diagnostics directly, with `file` naming your
91
+ logical input:
92
+
93
+ ```python
94
+ result = environment.check(broken_proof)
95
+ for error in result.errors:
96
+ print(error.file, error.line, error.message)
97
+ ```
98
+
89
99
  ## Lock for CI
90
100
 
91
101
  Resolve a friendly dependency declaration and retain its exact graph:
@@ -12,9 +12,13 @@ environment = lean.setup(["mathlib@v4.32.2"])
12
12
  project = lean.setup(project="./my-project")
13
13
  locked = lean.setup(lock="environment.lock.json")
14
14
  existing = lean.setup(environment="research-stack")
15
+ core = lean.setup(toolchain="v4.32.2")
15
16
  ```
16
17
 
17
- Exactly one of `deps`, `project`, `lock`, or `environment` is required. The
18
+ Exactly one of `deps`, `project`, `lock`, `environment`, or a bare
19
+ `toolchain` is required. A bare `toolchain` prepares the core-only
20
+ environment for that Lean release; combined with `deps` or `project` it
21
+ remains an override. The
18
22
  default `Runtime` is created lazily on the first operation; importing
19
23
  `lean_runtime` has no filesystem or network side effects. Supply
20
24
  `runtime=Runtime(...)` to any façade function for explicit configuration.
@@ -53,7 +57,24 @@ runs. Planning metadata narrows candidates but never asserts compatibility.
53
57
 
54
58
  ## Results
55
59
 
56
- Results remain inspectable values. Scripts that prefer exceptions can use:
60
+ Results remain inspectable values. Failed checks expose their parsed
61
+ diagnostics directly:
62
+
63
+ ```python
64
+ result = environment.check(source)
65
+
66
+ for error in result.errors:
67
+ print(error.file, error.line, error.message)
68
+
69
+ if result.first_error is not None:
70
+ print(result.first_error.location)
71
+ ```
72
+
73
+ `errors` and `warnings` are severity-filtered views of `diagnostics`;
74
+ `first_error` returns the first error or `None`. Diagnostic `file` values name
75
+ the caller's logical input (for example `Main.lean`); raw compiler output
76
+ remains authoritative on `stdout`/`stderr` and may contain physical sandbox
77
+ paths. Scripts that prefer exceptions can use:
57
78
 
58
79
  ```python
59
80
  result.raise_for_error()
@@ -15,9 +15,21 @@ environment is compatible. Runtime materializes each bounded candidate and
15
15
  Lean authoritatively checks the source before discovery can succeed.
16
16
 
17
17
  The bundled bootstrap catalog contains core Lean v4.32.2 plus exact Mathlib
18
- v4.32.2, v4.31.0, and v4.30.0 locks. `--catalog PATH` selects another validated catalog,
19
- `--max-candidates` and `--discovery-timeout` bound the search, and
20
- `--no-discover` restores strict explicit-context behavior.
18
+ v4.32.2, v4.31.0, and v4.30.0 locks. `--catalog PATH` selects another validated
19
+ catalog and `--no-discover` restores strict explicit-context behavior.
20
+
21
+ Three budgets bound the work independently:
22
+
23
+ - `--max-candidates` and `--search-timeout` bound the search itself: ranking
24
+ plus compiler probes.
25
+ - `--check-timeout` bounds each Lean invocation.
26
+ - `--acquire-timeout` bounds downloading, installing, or building one
27
+ candidate environment, including its source build. Acquisition never
28
+ consumes the search budget, so a slow first-time toolchain download cannot
29
+ expire an otherwise healthy search.
30
+
31
+ `--discovery-timeout` and `--timeout` remain as deprecated aliases of
32
+ `--search-timeout` and `--check-timeout`.
21
33
 
22
34
  ## Frontmatter format
23
35
 
@@ -53,12 +65,21 @@ environments only.
53
65
 
54
66
  ## Output
55
67
 
56
- Human output is concise:
68
+ Human output is concise, and error locations name the file you passed rather
69
+ than an internal staging path:
57
70
 
58
71
  ```text
59
72
  ✓ Main.lean accepted in 0.42s
60
73
  ```
61
74
 
75
+ ```text
76
+ proofs/Bad.lean:1:23: error: Type mismatch
77
+ ✗ proofs/Bad.lean rejected in 0.35s
78
+ ```
79
+
80
+ Only the checked file's own path is rewritten; dependency paths in compiler
81
+ output are shown as Lean printed them.
82
+
62
83
  Cold operations report meaningful dependency, cache, and build phases on
63
84
  stderr. `--quiet` suppresses progress and `--json` emits the complete structured
64
85
  `ExecutionResult` without progress messages.
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Trusted local execution
4
4
 
5
- Lean Runtime 0.5 orchestrates trusted code. It is not a sandbox.
5
+ Lean Runtime orchestrates trusted code. It is not a sandbox.
6
6
 
7
7
  Lake configurations are executable, dependencies may contain native code and
8
8
  custom build targets, and explicit artifact commands run subprocesses. Lockfile
@@ -153,6 +153,13 @@ def parser() -> argparse.ArgumentParser:
153
153
  action="store_true",
154
154
  help="publish blobs and platform manifest without updating the lock index",
155
155
  )
156
+ push.add_argument(
157
+ "--accelerate",
158
+ action="store_true",
159
+ help="hydrate artifacts from known package caches (e.g. Mathlib's) for locked "
160
+ "packages without an artifact command; the lock identity is unchanged and the "
161
+ "built environment is still probe-verified before publication",
162
+ )
156
163
  push.add_argument("--sign", action="store_true", help="sign the published lock index")
157
164
  push.add_argument(
158
165
  "--attest", action="store_true", help="publish a signed source/probe attestation"
@@ -271,8 +278,21 @@ def parser() -> argparse.ArgumentParser:
271
278
  diff.add_argument("right")
272
279
  diff.add_argument("--json", action="store_true")
273
280
 
281
+ toolchain_slim = commands.add_parser(
282
+ "toolchain-slim",
283
+ help="materialize a verified slim check-profile copy of a toolchain",
284
+ )
285
+ toolchain_slim.add_argument("toolchain", help="Lean toolchain, e.g. v4.32.2")
286
+ toolchain_slim.add_argument(
287
+ "--prune-original",
288
+ action="store_true",
289
+ help="uninstall the full Elan toolchain after verification; checking keeps "
290
+ "working through the slim copy, but source builds of new environments and "
291
+ "native compilation need the full toolchain again",
292
+ )
293
+
274
294
  profile = commands.add_parser("profile", help="measure repeated checks in one environment")
275
- profile.add_argument("environment")
295
+ profile.add_argument("environment", help="environment name or exact lock path")
276
296
  profile.add_argument("file", type=Path)
277
297
  profile.add_argument("--warmup", type=int, default=1)
278
298
  profile.add_argument("--repeat", type=int, default=5)
@@ -378,6 +398,7 @@ def main(argv: list[str] | None = None) -> int:
378
398
  EnvironmentLock.load(args.lock),
379
399
  name=args.name,
380
400
  build_timeout=args.timeout,
401
+ accelerate=args.accelerate,
381
402
  )
382
403
  _json(
383
404
  runtime.publish_environment(
@@ -519,6 +540,18 @@ def main(argv: list[str] | None = None) -> int:
519
540
  if args.command == "storage":
520
541
  _json(runtime.store_status().to_dict())
521
542
  return 0
543
+ if args.command == "toolchain-slim":
544
+ manifest = runtime.toolchains.materialize_slim(args.toolchain)
545
+ if args.prune_original:
546
+ runtime.toolchains.prune_original(args.toolchain)
547
+ _json(
548
+ {
549
+ **manifest.to_dict(),
550
+ "path": str(runtime.toolchains.slim_path(args.toolchain)),
551
+ "pruned_original": args.prune_original,
552
+ }
553
+ )
554
+ return 0
522
555
  if args.command == "doctor":
523
556
  doctor_report = runtime.doctor()
524
557
  _json(doctor_report.to_dict())
@@ -3,6 +3,8 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import re
6
+ from collections.abc import Mapping
7
+ from dataclasses import replace
6
8
 
7
9
  from .models import Diagnostic, Severity
8
10
 
@@ -46,6 +48,26 @@ def parse_diagnostics(output: str) -> tuple[Diagnostic, ...]:
46
48
  return tuple(diagnostics)
47
49
 
48
50
 
51
+ def map_diagnostic_paths(
52
+ diagnostics: tuple[Diagnostic, ...],
53
+ path_map: Mapping[str, str] | None,
54
+ ) -> tuple[Diagnostic, ...]:
55
+ """Rewrite staged physical paths to the caller's logical input names.
56
+
57
+ Only exact staged-file matches are rewritten; package files may
58
+ legitimately share basenames, and raw compiler output remains authoritative
59
+ on the execution result.
60
+ """
61
+ if not path_map:
62
+ return diagnostics
63
+ return tuple(
64
+ replace(item, file=path_map[item.file])
65
+ if item.file is not None and item.file in path_map
66
+ else item
67
+ for item in diagnostics
68
+ )
69
+
70
+
49
71
  def error_diagnostic(message: str) -> Diagnostic:
50
72
  """Create an infrastructure diagnostic."""
51
73
  severity: Severity = "error"
@@ -21,7 +21,7 @@ from .defaults import DEFAULT_CATALOG_PATH, default_catalog
21
21
  from .errors import CatalogError, DiscoveryError, PolicyError
22
22
  from .planner import Planner
23
23
  from .policy import DiscoveryPolicy
24
- from .probe import CandidateProbe, LeanRuntimeProbe, ProbeOutcome
24
+ from .probe import AcquiredCandidate, CandidateProbe, LeanRuntimeProbe, ProbeOutcome
25
25
  from .result import (
26
26
  RESULT_SCHEMA,
27
27
  CandidateAttempt,
@@ -39,6 +39,7 @@ __all__ = [
39
39
  "AvailabilityObservation",
40
40
  "Candidate",
41
41
  "CandidateAttempt",
42
+ "AcquiredCandidate",
42
43
  "CandidateProbe",
43
44
  "CandidateReason",
44
45
  "Catalog",