|
| 1 | +-- SPDX-License-Identifier: MPL-2.0 |
| 2 | +-- Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk> |
| 3 | +-- |
| 4 | +||| Layer-3 ABI invariants for iseriser, built over the SAME model as the |
| 5 | +||| Layer-2 flagship (`Iseriser.ABI.Semantics`): `Component`, `Scaffold`, |
| 6 | +||| `Has`, and `Conformant`. |
| 7 | +||| |
| 8 | +||| The Layer-2 theorem DECIDES conformance of a *given* scaffold. The |
| 9 | +||| properties here are deeper and structurally distinct: |
| 10 | +||| |
| 11 | +||| (1) GENERATION SOUNDNESS (correct-by-construction): |
| 12 | +||| `genScaffold` is a total generator that, for any `LanguageModel`, |
| 13 | +||| provably emits a Conformant scaffold — `(s ** Conformant s)`. The |
| 14 | +||| meta-framework does not merely *check* scaffolds; it *produces* |
| 15 | +||| conformant ones, with the proof carried alongside. |
| 16 | +||| |
| 17 | +||| (2) UPWARD-CLOSURE / MONOTONICITY (an algebraic closure law): |
| 18 | +||| Conformance is preserved under extension. Prepending any extra |
| 19 | +||| components to a Conformant scaffold yields a Conformant scaffold. |
| 20 | +||| This is proved via a genuine `Elem`-weakening lemma, not asserted. |
| 21 | +||| |
| 22 | +||| Both are accompanied by a POSITIVE control (a concrete generated witness) |
| 23 | +||| and NEGATIVE / non-vacuity controls (a `Not (...)` refutation, plus a |
| 24 | +||| `Dec` whose completeness is machine-checked). |
| 25 | + |
| 26 | +module Iseriser.ABI.Invariants |
| 27 | + |
| 28 | +import Iseriser.ABI.Types |
| 29 | +import Iseriser.ABI.Semantics |
| 30 | +import Data.List.Elem |
| 31 | + |
| 32 | +%default total |
| 33 | + |
| 34 | +-------------------------------------------------------------------------------- |
| 35 | +-- Elem weakening: the structural lemma the closure law rests on |
| 36 | +-------------------------------------------------------------------------------- |
| 37 | + |
| 38 | +||| Membership is preserved when a prefix is prepended on the left. |
| 39 | +||| If `x` is in `ys`, then `x` is in `xs ++ ys`. Proved by induction on the |
| 40 | +||| prefix `xs`; every step is a constructor (`There`), no holes. |
| 41 | +elemAppendRight : |
| 42 | + {0 x : Component} |
| 43 | + -> (xs : List Component) |
| 44 | + -> {0 ys : List Component} |
| 45 | + -> Elem x ys |
| 46 | + -> Elem x (xs ++ ys) |
| 47 | +elemAppendRight [] prf = prf |
| 48 | +elemAppendRight (_ :: zs) prf = There (elemAppendRight zs prf) |
| 49 | + |
| 50 | +-------------------------------------------------------------------------------- |
| 51 | +-- Property (1): Generation soundness — correct-by-construction |
| 52 | +-------------------------------------------------------------------------------- |
| 53 | + |
| 54 | +||| The canonical scaffold the generator emits: all five doctrine components |
| 55 | +||| in canonical order. (Independent of `Semantics.completeScaffold` so this |
| 56 | +||| module's generator stands on its own definition.) |
| 57 | +public export |
| 58 | +generatedScaffold : Scaffold |
| 59 | +generatedScaffold = MkScaffold [Manifest, Abi, Ffi, Codegen, Cli] |
| 60 | + |
| 61 | +||| Proof that the generated scaffold is Conformant. Each `Has` field is a |
| 62 | +||| concrete `Elem` position into the literal component list, so this checks |
| 63 | +||| by reduction with no appeal to any decision procedure. |
| 64 | +generatedIsConformant : Conformant Invariants.generatedScaffold |
| 65 | +generatedIsConformant = |
| 66 | + MkConformant |
| 67 | + Here -- Manifest @ 0 |
| 68 | + (There Here) -- Abi @ 1 |
| 69 | + (There (There Here)) -- Ffi @ 2 |
| 70 | + (There (There (There Here))) -- Codegen @ 3 |
| 71 | + (There (There (There (There Here)))) -- Cli @ 4 |
| 72 | + |
| 73 | +||| GENERATION SOUNDNESS THEOREM. |
| 74 | +||| |
| 75 | +||| For ANY language model, the meta-framework emits a scaffold together with |
| 76 | +||| a machine-checked proof that it is Conformant. The `LanguageModel` is a |
| 77 | +||| genuine, used input (every -iser is generated *for* some target language), |
| 78 | +||| but conformance of the emitted scaffold does not depend on it: the five |
| 79 | +||| architectural components are produced unconditionally. This is the |
| 80 | +||| dependent-pair statement `(s ** Conformant s)` — a constructive witness, |
| 81 | +||| not a boolean. |
| 82 | +public export |
| 83 | +genScaffold : LanguageModel -> (s : Scaffold ** Conformant s) |
| 84 | +genScaffold _ = (generatedScaffold ** generatedIsConformant) |
| 85 | + |
| 86 | +||| A Conformant scaffold is always certified `Ok` by the Layer-2 certifier. |
| 87 | +||| Proved by case-analysis on the SAME decision the certifier uses: the `No` |
| 88 | +||| branch is discharged by feeding the (given) witness to the refutation, |
| 89 | +||| which is absurd. (`decConformant` does not reduce definitionally through a |
| 90 | +||| bare `Refl`, so we reason about its result with a `with`-block rather than |
| 91 | +||| asserting equality.) |
| 92 | +public export |
| 93 | +conformantCertifies : |
| 94 | + {s : Scaffold} |
| 95 | + -> Conformant s |
| 96 | + -> certifyConformant s = Ok |
| 97 | +conformantCertifies w with (decConformant s) |
| 98 | + conformantCertifies _ | Yes _ = Refl |
| 99 | + conformantCertifies w | No no = void (no w) |
| 100 | + |
| 101 | +||| Corollary: the certifier from Layer 2 accepts every generated scaffold. |
| 102 | +||| This ties Layer 3 (construction) back to Layer 2 (decision): what we |
| 103 | +||| build is exactly what the Layer-2 certifier blesses as `Ok`. |
| 104 | +public export |
| 105 | +genScaffoldCertifies : |
| 106 | + (m : LanguageModel) |
| 107 | + -> certifyConformant (fst (genScaffold m)) = Ok |
| 108 | +genScaffoldCertifies m = conformantCertifies (snd (genScaffold m)) |
| 109 | + |
| 110 | +-------------------------------------------------------------------------------- |
| 111 | +-- Property (2): Upward-closure / monotonicity of Conformance |
| 112 | +-------------------------------------------------------------------------------- |
| 113 | + |
| 114 | +||| Extend a scaffold by prepending extra components (e.g. optional extras a |
| 115 | +||| richer target language requests). Defined as list concatenation. |
| 116 | +public export |
| 117 | +extend : List Component -> Scaffold -> Scaffold |
| 118 | +extend extra s = MkScaffold (extra ++ components s) |
| 119 | + |
| 120 | +||| Weaken a single `Has` obligation across an extension: if a component is |
| 121 | +||| present in `s`, it remains present in `extend extra s`. Direct corollary |
| 122 | +||| of `elemAppendRight`. |
| 123 | +hasUnderExtend : |
| 124 | + {0 c : Component} |
| 125 | + -> (extra : List Component) |
| 126 | + -> {0 s : Scaffold} |
| 127 | + -> Has c s |
| 128 | + -> Has c (extend extra s) |
| 129 | +hasUnderExtend extra prf = elemAppendRight extra prf |
| 130 | + |
| 131 | +||| CLOSURE LAW (monotonicity). |
| 132 | +||| |
| 133 | +||| Conformance is upward-closed under extension: extending a Conformant |
| 134 | +||| scaffold with any extra components yields a Conformant scaffold. Each of |
| 135 | +||| the five membership proofs is transported through `hasUnderExtend`. This |
| 136 | +||| is an algebraic closure property — genuinely distinct from the Layer-2 |
| 137 | +||| decision, and it cannot hold vacuously (it consumes a real `Conformant`). |
| 138 | +public export |
| 139 | +conformantStable : |
| 140 | + (extra : List Component) |
| 141 | + -> {0 s : Scaffold} |
| 142 | + -> Conformant s |
| 143 | + -> Conformant (extend extra s) |
| 144 | +conformantStable extra (MkConformant m a f g c) = |
| 145 | + MkConformant |
| 146 | + (hasUnderExtend extra m) |
| 147 | + (hasUnderExtend extra a) |
| 148 | + (hasUnderExtend extra f) |
| 149 | + (hasUnderExtend extra g) |
| 150 | + (hasUnderExtend extra c) |
| 151 | + |
| 152 | +-------------------------------------------------------------------------------- |
| 153 | +-- Positive control: a generated-then-extended scaffold is still Conformant |
| 154 | +-------------------------------------------------------------------------------- |
| 155 | + |
| 156 | +||| Take the generator's output and extend it with a duplicate Manifest in |
| 157 | +||| front (a realistic "extra"): still Conformant, by the closure law applied |
| 158 | +||| to the generation-soundness witness. |
| 159 | +public export |
| 160 | +extendedGeneratedConformant : |
| 161 | + Conformant (extend [Manifest] Invariants.generatedScaffold) |
| 162 | +extendedGeneratedConformant = |
| 163 | + conformantStable [Manifest] generatedIsConformant |
| 164 | + |
| 165 | +-------------------------------------------------------------------------------- |
| 166 | +-- Sound + complete decision for extension-conformance |
| 167 | +-------------------------------------------------------------------------------- |
| 168 | + |
| 169 | +||| Decide whether an extension of `s` is Conformant. Reuses the Layer-2 |
| 170 | +||| `decConformant` on the extended scaffold — sound and complete because |
| 171 | +||| `decConformant` is. This is the natural decision point for "is the |
| 172 | +||| scaffold still conformant after we added these extras?". |
| 173 | +public export |
| 174 | +decExtendConformant : |
| 175 | + (extra : List Component) |
| 176 | + -> (s : Scaffold) |
| 177 | + -> Dec (Conformant (extend extra s)) |
| 178 | +decExtendConformant extra s = decConformant (extend extra s) |
| 179 | + |
| 180 | +-------------------------------------------------------------------------------- |
| 181 | +-- Negative / non-vacuity control |
| 182 | +-------------------------------------------------------------------------------- |
| 183 | + |
| 184 | +||| A scaffold the generator would NEVER emit: everything except the Zig FFI. |
| 185 | +public export |
| 186 | +brokenScaffold : Scaffold |
| 187 | +brokenScaffold = MkScaffold [Manifest, Abi, Codegen, Cli] |
| 188 | + |
| 189 | +||| Machine-checked refutation: extending the FFI-less broken scaffold with |
| 190 | +||| MORE non-FFI components does NOT make it Conformant — the closure law |
| 191 | +||| only adds, it cannot conjure the missing `Ffi`. We pull the `Has Ffi` |
| 192 | +||| field out of any hypothetical witness over the extended list and show |
| 193 | +||| every membership position is impossible. This proves the closure law is |
| 194 | +||| not vacuous: extension genuinely preserves, but does not fabricate, |
| 195 | +||| conformance. |
| 196 | +||| |
| 197 | +||| The extended list is `[Codegen, Manifest] ++ [Manifest, Abi, Codegen, Cli]` |
| 198 | +||| = `[Codegen, Manifest, Manifest, Abi, Codegen, Cli]` — six positions, none |
| 199 | +||| of which is `Ffi`, so the `noFfi` clause refutes them all. |
| 200 | +public export |
| 201 | +extendedBrokenNotConformant : |
| 202 | + Not (Conformant (extend [Codegen, Manifest] Invariants.brokenScaffold)) |
| 203 | +extendedBrokenNotConformant (MkConformant _ _ f _ _) = noFfi f |
| 204 | + where |
| 205 | + noFfi : Not (Elem Ffi [Codegen, Manifest, Manifest, Abi, Codegen, Cli]) |
| 206 | + noFfi (There (There (There (There (There (There prf)))))) impossible |
0 commit comments