Skip to content

Commit f3ca344

Browse files
hyperpolymathclaude
andcommitted
docs(local-coord-mcp): proof schedule — 20 obligations, prioritised
Enumerates every formal-verification obligation the cartridge carries: 4 already-proved (loopback, port, federation, session token), 10 new (durability record format, CRC truncation, replay-equivalence, quarantine state machine, FIFO, monotonicity, supervisor gating, Tier-4 forbidden list, Nickel soundness, ABI correspondence), and 5 deferred Phase 2+ (choreographic, epistemic, echo, tropical, federation primacy). Keystone theorem is P-06 replay-equivalence: persist-then-replay ≡ direct execution. Unlocks Task #8 E2E sign-off. Prover choice defaults to Idris2 (already in use beside existing SafeLocalCoord.idr / Protocol.idr). Agda reserved for Phase 3 echo-type work (upstream `echo-types/` repo as dogfood consumer). Lean4 optional for P-12 risk-ladder soundness only. P0 block (6 days): P-04, P-05, P-06, P-07 before Task #8 sign-off. P1 block (3.5 days): P-08…P-11 before Task #13 track-record. P2 block (2.5 days): P-12, P-13 triggered by Task #17. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent edb7a78 commit f3ca344

1 file changed

Lines changed: 357 additions & 0 deletions

File tree

