machinechecked 0.1.1__tar.gz → 0.1.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.
- {machinechecked-0.1.1 → machinechecked-0.1.2}/PKG-INFO +3 -1
- {machinechecked-0.1.1 → machinechecked-0.1.2}/README.md +2 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/machinechecked.egg-info/PKG-INFO +3 -1
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/machinechecked.egg-info/SOURCES.txt +2 -2
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/formalization.py +3 -1
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/simple.py +151 -14
- machinechecked-0.1.2/engine/python/prooflens/web/assets/index-DY4pFtGh.js +285 -0
- machinechecked-0.1.1/engine/python/prooflens/web/assets/index-B2GDDbsW.css → machinechecked-0.1.2/engine/python/prooflens/web/assets/index-g0SLRgHD.css +1 -1
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/web/index.html +2 -2
- {machinechecked-0.1.1 → machinechecked-0.1.2}/pyproject.toml +1 -1
- machinechecked-0.1.1/engine/python/prooflens/web/assets/index-DN7uLe7p.js +0 -285
- {machinechecked-0.1.1 → machinechecked-0.1.2}/LICENSE +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/machinechecked.egg-info/dependency_links.txt +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/machinechecked.egg-info/entry_points.txt +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/machinechecked.egg-info/requires.txt +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/machinechecked.egg-info/top_level.txt +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/__init__.py +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/__main__.py +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/assess.py +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/audit.py +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/bundle.py +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/cli.py +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/config.py +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/data/ProofLensProbe.lean +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/data/prooflens.sty +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/data/schema/evidence.schema.json +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/data/schema/inventory.schema.json +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/data/schema/manifest-claim.schema.json +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/data/schema/manifest-index.schema.json +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/evidence.py +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/export.py +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/manifest.py +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/pdfclaims.py +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/pipeline.py +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/probe.py +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/promote.py +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/review_queue.py +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/reviews.py +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/schemas.py +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/server.py +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/sources.py +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/tex.py +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/util.py +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/web/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/web/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/web/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/web/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/web/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/web/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/web/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/web/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/web/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/web/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/web/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/prooflens/web/assets/pdf.worker.min-yatZIOMy.mjs +0 -0
- {machinechecked-0.1.1 → machinechecked-0.1.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: machinechecked
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Read a mathematical paper beside its Lean formalisation, and see claim by claim what Lean establishes.
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Project-URL: Homepage, https://machinechecked.org
|
|
@@ -30,6 +30,8 @@ MachineChecked opens a paper, finds its numbered statements and lets you explore
|
|
|
30
30
|
|
|
31
31
|
**A Lean proof establishes a formal statement—not automatically the claim in the paper.** MachineChecked keeps those two questions separate.
|
|
32
32
|
|
|
33
|
+
**MachineChecked runs locally, in your Lean project.** It reads your paper and your compiled Lean declarations, writes an interactive reader, and keeps its results on your computer: generated data in `.machinechecked/`, the links you confirm in `machinechecked.links.json`, and the reader as `MachineChecked.html` if you ask for one. No account, registration or upload is needed. Publishing an audit (on your own GitHub Pages, say, and listing it on machinechecked.org) is a separate step you choose to take.
|
|
34
|
+
|
|
33
35
|
[Try the demo](https://machinechecked.org/demo/) · [Website](https://machinechecked.org/) · [Installation and usage](https://github.com/cgarryZA/MachineChecked/blob/main/docs/GETTING_STARTED.md)
|
|
34
36
|
|
|
35
37
|
## Open your paper
|
|
@@ -6,6 +6,8 @@ MachineChecked opens a paper, finds its numbered statements and lets you explore
|
|
|
6
6
|
|
|
7
7
|
**A Lean proof establishes a formal statement—not automatically the claim in the paper.** MachineChecked keeps those two questions separate.
|
|
8
8
|
|
|
9
|
+
**MachineChecked runs locally, in your Lean project.** It reads your paper and your compiled Lean declarations, writes an interactive reader, and keeps its results on your computer: generated data in `.machinechecked/`, the links you confirm in `machinechecked.links.json`, and the reader as `MachineChecked.html` if you ask for one. No account, registration or upload is needed. Publishing an audit (on your own GitHub Pages, say, and listing it on machinechecked.org) is a separate step you choose to take.
|
|
10
|
+
|
|
9
11
|
[Try the demo](https://machinechecked.org/demo/) · [Website](https://machinechecked.org/) · [Installation and usage](https://github.com/cgarryZA/MachineChecked/blob/main/docs/GETTING_STARTED.md)
|
|
10
12
|
|
|
11
13
|
## Open your paper
|
{machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/machinechecked.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: machinechecked
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Read a mathematical paper beside its Lean formalisation, and see claim by claim what Lean establishes.
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Project-URL: Homepage, https://machinechecked.org
|
|
@@ -30,6 +30,8 @@ MachineChecked opens a paper, finds its numbered statements and lets you explore
|
|
|
30
30
|
|
|
31
31
|
**A Lean proof establishes a formal statement—not automatically the claim in the paper.** MachineChecked keeps those two questions separate.
|
|
32
32
|
|
|
33
|
+
**MachineChecked runs locally, in your Lean project.** It reads your paper and your compiled Lean declarations, writes an interactive reader, and keeps its results on your computer: generated data in `.machinechecked/`, the links you confirm in `machinechecked.links.json`, and the reader as `MachineChecked.html` if you ask for one. No account, registration or upload is needed. Publishing an audit (on your own GitHub Pages, say, and listing it on machinechecked.org) is a separate step you choose to take.
|
|
34
|
+
|
|
33
35
|
[Try the demo](https://machinechecked.org/demo/) · [Website](https://machinechecked.org/) · [Installation and usage](https://github.com/cgarryZA/MachineChecked/blob/main/docs/GETTING_STARTED.md)
|
|
34
36
|
|
|
35
37
|
## Open your paper
|
{machinechecked-0.1.1 → machinechecked-0.1.2}/engine/python/machinechecked.egg-info/SOURCES.txt
RENAMED
|
@@ -56,6 +56,6 @@ engine/python/prooflens/web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2
|
|
|
56
56
|
engine/python/prooflens/web/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2
|
|
57
57
|
engine/python/prooflens/web/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2
|
|
58
58
|
engine/python/prooflens/web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2
|
|
59
|
-
engine/python/prooflens/web/assets/index-
|
|
60
|
-
engine/python/prooflens/web/assets/index-
|
|
59
|
+
engine/python/prooflens/web/assets/index-DY4pFtGh.js
|
|
60
|
+
engine/python/prooflens/web/assets/index-g0SLRgHD.css
|
|
61
61
|
engine/python/prooflens/web/assets/pdf.worker.min-yatZIOMy.mjs
|
|
@@ -62,8 +62,10 @@ def statements(fy: dict) -> list[dict]:
|
|
|
62
62
|
if not names or not m:
|
|
63
63
|
continue
|
|
64
64
|
rest = src[m.end():]
|
|
65
|
+
module = r.get("module") if isinstance(r.get("module"), str) else None
|
|
65
66
|
out.append({"source": src, "kind": m.group(1).lower(), "number": m.group(2),
|
|
66
|
-
"hint": _tokens(rest), "lean": names, "status": r.get("status")
|
|
67
|
+
"hint": _tokens(rest), "lean": names, "status": r.get("status"),
|
|
68
|
+
"module": module})
|
|
67
69
|
return out
|
|
68
70
|
|
|
69
71
|
|
|
@@ -300,6 +300,123 @@ def run_simple_probe(root: Path, modules: list[str], libs: list[str], requests:
|
|
|
300
300
|
return recs
|
|
301
301
|
|
|
302
302
|
|
|
303
|
+
def library_of(module: str, libs: list[str]) -> str:
|
|
304
|
+
"""The library a module belongs to: the one whose root is its first component."""
|
|
305
|
+
first = module.split(".")[0]
|
|
306
|
+
return next((l for l in libs if l.split(".")[0] == first), first)
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def probe_modules(root: Path, modules: list[str], libs: list[str], requests: list[dict],
|
|
310
|
+
lake: str = "lake", log=print) -> tuple[list[dict], dict[str, str]]:
|
|
311
|
+
"""Probe the built modules without assuming they can all be imported into one Lean session.
|
|
312
|
+
|
|
313
|
+
A project may build modules that do not belong together: two libraries declaring the same
|
|
314
|
+
name, for instance a statement left as a challenge and its solution. Lean may load both and
|
|
315
|
+
silently keep one, so each library is probed in its own session, always; a library that
|
|
316
|
+
fails to load is split in halves, down to single modules. Each record is tagged with the
|
|
317
|
+
group it came from, and a name found in several groups is ambiguous until its module is
|
|
318
|
+
given. Returns the records and the modules that could not be loaded, with the reason."""
|
|
319
|
+
recs, failed = [], {}
|
|
320
|
+
|
|
321
|
+
def run(group: list[str], label: str):
|
|
322
|
+
try:
|
|
323
|
+
out = run_simple_probe(root, group, libs, requests, lake)
|
|
324
|
+
except ViewError as e:
|
|
325
|
+
if len(group) == 1:
|
|
326
|
+
failed[group[0]] = str(e)[-600:]
|
|
327
|
+
return
|
|
328
|
+
log(f"lean: {label} could not be loaded in one session; splitting it")
|
|
329
|
+
half = len(group) // 2
|
|
330
|
+
run(group[:half], label + "/a")
|
|
331
|
+
run(group[half:], label + "/b")
|
|
332
|
+
return
|
|
333
|
+
for r in out:
|
|
334
|
+
r["probe_group"] = label
|
|
335
|
+
recs.extend(out)
|
|
336
|
+
|
|
337
|
+
by_lib: dict[str, list[str]] = {}
|
|
338
|
+
for m in sorted(modules):
|
|
339
|
+
by_lib.setdefault(library_of(m, libs), []).append(m)
|
|
340
|
+
for lib, ms in sorted(by_lib.items()):
|
|
341
|
+
run(ms, lib)
|
|
342
|
+
return recs, failed
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
DECL_KEYWORDS = r"(?:theorem|lemma|def|abbrev|instance|structure|inductive|class|opaque|axiom)"
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def declared_names(text: str) -> set[str]:
|
|
349
|
+
"""The full names a Lean source declares, as far as its text shows: each declaration's
|
|
350
|
+
identifier inside the `namespace` blocks around it."""
|
|
351
|
+
names, stack = set(), []
|
|
352
|
+
decl = re.compile(rf"^\s*(?:@\[[^\]]*\]\s*)?(?:(?:private|protected|noncomputable|nonrec|"
|
|
353
|
+
rf"partial|unsafe)\s+)*{DECL_KEYWORDS}\s+([\w.'«»]+)")
|
|
354
|
+
for line in text.splitlines():
|
|
355
|
+
m = re.match(r"\s*(namespace|section)\b\s*([\w.'«»]*)", line)
|
|
356
|
+
if m:
|
|
357
|
+
stack.append((m.group(1), m.group(2)))
|
|
358
|
+
continue
|
|
359
|
+
m = re.match(r"\s*end\b\s*([\w.'«»]*)", line)
|
|
360
|
+
if m and stack:
|
|
361
|
+
stack.pop()
|
|
362
|
+
continue
|
|
363
|
+
m = decl.match(line)
|
|
364
|
+
if m:
|
|
365
|
+
ident = m.group(1)
|
|
366
|
+
if ident.startswith("_root_."):
|
|
367
|
+
names.add(ident[len("_root_."):])
|
|
368
|
+
else:
|
|
369
|
+
ns = [n for kind, n in stack if kind == "namespace" and n]
|
|
370
|
+
names.add(".".join(ns + [ident]))
|
|
371
|
+
return names
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def declaring_modules(root: Path, modules: list[str], name: str) -> list[str]:
|
|
375
|
+
"""Modules among `modules` whose source declares `name`, as far as its text shows. Used only
|
|
376
|
+
to explain a declaration that no probed module holds; it never makes a link read as
|
|
377
|
+
checked."""
|
|
378
|
+
out = []
|
|
379
|
+
for m in modules:
|
|
380
|
+
p = root / (m.replace(".", "/") + ".lean")
|
|
381
|
+
try:
|
|
382
|
+
if p.is_file() and name in declared_names(p.read_text(encoding="utf-8", errors="replace")):
|
|
383
|
+
out.append(m)
|
|
384
|
+
except OSError:
|
|
385
|
+
continue
|
|
386
|
+
return out
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
def resolve_link(name: str, records: list[dict], module: str | None, root: Path,
|
|
390
|
+
unbuilt: list[str], failed: dict[str, str]) -> tuple[dict | None, str | None]:
|
|
391
|
+
"""The probe record a link means, or why there is none.
|
|
392
|
+
|
|
393
|
+
A declaration is identified by its name and its module: when several loaded modules declare
|
|
394
|
+
the name, the module the project gave (formalization.yaml's `module`) decides, and without
|
|
395
|
+
one the link is ambiguous rather than guessed. With no record, the source says whether the
|
|
396
|
+
declaration's module is unbuilt or could not be loaded: only a declaration absent from the
|
|
397
|
+
modules that were inspected reads as not found."""
|
|
398
|
+
found = [r for r in records if "missing" not in r.get("errors", [])]
|
|
399
|
+
mod_of = lambda r: (r.get("decl") or {}).get("module") or r.get("module")
|
|
400
|
+
if module:
|
|
401
|
+
mine = [r for r in found if mod_of(r) == module]
|
|
402
|
+
if mine:
|
|
403
|
+
return mine[0], None
|
|
404
|
+
if module in unbuilt:
|
|
405
|
+
return None, f"linked: Lean not checked (its module {module} is not built)"
|
|
406
|
+
if module in failed:
|
|
407
|
+
return None, f"linked: Lean not checked (its module {module} could not be loaded)"
|
|
408
|
+
elif len({mod_of(r) for r in found}) > 1:
|
|
409
|
+
mods = ", ".join(sorted(str(mod_of(r)) for r in found))
|
|
410
|
+
return None, f"linked: Lean name is ambiguous (declared in {mods})"
|
|
411
|
+
elif found:
|
|
412
|
+
return found[0], None
|
|
413
|
+
for m in declaring_modules(root, unbuilt, name):
|
|
414
|
+
return None, f"linked: Lean not checked (its module {m} is not built)"
|
|
415
|
+
for m in declaring_modules(root, list(failed), name):
|
|
416
|
+
return None, f"linked: Lean not checked (its module {m} could not be loaded)"
|
|
417
|
+
return None, None
|
|
418
|
+
|
|
419
|
+
|
|
303
420
|
def link_state(rec: dict | None) -> tuple[str, str]:
|
|
304
421
|
"""The status of a confirmed link from its probe record, and its class."""
|
|
305
422
|
if rec is None or "missing" in rec.get("errors", []):
|
|
@@ -438,8 +555,10 @@ def build_view(root: Path, paper_path: Path, out_dir: Path, lake: str = "lake",
|
|
|
438
555
|
index, linkrecs, decls = [], {}, {}
|
|
439
556
|
if fy and "error" not in fy:
|
|
440
557
|
for c in claims:
|
|
441
|
-
|
|
442
|
-
|
|
558
|
+
rows = fz.links_for(fy, c["kind"], c["number"], paper.title)
|
|
559
|
+
c["declared"] = [n for st in rows for n in st["lean"]]
|
|
560
|
+
c["declared_modules"] = {n: st["module"] for st in rows for n in st["lean"]
|
|
561
|
+
if st.get("module")}
|
|
443
562
|
links = load_links(root).get("papers", {}).get(paper_key, {})
|
|
444
563
|
if not libs:
|
|
445
564
|
notes.append("no Lean library found in the lakefile")
|
|
@@ -454,13 +573,16 @@ def build_view(root: Path, paper_path: Path, out_dir: Path, lake: str = "lake",
|
|
|
454
573
|
icache = out_dir / "build" / "index-cache.json"
|
|
455
574
|
idigest = lean_digest(root)
|
|
456
575
|
cached = read_json(icache) if icache.exists() else {}
|
|
576
|
+
failed = {}
|
|
457
577
|
if cached.get("digest") == idigest:
|
|
458
|
-
index = cached["index"]
|
|
578
|
+
index, failed = cached["index"], cached.get("failed", {})
|
|
459
579
|
else:
|
|
460
580
|
log(f"lean: indexing {len(built)} built module(s)")
|
|
461
|
-
recs =
|
|
581
|
+
recs, failed = probe_modules(root, built, libs, [{"kind": "index", "name": ""}],
|
|
582
|
+
lake, log)
|
|
462
583
|
index = [r for r in recs if r["record"] == "index"]
|
|
463
|
-
write_json(icache, {"digest": idigest, "index": index},
|
|
584
|
+
write_json(icache, {"digest": idigest, "index": index, "failed": failed},
|
|
585
|
+
indent=None)
|
|
464
586
|
wanted = set()
|
|
465
587
|
for c in claims:
|
|
466
588
|
entry = links.get(c["key"], {})
|
|
@@ -472,23 +594,38 @@ def build_view(root: Path, paper_path: Path, out_dir: Path, lake: str = "lake",
|
|
|
472
594
|
wanted |= {s["name"] for s in c["suggestions"][:1] if s.get("kind")}
|
|
473
595
|
if wanted:
|
|
474
596
|
log(f"lean: checking {len(wanted)} linked or suggested declaration(s)")
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
597
|
+
loadable = [m for m in built if m not in failed]
|
|
598
|
+
recs, more = probe_modules(root, loadable, libs,
|
|
599
|
+
[{"kind": "link", "name": n} for n in sorted(wanted)],
|
|
600
|
+
lake, log)
|
|
601
|
+
failed.update(more)
|
|
602
|
+
for r in recs:
|
|
603
|
+
if r["record"] == "link":
|
|
604
|
+
linkrecs.setdefault(r["name"], []).append(r)
|
|
605
|
+
elif r["record"] == "decl":
|
|
606
|
+
decls.setdefault(r["name"], r)
|
|
607
|
+
if failed:
|
|
608
|
+
notes.append(f"{len(failed)} built module(s) could not be loaded by MachineChecked "
|
|
609
|
+
f"and are not indexed: {', '.join(sorted(failed)[:5])}"
|
|
610
|
+
+ ("…" if len(failed) > 5 else ""))
|
|
479
611
|
|
|
480
612
|
# Statuses.
|
|
481
613
|
for c in claims:
|
|
482
614
|
entry = links.get(c["key"], {})
|
|
483
615
|
c["links"] = []
|
|
484
616
|
for n in c.pop("link_names", None) or linked_names(c, entry):
|
|
485
|
-
|
|
486
|
-
|
|
617
|
+
rec = None
|
|
618
|
+
if not built:
|
|
619
|
+
status, cls = "linked: Lean not checked (the project is not built)", "unspecified"
|
|
620
|
+
else:
|
|
621
|
+
rec, why = resolve_link(n, linkrecs.get(n, []), c.get("declared_modules", {}).get(n),
|
|
622
|
+
root, unbuilt, failed)
|
|
623
|
+
status, cls = (why, "unspecified") if why else link_state(rec)
|
|
487
624
|
c["links"].append({"name": n, "status": status, "class": cls,
|
|
488
|
-
"source": link_source(c, entry, n),
|
|
489
|
-
"record": linkrecs.get(n)})
|
|
625
|
+
"source": link_source(c, entry, n), "record": rec})
|
|
490
626
|
for s in c.get("suggestions", []):
|
|
491
|
-
|
|
627
|
+
found = [r for r in linkrecs.get(s["name"], []) if "missing" not in r.get("errors", [])]
|
|
628
|
+
s["record"] = found[0] if len({((r.get("decl") or {}).get("module")) for r in found}) == 1 else None
|
|
492
629
|
if c["links"]:
|
|
493
630
|
worst = max(c["links"], key=lambda l: ["proved", "unspecified", "open", "malformed"]
|
|
494
631
|
.index(l["class"]))
|