Repository navigation
Conversation
A library's srcDir may hold a .lean file whose stem is not a plain
identifier, such as a Finder duplicate "Basic copy.lean", even when the
library's roots and globs never select it. project_modules still lists
every captured source module as local, and render_impact_probe spelled
"Demo.Basic copy" with _lean_name, which cannot parse it, so "autoform
work impact" exited 2 with "invalid Lean declaration name".
Spell each source module with Lean's guillemet quoting for components
that are not plain identifiers: Demo.«Basic copy». The probe then builds
the Name Lean reports for that module, so constants Lean can import
from it stay local and keep their impact, and the module-to-path lookup
agrees with the record's module. Skipping unrepresentable names instead
would have dropped such modules from locality and missed their
dependents. The lookup now compares names by component, so a Unicode
component Lean prints unquoted (Demo.α) still finds its file. The
components come from the parent directories and the stem rather than
from with_suffix(""), which on Python 3.13 rejects the stem "." of a
stray "..lean" (Lean's Demo.«.»).
A component containing "»", as in Demo/«Foo».lean or Demo/x»y.lean,
has no quoted spelling, so no import can name that module and it is
never local. Lake can still build such a file: it builds
Demo/«Foo».lean as a module whose last component is "«Foo»". So
_source_modules returns these files separately, spelled with the
same quoting so that Demo/Foo.x»y.lean stays one component outside
Demo.Foo.*, and a glob that selects one is refused as on main rather
than leaving the module's constants silently out of the report.
The quoting also treats a dotted stem such as Demo/Foo.Bar.lean as the
single component «Foo.Bar», matching Lean. A Demo.* glob over that file
is refused with "plain module names only", and an explicit root
Demo.Foo.Bar backed only by it reports "has no source file", where the
probe used to emit a wrong import. The glob branch still refuses to
import any quoted module, so the probe imports nothing new.
run_probe said "a built Lean project is required to extract skeletons" for every probe label, so "autoform work impact" without lake talked about skeletons. Phrase it with _probe_purpose(label) like the neighboring lake-manifest and freshness messages: "lake is not on PATH; running the impact probe requires a built Lean project".
Commands resolve --lean-root with pathlib, which raises RuntimeError in two cases: expanduser() for an unknown ~user, such as a mistyped '~nosuchuser/lean', on every Python version; and resolve() for a symbolic link loop (la -> lb -> la) before Python 3.13, which returns the loop path instead. "autoform check", "audit" and "skeleton" crashed with a traceback on such a root, while "work impact" and "doctor" already caught RuntimeError and reported the path as unreadable. build_linker and extract_skeletons now raise their usual error instead. check prints "Lean sources could not be indexed: Lean root cannot be resolved", a fixed message because index errors never show host paths, and skeleton names the root and the cause. The audit's Lean findings guard the expanduser, resolve and is_dir calls with the same exceptions doctor's _resolve_lean_root catches and report the existing invalid-lean-root finding. "render" has the same crash. It is left alone here because #165, which rewrites render, already guards that call.
Review at 4139feeVerdict: merge-ready. The quoting, the component-keyed locator and the three error-path fixes are correct on main, and CI is green at this head. It also fixes one silent drop the body doesn't claim (test gap 1). The interaction with #183 that item 3 of the posted #183 review predicts is real. The fix belongs in #183, which needs the same change for its own bug 3 anyway. Details are under Landing. Test gaps1. Digit-leading module components are fixed but not pinned ( On main,
Landing
|
Follow-up to #136. Re-reviewing it after it merged, I found one problem a user can hit and two error-path nits. All three still reproduce on main 4c80749.
What a user sees. A Finder duplicate such as
Demo/Basic copy.leanunder a library'ssrcDirmadeautoform work impactexit 2 withinvalid Lean declaration name: 'Demo.Basic copy', even though no root or glob selects that file. With this PR the impact report comes out as usual.impact.py).project_modulescounts every source module under a library as local, and the probe spelled each name with_lean_name, which cannot parseDemo.Basic copy._source_modulesnow quotes components that are not plain identifiers the way Lean does (Demo.«Basic copy»), so constants from that module stay local and keep their impact. The module-to-path lookup compares names by component, soDemo.α, which Lean prints unquoted, still finds its file. A dotted stem such asDemo/Foo.Bar.leanis now the single component«Foo.Bar», as in Lean, so aDemo.Foo.*glob no longer selects it asDemo.Foo.Bar, andDemo/..leanisDemo.«.»(with_suffix("")rejects that stem on Python 3.13). A component containing»has no quoted spelling: Lake still buildsDemo/«Foo».lean, but no import can name it, so such files are never local, and a glob that selects one is refused as it is on main. The glob branch refuses every quoted module, so the probe imports nothing new.lakenot on PATH (9a2d26f,skeleton.py). The message said "a built Lean project is required to extract skeletons" for the impact probe too. It now names the probe's purpose, like the neighboring messages: "lake is not on PATH; running the impact probe requires a built Lean project".--lean-root(4139fee,lean.py,skeleton.py,audit.py).expanduser()raisesRuntimeErrorfor an unknown~useron every Python version, and before 3.13resolve()raises it for a symbolic link loop;check,audit, andskeletoncrashed with a traceback on either.checknow prints "Lean sources could not be indexed: Lean root cannot be resolved" (index errors never show host paths),skeletonnames the root and the cause, andauditreports its existinginvalid-lean-rootfinding.work list,work context,work impact, anddoctoralready handled both. This one predates Report Lean revision impact and deprecated targets #136.Tests, in
tests/test_impact.py:test_unselected_source_with_a_quoted_module_name_stays_local(Basic copy.lean,α.lean,..lean,x»y.lean),test_project_modules_read_a_dotted_file_stem_as_one_component(Foo.Bar.leanandFoo.x»y.leanbeside aDemo.Foo.*glob), twotest_project_modules_fail_closedcases where a glob selects«Foo».leanorx»y.lean, and the extendedtest_impact_probe_freshness_messages_never_mention_skeletons. Intests/test_cli.py:test_lean_root_commands_report_an_unresolvable_root_without_traceback, which runscheck,audit, andskeletonagainst both roots on every Python version (on 3.13checkfails later for the loop, when it reads the sources, with the same prefix).Not changed:
renderhas the same crash for--lean-root, and for its blueprint and output paths. #165, which rewritesrender, already guards all three, so this PR leavesrender.pyalone rather than conflict with it.Overlap: merges cleanly with every open PR except three. #140 and #141 already conflict with main in 24 files; this adds 3 hunks to their
tests/test_impact.pyconflict. #75 conflicts with main only inskills/setup/SKILL.md; this adds a one-hunk conflict intests/test_cli.py.Validation at
4139fee: locally, the full suite on Python 3.13 and 3.10 (1855 passed, 56 skipped, 1 xfailed each), the real-Lean impact tests (77 passed),ruff check, andmake check-example. The real-Lean skeleton and open-statement jobs (173 passed; 95 passed, 1 skipped) last ran before a final change to_source_modulesand its tests, which they do not exercise.