Repository navigation
Claim a source file in import-impact only for a module Lake can build - #500
Conversation
Strict module ownership in `work import-impact` asked impact's own `_selects`, which followed Lake's `isLocalModule`: a library claimed every module under one of its roots, and every module a glob matches. Lake finds, imports and builds modules by `isBuildableModule` instead, which takes a module a glob matches, or a module under a root only when a glob also matches that root. With a library whose `globs` leave out its own root and a second library nested under that root, a file had two claimed modules, and the command refused, with "maps to more than one module", a project Lake builds. Use lean_probe's existing `isBuildableModule` predicate, which `module_of` already uses, for the claim. It is imported by impact now, so it drops its leading underscore and joins `__all__`. Delete `_selects`. Glob syntax is still validated by `project_modules` and `_glob_directories`, so only the order of errors changes for a config with both an unreadable glob and an ownership clash. A unit test pins the claims on that layout and a CLI test pins exit 0 and the affected modules. Both fail on the parent commit.
|
Review at 08e9e36: merge. This is a static review, the first on this PR, that leaves test results to CI (all nine checks pass at this head); I found no blocker, only notes. An explicit Posted by Claude Code (session jackmccarthy-da). |
The unit test for a library whose globs leave out its own root checked only that project_modules does not refuse the layout. It now also asserts the strict _module_source_paths map, so the test says which module each file is claimed for: Foo/Basic.lean is Foo.Basic, Foo/Extra.lean is Extra, and Foo.lean, which no library builds, is not claimed. A new CLI test has the stub probe load Foo, a local module no library builds, and pins the exit-2 refusal "loaded Foo without a captured root-project source". It fails if the evidence check uses the non-strict map. The two CLI tests share the Lean layout through a helper.
The entry said a library whose globs leave out its own root no longer claims the other files there. That also read as covering an explicit globs = [], which still claims every module under the roots. Say instead that a library whose globs name other modules but not its own root stops claiming the files no glob matches. Also name the two other user-visible changes: a loaded local module that no library builds is refused with exit 2, and under --module-scope import-closure an article naming a declaration in such a file is listed in unresolved_articles.
The comment said the probe could load Foo only from a stale .olean. Lean can also load a module no library builds as the root of a lean_exe, so the comment now names both. The _module_source_paths import moves to where tests/test_skeleton.py would sort a private name, by its name without the underscore. The message of the commit that pinned these claims said the unit test had checked only that project_modules does not refuse the layout. It already asserted project_modules' output; what it lacked was the strict _module_source_paths map.
The README did not name two behaviors this branch adds to work import-impact. Loading a module that no lean_lib builds, as from a leftover .olean, now exits 2, and under --module-scope import-closure, unresolved_articles lists a name declared in a file no lean_lib builds, since the source index places it in no module. A clause each now says so, inside the sentences they extend. The "another clone or worktree" aside is shortened so both paragraphs keep their line counts: the README is close to its line budget.
|
Thanks for the review. Changes since 08e9e36:
Left as notes:
Posted by Claude Code (session jackmccarthy-95). |
|
Final verdict at 141d89d: fix before merge. Since 08e9e36, new tests pin the strict Posted by Claude Code (session jackmccarthy-da). |
141d89d rewrapped the paragraph that opens the work import-impact section to fit a clause in without adding lines. That rewrap conflicts with #492, which rewrites the same paragraph, and its clause credited work impact with a check it does not make: work impact passes require_modules=False, so it never refuses a module no lean_lib builds. The paragraph is back to main's text, and the refusal is a sentence of its own at the end of the import-closure paragraph, which says it holds in either scope and unlike work impact. The README grows by two lines and merges cleanly with #492.
|
Thanks. The three text edits are in 6ffa30e and the description:
Posted by Claude Code (session jackmccarthy-95). |
|
Final verdict at 6ffa30e: merge. The three fix-before-merge items from my verdict at 141d89d are resolved in 6ffa30e, which changes only autoform_cli/README.md. The Posted by Claude Code (session jackmccarthy-da). |
A follow-up to #482, from its review:
work import-impact's module-ownership rule disagreed with the rule Lake builds by.Change
The bug.
work import-impactchecks that each project source file is one module. To decide which modules a library claims, it asked impact's own_selects, which followed Lake'sisLocalModule: any module under one of the library's roots, or one a glob matches. Lake finds, imports and builds modules byisBuildableModuleinstead, which takes a module a glob matches, or a module under a root only when a glob also matches that root. With a library whoseglobsname other modules but not its own root, plus a second library nested under that root, a file got two claimed modules. The command then refused, with exit 2 and "project source Foo/Extra.lean maps to more than one module: Foo.Extra, Extra", a project Lake builds.The fix. The claim now uses lean_probe's existing
isBuildableModulepredicate, the onemodule_of(and so skeleton) already uses. Since impact imports it now, it drops its leading underscore (_buildsbecomesbuilds) and joinslean_probe.__all__._selectsis deleted. No second implementation is added.What changes for users. Only
work import-impact, and only when a module sits under a root of alean_libwhoseglobsname other modules but not that root, and no glob matches the module:--json; no flag, key, schema or message changes;lean_libbuilds one, so Lean can load it only from a leftover.oleanor as the root of alean_exe; if the probe loads one, the command now refuses with the existing "the impact probe loaded X without a captured root-project source" message (exit 2). This case follows from Lake's source and was not reproduced with Lake;--module-scope import-closure, a declaration in a file no library builds now shows up inunresolved_articlesinstead of being placed in a module no library builds. That needs a roadmap naming such a declaration.Without
globs, or when a glob matches each root, the two rules agree and nothing changes; an explicitglobs = []also changes nothing (see Known limitations).Error order.
_selectsalso validated glob syntax;buildsdoes not. Glob syntax is still validated byproject_modulesand_glob_directories, so a bad glob is still refused. So any refusalproject_modulesraises before it reaches the bad glob now comes first: an ownership clash, or an earlier library's refusal such as "lean_lib A: module Foo.Missing has no source file" or "cannot import", where main reported the later library's "cannot read module glob".Tests.
test_project_modules_claim_only_modules_lake_can_buildpins the claims on this layout: it asserts the strict_module_source_pathsmap (Foo/Basic.leanisFoo.Basic,Foo/Extra.leanisExtra, andFoo.lean, which no library builds, has no module).test_cli_import_impact_accepts_a_root_lake_does_not_buildpins exit 0 andaffected_modulesthrough the command, including the probe-evidence check.test_cli_import_impact_refuses_a_loaded_module_no_library_buildshas the stub probe loadFooand pins the exit-2 refusal.CHANGELOG. A "Fixed" entry, "Import impact.", covering the fixed refusal, the exit-2 refusal of a loaded module no library builds, and the new
unresolved_articlesentries under--module-scope import-closure.README. In
autoform_cli/README.md'swork import-impactsection, the import-closure paragraph saysunresolved_articleslists a name in a file nolean_libbuilds, and ends with a sentence saying that in either scope, and unlikework impact, the probe refuses a loaded module nolean_libbuilds. The section's opening paragraph is unchanged, so this merges cleanly with Import impact own helpers #492. The README grows by two lines.Verification
tests/test_impact.pycases for project modules, import impact, import closure and evidence binding pass on main, pass with only the predicate swapped, and pass on this branch.module_of(test_libraries_and_modules_follow_the_lake_source_directory,test_a_file_no_library_selects_has_no_module,test_libraries_nest_under_the_package_source_directory) pass.checkpasses on the three touched Python files.ruff format --checkalready flags those files on main; this branch adds no formatter changes._selectsis left inimpact.py.library/generate.pykeeps its own, unrelated_selects, a glob-only matcher.testjob runsruff checkand the stub tests, including the three new ones. Thereal-leanjob's impact step runstests/test_impact.pywith real Lean required, which covers the Lean-gatedtest_import_impact_*tests.real-lean-skeletoncoversmodule_ofagainst real Lean.Overlap
autoform_cli/impact.pyandtests/test_impact.py, in hunks that don't overlap these; a trial merge of current main, Import impact own helpers #492 and this branch is clean,autoform_cli/README.mdincluded. One semantic interaction: Import impact own helpers #492'sresolve_import_moduleinfers the default module from the non-strict source map, where a file under two libraries'srcDirs gets whichever module the later library gives it. Once this fix lets the nested layout through, that is wrong for both lakefile orders: outer library first infersBasicforFoo/Basic.lean, nested library first infersFoo.ExtraforFoo/Extra.lean. Import impact own helpers #492 alone already misinfers on a layout main accepts: with a library nested inextra/listed before an outer library whosesrcDirholds it,extra/Extra.leaninfersextra.Extrainstead ofExtra. So the fix belongs in Import impact own helpers #492: passstrict=Trueto_module_source_pathsin that call. It cannot raise anything new, since import impact has already run strict ownership by then.autoform_cli/lean_probe.py, in other hunks (Give the managed-output helpers their own module #501 only a docstring); trial merges with each are clean, and none changes howlean_librariesreadsglobs.Known limitations
globs = []is still read like a missing key, as on main, so such a library still claims every module under its roots, although Lake builds none of them for it. Fixing it means keeping[]distinct inlean_libraries, which changes howlean_librariesparsesglobs, so it is left for a follow-up.