lean-runtime 3.0.1__tar.gz → 3.0.2__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 (188) hide show
  1. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/CHANGELOG.md +8 -0
  2. {lean_runtime-3.0.1/lean_runtime.egg-info → lean_runtime-3.0.2}/PKG-INFO +1 -1
  3. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/toolchains.py +13 -6
  4. {lean_runtime-3.0.1 → lean_runtime-3.0.2/lean_runtime.egg-info}/PKG-INFO +1 -1
  5. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/pyproject.toml +1 -1
  6. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_toolchain_slim.py +78 -0
  7. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/LICENSE +0 -0
  8. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/MANIFEST.in +0 -0
  9. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/README.md +0 -0
  10. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/catalog/environments.toml +0 -0
  11. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/catalog/locks/core-v4.32.2.lock.json +0 -0
  12. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/catalog/locks/leancert-v4.30.0.5.lock.json +0 -0
  13. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/catalog/locks/leancert-v4.31.0.lock.json +0 -0
  14. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/catalog/locks/leancert-v4.32.2.4.lock.json +0 -0
  15. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/catalog/locks/leancert-v4.33.0.lock.json +0 -0
  16. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/catalog/locks/mathlib-v4.30.0.lock.json +0 -0
  17. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/catalog/locks/mathlib-v4.31.0.lock.json +0 -0
  18. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/catalog/locks/mathlib-v4.32.2.lock.json +0 -0
  19. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/catalog/locks/mathlib-v4.33.0.lock.json +0 -0
  20. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/compatibility/README.md +0 -0
  21. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/compatibility/lake-artifact-cache-4.33.0.json +0 -0
  22. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/compatibility/mathlib-4.32.2.json +0 -0
  23. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/compatibility/mathlib-4.32.2.toml +0 -0
  24. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/compatibility/mathlib-4.33.0.json +0 -0
  25. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/compatibility/mathlib-4.33.0.toml +0 -0
  26. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/docs/architecture.md +0 -0
  27. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/docs/captures.md +0 -0
  28. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/docs/case-study-v1.md +0 -0
  29. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/docs/cli.md +0 -0
  30. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/docs/development.md +0 -0
  31. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/docs/environments.md +0 -0
  32. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/docs/getting-started.md +0 -0
  33. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/docs/index.md +0 -0
  34. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/docs/lake-artifact-cache-design.md +0 -0
  35. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/docs/local-projects.md +0 -0
  36. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/docs/portable-copies.md +0 -0
  37. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/docs/project-publishing.md +0 -0
  38. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/docs/python-api.md +0 -0
  39. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/docs/ready-programs.md +0 -0
  40. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/docs/standalone-files.md +0 -0
  41. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/docs/trust-and-limitations.md +0 -0
  42. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/docs/v1-precision.md +0 -0
  43. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/examples/mathlib.toml +0 -0
  44. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/__init__.py +0 -0
  45. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/__main__.py +0 -0
  46. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/_git.py +0 -0
  47. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/_paths.py +0 -0
  48. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/backends.py +0 -0
  49. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/bundles.py +0 -0
  50. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/capsules.py +0 -0
  51. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/cli.py +0 -0
  52. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/comparison.py +0 -0
  53. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/console.py +0 -0
  54. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/decisions.py +0 -0
  55. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/diagnostics.py +0 -0
  56. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/discovery/__init__.py +0 -0
  57. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/discovery/analyzer.py +0 -0
  58. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/discovery/api.py +0 -0
  59. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/discovery/candidate.py +0 -0
  60. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/discovery/catalog.py +0 -0
  61. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/discovery/catalog_build.py +0 -0
  62. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/discovery/catalog_cli.py +0 -0
  63. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/discovery/catalog_manifest.py +0 -0
  64. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/discovery/data/catalog.json +0 -0
  65. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/discovery/defaults.py +0 -0
  66. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/discovery/engine.py +0 -0
  67. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/discovery/errors.py +0 -0
  68. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/discovery/module_inventory.py +0 -0
  69. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/discovery/planner.py +0 -0
  70. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/discovery/policy.py +0 -0
  71. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/discovery/probe.py +0 -0
  72. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/discovery/py.typed +0 -0
  73. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/discovery/result.py +0 -0
  74. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/discovery/schema_resources.py +0 -0
  75. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/discovery/schemas/catalog-v1.schema.json +0 -0
  76. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/discovery/schemas/plan-v1.schema.json +0 -0
  77. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/discovery/schemas/result-v1.schema.json +0 -0
  78. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/environments.py +0 -0
  79. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/errors.py +0 -0
  80. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/events.py +0 -0
  81. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/facade.py +0 -0
  82. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/frontmatter.py +0 -0
  83. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/header_cache.py +0 -0
  84. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/health.py +0 -0
  85. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/identifier_resolver.py +0 -0
  86. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/lake.py +0 -0
  87. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/lake_cache.py +0 -0
  88. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/lockfiles.py +0 -0
  89. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/locking.py +0 -0
  90. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/matrix.py +0 -0
  91. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/models.py +0 -0
  92. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/oci.py +0 -0
  93. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/oci_protocol.py +0 -0
  94. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/packs.py +0 -0
  95. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/policies.py +0 -0
  96. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/profiling.py +0 -0
  97. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/programs.py +0 -0
  98. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/project_execution.py +0 -0
  99. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/project_sharing.py +0 -0
  100. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/projects.py +0 -0
  101. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/publisher_verification.py +0 -0
  102. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/py.typed +0 -0
  103. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/references.py +0 -0
  104. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/resolver.py +0 -0
  105. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/run_cli.py +0 -0
  106. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/runtime.py +0 -0
  107. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/schema_resources.py +0 -0
  108. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/serialization.py +0 -0
  109. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/shared_projects.py +0 -0
  110. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/specs.py +0 -0
  111. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/store.py +0 -0
  112. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/timings.py +0 -0
  113. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/toolchain_oci.py +0 -0
  114. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/toolchain_slim.py +0 -0
  115. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/verification.py +0 -0
  116. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime/wire.py +0 -0
  117. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime.egg-info/SOURCES.txt +0 -0
  118. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime.egg-info/dependency_links.txt +0 -0
  119. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime.egg-info/entry_points.txt +0 -0
  120. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime.egg-info/requires.txt +0 -0
  121. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/lean_runtime.egg-info/top_level.txt +0 -0
  122. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/mkdocs.yml +0 -0
  123. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/schemas/attestation-v1.schema.json +0 -0
  124. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/schemas/check-batch-v1.schema.json +0 -0
  125. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/schemas/cleanup-v1.schema.json +0 -0
  126. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/schemas/comparison-v1.schema.json +0 -0
  127. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/schemas/execution-v1.schema.json +0 -0
  128. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/schemas/inspect-v1.schema.json +0 -0
  129. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/schemas/matrix-v1.schema.json +0 -0
  130. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/schemas/plan-v1.schema.json +0 -0
  131. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/schemas/profile-v1.schema.json +0 -0
  132. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/schemas/publication-v1.schema.json +0 -0
  133. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/schemas/verify-v1.schema.json +0 -0
  134. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/scripts/announcement_gate.py +0 -0
  135. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/scripts/lake_cache_gate.py +0 -0
  136. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/scripts/registry_preflight.py +0 -0
  137. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/scripts/run_compatibility.py +0 -0
  138. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/scripts/run_v1_case_study.py +0 -0
  139. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/scripts/smoke_wheel.py +0 -0
  140. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/setup.cfg +0 -0
  141. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/conftest.py +0 -0
  142. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/discovery/e2e/test_real_discovery.py +0 -0
  143. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/discovery/test_analyzer.py +0 -0
  144. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/discovery/test_catalog.py +0 -0
  145. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/discovery/test_catalog_build.py +0 -0
  146. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/discovery/test_discovery_schema_resources.py +0 -0
  147. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/discovery/test_engine.py +0 -0
  148. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/discovery/test_planner.py +0 -0
  149. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/discovery/test_policy.py +0 -0
  150. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_backend.py +0 -0
  151. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_bundles.py +0 -0
  152. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_capsules.py +0 -0
  153. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_cli.py +0 -0
  154. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_console.py +0 -0
  155. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_diagnostics.py +0 -0
  156. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_environment_integration.py +0 -0
  157. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_events_health.py +0 -0
  158. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_facade.py +0 -0
  159. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_frontmatter.py +0 -0
  160. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_git.py +0 -0
  161. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_header_cache.py +0 -0
  162. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_identifier_resolver.py +0 -0
  163. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_interactive.py +0 -0
  164. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_lake_cache.py +0 -0
  165. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_lockfiles.py +0 -0
  166. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_locking.py +0 -0
  167. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_models.py +0 -0
  168. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_multifile.py +0 -0
  169. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_oci_protocol.py +0 -0
  170. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_packs.py +0 -0
  171. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_paths.py +0 -0
  172. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_prebuilt_policy.py +0 -0
  173. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_programs.py +0 -0
  174. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_project_publish.py +0 -0
  175. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_projects.py +0 -0
  176. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_references.py +0 -0
  177. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_run_cli.py +0 -0
  178. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_runtime.py +0 -0
  179. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_schema_resources.py +0 -0
  180. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_schemas.py +0 -0
  181. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_signatures.py +0 -0
  182. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_specs.py +0 -0
  183. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_store.py +0 -0
  184. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_toolchain_oci.py +0 -0
  185. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_toolchains.py +0 -0
  186. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_v1_precision.py +0 -0
  187. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_verification_inventory.py +0 -0
  188. {lean_runtime-3.0.1 → lean_runtime-3.0.2}/tests/test_verification_probe.py +0 -0
