Skip to content

Commit da34183

Browse files
ArghDA M10 follow-on: Mizar local-article cross-references (M10 → 95%) (#51)
## What A Mizar article that `Require`s a sibling — `theorems X;` on a local article `X` — is now checkable. Before this, `X` wasn't in any library, so `accom` on the dependent errored. ## How Ground-truthed the export pipeline against real Mizar 8.1.15: to reference a local `X`, `X` must be built into a local library — `accom X; verifier X; exporter X; transfer X` produces `X`'s library files, and `transfer` populates a local `./prel` the accommodator reads. `check_file` now, before checking the target, exports each in-tree transitive dependency in **topological order** (`mizar_transitive_deps` is a cycle-safe post-order DFS over `environ` imports; MML references are skipped) via that 4-tool pipeline in the temp work dir. ## Honesty preserved A broken dependency fails the dependent — no false green: | case | result | |---|---| | `y.miz` with `theorems X;` using `by X:1`, valid `x` | `proven` (was `error` before) | | `ybad` requiring a **broken** `xbad` | `error` | | `reason --check` over the dir | x/y `proven`, xbad/ybad `error` | ## Verification (actually run) - `cargo fmt --check` / `clippy -D warnings` — clean - `cargo test` — **175 pass** (+1 topo-order unit) - `check-spdx.sh` — OK - Dogfooded vs real Mizar 8.1.15 (`MIZFILES=/opt/mizar`) — table above. ## Honest scope The **theorems** cross-reference path is dogfooded end-to-end. The same `accom → verifier → exporter → transfer` pipeline is Mizar's standard library build, so definitions/notations/constructors cross-refs travel the same path, but were **not separately dogfooded** (a correct definitions fixture is finicky to author; I chose not to rabbit-hole). Residual (the 5%): verify those + a session/root convention. Part of the heavy-tail completion cuts — last one next: Isabelle multi-session (M9). 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_012MpYSh6Wy8YMBH2E3qVyT7 --- _Generated by [Claude Code](https://claude.ai/code/session_012MpYSh6Wy8YMBH2E3qVyT7)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent ad7d949 commit da34183

2 files changed

Lines changed: 104 additions & 8 deletions

File tree

.machine_readable/6a2/STATE.a2ml

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ milestones = [
5050
{ name = "M7: Echidna dispatch seam (optional route to orchestrator :8090, same Outcome)", completion = 70 },
5151
{ name = "M8: Coq/Rocq adapter (--heavy provisioning; Section-aware postulate classifier)", completion = 97 },
5252
{ name = "M9: Isabelle adapter (--heavy; dogfood tropical-resource-typing .thy)", completion = 90 },
53-
{ name = "M10: Mizar adapter (detect-only first; highest uncertainty)", completion = 85 },
53+
{ name = "M10: Mizar adapter (detect-only first; highest uncertainty)", completion = 95 },
5454
{ name = "M11: studio JSON freeze (reason/0.1) + Groove manifest", completion = 100 },
5555
]
5656
# M0 provisioning verified in-container 2026-07-01: agda 2.6.3 (+stdlib v2.3
@@ -114,6 +114,26 @@ milestones = [
114114
# --backend idris2` over an ipkg fixture → crt_roots ['App'], App+Helper wired.
115115
# M4 now 95% (remaining: totality-hole `?name` + per-def `partial` lint).
116116
#
117+
# M10 FOLLOW-ON landed 2026-07-01 (M10 85% → 95%): Mizar local-article cross-
118+
# references. Was: `theorems X;` on a sibling article errored (X not in the
119+
# library). GROUND-TRUTHED the export pipeline vs real Mizar 8.1.15: to Require
120+
# a local X, X must be built into a local library — `accom X; verifier X;
121+
# exporter X; transfer X` produces X's library files and `transfer` populates a
122+
# local `./prel` the accommodator reads. check_file now, before checking the
123+
# target, exports each in-tree transitive dep in TOPOLOGICAL order
124+
# (`mizar_transitive_deps` = post-order DFS over environ imports, cycle-safe,
125+
# MML refs skipped) via that 4-tool pipeline in the temp work dir. 175 tests
126+
# (+1 topo-order unit). DOGFOODED vs real Mizar 8.1.15 (MIZFILES=/opt/mizar):
127+
# y.miz with `theorems X;` using `by X:1` → proven (was error pre-fix); the
128+
# honesty case — ybad requiring a BROKEN xbad → error (a broken dep fails the
129+
# dependent, no false green); reason --check → x/y proven, xbad/ybad error.
130+
# HONEST SCOPE: the THEOREMS cross-reference path is dogfooded end-to-end. The
131+
# same accom→verifier→exporter→transfer pipeline is Mizar's standard library
132+
# build, so definitions/notations/constructors cross-refs travel the same path,
133+
# but were NOT separately dogfooded (a definitions fixture is finicky to author
134+
# correctly; not rabbit-holed). Residual 5%: verify definitions/notations
135+
# cross-refs + a session/root convention.
136+
#
117137
# M8 FOLLOW-ON landed 2026-07-01 (M8 90% → 97%): dependency-ordered Coq
118138
# compilation — multi-file projects are now checkable. Was: a bare `coqc B.v`
119139
# where B `Require`s an in-tree A errored "Cannot find a physical path bound to
@@ -453,7 +473,7 @@ actions = [
453473
"M9 (Isabelle): DONE (90%) — Isabelle2025 provisioned + adapter built + dogfooded (proven/admitted/postulated/error) via session-build; ROOT-based roots, imports-clause edges. Remaining: session-qualified imports + dependency-ordered multi-session builds.",
454474
"M10 (Mizar): DONE (85%) — turned out to be a REAL verify, not detect-only: static i386 verifier runs on x86_64; provisioned + adapter (accom+verifier+.err) + dogfooded (proven/error). HEAVY TAIL M8-M10 COMPLETE. Remaining: local-article prel export.",
455475
"M7 client INVESTIGATED 2026-07-01 → BLOCKED (stub stays): no confirmed Echidna HTTP contract exists (dispatch.rs says API unconfirmed; ECOSYSTEM.a2ml gives no endpoints/schema; the echidna repo is out of this session's access scope). Building a client would mean inventing an unverifiable contract — forbidden. Unblock: a published Echidna API + a reachable instance to dogfood; then wire Dispatch::run behind a cargo feature. ROADMAP TERMINUS — all tractable items done; M7's client is the sole residual, externally blocked.",
456-
"HEAVY-TAIL COMPLETION CUTS (owner asked for these 2026-07-01, doing foundation-first, one PR each, real-tool dogfood): [DONE] Coq dependency-ordered compilation (M8 90→97%); [NEXT] Mizar local-article prel export via miz2prel so cross-article refs check (M10 85→~100%); [THEN] Isabelle session-qualified imports + multi-session builds (M9 90→~100%). Residual after: Coq _CoqProject custom -Q/-R prefixes (3%); arghda-studio visual layer (separate repo, out of this session's scope; AffineScript).",
476+
"HEAVY-TAIL COMPLETION CUTS (owner asked 2026-07-01, foundation-first, one PR each, real-tool dogfood): [DONE] Coq dependency-ordered compilation (M8 90→97%); [DONE] Mizar local-article cross-refs via accom/verifier/exporter/transfer export pipeline (M10 85→95%, theorems path dogfooded); [NEXT/LAST] Isabelle session-qualified imports + multi-session builds (M9 90→~100%). Residual after: Coq _CoqProject custom -Q/-R prefixes (3%); Mizar definitions/notations cross-refs not separately dogfooded (5%); arghda-studio visual layer (separate repo, out of this session's scope; AffineScript).",
457477
]
458478

459479
[maintenance-status]
@@ -462,10 +482,11 @@ last-result = "pass" # unknown | pass | warn | fail
462482
open-warnings = 0
463483
open-failures = 0
464484
# `just check` (fmt-check + clippy -D warnings + build + test + SPDX) green
465-
# post-M8-deporder: 131 lib + 43 integration = 174 tests pass. M8 dependency-
466-
# ordered Coq compilation dogfooded vs real coqc 8.18.0 (A←B←C chain → all
467-
# proven; transitive admit demotes the dependent's effective verdict, not
468-
# whitewashed). M4 totality-hole + partial lint dogfooded vs real idris2 0.7.0.
485+
# post-M10-crossref: 132 lib + 43 integration = 175 tests pass. M10 Mizar
486+
# local-article cross-refs dogfooded vs real Mizar 8.1.15 (y requires local x →
487+
# proven; broken dep → dependent error). M8 dependency-ordered Coq compilation
488+
# dogfooded vs real coqc 8.18.0 (A←B←C chain → all proven; transitive admit
489+
# demotes the dependent's effective verdict). M4 totality lint dogfooded vs idris2.
469490
# M6 lake-env import resolution dogfooded vs real Lean 4.13.0 + Lake 5.0.0
470491
# (imported file in a built lake project → proven; outside → error). codeql.yml added
471492
# (code-scanning gate fix). M10 Mizar adapter dogfooded vs real Mizar 8.1.15

src/prover/mizar.rs

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@
2727
//! so [`crate::graph::module_name_of`] is reused. Import edges come from the
2828
//! `environ` block's directives (`vocabularies`/`notations`/`theorems`/…),
2929
//! lower-cased to match the on-disk stem; only in-tree articles become edges
30-
//! (the MML is external). Local-article prel export (`miz2prel`) and a root
31-
//! convention are documented follow-ons.
30+
//! (the MML is external). Local-article cross-references are supported:
31+
//! [`Backend::check_file`] exports each in-tree dependency in topological order
32+
//! (accom → verifier → exporter → transfer, populating a local `./prel` the
33+
//! accommodator reads) before checking the target, so a `theorems X;` on a
34+
//! sibling article `X` resolves. A session/root convention remains a follow-on.
3235
3336
use super::{probe_tool_arg, Backend, BackendKind, Outcome, Probe, Verdict};
3437
use crate::graph;
@@ -123,6 +126,25 @@ impl Backend for Mizar {
123126
}
124127
let _ = fs::copy(file, work.join(format!("{stem}.miz")));
125128

129+
// Build the target's in-tree dependencies into a local library so its
130+
// `theorems`/`definitions`/… directives resolve: for each dep in
131+
// topological order (deps before dependents), run the export pipeline
132+
// accom → verifier → exporter → transfer, which populates `./prel` in
133+
// the work dir (the accommodator reads local library files from there).
134+
// External MML articles are skipped (resolved from MIZFILES). Verdict-
135+
// affecting failures surface honestly as a non-empty target `.err`.
136+
let src = fs::read_to_string(file).unwrap_or_default();
137+
let deps = mizar_transitive_deps(&parse_environ_imports(&src), include_root);
138+
for dep in &deps {
139+
for tool in ["accom", "verifier", "exporter", "transfer"] {
140+
let _ = Command::new(tool)
141+
.arg(dep)
142+
.current_dir(&work)
143+
.env("MIZFILES", &mizfiles)
144+
.output();
145+
}
146+
}
147+
126148
// Step 1: accommodate the environment.
127149
let accom = Command::new("accom")
128150
.arg(&stem)
@@ -223,6 +245,40 @@ impl Backend for Mizar {
223245
}
224246
}
225247

248+
/// The in-tree transitive article dependencies of a Mizar file, given the
249+
/// articles its `environ` block references, in dependency-first (topological)
250+
/// order — so exporting the list left-to-right satisfies every later `accom`.
251+
/// External MML articles (absent under `include_root`) are skipped. Cycle-safe
252+
/// via the visited set.
253+
fn mizar_transitive_deps(direct: &[String], include_root: &Path) -> Vec<String> {
254+
let mut visited = std::collections::HashSet::new();
255+
let mut order = Vec::new();
256+
for m in direct {
257+
mizar_visit_dep(m, include_root, &mut visited, &mut order);
258+
}
259+
order
260+
}
261+
262+
fn mizar_visit_dep(
263+
module: &str,
264+
include_root: &Path,
265+
visited: &mut std::collections::HashSet<String>,
266+
order: &mut Vec<String>,
267+
) {
268+
if !visited.insert(module.to_string()) {
269+
return;
270+
}
271+
// Only in-tree articles resolve to a readable `.miz`; MML articles are
272+
// left for MIZFILES.
273+
let Ok(src) = fs::read_to_string(include_root.join(format!("{module}.miz"))) else {
274+
return;
275+
};
276+
for imp in parse_environ_imports(&src) {
277+
mizar_visit_dep(&imp, include_root, visited, order);
278+
}
279+
order.push(module.to_string());
280+
}
281+
226282
/// Extract the articles referenced by a Mizar `environ` block's directives
227283
/// (`vocabularies`/`notations`/`theorems`/…), lower-cased to match on-disk
228284
/// stems. `::` line comments are stripped; only the region between `environ`
@@ -330,6 +386,25 @@ mod tests {
330386
assert!(Mizar.lint_rules(&RuleConfig::default()).unwrap().is_empty());
331387
}
332388

389+
#[test]
390+
fn transitive_deps_are_topologically_ordered() {
391+
// z requires y; y requires x; x is a leaf. Build order for z must be
392+
// [x, y] (deps before dependents); MML refs are skipped.
393+
let tmp = tempfile::tempdir().unwrap();
394+
let r = tmp.path();
395+
std::fs::write(r.join("x.miz"), "environ\nbegin\n").unwrap();
396+
std::fs::write(r.join("y.miz"), "environ\n theorems X;\nbegin\n").unwrap();
397+
std::fs::write(r.join("z.miz"), "environ\n theorems Y, XBOOLE_0;\nbegin\n").unwrap();
398+
let deps =
399+
mizar_transitive_deps(&parse_environ_imports("environ\n theorems Z;\nbegin\n"), r);
400+
assert_eq!(
401+
deps,
402+
vec!["x".to_string(), "y".to_string(), "z".to_string()]
403+
);
404+
// The MML article is not staged as an in-tree dep.
405+
assert!(!deps.iter().any(|m| m == "xboole_0"));
406+
}
407+
333408
#[test]
334409
fn check_file_is_honest_about_availability() {
335410
// Never a fabricated pass, whatever the environment: with MIZFILES

0 commit comments

Comments
 (0)