Skip to content

Commit 7dd4a45

Browse files
committed
feat(L16): land agent choreography composition proof + v1.5 surface
1 parent ac544bf commit 7dd4a45

9 files changed

Lines changed: 950 additions & 13 deletions

File tree

LEVEL-STATUS.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ full trajectory and keyword reservations.
1616
| v1.2 | L1-10, L13 | v0.3 sugar | +L13 Module isolation: `module Name isolated { ... }`, `private_memory`, `boundary`. Idris2 proof: ModuleIsolation.idr. Surface enforcement: Checker.checkIsolatedModule. |
1717
| v1.3 | L1-10, L13, L14 | v0.4 sugar | +L14 Session protocols: `session Name { state ...; transition consume X -> yield Y; dual : ...; }`. Idris2 proof: SessionProtocol.idr (SessionHandle parameterised by state index, step soundness, DualPair symmetry). Surface enforcement: Checker.checkSession. 63/63 parser tests. |
1818
| **v1.4** | **L1-10, L13, L14, L15** | **v0.5 sugar** | **+L15 Resource capabilities: `capability NAME;` top-level and isolated-module-body declarations; v1.1 `caps: { ... }` sub-clause becomes load-bearing. Idris2 proof: ResourceCapabilities.idr (DistinctCaps L15-A, ContainedIn + containedTrans L15-B, CallCompatible + callCompose L15-C, FullEffectBudget orthogonality with L8). Surface enforcement: Checker.checkCapabilities + scope-threaded checkDeclaration. L15-A (distinct) + L15-B (well-scoped) live at v1.4; L15-C (call-graph monotone) deferred to v1.4.x (proof already carries the theorem). 76/76 parser tests pass.** |
19-
| v1.5 / v2.0 | L1-L16 | v0.2 sugar | +L16 Agent choreography (composition proof over L13+L14+L15) |
19+
| **v1.5** | **L1-10, L13, L14, L15, L16** | **v0.6 sugar** | **+L16 Agent choreography: `choreography { agent_role ...; message ...; composes: L13 + L14 + L15; }`. Idris2 proof: Choreography.idr (composition-only theorem citing lower levels). Surface enforcement: Checker.checkChoreography (L16-A..L16-D). 88/88 parser tests pass.** |
2020
| L17 (reserved) | L1-L16, **L17** | future | "Layout-proof striation" with `strided_ptr<T>` — removes the projection-only restriction on striated regions |
2121

2222
**L11 (Tropical)** and **L12 (Epistemic)** remain draft-only at v1.1. They are
@@ -38,7 +38,7 @@ natural home for "striation is cheaper" proofs once it lands.
3838
**AST and lexer tokens landed 2026-04-13. Parser rules and Checker module are
3939
the remaining v1.1 work.**
4040

41-
## Current: checked core = L1-10, L11-L12 = draft, v1.1 surface sugar IN PROGRESS
41+
## Current: checked core = L1-10 + L13-L16, L11-L12 = draft
4242

