theorem affineLocally_stableUnderComposition : (affineLocally @P).StableUnderComposition := by
  intro X Y S f g hf hg
  let 𝒰 : ∀ i, ((S.affineCover.pullbackCover (f ≫ g)).obj i).OpenCover := by
    intro i
    refine' Scheme.OpenCover.bind _ fun i => Scheme.affineCover _
    apply Scheme.OpenCover.pushforwardIso _
      (pullbackRightPullbackFstIso g (S.affineCover.map i) f).hom
    apply Scheme.Pullback.openCoverOfRight
    exact (pullback g (S.affineCover.map i)).affineCover
  -- Porting note: used to be - rw [hP.affine_openCover_iff (f ≫ g) S.affineCover _] - but
  -- metavariables cause problems in the instance search
  apply (@affine_openCover_iff _ hP _ _ (f ≫ g) S.affineCover _ ?_ ?_).mpr
  rotate_left
  · exact 𝒰
  · intro i j; dsimp at *; infer_instance
  · rintro i ⟨j, k⟩
    dsimp at i j k
    dsimp only [Scheme.OpenCover.bind_map, Scheme.OpenCover.pushforwardIso_obj,
      Scheme.Pullback.openCoverOfRight_obj, Scheme.OpenCover.pushforwardIso_map,
      Scheme.Pullback.openCoverOfRight_map, Scheme.OpenCover.bind_obj]
    

Proof state:
case mk
P : {R S : Type u} → [inst : CommRing R] → [inst_1 : CommRing S] → (R →+* S) → Prop
hP : PropertyIsLocal P
X Y S : Scheme
f : X ⟶ Y
g : Y ⟶ S
hf : affineLocally P f
hg : affineLocally P g
𝒰 : (i : (Scheme.OpenCover.pullbackCover (Scheme.affineCover S) (f ≫ g)).J) →
  Scheme.OpenCover (Scheme.OpenCover.obj (Scheme.OpenCover.pullbackCover (Scheme.affineCover S) (f ≫ g)) i) :=
  fun i =>
    Scheme.OpenCover.bind
      (Scheme.OpenCover.pushforwardIso
        (Scheme.Pullback.openCoverOfRight
          (Scheme.affineCover (pullback g (Scheme.OpenCover.map (Scheme.affineCover S) i))) f pullback.fst)
        (pullbackRightPullbackFstIso g (Scheme.OpenCover.map (Scheme.affineCover S) i) f).hom)
      fun i_1 =>
      Scheme.affineCover
        (Scheme.OpenCover.obj
          (Scheme.OpenCover.pushforwardIso
            (Scheme.Pullback.openCoverOfRight
              (Scheme.affineCover (pullback g (Scheme.OpenCover.map (Scheme.affineCover S) i))) f pullback.fst)
            (pullbackRightPullbackFstIso g (Scheme.OpenCover.map (Scheme.affineCover S) i) f).hom)
          i_1)
i : (Scheme.affineCover S).J
j : (Scheme.affineCover (pullback g (Scheme.OpenCover.map (Scheme.affineCover S) i))).J
k :
  (Scheme.affineCover
      (pullback f
        (Scheme.OpenCover.map (Scheme.affineCover (pullback g (Scheme.OpenCover.map (Scheme.affineCover S) i))) j ≫
          pullback.fst))).J
⊢ P
    (Scheme.Γ.map
      ((Scheme.OpenCover.map
              (Scheme.affineCover
                (pullback f
                  (Scheme.OpenCover.map
                      (Scheme.affineCover (pullback g (Scheme.OpenCover.map (Scheme.affineCover S) i))) j ≫
                    pullback.fst)))
              k ≫
            pullback.map f
                (Scheme.OpenCover.map (Scheme.affineCover (pullback g (Scheme.OpenCover.map (Scheme.affineCover S) i)))
                    j ≫
                  pullback.fst)
                f pullback.fst (𝟙 X)
                (Scheme.OpenCover.map (Scheme.affineCover (pullback g (Scheme.OpenCover.map (Scheme.affineCover S) i)))
                  j)
                (𝟙 Y) (_ : f ≫ 𝟙 Y = 𝟙 X ≫ f)
                (_ :
                  (Scheme.OpenCover.map
                          (Scheme.affineCover (pullback g (Scheme.OpenCover.map (Scheme.affineCover S) i))) j ≫
                        pullback.fst) ≫
                      𝟙 Y =
                    Scheme.OpenCover.map
                        (Scheme.affineCover (pullback g (Scheme.OpenCover.map (Scheme.affineCover S) i))) j ≫
                      pullback.fst) ≫
              (pullbackRightPullbackFstIso g (Scheme.OpenCover.map (Scheme.affineCover S) i) f).hom) ≫
          pullback.snd).op)

Next tactic:
rw [Category.assoc, Category.assoc, pullbackRightPullbackFstIso_hom_snd,
      pullback.lift_snd_assoc, Category.assoc, ← Category.assoc, op_comp, Functor.map_comp]