/-- If `E` is a cone of shape `K` of sheaves, which is a limit on the level of presheaves,
this definition shows that the limit presheaf satisfies the multifork variant of the sheaf
condition, at a given covering `W`.

This is used below in `isSheaf_of_isLimit` to show that the limit presheaf is indeed a sheaf.
-/
def isLimitMultiforkOfIsLimit (F : K ⥤ Sheaf J D) (E : Cone (F ⋙ sheafToPresheaf J D))
    (hE : IsLimit E) (X : C) (W : J.Cover X) : IsLimit (W.multifork E.pt) :=
  Multifork.IsLimit.mk _
    (fun S => (isLimitOfPreserves ((evaluation Cᵒᵖ D).obj (op X)) hE).lift <|
      multiforkEvaluationCone F E X W S)
    (by
      intro S i
      apply (isLimitOfPreserves ((evaluation Cᵒᵖ D).obj (op i.Y)) hE).hom_ext
      intro k
      dsimp [Multifork.ofι]
      erw [Category.assoc, (E.π.app k).naturality]
      dsimp
      rw [← Category.assoc]
      erw [(isLimitOfPreserves ((evaluation Cᵒᵖ D).obj (op X)) hE).fac
        (multiforkEvaluationCone F E X W S)]
      dsimp [multiforkEvaluationCone, Presheaf.isLimitOfIsSheaf]
      erw [Presheaf.IsSheaf.amalgamate_map]
      rfl)
    (by
      intro S m hm
      apply (isLimitOfPreserves ((evaluation Cᵒᵖ D).obj (op X)) hE).hom_ext
      intro k
      dsimp
      erw [(isLimitOfPreserves ((evaluation Cᵒᵖ D).obj (op X)) hE).fac]
      apply Presheaf.IsSheaf.hom_ext (F.obj k).2 W
      intro i
      dsimp only [multiforkEvaluationCone, Presheaf.isLimitOfIsSheaf]
      

Proof state:
case h
C : Type u
inst✝³ : Category.{v, u} C
J : GrothendieckTopology C
D : Type w
inst✝² : Category.{max v u, w} D
K : Type z
inst✝¹ : Category.{z', z} K
inst✝ : HasLimitsOfShape K D
F : K ⥤ Sheaf J D
E : Cone (F ⋙ sheafToPresheaf J D)
hE : IsLimit E
X : C
W : GrothendieckTopology.Cover J X
S : Multifork (GrothendieckTopology.Cover.index W E.pt)
m : S.pt ⟶ (GrothendieckTopology.Cover.multifork W E.pt).pt
hm :
  ∀ (i : (GrothendieckTopology.Cover.index W E.pt).L),
    m ≫ Multifork.ι (GrothendieckTopology.Cover.multifork W E.pt) i = Multifork.ι S i
k : K
i : GrothendieckTopology.Cover.Arrow W
⊢ (m ≫ (E.π.app k).app (op X)) ≫ (F.obj k).val.map i.f.op =
    Presheaf.IsSheaf.amalgamate (_ : Presheaf.IsSheaf J (F.obj k).val) W
        (fun I =>
          Multifork.ι
            (Multifork.ofι (GrothendieckTopology.Cover.index W (F.obj k).val) S.pt
              (fun i => Multifork.ι S i ≫ (E.π.app k).app (op i.Y))
              (_ :
                ∀ (i : (GrothendieckTopology.Cover.index W (F.obj k).val).R),
                  (fun i => Multifork.ι S i ≫ (E.π.app k).app (op i.Y))
                        (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj k).val) i) ≫
                      MulticospanIndex.fst (GrothendieckTopology.Cover.index W (F.obj k).val) i =
                    (fun i => Multifork.ι S i ≫ (E.π.app k).app (op i.Y))
                        (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj k).val) i) ≫
                      MulticospanIndex.snd (GrothendieckTopology.Cover.index W (F.obj k).val) i))
            I)
        (_ :
          ∀ (I : GrothendieckTopology.Cover.Relation W),
            Multifork.ι
                  (Multifork.ofι (GrothendieckTopology.Cover.index W (F.obj k).val) S.pt
                    (fun i => Multifork.ι S i ≫ (E.π.app k).app (op i.Y))
                    (_ :
                      ∀ (i : (GrothendieckTopology.Cover.index W (F.obj k).val).R),
                        (fun i => Multifork.ι S i ≫ (E.π.app k).app (op i.Y))
                              (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj k).val) i) ≫
                            MulticospanIndex.fst (GrothendieckTopology.Cover.index W (F.obj k).val) i =
                          (fun i => Multifork.ι S i ≫ (E.π.app k).app (op i.Y))
                              (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj k).val) i) ≫
                            MulticospanIndex.snd (GrothendieckTopology.Cover.index W (F.obj k).val) i))
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj k).val) I) ≫
                MulticospanIndex.fst (GrothendieckTopology.Cover.index W (F.obj k).val) I =
              Multifork.ι
                  (Multifork.ofι (GrothendieckTopology.Cover.index W (F.obj k).val) S.pt
                    (fun i => Multifork.ι S i ≫ (E.π.app k).app (op i.Y))
                    (_ :
                      ∀ (i : (GrothendieckTopology.Cover.index W (F.obj k).val).R),
                        (fun i => Multifork.ι S i ≫ (E.π.app k).app (op i.Y))
                              (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj k).val) i) ≫
                            MulticospanIndex.fst (GrothendieckTopology.Cover.index W (F.obj k).val) i =
                          (fun i => Multifork.ι S i ≫ (E.π.app k).app (op i.Y))
                              (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj k).val) i) ≫
                            MulticospanIndex.snd (GrothendieckTopology.Cover.index W (F.obj k).val) i))
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj k).val) I) ≫
                MulticospanIndex.snd (GrothendieckTopology.Cover.index W (F.obj k).val) I) ≫
      (F.obj k).val.map i.f.op

Next tactic:
rw [(F.obj k).cond.amalgamate_map]