-- Mathlib/CategoryTheory/Sites/DenseSubsite/SheafEquiv.lean
lemma isIso_ranCounit_app_of_isDenseSubsite (Y : Sheaf J A) (U X) :
    IsIso ((yoneda.map ((G.op.ranCounit.app Y.val).app (op U))).app (op X))

Proof state:
case right
C : Type u_1
D : Type u_2
inst✝⁴ : Category.{u_3, u_1} C
inst✝³ : Category.{u_4, u_2} D
G : C ⥤ D
J : GrothendieckTopology C
K : GrothendieckTopology D
A : Type w
inst✝² : Category.{w', w} A
inst✝¹ : ∀ (X : Dᵒᵖ), Limits.HasLimitsOfShape (StructuredArrow X G.op) A
inst✝ : IsDenseSubsite J K G
Y : Sheaf J A
U : C
X : A
f : (yoneda.obj (((𝟭 (Cᵒᵖ ⥤ A)).obj Y.val).obj (op U))).obj (op X)
l : (X Y Z : C) → (f : X ⟶ Y) → (g : G.obj Y ⟶ G.obj Z) → (G.imageSieve g).arrows f → (X ⟶ Z)
hl :
  ∀ (X Y Z : C) (f : X ⟶ Y) (g : G.obj Y ⟶ G.obj Z) (hf : (G.imageSieve g).arrows f),
    G.map (l X Y Z f g hf) = G.map f ≫ g
c : Limits.Cone (StructuredArrow.proj (op (G.obj U)) G.op ⋙ Y.val) :=
  { pt := X,
    π :=
      {
        app := fun g =>
          ⋯.amalgamate ⟨G.imageSieve g.hom.unop, ⋯⟩ (fun I => f ≫ Y.val.map (l I.Y (unop g.2) U I.f g.hom.unop ⋯).op) ⋯,
        naturality := ⋯ } }
⊢ (yoneda.map ((G.op.ranCounit.app Y.val).app (op U))).app (op X)
      ((G.op.isPointwiseRightKanExtensionRanCounit Y.val (op (G.obj U))).lift c) =
    f

Tactic:
have := (isPointwiseRightKanExtensionRanCounit G.op Y.1 (.op (G.obj U))).fac c (.mk (𝟙 _))

Result:
case right
C : Type u_1
D : Type u_2
inst✝⁴ : Category.{u_3, u_1} C
inst✝³ : Category.{u_4, u_2} D
G : C ⥤ D
J : GrothendieckTopology C
K : GrothendieckTopology D
A : Type w
inst✝² : Category.{w', w} A
inst✝¹ : ∀ (X : Dᵒᵖ), Limits.HasLimitsOfShape (StructuredArrow X G.op) A
inst✝ : IsDenseSubsite J K G
Y : Sheaf J A
U : C
X : A
f : (yoneda.obj (((𝟭 (Cᵒᵖ ⥤ A)).obj Y.val).obj (op U))).obj (op X)
l : (X Y Z : C) → (f : X ⟶ Y) → (g : G.obj Y ⟶ G.obj Z) → (G.imageSieve g).arrows f → (X ⟶ Z)
hl :
  ∀ (X Y Z : C) (f : X ⟶ Y) (g : G.obj Y ⟶ G.obj Z) (hf : (G.imageSieve g).arrows f),
    G.map (l X Y Z f g hf) = G.map f ≫ g
c : Limits.Cone (StructuredArrow.proj (op (G.obj U)) G.op ⋙ Y.val) :=
  { pt := X,
    π :=
      {
        app := fun g =>
          ⋯.amalgamate ⟨G.imageSieve g.hom.unop, ⋯⟩ (fun I => f ≫ Y.val.map (l I.Y (unop g.2) U I.f g.hom.unop ⋯).op) ⋯,
        naturality := ⋯ } }
this :
  (G.op.isPointwiseRightKanExtensionRanCounit Y.val (op (G.obj U))).lift c ≫
      ((RightExtension.mk (G.op.ran.obj Y.val) (G.op.ranCounit.app Y.val)).coneAt (op (G.obj U))).π.app
        (StructuredArrow.mk (𝟙 (op (G.obj U)))) =
    c.π.app (StructuredArrow.mk (𝟙 (op (G.obj U))))
⊢ (yoneda.map ((G.op.ranCounit.app Y.val).app (op U))).app (op X)
      ((G.op.isPointwiseRightKanExtensionRanCounit Y.val (op (G.obj U))).lift c) =
    f

Proof state:
case left.mk.mk.unit.op.intro.intro
C : Type u_1
D : Type u_2
inst✝⁴ : Category.{u_3, u_1} C
inst✝³ : Category.{u_4, u_2} D
G : C ⥤ D
J : GrothendieckTopology C
K : GrothendieckTopology D
A : Type w
inst✝² : Category.{w', w} A
inst✝¹ : ∀ (X : Dᵒᵖ), Limits.HasLimitsOfShape (StructuredArrow X G.op) A
inst✝ : IsDenseSubsite J K G
Y : Sheaf J A
U : C
X : A
f₁ f₂ : (yoneda.obj (((G.op.ran ⋙ (whiskeringLeft Cᵒᵖ Dᵒᵖ A).obj G.op).obj Y.val).obj (op U))).obj (op X)
e :
  (yoneda.map ((G.op.ranCounit.app Y.val).app (op U))).app (op X) f₁ =
    (yoneda.map ((G.op.ranCounit.app Y.val).app (op U))).app (op X) f₂
W : C
g : G.obj W ⟶ G.obj U
V : C
iVW : V ⟶ W
iVU : V ⟶ U
e' : G.map iVU = G.map iVW ≫ g
⊢ (f₁ ≫ (G.op.ran.obj Y.val).map g.op ≫ (G.op.ranCounit.app Y.val).app (op W)) ≫ Y.val.map iVW.op =
    (f₂ ≫ (G.op.ran.obj Y.val).map g.op ≫ (G.op.ranCounit.app Y.val).app (op W)) ≫ Y.val.map iVW.op

Tactic:
have := congr($e ≫ Y.1.map iVU.op)

Result:
case left.mk.mk.unit.op.intro.intro
C : Type u_1
D : Type u_2
inst✝⁴ : Category.{u_3, u_1} C
inst✝³ : Category.{u_4, u_2} D
G : C ⥤ D
J : GrothendieckTopology C
K : GrothendieckTopology D
A : Type w
inst✝² : Category.{w', w} A
inst✝¹ : ∀ (X : Dᵒᵖ), Limits.HasLimitsOfShape (StructuredArrow X G.op) A
inst✝ : IsDenseSubsite J K G
Y : Sheaf J A
U : C
X : A
f₁ f₂ : (yoneda.obj (((G.op.ran ⋙ (whiskeringLeft Cᵒᵖ Dᵒᵖ A).obj G.op).obj Y.val).obj (op U))).obj (op X)
e :
  (yoneda.map ((G.op.ranCounit.app Y.val).app (op U))).app (op X) f₁ =
    (yoneda.map ((G.op.ranCounit.app Y.val).app (op U))).app (op X) f₂
W : C
g : G.obj W ⟶ G.obj U
V : C
iVW : V ⟶ W
iVU : V ⟶ U
e' : G.map iVU = G.map iVW ≫ g
this :
  (yoneda.map ((G.op.ranCounit.app Y.val).app (op U))).app (op X) f₁ ≫ Y.val.map iVU.op =
    (yoneda.map ((G.op.ranCounit.app Y.val).app (op U))).app (op X) f₂ ≫ Y.val.map iVU.op
⊢ (f₁ ≫ (G.op.ran.obj Y.val).map g.op ≫ (G.op.ranCounit.app Y.val).app (op W)) ≫ Y.val.map iVW.op =
    (f₂ ≫ (G.op.ran.obj Y.val).map g.op ≫ (G.op.ranCounit.app Y.val).app (op W)) ≫ Y.val.map iVW.op

Proof state:
case left.mk.mk.unit.op.intro
C : Type u_1
D : Type u_2
inst✝⁴ : Category.{u_3, u_1} C
inst✝³ : Category.{u_4, u_2} D
G : C ⥤ D
J : GrothendieckTopology C
K : GrothendieckTopology D
A : Type w
inst✝² : Category.{w', w} A
inst✝¹ : ∀ (X : Dᵒᵖ), Limits.HasLimitsOfShape (StructuredArrow X G.op) A
inst✝ : IsDenseSubsite J K G
Y : Sheaf J A
U : C
X : A
f₁ f₂ : (yoneda.obj (((G.op.ran ⋙ (whiskeringLeft Cᵒᵖ Dᵒᵖ A).obj G.op).obj Y.val).obj (op U))).obj (op X)
e :
  (yoneda.map ((G.op.ranCounit.app Y.val).app (op U))).app (op X) f₁ =
    (yoneda.map ((G.op.ranCounit.app Y.val).app (op U))).app (op X) f₂
W : C
g : G.obj W ⟶ G.obj U
⊢ ∀ ⦃Y_1 : C⦄ ⦃f : Y_1 ⟶ W⦄,
    (G.imageSieve g).arrows f →
      (Y.val ⋙ coyoneda.obj (op X)).map f.op
          (f₁ ≫
            ((RightExtension.mk (G.op.ran.obj Y.val) (G.op.ranCounit.app Y.val)).coneAt (op (G.obj U))).π.app
              { left := { as := PUnit.unit }, right := op W, hom := g.op }) =
        (Y.val ⋙ coyoneda.obj (op X)).map f.op
          (f₂ ≫
            ((RightExtension.mk (G.op.ran.obj Y.val) (G.op.ranCounit.app Y.val)).coneAt (op (G.obj U))).π.app
              { left := { as := PUnit.unit }, right := op W, hom := g.op })

Tactic:
dsimp

Result:
case left.mk.mk.unit.op.intro
C : Type u_1
D : Type u_2
inst✝⁴ : Category.{u_3, u_1} C
inst✝³ : Category.{u_4, u_2} D
G : C ⥤ D
J : GrothendieckTopology C
K : GrothendieckTopology D
A : Type w
inst✝² : Category.{w', w} A
inst✝¹ : ∀ (X : Dᵒᵖ), Limits.HasLimitsOfShape (StructuredArrow X G.op) A
inst✝ : IsDenseSubsite J K G
Y : Sheaf J A
U : C
X : A
f₁ f₂ : (yoneda.obj (((G.op.ran ⋙ (whiskeringLeft Cᵒᵖ Dᵒᵖ A).obj G.op).obj Y.val).obj (op U))).obj (op X)
e :
  (yoneda.map ((G.op.ranCounit.app Y.val).app (op U))).app (op X) f₁ =
    (yoneda.map ((G.op.ranCounit.app Y.val).app (op U))).app (op X) f₂
W : C
g : G.obj W ⟶ G.obj U
⊢ ∀ ⦃Y_1 : C⦄ ⦃f : Y_1 ⟶ W⦄,
    (G.imageSieve g).arrows f →
      (f₁ ≫ (G.op.ran.obj Y.val).map g.op ≫ (G.op.ranCounit.app Y.val).app (op W)) ≫ Y.val.map f.op =
        (f₂ ≫ (G.op.ran.obj Y.val).map g.op ≫ (G.op.ranCounit.app Y.val).app (op W)) ≫ Y.val.map f.op

Proof state:
case right
C : Type u_1
D : Type u_2
inst✝⁴ : Category.{u_3, u_1} C
inst✝³ : Category.{u_4, u_2} D
G : C ⥤ D
J : GrothendieckTopology C
K : GrothendieckTopology D
A : Type w
inst✝² : Category.{w', w} A
inst✝¹ : ∀ (X : Dᵒᵖ), Limits.HasLimitsOfShape (StructuredArrow X G.op) A
inst✝ : IsDenseSubsite J K G
Y : Sheaf J A
U : C
X : A
⊢ Function.Surjective ((yoneda.map ((G.op.ranCounit.app Y.val).app (op U))).app (op X))

Tactic:
intro f

Result:
case right
C : Type u_1
D : Type u_2
inst✝⁴ : Category.{u_3, u_1} C
inst✝³ : Category.{u_4, u_2} D
G : C ⥤ D
J : GrothendieckTopology C
K : GrothendieckTopology D
A : Type w
inst✝² : Category.{w', w} A
inst✝¹ : ∀ (X : Dᵒᵖ), Limits.HasLimitsOfShape (StructuredArrow X G.op) A
inst✝ : IsDenseSubsite J K G
Y : Sheaf J A
U : C
X : A
f : (yoneda.obj (((𝟭 (Cᵒᵖ ⥤ A)).obj Y.val).obj (op U))).obj (op X)
⊢ ∃ a, (yoneda.map ((G.op.ranCounit.app Y.val).app (op U))).app (op X) a = f