diff --git a/multris/channel/proto.v b/multris/channel/proto.v
index 950d5f43e8bb68f3bd8e5726d39dc10a997965c2..8849b59948c1dfe7603ad3c6178fcd6e6cbd96cf 100644
--- a/multris/channel/proto.v
+++ b/multris/channel/proto.v
@@ -117,6 +117,15 @@ Definition iProto_message_eq :
 Arguments iProto_message {_ _} _ _%_msg.
 Global Instance: Params (@iProto_message) 3 := {}.
 
+Definition iProto_union_def {Σ V} (p1 p2 : iProto Σ V) : iProto Σ V :=
+  proto_union p1 p2.
+Definition iProto_union_aux : seal (@iProto_union_def). by eexists. Qed.
+Definition iProto_union := iProto_union_aux.(unseal).
+Definition iProto_union_eq :
+  @iProto_union = @iProto_union_def := iProto_union_aux.(seal_eq).
+Arguments iProto_union {_ _} _ _%_msg.
+Global Instance: Params (@iProto_union) 3 := {}.
+
 Notation "'END'" := iProto_end : proto_scope.
 
 Notation "< a > m" := (iProto_message a m)
@@ -129,6 +138,8 @@ Notation "< a @.. x1 .. xn > m" := (iProto_message a (∃.. x1, .. (∃.. xn, m)
   (at level 200, a at level 10, x1 closed binder, xn closed binder, m at level 200,
    format "< a  @..  x1  ..  xn >  m") : proto_scope.
 
+Infix "<+>'" := iProto_union (at level 20) : proto_scope.
+
 Class MsgTele {Σ V} {TT : tele} (m : iMsg Σ V)
     (tv : TT -t> V) (tP : TT -t> iProp Σ) (tp : TT -t> iProto Σ V) :=
   msg_tele : m ≡ (∃.. x, MSG tele_app tv x {{ tele_app tP x }}; tele_app tp x)%msg.
@@ -140,51 +151,134 @@ Program Definition iMsg_map {Σ V}
   IMsg (λ v, λne p1', ∃ p1, iMsg_car m v (Next p1) ∗ p1' ≡ Next (rec p1))%I.
 Next Obligation. solve_proper. Qed.
 
-(* Program Definition iProto_map_app_aux {Σ V} *)
-(*     (f : action → action) (p2 : iProto Σ V) *)
-(*     (rec : iProto Σ V -n> iProto Σ V) : iProto Σ V -n> iProto Σ V := λne p, *)
-(*   proto_elim p2 (λ a m, *)
-(*     proto_message (f a) (iMsg_car (iMsg_map rec (IMsg m)))) p. *)
-(* Next Obligation. *)
-(*   intros Σ V f p2 rec n p1 p1' Hp. apply proto_elim_ne=> // a m1 m2 Hm. *)
-(*   apply proto_message_ne=> v p' /=. by repeat f_equiv. *)
-(* Qed. *)
 
-(* Global Instance iProto_map_app_aux_contractive {Σ V} f (p2 : iProto Σ V) : *)
-(*   Contractive (iProto_map_app_aux f p2). *)
-(* Proof. *)
-(*   intros n rec1 rec2 Hrec p1; simpl. apply proto_elim_ne=> // a m1 m2 Hm. *)
-(*   apply proto_message_ne=> v p' /=. by repeat (f_contractive || f_equiv). *)
-(* Qed. *)
+(* TODO: Move to proto_model.v *)
+Lemma fold_left_ne {A B : ofe} (f1 f2 : A → B → A) (xs1 xs2 : list B) (y1 y2 : A) n :
+  (∀ a1 a2 y1 y2, a1 ≡{n}≡ a2 → y1 ≡{n}≡ y2 → f1 a1 y1 ≡{n}≡ f2 a2 y2) →
+  y1 ≡{n}≡ y2 →
+  xs1 ≡{n}≡ xs2 →
+  fold_left f1 xs1 y1 ≡{n}≡ fold_left f2 xs2 y2.
+Proof.
+  revert xs2. revert y1 y2.
+  induction xs1 as [|x1 xs1 IHxs1].
+  - intros y1 y2 xs2 Hf Hx Hxs.
+    destruct xs2; [|by inversion Hxs].
+    simpl. done.
+  - intros y1 y2 xs2 Hf Hx Hxs.
+    destruct xs2; [by inversion Hxs|].
+    inversion Hxs; subst.
+    simpl. apply IHxs1; try done.
+    by apply Hf.
+Qed.
+
+Definition proto_elim {V} `{!Cofe PROPn, !Cofe PROP} {A}
+    (x y : A) (f : A → action → (V → laterO (proto V PROP PROPn) -n> PROP) → A)
+    (p : proto V PROPn PROP) : A :=
+  match p with
+  | [] => x
+  | p  => fold_left (λ acc am, f acc (am.1) (λ v, am.2 v ◎ laterO_map proto_unfold)) p y
+  end.
+Global Arguments proto_elim : simpl never.
+
+
+Lemma proto_elim_ne {V} `{!Cofe PROPn, !Cofe PROP} {A : ofe}
+    (x y : A) (f1 f2 : A → action → (V → laterO (proto V PROP PROPn) -n> PROP) → A) p1 p2 n :
+  (∀ x1 x2 a m1 m2, x1 ≡{n}≡ x2 → (∀ v, m1 v ≡{n}≡ m2 v) → f1 x1 a m1 ≡{n}≡ f2 x2 a m2) →
+  p1 ≡{n}≡ p2 →
+  proto_elim x y f1 p1 ≡{n}≡ proto_elim x y f2 p2.
+Proof.
+  rewrite /proto_elim. intros Hf. revert p2.
+  destruct p1 as [|[a m] p1].
+  - intros p2 Hp. by inversion Hp.
+  - intros p2 Hp. destruct p2 as [|[a2 m2]]; [by inversion Hp|].
+    apply (fold_left_ne _ _ ((a, m) :: p1)); try done.
+    intros *. intros Ha Hx. destruct y1, y2. simpl in *.
+    destruct Hx. simpl in *. destruct H.
+    apply Hf; try done.
+    intros *. f_equiv. done.
+Qed.
 
-(* Definition iProto_map_app {Σ V} (f : action → action) *)
-(*     (p2 : iProto Σ V) : iProto Σ V -n> iProto Σ V := *)
-(*   fixpoint (iProto_map_app_aux f p2). *)
-
-(* Definition iProto_app_def {Σ V} (p1 p2 : iProto Σ V) : iProto Σ V := *)
-(*   iProto_map_app id p2 p1. *)
-(* Definition iProto_app_aux : seal (@iProto_app_def). Proof. by eexists. Qed. *)
-(* Definition iProto_app := iProto_app_aux.(unseal). *)
-(* Definition iProto_app_eq : @iProto_app = @iProto_app_def := iProto_app_aux.(seal_eq). *)
-(* Arguments iProto_app {_ _} _%_proto _%_proto. *)
-(* Global Instance: Params (@iProto_app) 2 := {}. *)
-(* Infix "<++>" := iProto_app (at level 60) : proto_scope. *)
-(* Notation "m <++> p" := (iMsg_map (flip iProto_app p) m) : msg_scope. *)
-
-(* Definition iProto_dual_def {Σ V} (p : iProto Σ V) : iProto Σ V := *)
-(*   iProto_map_app action_dual proto_end p. *)
-(* Definition iProto_dual_aux : seal (@iProto_dual_def). Proof. by eexists. Qed. *)
-(* Definition iProto_dual := iProto_dual_aux.(unseal). *)
-(* Definition iProto_dual_eq : *)
-(*   @iProto_dual = @iProto_dual_def := iProto_dual_aux.(seal_eq). *)
-(* Arguments iProto_dual {_ _} _%_proto. *)
-(* Global Instance: Params (@iProto_dual) 2 := {}. *)
-(* Notation iMsg_dual := (iMsg_map iProto_dual). *)
-
-(* Definition iProto_dual_if {Σ V} (d : bool) (p : iProto Σ V) : iProto Σ V := *)
-(*   if d then iProto_dual p else p. *)
-(* Arguments iProto_dual_if {_ _} _ _%_proto. *)
-(* Global Instance: Params (@iProto_dual_if) 3 := {}. *)
+Lemma proto_elim_end {V} `{!Cofe PROPn, !Cofe PROP} {A : ofe}
+    (x y : A) (f : A → action → (V → laterO (proto V PROP PROPn) -n> PROP) → A) :
+  proto_elim x y f proto_end ≡ x.
+Proof. done. Qed.
+
+Lemma proto_elim_message {V} `{!Cofe PROPn, !Cofe PROP} {A : ofe}
+    (x y : A) (f : A → action → (V → laterO (proto V PROP PROPn) -n> PROP) → A) (a:action) m :
+  (Proper ((≡) ==> (=) ==> (pointwise_relation _ (≡)) ==> (≡)) f) →
+  proto_elim x y f (proto_message a m) ≡ f y a m.
+Proof.
+  intros. rewrite /proto_elim /proto_message /=. f_equiv=> v p /=. f_equiv.
+  rewrite -later_map_compose -{2}(later_map_id p).
+  apply later_map_ext=> p' /=. by rewrite proto_fold_unfold.
+Qed.
+
+(* TODO: Consider using cons over union *)
+Lemma proto_elim_union {V} `{!Cofe PROPn, !Cofe PROP} {A : ofe}
+    (x y : A) (f : A → action → (V → laterO (proto V PROP PROPn) -n> PROP) → A) p1 p2 :
+  (Proper ((≡) ==> (=) ==> (pointwise_relation _ (≡)) ==> (≡)) f) →
+  proto_elim x y f (proto_union p1 p2) ≡ proto_elim x (proto_elim x y f p1) f p2 .
+Proof. Admitted.
+
+Program Definition iProto_map_app_aux {Σ V}
+  (f : action → action)
+  (p2 : iProto Σ V)
+  (rec: iProto Σ V -n> iProto Σ V)
+  : iProto Σ V -n> iProto Σ V := λne p,
+  proto_elim p2 proto_end
+    (λ acc a (m : V → laterO (iProto Σ V) -n> iProp Σ),
+      proto_union
+        (proto_message (f a) (iMsg_car (iMsg_map rec (IMsg m)))) acc) p.
+Next Obligation.
+  intros Σ V f p2 rec n p1 p1' Hp. apply proto_elim_ne=> // p1'' p2' m1 m2 Ha Hp' Hm.
+  apply proto_union_ne; [|done].
+  simpl. 
+  apply proto_message_ne=> v p' /=. by repeat f_equiv.
+Qed.
+Global Arguments iProto_map_app_aux : simpl never.
+
+Global Instance iProto_map_app_aux_contractive {Σ V} f (p2 : iProto Σ V) :
+  Contractive (iProto_map_app_aux f p2).
+Proof.  
+  intros n rec1 rec2 Hrec p1; simpl. apply proto_elim_ne=> // p1' p2' m1 m2 Ha Hm Hf.
+  f_equiv; [|done].
+  apply pair_ne; [solve_proper|].
+  intros v m. simpl.
+  by repeat (f_contractive || f_equiv).
+Qed.
+
+Definition iProto_map_app {Σ V} (f : action → action)
+    (p2 : iProto Σ V) : iProto Σ V -n> iProto Σ V :=
+  fixpoint (iProto_map_app_aux f p2).
+
+Definition iProto_app_def {Σ V} (p1 p2 : iProto Σ V) : iProto Σ V :=
+  iProto_map_app id p2 p1.
+Definition iProto_app_aux : seal (@iProto_app_def). Proof. by eexists. Qed.
+Definition iProto_app := iProto_app_aux.(unseal).
+Definition iProto_app_eq : @iProto_app = @iProto_app_def := iProto_app_aux.(seal_eq).
+Arguments iProto_app {_ _} _%_proto _%_proto.
+Global Instance: Params (@iProto_app) 2 := {}.
+Infix "<++>" := iProto_app (at level 60) : proto_scope.
+Notation "m <++> p" := (iMsg_map (flip iProto_app p) m) : msg_scope.
+Lemma iProto_app_unfold {Σ V} (p1 p2 : iProto Σ V) :
+  iProto_app p1 p2 ≡ iProto_map_app_aux id p2 (iProto_map_app id p2) p1.
+Proof. rewrite iProto_app_eq. rewrite /iProto_app_def /iProto_map_app.
+       apply: (fixpoint_unfold (iProto_map_app_aux id p2)). Qed.
+
+Definition iProto_dual_def {Σ V} (p : iProto Σ V) : iProto Σ V :=
+  iProto_map_app action_dual proto_end p.
+Definition iProto_dual_aux : seal (@iProto_dual_def). Proof. by eexists. Qed.
+Definition iProto_dual := iProto_dual_aux.(unseal).
+Definition iProto_dual_eq :
+  @iProto_dual = @iProto_dual_def := iProto_dual_aux.(seal_eq).
+Arguments iProto_dual {_ _} _%_proto.
+Global Instance: Params (@iProto_dual) 2 := {}.
+Notation iMsg_dual := (iMsg_map iProto_dual).
+
+Definition iProto_dual_if {Σ V} (d : bool) (p : iProto Σ V) : iProto Σ V :=
+  if d then iProto_dual p else p.
+Arguments iProto_dual_if {_ _} _ _%_proto.
+Global Instance: Params (@iProto_dual_if) 3 := {}.
 
 (** * Proofs *)
 Section proto.
@@ -194,11 +288,19 @@ Section proto.
   Implicit Types m : iMsg Σ V.
 
   (** ** Equality *)
+  Lemma iProto_case p : p ≡ END ∨ ∃ t n m ps, p ≡ proto_union (iProto_message (t, n) m) ps.
+  Proof.
+    (* rewrite iProto_end_eq. destruct p. left. done. right. *)
+    (* eexists _, (IMsg <$> p). done. *)
+    (* done. done. *)
+    destruct (proto_case p) as [|([t n] & m & ps & Hps)]; [left; by rewrite iProto_end_eq|].
+    right. exists t, n, (IMsg m), ps. rewrite iProto_message_eq. done.
+  Qed.
   (* Lemma iProto_case p : p ≡ END ∨ ∃ t n m, p ≡ <(t,n)> m. *)
   (* Proof. *)
   (*   rewrite iProto_message_eq iProto_end_eq. *)
   (*   destruct (proto_case p) as [|([a n]&m&?)]; [by left|right]. *)
-  (*   by exists a, n, (IMsg m). *)
+  (*   exists a, n, (IMsg m). *)
   (* Qed. *)
   Lemma iProto_message_equivI a1 a2 m1 m2 :
     (<a1> m1) ≡ (<a2> m2) ⊣⊢@{iProp Σ} ⌜ a1 = a2 ⌝ ∧
@@ -316,36 +418,36 @@ Section proto.
   Qed.
 
   (** ** Dual *)
-  (* Global Instance iProto_dual_ne : NonExpansive (@iProto_dual Σ V). *)
-  (* Proof. rewrite iProto_dual_eq. solve_proper. Qed. *)
-  (* Global Instance iProto_dual_proper : Proper ((≡) ==> (≡)) (@iProto_dual Σ V). *)
-  (* Proof. apply (ne_proper _). Qed. *)
-  (* Global Instance iProto_dual_if_ne d : NonExpansive (@iProto_dual_if Σ V d). *)
-  (* Proof. solve_proper. Qed. *)
-  (* Global Instance iProto_dual_if_proper d : *)
-  (*   Proper ((≡) ==> (≡)) (@iProto_dual_if Σ V d). *)
-  (* Proof. apply (ne_proper _). Qed. *)
-
-  (* Lemma iProto_dual_end : iProto_dual (Σ:=Σ) (V:=V) END ≡ END. *)
-  (* Proof. *)
-  (*   rewrite iProto_end_eq iProto_dual_eq /iProto_dual_def /iProto_map_app. *)
-  (*   etrans; [apply (fixpoint_unfold (iProto_map_app_aux _ _))|]; simpl. *)
-  (*   by rewrite proto_elim_end. *)
-  (* Qed. *)
-  (* Lemma iProto_dual_message a m : *)
-  (*   iProto_dual (<a> m) ≡ <action_dual a> iMsg_dual m. *)
-  (* Proof. *)
-  (*   rewrite iProto_message_eq iProto_dual_eq /iProto_dual_def /iProto_map_app. *)
-  (*   etrans; [apply (fixpoint_unfold (iProto_map_app_aux _ _))|]; simpl. *)
-  (*   rewrite /iProto_message_def. rewrite ->proto_elim_message; [done|]. *)
-  (*   intros a' m1 m2 Hm; f_equiv; solve_proper. *)
-  (* Qed. *)
-  (* Lemma iMsg_dual_base v P p : *)
-  (*   iMsg_dual (MSG v {{ P }}; p) ≡ (MSG v {{ P }}; iProto_dual p)%msg. *)
-  (* Proof. apply iMsg_map_base, _. Qed. *)
-  (* Lemma iMsg_dual_exist {A} (m : A → iMsg Σ V) : *)
-  (*   iMsg_dual (∃ x, m x) ≡ (∃ x, iMsg_dual (m x))%msg. *)
-  (* Proof. apply iMsg_map_exist. Qed. *)
+  Global Instance iProto_dual_ne : NonExpansive (@iProto_dual Σ V).
+  Proof. rewrite iProto_dual_eq. solve_proper. Qed.
+  Global Instance iProto_dual_proper : Proper ((≡) ==> (≡)) (@iProto_dual Σ V).
+  Proof. apply (ne_proper _). Qed.
+  Global Instance iProto_dual_if_ne d : NonExpansive (@iProto_dual_if Σ V d).
+  Proof. solve_proper. Qed.
+  Global Instance iProto_dual_if_proper d :
+    Proper ((≡) ==> (≡)) (@iProto_dual_if Σ V d).
+  Proof. apply (ne_proper _). Qed.
+
+  Lemma iProto_dual_end : iProto_dual (Σ:=Σ) (V:=V) END ≡ END.
+  Proof.
+    rewrite iProto_end_eq iProto_dual_eq /iProto_dual_def /iProto_map_app.
+    etrans; [apply (fixpoint_unfold (iProto_map_app_aux _ _))|]; simpl.
+    by rewrite proto_elim_end.
+  Qed.
+  Lemma iProto_dual_message a m :
+    iProto_dual (<a> m) ≡ <action_dual a> iMsg_dual m.
+  Proof.
+    rewrite iProto_message_eq iProto_dual_eq /iProto_dual_def /iProto_map_app.
+    etrans; [apply (fixpoint_unfold (iProto_map_app_aux _ _))|]; simpl.
+    rewrite /iProto_message_def. rewrite ->proto_elim_message; [done|].
+    intros p1 p2 Hp a' ? <- m1 m2 Hm. f_equiv; [|done]. f_equiv. solve_proper.
+  Qed.
+  Lemma iMsg_dual_base v P p :
+    iMsg_dual (MSG v {{ P }}; p) ≡ (MSG v {{ P }}; iProto_dual p)%msg.
+  Proof. apply iMsg_map_base, _. Qed.
+  Lemma iMsg_dual_exist {A} (m : A → iMsg Σ V) :
+    iMsg_dual (∃ x, m x) ≡ (∃ x, iMsg_dual (m x))%msg.
+  Proof. apply iMsg_map_exist. Qed.
 
   (* Global Instance iProto_dual_involutive : Involutive (≡) (@iProto_dual Σ V). *)
   (* Proof. *)
@@ -363,43 +465,60 @@ Section proto.
   (*     rewrite Hp'. iSplitL; [by auto|]. iIntros "!>". by iRewrite ("IH" $! p''). *)
   (* Qed. *)
 
-  (* (** ** Append *) *)
-  (* Global Instance iProto_app_end_l : LeftId (≡) END (@iProto_app Σ V). *)
-  (* Proof. *)
-  (*   intros p. rewrite iProto_end_eq iProto_app_eq /iProto_app_def /iProto_map_app. *)
-  (*   etrans; [apply (fixpoint_unfold (iProto_map_app_aux _ _))|]; simpl. *)
-  (*   by rewrite proto_elim_end. *)
-  (* Qed. *)
-  (* Lemma iProto_app_message a m p2 : (<a> m) <++> p2 ≡ <a> m <++> p2. *)
-  (* Proof. *)
-  (*   rewrite iProto_message_eq iProto_app_eq /iProto_app_def /iProto_map_app. *)
-  (*   etrans; [apply (fixpoint_unfold (iProto_map_app_aux _ _))|]; simpl. *)
-  (*   rewrite /iProto_message_def. rewrite ->proto_elim_message; [done|]. *)
-  (*   intros a' m1 m2 Hm. f_equiv; solve_proper. *)
+  (** ** Append *)
+  Global Instance iProto_app_end_l : LeftId (≡) END (@iProto_app Σ V).
+  Proof.
+    intros p. rewrite iProto_end_eq iProto_app_eq /iProto_app_def /iProto_map_app.
+    etrans; [apply (fixpoint_unfold (iProto_map_app_aux _ _))|]; simpl.
+    by rewrite proto_elim_end.
+  Qed.
+  Lemma iProto_app_message a m p : (<a> m) <++> p ≡ <a> m <++> p.
+  Proof.
+    rewrite iProto_message_eq iProto_app_eq /iProto_app_def /iProto_map_app.
+    etrans; [apply (fixpoint_unfold (iProto_map_app_aux _ _))|].
+    rewrite /iProto_message_def. simpl.
+    rewrite ->proto_elim_message; [done|].
+    intros p1 p2 Hp a1 a2 Ha m1 m2 Hm. f_equiv; [|solve_proper].
+    f_equiv; [done|]. solve_proper.
+  Qed.
+  Lemma iProto_app_union p1 p2 p :
+    p1 ≠ END → p2 ≠ END →
+    (proto_union p1 p2) <++> p ≡ proto_union (p1 <++> p) (p2 <++> p).
+  Proof. Admitted.
+  (*   rewrite iProto_app_eq /iProto_app_def /iProto_map_app. *)
+  (*   (* rewrite iProto_message_eq iProto_app_eq /iProto_app_def /iProto_map_app. *) *)
+  (*   etrans; [apply (fixpoint_unfold (iProto_map_app_aux _ _))|]. *)
+  (*   simpl. *)
+  (*   rewrite ->proto_elim_union. *)
+  (*   { rewrite /proto_elim. induction p2; [simpl|]. *)
+  (*     {  rewrite /proto_union.  } *)
+  (*   intros p1' p2' Hp a1 a2 Ha m1 m2 Hm. f_equiv; [|solve_proper]. *)
+  (*   f_equiv; [done|]. solve_proper. *)
   (* Qed. *)
-
-  (* Global Instance iProto_app_ne : NonExpansive2 (@iProto_app Σ V). *)
-  (* Proof. *)
-  (*   assert (∀ n, Proper (dist n ==> (=) ==> dist n) (@iProto_app Σ V)). *)
-  (*   { intros n p1 p1' Hp1 p2 p2' <-. by rewrite iProto_app_eq /iProto_app_def Hp1. } *)
-  (*   assert (Proper ((≡) ==> (=) ==> (≡)) (@iProto_app Σ V)). *)
-  (*   { intros p1 p1' Hp1 p2 p2' <-. by rewrite iProto_app_eq /iProto_app_def Hp1. } *)
-  (*   intros n p1 p1' Hp1 p2 p2' Hp2. rewrite Hp1. clear p1 Hp1. *)
-  (*   revert p1'. induction (lt_wf n) as [n _ IH]; intros p1. *)
+  
+  Global Instance iProto_app_ne : NonExpansive2 (@iProto_app Σ V).
+  Proof.
+    assert (∀ n, Proper (dist n ==> (=) ==> dist n) (@iProto_app Σ V)).
+    { intros n p1 p1' Hp1 p2 p2' <-. by rewrite iProto_app_eq /iProto_app_def Hp1. }
+    assert (Proper ((≡) ==> (=) ==> (≡)) (@iProto_app Σ V)).
+    { intros p1 p1' Hp1 p2 p2' <-. by rewrite iProto_app_eq /iProto_app_def Hp1. }
+    intros n p1 p1' Hp1 p2 p2' Hp2. rewrite Hp1. clear p1 Hp1.
+    revert p1'. induction (lt_wf n) as [n _ IH]; intros p1.
+  Admitted.    
   (*   destruct (iProto_case p1) as [->|(a&i&m&->)]. *)
   (*   { by rewrite !left_id. } *)
   (*   rewrite !iProto_app_message. f_equiv=> v p' /=. do 4 f_equiv. *)
   (*   f_contractive. apply IH; eauto using dist_le with lia. *)
   (* Qed. *)
-  (* Global Instance iProto_app_proper : Proper ((≡) ==> (≡) ==> (≡)) (@iProto_app Σ V). *)
-  (* Proof. apply (ne_proper_2 _). Qed. *)
+  Global Instance iProto_app_proper : Proper ((≡) ==> (≡) ==> (≡)) (@iProto_app Σ V).
+  Proof. apply (ne_proper_2 _). Qed.
 
-  (* Lemma iMsg_app_base v P p1 p2 : *)
-  (*   ((MSG v {{ P }}; p1) <++> p2)%msg ≡ (MSG v {{ P }}; p1 <++> p2)%msg. *)
-  (* Proof. apply: iMsg_map_base. Qed. *)
-  (* Lemma iMsg_app_exist {A} (m : A → iMsg Σ V) p2 : *)
-  (*   ((∃ x, m x) <++> p2)%msg ≡ (∃ x, m x <++> p2)%msg. *)
-  (* Proof. apply iMsg_map_exist. Qed. *)
+  Lemma iMsg_app_base v P p1 p2 :
+    ((MSG v {{ P }}; p1) <++> p2)%msg ≡ (MSG v {{ P }}; p1 <++> p2)%msg.
+  Proof. apply: iMsg_map_base. Qed.
+  Lemma iMsg_app_exist {A} (m : A → iMsg Σ V) p2 :
+    ((∃ x, m x) <++> p2)%msg ≡ (∃ x, m x <++> p2)%msg.
+  Proof. apply iMsg_map_exist. Qed.
 
   (* Global Instance iProto_app_end_r : RightId (≡) END (@iProto_app Σ V). *)
   (* Proof. *)
@@ -447,7 +566,7 @@ Section proto.
   (*     iExists (p1d <++> p2). iSplitL; [by auto|]. *)
   (*     iRewrite "Hp12". iIntros "!>". iRewrite "Hp1'". by iRewrite ("IH" $! p1d p2). *)
   (* Qed. *)
-
+  
 End proto.
 
 Global Instance iProto_inhabited {Σ V} : Inhabited (iProto Σ V) := populate END.
diff --git a/multris/channel/proto_model.v b/multris/channel/proto_model.v
index c706776fe04507d862210b42352a8ea4fdf23fa2..2e112b1079861576bd6654526f24ba5ab315c0e2 100644
--- a/multris/channel/proto_model.v
+++ b/multris/channel/proto_model.v
@@ -64,12 +64,12 @@ Module Export action.
   Proof. by intros [[]]. Qed.
 End action.
 
-Notation proto_aux V PROP A :=
-  (gmap action (V -d> laterO A -n> PROP)).
-Notation proto_auxO V PROP A :=
-  (gmapO actionO (V -d> laterO A -n> PROP)).
+Definition proto_aux V PROP A :=
+  (list (prod action (V -d> laterO A -n> PROP))).
+Definition proto_auxO V PROP A :=
+  (listO (prod actionO (V -d> laterO A -n> PROP))).
 Definition proto_auxOF V PROP :=
-  (gmapOF actionO ((V -d> ▶ ∙ -n> PROP))).
+  (listOF (actionO * ((V -d> ▶ ∙ -n> PROP)))).
 
 Definition proto_result (V : Type) := result_2 (proto_auxOF V).
 Definition pre_protoO (V : Type) (PROPn PROP : ofe) `{!Cofe PROPn, !Cofe PROP} : ofe :=
@@ -105,25 +105,29 @@ Lemma proto_unfold_fold {V} `{!Cofe PROPn, !Cofe PROP}
   proto_unfold (proto_fold p) ≡ p.
 Proof. apply (ofe_iso_12 proto_iso). Qed.
 
-Definition proto_end {V} `{!Cofe PROPn, !Cofe PROP} : proto V PROPn PROP := ∅ .
+Definition proto_end {V} `{!Cofe PROPn, !Cofe PROP} : proto V PROPn PROP := [].
 Definition proto_message {V} `{!Cofe PROPn, !Cofe PROP} (a : action)
   (m : V -d> later (proto V PROP PROPn) -n> PROP) : proto V PROPn PROP :=
-  ({[a := (λ v, m v ◎ laterO_map proto_fold)]}).
+  ([(a,(λ v, m v ◎ laterO_map proto_fold))]).
 Definition proto_union {V} `{!Cofe PROPn, !Cofe PROP} (p1 p2 : proto V PROPn PROP) : proto V PROPn PROP :=
-  (p1:gmap _ _) ∪ p2.
+  p1 ++ p2.
 
 Global Instance proto_message_ne {V} `{!Cofe PROPn, !Cofe PROP} a n :
   Proper (pointwise_relation V (dist n) ==> dist n)
          (proto_message (PROPn:=PROPn) (PROP:=PROP) a).
 Proof.
-  intros c1 c2 Hc. rewrite /proto_message.
-  apply insert_ne; [|done]. solve_proper.
+  intros c1 c2 Hc. rewrite /proto_message. simpl.
+  f_equiv.
+  - apply pair_ne.
+    + done.
+    + solve_proper.
+  - done.
 Qed.
 
 Global Instance proto_message_proper {V} `{!Cofe PROPn, !Cofe PROP} a :
   Proper (pointwise_relation V (≡) ==> (≡))
          (proto_message (PROPn:=PROPn) (PROP:=PROP) a).
-Proof. intros c1 c2 Hc. rewrite /proto_message. apply: insert_proper; [|done]. solve_proper.
+Proof. intros c1 c2 Hc. rewrite /proto_message. repeat f_equiv. solve_proper.
 Qed.
 
 Global Instance proto_union_ne {V} `{!Cofe PROPn, !Cofe PROP} n :
@@ -141,176 +145,200 @@ Proof.
   intros p11 p12 Hp1 p21 p22 Hp2. rewrite /proto_union. by f_equiv.
 Qed.
 
-(* Should hold in the same way map_ind holds *)
+(* TODO: This is FALSE *)
 Lemma proto_ind {V} `{!Cofe PROPn, !Cofe PROP} (P : proto V PROPn PROP → Prop) :
   Proper ((≡) ==> impl) P →
-  P proto_end → (∀ i x p, p !! i ≡ None → P p → P (proto_union (proto_message i x) p)) → ∀ m, P m.
-Proof.
-  intros HP ? Hins m.
-  induction (map_wf m) as [m _ IH].
-  destruct (map_choose_or_empty m) as [(i&x&?)| H'].
-  {
-    assert (m ≡ proto_union (proto_message i (λ v, x v ◎ laterO_map proto_unfold)) (delete i m)) as Heq.
-    {
-      rewrite /proto_message /proto_union.
-      rewrite -insert_union_singleton_l.
-      intros i'.
-      (* TODO: Simplify *)
-      destruct (decide (i=i')) as [->|].
-      { rewrite H0. rewrite lookup_insert. f_equiv.
-        intros v.
-        intros x''.
-        simpl.
-        rewrite -later_map_compose.
-        simpl. f_equiv.
-        destruct x''.
-        rewrite later_map_Next. f_equiv.
-        simpl. rewrite proto_unfold_fold. done. }
-      rewrite lookup_insert_ne; [|done].
-      by rewrite lookup_delete_ne. }
-    rewrite Heq.
-    apply Hins.
-    { by rewrite lookup_delete. }
-    eapply IH. by apply: delete_subset.
-  }
-  rewrite /proto_end in H.
-  by rewrite -H' in H.
-Qed.
-  
+  P proto_end → (∀ i x p, p ≡ [] → P p → P (proto_union (proto_message i x) p)) → ∀ m, P m.
+(* Proof. *)
+(* (* Should hold in the same way map_ind holds *) *)
+(* Lemma proto_ind {V} `{!Cofe PROPn, !Cofe PROP} (P : proto V PROPn PROP → Prop) : *)
+(*   Proper ((≡) ==> impl) P → *)
+(*   P proto_end → (∀ i x p, p !! i ≡ None → P p → P (proto_union (proto_message i x) p)) → ∀ m, P m. *)
+(* Proof. *)
+(*   intros HP ? Hins m. *)
+(*   induction (map_wf m) as [m _ IH]. *)
+(*   destruct (map_choose_or_empty m) as [(i&x&?)| H']. *)
+(*   { *)
+(*     assert (m ≡ proto_union (proto_message i (λ v, x v ◎ laterO_map proto_unfold)) (delete i m)) as Heq. *)
+(*     { *)
+(*       rewrite /proto_message /proto_union. *)
+(*       rewrite -insert_union_singleton_l. *)
+(*       intros i'. *)
+(*       (* TODO: Simplify *) *)
+(*       destruct (decide (i=i')) as [->|]. *)
+(*       { rewrite H0. rewrite lookup_insert. f_equiv. *)
+(*         intros v. *)
+(*         intros x''. *)
+(*         simpl. *)
+(*         rewrite -later_map_compose. *)
+(*         simpl. f_equiv. *)
+(*         destruct x''. *)
+(*         rewrite later_map_Next. f_equiv. *)
+(*         simpl. rewrite proto_unfold_fold. done. } *)
+(*       rewrite lookup_insert_ne; [|done]. *)
+(*       by rewrite lookup_delete_ne. } *)
+(*     rewrite Heq. *)
+(*     apply Hins. *)
+(*     { by rewrite lookup_delete. } *)
+(*     eapply IH. by apply: delete_subset. *)
+(*   } *)
+(*   rewrite /proto_end in H. *)
+(*   by rewrite -H' in H. *)
+(* Qed. *)
+Admitted.
+
+Lemma proto_case {V} `{!Cofe PROPn, !Cofe PROP} (p : proto V PROPn PROP) :
+  p ≡ proto_end ∨ ∃ a m p', p ≡ proto_union (proto_message a m) p'.
+Proof. Admitted.
+(*   destruct (proto_unfold p) as [[a m]|] eqn:E; simpl in *; last first. *)
+(*   - left. by rewrite -(proto_fold_unfold p) E. *)
+(*   - right. exists a, m. by rewrite /proto_message -E proto_fold_unfold. *)
+(* Qed. *)
 Global Instance proto_inhabited {V} `{!Cofe PROPn, !Cofe PROP} :
   Inhabited (proto V PROPn PROP) := populate proto_end.
 
 Lemma proto_message_equivI {Σ} {V} `{!Cofe PROPn, !Cofe PROP} a1 a2 m1 m2 :
   proto_message (V:=V) (PROPn:=PROPn) (PROP:=PROP) a1 m1 ≡ proto_message a2 m2
   ⊣⊢@{iProp Σ} ⌜ a1 = a2 ⌝ ∧ (∀ v p', m1 v p' ≡ m2 v p').
-Proof.
-  rewrite /proto_message gmap_equivI /=.
-  iSplit.
-  { destruct (decide (a1=a2)) as [->|Hne]; last first.
-    { iIntros "H". iSpecialize ("H" $! a1).
-      rewrite lookup_insert. rewrite lookup_insert_ne; [|done].
-      by rewrite option_equivI. }
-    iIntros "H". iSpecialize ("H" $! a2).
-    rewrite !lookup_insert option_equivI.
-    iSplit; [done|].
-    iIntros (v p). rewrite discrete_fun_equivI.
-    iSpecialize ("H" $! v).
-    rewrite ofe_morO_equivI=> /=.
-    iSpecialize ("H" $! (laterO_map proto_unfold p)).
-    assert (p ≡ later_map proto_fold (later_map proto_unfold p)) as <-; last by done.
-    rewrite -later_map_compose. rewrite -(later_map_id p).
-    apply later_map_ext=> p' /=. by rewrite proto_fold_unfold. }
-  iIntros "[%Heq H2]" (i). rewrite Heq.
-  destruct (decide (a2 = i)) as [->|Hneq]; [|by rewrite !lookup_insert_ne].
-  rewrite !lookup_insert option_equivI discrete_fun_equivI.
-  iIntros (v). rewrite ofe_morO_equivI. by iIntros (p).
-Qed.
+Proof. Admitted.
+(*   rewrite /proto_message list_equivI /=. *)
+(*   iSplit. *)
+(*   { destruct (decide (a1=a2)) as [->|Hne]; last first. *)
+(*     { iIntros "H". iSpecialize ("H" $! 0). simpl. *)
+(*       rewrite option_equivI. rewrite prod_equivI. simpl. } *)
+(*     iIntros "H". iSpecialize ("H" $! a2). *)
+(*     rewrite !lookup_insert option_equivI. *)
+(*     iSplit; [done|]. *)
+(*     iIntros (v p). rewrite discrete_fun_equivI. *)
+(*     iSpecialize ("H" $! v). *)
+(*     rewrite ofe_morO_equivI=> /=. *)
+(*     iSpecialize ("H" $! (laterO_map proto_unfold p)). *)
+(*     assert (p ≡ later_map proto_fold (later_map proto_unfold p)) as <-; last by done. *)
+(*     rewrite -later_map_compose. rewrite -(later_map_id p). *)
+(*     apply later_map_ext=> p' /=. by rewrite proto_fold_unfold. } *)
+(*   iIntros "[%Heq H2]" (i). rewrite Heq. *)
+(*   destruct (decide (a2 = i)) as [->|Hneq]; [|by rewrite !lookup_insert_ne]. *)
+(*   rewrite !lookup_insert option_equivI discrete_fun_equivI. *)
+(*   iIntros (v). rewrite ofe_morO_equivI. by iIntros (p). *)
+(* Qed. *)
 Lemma proto_message_end_equivI  {Σ} {V} `{!Cofe PROPn, !Cofe PROP} a m :
   proto_message (V:=V) (PROPn:=PROPn) (PROP:=PROP) a m ≡ proto_end ⊢@{iProp Σ} False.
-Proof.
-  rewrite /proto_message /proto_end. rewrite gmap_equivI.
-  iIntros "H". iSpecialize ("H" $! a). rewrite lookup_insert. rewrite lookup_empty.
-  by rewrite option_equivI.
-Qed.
+Proof. Admitted.
+(*   rewrite /proto_message /proto_end. rewrite gmap_equivI. *)
+(*   iIntros "H". iSpecialize ("H" $! a). rewrite lookup_insert. rewrite lookup_empty. *)
+(*   by rewrite option_equivI. *)
+(* Qed. *)
 Lemma proto_end_message_equivI {Σ} {V} `{!Cofe PROPn, !Cofe PROP} a m :
   proto_end ≡ proto_message (V:=V) (PROPn:=PROPn) (PROP:=PROP) a m ⊢@{iProp Σ} False.
 Proof. by rewrite internal_eq_sym proto_message_end_equivI. Qed.
 
+(* Definition proto_elim {V} `{!Cofe PROPn, !Cofe PROP} {A} *)
+(*     (x : A) (f : A → action → (V → laterO (proto V PROP PROPn) -n> PROP) → A) *)
+(*     (p : proto V PROPn PROP) : A := *)
+(*   match p with *)
+(*   | [] => x *)
+(*   | p' => fold_left (λ acc am, f acc am.1 (λ v, am.2 v ◎ laterO_map proto_unfold)) p' x *)
+(*   end. *)
+
+(* Lemma proto_elim_ne {V} `{!Cofe PROPn, !Cofe PROP} {A : ofe} *)
+(*     (x : A) (f1 f2 : A → action → (V → laterO (proto V PROP PROPn) -n> PROP) → A) p1 p2 n : *)
+(*   (∀ x a m1 m2, (∀ v, m1 v ≡{n}≡ m2 v) → f1 x a m1 ≡{n}≡ f2 x a m2) → *)
+(*   p1 ≡{n}≡ p2 → *)
+(*   proto_elim x f1 p1 ≡{n}≡ proto_elim x f2 p2. *)
+(* Proof. Admitted. *)
+
 (** Functor *)
+(* Program Definition proto_map_aux {V} `{!Cofe PROPn, !Cofe PROPn', !Cofe PROP, !Cofe PROP'} *)
+(*     (g : PROP -n> PROP') (rec : proto V PROP' PROPn' -n> proto V PROP PROPn) : *)
+(*   proto V PROPn PROP -n> proto V PROPn' PROP' := λne p, *)
+(*     proto_elim proto_end (λ acc a m, proto_union acc $ proto_message a (λ v, g ◎ m v ◎ laterO_map rec)) p. *)
+(* Next Obligation. *)
+(*   intros V PROPn ? PROPn' ? PROP ? PROP' ? g rec n p1 p2 Hp. *)
+(*   apply proto_elim_ne. *)
+(*   - intros. repeat f_equiv. done. *)
+(*   - done. *)
+(* Qed. *)
+
 Program Definition proto_map_aux {V} `{!Cofe PROPn, !Cofe PROPn', !Cofe PROP, !Cofe PROP'}
-    (g : PROP -n> PROP') (rec : proto V PROP' PROPn' -n> proto V PROP PROPn) :
+    (f : action → action) (g : PROP -n> PROP') (rec : proto V PROP' PROPn' -n> proto V PROP PROPn) :
   proto V PROPn PROP -n> proto V PROPn' PROP' := λne p,
-    (λ m, λ v, g ◎ m v ◎ laterO_map proto_unfold ◎ laterO_map rec ◎ laterO_map proto_fold) <$> p.
+    (λ am, (f am.1, λ v, g ◎ am.2 v ◎ laterO_map proto_unfold ◎ laterO_map rec ◎ laterO_map proto_fold)) <$> p.
 Next Obligation.
-  intros V PROPn ? PROPn' ? PROP ? PROP' ? g rec n p1 p2 Hp.
-  apply: (map_fmap_ne _ n _ p1 p2); [|done].
-  solve_proper.
+  intros V PROPn ? PROPn' ? PROP ? PROP' ? f g rec n p1 p2 Hp.
+  apply: (list_fmap_ne n _ _ _ p1 p2); [|done].
+  intros [a1 m1] [a2 m2] [Haeq Hmeq]. simpl in *.
+  apply pair_ne; solve_proper.
 Qed.
 
 Global Instance proto_map_aux_contractive {V}
-   `{!Cofe PROPn, !Cofe PROPn', !Cofe PROP, !Cofe PROP'} (g : PROP -n> PROP') :
-  Contractive (proto_map_aux (V:=V) (PROPn:=PROPn) (PROPn':=PROPn') g).
-Proof.
-  intros n p1 p2 Hp. rewrite /proto_map_aux.
-  intros p. simpl.
-  apply: gmap_fmap_ne_ext.
-  intros i x Hix v. f_equiv. f_equiv. f_contractive.
-  done.
-Qed.
+   `{!Cofe PROPn, !Cofe PROPn', !Cofe PROP, !Cofe PROP'} f (g : PROP -n> PROP') :
+  Contractive (proto_map_aux (V:=V) (PROPn:=PROPn) (PROPn':=PROPn') f g).
+Proof. Admitted.
 
 Definition proto_map_aux_2 {V}
    `{!Cofe PROPn, !Cofe PROPn', !Cofe PROP, !Cofe PROP'}
-    (gn : PROPn' -n> PROPn) (g : PROP -n> PROP')
+    f (gn : PROPn' -n> PROPn) (g : PROP -n> PROP')
     (rec : proto V PROPn PROP -n> proto V PROPn' PROP') :
     proto V PROPn PROP -n> proto V PROPn' PROP' :=
-  proto_map_aux g (proto_map_aux gn rec).
+  proto_map_aux f g (proto_map_aux f gn rec).
 Global Instance proto_map_aux_2_contractive {V}
    `{!Cofe PROPn, !Cofe PROPn', !Cofe PROP, !Cofe PROP'}
-    (gn : PROPn' -n> PROPn) (g : PROP -n> PROP') :
-  Contractive (proto_map_aux_2 (V:=V) gn g).
+    f (gn : PROPn' -n> PROPn) (g : PROP -n> PROP') :
+  Contractive (proto_map_aux_2 (V:=V) f gn g).
 Proof.
   intros n rec1 rec2 Hrec. rewrite /proto_map_aux_2.
   f_equiv. by apply proto_map_aux_contractive.
 Qed.
 Definition proto_map {V}
    `{!Cofe PROPn, !Cofe PROPn', !Cofe PROP, !Cofe PROP'}
-    (gn : PROPn' -n> PROPn) (g : PROP -n> PROP') :
+    f (gn : PROPn' -n> PROPn) (g : PROP -n> PROP') :
     proto V PROPn PROP -n> proto V PROPn' PROP' :=
-  fixpoint (proto_map_aux_2 gn g).
+  fixpoint (proto_map_aux_2 f gn g).
 
 Lemma proto_map_unfold {V}
     `{Hcn:!Cofe PROPn, Hcn':!Cofe PROPn', Hc:!Cofe PROP, Hc':!Cofe PROP'}
-    (gn : PROPn' -n> PROPn) (g : PROP -n> PROP') p :
-  proto_map (V:=V) gn g p ≡ proto_map_aux g (proto_map g gn) p.
+    (f : action → action) (gn : PROPn' -n> PROPn) (g : PROP -n> PROP') p :
+  proto_map (V:=V) f gn g p ≡ proto_map_aux f g (proto_map f g gn) p.
 Proof.
   apply equiv_dist=> n. revert PROPn Hcn PROPn' Hcn' PROP Hc PROP' Hc' gn g p.
   induction (lt_wf n) as [n _ IH]=>
     PROPn Hcn PROPn' Hcn' PROP Hc PROP' Hc' gn g p.
-  etrans; [apply equiv_dist, (fixpoint_unfold (proto_map_aux_2 gn g))|].
+  etrans; [apply equiv_dist, (fixpoint_unfold (proto_map_aux_2 f gn g))|].
   apply proto_map_aux_contractive; constructor=> n' ?. symmetry. apply: IH. lia.
 Qed.
 Lemma proto_map_end {V} `{!Cofe PROPn, !Cofe PROPn', !Cofe PROP, !Cofe PROP'}
-    (gn : PROPn' -n> PROPn) (g : PROP -n> PROP') :
-  proto_map (V:=V) gn g proto_end ≡ proto_end.
+    f (gn : PROPn' -n> PROPn) (g : PROP -n> PROP') :
+  proto_map (V:=V) f gn g proto_end ≡ proto_end.
 Proof.
   rewrite proto_map_unfold /proto_map_aux /=.
   done.
 Qed.
 Lemma proto_map_message {V} `{!Cofe PROPn, !Cofe PROPn', !Cofe PROP, !Cofe PROP'}
-    (gn : PROPn' -n> PROPn) (g : PROP -n> PROP') a m :
-  proto_map (V:=V) gn g (proto_message a m)
-  ≡ proto_message a (λ v, g ◎ m v ◎ laterO_map (proto_map g gn)).
+    f (gn : PROPn' -n> PROPn) (g : PROP -n> PROP') a m :
+  proto_map (V:=V) f gn g (proto_message a m)
+  ≡ proto_message (f a) (λ v, g ◎ m v ◎ laterO_map (proto_map f g gn)).
 Proof.
   rewrite proto_map_unfold /proto_map_aux /=.
-  rewrite /proto_message.
-  rewrite fmap_insert. rewrite fmap_empty.
-  intros a'. destruct (decide (a=a')).
-  { subst. rewrite !lookup_insert.
-    f_equiv.
-    intros v. f_equiv. f_equiv.
-    intros x. simpl. f_equiv. f_equiv.
-    intros y. simpl. rewrite proto_fold_unfold. done.
-  }
-  by rewrite !lookup_insert_ne.
+  rewrite /proto_message. f_equiv. f_equiv. intros v. simpl. repeat f_equiv.
+  intros m'. simpl. repeat f_equiv. rewrite -later_map_compose.
+  destruct m'. simpl. rewrite later_map_Next. simpl. rewrite proto_fold_unfold.
+  done.
 Qed.
 Lemma proto_map_union {V} `{!Cofe PROPn, !Cofe PROPn', !Cofe PROP, !Cofe PROP'}
-    (gn : PROPn' -n> PROPn) (g : PROP -n> PROP') p1 p2 :
-  proto_map (V:=V) gn g (proto_union p1 p2)
-  ≡ proto_union (proto_map gn g p1) (proto_map gn g p2).
+    f (gn : PROPn' -n> PROPn) (g : PROP -n> PROP') p1 p2 :
+  proto_map (V:=V) f gn g (proto_union p1 p2)
+  ≡ proto_union (proto_map f gn g p1) (proto_map f gn g p2).
 Proof.
-  rewrite proto_map_unfold /proto_map_aux /=.
-  rewrite proto_map_unfold /proto_map_aux /=.
-  rewrite proto_map_unfold /proto_map_aux /=.
+  rewrite !proto_map_unfold !/proto_map_aux /=.
   rewrite !/proto_union.
-  rewrite !map_fmap_union.
-  f_equiv.
+  rewrite fmap_app. done.
 Qed.
 
 Lemma proto_map_ne {V}
     `{Hcn:!Cofe PROPn, Hcn':!Cofe PROPn', Hc:!Cofe PROP, Hc':!Cofe PROP'}
-    (gn1 gn2 : PROPn' -n> PROPn) (g1 g2 : PROP -n> PROP') p n :
+    f (gn1 gn2 : PROPn' -n> PROPn) (g1 g2 : PROP -n> PROP') p n :
   gn1 ≡{n}≡ gn2 → g1 ≡{n}≡ g2 →
-  proto_map (V:=V) gn1 g1 p ≡{n}≡ proto_map (V:=V) gn2 g2 p.
+  proto_map (V:=V) f gn1 g1 p ≡{n}≡ proto_map (V:=V) f gn2 g2 p.
 Proof.
   revert PROPn Hcn PROPn' Hcn' PROP Hc PROP' Hc' gn1 gn2 g1 g2 p.
   induction (lt_wf n) as [n _ IH]=>
@@ -319,29 +347,32 @@ Proof.
   { intros p1 p2 Hp H'. rewrite -Hp. done. }
   { rewrite !proto_map_end. done. }
   intros a m p' Hp Hp'.
+  clear Hp.                     (* Make sure we dont abuse false assumption *)
   rewrite !proto_map_union.
-  rewrite !proto_map_message /=.
-  apply proto_union_ne.
-  { apply proto_message_ne => // v p'' /=. f_equiv; [done|]. f_equiv.
+  apply proto_union_ne; [|done].
+  { rewrite !proto_map_message /=.
+    apply proto_message_ne => // v p'' /=. f_equiv; [done|]. f_equiv.
     apply Next_contractive; dist_later_intro as n' Hn'; eauto using dist_le with lia. }
-  done.
 Qed.
 Lemma proto_map_ext {V} `{!Cofe PROPn, !Cofe PROPn', !Cofe PROP, !Cofe PROP'}
-    (gn1 gn2 : PROPn' -n> PROPn) (g1 g2 : PROP -n> PROP') p :
-  gn1 ≡ gn2 → g1 ≡ g2 → proto_map (V:=V) gn1 g1 p ≡ proto_map (V:=V) gn2 g2 p.
+    (gn1 gn2 : PROPn' -n> PROPn) f (g1 g2 : PROP -n> PROP') p :
+  gn1 ≡ gn2 → g1 ≡ g2 → proto_map (V:=V) f gn1 g1 p ≡ proto_map (V:=V) f gn2 g2 p.
 Proof.
   intros Hgn Hg. apply equiv_dist=> n.
   apply proto_map_ne=> // ?; by apply equiv_dist.
 Qed.
 Lemma proto_map_id {V} `{Hcn:!Cofe PROPn, Hc:!Cofe PROP} (p : proto V PROPn PROP) :
-  proto_map cid cid p ≡ p.
+  proto_map id cid cid p ≡ p.
 Proof.
   apply equiv_dist=> n. revert PROPn Hcn PROP Hc p.
   induction (lt_wf n) as [n _ IH]=> PROPn ? PROP ? p /=.
-    pattern p. apply proto_ind.
+  pattern p.
+  (* induction p. *)
+  apply proto_ind.
   { intros p1 p2 Hp H'. rewrite -Hp. done. }
   { rewrite !proto_map_end. done. }
   intros a m p' Hp Hp'.
+  clear Hp.                     (* Make sure we dont use false assumption *)
   rewrite proto_map_union. f_equiv.
   { rewrite !proto_map_message /=. apply proto_message_ne=> // v p'' /=. f_equiv.
     apply Next_contractive; dist_later_intro as n' Hn'; auto. }
@@ -352,7 +383,7 @@ Lemma proto_map_compose {V}
      Hc:!Cofe PROP, Hc':!Cofe PROP', Hc'':!Cofe PROP''}
     (gn1 : PROPn'' -n> PROPn') (gn2 : PROPn' -n> PROPn)
     (g1 : PROP -n> PROP') (g2 : PROP' -n> PROP'') (p : proto V PROPn PROP) :
-  proto_map (gn2 ◎ gn1) (g2 ◎ g1) p ≡ proto_map gn1 g2 (proto_map gn2 g1 p).
+  proto_map id (gn2 ◎ gn1) (g2 ◎ g1) p ≡ proto_map id gn1 g2 (proto_map id gn2 g1 p).
 Proof.  
   apply equiv_dist=> n. revert PROPn Hcn PROPn' Hcn' PROPn'' Hcn''
     PROP Hc PROP' Hc' PROP'' Hc'' gn1 gn2 g1 g2 p.
@@ -362,6 +393,7 @@ Proof.
   { intros p1 p2 Hp H'. rewrite -Hp. done. }
   { rewrite !proto_map_end. done. }
   intros a m p' Hp Hp'.
+  clear Hp.                     (* Make sure we dont use false assumption *)
   rewrite !proto_map_union. f_equiv.
   { rewrite !proto_map_message /=. apply proto_message_ne=> // v p'' /=. do 3 f_equiv.
     apply Next_contractive; dist_later_intro as n' Hn'; auto. }
@@ -373,7 +405,7 @@ Program Definition protoOF (V : Type) (Fn F : oFunctor)
     `{!∀ A B `{!Cofe A, !Cofe B}, Cofe (oFunctor_car F A B)} : oFunctor := {|
   oFunctor_car A _ B _ := proto V (oFunctor_car Fn B A) (oFunctor_car F A B);
   oFunctor_map A1 _ A2 _ B1 _ B2 _ fg :=
-    proto_map (oFunctor_map Fn (fg.2, fg.1)) (oFunctor_map F fg)
+    proto_map id (oFunctor_map Fn (fg.2, fg.1)) (oFunctor_map F fg)
 |}.
 Next Obligation.
   intros V Fn F ?? A1 ? A2 ? B1 ? B2 ? n f g [??] p; simpl in *.