-- Mathlib/CategoryTheory/Limits/Shapes/KernelPair.lean
theorem cancel_right {f₁ : X ⟶ Y} {f₂ : Y ⟶ Z} (comm : a ≫ f₁ = b ≫ f₁)
    (big_k : IsKernelPair (f₁ ≫ f₂) a b) : IsKernelPair f₁ a b :=
  { w := comm
    isLimit' :=
      ⟨PullbackCone.isLimitAux' _ fun s => by
        let s' : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂) :=
          PullbackCone.mk s.fst s.snd (s.condition_assoc _)
        refine ⟨big_k.isLimit.lift s', big_k.isLimit.fac _ WalkingCospan.left,
          big_k.isLimit.fac _ WalkingCospan.right, fun m₁ m₂ => ?_⟩
        apply big_k.isLimit.hom_ext
        refine (PullbackCone.mk a b ?_ : PullbackCone (f₁ ≫ f₂) _).equalizer_ext ?_ ?_
        · apply reassoc_of% comm
        · apply m₁.trans (big_k.isLimit.fac s' WalkingCospan.left).symm
        · apply m₂.trans (big_k.isLimit.fac s' WalkingCospan.right).symm⟩ }

Proof state:
C : Type u
inst✝ : Category.{v, u} C
R X Y Z : C
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
comm : a ≫ f₁ = b ≫ f₁
big_k : IsKernelPair (f₁ ≫ f₂) a b
s : PullbackCone f₁ f₁
s' : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂) := PullbackCone.mk s.fst s.snd ⋯
m✝ : s.pt ⟶ (PullbackCone.mk a b ⋯).pt
m₁ : m✝ ≫ (PullbackCone.mk a b ⋯).fst = s.fst
m₂ : m✝ ≫ (PullbackCone.mk a b ⋯).snd = s.snd
⊢ m✝ = (IsPullback.isLimit big_k).lift s'

Tactic:
apply big_k.isLimit.hom_ext

Result:
C : Type u
inst✝ : Category.{v, u} C
R X Y Z : C
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
comm : a ≫ f₁ = b ≫ f₁
big_k : IsKernelPair (f₁ ≫ f₂) a b
s : PullbackCone f₁ f₁
s' : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂) := PullbackCone.mk s.fst s.snd ⋯
m✝ : s.pt ⟶ (PullbackCone.mk a b ⋯).pt
m₁ : m✝ ≫ (PullbackCone.mk a b ⋯).fst = s.fst
m₂ : m✝ ≫ (PullbackCone.mk a b ⋯).snd = s.snd
⊢ ∀ (j : WalkingCospan),
    m✝ ≫ (IsPullback.cone big_k).π.app j = (IsPullback.isLimit big_k).lift s' ≫ (IsPullback.cone big_k).π.app j

Proof state:
C : Type u
inst✝ : Category.{v, u} C
R X Y Z : C
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
comm : a ≫ f₁ = b ≫ f₁
big_k : IsKernelPair (f₁ ≫ f₂) a b
s : PullbackCone f₁ f₁
s' : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂) := PullbackCone.mk s.fst s.snd ⋯
m✝ : s.pt ⟶ (PullbackCone.mk a b ⋯).pt
m₁ : m✝ ≫ (PullbackCone.mk a b ⋯).fst = s.fst
m₂ : m✝ ≫ (PullbackCone.mk a b ⋯).snd = s.snd
⊢ ∀ (j : WalkingCospan),
    m✝ ≫ (IsPullback.cone big_k).π.app j = (IsPullback.isLimit big_k).lift s' ≫ (IsPullback.cone big_k).π.app j

Tactic:
refine (PullbackCone.mk a b ?_ : PullbackCone (f₁ ≫ f₂) _).equalizer_ext ?_ ?_

Result:
case refine_1
C : Type u
inst✝ : Category.{v, u} C
R X Y Z : C
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
comm : a ≫ f₁ = b ≫ f₁
big_k : IsKernelPair (f₁ ≫ f₂) a b
s : PullbackCone f₁ f₁
s' : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂) := PullbackCone.mk s.fst s.snd ⋯
m✝ : s.pt ⟶ (PullbackCone.mk a b ⋯).pt
m₁ : m✝ ≫ (PullbackCone.mk a b ⋯).fst = s.fst
m₂ : m✝ ≫ (PullbackCone.mk a b ⋯).snd = s.snd
⊢ a ≫ f₁ ≫ f₂ = b ≫ f₁ ≫ f₂

case refine_2
C : Type u
inst✝ : Category.{v, u} C
R X Y Z : C
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
comm : a ≫ f₁ = b ≫ f₁
big_k : IsKernelPair (f₁ ≫ f₂) a b
s : PullbackCone f₁ f₁
s' : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂) := PullbackCone.mk s.fst s.snd ⋯
m✝ : s.pt ⟶ (PullbackCone.mk a b ⋯).pt
m₁ : m✝ ≫ (PullbackCone.mk a b ⋯).fst = s.fst
m₂ : m✝ ≫ (PullbackCone.mk a b ⋯).snd = s.snd
⊢ m✝ ≫ (PullbackCone.mk a b ?refine_1).fst = (IsPullback.isLimit big_k).lift s' ≫ (PullbackCone.mk a b ?refine_1).fst

case refine_3
C : Type u
inst✝ : Category.{v, u} C
R X Y Z : C
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
comm : a ≫ f₁ = b ≫ f₁
big_k : IsKernelPair (f₁ ≫ f₂) a b
s : PullbackCone f₁ f₁
s' : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂) := PullbackCone.mk s.fst s.snd ⋯
m✝ : s.pt ⟶ (PullbackCone.mk a b ⋯).pt
m₁ : m✝ ≫ (PullbackCone.mk a b ⋯).fst = s.fst
m₂ : m✝ ≫ (PullbackCone.mk a b ⋯).snd = s.snd
⊢ m✝ ≫ (PullbackCone.mk a b ?refine_1).snd = (IsPullback.isLimit big_k).lift s' ≫ (PullbackCone.mk a b ?refine_1).snd

Proof state:
case refine_3
C : Type u
inst✝ : Category.{v, u} C
R X Y Z : C
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
comm : a ≫ f₁ = b ≫ f₁
big_k : IsKernelPair (f₁ ≫ f₂) a b
s : PullbackCone f₁ f₁
s' : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂) := PullbackCone.mk s.fst s.snd ⋯
m✝ : s.pt ⟶ (PullbackCone.mk a b ⋯).pt
m₁ : m✝ ≫ (PullbackCone.mk a b ⋯).fst = s.fst
m₂ : m✝ ≫ (PullbackCone.mk a b ⋯).snd = s.snd
⊢ m✝ ≫ (PullbackCone.mk a b ⋯).snd = (IsPullback.isLimit big_k).lift s' ≫ (PullbackCone.mk a b ⋯).snd

Tactic:
apply m₂.trans (big_k.isLimit.fac s' WalkingCospan.right).symm

Result:
no goals

Proof state:
case refine_2
C : Type u
inst✝ : Category.{v, u} C
R X Y Z : C
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
comm : a ≫ f₁ = b ≫ f₁
big_k : IsKernelPair (f₁ ≫ f₂) a b
s : PullbackCone f₁ f₁
s' : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂) := PullbackCone.mk s.fst s.snd ⋯
m✝ : s.pt ⟶ (PullbackCone.mk a b ⋯).pt
m₁ : m✝ ≫ (PullbackCone.mk a b ⋯).fst = s.fst
m₂ : m✝ ≫ (PullbackCone.mk a b ⋯).snd = s.snd
⊢ m✝ ≫ (PullbackCone.mk a b ⋯).fst = (IsPullback.isLimit big_k).lift s' ≫ (PullbackCone.mk a b ⋯).fst

Tactic:
apply m₁.trans (big_k.isLimit.fac s' WalkingCospan.left).symm

Result:
no goals

Proof state:
case refine_1
C : Type u
inst✝ : Category.{v, u} C
R X Y Z : C
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
comm : a ≫ f₁ = b ≫ f₁
big_k : IsKernelPair (f₁ ≫ f₂) a b
s : PullbackCone f₁ f₁
s' : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂) := PullbackCone.mk s.fst s.snd ⋯
m✝ : s.pt ⟶ (PullbackCone.mk a b ⋯).pt
m₁ : m✝ ≫ (PullbackCone.mk a b ⋯).fst = s.fst
m₂ : m✝ ≫ (PullbackCone.mk a b ⋯).snd = s.snd
⊢ a ≫ f₁ ≫ f₂ = b ≫ f₁ ≫ f₂

Tactic:
apply reassoc_of% comm

Result:
no goals

Proof state:
C : Type u
inst✝ : Category.{v, u} C
R X Y Z : C
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
comm : a ≫ f₁ = b ≫ f₁
big_k : IsKernelPair (f₁ ≫ f₂) a b
s : PullbackCone f₁ f₁
s' : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂) := PullbackCone.mk s.fst s.snd ⋯
⊢ { l //
    l ≫ (PullbackCone.mk a b ⋯).fst = s.fst ∧
      l ≫ (PullbackCone.mk a b ⋯).snd = s.snd ∧
        ∀ {m : s.pt ⟶ (PullbackCone.mk a b ⋯).pt},
          m ≫ (PullbackCone.mk a b ⋯).fst = s.fst → m ≫ (PullbackCone.mk a b ⋯).snd = s.snd → m = l }

Tactic:
refine ⟨big_k.isLimit.lift s', big_k.isLimit.fac _ WalkingCospan.left,
  big_k.isLimit.fac _ WalkingCospan.right, fun m₁ m₂ => ?_⟩

Result:
C : Type u
inst✝ : Category.{v, u} C
R X Y Z : C
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
comm : a ≫ f₁ = b ≫ f₁
big_k : IsKernelPair (f₁ ≫ f₂) a b
s : PullbackCone f₁ f₁
s' : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂) := PullbackCone.mk s.fst s.snd ⋯
m✝ : s.pt ⟶ (PullbackCone.mk a b ⋯).pt
m₁ : m✝ ≫ (PullbackCone.mk a b ⋯).fst = s.fst
m₂ : m✝ ≫ (PullbackCone.mk a b ⋯).snd = s.snd
⊢ m✝ = (IsPullback.isLimit big_k).lift s'

Proof state:
C : Type u
inst✝ : Category.{v, u} C
R X Y Z : C
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
comm : a ≫ f₁ = b ≫ f₁
big_k : IsKernelPair (f₁ ≫ f₂) a b
s : PullbackCone f₁ f₁
⊢ { l //
    l ≫ (PullbackCone.mk a b ⋯).fst = s.fst ∧
      l ≫ (PullbackCone.mk a b ⋯).snd = s.snd ∧
        ∀ {m : s.pt ⟶ (PullbackCone.mk a b ⋯).pt},
          m ≫ (PullbackCone.mk a b ⋯).fst = s.fst → m ≫ (PullbackCone.mk a b ⋯).snd = s.snd → m = l }

Tactic:
let s' : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂) :=
  PullbackCone.mk s.fst s.snd (s.condition_assoc _)

Result:
C : Type u
inst✝ : Category.{v, u} C
R X Y Z : C
a b : R ⟶ X
f₁ : X ⟶ Y
f₂ : Y ⟶ Z
comm : a ≫ f₁ = b ≫ f₁
big_k : IsKernelPair (f₁ ≫ f₂) a b
s : PullbackCone f₁ f₁
s' : PullbackCone (f₁ ≫ f₂) (f₁ ≫ f₂) := PullbackCone.mk s.fst s.snd ⋯
⊢ { l //
    l ≫ (PullbackCone.mk a b ⋯).fst = s.fst ∧
      l ≫ (PullbackCone.mk a b ⋯).snd = s.snd ∧
        ∀ {m : s.pt ⟶ (PullbackCone.mk a b ⋯).pt},
          m ≫ (PullbackCone.mk a b ⋯).fst = s.fst → m ≫ (PullbackCone.mk a b ⋯).snd = s.snd → m = l }