/-- If `A : S.obj B ⟶ T` is a costructured arrow for `S : C ⥤ D` and `T : D`, then we can
    explicitly describe the quotients of `A` as the quotients `P` of `B` in `C` for which `A.hom`
    factors through the image of `P` under `S`. -/
def quotientEquiv [HasColimits C] [PreservesColimits S] (A : CostructuredArrow S T) :
    Subobject (op A) ≃o { P : Subobject (op A.left) // ∃ q, S.map P.arrow.unop ≫ q = A.hom } where
  toFun P := ⟨projectQuotient P, projectQuotient_factors P⟩
  invFun P := liftQuotient P.val P.prop.choose_spec
  left_inv P := lift_projectQuotient _ _
  right_inv P := Subtype.ext (by simp only [liftQuotient, Quiver.Hom.unop_op, homMk_left,
      Quiver.Hom.op_unop, projectQuotient_mk, Subobject.mk_arrow])
  map_rel_iff' := by
    apply Subobject.ind₂
    intro P Q f g hf hg
    refine' ⟨fun h => Subobject.mk_le_mk_of_comm _ _, fun h => _⟩
    · 

Proof state:
case h.refine'_1
C : Type u₁
inst✝³ : Category.{v, u₁} C
D : Type u₂
inst✝² : Category.{v, u₂} D
S : C ⥤ D
T : D
inst✝¹ : HasColimits C
inst✝ : PreservesColimits S
A : CostructuredArrow S T
P Q : (CostructuredArrow S T)ᵒᵖ
f : P ⟶ op A
g : Q ⟶ op A
hf : Mono f
hg : Mono g
h :
  {
        toFun := fun P =>
          { val := projectQuotient P,
            property := (_ : ∃ q, S.map (Subobject.arrow (projectQuotient P)).unop ≫ q = A.hom) },
        invFun := fun P =>
          liftQuotient ↑P
            (_ :
              S.map (Subobject.arrow ↑P).unop ≫ Exists.choose (_ : ∃ q, S.map (Subobject.arrow ↑P).unop ≫ q = A.hom) =
                A.hom),
        left_inv :=
          (_ :
            ∀ (P : Subobject (op A)),
              liftQuotient (projectQuotient P)
                  (_ :
                    S.map
                          (Subobject.arrow
                              ↑((fun P =>
                                    { val := projectQuotient P,
                                      property :=
                                        (_ : ∃ q, S.map (Subobject.arrow (projectQuotient P)).unop ≫ q = A.hom) })
                                  P)).unop ≫
                        Exists.choose
                          (_ :
                            ∃ q,
                              S.map
                                    (Subobject.arrow
                                        ↑((fun P =>
                                              { val := projectQuotient P,
                                                property :=
                                                  (_ :
                                                    ∃ q,
                                                      S.map (Subobject.arrow (projectQuotient P)).unop ≫ q = A.hom) })
                                            P)).unop ≫
                                  q =
                                A.hom) =
                      A.hom) =
                P),
        right_inv :=
          (_ :
            ∀ (P : { P // ∃ q, S.map (Subobject.arrow P).unop ≫ q = A.hom }),
              (fun P =>
                    { val := projectQuotient P,
                      property := (_ : ∃ q, S.map (Subobject.arrow (projectQuotient P)).unop ≫ q = A.hom) })
                  ((fun P =>
                      liftQuotient ↑P
                        (_ :
                          S.map (Subobject.arrow ↑P).unop ≫
                              Exists.choose (_ : ∃ q, S.map (Subobject.arrow ↑P).unop ≫ q = A.hom) =
                            A.hom))
                    P) =
                P) }
      (Subobject.mk f) ≤
    {
        toFun := fun P =>
          { val := projectQuotient P,
            property := (_ : ∃ q, S.map (Subobject.arrow (projectQuotient P)).unop ≫ q = A.hom) },
        invFun := fun P =>
          liftQuotient ↑P
            (_ :
              S.map (Subobject.arrow ↑P).unop ≫ Exists.choose (_ : ∃ q, S.map (Subobject.arrow ↑P).unop ≫ q = A.hom) =
                A.hom),
        left_inv :=
          (_ :
            ∀ (P : Subobject (op A)),
              liftQuotient (projectQuotient P)
                  (_ :
                    S.map
                          (Subobject.arrow
                              ↑((fun P =>
                                    { val := projectQuotient P,
                                      property :=
                                        (_ : ∃ q, S.map (Subobject.arrow (projectQuotient P)).unop ≫ q = A.hom) })
                                  P)).unop ≫
                        Exists.choose
                          (_ :
                            ∃ q,
                              S.map
                                    (Subobject.arrow
                                        ↑((fun P =>
                                              { val := projectQuotient P,
                                                property :=
                                                  (_ :
                                                    ∃ q,
                                                      S.map (Subobject.arrow (projectQuotient P)).unop ≫ q = A.hom) })
                                            P)).unop ≫
                                  q =
                                A.hom) =
                      A.hom) =
                P),
        right_inv :=
          (_ :
            ∀ (P : { P // ∃ q, S.map (Subobject.arrow P).unop ≫ q = A.hom }),
              (fun P =>
                    { val := projectQuotient P,
                      property := (_ : ∃ q, S.map (Subobject.arrow (projectQuotient P)).unop ≫ q = A.hom) })
                  ((fun P =>
                      liftQuotient ↑P
                        (_ :
                          S.map (Subobject.arrow ↑P).unop ≫
                              Exists.choose (_ : ∃ q, S.map (Subobject.arrow ↑P).unop ≫ q = A.hom) =
                            A.hom))
                    P) =
                P) }
      (Subobject.mk g)
⊢ P ⟶ Q

Next tactic:
refine' (homMk (Subobject.ofMkLEMk _ _ h).unop ((cancel_epi (S.map g.unop.left)).1 _)).op