Skip to content

Commit d61ae75

Browse files
ArghDA M10: Mizar adapter — heavy tail complete (a real verify, not detect-only) (#46)
## What The third and last heavy-tail backend — and the "highest uncertainty" one. It turned out **tractable**: Mizar 8.1.15's statically-linked i386 verifier runs on x86_64 with no 32-bit libs, so M10 is a **genuine dogfooded verify**, not the planned detect-only stub. arghda is now a **nine-backend** prover-parametric workspace (agda, agda-cubical, idris2, lean4, coq, isabelle, **mizar** as Assistants; z3, cvc5 as Solvers). **The heavy tail (M8–M10) is complete.** ## How **Adapter — `src/prover/mizar.rs` (`Mizar`)** - Assistant kind, extensions `[miz]`, command `verifier`. - **No lint pack, by design**: Mizar has no `sorry`/`admit` escape hatch — an incomplete proof is simply a verifier error, and a normal article cannot introduce axioms — so soundness *is* the verifier and the verdict is binary. - `check_file`, ground-truthed vs Mizar 8.1.15: `MIZFILES` unset → `Unavailable` (the MML data dir is the precondition — honest, never a fabricated pass); binary absent → `Unavailable`; otherwise copy the `.miz` (+ siblings) to a temp dir, run `accom` then `verifier` (env `MIZFILES`), and read the sibling `<stem>.err` — **empty + exit 0 → `Proven`, non-empty / exit ≠ 0 → `Error`** (Mizar reports errors in `.err`, the authoritative signal). - Imports: the `environ` block's directives (`vocabularies`/`notations`/`theorems`/…), lower-cased to match on-disk stems; MML references are external and dropped. - Roots: none — Mizar has no aggregator convention (honest empty set). - `probe()` overridden to `verifier -v`. **Provisioning at source**: `install_mizar` upgraded from a warn-stub to a real installer (static i386 tarball from `mizar.uwb.edu.pl` → `/opt/mizar` + symlinks), with a `MIZAR_TAR` pin and a `doctor` verify line. **Wired**: `backend_for "mizar"`, `KNOWN_BACKENDS`, all four `--backend` help strings, the CLI about line. ## Verification (actually run) - `cargo fmt --check` — clean - `cargo clippy --all-targets -- -D warnings` — clean - `cargo test` — **167 pass** (+6 mizar unit, +2 mizar integration; the graph tests are hermetic — `environ` text only, run tool-less) - `bash scripts/check-spdx.sh .` — OK **Dogfooded against real Mizar 8.1.15** (`MIZFILES=/opt/mizar`): | fixture | `arghda check --backend mizar` | |---|---| | `good.miz` (`theorem for X being set holds X = X`, importing XBOOLE_0) | `proven` | | `broken.miz` (undefined reference) | `error` | | `empty.miz` (empty environ+begin) | `proven` | - `arghda doctor` → `[OK] mizar assistant Mizar Ver. 8.1.15` ## Scope M10 at 85%. Remaining: local-article cross-references need prel export (`miz2prel`) for the throwaway session; no root convention. 🤖 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 b0697cb commit d61ae75

10 files changed

Lines changed: 507 additions & 25 deletions

File tree

.machine_readable/6a2/STATE.a2ml

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ status = "active" # active | paused | archived
1111

1212
[project-context]
1313
name = "arghda-core"
14-
purpose = "Multi-backend proof-workspace manager — the 'Flying Logic for provers/solvers' engine. A four-state triage workspace (inbox/working/proven/rejected) as file moves, per-backend lint packs targeting the silent-failure class, a backend-parametric import-graph DAG, a demote-only status-propagating reasoning graph, and a JSON + event-stream contract a visual layer (arghda-studio) consumes. Eight backends across both interaction models (Agda, Cubical-Agda, Idris2, Lean4, Coq/Rocq, Isabelle/HOL assistants; Z3, CVC5 solvers). It never proves anything itself; the tools do."
14+
purpose = "Multi-backend proof-workspace manager — the 'Flying Logic for provers/solvers' engine. A four-state triage workspace (inbox/working/proven/rejected) as file moves, per-backend lint packs targeting the silent-failure class, a backend-parametric import-graph DAG, a demote-only status-propagating reasoning graph, and a JSON + event-stream contract a visual layer (arghda-studio) consumes. Nine backends across both interaction models (Agda, Cubical-Agda, Idris2, Lean4, Coq/Rocq, Isabelle/HOL, Mizar assistants; Z3, CVC5 solvers). It never proves anything itself; the tools do."
1515
completion-percentage = 92
1616

1717
[position]
@@ -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 = 90 },
5252
{ name = "M9: Isabelle adapter (--heavy; dogfood tropical-resource-typing .thy)", completion = 90 },
53-
{ name = "M10: Mizar adapter (detect-only first; highest uncertainty)", completion = 0 },
53+
{ name = "M10: Mizar adapter (detect-only first; highest uncertainty)", completion = 85 },
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
@@ -63,8 +63,14 @@ milestones = [
6363
# /opt, symlinked to /usr/local/bin/isabelle; `isabelle version` → Isabelle2025;
6464
# doctor [OK] isabelle. NB the provision script's Isabelle URL was stale
6565
# (/dist/Isabelle2024… 404s once a newer release is current) — FIXED at source
66-
# to the archived /website-<VER>/dist/ path + bumped to Isabelle2025. Mizar
67-
# remains scripted (behind --mizar) but not installed (distribution manual).
66+
# to the archived /website-<VER>/dist/ path + bumped to Isabelle2025. MIZAR NOW
67+
# INSTALLED (2026-07-01) — the "highest uncertainty" one turned out tractable:
68+
# mizar.org → mizar.uwb.edu.pl ships a STATICALLY-LINKED i386 tarball
69+
# (mizar-8.1.15_5.94.1493) that runs on x86_64 with NO 32-bit libs; unpacked to
70+
# /opt/mizar (binaries + MML flat), verifier/accom symlinked to /usr/local/bin;
71+
# `verifier -v` → Mizar 8.1.15; doctor [OK] mizar. Runtime needs MIZFILES=
72+
# /opt/mizar. The provision script's install_mizar was upgraded from a warn-stub
73+
# to a real installer + verify line.
6874
# Remaining M0: `arghda doctor` Rust subcommand (interim: `just doctor` shells
6975
# the script's --verify-only table).
7076
#
@@ -184,6 +190,33 @@ milestones = [
184190
# doctor → [OK] isabelle assistant Isabelle2025. Remaining 10%: session-
185191
# qualified / relative-path imports + dependency-ordered multi-session builds.
186192
#
193+
# M10 landed 2026-07-01 (85%, third heavy-tail backend — and a REAL verify, not
194+
# the planned detect-only). Foundation-first: the "highest uncertainty" one
195+
# turned out tractable — Mizar 8.1.15's static i386 verifier runs on x86_64, so
196+
# it became a genuine dogfood. src/prover/mizar.rs (`Mizar`): Assistant kind,
197+
# extensions [miz], command `verifier`. NO lint pack (empty by design): Mizar
198+
# has no sorry/admit escape hatch — an incomplete proof is just a verifier
199+
# error, and a normal article can't add axioms — so soundness IS the verifier
200+
# (verdict is binary). check_file (ground-truthed vs Mizar 8.1.15): MIZFILES
201+
# unset → Unavailable (the MML data dir is the precondition — honest, not a
202+
# fake pass); binary absent → Unavailable; else copy the .miz (+ siblings) to a
203+
# temp dir, run `accom` then `verifier` (env MIZFILES), and read the sibling
204+
# `<stem>.err` — EMPTY + exit 0 → Proven, non-empty/exit≠0 → Error (Mizar
205+
# reports errors in .err, the authoritative signal). Imports: the `environ`
206+
# block directives (vocabularies/notations/theorems/…), lower-cased to match
207+
# on-disk stems; MML refs external/dropped. Roots: none (Mizar has no
208+
# aggregator convention — honest empty set, nothing wired). probe() overridden
209+
# to `verifier -v`. Wired: backend_for "mizar" + KNOWN_BACKENDS + all four
210+
# --backend help strings + about line. Provision script's install_mizar upgraded
211+
# from a warn-stub to a real installer (static-i386 tarball + symlinks) + a
212+
# verify line + MIZAR_TAR pin. 167 tests (+6 mizar unit +2 mizar integration;
213+
# graph tests hermetic — environ text only, run tool-less). DOGFOODED vs real
214+
# Mizar 8.1.15 (MIZFILES=/opt/mizar): check → good=proven (theorem for X being
215+
# set holds X = X, importing XBOOLE_0) / broken=error / empty=proven; doctor →
216+
# [OK] mizar assistant Mizar Ver. 8.1.15. Remaining 15%: local-article
217+
# cross-references need prel export (miz2prel) for the throwaway session; no
218+
# root convention.
219+
#
187220
# M7 landed 2026-07-01 (70%): the Echidna dispatch seam — completes the
188221
# engine-spine deliverable (M0-M7 + M11). src/dispatch.rs: `Dispatch { Local,
189222
# Echidna { base_url } }` + `run(backend, file, include_root) -> Outcome`
@@ -347,7 +380,8 @@ actions = [
347380
"M3 follow-on: DONE — `reason --workspace <ws>` sources real verdicts from a `proven/` state (workspace_verdicts) + demotes stale-proven via the content-hash closure. Refinement follow-ons bucket now complete.",
348381
"M8 (Coq/Rocq): DONE (90%) — coqc 8.18.0 provisioned + adapter built + dogfooded (proven/admitted/postulated/error) with Section-aware postulate classifier. Remaining: _CoqProject logical paths + dependency-ordered compilation.",
349382
"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.",
350-
"M10 (Mizar): next, foundation-first — detect-only first (distribution is manual/niche via mizar.org; provision honestly, check_file → Unavailable until a real toolchain confirms invocation). Then climb to M6 lake-env, M4 totality lint, M7 Echidna client.",
383+
"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.",
384+
"Next, climb up: M6 (lake-env/LEAN_PATH so imported Lean files get audited), M4 (totality-hole ?name + per-def partial lint for Idris2), M7 (real Echidna HTTP client, feature-gated). Each its own focused draft PR, gate green, real-tool dogfood where installed.",
351385
]
352386

353387
[maintenance-status]
@@ -356,14 +390,15 @@ last-result = "pass" # unknown | pass | warn | fail
356390
open-warnings = 0
357391
open-failures = 0
358392
# `just check` (fmt-check + clippy -D warnings + build + test + SPDX) green
359-
# post-M9: 118 lib + 41 integration = 159 tests pass. codeql.yml added
360-
# (code-scanning gate fix). M9 Isabelle adapter dogfooded vs real Isabelle2025
361-
# (proven/admitted/postulated/error; reason --check; imports edges; ROOT roots;
362-
# wired; doctor [OK] isabelle). M8 Coq adapter dogfooded vs real coqc 8.18.0.
363-
# reason --workspace verdicts+staleness dogfooded. Lean #print axioms audit
364-
# dogfooded. doctor/groove/dispatch dogfooded. EIGHT backends now: agda +
365-
# agda-cubical + idris2 + lean4 + coq + isabelle (Assistant), z3 + cvc5
366-
# (Solver). Dogfooded historically vs echo-types + agda-unused.
393+
# post-M10: 124 lib + 43 integration = 167 tests pass. codeql.yml added
394+
# (code-scanning gate fix). M10 Mizar adapter dogfooded vs real Mizar 8.1.15
395+
# (proven/error via accom+verifier+.err; MIZFILES=/opt/mizar; doctor [OK]
396+
# mizar). M9 Isabelle dogfooded vs Isabelle2025; M8 Coq dogfooded vs coqc
397+
# 8.18.0. reason --workspace verdicts+staleness dogfooded. Lean #print axioms
398+
# audit dogfooded. doctor/groove/dispatch dogfooded. NINE backends now: agda +
399+
# agda-cubical + idris2 + lean4 + coq + isabelle + mizar (Assistant), z3 + cvc5
400+
# (Solver). HEAVY TAIL M8-M10 COMPLETE. Dogfooded historically vs echo-types +
401+
# agda-unused.
367402

368403
[ecosystem]
369404
part-of = ["arghda"]

scripts/provision-provers.sh

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ LEAN_VER="v4.13.0" # tropical-resource-typing lean-toolch
3636
CVC5_VER="1.2.0" # cvc5 static-binary release
3737
COQ_VER="8.18.0" # opam (with --heavy)
3838
ISABELLE_VER="Isabelle2025" # TUM tarball (with --heavy)
39+
MIZAR_TAR="mizar-8.1.15_5.94.1493-i386-linux.tar" # mizar.uwb.edu.pl (--mizar)
3940

4041
STDLIB_DIR=/opt/agda-stdlib
4142
CUBICAL_DIR=/opt/agda-cubical
@@ -218,8 +219,29 @@ install_isabelle() {
218219
}
219220

220221
install_mizar() {
221-
have mizar && { log "mizar present"; return; }
222-
warn "mizar not auto-installed: distribution is manual (mizar.org). Flagged as UNKNOWN."
222+
command -v verifier >/dev/null 2>&1 && { log "mizar (verifier) present"; return; }
223+
# mizar.org (→ mizar.uwb.edu.pl) ships a statically-linked i386 tarball that
224+
# runs on x86_64 with no 32-bit libs. Outer tar → mizbin/mizshare/mizdoc
225+
# .tar.gz; binaries + the MML land flat under /opt/mizar. MIZFILES must point
226+
# there at runtime (verifier/accom read the MML from it).
227+
local base="http://mizar.uwb.edu.pl/~softadm/pub/system/i386-linux"
228+
local tar="${MIZAR_TAR}"
229+
log "installing mizar ${tar} (i386 static, ~55 MB)…"
230+
if curl -fSL -m 300 "${base}/${tar}" -o /tmp/mizar.tar 2>/dev/null; then
231+
mkdir -p /opt/mizar && tar -xf /tmp/mizar.tar -C /opt/mizar 2>/dev/null || true
232+
for inner in mizbin.tar.gz mizshare.tar.gz; do
233+
[ -f "/opt/mizar/${inner}" ] && tar -xzf "/opt/mizar/${inner}" -C /opt/mizar 2>/dev/null
234+
done
235+
ln -sf /opt/mizar/verifier /usr/local/bin/verifier
236+
ln -sf /opt/mizar/accom /usr/local/bin/accom
237+
if command -v verifier >/dev/null 2>&1; then
238+
log "mizar installed; set MIZFILES=/opt/mizar to run checks"
239+
else
240+
warn "mizar unpack produced no verifier binary"
241+
fi
242+
else
243+
warn "mizar download failed: ${base}/${tar}"
244+
fi
223245
}
224246

225247
# =============================================================================
@@ -252,6 +274,7 @@ run_doctor() {
252274
verify "zig" zig version
253275
verify "coqc" coqc --version
254276
verify "isabelle" isabelle version
277+
verify "mizar" verifier -v
255278
[ -f "${CUBICAL_DIR}/cubical.agda-lib" ] \
256279
&& REPORT+=("OK | cubical-lib | ${CUBICAL_DIR}") \
257280
|| REPORT+=("MISSING | cubical-lib | (flag --cubical still works without it)")

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ pub use graph::{build as build_graph, ImportGraph};
3535
pub use groove::{manifest as groove_manifest, GrooveManifest};
3636
pub use lint::{default_rules, rules_with_config, run_lints, LintRule, RuleConfig};
3737
pub use prover::{
38-
default_backend, Agda, AgdaCubical, Backend, BackendKind, Coq, Idris2, Isabelle, Lean, Outcome,
39-
Probe, Smt, Verdict,
38+
default_backend, Agda, AgdaCubical, Backend, BackendKind, Coq, Idris2, Isabelle, Lean, Mizar,
39+
Outcome, Probe, Smt, Verdict,
4040
};
4141
pub use reason::{
4242
build as build_reason, workspace_verdicts, Junct, ReasonDocument, ReasonEdge, ReasonNode,

src/main.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use anyhow::{Context, Result};
55
use arghda_core::lint::LintContext;
66
use arghda_core::{
77
build_dag, build_reason, event, groove_manifest, run_lints, unused, watcher, Agda, AgdaCubical,
8-
Backend, BackendKind, Coq, Dispatch, Idris2, Isabelle, Lean, LintRule, Probe, RuleConfig, Smt,
9-
State, Verdict, Workspace,
8+
Backend, BackendKind, Coq, Dispatch, Idris2, Isabelle, Lean, LintRule, Mizar, Probe,
9+
RuleConfig, Smt, State, Verdict, Workspace,
1010
};
1111
use clap::{Parser, Subcommand};
1212
use std::path::{Path, PathBuf};
@@ -24,6 +24,7 @@ const KNOWN_BACKENDS: &[&str] = &[
2424
"lean4",
2525
"coq",
2626
"isabelle",
27+
"mizar",
2728
"z3",
2829
"cvc5",
2930
];
@@ -38,10 +39,11 @@ fn backend_for(name: &str) -> Result<Box<dyn Backend>> {
3839
"lean4" => Ok(Box::new(Lean)),
3940
"coq" => Ok(Box::new(Coq)),
4041
"isabelle" => Ok(Box::new(Isabelle)),
42+
"mizar" => Ok(Box::new(Mizar)),
4143
"z3" => Ok(Box::new(Smt::z3())),
4244
"cvc5" => Ok(Box::new(Smt::cvc5())),
4345
other => anyhow::bail!(
44-
"unknown backend `{other}` (known: agda, agda-cubical, idris2, lean4, coq, isabelle, z3, cvc5)"
46+
"unknown backend `{other}` (known: agda, agda-cubical, idris2, lean4, coq, isabelle, mizar, z3, cvc5)"
4547
),
4648
}
4749
}
@@ -50,7 +52,7 @@ fn backend_for(name: &str) -> Result<Box<dyn Backend>> {
5052
#[command(
5153
name = "arghda",
5254
version,
53-
about = "Proof-workspace manager for provers/solvers (Agda, Cubical, Idris2, Lean4, Coq, Isabelle, Z3, CVC5)"
55+
about = "Proof-workspace manager for provers/solvers (Agda, Cubical, Idris2, Lean4, Coq, Isabelle, Mizar, Z3, CVC5)"
5456
)]
5557
struct Cli {
5658
#[command(subcommand)]
@@ -78,7 +80,7 @@ enum Cmd {
7880
#[arg(long)]
7981
config: Option<PathBuf>,
8082
/// Backend: `agda` (default), `agda-cubical`, `idris2`, `lean4`,
81-
/// `coq`, `isabelle`, `z3`, `cvc5`.
83+
/// `coq`, `isabelle`, `mizar`, `z3`, `cvc5`.
8284
#[arg(long, default_value = "agda")]
8385
backend: String,
8486
/// Also run the external `agda-unused` analyser and re-emit its
@@ -98,7 +100,7 @@ enum Cmd {
98100
#[arg(long)]
99101
include_root: Option<PathBuf>,
100102
/// Backend: `agda` (default), `agda-cubical`, `idris2`, `lean4`,
101-
/// `coq`, `isabelle`, `z3`, `cvc5`.
103+
/// `coq`, `isabelle`, `mizar`, `z3`, `cvc5`.
102104
#[arg(long, default_value = "agda")]
103105
backend: String,
104106
/// Where the check runs: `local` (default) or `echidna[=<url>]`
@@ -126,7 +128,7 @@ enum Cmd {
126128
#[arg(long)]
127129
config: Option<PathBuf>,
128130
/// Backend: `agda` (default), `agda-cubical`, `idris2`, `lean4`,
129-
/// `coq`, `isabelle`, `z3`, `cvc5`.
131+
/// `coq`, `isabelle`, `mizar`, `z3`, `cvc5`.
130132
#[arg(long, default_value = "agda")]
131133
backend: String,
132134
},
@@ -150,7 +152,7 @@ enum Cmd {
150152
#[arg(long)]
151153
config: Option<PathBuf>,
152154
/// Backend: `agda` (default), `agda-cubical`, `idris2`, `lean4`,
153-
/// `coq`, `isabelle`, `z3`, `cvc5`.
155+
/// `coq`, `isabelle`, `mizar`, `z3`, `cvc5`.
154156
#[arg(long, default_value = "agda")]
155157
backend: String,
156158
/// Run the backend on every node to populate REAL prover verdicts

0 commit comments

Comments
 (0)