@@ -2,6 +2,14 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 3.0.2 - 2026-08-17
6
+
7
+ - Route the first check directly through a newly downloaded slim Lean runtime.
8
+ Command construction and executable hashing now re-evaluate toolchain state
9
+ after remote acquisition and ignore incomplete Elan toolchain directories,
10
+ preventing cold discovery from starting an unintended full toolchain install.
11
+
12
+
5
13
  ## 3.0.1 - 2026-08-17
6
14
 
7
15
  - Point the portable-copy consuming examples at
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lean-runtime
3
- Version: 3.0.1
3
+ Version: 3.0.2
4
4
  Summary: Run Lean 4 proofs from Python or standalone files
5
5
  Author: Alejandro Radisic
6
6
  License-Expression: Apache-2.0
@@ -325,26 +325,33 @@ class ToolchainManager:
325
325
  A full Elan installation is preferred; when only a verified slim copy
326
326
  remains, its executables are invoked directly.
327
327
  """
328
- name = normalize_toolchain(toolchain)
329
- if self.has_slim(name) and not self._elan_toolchain_dir(name).is_dir():
328
+ name = self.ensure(toolchain)
329
+ full = self._elan_toolchain_dir(name)
330
+ full_lean = full / "bin" / "lean"
331
+ if os.name == "nt":
332
+ full_lean = full_lean.with_suffix(".exe")
333
+ if self.has_slim(name) and not full_lean.is_file():
330
334
  binary = self.slim_path(name) / "bin" / executable
335
+ if os.name == "nt":
336
+ binary = binary.with_suffix(".exe")
331
337
  if not binary.is_file():
332
338
  raise ToolchainError(
333
339
  f"slim toolchain {name!r} does not provide {executable!r}; "
334
340
  "reinstall the full toolchain for this operation"
335
341
  )
336
342
  return [str(binary), *args]
337
- name = self.ensure(name)
338
343
  return [str(self.elan_path()), "run", name, executable, *args]
339
344
 
340
345
  def executable_digest(self, toolchain: str, executable: str) -> str:
341
346
  """Hash the exact resolved executable for compatibility-cache identities."""
342
- name = normalize_toolchain(toolchain)
347
+ name = self.ensure(toolchain)
343
348
  full = self._elan_toolchain_dir(name)
344
- if self.has_slim(name) and not full.is_dir():
349
+ full_lean = full / "bin" / "lean"
350
+ if os.name == "nt":
351
+ full_lean = full_lean.with_suffix(".exe")
352
+ if self.has_slim(name) and not full_lean.is_file():
345
353
  binary = self.slim_path(name) / "bin" / executable
346
354
  else:
347
- self.ensure(name)
348
355
  binary = full / "bin" / executable
349
356
  if os.name == "nt" and not binary.is_file():
350
357
  binary = binary.with_suffix(".exe")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lean-runtime
3
- Version: 3.0.1
3
+ Version: 3.0.2
4
4
  Summary: Run Lean 4 proofs from Python or standalone files
5
5
  Author: Alejandro Radisic
6
6
  License-Expression: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "lean-runtime"
7
- version = "3.0.1"
7
+ version = "3.0.2"
8
8
  description = "Run Lean 4 proofs from Python or standalone files"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import hashlib
5
6
  import threading
6
7
  from pathlib import Path
7
8
 
@@ -114,6 +115,83 @@ def test_command_uses_the_slim_copy_when_the_full_toolchain_is_gone(tmp_path: Pa
114
115
  assert command == [str(manager.slim_path(TOOLCHAIN) / "bin" / "lean"), "Main.lean"]
115
116
 
116
117
 
118
+ def test_command_uses_a_slim_copy_acquired_during_the_first_call(
119
+ tmp_path: Path,
120
+ monkeypatch: pytest.MonkeyPatch,
121
+ ) -> None:
122
+ manager = ToolchainManager(tmp_path / "runtime")
123
+ source = _fake_toolchain(tmp_path)
124
+
125
+ def acquire(toolchain: str, _cancel: threading.Event | None) -> bool:
126
+ materialize(
127
+ source,
128
+ manager.slim_path(toolchain),
129
+ toolchain=toolchain,
130
+ created_at="2026-08-17T00:00:00+00:00",
131
+ )
132
+ return True
133
+
134
+ manager.remote_ensure = acquire
135
+ monkeypatch.setattr(
136
+ manager,
137
+ "elan_path",
138
+ lambda: pytest.fail("cold slim execution must not invoke Elan"),
139
+ )
140
+
141
+ command = manager.command(TOOLCHAIN, "lean", "Main.lean")
142
+
143
+ assert command == [str(manager.slim_path(TOOLCHAIN) / "bin" / "lean"), "Main.lean"]
144
+
145
+
146
+ def test_command_ignores_an_incomplete_elan_toolchain_directory(tmp_path: Path) -> None:
147
+ manager = _manager_with_slim(tmp_path)
148
+ manager._elan_toolchain_dir(TOOLCHAIN).mkdir(parents=True)
149
+
150
+ command = manager.command(TOOLCHAIN, "lean", "Main.lean")
151
+
152
+ assert command == [str(manager.slim_path(TOOLCHAIN) / "bin" / "lean"), "Main.lean"]
153
+
154
+
155
+ def test_command_prefers_a_usable_full_toolchain(
156
+ tmp_path: Path,
157
+ monkeypatch: pytest.MonkeyPatch,
158
+ ) -> None:
159
+ manager = _manager_with_slim(tmp_path)
160
+ full_lean = manager._elan_toolchain_dir(TOOLCHAIN) / "bin" / "lean"
161
+ full_lean.parent.mkdir(parents=True)
162
+ full_lean.write_text("full lean")
163
+ elan = tmp_path / "elan-executable"
164
+ elan.write_text("elan")
165
+ monkeypatch.setenv("LEAN_RUNTIME_ELAN", str(elan))
166
+
167
+ command = manager.command(TOOLCHAIN, "lean", "Main.lean")
168
+
169
+ assert command == [str(elan.absolute()), "run", TOOLCHAIN, "lean", "Main.lean"]
170
+
171
+
172
+ def test_executable_digest_uses_a_slim_copy_acquired_during_the_first_call(
173
+ tmp_path: Path,
174
+ ) -> None:
175
+ manager = ToolchainManager(tmp_path / "runtime")
176
+ source = _fake_toolchain(tmp_path)
177
+
178
+ def acquire(toolchain: str, _cancel: threading.Event | None) -> bool:
179
+ materialize(
180
+ source,
181
+ manager.slim_path(toolchain),
182
+ toolchain=toolchain,
183
+ created_at="2026-08-17T00:00:00+00:00",
184
+ )
185
+ return True
186
+
187
+ manager.remote_ensure = acquire
188
+
189
+ assert manager.executable_digest(TOOLCHAIN, "lean") == (
190
+ "sha256:" + hashlib.sha256(b"bin/lean").hexdigest()
191
+ )
192
+ assert not manager.elan_home.exists()
193
+
194
+
117
195
  def test_command_rejects_executables_outside_the_slim_profile(tmp_path: Path) -> None:
118
196
  manager = _manager_with_slim(tmp_path)
119
197
  with pytest.raises(ToolchainError, match="does not provide 'leanc'"):
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes