Cairn · module

Cairn.Runtime.WorldProofs

lean/Cairn/Runtime/WorldProofs.lean

What the runtime guarantees about the outside world (docs/effects.md, "Semantics").

  • The clock never goes back (step_clock).
  • A timer reaches receive only while it is set: a cancelled timer never fires, and a timer fires once per setting (steps_book, read with Book.run).
  • A reply reaches receive only for a pending request, with the id it was sent under, in the shape that answers its kind, and once (steps_book, step_reply, step_reply_ignored).
  • Subscription diffs start exactly the wanted subscriptions that are not running, stop exactly the running ones no longer wanted, and the active set becomes what the app wants (diffSubs_stop, diffSubs_start, diffSubs_active).

The timer and reply statements are about a recording wrapper, logged app, whose state carries the list of everything delivered to receive and update, with the effects each returned. Book.run is the specification such a log must meet: it replays the log against a book of armed timers and pending requests and fails at the first delivery the book does not allow.

Imports Cairn.Runtime.Proofs

Order

Structures 1

structure

Cairn.Runtime.Book

lean/Cairn/Runtime/WorldProofs.lean:102
Book : Type

The specification's state: which timers are armed and which requests are pending.

Fields
armed : Bool
pending : Option Request.Kind

Inductive types 1

inductive

Cairn.Runtime.Entry

lean/Cairn/Runtime/WorldProofs.lean:97
Entry : Type

What a delivery log records: a message to receive or an action to update, with the effects it returned.

Constructors
recv (m : Msg) (es : List Effect) : Entry
upd (a : Action) (es : List Effect) : Entry

Definitions 18

def

Cairn.Runtime.Same