Lines changed: 357 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,357 @@
1+
// SPDX-License-Identifier: PMPL-1.0-or-later
2+
// Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3+
4+
= local-coord-mcp — proof schedule
5+
:author: Jonathan D.A. Jewell
6+
:date: 2026-04-20
7+
:toc: macro
8+
:version: 1
9+
10+
Companion to `SafeLocalCoord.idr` (already-proved invariants) and
11+
`Protocol.idr` (message-passing algebra). This document enumerates every
12+
formal-verification obligation the cartridge carries, ranks them by
13+
priority, names the prover, and sequences the work.
14+
15+
Scope is *Phase 1* (local, hermetic). Phase 2+ obligations (choreographic /
16+
epistemic / echo / tropical) are listed but deferred per
17+
`Desktop/COORD-MCP-DESIGN-LOG.md` Appendices H-J.
18+
19+
toc::[]
20+
21+
== Summary
22+
23+
[cols="1,4,1,1,2",options="header"]
24+
|===
25+
| # | Obligation | Prior | Status | Prover
26+
| P-00 | Loopback-only bind | — | ✅ done | Idris2
27+
| P-01 | Port in non-privileged range | — | ✅ done | Idris2
28+
| P-02 | Federation policy ≡ LocalOnly uninhabited elsewhere | — | ✅ done | Idris2
29+
| P-03 | Session-token non-empty on issue | — | ✅ done (type-level) | Idris2
30+
| P-04 | Record format invariants (magic ∧ version ∧ CRC) | P-00…P-03 | P0 | Idris2
31+
| P-05 | CRC truncation tolerance (prefix-closed replay) | P-04 | P0 | Idris2
32+
| P-06 | Replay-equivalence (persist-then-replay ≡ direct execute) | P-04, P-05 | P0 | Idris2
33+
| P-07 | Quarantine state machine (determinism + monotonicity) | P-06 | P0 | Idris2
34+
| P-08 | Ring-buffer FIFO correctness under replay | P-06 | P1 | Idris2
35+
| P-09 | Persistence monotonicity (commits cannot un-happen) | P-05, P-06 | P1 | Idris2
36+
| P-10 | Supervisor privilege gating (env-var secret necessary) | P-03 | P1 | Idris2
37+
| P-11 | Tier-4 forbidden-list schema-level reject for `supervised` | P-10 | P1 | Nickel + Idris2
38+
| P-12 | Nickel-contract soundness wrt risk-ladder spec | P-11 | P2 | Lean4 ‖ Idris2
39+
| P-13 | Zig ↔ Idris2 ABI correspondence (hardcoded `127.0.0.1` realises `IsIPv4Loop`) | P-00 | P2 | Idris2 + SPARK-style assertions
40+
| P-14 | Token unforgeability (probabilistic; 128-bit CSPRNG) | P-03 | documented | prose argument
41+
| P-15 | Choreographic types for supervisor/attestation flow | P-06, P-07 | Phase 2 (deferred) | Idris2 session types
42+
| P-16 | Epistemic types for context-knowledge-witness | P-15 | Phase 2 (deferred) | Idris2 + A2ML tags
43+
| P-17 | Echo-type formalisation of audit + summary + hash chain | P-15, P-16 | Phase 3 (deferred) | Agda (echo-types repo)
44+
| P-18 | Tropical-semiring model of TTL + trust | P-17 | Phase 3 (deferred) | Agda (EchoTropical)
45+
| P-19 | Cross-site primacy ceremony | P-15…P-18 | Phase 4 (deferred) | Idris2 + Agda
46+
|===
47+
48+
Stage priorities:
49+
50+
P0 (**must land before Task #8 e2e sign-off**) → P-04, P-05, P-06, P-07.
51+
52+
P1 (**should land before track-record work, Task #13**) → P-08, P-09, P-10, P-11.
53+
54+
P2 (**nice-to-have; unblocks Task #17 Deno shim formal verification**) → P-12, P-13.
55+
56+
== Already proved — carry forward
57+
58+
=== P-00 Loopback-only bind
59+
60+
`SafeLocalCoord.loopbackToString` is total, and `IsLoopback addr` has
61+
exactly two inhabitants (`IsIPv4Loop`, `IsIPv6Loop`). `BindConfig`
62+
requires a `LoopbackAddr` value, and the only constructors map to
63+
"127.0.0.1" or "::1". `wildcardNotLoopback : IsLoopback "0.0.0.0" -> Void`
64+
closes the negative case.
65+
66+
=== P-01 Port range
67+
68+
`ValidPort p` requires `LTE 1024 p` and `LTE p 65535` implicit args.
69+
`coordPortValid : ValidPort 7745` is the specific instance used.
70+
71+
=== P-02 Federation opt-out
72+
73+
`FederationPolicy` has one constructor (`LocalOnly`). `IsFederated` is
74+
defined with no constructor — uninhabited. `localOnlyNotFederated`
75+
closes the case.
76+
77+
=== P-03 Session token non-emptiness
78+
79+
`SessionToken`'s constructor demands `NonEmpty (unpack tok)`.
80+
81+
These are the spine SafeLocalCoord.idr already enforces. Every new
82+
obligation below composes with them.
83+
84+
== New obligations (this task + Task #7 durability layer)
85+
86+
=== P-04 Record format invariants [P0]
87+
88+
*Claim.* For every record `r` successfully decoded by the replay
89+
iterator, `r.magic = MAGIC ∧ r.format_version = 1 ∧ crc32(header(r) ‖
90+
payload(r)) = r.crc`.
91+
92+
*Artefact.* `abi/LocalCoord/Durability.idr` defines a record type
93+
`DurableRecord` whose constructor requires all three witnesses as
94+
implicit args. `decodeOne : BitStream -> Maybe DurableRecord` total.
95+
96+
*Dependencies.* Idris2 library for CRC32 (or a cheap algebraic stand-in
97+
for the proof; the CRC need only be opaque + extensional).
98+
99+
*Acceptance.* `decodeOne` is shown to produce only well-formed records;
100+
any corruption yields `Nothing`.
101+
102+
=== P-05 CRC truncation tolerance [P0]
103+
104+
*Claim.* For any log `L` with a valid prefix `L_good` followed by a
105+
corrupt tail `L_bad` (bad magic, wrong version, or failed CRC), replay
106+
accepts exactly the events in `L_good` and emits nothing for `L_bad`.
107+
108+
*Artefact.* `Durability.idr`:
109+
`replay : BitStream -> List DurableRecord` total + a corollary
110+
`replayPrefixClosed : (L_good, L_bad : BitStream) -> (allValid L_good) ->
111+
(¬ allValid L_bad) -> replay (L_good ‖ L_bad) = replay L_good`.
112+
113+
*Dependencies.* P-04.
114+
115+
*Acceptance.* Matches `test "replay stops at CRC corruption"` in
116+
`coord_durability.zig` — property-test lines up with theorem statement.
117+
118+
=== P-06 Replay-equivalence [P0 — keystone theorem]
119+
120+
*Claim.* Let `σ : State` be the coord in-memory state. Let `step :
121+
State -> Mutation -> State` be the direct mutation step. Let `logStep :
122+
LogBuffer -> Mutation -> LogBuffer` be the append side. Let `replayInto
123+
: LogBuffer -> State -> State` be the dispatcher. Then for any
124+
mutation sequence `ms : List Mutation` and initial `σ0`,
125+
126+
foldl step σ0 ms ≡ replayInto (foldl logStep [] ms) σ0
127+
128+
*Interpretation.* Persist-then-replay is observationally equivalent to
129+
direct execution. The durability layer never changes semantics.
130+
131+
*Artefact.* `abi/LocalCoord/Durability.idr` bundles `step`, `logStep`,
132+
`replayInto` with the equivalence lemma `replayEquivalent`.
133+
134+
*Dependencies.* P-04, P-05. Requires encoding coord `State` (peers,
135+
claims, quarantine, next_request_id) in Idris2 — 80% overlap with
136+
`Protocol.idr` state.
137+
138+
*Acceptance.* Unit-tested empirically already by
139+
`test "restart replay restores peer, claim, inbox, quarantine"`; proof
140+
closes the case for arbitrary mutation sequences.
141+
142+
*Subtlety.* The replay dispatcher uses "first free slot" for quarantine
143+
reconstruction. The theorem must state slot assignments need not match
144+
the original run — only the *active-entry-set* (modulo slot identity)
145+
must. This is the right abstraction since callers address entries by
146+
`request_id`, not by slot index.
147+
148+
=== P-07 Quarantine state machine [P0]
149+
150+
*Claim.* For every `request_id r`, the log contains at most one terminal
151+
event among `{QUAR_APPROVE r, QUAR_REJECT r}` after `QUAR_ADD r`. After
152+
a terminal event, no further events reference `r`.
153+
154+
*State chart.*
155+
[cols="1,1,1,1",options="header"]
156+
|===
157+
| State | QUAR_ADD | QUAR_APPROVE | QUAR_REJECT
158+
| initial | → pending (ok) | error | error
159+
| pending | error | → approved (ok) | → rejected (ok)
160+
| approved | error | error | error
161+
| rejected | error | error | error
162+
|===
163+
164+
*Artefact.* `abi/LocalCoord/Quarantine.idr` — state-machine witness with
165+
`QuarState` enum, `validTransition` predicate, and a soundness lemma
166+
that the event stream respects it.
167+
168+
*Dependencies.* P-06.
169+
170+
*Acceptance.* Existing `coord_approve` / `coord_reject` are single-shot
171+
(they deactivate the entry); the code meets the spec already — proof
172+
just makes it type-level.
173+
174+
=== P-08 Ring-buffer FIFO correctness [P1]
175+
176+
*Claim.* Under a schedule of `INBOX_PUSH(peer, msg_i)` and
177+
`INBOX_POP(peer)` events with the invariant `count ≤ MAX_MESSAGES`, the
178+
sequence of messages returned by consecutive `coord_receive` calls is
179+
the sub-sequence of pushed messages whose indices exceed the number of
180+
prior pops. (FIFO.)
181+
182+
*Artefact.* `abi/LocalCoord/RingBuffer.idr` — with `Vect n Msg` indexed
183+
by queue depth + push/pop operations + `popOrderFifo` lemma.
184+
185+
*Dependencies.* P-06 (to lift single-peer reasoning to the replay-aware
186+
form).
187+
188+
*Acceptance.* Corresponds to the `"send and receive direct message"`
189+
and `"broadcast message"` Zig tests.
190+
191+
=== P-09 Persistence monotonicity [P1]
192+
193+
*Claim.* Let `L_t` be the log at wall-clock time `t`. For `t1 < t2`
194+
without intervening truncation or CRC-destroying corruption, `replay
195+
L_t1 ⊆ replay L_t2` (prefix-wise).
196+
197+
*Artefact.* `Durability.idr` lemma `replayMonotone`.
198+
199+
*Dependencies.* P-05.
200+
201+
*Acceptance.* Matches the in-code guarantee that `logPeerAdd` et al.
202+
only *append*, never overwrite.
203+
204+
=== P-10 Supervisor privilege gating [P1]
205+
206+
*Claim.* There is no execution in which `peers[i].role = supervisor`
207+
without one of:
208+
209+
. a prior call to `coord_promote_to_supervisor(tok_i, secret, ...)` with
210+
`secret ≡ getenv(BOJ_SUPERVISOR_TOKEN)` (constant-time match), *or*
211+
. a test-only direct mutation (explicitly out of scope — the proof
212+
applies to the public API only).
213+
214+
*Artefact.* `abi/LocalCoord/Role.idr` — `Role` type with phantom
215+
witness `PromotedVia`; public API functions require a `PromotedVia`
216+
argument to produce a `supervisor`-tagged peer.
217+
218+
*Dependencies.* P-03.
219+
220+
*Acceptance.* Corresponds to the run-time rejection paths already
221+
wired (return codes -3 / -4 / promote-requires-env-var).
222+
223+
=== P-11 Tier-4 forbidden list [P1]
224+
225+
*Claim.* For any envelope `e` with `sender_role = supervised` and
226+
`op_kind` matching a Tier-4 forbidden pattern (force-push, branch
227+
delete, public-repo create, license change, always-private-repo touch),
228+
`validate e` rejects.
229+
230+
*Artefact.* New `forbiddenT4Patterns` predicate in
231+
`coord-messages-contracts.ncl` + Idris2 wrapper proving
232+
exhaustiveness over the current taxonomy (schema-driven).
233+
234+
*Dependencies.* P-10.
235+
236+
*Acceptance.* Gates the envelope before it reaches the FFI.
237+
238+
=== P-12 Nickel-contract soundness wrt risk-ladder spec [P2]
239+
240+
*Claim.* The four dependent contracts (TierContextGate,
241+
TierAttestationGate, UrgentDirectRestriction, TierOverrideJustification)
242+
are sound wrt a Lean4 model of the risk ladder: every envelope the
243+
ladder should reject is rejected, and every envelope the ladder should
244+
accept is accepted.
245+
246+
*Artefact.* `proofs/RiskLadder.lean` — model of the ladder + contract
247+
equivalence theorem. Optional: translate back to Idris2 if we want a
248+
single-prover house.
249+
250+
*Dependencies.* P-11. Prover tentative; Idris2 can also do this.
251+
252+
*Acceptance.* Closes the Nickel-vs-Zig boundary question currently open
253+
in Appendix K.
254+
255+
=== P-13 Zig ↔ Idris2 ABI correspondence [P2]
256+
257+
*Claim.* The Zig constant `BIND_ADDR = [4]u8{127,1,0,1}` together with
258+
`BIND_PORT = 7745` faithfully realises `coordBindConfig` from
259+
`SafeLocalCoord.idr`.
260+
261+
*Artefact.* An extraction-style check: Idris2 generates a C header
262+
declaring `BIND_ADDR`/`BIND_PORT`; Zig imports it. Any divergence is a
263+
compile error.
264+
265+
*Dependencies.* P-00.
266+
267+
*Acceptance.* Pure mechanical — turns a convention into a constraint.
268+
269+
== Deferred (Phase 2+)
270+
271+
=== P-15 Choreographic types
272+
273+
Model the `supervised → server → {opus, attester} → server → target`
274+
protocol as a session type. Compile-time enforcement replaces run-time
275+
imperative checks in `coord_send_gated`.
276+
277+
Reference: Appendix H in design log.
278+
279+
=== P-16 Epistemic types
280+
281+
Rename `context_fetch_id` to `knowledge_witness`; formalise per-role
282+
epistemic policy. Track what each peer knows, with K_A(φ) logic.
283+
284+
Reference: Appendix H.
285+
286+
=== P-17 Echo-type formalisation
287+
288+
Use `echo-types/` bridges (`EchoChoreo`, `EchoEpistemic`, `EchoTropical`)
289+
to prove audit + summary + hash-chain behave as echo types — structured
290+
irreversibility with retained constraint.
291+
292+
Reference: Appendix I.
293+
294+
=== P-18 Tropical-semiring TTL/trust
295+
296+
Model watchdog TTLs as tropical max, trust composition as tropical min.
297+
Integrates with P-17.
298+
299+
Reference: Appendix J.
300+
301+
=== P-19 Cross-site primacy ceremony (v2 federation)
302+
303+
When Phase 4 lands, prove the authoritative-site model provides primacy
304+
transfer as a choreographic + epistemic ceremony.
305+
306+
Reference: Appendix G.
307+
308+
== Work schedule
309+
310+
.P0 block — before Task #8 E2E sign-off
311+
1. P-04 (record format) — ~1 day — `abi/LocalCoord/Durability.idr`, smallest theorem, unlocks rest.
312+
2. P-05 (CRC truncation) — ~1 day — prefix-closure lemma on top of P-04.
313+
3. P-06 (replay-equivalence) — ~3 days — biggest single theorem, needs `State` encoding. Most of the value.
314+
4. P-07 (quarantine state machine) — ~1 day — simple state chart, well-isolated.
315+
316+
.P1 block — before Task #13 track-record
317+
5. P-08 (FIFO) — ~1 day — standard Vect-indexed argument.
318+
6. P-09 (monotonicity) — ~0.5 day — corollary of P-05.
319+
7. P-10 (supervisor privilege) — ~1 day — phantom-witness refactor.
320+
8. P-11 (Tier-4 forbidden) — ~1 day — schema + Idris2 wrapper.
321+
322+
.P2 block — nice-to-have; triggered by Task #17 Deno shim
323+
9. P-12 (Nickel soundness) — ~2 days.
324+
10. P-13 (Zig↔Idris2 correspondence) — ~0.5 day — mostly plumbing.
325+
326+
.Phase 2+ — deferred; revisit when moving from v1
327+
11. P-15 through P-19 — scheduled by federation triggers, not by calendar.
328+
329+
Estimate totals: P0 ≈ 6 days, P1 ≈ 3.5 days, P2 ≈ 2.5 days. Comfortably
330+
one Claude-calendar-week of focused proof work if taken end-to-end.
331+
332+
== Notes on prover choice
333+
334+
Idris2 remains the default — proofs for a cartridge ABI belong next to
335+
the existing `SafeLocalCoord.idr` and `Protocol.idr`. Idris2 handles
336+
everything through P-13.
337+
338+
Agda enters only for Phase 3 echo-type + tropical work, consuming the
339+
`echo-types/` bridge library. No echo-type obligation lives inside the
340+
cartridge repo — it lands upstream in `echo-types/` with coord as the
341+
dogfood consumer.
342+
343+
Lean4 is listed as an alternative for P-12 only, and only if the user
344+
wants an external mathlib-backed model of the ladder; otherwise Idris2
345+
does it.
346+
347+
No part of the schedule needs Coq/Rocq or SPARK/Ada — those are
348+
reserved for upstream proof-heavy consumers (007, Cerro-Torre).
349+
350+
== Cross-references
351+
352+
* Already-proved obligations: `SafeLocalCoord.idr`, `Protocol.idr`.
353+
* Phase 2+/Phase 3 rationale: `Desktop/COORD-MCP-DESIGN-LOG.md`
354+
Appendices H, I, J, K.
355+
* Durability module: `../../ffi/coord_durability.zig`.
356+
* Envelope schema + contracts:
357+
`../../schemas/coord-messages.ncl`, `coord-messages-contracts.ncl`.

0 commit comments

Comments
 (0)