|
| 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 | +# TypeQL-Experimental Operational Semantics |
| 5 | + |
| 6 | +**Version:** 1.0.0 |
| 7 | +**Date:** 2026-03-14 |
| 8 | + |
| 9 | +--- |
| 10 | + |
| 11 | +## 1. Notation |
| 12 | + |
| 13 | +- `Γ` — Type context (variable typing assumptions) |
| 14 | +- `D` — Database state |
| 15 | +- `Γ, D ⊢ q : τ ⇓ v` — Query `q` has type `τ` and evaluates to `v` |
| 16 | +- `Γ ⊢ q : τ` — Query `q` type-checks to `τ` (compile-time) |
| 17 | +- Quantities: `0` (erased), `1` (linear), `ω` (unrestricted) |
| 18 | + |
| 19 | +--- |
| 20 | + |
| 21 | +## 2. Values |
| 22 | + |
| 23 | +``` |
| 24 | +v ∈ Value ::= |
| 25 | + QueryResult(rows) query result set |
| 26 | + | LinConn(handle, remaining) linear connection (indexed by uses) |
| 27 | + | Session(state) session state machine |
| 28 | + | Box(world, v) modal box (scoped value) |
| 29 | + | ProvedResult(v, proof) result with attached theorem |
| 30 | + | BoundedResource(v, remaining) usage-limited resource |
| 31 | + | EffectSet(effects) declared effect set |
| 32 | +``` |
| 33 | + |
| 34 | +--- |
| 35 | + |
| 36 | +## 3. Type System (Compile-Time) |
| 37 | + |
| 38 | +### 3.1 Linear Types (CONSUME AFTER N USE) |
| 39 | + |
| 40 | +``` |
| 41 | + Γ, (1 conn : LinConn (S n)) ⊢ query : τ |
| 42 | + ───────────────────────────────────────────────────────── [Lin-Use] |
| 43 | + Γ ⊢ useConn(conn) : (QueryResult, LinConn n) |
| 44 | +
|
| 45 | + Γ, (1 conn : LinConn 0) ⊢ close : IO () |
| 46 | + ────────────────────────────────────────────────────── [Lin-Close] |
| 47 | + Γ ⊢ closeConn(conn) : IO () |
| 48 | +
|
| 49 | + conn used twice (linear quantity violated) |
| 50 | + ────────────────────────────────────────────────────── [Lin-Error] |
| 51 | + Γ ⊢ program ⇒ TYPE ERROR: linear variable used more than once |
| 52 | +``` |
| 53 | + |
| 54 | +### 3.2 Session Types (WITH SESSION) |
| 55 | + |
| 56 | +``` |
| 57 | + Γ, (1 s : Session Fresh) ⊢ auth(s) : Either AuthError (Session Authenticated) |
| 58 | + ──────────────────────────────────────────────────────────────────────────── [Sess-Auth] |
| 59 | +
|
| 60 | + Γ, (1 s : Session InTransaction) ⊢ query(s, plan) : (QueryResult, Session InTransaction) |
| 61 | + ───────────────────────────────────────────────────────────────────────────────────────── [Sess-Query] |
| 62 | +
|
| 63 | + Γ, (1 s : Session InTransaction) ⊢ commit(s) : Either TxError (Session Committed) |
| 64 | + ────────────────────────────────────────────────────────────────────────────────────── [Sess-Commit] |
| 65 | +
|
| 66 | + Γ, (1 s : Session Fresh) ⊢ query(s, plan) ⇒ TYPE ERROR |
| 67 | + ───────────────────────────────────────────────────────── [Sess-Error] |
| 68 | + (query requires Session InTransaction, not Session Fresh) |
| 69 | +``` |
| 70 | + |
| 71 | +### 3.3 Effect System (EFFECTS) |
| 72 | + |
| 73 | +``` |
| 74 | + actual_effects(q) = {Read} declared = {Read} |
| 75 | + actual ⊆ declared |
| 76 | + ────────────────────────────────────────────────────── [Eff-Ok] |
| 77 | + Γ ⊢ q EFFECTS { Read } : τ |
| 78 | +
|
| 79 | + actual_effects(q) = {Read, Write} declared = {Read} |
| 80 | + Write ∉ declared |
| 81 | + ────────────────────────────────────────────────────── [Eff-Error] |
| 82 | + Γ ⊢ q EFFECTS { Read } ⇒ TYPE ERROR: Write not in declared effects |
| 83 | +
|
| 84 | + Subsumes(declared, actual) = ∀e ∈ actual. e ∈ declared |
| 85 | + ────────────────────────────────────────────────── [Eff-Subsumes] |
| 86 | + Γ ⊢ Subsumes(declared, actual) : Type |
| 87 | +``` |
| 88 | + |
| 89 | +### 3.4 Modal Types (IN TRANSACTION) |
| 90 | + |
| 91 | +``` |
| 92 | + Γ ⊢ v : a w : World |
| 93 | + ─────────────────────────── [Modal-Box] |
| 94 | + Γ ⊢ MkBox(v) : Box w a |
| 95 | +
|
| 96 | + Γ ⊢ b : Box w a Γ ⊢ InScope w |
| 97 | + ───────────────────────────────────── [Modal-Extract] |
| 98 | + Γ ⊢ extract(b) : a |
| 99 | +
|
| 100 | + Γ ⊢ b : Box w₁ a Γ ⊢ f : a → b |
| 101 | + ───────────────────────────────────────── [Modal-Marshal] |
| 102 | + Γ ⊢ marshal(b, f) : Box w₂ b |
| 103 | +
|
| 104 | + Γ ⊢ b : Box w₁ a attempt extract without InScope w₁ |
| 105 | + ────────────────────────────────────────────────────────── [Modal-Error] |
| 106 | + TYPE ERROR: cannot extract from Box w₁ without InScope w₁ evidence |
| 107 | +``` |
| 108 | + |
| 109 | +### 3.5 Proof-Carrying Code (PROOF ATTACHED) |
| 110 | + |
| 111 | +``` |
| 112 | + Γ ⊢ q : QueryResult Γ ⊢ thm : Theorem |
| 113 | + Γ ⊢ verify(q, thm) succeeds |
| 114 | + ───────────────────────────────────────────────── [Proof-Attach] |
| 115 | + Γ ⊢ q PROOF ATTACHED thm : ProvedResult QueryResult Theorem |
| 116 | +
|
| 117 | + ProvedResult(v, prf) = (result : τ ** ProofOf thm result) |
| 118 | + ───────────────────────────────────────────────────────── [Proof-Type] |
| 119 | + (dependent pair: data bundled with its proof) |
| 120 | +``` |
| 121 | + |
| 122 | +### 3.6 Quantitative Types (USAGE LIMIT) |
| 123 | + |
| 124 | +``` |
| 125 | + Γ, (r : BoundedResource (S n) a) ⊢ consume(r) : (a, BoundedResource n a) |
| 126 | + ───────────────────────────────────────────────────────────────────────── [Quant-Consume] |
| 127 | +
|
| 128 | + Γ, (r : BoundedResource 0 a) ⊢ consume(r) ⇒ TYPE ERROR |
| 129 | + ────────────────────────────────────────────────────────── [Quant-Depleted] |
| 130 | + (no consume operation exists on BoundedResource 0) |
| 131 | +``` |
| 132 | + |
| 133 | +--- |
| 134 | + |
| 135 | +## 4. Runtime Semantics |
| 136 | + |
| 137 | +### 4.1 Query Evaluation (standard VQL pipeline) |
| 138 | + |
| 139 | +``` |
| 140 | + D ⊢ SELECT modalities FROM hexad WHERE conditions ⇓ rows |
| 141 | + ──────────────────────────────────────────────────────────── [Query-Base] |
| 142 | + Γ, D ⊢ query ⇓ QueryResult(rows) |
| 143 | +``` |
| 144 | + |
| 145 | +### 4.2 Linear Connection Runtime |
| 146 | + |
| 147 | +``` |
| 148 | + handle = open_connection(db_url) remaining = n |
| 149 | + ──────────────────────────────────────────────────── [LinConn-Open] |
| 150 | + Γ, D ⊢ openConn(n) ⇓ LinConn(handle, n) |
| 151 | +
|
| 152 | + conn = LinConn(handle, S(k)) |
| 153 | + result = execute(handle, plan) |
| 154 | + conn' = LinConn(handle, k) |
| 155 | + ──────────────────────────────────────────── [LinConn-Use] |
| 156 | + Γ, D ⊢ useConn(conn, plan) ⇓ (result, conn') |
| 157 | +
|
| 158 | + conn = LinConn(handle, 0) |
| 159 | + close(handle) |
| 160 | + ──────────────────────────────────────── [LinConn-Close] |
| 161 | + Γ, D ⊢ closeConn(conn) ⇓ () |
| 162 | +``` |
| 163 | + |
| 164 | +### 4.3 Session State Machine Runtime |
| 165 | + |
| 166 | +``` |
| 167 | + s = Session Fresh |
| 168 | + auth_result = authenticate(credentials) |
| 169 | + ──────────────────────────────────────────────────── [Session-Auth] |
| 170 | + Γ, D ⊢ auth(s, creds) ⇓ Right(Session Authenticated) |
| 171 | + | Left(AuthError) |
| 172 | +
|
| 173 | + s = Session Authenticated |
| 174 | + ──────────────────────────────────────────────── [Session-Begin] |
| 175 | + Γ, D ⊢ beginTx(s) ⇓ Session InTransaction |
| 176 | +
|
| 177 | + s = Session InTransaction |
| 178 | + result = execute(plan) |
| 179 | + ──────────────────────────────────────────────────── [Session-Query] |
| 180 | + Γ, D ⊢ query(s, plan) ⇓ (result, Session InTransaction) |
| 181 | +
|
| 182 | + s = Session InTransaction |
| 183 | + commit_result = commit_transaction() |
| 184 | + ──────────────────────────────────────────────────── [Session-Commit] |
| 185 | + Γ, D ⊢ commit(s) ⇓ Right(Session Committed) |
| 186 | + | Left(TxError) |
| 187 | +``` |
| 188 | + |
| 189 | +### 4.4 Effect Checking Runtime |
| 190 | + |
| 191 | +``` |
| 192 | + query_plan = plan(q) |
| 193 | + actual = collect_effects(query_plan) |
| 194 | + actual ⊆ declared (verified at compile time by Idris2) |
| 195 | + ──────────────────────────────────────────────────────────── [Effects-Run] |
| 196 | + Γ, D ⊢ q EFFECTS { declared } ⇓ execute(query_plan) |
| 197 | +``` |
| 198 | + |
| 199 | +### 4.5 Modal Scoping Runtime |
| 200 | + |
| 201 | +``` |
| 202 | + v computed in transaction scope w |
| 203 | + ──────────────────────────────────── [Modal-Wrap] |
| 204 | + Γ, D ⊢ MkBox(v) ⇓ Box(w, v) |
| 205 | +
|
| 206 | + b = Box(w, v) current_scope = w (scope matches) |
| 207 | + ──────────────────────────────────────────────────────── [Modal-Open] |
| 208 | + Γ, D ⊢ extract(b) ⇓ v |
| 209 | +``` |
| 210 | + |
| 211 | +### 4.6 Proof Verification Runtime |
| 212 | + |
| 213 | +``` |
| 214 | + result = execute(q) |
| 215 | + proof = verify_theorem(thm, result) |
| 216 | + proof succeeds |
| 217 | + ───────────────────────────────────────────── [Proof-Verify] |
| 218 | + Γ, D ⊢ q PROOF ATTACHED thm ⇓ ProvedResult(result, proof) |
| 219 | +
|
| 220 | + proof fails |
| 221 | + ───────────────────────────────────────────────── [Proof-Fail] |
| 222 | + Γ, D ⊢ q PROOF ATTACHED thm ⇓ ⊥("theorem verification failed") |
| 223 | +``` |
| 224 | + |
| 225 | +### 4.7 Resource Budget Runtime |
| 226 | + |
| 227 | +``` |
| 228 | + r = BoundedResource(v, S(k)) |
| 229 | + ──────────────────────────────────────────────────── [Resource-Use] |
| 230 | + Γ, D ⊢ consume(r) ⇓ (v, BoundedResource(v, k)) |
| 231 | +
|
| 232 | + budget_remaining = 0 (enforced at compile time; never reached at runtime) |
| 233 | +``` |
| 234 | + |
| 235 | +--- |
| 236 | + |
| 237 | +## 5. Extension Composition |
| 238 | + |
| 239 | +The six extensions compose independently because each operates on a different |
| 240 | +dimension of the type: |
| 241 | + |
| 242 | +``` |
| 243 | + Γ ⊢ q : QueryResult |
| 244 | + Γ ⊢ q CONSUME AFTER 1 USE (LinConn dimension) |
| 245 | + Γ ⊢ q WITH SESSION ReadOnly (Session dimension) |
| 246 | + Γ ⊢ q EFFECTS { Read, Cite } (Effect dimension) |
| 247 | + Γ ⊢ q IN TRANSACTION Committed (World dimension) |
| 248 | + Γ ⊢ q PROOF ATTACHED Integrity (Proof dimension) |
| 249 | + Γ ⊢ q USAGE LIMIT 100 (Budget dimension) |
| 250 | + ────────────────────────────────────────────────────────────── [Compose] |
| 251 | + Γ ⊢ composed_query : ProvedResult (Box Committed QueryResult) IntegrityThm |
| 252 | + with linear connection, session protocol, effect bounds, and resource limit |
| 253 | +``` |
| 254 | + |
| 255 | +The `Checker.idr` module validates all six constraints simultaneously by |
| 256 | +composing individual check functions. |
| 257 | + |
| 258 | +--- |
| 259 | + |
| 260 | +## 6. Invariants |
| 261 | + |
| 262 | +1. **Linear safety:** A `LinConn n` is used exactly `n` times before closing. Enforced by QTT at compile time. |
| 263 | +2. **Protocol compliance:** Session operations only succeed in valid states. Enforced by indexed types. |
| 264 | +3. **Effect containment:** Actual effects ⊆ declared effects. Enforced by `Subsumes` proof. |
| 265 | +4. **Scope isolation:** Data in `Box w₁` cannot be extracted without `InScope w₁` evidence. |
| 266 | +5. **Proof integrity:** `ProvedResult` pairs are unforgeable — the proof must type-check. |
| 267 | +6. **Budget monotonicity:** `BoundedResource n` can only decrease to `BoundedResource (n-1)`. |
| 268 | +7. **Totality:** All Idris2 modules compile with `%default total` — no infinite loops, no partial functions. |
| 269 | +8. **Zero axioms:** No `believe_me`, `assert_total`, or `assert_smaller` in proof code. |
0 commit comments