Fixpoint wf (proof_tree : cbv) : Prop :=
  match proof_tree with
    | cbv_constr l C (capply c lt) C' (c_capply c' lv) =>
        cache_path C C' l = true /\
        c = c' /\
        lt = map proj_left l /\ lv = map proj_right l /\
        andl (map wf  l) /\ List.length l <= max_arity
    | cbv_split l ((cbv_update _ _ _ C' (fapply f lv) C'' v) as p) C (fapply f' lt) C''' v' =>
        C''' = C'' /\
        cache_path C C' l = true /\
        lt = map proj_left l /\ lv = map (@term_from_value _ _ _) (map proj_right l) /\
        andl (map wf  l) /\
        f = f' /\ v = v' /\
        wf  p /\ length l <= max_arity
    | cbv_split l ((cbv_read C' (fapply f lv) v) as p) C (fapply f' lt) C'' v' =>
        C'' = C' /\
        cache_path C C' l = true /\
        lt = map proj_left l /\ lv = map (@term_from_value _ _ _) (map proj_right l) /\
        andl (map wf  l) /\
        f = f' /\ v = v' /\
        wf  p /\ length l <= max_arity
    | cbv_update i s p C (fapply f lv as t0) C' v =>
        assoc term_beq t0 C = None /\
        exists lp t,
        i < length prog /\
        nth i prog rule_default = rule_intro f lp t /\
        lv = map (@term_from_value _ _ _) (map (psubst s) lp) /\
        proj_left p = subst s t /\ proj_right p = v /\
        cache_left p = C /\  True /\
        C' = (t0, v) :: cache_right p /\ 
        wf  p /\ length lv <= max_arity
    | cbv_read C (fapply _ lv as t) v =>
        assoc term_beq t C = Some v /\
        exists lv', lv = map (@term_from_value _ _ _) lv'
    | _ => False
  end.

Lemma wf_cbv_update i s p c1 t c2 v : wf (cbv_update i s p c1 t c2 v) -> wf p.