4343
| Level | Name | Idris2 Proof | Zig FFI | Tests | Status |
4444
|-------|------|-------------|---------|-------|--------|
@@ -56,7 +56,8 @@ the remaining v1.1 work.**
5656
| 12 | Epistemic safety | Epistemic.idr | Not yet | None | **Draft only; not in package; standalone check currently fails** |
5757
| 13 | Module isolation | ModuleIsolation.idr | (per-module handles, future) | 12 parser/Checker tests | **v1.2 — Idris2 proof + surface checker live; 007 lowering DONE (task #5)** |
5858
| 14 | Session protocols | SessionProtocol.idr | (typed-state handles, future) | 13 parser/Checker tests | **v1.3 — Idris2 proof + surface checker live; 007 send/receive lowering DONE (task #7)** |
59-
| 15 | Resource capabilities | ResourceCapabilities.idr | (future) | 13 parser/Checker tests | **v1.4 — Idris2 proof + surface checker (L15-A + L15-B) live; L15-C call-graph check deferred to v1.4.x; 007 lowering pending (task #9)** |
59+
| 15 | Resource capabilities | ResourceCapabilities.idr | (future) | 13 parser/Checker tests | **v1.4 — Idris2 proof + surface checker (L15-A + L15-B) live; L15-C call-graph check deferred to v1.4.x; 007 lowering DONE (task #9)** |
60+
| 16 | Agent choreography | Choreography.idr | (future) | 12 parser/Checker tests | **v1.5 — composition proof over L13+L14+L15 live; surface checker enforces L16-A (role targets exist), L16-B (message endpoints declared), L16-C (payload primitive/declared region ref), L16-D (exact `L13 + L14 + L15` composition spec).** |
6061

6162
**[sfap]** = "so far as possible" — proofs are machine-checked in Idris2 with
6263
zero dangerous patterns. They are as complete as the Idris2 type checker can
@@ -94,6 +95,7 @@ toolchain remains future work.
9495
| ModuleIsolation.idr | 0 | 0 | 0 | In package (v1.2 / L13) |
9596
| SessionProtocol.idr | 0 | 0 | 0 | In package (v1.3 / L14) |
9697
| ResourceCapabilities.idr | 0 | 0 | 0 | In package (v1.4 / L15) |
98+
| Choreography.idr | 0 | 0 | 0 | In package (v1.5 / L16) |
9799
| Proofs.idr | 0 | 0 | 0 | In package |
98100
| Tropical.idr | 0 | 0 | 0 | Draft file; standalone check fails |
99101
| Epistemic.idr | 0 | 0 | 0 | Draft file; standalone check fails |

spec/L13-L16-reserved-syntax.adoc

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@ Each is claimed for a specific future level.
5858
| `grant` | L15 | (reserved; not live at v1.4 — future v1.4.x dynamic grant/relinquish refinement)
5959
| `relinquish` | L15 | (reserved; not live at v1.4 — future v1.4.x dynamic grant/relinquish refinement)
6060
| `requires_caps` | L15 | (reserved; not live at v1.4 — future refinement; v1.4 uses `caps:` sub-clause as the surface)
61-
| `choreography` | L16 | Multi-agent protocol declaration
62-
| `agent_role` | L16 | Named role within a choreography
63-
| `message` | L16 | Typed message between roles
64-
| `composes` | L16 | Composition directive linking L13/L14/L15 proofs
61+
| `choreography` | L16 | **LIVE v1.5** — Multi-agent protocol declaration
62+
| `agent_role` | L16 | **LIVE v1.5** — Named role within a choreography
63+
| `message` | L16 | **LIVE v1.5** — Typed message between roles
64+
| `composes` | L16 | **LIVE v1.5** — Composition directive linking L13/L14/L15 proofs
6565
| `striated` | v1.1 | SoA layout annotation on array regions (added v1.1; cost story lands with L11 Tropical)
6666
| `strided_ptr` | L17* | Future: proof-visible strided-pointer variant (reserved for potential L17 "Layout-proof striation")
6767
| `packed` | L17* | Future: AoS-preserving dense layout annotation (reserved; contrast with `striated`)
@@ -310,5 +310,9 @@ These are reserved now so v1.1 sugar and L13–L16 level work do not claim them.
310310
Surface enforcement: `Checker.checkCapabilities` + scope-threaded
311311
`checkDeclaration` (L15-A + L15-B only; L15-C surface analysis deferred
312312
to v1.4.x). Parser tests: 13 (L15) + 63 (prior) = 76 passing.
313-
* v1.5 = v1.4 + L16 checked (or v2.0 if the aggregate library is promoted at this point)
313+
* **v1.5 = v1.4 + L16 checked (LIVE 2026-04-13).** Idris2 proof:
314+
`src/abi/TypedWasm/ABI/Choreography.idr` — composition-only theorem over
315+
L13 + L14 + L15 (no re-proof of lower levels). Surface enforcement:
316+
`Checker.checkChoreography` with L16-A..L16-D. Parser tests: 12 (L16) +
317+
76 (prior) = 88 passing.
314318
* L17 = reserved, unscheduled — "Layout-proof striation" with `strided_ptr<T>`

spec/grammar.ebnf

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,22 @@
33
(*
44
* typed-wasm — Typed Memory Regions for WebAssembly
55
* Format: Extended Backus-Naur Form (EBNF)
6-
* Version: 0.5.0 (v1.4L15 Resource Capabilities)
6+
* Version: 0.6.0 (v1.5L16 Agent Choreography)
77
* Date: 2026-04-13
88
*
9+
* v1.5 additions over v0.5 (L16 Agent choreography):
10+
* - `choreography Name { ... }` declaration form for multi-agent protocol
11+
* composition over L13 + L14 + L15.
12+
* - `agent_role Role : Target;` entries binding choreography roles to
13+
* session/module realisations declared in the same file.
14+
* - `message Msg : From -> To, field_type;` typed message edges.
15+
* - Mandatory composition clause: `composes: L13 + L14 + L15;`
16+
* - Checker enforcements: L16-A role target exists (session/module),
17+
* L16-B message endpoints declared, L16-C payload primitive or declared
18+
* region reference, L16-D composition spec fixed to L13+L14+L15 at v1.5.
19+
* - Idris2 proof artefact: src/abi/TypedWasm/ABI/Choreography.idr —
20+
* composition-only theorem citing L13/L14/L15 witnesses per role.
21+
*
922
* v1.4 additions over v0.4 (L15 Resource Capabilities):
1023
* - `capability NAME ;` top-level and isolated-module-body declaration
1124
* - The v1.1 `caps: { ... }` sub-clause of split effects becomes load-bearing:
@@ -102,7 +115,8 @@ declaration = region_decl
102115
| const_decl (* v1.1 *)
103116
| module_isolated_decl (* v1.2 / L13 *)
104117
| session_decl (* v1.3 / L14 *)
105-
| capability_decl ; (* v1.4 / L15 *)
118+
| capability_decl (* v1.4 / L15 *)
119+
| choreography_decl ; (* v1.5 / L16 *)
106120
107121
(* v1.4 / L15: a capability declaration names an external resource that
108122
functions may require via the `caps: { ... }` sub-clause of the v1.1
@@ -117,6 +131,24 @@ declaration = region_decl
117131
with a pointer to L15+future. *)
118132
capability_decl = 'capability', identifier, ';' ;
119133
134+
(* v1.5 / L16: choreography composes lower-level invariants across
135+
multiple agent roles. `agent_role` binds a choreography role-name to
136+
a same-file session/module target. `message` edges are typed and must
137+
connect declared roles. `composes` is currently fixed to
138+
`L13 + L14 + L15` at v1.5. *)
139+
choreography_decl = 'choreography', identifier, '{',
140+
{ agent_role_decl },
141+
{ message_decl },
142+
'composes', ':', composition_spec, ';',
143+
'}' ;
144+
145+
agent_role_decl = 'agent_role', identifier, ':', identifier, ';' ;
146+
147+
message_decl = 'message', identifier, ':',
148+
identifier, '->', identifier, ',', field_type, ';' ;
149+
150+
composition_spec = 'L13', '+', 'L14', '+', 'L15' ;
151+
120152
(* v1.3 / L14: a session protocol is a finite-state machine over typed
121153
linear handles. Each `state` declares a labelled typed state (optionally
122154
carrying a payload field type), each `transition` lifts a single L10
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
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+
-- Choreography.idr — L16 Agent choreography composition for typed-wasm ABI
5+
--
6+
-- L16 composes three already-proven lower levels:
7+
-- * L13 Module isolation (ModuleIsolation.idr)
8+
-- * L14 Session protocols (SessionProtocol.idr)
9+
-- * L15 Resource capabilities (ResourceCapabilities.idr)
10+
--
11+
-- The point of this module is NOT to re-prove those levels. Instead, L16
12+
-- packages one proof witness per role and lifts that bundle to choreography-
13+
-- level soundness for legal traces.
14+
--
15+
-- NO `believe_me`, NO `postulate`, NO `assert_total`, NO `Admitted`.
16+
-- `%default total`.
17+
18+
module TypedWasm.ABI.Choreography
19+
20+
import Data.List
21+
import Data.List.Elem
22+
23+
import TypedWasm.ABI.ModuleIsolation
24+
import TypedWasm.ABI.SessionProtocol
25+
import TypedWasm.ABI.ResourceCapabilities
26+
27+
%default total
28+
29+
-- ============================================================================
30+
-- L16 Surface Core
31+
-- ============================================================================
32+
33+
||| Nominal role identifier in a choreography.
34+
public export
35+
record AgentRole where
36+
constructor MkAgentRole
37+
roleName : String
38+
39+
public export
40+
Eq AgentRole where
41+
(MkAgentRole a) == (MkAgentRole b) = a == b
42+
43+
||| Typed message edge: sender role, receiver role, payload type.
44+
||| The constructor carries only a label; the payload type is tracked at type
45+
||| level so message declarations remain typed without forcing value-level
46+
||| payload terms into the choreography definition.
47+
public export
48+
data Message : (from : AgentRole) -> (to : AgentRole) -> (payload : Type) -> Type where
49+
MkMessage : (label : String) -> Message from to payload
50+
51+
||| Existential packaging for heterogeneous message payload types.
52+
public export
53+
record MessageDecl where
54+
constructor MkMessageDecl
55+
fromRole : AgentRole
56+
toRole : AgentRole
57+
payloadTy : Type
58+
msg : Message fromRole toRole payloadTy
59+
60+
-- ============================================================================
61+
-- Per-role realisation and lower-level composition witness
62+
-- ============================================================================
63+
64+
||| One role's concrete lower-level realisation.
65+
|||
66+
||| `roleFunctionCaps` is a capability budget witness for the role's runtime
67+
||| entrypoint in `moduleCaps`. L15 containment for this role is obtained by
68+
||| citing `l15bSoundness`.
69+
public export
70+
record RoleRealisation where
71+
constructor MkRoleRealisation
72+
role : AgentRole
73+
isolatedModule : IsolatedModule
74+
sessionProtocol : Protocol
75+
sessionWellFormed : WellFormedProtocol sessionProtocol
76+
moduleCaps : ModuleCaps
77+
roleFunctionCaps : FunctionCaps moduleCaps
78+
79+
||| Per-role bundle of lower-level proof obligations (L13 + L14 + L15).
80+
public export
81+
record RoleRealisationWellFormed (r : RoleRealisation) where
82+
constructor MkRoleRealisationWellFormed
83+
l13Isolation : WellFormedBoundaries r.isolatedModule.modId r.isolatedModule.boundaries
84+
l14SessionLinearity : WellFormedProtocol r.sessionProtocol
85+
l15CapsContainment : ContainedIn r.roleFunctionCaps.required (declared r.moduleCaps)
86+
87+
||| Build the per-role witness by CITING lower-level results:
88+
||| * L13: `isolatedModule.wellFormed`
89+
||| * L14: `sessionWellFormed`
90+
||| * L15: `l15bSoundness roleFunctionCaps`
91+
public export
92+
roleWitness : (r : RoleRealisation) -> RoleRealisationWellFormed r
93+
roleWitness r =
94+
MkRoleRealisationWellFormed
95+
r.isolatedModule.wellFormed
96+
r.sessionWellFormed
97+
(l15bSoundness r.roleFunctionCaps)
98+
99+
||| List-level composition witness: every role in the choreography carries a
100+
||| lower-level well-formedness witness.
101+
public export
102+
data AllRolesWellFormed : List RoleRealisation -> Type where
103+
AllWFNil : AllRolesWellFormed []
104+
AllWFCons : {r : RoleRealisation}
105+
-> {rest : List RoleRealisation}
106+
-> RoleRealisationWellFormed r
107+
-> AllRolesWellFormed rest
108+
-> AllRolesWellFormed (r :: rest)
109+
110+
||| Convenience constructor: derive the list-level witness directly from the
111+
||| role realisation list by reusing `roleWitness` for each role.
112+
public export
113+
deriveRoleWitnesses : (rs : List RoleRealisation) -> AllRolesWellFormed rs
114+
deriveRoleWitnesses [] = AllWFNil
115+
deriveRoleWitnesses (r :: rest) =
116+
AllWFCons (roleWitness r) (deriveRoleWitnesses rest)
117+
118+
-- ============================================================================
119+
-- Choreography object
120+
-- ============================================================================
121+
122+
||| L16 choreography declaration payload:
123+
||| * role list
124+
||| * typed message list
125+
||| * composition witness bundling L13/L14/L15 obligations per role
126+
public export
127+
record Choreography where
128+
constructor MkChoreography
129+
roles : List AgentRole
130+
messages : List MessageDecl
131+
realisations : List RoleRealisation
132+
compositionWitness : AllRolesWellFormed realisations
133+
134+
-- ============================================================================
135+
-- Legal traces
136+
-- ============================================================================
137+
138+
public export
139+
data TraceStep : Type where
140+
TraceMessage : MessageDecl -> TraceStep
141+
142+
public export
143+
Trace : Type
144+
Trace = List TraceStep
145+
146+
||| A legal trace is a sequence of declared choreography messages.
147+
public export
148+
data LegalTrace : (c : Choreography) -> Trace -> Type where
149+
LegalTraceNil : LegalTrace c []
150+
LegalTraceCons : {msg : MessageDecl}
151+
-> (declared : Elem msg c.messages)
152+
-> LegalTrace c rest
153+
-> LegalTrace c (TraceMessage msg :: rest)
154+
155+
-- ============================================================================
156+
-- Choreography soundness (composition-only)
157+
-- ============================================================================
158+
159+
||| Extracted L13 obligations for all roles.
160+
public export
161+
data AllIsolation : List RoleRealisation -> Type where
162+
IsolationNil : AllIsolation []
163+
IsolationCons : {r : RoleRealisation}
164+
-> {rest : List RoleRealisation}
165+
-> WellFormedBoundaries r.isolatedModule.modId r.isolatedModule.boundaries
166+
-> AllIsolation rest
167+
-> AllIsolation (r :: rest)
168+
169+
||| Extracted L14 obligations for all roles.
170+
public export
171+
data AllSessionLinearity : List RoleRealisation -> Type where
172+
SessionNil : AllSessionLinearity []
173+
SessionCons : {r : RoleRealisation}
174+
-> {rest : List RoleRealisation}
175+
-> WellFormedProtocol r.sessionProtocol
176+
-> AllSessionLinearity rest
177+
-> AllSessionLinearity (r :: rest)
178+
179+
||| Extracted L15 obligations for all roles.
180+
public export
181+
data AllCapabilityContainment : List RoleRealisation -> Type where
182+
CapabilityNil : AllCapabilityContainment []
183+
CapabilityCons : {r : RoleRealisation}
184+
-> {rest : List RoleRealisation}
185+
-> ContainedIn r.roleFunctionCaps.required (declared r.moduleCaps)
186+
-> AllCapabilityContainment rest
187+
-> AllCapabilityContainment (r :: rest)
188+
189+
||| Build choreography-wide L13 obligations from the composition witness.
190+
public export
191+
collectIsolation : (rs : List RoleRealisation)
192+
-> AllRolesWellFormed rs
193+
-> AllIsolation rs
194+
collectIsolation [] AllWFNil = IsolationNil
195+
collectIsolation (_ :: rest) (AllWFCons wf restWf) =
196+
IsolationCons wf.l13Isolation (collectIsolation rest restWf)
197+
198+
||| Build choreography-wide L14 obligations from the composition witness.
199+
public export
200+
collectSessionLinearity : (rs : List RoleRealisation)
201+
-> AllRolesWellFormed rs
202+
-> AllSessionLinearity rs
203+
collectSessionLinearity [] AllWFNil = SessionNil
204+
collectSessionLinearity (_ :: rest) (AllWFCons wf restWf) =
205+
SessionCons wf.l14SessionLinearity (collectSessionLinearity rest restWf)
206+
207+
||| Build choreography-wide L15 obligations from the composition witness.
208+
public export
209+
collectCapabilityContainment : (rs : List RoleRealisation)
210+
-> AllRolesWellFormed rs
211+
-> AllCapabilityContainment rs
212+
collectCapabilityContainment [] AllWFNil = CapabilityNil
213+
collectCapabilityContainment (_ :: rest) (AllWFCons wf restWf) =
214+
CapabilityCons wf.l15CapsContainment (collectCapabilityContainment rest restWf)
215+
216+
||| L16 soundness payload:
217+
||| for a legal choreography trace, L13 isolation, L14 session linearity,
218+
||| and L15 capability containment all hold role-wise.
219+
public export
220+
record ChoreographySoundness (c : Choreography) where
221+
constructor MkChoreographySoundness
222+
l13Holds : AllIsolation c.realisations
223+
l14Holds : AllSessionLinearity c.realisations
224+
l15Holds : AllCapabilityContainment c.realisations
225+
226+
||| Main L16 theorem (composition-only):
227+
||| For every legal trace of a choreography, the lower-level obligations hold.
228+
||| The proof is by extraction from `compositionWitness`; no lower-level
229+
||| theorem is re-proven here.
230+
public export
231+
traceSoundness : (c : Choreography)
232+
-> (tr : Trace)
233+
-> LegalTrace c tr
234+
-> ChoreographySoundness c
235+
traceSoundness c tr legal =
236+
let _ = tr in
237+
let _ = legal in
238+
MkChoreographySoundness
239+
(collectIsolation c.realisations c.compositionWitness)
240+
(collectSessionLinearity c.realisations c.compositionWitness)
241+
(collectCapabilityContainment c.realisations c.compositionWitness)

src/abi/typed-wasm.ipkg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ modules = TypedWasm.ABI.Region
1919
, TypedWasm.ABI.ModuleIsolation
2020
, TypedWasm.ABI.SessionProtocol
2121
, TypedWasm.ABI.ResourceCapabilities
22+
, TypedWasm.ABI.Choreography
2223
, TypedWasm.ABI.Proofs
2324
-- Cross-language layout contracts (aggregate library role, ADR-004)
2425
, Layout.Types

0 commit comments

Comments
 (0)