/-- An auxiliary definition to be used below.

Whenever `E` is a cone of shape `K` of sheaves, and `S` is the multifork associated to a
covering `W` of an object `X`, with respect to the cone point `E.X`, this provides a cone of
shape `K` of objects in `D`, with cone point `S.X`.

See `isLimitMultiforkOfIsLimit` for more on how this definition is used.
-/
def multiforkEvaluationCone (F : K ⥤ Sheaf J D) (E : Cone (F ⋙ sheafToPresheaf J D)) (X : C)
    (W : J.Cover X) (S : Multifork (W.index E.pt)) :
    Cone (F ⋙ sheafToPresheaf J D ⋙ (evaluation Cᵒᵖ D).obj (op X)) where
  pt := S.pt
  π :=
    { app := fun k => (Presheaf.isLimitOfIsSheaf J (F.obj k).1 W (F.obj k).2).lift <|
        Multifork.ofι _ S.pt (fun i => S.ι i ≫ (E.π.app k).app (op i.Y))
          (by
            intro i
            simp only [Category.assoc]
            erw [← (E.π.app k).naturality, ← (E.π.app k).naturality]
            dsimp
            simp only [← Category.assoc]
            congr 1
            apply S.condition)
      naturality := by
        intro i j f
        dsimp [Presheaf.isLimitOfIsSheaf]
        rw [Category.id_comp]
        apply Presheaf.IsSheaf.hom_ext (F.obj j).2 W
        intro ii
        

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
F : K ⥤ Sheaf J D
E : Cone (F ⋙ sheafToPresheaf J D)
X : C
W : GrothendieckTopology.Cover J X
S : Multifork (GrothendieckTopology.Cover.index W E.pt)
i j : K
f : i ⟶ j
ii : GrothendieckTopology.Cover.Arrow W
⊢ Presheaf.IsSheaf.amalgamate (_ : Presheaf.IsSheaf J (F.obj j).val) W
        (fun I =>
          Multifork.ι
            (Multifork.ofι (GrothendieckTopology.Cover.index W (F.obj j).val) S.pt
              (fun i => Multifork.ι S i ≫ (E.π.app j).app (op i.Y))
              (_ :
                ∀ (i : (GrothendieckTopology.Cover.index W (F.obj j).val).R),
                  (Multifork.ι S (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj j).val) i) ≫
                        (E.π.app j).app
                          (op (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj j).val) i).Y)) ≫
                      MulticospanIndex.fst (GrothendieckTopology.Cover.index W (F.obj j).val) i =
                    (Multifork.ι S (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj j).val) i) ≫
                        (E.π.app j).app
                          (op (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj j).val) i).Y)) ≫
                      MulticospanIndex.snd (GrothendieckTopology.Cover.index W (F.obj j).val) i))
            I)
        (_ :
          ∀ (I : GrothendieckTopology.Cover.Relation W),
            Multifork.ι
                  (Multifork.ofι (GrothendieckTopology.Cover.index W (F.obj j).val) S.pt
                    (fun i => Multifork.ι S i ≫ (E.π.app j).app (op i.Y))
                    (_ :
                      ∀ (i : (GrothendieckTopology.Cover.index W (F.obj j).val).R),
                        (Multifork.ι S (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj j).val) i) ≫
                              (E.π.app j).app
                                (op (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj j).val) i).Y)) ≫
                            MulticospanIndex.fst (GrothendieckTopology.Cover.index W (F.obj j).val) i =
                          (Multifork.ι S (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj j).val) i) ≫
                              (E.π.app j).app
                                (op (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj j).val) i).Y)) ≫
                            MulticospanIndex.snd (GrothendieckTopology.Cover.index W (F.obj j).val) i))
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj j).val) I) ≫
                MulticospanIndex.fst (GrothendieckTopology.Cover.index W (F.obj j).val) I =
              Multifork.ι
                  (Multifork.ofι (GrothendieckTopology.Cover.index W (F.obj j).val) S.pt
                    (fun i => Multifork.ι S i ≫ (E.π.app j).app (op i.Y))
                    (_ :
                      ∀ (i : (GrothendieckTopology.Cover.index W (F.obj j).val).R),
                        (Multifork.ι S (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj j).val) i) ≫
                              (E.π.app j).app
                                (op (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj j).val) i).Y)) ≫
                            MulticospanIndex.fst (GrothendieckTopology.Cover.index W (F.obj j).val) i =
                          (Multifork.ι S (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj j).val) i) ≫
                              (E.π.app j).app
                                (op (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj j).val) i).Y)) ≫
                            MulticospanIndex.snd (GrothendieckTopology.Cover.index W (F.obj j).val) i))
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj j).val) I) ≫
                MulticospanIndex.snd (GrothendieckTopology.Cover.index W (F.obj j).val) I) ≫
      (F.obj j).val.map ii.f.op =
    (Presheaf.IsSheaf.amalgamate (_ : Presheaf.IsSheaf J (F.obj i).val) W
          (fun I =>
            Multifork.ι
              (Multifork.ofι (GrothendieckTopology.Cover.index W (F.obj i).val) S.pt
                (fun i_1 => Multifork.ι S i_1 ≫ (E.π.app i).app (op i_1.Y))
                (_ :
                  ∀ (i_1 : (GrothendieckTopology.Cover.index W (F.obj i).val).R),
                    (Multifork.ι S (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj i).val) i_1) ≫
                          (E.π.app i).app
                            (op (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj i).val) i_1).Y)) ≫
                        MulticospanIndex.fst (GrothendieckTopology.Cover.index W (F.obj i).val) i_1 =
                      (Multifork.ι S (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj i).val) i_1) ≫
                          (E.π.app i).app
                            (op (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj i).val) i_1).Y)) ≫
                        MulticospanIndex.snd (GrothendieckTopology.Cover.index W (F.obj i).val) i_1))
              I)
          (_ :
            ∀ (I : GrothendieckTopology.Cover.Relation W),
              Multifork.ι
                    (Multifork.ofι (GrothendieckTopology.Cover.index W (F.obj i).val) S.pt
                      (fun i_1 => Multifork.ι S i_1 ≫ (E.π.app i).app (op i_1.Y))
                      (_ :
                        ∀ (i_1 : (GrothendieckTopology.Cover.index W (F.obj i).val).R),
                          (Multifork.ι S
                                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj i).val) i_1) ≫
                                (E.π.app i).app
                                  (op
                                    (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj i).val)
                                        i_1).Y)) ≫
                              MulticospanIndex.fst (GrothendieckTopology.Cover.index W (F.obj i).val) i_1 =
                            (Multifork.ι S
                                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj i).val) i_1) ≫
                                (E.π.app i).app
                                  (op
                                    (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj i).val)
                                        i_1).Y)) ≫
                              MulticospanIndex.snd (GrothendieckTopology.Cover.index W (F.obj i).val) i_1))
                    (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj i).val) I) ≫
                  MulticospanIndex.fst (GrothendieckTopology.Cover.index W (F.obj i).val) I =
                Multifork.ι
                    (Multifork.ofι (GrothendieckTopology.Cover.index W (F.obj i).val) S.pt
                      (fun i_1 => Multifork.ι S i_1 ≫ (E.π.app i).app (op i_1.Y))
                      (_ :
                        ∀ (i_1 : (GrothendieckTopology.Cover.index W (F.obj i).val).R),
                          (Multifork.ι S
                                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj i).val) i_1) ≫
                                (E.π.app i).app
                                  (op
                                    (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj i).val)
                                        i_1).Y)) ≫
                              MulticospanIndex.fst (GrothendieckTopology.Cover.index W (F.obj i).val) i_1 =
                            (Multifork.ι S
                                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj i).val) i_1) ≫
                                (E.π.app i).app
                                  (op
                                    (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj i).val)
                                        i_1).Y)) ≫
                              MulticospanIndex.snd (GrothendieckTopology.Cover.index W (F.obj i).val) i_1))
                    (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj i).val) I) ≫
                  MulticospanIndex.snd (GrothendieckTopology.Cover.index W (F.obj i).val) I) ≫
        (F.map f).val.app (op X)) ≫
      (F.obj j).val.map ii.f.op

Next tactic:
rw [Presheaf.IsSheaf.amalgamate_map, Category.assoc, ← (F.map f).val.naturality, ←
          Category.assoc, Presheaf.IsSheaf.amalgamate_map]