-- Mathlib/CategoryTheory/Sites/Subsheaf.lean
theorem Subpresheaf.to_sheafify_lift_unique (h : Presieve.IsSheaf J F')
    (l₁ l₂ : (G.sheafify J).toPresheaf ⟶ F')
    (e : Subpresheaf.homOfLe (G.le_sheafify J) ≫ l₁ = Subpresheaf.homOfLe (G.le_sheafify J) ≫ l₂) :
    l₁ = l₂

Proof state:
case w.h.h.mk
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' : Cᵒᵖ ⥤ Type w
G : Subpresheaf F
h : Presieve.IsSheaf J F'
l₁ l₂ : (sheafify J G).toPresheaf ⟶ F'
e : homOfLe ⋯ ≫ l₁ = homOfLe ⋯ ≫ l₂
U : Cᵒᵖ
s : F.obj U
hs : s ∈ (sheafify J G).obj U
V : C
i : V ⟶ unop U
hi : (G.sieveOfSection s).arrows i
⊢ F'.map i.op (l₁.app U ⟨s, hs⟩) = F'.map i.op (l₂.app U ⟨s, hs⟩)

Tactic:
dsimp at hi

Result:
case w.h.h.mk
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' : Cᵒᵖ ⥤ Type w
G : Subpresheaf F
h : Presieve.IsSheaf J F'
l₁ l₂ : (sheafify J G).toPresheaf ⟶ F'
e : homOfLe ⋯ ≫ l₁ = homOfLe ⋯ ≫ l₂
U : Cᵒᵖ
s : F.obj U
hs : s ∈ (sheafify J G).obj U
V : C
i : V ⟶ unop U
hi : F.map i.op s ∈ G.obj (op V)
⊢ F'.map i.op (l₁.app U ⟨s, hs⟩) = F'.map i.op (l₂.app U ⟨s, hs⟩)

Proof state:
case w.h.h.mk
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' : Cᵒᵖ ⥤ Type w
G : Subpresheaf F
h : Presieve.IsSheaf J F'
l₁ l₂ : (sheafify J G).toPresheaf ⟶ F'
e : homOfLe ⋯ ≫ l₁ = homOfLe ⋯ ≫ l₂
U : Cᵒᵖ
s : F.obj U
hs : s ∈ (sheafify J G).obj U
⊢ l₁.app U ⟨s, hs⟩ = l₂.app U ⟨s, hs⟩

Tactic:
apply (h _ hs).isSeparatedFor.ext

Result:
case w.h.h.mk
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' : Cᵒᵖ ⥤ Type w
G : Subpresheaf F
h : Presieve.IsSheaf J F'
l₁ l₂ : (sheafify J G).toPresheaf ⟶ F'
e : homOfLe ⋯ ≫ l₁ = homOfLe ⋯ ≫ l₂
U : Cᵒᵖ
s : F.obj U
hs : s ∈ (sheafify J G).obj U
⊢ ∀ ⦃Y : C⦄ ⦃f : Y ⟶ unop U⦄,
    (G.sieveOfSection s).arrows f → F'.map f.op (l₁.app U ⟨s, hs⟩) = F'.map f.op (l₂.app U ⟨s, hs⟩)

Proof state:
case w.h.h.mk
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' : Cᵒᵖ ⥤ Type w
G : Subpresheaf F
h : Presieve.IsSheaf J F'
l₁ l₂ : (sheafify J G).toPresheaf ⟶ F'
e : homOfLe ⋯ ≫ l₁ = homOfLe ⋯ ≫ l₂
U : Cᵒᵖ
s : F.obj U
hs : s ∈ (sheafify J G).obj U
V : C
i : V ⟶ unop U
hi : F.map i.op s ∈ G.obj (op V)
⊢ F'.map i.op (l₁.app U ⟨s, hs⟩) = F'.map i.op (l₂.app U ⟨s, hs⟩)

Tactic:
rw [← FunctorToTypes.naturality, ← FunctorToTypes.naturality]

Result:
case w.h.h.mk
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' : Cᵒᵖ ⥤ Type w
G : Subpresheaf F
h : Presieve.IsSheaf J F'
l₁ l₂ : (sheafify J G).toPresheaf ⟶ F'
e : homOfLe ⋯ ≫ l₁ = homOfLe ⋯ ≫ l₂
U : Cᵒᵖ
s : F.obj U
hs : s ∈ (sheafify J G).obj U
V : C
i : V ⟶ unop U
hi : F.map i.op s ∈ G.obj (op V)
⊢ l₁.app (op V) ((sheafify J G).toPresheaf.map i.op ⟨s, hs⟩) =
    l₂.app (op V) ((sheafify J G).toPresheaf.map i.op ⟨s, hs⟩)

Proof state:
case w.h.h.mk
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' : Cᵒᵖ ⥤ Type w
G : Subpresheaf F
h : Presieve.IsSheaf J F'
l₁ l₂ : (sheafify J G).toPresheaf ⟶ F'
e : homOfLe ⋯ ≫ l₁ = homOfLe ⋯ ≫ l₂
U : Cᵒᵖ
s : F.obj U
hs : s ∈ (sheafify J G).obj U
V : C
i : V ⟶ unop U
hi : F.map i.op s ∈ G.obj (op V)
⊢ l₁.app (op V) ((sheafify J G).toPresheaf.map i.op ⟨s, hs⟩) =
    l₂.app (op V) ((sheafify J G).toPresheaf.map i.op ⟨s, hs⟩)

Tactic:
exact (congr_fun (congr_app e <| op V) ⟨_, hi⟩ :)

Result:
no goals

Proof state:
case w.h.h.mk
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' : Cᵒᵖ ⥤ Type w
G : Subpresheaf F
h : Presieve.IsSheaf J F'
l₁ l₂ : (sheafify J G).toPresheaf ⟶ F'
e : homOfLe ⋯ ≫ l₁ = homOfLe ⋯ ≫ l₂
U : Cᵒᵖ
s : F.obj U
hs : s ∈ (sheafify J G).obj U
⊢ ∀ ⦃Y : C⦄ ⦃f : Y ⟶ unop U⦄,
    (G.sieveOfSection s).arrows f → F'.map f.op (l₁.app U ⟨s, hs⟩) = F'.map f.op (l₂.app U ⟨s, hs⟩)

Tactic:
rintro V i hi

Result:
case w.h.h.mk
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' : Cᵒᵖ ⥤ Type w
G : Subpresheaf F
h : Presieve.IsSheaf J F'
l₁ l₂ : (sheafify J G).toPresheaf ⟶ F'
e : homOfLe ⋯ ≫ l₁ = homOfLe ⋯ ≫ l₂
U : Cᵒᵖ
s : F.obj U
hs : s ∈ (sheafify J G).obj U
V : C
i : V ⟶ unop U
hi : (G.sieveOfSection s).arrows i
⊢ F'.map i.op (l₁.app U ⟨s, hs⟩) = F'.map i.op (l₂.app U ⟨s, hs⟩)

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' : Cᵒᵖ ⥤ Type w
G : Subpresheaf F
h : Presieve.IsSheaf J F'
l₁ l₂ : (sheafify J G).toPresheaf ⟶ F'
e : homOfLe ⋯ ≫ l₁ = homOfLe ⋯ ≫ l₂
⊢ l₁ = l₂

Tactic:
ext U ⟨s, hs⟩

Result:
case w.h.h.mk
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' : Cᵒᵖ ⥤ Type w
G : Subpresheaf F
h : Presieve.IsSheaf J F'
l₁ l₂ : (sheafify J G).toPresheaf ⟶ F'
e : homOfLe ⋯ ≫ l₁ = homOfLe ⋯ ≫ l₂
U : Cᵒᵖ
s : F.obj U
hs : s ∈ (sheafify J G).obj U
⊢ l₁.app U ⟨s, hs⟩ = l₂.app U ⟨s, hs⟩