lean/Cairn/Runtime/WorldProofs.lean:67
Same (w w' : World) : Prop

Absorbing effects touches only timers and requests.

def

Cairn.Runtime.Book.arm

lean/Cairn/Runtime/WorldProofs.lean:108
arm (b : Book) (n : String) (on : Bool) : Book
def

Cairn.Runtime.Book.drop

lean/Cairn/Runtime/WorldProofs.lean:111
drop (b : Book) (id : Nat) : Book
def

Cairn.Runtime.Book.take

lean/Cairn/Runtime/WorldProofs.lean:118
take (b : Book) : Effect → Book

One effect: setTimer arms, cancelTimer disarms, a request with a fresh id becomes pending (one whose id is pending is refused), cancelRequest withdraws a pending request. Whether a request is sent at once or waits for a slot is the runtime's business, not the book's: the book's pending requests are the ones the app may still hear about.

def

Cairn.Runtime.Book.takeAll

lean/Cairn/Runtime/WorldProofs.lean:128
takeAll (b : Book) (es : List Effect) : Book
def

Cairn.Runtime.Book.admits

lean/Cairn/Runtime/WorldProofs.lean:132
admits (b : Book) : Msg → Bool

Which messages may be delivered: a timer only while armed, a reply only to a pending request and in the shape that answers it.

def

Cairn.Runtime.Book.pre

lean/Cairn/Runtime/WorldProofs.lean:142
pre (b : Book) : Msg → Book

Delivering a message uses it up: a fired timer is disarmed, an answered request is no longer pending.

def

Cairn.Runtime.Book.run

lean/Cairn/Runtime/WorldProofs.lean:148
run (b : Book) : List Entry → Option Book

Replay a log; none at the first delivery the book does not allow.

def

Cairn.Runtime.World.Keys

lean/Cairn/Runtime/WorldProofs.lean:314
Keys (w : World) : Prop

No id is both pending and queued, or twice in either.

def

Cairn.Runtime.World.wkind

lean/Cairn/Runtime/WorldProofs.lean:317
wkind (p : Nat × Request) : Nat × Request.Kind

How a queued request shows in entries.

def

Cairn.Runtime.Agrees

lean/Cairn/Runtime/WorldProofs.lean:352
Agrees (w : World) (b : Book) : Prop

The runtime's tables and a book agree: the same timers armed, and the requests the app may still hear about (pending or queued) the same, each id once.

def

Cairn.Runtime.qkind

lean/Cairn/Runtime/WorldProofs.lean:511
qkind (q : Nat × Nat × Request) : Nat × Request.Kind

How a queued request shows in entries.

def

Cairn.Runtime.logUpdate

lean/Cairn/Runtime/WorldProofs.lean:593
logUpdate {S : Type} (app : App S) (st : S × List Entry) (a : Action) :
  (S × List Entry) × List Effect
def

Cairn.Runtime.logReceive

lean/Cairn/Runtime/WorldProofs.lean:597
logReceive {S : Type} (app : App S) (st : S × List Entry) (m : Msg) :
  (S × List Entry) × List Effect
def

Cairn.Runtime.logged

lean/Cairn/Runtime/WorldProofs.lean:603
logged {S : Type} (app : App S) : App (S × List Entry)

app, with a log of every delivery in its state. It behaves as app does: every field reads only the first component.

def

Cairn.Runtime.Inv

lean/Cairn/Runtime/WorldProofs.lean:652
Inv {S : Type} (log0 : List Entry) (b0 : Book) (c : Ctx (S × List Entry)) :
  Prop

A context whose log extends log0 by entries the book b0 allows, ending at a book that agrees with the context's world.

def

Cairn.Runtime.Grows

lean/Cairn/Runtime/WorldProofs.lean:784
Grows (w w' : World) : Prop

The clock does not go back and a booted world stays booted.

def

Cairn.Runtime.KeepsOnClock

lean/Cairn/Runtime/WorldProofs.lean:973
KeepsOnClock {S : Type} (app : App S) (id : Nat) : Prop

The app does not withdraw request id when it hears the time.

Theorems 102

theorem

Cairn.Runtime.lookup_append

provedlean/Cairn/Runtime/WorldProofs.lean:25
lookup_append {β : Type} (l m : List (Nat × β)) (x : Nat) :
  List.lookup x (l ++ m) = (List.lookup x l).or (List.lookup x m)
theorem

Cairn.Runtime.lookup_filter

provedlean/Cairn/Runtime/WorldProofs.lean:34
lookup_filter {β : Type} (l : List (Nat × β)) (id x : Nat) :
  List.lookup x (List.filter (fun p => p.fst != id) l) =
    if x = id then none else List.lookup x l
theorem

Cairn.Runtime.any_eq_lookup

provedlean/Cairn/Runtime/WorldProofs.lean:53
any_eq_lookup {β : Type} (l : List (Nat × β)) (id : Nat) :
  (l.any fun p => p.fst == id) = (List.lookup id l).isSome
theorem

Cairn.Runtime.Same.trans

provedlean/Cairn/Runtime/WorldProofs.lean:71
trans {a b c : World} (h1 : Same a b) (h2 : Same b c) : Same a c
theorem

Cairn.Runtime.cancel_same

provedlean/Cairn/Runtime/WorldProofs.lean:76
cancel_same (w : World) (id : Nat) : Same w (w.cancel id).fst
theorem

Cairn.Runtime.absorb1_same

provedlean/Cairn/Runtime/WorldProofs.lean:81
absorb1_same (w : World) (e : Effect) : Same w (w.absorb1 e).fst
theorem

Cairn.Runtime.absorb_cons

provedlean/Cairn/Runtime/WorldProofs.lean:85
absorb_cons (w : World) (e : Effect) (es : List Effect) :
  (w.absorb (e :: es)).fst = ((w.absorb1 e).fst.absorb es).fst
theorem

Cairn.Runtime.absorb_same

provedlean/Cairn/Runtime/WorldProofs.lean:88
absorb_same (es : List Effect) (w : World) : Same w (w.absorb es).fst
theorem

Cairn.Runtime.Book.run_append

provedlean/Cairn/Runtime/WorldProofs.lean:153
run_append (xs ys : List Entry) (b : Book) :
  b.run (xs ++ ys) = (b.run xs).bind fun x => x.run ys
theorem

Cairn.Runtime.Book.takeAll_append

provedlean/Cairn/Runtime/WorldProofs.lean:166
takeAll_append (b : Book) (xs ys : List Effect) :
  b.takeAll (xs ++ ys) = (b.takeAll xs).takeAll ys
theorem

Cairn.Runtime.Book.cancel_disarms

provedlean/Cairn/Runtime/WorldProofs.lean:170
cancel_disarms (b : Book) (n : String) (es rest : List Effect)
  (h : ∀ (ms : Nat), ¬Effect.setTimer n ms ∈ rest) :
  (b.takeAll (es ++ Effect.cancelTimer n :: rest)).armed n = false

A timer whose last word in a delivery's effects was cancelTimer is not armed after it.

theorem

Cairn.Runtime.Book.cancel_blocks

provedlean/Cairn/Runtime/WorldProofs.lean:194
cancel_blocks (b : Book) (id : Nat) (es rest : List Effect) (r : Reply)
  (h : ∀ (q : Request), ¬Effect.request id q ∈ rest) :
  (b.takeAll (es ++ Effect.cancelRequest id :: rest)).admits (Msg.reply id r) = false

A cancelled request is never answered: once cancelRequest id is the last word on id in a delivery's effects (no request under id after it), no reply to id is admitted.

theorem

Cairn.Runtime.Book.reply_once

provedlean/Cairn/Runtime/WorldProofs.lean:222
reply_once (b : Book) (id : Nat) (r r' : Reply) :
  (b.pre (Msg.reply id r)).admits (Msg.reply id r') = false

A reply uses up its request: right after delivery a second reply to the same id is not admitted.

theorem

Cairn.Runtime.lookup_some_mem

provedlean/Cairn/Runtime/WorldProofs.lean:233
lookup_some_mem {β : Type} {l : List (Nat × β)} {x : Nat} {v : β}
  (h : List.lookup x l = some v) : (x, v) ∈ l
theorem

Cairn.Runtime.lookup_none_of

provedlean/Cairn/Runtime/WorldProofs.lean:246
lookup_none_of {β : Type} {l : List (Nat × β)} {x : Nat}
  (h : ¬x ∈ List.map (fun x => x.fst) l) : List.lookup x l = none
theorem

Cairn.Runtime.lookup_isSome_iff

provedlean/Cairn/Runtime/WorldProofs.lean:256
lookup_isSome_iff {β : Type} (l : List (Nat × β)) (x : Nat) :
  (List.lookup x l).isSome = true ↔ x ∈ List.map (fun x => x.fst) l
theorem

Cairn.Runtime.lookup_of_mem

provedlean/Cairn/Runtime/WorldProofs.lean:274
lookup_of_mem {β : Type} {l : List (Nat × β)} {x : Nat} {v : β}
  (hn : (List.map (fun x => x.fst) l).Nodup) (h : (x, v) ∈ l) : List.lookup x l = some v
theorem

Cairn.Runtime.lookup_congr

provedlean/Cairn/Runtime/WorldProofs.lean:288
lookup_congr {β : Type} {l l' : List (Nat × β)}
  (hm : ∀ (p : Nat × β), p ∈ l ↔ p ∈ l') (hn : (List.map (fun x => x.fst) l).Nodup)
  (hn' : (List.map (fun x => x.fst) l').Nodup) (x : Nat) :
  List.lookup x l = List.lookup x l'

Two keyed lists with the same members and no repeated key look up alike.

theorem

Cairn.Runtime.nodup_middle

provedlean/Cairn/Runtime/WorldProofs.lean:299
nodup_middle {α : Type} {a c : List α} {x : α} (h : (a ++ c).Nodup)
  (hx : ¬x ∈ a ++ c) : (a ++ [x] ++ c).Nodup
theorem

Cairn.Runtime.nodup_snoc

provedlean/Cairn/Runtime/WorldProofs.lean:305
nodup_snoc {α : Type} {a : List α} {x : α} (h : a.Nodup) (hx : ¬x ∈ a) :
  (a ++ [x]).Nodup
theorem

Cairn.Runtime.World.entries_eq

provedlean/Cairn/Runtime/WorldProofs.lean:319
entries_eq (w : World) :
  w.entries = w.pending ++ List.map wkind w.waiting
theorem

Cairn.Runtime.World.map_wkind_keys

provedlean/Cairn/Runtime/WorldProofs.lean:321
map_wkind_keys (l : List (Nat × Request)) :
  List.map (fun x => x.fst) (List.map wkind l) = List.map (fun x => x.fst) l
theorem

Cairn.Runtime.World.live_none

provedlean/Cairn/Runtime/WorldProofs.lean:324
live_none {w : World} {id : Nat} (h : w.live id = none) :
  List.lookup id w.pending = none ∧ List.lookup id (List.map wkind w.waiting) = none
theorem

Cairn.Runtime.World.waiting_any

provedlean/Cairn/Runtime/WorldProofs.lean:329
waiting_any {w : World} {id : Nat} :
  (w.waiting.any fun x => x.fst == id) = true ↔ id ∈ List.map (fun x => x.fst) w.waiting
theorem

Cairn.Runtime.World.keys_disjoint

provedlean/Cairn/Runtime/WorldProofs.lean:334
keys_disjoint {w : World} (hk : w.Keys) {id : Nat}
  (hp : id ∈ List.map (fun x => x.fst) w.pending)
  (hq : id ∈ List.map (fun x => x.fst) w.waiting) : False

An id both pending and queued contradicts Keys.

theorem

Cairn.Runtime.World.waiting_filter

provedlean/Cairn/Runtime/WorldProofs.lean:340
waiting_filter (w : World) (id : Nat) :
  List.map (fun x => x.snd) (List.filter (fun x => x.snd.fst != id) w.queued) =
    List.filter (fun x => x.fst != id) w.waiting
theorem

Cairn.Runtime.World.map_wkind_filter

provedlean/Cairn/Runtime/WorldProofs.lean:344
map_wkind_filter (l : List (Nat × Request)) (id : Nat) :
  List.map wkind (List.filter (fun x => x.fst != id) l) =
    List.filter (fun x => x.fst != id) (List.map wkind l)
theorem

Cairn.Runtime.mem_setTimer

provedlean/Cairn/Runtime/WorldProofs.lean:355
mem_setTimer (w : World) (n x : String) (ms : Nat) :
  x ∈ (w.setTimer n ms).timerNames ↔ x = n ∨ x ∈ w.timerNames
theorem

Cairn.Runtime.mem_cancelTimer

provedlean/Cairn/Runtime/WorldProofs.lean:369
mem_cancelTimer (w : World) (n x : String) :
  x ∈ (w.cancelTimer n).timerNames ↔ x ≠ n ∧ x ∈ w.timerNames
theorem

Cairn.Runtime.send_agrees

provedlean/Cairn/Runtime/WorldProofs.lean:378
send_agrees {w : World} {b : Book} (h : Agrees w b) {id : Nat}
  (k : Request.Kind) (hb : b.pending id = none) :
  Agrees (w.send id k)
    { armed := b.armed, pending := fun x => if x = id then some k else b.pending x }

Sending a request with a fresh id.

theorem

Cairn.Runtime.enqueue_agrees

provedlean/Cairn/Runtime/WorldProofs.lean:399
enqueue_agrees {w : World} {b : Book} (h : Agrees w b) {id : Nat}
  (r : Request) (hb : b.pending id = none) :
  Agrees (w.enqueue id r)
    { armed := b.armed, pending := fun x => if x = id then some r.kind else b.pending x }

Queueing a request with a fresh id.

theorem

Cairn.Runtime.cancel_agrees

provedlean/Cairn/Runtime/WorldProofs.lean:421
cancel_agrees {w : World} {b : Book} (h : Agrees w b) (id : Nat) :
  Agrees (w.cancel id).fst (b.drop id)
theorem

Cairn.Runtime.absorb1_agrees

provedlean/Cairn/Runtime/WorldProofs.lean:460
absorb1_agrees {w : World} {b : Book} (h : Agrees w b) (e : Effect) :
  Agrees (w.absorb1 e).fst (b.take e)
theorem

Cairn.Runtime.absorb_agrees

provedlean/Cairn/Runtime/WorldProofs.lean:491
absorb_agrees (es : List Effect) {w : World} {b : Book} :
  Agrees w b → Agrees (w.absorb es).fst (b.takeAll es)
theorem

Cairn.Runtime.takeReply_some

provedlean/Cairn/Runtime/WorldProofs.lean:497
takeReply_some {w w' : World} {id : Nat} {r : Reply}
  (h : w.takeReply id r = some w') :
  ∃ k,
    List.lookup id w.pending = some k ∧
      Reply.answers k r = true ∧
        w' =
          { clock := w.clock, heard := w.heard, booted := w.booted, timers := w.timers,
            pending := List.filter (fun p => p.fst != id) w.pending, queued := w.queued,
            stopping := w.stopping, cap := w.cap, nextTicket := w.nextTicket,
            subs := w.subs, nextSub := w.nextSub }
theorem

Cairn.Runtime.entries_queued

provedlean/Cairn/Runtime/WorldProofs.lean:513
entries_queued (w : World) : w.entries = w.pending ++ List.map qkind w.queued
theorem

Cairn.Runtime.promoteGo_spec

provedlean/Cairn/Runtime/WorldProofs.lean:518
promoteGo_spec (rest : List (Nat × Nat × Request)) (w : World) :
  (∃ p q,
      (w.promoteGo rest).fst =
        { clock := w.clock, heard := w.heard, booted := w.booted, timers := w.timers,
          pending := p, queued := q, stopping := w.stopping, cap := w.cap,
          nextTicket := w.nextTicket, subs := w.subs, nextSub := w.nextSub }) ∧
    (w.promoteGo rest).fst.entries.Perm (w.entries ++ List.map qkind rest)

promoteGo moves the requests it is given into pending or the queue, touching nothing else.

theorem

Cairn.Runtime.promote_spec

provedlean/Cairn/Runtime/WorldProofs.lean:537
promote_spec (w : World) :
  (∃ p q,
      w.promote.fst =
        { clock := w.clock, heard := w.heard, booted := w.booted, timers := w.timers,
          pending := p, queued := q, stopping := w.stopping, cap := w.cap,
          nextTicket := w.nextTicket, subs := w.subs, nextSub := w.nextSub }) ∧
    w.promote.fst.entries.Perm w.entries
theorem

Cairn.Runtime.agrees_entries

provedlean/Cairn/Runtime/WorldProofs.lean:546
agrees_entries {w w' : World} {b : Book} (ht : w'.timers = w.timers)
  (hp : w'.entries.Perm w.entries) (h : Agrees w b) : Agrees w' b
theorem

Cairn.Runtime.promote_agrees

provedlean/Cairn/Runtime/WorldProofs.lean:554
promote_agrees {w : World} {b : Book} (h : Agrees w b) :
  Agrees w.promote.fst b
theorem

Cairn.Runtime.takeStop_some

provedlean/Cairn/Runtime/WorldProofs.lean:558
takeStop_some {w w' : World} {id : Nat} (h : w.takeStop id = some w') :
  w.isStopping id = true ∧
    w' =
      { clock := w.clock, heard := w.heard, booted := w.booted, timers := w.timers,
        pending := w.pending, queued := w.queued,
        stopping := List.filter (fun x => x.fst != id) w.stopping, cap := w.cap,
        nextTicket := w.nextTicket, subs := w.subs, nextSub := w.nextSub }
theorem

Cairn.Runtime.takeStop_agrees

provedlean/Cairn/Runtime/WorldProofs.lean:565
takeStop_agrees {w w' : World} {b : Book} {id : Nat} (h : Agrees w b)
  (hw : w.takeStop id = some w') : Agrees w' b
theorem

Cairn.Runtime.takeReply_agrees

provedlean/Cairn/Runtime/WorldProofs.lean:570
takeReply_agrees {w w' : World} {b : Book} {id : Nat} {r : Reply}
  (h : Agrees w b) (hw : w.takeReply id r = some w') : Agrees w' (b.drop id)
theorem

Cairn.Runtime.live_of_pending

provedlean/Cairn/Runtime/WorldProofs.lean:587
live_of_pending {w : World} {id : Nat} {k : Request.Kind}
  (h : List.lookup id w.pending = some k) : w.live id = some k

A pending request is live, with its kind.

theorem

Cairn.Runtime.deliver_acc

provedlean/Cairn/Runtime/WorldProofs.lean:614
deliver_acc {S : Type} (u : S → Action → S × List Effect) (acts : List Action)
  (st : S) (effs : List Effect) :
  List.foldl
      (fun x a =>
        match x with
        | (st, effs) =>
          match u st a with
          | (st', e) => (st', effs ++ e))
      (st, effs) acts =
    ((deliver u st acts).fst, effs ++ (deliver u st acts).snd)
theorem

Cairn.Runtime.deliver_cons

provedlean/Cairn/Runtime/WorldProofs.lean:626
deliver_cons {S : Type} (u : S → Action → S × List Effect) (st : S)
  (a : Action) (acts : List Action) :
  deliver u st (a :: acts) =
    ((deliver u (u st a).fst acts).fst, (u st a).snd ++ (deliver u (u st a).fst acts).snd)
theorem

Cairn.Runtime.deliver_logged

provedlean/Cairn/Runtime/WorldProofs.lean:634
deliver_logged {S : Type} (app : App S) (acts : List Action)
  (st : S × List Entry) :
  ∃ ups,
    (deliver (logUpdate app) st acts).fst.snd = st.snd ++ ups ∧
      ∀ (b : Book), b.run ups = some (b.takeAll (deliver (logUpdate app) st acts).snd)
theorem

Cairn.Runtime.give_inv

provedlean/Cairn/Runtime/WorldProofs.lean:655
give_inv {S : Type} (app : App S) {log0 : List Entry} {b0 b : Book}
  {c : Ctx (S × List Entry)} {new : List Entry} {m : Msg} (hl : c.app.snd = log0 ++ new)
  (hr : b0.run new = some b) (ha : b.admits m = true) (hw : Agrees c.world (b.pre m)) :
  Inv log0 b0 (give (logged app) c m)
theorem

Cairn.Runtime.hear_inv

provedlean/Cairn/Runtime/WorldProofs.lean:665
hear_inv {S : Type} (app : App S) {log0 : List Entry} {b0 : Book}
  {c : Ctx (S × List Entry)} (h : Inv log0 b0 c) : Inv log0 b0 (hear (logged app) c)
theorem

Cairn.Runtime.fire_inv

provedlean/Cairn/Runtime/WorldProofs.lean:672
fire_inv {S : Type} (app : App S) {log0 : List Entry} {b0 : Book}
  {c : Ctx (S × List Entry)} (n : String) (h : Inv log0 b0 c) :
  Inv log0 b0 (fire (logged app) c n)
theorem

Cairn.Runtime.foldl_fire_inv

provedlean/Cairn/Runtime/WorldProofs.lean:684
foldl_fire_inv {S : Type} (app : App S) {log0 : List Entry} {b0 : Book}
  (ns : List String) {c : Ctx (S × List Entry)} :
  Inv log0 b0 c → Inv log0 b0 (List.foldl (fire (logged app)) c ns)
theorem

Cairn.Runtime.boot_booted

provedlean/Cairn/Runtime/WorldProofs.lean:690
boot_booted {S : Type} (app : App S) (c : Ctx S) (h : c.world.booted = true) :
  boot app c = c
theorem

Cairn.Runtime.ack_inv

provedlean/Cairn/Runtime/WorldProofs.lean:693
ack_inv {S : Type} {log0 : List Entry} {b0 : Book} {c : Ctx (S × List Entry)}
  (h : Inv log0 b0 c) (id : Nat) : Inv log0 b0 (ack c id)
theorem

Cairn.Runtime.admit_inv

provedlean/Cairn/Runtime/WorldProofs.lean:701
admit_inv {S : Type} (app : App S) (s : State (S × List Entry)) (e : Event)
  (hb : s.world.booted = true) {b0 : Book} (ha : Agrees s.world b0) :
  Inv s.app.snd b0 (admit (logged app) s e)
theorem

Cairn.Runtime.act_inv

provedlean/Cairn/Runtime/WorldProofs.lean:732
act_inv {S : Type} (app : App S) {log0 : List Entry} {b0 : Book}
  {c : Ctx (S × List Entry)} (acts : List Action) (h : Inv log0 b0 c) :
  Inv log0 b0 (act (logged app) c acts)
theorem

Cairn.Runtime.act_nil

provedlean/Cairn/Runtime/WorldProofs.lean:747
act_nil {S : Type} (app : App S) (c : Ctx S) : act app c [] = c
theorem

Cairn.Runtime.step_ctx

provedlean/Cairn/Runtime/WorldProofs.lean:753
step_ctx {S : Type} (app : App S) (cfg : Config) (s : State S) (e : Event) :
  have c := act app (admit app s e) (route cfg.metrics s e).snd;
  (step app cfg s e).fst.app = c.app ∧
    ∃ subs next,
      (step app cfg s e).fst.world =
        have __src := c.world;
        { clock := __src.clock, heard := __src.heard, booted := __src.booted,
          timers := __src.timers, pending := __src.pending, queued := __src.queued,
          stopping := __src.stopping, cap := __src.cap, nextTicket := __src.nextTicket,
          subs := subs, nextSub := next }

What a step leaves in the world, and the app, is what act leaves after admit; the step only adds the subscription diff.

theorem

Cairn.Runtime.step_book

provedlean/Cairn/Runtime/WorldProofs.lean:773
step_book {S : Type} (app : App S) (cfg : Config) (s : State (S × List Entry))
  (e : Event) (hb : s.world.booted = true) {b0 : Book} (ha : Agrees s.world b0) :
  ∃ new b,
    (step (logged app) cfg s e).fst.app.snd = s.app.snd ++ new ∧
      b0.run new = some b ∧ Agrees (step (logged app) cfg s e).fst.world b

One step of the recording app: the log grows by entries the book allows, and the runtime's tables agree with the book afterwards.

theorem

Cairn.Runtime.Grows.refl

provedlean/Cairn/Runtime/WorldProofs.lean:787
refl (w : World) : Grows w w
theorem

Cairn.Runtime.Grows.trans

provedlean/Cairn/Runtime/WorldProofs.lean:789
trans {a b c : World} (h1 : Grows a b) (h2 : Grows b c) : Grows a c
theorem

Cairn.Runtime.Same.grows

provedlean/Cairn/Runtime/WorldProofs.lean:792
grows {w w' : World} (h : Same w w') : Grows w w'
theorem

Cairn.Runtime.give_grows

provedlean/Cairn/Runtime/WorldProofs.lean:795
give_grows {S : Type} (app : App S) (c : Ctx S) (m : Msg) :
  Grows c.world (give app c m).world
theorem

Cairn.Runtime.give_grows'

provedlean/Cairn/Runtime/WorldProofs.lean:798
give_grows' {S : Type} (app : App S) {w : World} {c : Ctx S} {m : Msg}
  (h : Grows w c.world) : Grows w (give app c m).world
theorem

Cairn.Runtime.hear_grows

provedlean/Cairn/Runtime/WorldProofs.lean:802
hear_grows {S : Type} (app : App S) (c : Ctx S) :
  Grows c.world (hear app c).world
theorem

Cairn.Runtime.fire_grows

provedlean/Cairn/Runtime/WorldProofs.lean:807
fire_grows {S : Type} (app : App S) (c : Ctx S) (n : String) :
  Grows c.world (fire app c n).world
theorem

Cairn.Runtime.foldl_fire_grows

provedlean/Cairn/Runtime/WorldProofs.lean:812
foldl_fire_grows {S : Type} (app : App S) (ns : List String) (c : Ctx S) :
  Grows c.world (List.foldl (fire app) c ns).world
theorem

Cairn.Runtime.boot_grows

provedlean/Cairn/Runtime/WorldProofs.lean:818
boot_grows {S : Type} (app : App S) (c : Ctx S) :
  Grows c.world (boot app c).world
theorem

Cairn.Runtime.tick_mono

provedlean/Cairn/Runtime/WorldProofs.lean:825
tick_mono (w : World) (t : Time) : w.clock.mono ≤ (w.tick t).clock.mono
theorem

Cairn.Runtime.tick_reaches

provedlean/Cairn/Runtime/WorldProofs.lean:828
tick_reaches (w : World) (t : Time) : t.mono ≤ (w.tick t).clock.mono
theorem

Cairn.Runtime.admit_clock_grows

provedlean/Cairn/Runtime/WorldProofs.lean:831
admit_clock_grows {S : Type} (app : App S) (s : State S) (t : Time) :
  Grows (s.world.tick t) (admit app s (Event.clock t)).world
theorem

Cairn.Runtime.promoteGo_same

provedlean/Cairn/Runtime/WorldProofs.lean:839
promoteGo_same (rest : List (Nat × Nat × Request)) (w : World) :
  Same w (w.promoteGo rest).fst
theorem

Cairn.Runtime.promote_same

provedlean/Cairn/Runtime/WorldProofs.lean:844
promote_same (w : World) : Same w w.promote.fst
theorem

Cairn.Runtime.release_grows

provedlean/Cairn/Runtime/WorldProofs.lean:848
release_grows {S : Type} (c : Ctx S) (w : World) (h : Same c.world w) :
  Grows c.world (release c w).world
theorem

Cairn.Runtime.ack_grows

provedlean/Cairn/Runtime/WorldProofs.lean:852
ack_grows {S : Type} (c : Ctx S) (id : Nat) : Grows c.world (ack c id).world
theorem

Cairn.Runtime.admit_grows

provedlean/Cairn/Runtime/WorldProofs.lean:859
admit_grows {S : Type} (app : App S) (s : State S) (e : Event) :
  Grows s.world (admit app s e).world
theorem

Cairn.Runtime.act_grows

provedlean/Cairn/Runtime/WorldProofs.lean:881
act_grows {S : Type} (app : App S) (c : Ctx S) (acts : List Action) :
  Grows c.world (act app c acts).world
theorem

Cairn.Runtime.step_clock

provedlean/Cairn/Runtime/WorldProofs.lean:889
step_clock {S : Type} (app : App S) (cfg : Config) (s : State S) (e : Event) :
  Grows s.world (step app cfg s e).fst.world

A step never moves the clock back, and once the first clock has booted the app it stays booted.

theorem

Cairn.Runtime.step_clock_reaches

provedlean/Cairn/Runtime/WorldProofs.lean:896
step_clock_reaches {S : Type} (app : App S) (cfg : Config) (s : State S)
  (t : Time) : t.mono ≤ (step app cfg s (Event.clock t)).fst.world.clock.mono

A clock event brings the runtime's clock at least to the host's time.

theorem

Cairn.Runtime.steps_go

provedlean/Cairn/Runtime/WorldProofs.lean:905
steps_go {S : Type} (app : App S) (cfg : Config) (P : State S → Prop)
  (hstep : ∀ (s : State S) (e : Event), P s → P (step app cfg s e).fst) (es : List Event)
  (s : State S) (effs : List Effect) :
  P s →
    P
      (List.foldl
          (fun x e =>
            match x with
            | (s, effs) =>
              match step app cfg s e with
              | (s', e') => (s', effs ++ e'))
          (s, effs) es).fst
theorem

Cairn.Runtime.steps_clock

provedlean/Cairn/Runtime/WorldProofs.lean:915
steps_clock {S : Type} (app : App S) (cfg : Config) (s : State S)
  (es : List Event) :
  s.world.clock.mono ≤ (steps app cfg s es).fst.world.clock.mono ∧
    (s.world.booted = true → (steps app cfg s es).fst.world.booted = true)

A batch never moves the clock back.

theorem

Cairn.Runtime.steps_book

provedlean/Cairn/Runtime/WorldProofs.lean:925
steps_book {S : Type} (app : App S) (cfg : Config)
  (s : State (S × List Entry)) (es : List Event) (hb : s.world.booted = true) {b0 : Book}
  (ha : Agrees s.world b0) :
  ∃ new b,
    (steps (logged app) cfg s es).fst.app.snd = s.app.snd ++ new ∧
      b0.run new = some b ∧ Agrees (steps (logged app) cfg s es).fst.world b

Timers and replies. Over any batch of events after the first clock, everything delivered to the app is allowed by the book: a timer reaches receive only while it is set (never after cancelTimer, and once per setTimer), and a reply only to a pending request of the kind it answers, once. And the runtime's tables still agree with the book at the end.

theorem

Cairn.Runtime.absorb1_pending

provedlean/Cairn/Runtime/WorldProofs.lean:942
absorb1_pending (w : World) (e : Effect) {id : Nat} {k : Request.Kind}
  (he : e ≠ Effect.cancelRequest id) (h : List.lookup id w.pending = some k) :
  List.lookup id (w.absorb1 e).fst.pending = some k
theorem

Cairn.Runtime.absorb_pending

provedlean/Cairn/Runtime/WorldProofs.lean:961
absorb_pending (es : List Effect) (w : World) {id : Nat} {k : Request.Kind} :
  ¬Effect.cancelRequest id ∈ es →
    List.lookup id w.pending = some k → List.lookup id (w.absorb es).fst.pending = some k
theorem

Cairn.Runtime.hear_pending

provedlean/Cairn/Runtime/WorldProofs.lean:976
hear_pending {S : Type} (app : App S) (c : Ctx S) {id : Nat}
  {k : Request.Kind} (hq : KeepsOnClock app id)
  (h : List.lookup id c.world.pending = some k) :
  List.lookup id (hear app c).world.pending = some k
theorem

Cairn.Runtime.route_reply

provedlean/Cairn/Runtime/WorldProofs.lean:983
route_reply {S : Type} (m : TextMetrics) (s : State S) (id : Nat)
  (r : Reply) : (route m s (Event.reply id r)).snd = []
theorem

Cairn.Runtime.route_subEvent

provedlean/Cairn/Runtime/WorldProofs.lean:986
route_subEvent {S : Type} (m : TextMetrics) (s : State S) (id : Nat)
  (ev : SubEvent) : (route m s (Event.subEvent id ev)).snd = []
theorem

Cairn.Runtime.step_reply

provedlean/Cairn/Runtime/WorldProofs.lean:993
step_reply {S : Type} (app : App S) (cfg : Config)
  (s : State (S × List Entry)) {id : Nat} {r : Reply} {k : Request.Kind}
  (hk : List.lookup id s.world.pending = some k) (ha : Reply.answers k r = true)
  (hq : KeepsOnClock app id) :
  ∃ es,
    (step (logged app) cfg s (Event.reply id r)).fst.app.snd.getLast? =
      some (Entry.recv (Msg.reply id r) es)

A reply to a pending request, in the shape that answers it, is delivered to receive with the id it was requested under: it is the last thing the app hears in that step. (Unless the app withdrew the request on hearing the time just before: then it is swallowed, step_reply_cancelled.)

theorem

Cairn.Runtime.step_reply_ignored

provedlean/Cairn/Runtime/WorldProofs.lean:1009
step_reply_ignored {S : Type} (app : App S) (cfg : Config) (s : State S)
  {id : Nat} {r : Reply} (h : s.world.takeReply id r = none) :
  (step app cfg s (Event.reply id r)).fst.app = s.app

A reply to an id that is not pending, or in the wrong shape, reaches no one.

theorem

Cairn.Runtime.step_sub

provedlean/Cairn/Runtime/WorldProofs.lean:1015
step_sub {S : Type} (app : App S) (cfg : Config) (s : State (S × List Entry))
  {id : Nat} {sub : Sub} (ev : SubEvent) (h : s.world.subOf id = some sub) :
  ∃ es,
    (step (logged app) cfg s (Event.subEvent id ev)).fst.app.snd.getLast? =
      some (Entry.recv (Msg.sub sub ev) es)

An event from an active subscription is delivered as that subscription's message.

theorem

Cairn.Runtime.step_sub_ignored

provedlean/Cairn/Runtime/WorldProofs.lean:1026
step_sub_ignored {S : Type} (app : App S) (cfg : Config) (s : State S)
  {id : Nat} (ev : SubEvent) (h : s.world.subOf id = none) :
  (step app cfg s (Event.subEvent id ev)).fst.app = s.app

An event for a subscription that is not active (stopped, or never started) reaches no one.

theorem

Cairn.Runtime.mem_freshSubs

provedlean/Cairn/Runtime/WorldProofs.lean:1033
mem_freshSubs (want seen : List Sub) (x : Sub) :
  x ∈ freshSubs seen want ↔ x ∈ want ∧ ¬x ∈ seen
theorem

Cairn.Runtime.mem_number

provedlean/Cairn/Runtime/WorldProofs.lean:1061
mem_number (l : List Sub) (n id : Nat) (x : Sub) :
  (id, x) ∈ number n l → x ∈ l ∧ n ≤ id ∧ id < n + l.length
theorem

Cairn.Runtime.number_mem

provedlean/Cairn/Runtime/WorldProofs.lean:1073
number_mem (l : List Sub) (n : Nat) (x : Sub) :
  x ∈ l → ∃ id, (id, x) ∈ number n l
theorem

Cairn.Runtime.contains_false

provedlean/Cairn/Runtime/WorldProofs.lean:1083
contains_false {l : List Sub} {x : Sub} : (!l.contains x) = true ↔ ¬x ∈ l
theorem

Cairn.Runtime.diffSubs_stop

provedlean/Cairn/Runtime/WorldProofs.lean:1087
diffSubs_stop (active : List (Nat × Sub)) (want : List Sub) (next id : Nat) :
  SubCmd.stop id ∈ (diffSubs active want next).snd.fst ↔
    ∃ sub, (id, sub) ∈ active ∧ ¬sub ∈ want

The diff stops exactly the running subscriptions the app no longer wants.

theorem

Cairn.Runtime.diffSubs_start

provedlean/Cairn/Runtime/WorldProofs.lean:1098
diffSubs_start (active : List (Nat × Sub)) (want : List Sub) (next id : Nat)
  (sub : Sub) :
  SubCmd.start id sub ∈ (diffSubs active want next).snd.fst ↔
    (id, sub) ∈
      number next
        (freshSubs
          (List.map (fun x => x.snd) (List.filter (fun p => want.contains p.snd) active))
          want)

The new subscriptions the diff starts, under the ids it gives them.

theorem

Cairn.Runtime.fresh_iff

provedlean/Cairn/Runtime/WorldProofs.lean:1108
fresh_iff (active : List (Nat × Sub)) (want : List Sub) (sub : Sub) :
  sub ∈
      freshSubs
        (List.map (fun x => x.snd) (List.filter (fun p => want.contains p.snd) active))
        want ↔
    sub ∈ want ∧ ∀ (id : Nat), ¬(id, sub) ∈ active
theorem

Cairn.Runtime.diffSubs_starts

provedlean/Cairn/Runtime/WorldProofs.lean:1120
diffSubs_starts (active : List (Nat × Sub)) (want : List Sub) (next : Nat)
  (sub : Sub) :
  (∃ id, SubCmd.start id sub ∈ (diffSubs active want next).snd.fst) ↔
    sub ∈ want ∧ ∀ (id : Nat), ¬(id, sub) ∈ active

The diff starts exactly the wanted subscriptions that are not running, each once.

theorem

Cairn.Runtime.diffSubs_fresh

provedlean/Cairn/Runtime/WorldProofs.lean:1129
diffSubs_fresh (active : List (Nat × Sub)) (want : List Sub) (next id : Nat)
  (sub : Sub) (h : SubCmd.start id sub ∈ (diffSubs active want next).snd.fst) :
  next ≤ id ∧ id < (diffSubs active want next).snd.snd

Started subscriptions get fresh ids: at least next and below the new next.

theorem

Cairn.Runtime.diffSubs_active

provedlean/Cairn/Runtime/WorldProofs.lean:1143
diffSubs_active (active : List (Nat × Sub)) (want : List Sub) (next : Nat)
  (sub : Sub) : sub ∈ List.map (fun x => x.snd) (diffSubs active want next).fst ↔ sub ∈ want

After the diff, the running subscriptions are exactly the ones the app wants.

theorem

Cairn.Runtime.lookup_eq_none

provedlean/Cairn/Runtime/WorldProofs.lean:1159
lookup_eq_none {β : Type} (l : List (Nat × β)) (id : Nat)
  (h : ∀ (x : β), ¬(id, x) ∈ l) : List.lookup id l = none
theorem

Cairn.Runtime.diffSubs_stopped

provedlean/Cairn/Runtime/WorldProofs.lean:1172
diffSubs_stopped (active : List (Nat × Sub)) (want : List Sub) (next id : Nat)
  (hlt : ∀ (p : Nat × Sub), p ∈ active → p.fst < next)
  (hu : ∀ (a b : Sub), (id, a) ∈ active → (id, b) ∈ active → a = b)
  (h : SubCmd.stop id ∈ (diffSubs active want next).snd.fst) :
  List.lookup id (diffSubs active want next).fst = none

A stopped subscription is gone from the active set (when ids are below next and name one subscription each, as diffSubs keeps them), so its late events reach no one (step_sub_ignored).