Skip to content

Commit 43d4975

Browse files
committed
docs: import arghda-spec.adoc from echo-types/docs/
Bring the original arghda MVP spec into this repo where it belongs. The file was previously at echo-types/docs/arghda-spec.adoc — moved 2026-05-30 as part of the arghda-core extraction per echo-types#159. Verbatim copy at this commit; revisions to follow as arghda's scope evolves independently of echo-types.
1 parent 7c47377 commit 43d4975

1 file changed

Lines changed: 220 additions & 0 deletions

File tree

docs/arghda-spec.adoc

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
// SPDX-License-Identifier: CC-BY-4.0
2+
// SPDX-FileCopyrightText: 2025-2026 Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
3+
= ArghDA MVP Specification
4+
:toc: macro
5+
:toclevels: 2
6+
7+
toc::[]
8+
9+
== Purpose
10+
11+
ArghDA is a lightweight proof-workspace manager. Initial target:
12+
Agda. It exists to close a specific user-experience gap that
13+
`agda-mode` and `agda-language-server` do not: making the
14+
_lifecycle_ of a proof (inbox → working → proven | rejected) a
15+
first-class, visible object, with a thin linter that catches the
16+
silent-failure class _before_ the typechecker.
17+
18+
Scope discipline: small tool, narrow job. Not a proof assistant,
19+
not a replacement for `agda-mode`, not a tactic framework.
20+
21+
== Motivation
22+
23+
From echo-types sessions (see `docs/buchholz-plan.adoc`), the
24+
operator repeatedly hit a specific failure mode:
25+
26+
* a proof file exists, looks like it typechecked, but is missing
27+
`--safe` / `--without-K`, or is not imported from `All.agda`,
28+
or is not pinned in `Smoke.agda`
29+
* the "did it really work?" question is answered only by running
30+
the whole suite, which is slow and emotionally punishing
31+
* there is no visible pipeline: no inbox, no "in-progress", no
32+
"proven" tag; just a flat directory of `.agda` files
33+
34+
The existing ecosystem (see ArghDA scout report: `coq-lsp`,
35+
`VSCoq`, `Alectryon`, `LeanInk`, `Mathlib stats`, `Isabelle/jEdit
36+
PIDE`, `agda-language-server`, `agda-unused`) gives excellent
37+
per-file UX and some library-level dependency views, but nobody
38+
treats proofs as _items flowing through pipeline stages_. That is
39+
the novel contribution.
40+
41+
== Split
42+
43+
Two layers, developed and published as two packages:
44+
45+
`arghda-core`:: Language-agnostic engine. Rust. No UI. Exposes a
46+
CLI, a library API, and a JSON event stream. Runs in CI, standalone,
47+
or embedded.
48+
49+
`arghda-panll`:: PanLL presentation layer. Gossamer webview +
50+
ReScript panel consuming `arghda-core`'s event stream. Lives in the
51+
PanLL surface, probably adjacent to Pane-W.
52+
53+
Rationale for the split:
54+
55+
* Proof triage is useful outside PanLL (students, CI, large collabs).
56+
* Testing `arghda-core` doesn't require booting PanLL.
57+
* PanLL gains a polished dependency rather than an internal subsystem.
58+
* Matches PanLL's existing pattern with `panll_beam`.
59+
60+
== State machine (core)
61+
62+
Four states, implemented as four directories under a workspace root:
63+
64+
[source]
65+
----
66+
<workspace>/
67+
inbox/ -- new or returning proof files
68+
working/ -- operator has picked this up
69+
proven/ -- typecheck + lint clean
70+
rejected/ -- typecheck failed, or lint-block, or manual reject
71+
----
72+
73+
Transitions are _file moves_. This keeps the ground truth on disk,
74+
makes recovery obvious (`mv` it back), and survives ArghDA crashing.
75+
76+
Transition rules:
77+
78+
[cols="1,2,3"]
79+
|===
80+
| From | To | Trigger
81+
82+
| inbox | working | operator claim (explicit)
83+
| working | proven | typecheck clean AND lint clean
84+
| working | rejected | typecheck failed OR lint-hard-block
85+
| rejected | inbox | manual re-queue
86+
| proven | inbox | upstream change invalidates (see DAG below)
87+
|===
88+
89+
Every transition emits a JSON event to a rolling log under
90+
`<workspace>/.arghda/events.jsonl`.
91+
92+
== Linter rules (Agda, v0)
93+
94+
The linter targets the _silent-failure_ class — cases where Agda
95+
appears to succeed but the file is not actually in the verified
96+
suite. Rules, each emitting a structured diagnostic:
97+
98+
* `missing-safe-pragma` — file lacks `{-# OPTIONS --safe --without-K #-}`
99+
* `missing-without-k` — `--safe` without `--without-K` (or vice versa)
100+
* `orphan-module` — module not imported (transitively) from `All.agda`
101+
* `unpinned-headline` — module exports a theorem matching a
102+
headline-naming pattern (operator-configurable regex) but the name
103+
is not pinned in `Smoke.agda` via a `using` clause
104+
* `unjustified-postulate` — `postulate` block without an adjacent
105+
comment line starting with `-- JUSTIFY:`
106+
* `unused-import` — shell out to `agda-unused` and re-emit findings
107+
* `tab-mix` — file mixes tabs and spaces at line start
108+
109+
Severity: `hard-block` (forbids `working → proven`) vs `warn`
110+
(surfaced but non-blocking). Default: `missing-safe-pragma`,
111+
`orphan-module`, `unjustified-postulate` are hard-block; the rest
112+
are warn.
113+
114+
Non-goals for v0: semantic linting, redundancy detection,
115+
style-guide enforcement beyond whitespace.
116+
117+
== DAG JSON schema (v0)
118+
119+
Emitted by `arghda-core dag` as a single JSON document. Consumable by
120+
the PanLL panel, a static HTML viewer, or third-party tools.
121+
122+
[source,json]
123+
----
124+
{
125+
"version": "0.1",
126+
"workspace": "/path/to/workspace",
127+
"generated_at": "ISO-8601",
128+
"nodes": [
129+
{
130+
"id": "Ordinal.Closure",
131+
"file": "proofs/agda/Ordinal/Closure.agda",
132+
"status": "proven",
133+
"lint": { "hard_block": [], "warn": [] },
134+
"headlines": ["C-monotone"]
135+
}
136+
],
137+
"edges": [
138+
{ "from": "Ordinal.Closure", "to": "Ordinal.Base", "kind": "imports" }
139+
],
140+
"blocked": [
141+
{
142+
"node": "Ordinal.Buchholz.Psi",
143+
"blocked_by": ["Ordinal.Buchholz.Closure"],
144+
"reason": "prereq not proven"
145+
}
146+
]
147+
}
148+
----
149+
150+
Renderer is a separate concern; the panel consumes this verbatim.
151+
152+
== Integration points
153+
154+
* **LSP** (coq-lsp pattern) — per-file editor feedback.
155+
* **PIDE async model** (Isabelle) — asynchronous document state
156+
for the "checking now" sub-state within `working`.
157+
* **`agda --only-scope-checking`** — cheap pre-pass for quick
158+
syntactic / import validation before full typecheck.
159+
* **`agda-unused`** — shell out; re-emit diagnostics in the
160+
ArghDA diagnostic format.
161+
* **Alectryon-style rendering** (future) — static HTML render of
162+
proof states as a by-product of `proven` transition.
163+
164+
== Non-goals (MVP)
165+
166+
* Tactic language.
167+
* Writing proofs for the operator.
168+
* IDE replacement.
169+
* Multi-prover support (Coq/Lean/Isabelle postponed to v0.2).
170+
* Distributed execution. A single workspace, a single machine.
171+
172+
== First sprint (v0.1)
173+
174+
Ordered by unblock-value:
175+
176+
. `arghda-core` Rust crate skeleton; `Workspace::open(path)` API.
177+
. Filesystem watcher over `inbox/` and `working/` using `notify`.
178+
. Two linter rules: `missing-safe-pragma`, `orphan-module`.
179+
. `arghda-core check <file>` command: runs agda, captures exit code,
180+
emits a `LintReport` JSON.
181+
. `arghda-core promote <file>` / `arghda-core reject <file>`:
182+
the state-machine CLI.
183+
. `arghda-core dag` emitting the schema above for the current
184+
workspace.
185+
. Minimal end-to-end smoke test over `echo-types` itself as the
186+
first real workspace.
187+
188+
PanLL panel (`arghda-panll`) is v0.2 and deliberately not in this
189+
sprint. The CLI + JSON is the interface contract; the panel is a
190+
consumer.
191+
192+
== Open questions
193+
194+
* Language choice for `arghda-core`: Rust (matches PanLL stack) vs
195+
Zig (matches Gossamer / Burble). Default: Rust, pending operator
196+
pushback.
197+
* Should the `proven` state record a content hash so upstream
198+
changes can invalidate it automatically? Default: yes, SHA-256
199+
of the file plus imports.
200+
* Naming convention for "headlines" — regex default
201+
`^[a-z][A-Za-z0-9-]*$` with export-only filter, operator-overridable
202+
per-workspace in `.arghda/config.toml`.
203+
204+
== Acceptance criteria for v0.1
205+
206+
* End-to-end demo: take `echo-types` at its current commit, place
207+
all `*.agda` files into `inbox/`, run `arghda-core` against it,
208+
observe that every file moves to `proven/` with no hard-blocks,
209+
and that the emitted DAG matches the actual import graph.
210+
* Introduce one synthetic bug (delete `--safe` from a file): observe
211+
that file lands in `rejected/` with the correct diagnostic.
212+
* Introduce one synthetic orphan (new `.agda` not imported from
213+
`All.agda`): observe `orphan-module` hard-block.
214+
215+
== References
216+
217+
* ArghDA scout report (this session): existing proof-workspace
218+
landscape across Coq/Rocq, Lean 4, Isabelle, Agda.
219+
* `docs/buchholz-plan.adoc` — the motivating proof pipeline that
220+
surfaced the silent-failure gap.

0 commit comments

Comments
 (0)