import Sal.ConditionedMRDTs.Metatheory.Adequacy

/-!
# The stability VC: verified GC callbacks

The runtime learns which events have reached every replica and calls
back into the datatype to shed redundant records. This file provides:

* **§1 `SettledAt`**: the semantic cut condition (`S ⊆ E(v)`,
  downward closed, all *existing* concurrency inside `E(v)`) and the
  runtime-facing **commit-shaped** evidence form, with the lemma
  `settledAtOn_of_evidence`: heard-from-everyone-since-`S` implies concurrency
  containment. Evidence quantifies over a covered replica set `J` (open
  membership is deferred).
* **§2 the VC bundle** `StabilityVC` and the lifted configuration
  relation `ConfigRelS`. VC-S4 (`vc_merge`) is **not** a
  free argumentwise congruence: it is stated over related reachable pairs,
  encoded by threading the instance's auxiliary pair-invariant `Aux` (the
  external-invariant pattern) through every VC.
* **§3 the metatheorem** `stability_simulation`: every `Step3` step
  of the full run is matched, same label (query readback up to the observation),
  by the compacted run; a `SettledAt` compaction is a *stuttering* step, where the
  full side takes a self-merge (a genuine `Step3.merge r r`, legal because
  `IsLCA` is reflexive) and the compacted side registers `compact ŝ` at the same
  fresh slot, so DAG shapes never diverge. Reads are equal at every version
  (`stability_reads_equal`), and RA-linearizability is inherited
  *observationally* (`stability_ra_inherited`).

**Scope notes.**
1. VC-S3's class (b) (in-flight ops referencing dropped records) has no
   separate update-time clause here: in the state-based ternary model in-flight
   effects arrive exclusively through `Step3.merge` branch states, so class (b)
   is absorbed into VC-S4. `vc_step` covers exactly class (a) (fresh mints).
2. `createReplica` is gated by the bundle's `canCreate`: a replica minted at
   the root after a compaction can mint events concurrent with the cut,
   destroying settledness (the open-membership deferral made
   operational). Instances that never compact take `canCreate := ⊤`.
3. Query labels carry the raw `D.Value`; the compacted side answers with its
   own raw value (`LabelSim.query` leaves it free) and the guarantee is
   observational (`stability_reads_equal` / `reads_replica_equal`).

**Step3V compatibility** (`settledAtOn_of_evidence_reachableV`): `SettledAt` is
a per-configuration predicate and the evidence lemma consumes only `StoreInv`,
which is a `Step3V` reachability invariant (`storeInv_reachableV`), so the
evidence route is available verbatim on the widened system. The simulation
itself is stated over `Step3` (what `gc_safety` uses); widening the matching to
`Step3V.mergeVirtual` would require VC-S4 at virtual-LCA states and is out of
scope.
-/

namespace Sal.ConditionedMRDTs

open Sal.Emulation

section Settled

variable {D : ConditionedMRDTSig}

/-! ## §1 SettledAt: the semantic cut condition and the evidence form -/

/-- Two events are concurrent in `C`: distinct and `vis`-unrelated. -/
def ConcOp (C : Configuration D) (e a : Op D.AppOp) : Prop :=
  e ≠ a ∧ ¬ C.vis e a ∧ ¬ C.vis a e

/-- **The semantic settled condition**, stated against the event set
`E` of the settling version: the cut is inside `E` and causally downward
closed, and every event *existing anywhere in the configuration* that is
concurrent with a cut member is already in `E`. -/
structure SettledAtOn (C : Configuration D) (E S : Set (Op D.AppOp)) : Prop where
  /-- `S ⊆ E(v)`. -/
  sub : S ⊆ E
  /-- `S` is causally downward closed. -/
  down : ∀ a b, C.vis a b → b ∈ S → a ∈ S
  /-- All existing concurrency with `S` is inside `E(v)`. -/
  conc : ∀ e ∈ C.events, (∃ a ∈ S, ConcOp C e a) → e ∈ E

/-- `SettledAt v S`: version `v` is allocated and its event set settles `S`. -/
def SettledAt (C : Configuration D) (v : Version) (S : Set (Op D.AppOp)) : Prop :=
  ∃ s E, C.ver v = some (s, E) ∧ SettledAtOn C E S

/-- **Commit-shaped per-replica evidence**: a version `c`
absorbed by `v` (`Reaches`), containing `S`, certified as replica `j`'s commit
by the chain clause: every `j`-event outside `E(c)` post-dates it, in
particular has all of `S` in its causal past. A pull that brings no new events
can still bring `c`; nothing here mentions minted events of the pull itself. -/
def EvidenceCommit (C : Configuration D) (v : Version) (S : Set (Op D.AppOp))
    (j : Replica) : Prop :=
  ∃ c sc Ec, Reaches C.parents c v ∧ C.ver c = some (sc, Ec) ∧ S ⊆ Ec ∧
    ∀ e ∈ C.events, Op.rep e = j → e ∉ Ec → ∀ a ∈ S, C.vis a e

/-- **The evidence lemma**: if `v` has absorbed an evidence commit
for every replica of a set `J` covering all event authors, then all existing
concurrency with `S` is inside `E(v)`: the runtime's per-replica commits
discharge the semantic condition. The only store fact consumed is
`events_mono` along `Reaches` (`StoreInv`). -/
theorem settledAtOn_of_evidence {C : Configuration D}
    (hStore : StoreInv C.ver C.parents)
    {v : Version} {s : D.State} {E S : Set (Op D.AppOp)}
    (hv : C.ver v = some (s, E))
    (hsub : S ⊆ E) (hdown : ∀ a b, C.vis a b → b ∈ S → a ∈ S)
    {J : Set Replica}
    (hJ : ∀ e ∈ C.events, Op.rep e ∈ J)
    (hev : ∀ j ∈ J, EvidenceCommit C v S j) :
    SettledAtOn C E S := by
  refine ⟨hsub, hdown, ?_⟩
  rintro e he ⟨a, ha, -, -, hnae⟩
  obtain ⟨c, sc, Ec, hreach, hc, hSc, hcert⟩ := hev (Op.rep e) (hJ e he)
  by_cases hmem : e ∈ Ec
  · exact storeInv_events_mono_reaches hStore hreach hc hv hmem
  · exact absurd (hcert e he rfl hmem a ha) hnae

/-- The version-level form: `SettledAt` from allocatedness + the evidence. -/
theorem settledAt_of_evidence {C : Configuration D}
    (hStore : StoreInv C.ver C.parents)
    {v : Version} {s : D.State} {E S : Set (Op D.AppOp)}
    (hv : C.ver v = some (s, E))
    (hsub : S ⊆ E) (hdown : ∀ a b, C.vis a b → b ∈ S → a ∈ S)
    {J : Set Replica}
    (hJ : ∀ e ∈ C.events, Op.rep e ∈ J)
    (hev : ∀ j ∈ J, EvidenceCommit C v S j) :
    SettledAt C v S :=
  ⟨s, E, hv, settledAtOn_of_evidence hStore hv hsub hdown hJ hev⟩

open LabeledTS in
/-- **Step3V compatibility**: the evidence lemma is available
at every configuration reachable in the *widened* system `Step3V`, because
`StoreInv` is a `Step3V` reachability invariant. Nothing else in `SettledAt`
mentions the step relation. -/
theorem settledAt_of_evidence_reachableV {hInit : D.Inv D.init}
    {C : Configuration D}
    (hReach : (labeledTS3V D).ReachableFrom (initConfig D hInit) C)
    {v : Version} {s : D.State} {E S : Set (Op D.AppOp)}
    (hv : C.ver v = some (s, E))
    (hsub : S ⊆ E) (hdown : ∀ a b, C.vis a b → b ∈ S → a ∈ S)
    {J : Set Replica}
    (hJ : ∀ e ∈ C.events, Op.rep e ∈ J)
    (hev : ∀ j ∈ J, EvidenceCommit C v S j) :
    SettledAt C v S :=
  settledAt_of_evidence (storeInv_reachableV hReach) hv hsub hdown hJ hev

/-- **Event-shaped witness ⟹ commit-shaped evidence** (a valid *strengthening*,
not a definition): an event `w ∈ E(v)`
by `j` with all of `S` visible to it certifies `v` itself as `j`'s evidence
commit. Uses `vis` transitivity, per-version causal closure and the structural
same-replica totality, all supplied by `GoodConfig3` below. -/
theorem evidenceCommit_of_witness {C : Configuration D}
    (hTrans : ∀ {a b c : Op D.AppOp}, C.vis a b → C.vis b c → C.vis a c)
    {v : Version} {s : D.State} {E S : Set (Op D.AppOp)}
    (hv : C.ver v = some (s, E))
    (hCausal : ∀ a b, C.vis a b → b ∈ E → a ∈ E)
    (hEsub : ∀ a ∈ E, a ∈ C.events)
    (hSsub : S ⊆ E)
    {j : Replica} {w : Op D.AppOp}
    (hw : w ∈ E) (hrep : Op.rep w = j) (hpast : ∀ a ∈ S, C.vis a w) :
    EvidenceCommit C v S j := by
  refine ⟨v, s, E, Relation.ReflTransGen.refl, hv, hSsub, ?_⟩
  intro e he hej hne a ha
  have hwE : w ∈ C.events := hEsub w hw
  obtain ⟨r₁, s₁, hL₁, hs₁⟩ := he
  obtain ⟨r₂, s₂, hL₂, hs₂⟩ := hwE
  have hnew : e ≠ w := fun h => hne (h ▸ hw)
  have hrr : e.2.1 = w.2.1 := by
    show Op.rep e = Op.rep w
    rw [hej, hrep]
  rcases C.vis_total_same_replica hL₁ hs₁ hL₂ hs₂ hnew hrr with hew | hwe
  · exact absurd (hCausal e w hew hw) hne
  · exact hTrans (hpast a ha) hwe

/-- The `GoodConfig3` packaging of the witness bridge. -/
theorem evidenceCommit_of_witness_good {C : Configuration D}
    (hGood : GoodConfig3 C)
    {v : Version} {s : D.State} {E S : Set (Op D.AppOp)}
    (hv : C.ver v = some (s, E)) (hSsub : S ⊆ E)
    {j : Replica} {w : Op D.AppOp}
    (hw : w ∈ E) (hrep : Op.rep w = j) (hpast : ∀ a ∈ S, C.vis a w) :
    EvidenceCommit C v S j :=
  evidenceCommit_of_witness (fun hab hbc => hGood.vis_trans hab hbc) hv
    (hGood.ver_causal v s E hv) (hGood.ver_events_sub v s E hv) hSsub hw hrep
    hpast

/-- **The all-heads frontier condition**: every current head's event set
contains `S`. This is the same all-heads knowledge the commit GC (`gc_safety`)
requires; as a compaction *gate* alone it is unsound
(the OR-set SPOT pins the countermodel), so instances use it only as the
stability side of the runtime contract, alongside `SettledAt`. -/
def AllHeard (C : Configuration D) (S : Set (Op D.AppOp)) : Prop :=
  ∀ r v s E, C.head r = some v → C.ver v = some (s, E) → S ⊆ E

end Settled

section Lifted

variable {D : ConditionedMRDTSig}

/-! ## §2 The lifted configuration relation -/

/-- **The lifted relation**: DAG shape, heads, visibility and event
sets shared verbatim; version payloads pointwise `R`-related (full on the left,
compacted on the right). `heads_alloc`/`head_none` are the two head-hygiene
facts of the full side that every reachable configuration enjoys; they are
carried here so the matching lemmas close without a reachability detour. -/
structure ConfigRelS (R : D.State → D.State → Prop)
    (C Ĉ : Configuration D) : Prop where
  L_eq : Ĉ.L = C.L
  vis_eq : Ĉ.vis = C.vis
  head_eq : Ĉ.head = C.head
  parents_eq : Ĉ.parents = C.parents
  heads_alloc : ∀ r v, C.head r = some v → (C.ver v).isSome
  head_none : ∀ r, C.head r = none → C.N r = none
  ver_events : ∀ v, (Ĉ.ver v).map Prod.snd = (C.ver v).map Prod.snd
  ver_rel : ∀ v s E ŝ Ê, C.ver v = some (s, E) → Ĉ.ver v = some (ŝ, Ê) →
    R s ŝ

namespace ConfigRelS

variable {R : D.State → D.State → Prop} {C Ĉ : Configuration D}

theorem events_eq (h : ConfigRelS R C Ĉ) : Ĉ.events = C.events := by
  unfold Configuration.events
  rw [h.L_eq]

/-- Allocation matches slot for slot. -/
theorem ver_isSome (h : ConfigRelS R C Ĉ) (v : Version) :
    (Ĉ.ver v).isSome = (C.ver v).isSome := by
  have hE := h.ver_events v
  cases hc : C.ver v with
  | none =>
    rw [hc] at hE
    cases hĉ : Ĉ.ver v with
    | none => rfl
    | some q => rw [hĉ] at hE; simp at hE
  | some p =>
    rw [hc] at hE
    cases hĉ : Ĉ.ver v with
    | none => rw [hĉ] at hE; simp at hE
    | some q => rfl

/-- A full-side allocation forces a compacted one with the *same* event set. -/
theorem ver_some (h : ConfigRelS R C Ĉ) {v : Version} {s : D.State}
    {E : Set (Op D.AppOp)} (hv : C.ver v = some (s, E)) :
    ∃ ŝ, Ĉ.ver v = some (ŝ, E) ∧ R s ŝ := by
  have hE := h.ver_events v
  rw [hv] at hE
  cases hĉ : Ĉ.ver v with
  | none => rw [hĉ] at hE; simp at hE
  | some q =>
    obtain ⟨ŝ, Ê⟩ := q
    rw [hĉ] at hE
    simp only [Option.map_some] at hE
    have hEE : Ê = E := by injection hE
    rw [hEE] at hĉ
    refine ⟨ŝ, ?_, h.ver_rel v s E ŝ E hv hĉ⟩
    rw [hEE]

theorem ver_none (h : ConfigRelS R C Ĉ) {v : Version}
    (hv : C.ver v = none) : Ĉ.ver v = none := by
  have hs := h.ver_isSome v
  rw [hv] at hs
  cases hĉ : Ĉ.ver v with
  | none => rfl
  | some q => rw [hĉ] at hs; simp at hs

/-- The compacted side answers every replica read with an `R`-related state. -/
theorem N_some (h : ConfigRelS R C Ĉ) {r : Replica} {s : D.State}
    (hN : C.N r = some s) : ∃ ŝ, Ĉ.N r = some ŝ ∧ R s ŝ := by
  cases hh : C.head r with
  | none =>
    have := h.head_none r hh
    rw [hN] at this
    cases this
  | some v =>
    have hcoh := C.head_coherent r v hh
    have halloc := h.heads_alloc r v hh
    obtain ⟨⟨sv, Ev⟩, hv⟩ := Option.isSome_iff_exists.mp halloc
    have hsv : sv = s := by
      have := hcoh.1
      rw [hv, hN] at this
      simpa using this
    subst hsv
    obtain ⟨ŝ, hĉ, hR⟩ := h.ver_some hv
    have hĥ : Ĉ.head r = some v := by rw [h.head_eq]; exact hh
    have hcohĉ := Ĉ.head_coherent r v hĥ
    refine ⟨ŝ, ?_, hR⟩
    have := hcohĉ.1
    rw [hĉ] at this
    simpa using this.symm

theorem N_none (h : ConfigRelS R C Ĉ) {r : Replica}
    (hN : C.N r = none) : Ĉ.N r = none := by
  have hL : C.L r = none := (C.dom_eq r).mp hN
  refine (Ĉ.dom_eq r).mpr ?_
  rw [h.L_eq]
  exact hL

theorem N_none_iff (h : ConfigRelS R C Ĉ) (r : Replica) :
    Ĉ.N r = none ↔ C.N r = none := by
  rw [Ĉ.dom_eq r, C.dom_eq r, h.L_eq]

/-- A compacted-side allocation reflects to the full side, same event set. -/
theorem ver_some' (h : ConfigRelS R C Ĉ) {v : Version} {ŝ : D.State}
    {Ê : Set (Op D.AppOp)} (hv : Ĉ.ver v = some (ŝ, Ê)) :
    ∃ s, C.ver v = some (s, Ê) := by
  have hE := h.ver_events v
  rw [hv] at hE
  cases hc : C.ver v with
  | none => rw [hc] at hE; simp at hE
  | some p =>
    obtain ⟨ps, pe⟩ := p
    rw [hc] at hE
    simp only [Option.map_some] at hE
    have hpe : Ê = pe := by injection hE
    subst hpe
    exact ⟨ps, rfl⟩

end ConfigRelS

/-- The lifted relation holds reflexively at any configuration whose heads are
hygienic, in particular at `initConfig` (`relS_init`). -/
theorem relS_refl {R : D.State → D.State → Prop} {C : Configuration D}
    (hrefl : ∀ s, R s s)
    (hha : ∀ r v, C.head r = some v → (C.ver v).isSome)
    (hhn : ∀ r, C.head r = none → C.N r = none) :
    ConfigRelS R C C where
  L_eq := rfl
  vis_eq := rfl
  head_eq := rfl
  parents_eq := rfl
  heads_alloc := hha
  head_none := hhn
  ver_events := fun _ => rfl
  ver_rel := fun v s E ŝ Ê hv hv' => by
    rw [hv] at hv'
    have : s = ŝ := by
      have := congrArg (Option.map Prod.fst) hv'
      simpa using this
    rw [← this]
    exact hrefl s

theorem relS_init {R : D.State → D.State → Prop} (hrefl : ∀ s, R s s)
    (hInit : D.Inv D.init) :
    ConfigRelS R (initConfig D hInit) (initConfig D hInit) := by
  refine relS_refl hrefl ?_ ?_
  · intro r v hh
    by_cases hr : r = 0
    · subst hr
      have h00 : (initConfig D hInit).head 0 = some 0 := rfl
      rw [h00] at hh
      injection hh with hh
      subst hh
      rw [(initConfig D hInit).ver_init]
      rfl
    · have : (initConfig D hInit).head r = none := by
        show (if r = 0 then some 0 else none) = none
        rw [if_neg hr]
      rw [this] at hh
      cases hh
  · intro r hh
    by_cases hr : r = 0
    · subst hr
      have : (initConfig D hInit).head 0 = some 0 := rfl
      rw [this] at hh
      cases hh
    · show (if r = 0 then some D.init else none) = none
      rw [if_neg hr]

/-! ## §2b The payload surgery

`restate Cb Nc verc …` is `Cb` (the *full-side target* of a step) with its
per-version states and replica heads replaced; event sets, DAG, heads and the
whole replica-keyed causal core are carried verbatim. The five obligations are
exactly what the `Configuration` invariants need; in particular `lca_events`
transfers because the event components are untouched. -/

def restate (Cb : Configuration D)
    (Nc : Replica → Option D.State)
    (verc : Version → Option (D.State × Set (Op D.AppOp)))
    (hE : ∀ v, (verc v).map Prod.snd = (Cb.ver v).map Prod.snd)
    (h0 : verc 0 = some (D.init, ∅))
    (hInv : ∀ v s e, verc v = some (s, e) → D.Inv s)
    (hNd : ∀ r, Nc r = none ↔ Cb.N r = none)
    (hcoh : ∀ r v, Cb.head r = some v → (verc v).map Prod.fst = Nc r) :
    Configuration D where
  N := Nc
  L := Cb.L
  vis := Cb.vis
  dom_eq := fun r => (hNd r).trans (Cb.dom_eq r)
  vis_src := Cb.vis_src
  vis_tgt := Cb.vis_tgt
  vis_causal := Cb.vis_causal
  timestamps_distinct := Cb.timestamps_distinct
  causal_mono := Cb.causal_mono
  vis_total_same_replica := Cb.vis_total_same_replica
  ver := verc
  head := Cb.head
  parents := Cb.parents
  parents_lt := Cb.parents_lt
  ver_init := h0
  head_coherent := fun r v h =>
    ⟨hcoh r v h, (hE v).trans (Cb.head_coherent r v h).2⟩
  ver_inv := hInv
  lca_events := by
    intro v₁ v₂ vT s₁ e₁ s₂ e₂ sT eT hlca h1 h2 hT
    have conv : ∀ {w sw ew}, verc w = some (sw, ew) →
        ∃ sw', Cb.ver w = some (sw', ew) := by
      intro w sw ew hw
      have hEw := hE w
      rw [hw] at hEw
      cases hb : Cb.ver w with
      | none => rw [hb] at hEw; simp at hEw
      | some p =>
        obtain ⟨ps, pe⟩ := p
        rw [hb] at hEw
        simp only [Option.map_some] at hEw
        have hpe : ew = pe := by injection hEw
        subst hpe
        exact ⟨ps, rfl⟩
    obtain ⟨s₁', h1'⟩ := conv h1
    obtain ⟨s₂', h2'⟩ := conv h2
    obtain ⟨sT', hT'⟩ := conv hT
    exact Cb.lca_events hlca h1' h2' hT'

@[simp] theorem restate_ver (Cb : Configuration D) (Nc verc hE h0 hInv hNd hcoh) :
    (restate Cb Nc verc hE h0 hInv hNd hcoh).ver = verc := rfl

@[simp] theorem restate_N (Cb : Configuration D) (Nc verc hE h0 hInv hNd hcoh) :
    (restate Cb Nc verc hE h0 hInv hNd hcoh).N = Nc := rfl

@[simp] theorem restate_L (Cb : Configuration D) (Nc verc hE h0 hInv hNd hcoh) :
    (restate Cb Nc verc hE h0 hInv hNd hcoh).L = Cb.L := rfl

@[simp] theorem restate_vis (Cb : Configuration D) (Nc verc hE h0 hInv hNd hcoh) :
    (restate Cb Nc verc hE h0 hInv hNd hcoh).vis = Cb.vis := rfl

@[simp] theorem restate_head (Cb : Configuration D) (Nc verc hE h0 hInv hNd hcoh) :
    (restate Cb Nc verc hE h0 hInv hNd hcoh).head = Cb.head := rfl

@[simp] theorem restate_parents (Cb : Configuration D)
    (Nc verc hE h0 hInv hNd hcoh) :
    (restate Cb Nc verc hE h0 hInv hNd hcoh).parents = Cb.parents := rfl

end Lifted

section Bundle

variable {D : ConditionedMRDTSig}

/-! ## §2c The VC bundle -/

/-- **The stability VC bundle** for a fixed cut `S` and callback `compact`.

* `R`: the simulation relation (full left, compacted right); `vc_refl` keeps
  the pre-compaction run related.
* `obs`: the datatype's read interface; **VC-S2** is `vc_obs`.
* `Aux`: the instance's auxiliary pair-invariant, the *reachable-triples*
  side condition threaded through `vc_step`/`vc_merge`/
  `vc_entry` and maintained by the `aux_*` obligations (external-invariant
  pattern).
* **VC-S1** is `vc_entry` (the full side's stuttering self-merge payload
  `mergeL s s s` against `compact ŝ`), gated by `gate`, which must imply
  `SettledAt` (`gate_settled`).
* **VC-S3** is `vc_step`, class (a) only; class (b) is absorbed into VC-S4
  (scope note 1).
* **VC-S4** is `vc_merge`, *not* a free congruence: it fires only under
  `ConfigRelS ∧ Aux` at genuine merge premises.
* **VC-S5** is `vc_inv` (state-shape contract preservation; the honesty
  contract is inherited observationally by `stability_ra_inherited`).
* **VC-S6** (epoch coherence) is the standalone `EpochCoherentObs` below.
-/
structure StabilityVC (D : ConditionedMRDTSig) where
  R : D.State → D.State → Prop
  Obs : Type
  obs : D.State → Obs
  compact : D.State → D.State
  S : Set (Op D.AppOp)
  Aux : Configuration D → Configuration D → Prop
  gate : Configuration D → Configuration D → Replica → Version → Prop
  canCreate : Configuration D → Configuration D → Replica → Prop
  vc_refl : ∀ s, R s s
  vc_obs : ∀ {s ŝ}, R s ŝ → obs s = obs ŝ
  vc_inv : ∀ {s ŝ}, R s ŝ → D.Inv s → D.Inv ŝ
  gate_settled : ∀ {C Ĉ r v}, gate C Ĉ r v → SettledAt C v S
  vc_step : ∀ {C Ĉ : Configuration D}, ConfigRelS R C Ĉ → Aux C Ĉ →
    ∀ {t : Timestamp} {r : Replica} {o : D.AppOp} {v : Version}
      {s ŝ : D.State} {E : Set (Op D.AppOp)},
    C.head r = some v → C.ver v = some (s, E) → Ĉ.ver v = some (ŝ, E) →
    (∀ e' ∈ C.events, Op.time e' ≠ t) →
    (∀ w sw Ew, C.ver w = some (sw, Ew) → ∀ e' ∈ Ew, Op.time e' ≠ t) →
    R s ŝ → R (D.update s (t, r, o)) (D.update ŝ (t, r, o))
  vc_merge : ∀ {C Ĉ : Configuration D}, ConfigRelS R C Ĉ → Aux C Ĉ →
    ∀ {r₁ r₂ : Replica} {v₁ v₂ vT : Version} {s₁ s₂ sT ŝ₁ ŝ₂ ŝT : D.State}
      {E₁ E₂ ET : Set (Op D.AppOp)},
    C.head r₁ = some v₁ → C.head r₂ = some v₂ →
    C.ver v₁ = some (s₁, E₁) → C.ver v₂ = some (s₂, E₂) →
    IsLCA C.parents v₁ v₂ vT → C.ver vT = some (sT, ET) →
    Ĉ.ver v₁ = some (ŝ₁, E₁) → Ĉ.ver v₂ = some (ŝ₂, E₂) →
    Ĉ.ver vT = some (ŝT, ET) →
    R (D.mergeL sT s₁ s₂) (D.mergeL ŝT ŝ₁ ŝ₂)
  vc_entry : ∀ {C Ĉ : Configuration D}, ConfigRelS R C Ĉ → Aux C Ĉ →
    ∀ {r : Replica} {v : Version} {s ŝ : D.State} {E : Set (Op D.AppOp)},
    gate C Ĉ r v → C.head r = some v → C.ver v = some (s, E) →
    Ĉ.ver v = some (ŝ, E) →
    R (D.mergeL s s s) (compact ŝ)
  aux_init : ∀ hInit : D.Inv D.init,
    Aux (initConfig D hInit) (initConfig D hInit)
  aux_create : ∀ {C Ĉ C' Ĉ' : Configuration D} {r : Replica},
    ConfigRelS R C Ĉ → Aux C Ĉ → canCreate C Ĉ r →
    Step3 D C (.createReplica r) C' → Step3 D Ĉ (.createReplica r) Ĉ' →
    ConfigRelS R C' Ĉ' → Aux C' Ĉ'
  aux_apply : ∀ {C Ĉ C' Ĉ' : Configuration D} {t : Timestamp} {r : Replica}
      {o : D.AppOp},
    ConfigRelS R C Ĉ → Aux C Ĉ →
    Step3 D C (.apply t r o) C' → Step3 D Ĉ (.apply t r o) Ĉ' →
    ConfigRelS R C' Ĉ' → Aux C' Ĉ'
  aux_merge : ∀ {C Ĉ C' Ĉ' : Configuration D} {r₁ r₂ : Replica},
    ConfigRelS R C Ĉ → Aux C Ĉ →
    Step3 D C (.merge r₁ r₂) C' → Step3 D Ĉ (.merge r₁ r₂) Ĉ' →
    ConfigRelS R C' Ĉ' → Aux C' Ĉ'
  aux_compact : ∀ {C Ĉ C' Ĉ' : Configuration D} {r : Replica} {v vm : Version}
      {s ŝ : D.State} {E : Set (Op D.AppOp)},
    ConfigRelS R C Ĉ → Aux C Ĉ → gate C Ĉ r v →
    C.head r = some v → C.ver v = some (s, E) → Ĉ.ver v = some (ŝ, E) →
    C.ver vm = none → v < vm →
    Step3 D C (.merge r r) C' →
    C'.ver = (fun w => if w = vm then some (D.mergeL s s s, E ∪ E)
      else C.ver w) →
    C'.head = (fun r' => if r' = r then some vm else C.head r') →
    C'.L = updateRep C.L r (E ∪ E) →
    C'.vis = C.vis →
    C'.parents = (fun w => if w = vm then [v, v] else C.parents w) →
    Ĉ'.N = updateRep Ĉ.N r (compact ŝ) →
    Ĉ'.L = C'.L → Ĉ'.vis = C'.vis → Ĉ'.head = C'.head →
    Ĉ'.parents = C'.parents →
    Ĉ'.ver = (fun w => if w = vm then some (compact ŝ, E ∪ E) else Ĉ.ver w) →
    ConfigRelS R C' Ĉ' → Aux C' Ĉ'

/-- **VC-S6, epoch coherence, observational form**: compacting at `S` and then
at `S' ⊇ S` lands in the same
*observational* class as compacting at `S'` directly. (As a same-`R`-class
statement it is false for graph-shaped relations: a tag dropped at the first
epoch whose second-epoch keeper has since died is kept by the direct `S'`
compaction; reads still agree, which is what the harness checks.) -/
def EpochCoherentObs (V V' : StabilityVC D) : Prop :=
  ∀ h : V'.Obs = V.Obs, ∀ s,
    h ▸ V'.obs (V'.compact (V.compact s)) = h ▸ V'.obs (V'.compact s)

/-- Label matching: mutating labels verbatim; a query answers with the raw
value of the answering side (the observational guarantee is
`stability_reads_equal` / `reads_replica_equal`). -/
inductive LabelSim (D : ConditionedMRDTSig) : Label3 D → Label3 D → Prop where
  | create (r : Replica) :
      LabelSim D (.createReplica r) (.createReplica r)
  | apply (t : Timestamp) (r : Replica) (o : D.AppOp) :
      LabelSim D (.apply t r o) (.apply t r o)
  | merge (r₁ r₂ : Replica) : LabelSim D (.merge r₁ r₂) (.merge r₁ r₂)
  | query (r : Replica) (q : D.Query) (val val' : D.Value) :
      LabelSim D (.query r q val) (.query r q val')

end Bundle

section Matching

variable {D : ConditionedMRDTSig} (V : StabilityVC D)

/-! ## §3 The matching lemmas: every full step is matched compactedly -/

/-- CreateReplica is matched verbatim (store untouched on either side). -/
theorem stability_match_create {C Ĉ C' : Configuration D} {r : Replica}
    (rel : ConfigRelS V.R C Ĉ) (aux : V.Aux C Ĉ)
    (hcc : V.canCreate C Ĉ r)
    (hstep : Step3 D C (.createReplica r) C') :
    ∃ Ĉ', Step3 D Ĉ (.createReplica r) Ĉ' ∧
      ConfigRelS V.R C' Ĉ' ∧ V.Aux C' Ĉ' := by
  cases hstep with
  | @createReplica _ h_fresh C' hN hL hvis hver hhead hparents =>
  have hE : ∀ w, (Ĉ.ver w).map Prod.snd = (C'.ver w).map Prod.snd := by
    intro w; rw [hver]; exact rel.ver_events w
  have hNd : ∀ r', updateRep Ĉ.N r D.init r' = none ↔ C'.N r' = none := by
    intro r'
    rw [hN]
    show updateRep Ĉ.N r D.init r' = none ↔ updateRep C.N r D.init r' = none
    unfold updateRep
    by_cases hr : r' = r
    · rw [if_pos hr, if_pos hr]
    · rw [if_neg hr, if_neg hr]
      exact rel.N_none_iff r'
  have hcoh : ∀ r' w, C'.head r' = some w →
      (Ĉ.ver w).map Prod.fst = updateRep Ĉ.N r D.init r' := by
    intro r' w hw
    simp only [hhead] at hw
    unfold updateRep
    by_cases hr : r' = r
    · rw [if_pos hr] at hw ⊢
      injection hw with hw
      subst hw
      rw [Ĉ.ver_init]
      rfl
    · rw [if_neg hr] at hw ⊢
      have hĥ : Ĉ.head r' = some w := by rw [rel.head_eq]; exact hw
      exact (Ĉ.head_coherent r' w hĥ).1
  let Ĉ' : Configuration D :=
    restate C' (updateRep Ĉ.N r D.init) Ĉ.ver hE Ĉ.ver_init Ĉ.ver_inv hNd hcoh
  have hstep' : Step3 D Ĉ (.createReplica r) Ĉ' := by
    refine Step3.createReplica (rel.N_none h_fresh) _ rfl ?_ ?_ rfl ?_ ?_
    · show C'.L = updateRep Ĉ.L r ∅
      rw [hL, rel.L_eq]
    · show C'.vis = Ĉ.vis
      rw [hvis, rel.vis_eq]
    · show C'.head = fun r' => if r' = r then some 0 else Ĉ.head r'
      rw [hhead, rel.head_eq]
    · show C'.parents = Ĉ.parents
      rw [hparents, rel.parents_eq]
  have hrel' : ConfigRelS V.R C' Ĉ' := by
    refine ⟨rfl, rfl, rfl, rfl, ?_, ?_, hE, ?_⟩
    · intro r' w hw
      simp only [hhead] at hw
      rw [hver]
      by_cases hr : r' = r
      · rw [if_pos hr] at hw
        injection hw with hw
        subst hw
        rw [C.ver_init]
        rfl
      · rw [if_neg hr] at hw
        exact rel.heads_alloc r' w hw
    · intro r' hw
      simp only [hhead] at hw
      by_cases hr : r' = r
      · rw [if_pos hr] at hw
        cases hw
      · rw [if_neg hr] at hw
        rw [hN]
        show updateRep C.N r D.init r' = none
        unfold updateRep
        rw [if_neg hr]
        exact rel.head_none r' hw
    · intro w s E ŝ Ê hw hŵ
      rw [hver] at hw
      exact rel.ver_rel w s E ŝ Ê hw hŵ
  exact ⟨Ĉ', hstep', hrel', V.aux_create rel aux hcc
    (Step3.createReplica h_fresh C' hN hL hvis hver hhead hparents)
    hstep' hrel'⟩

/-- Apply is matched verbatim: same op, same fresh slot; the fresh payload is
related by **VC-S3** (`vc_step`). -/
theorem stability_match_apply {C Ĉ C' : Configuration D} {t : Timestamp}
    {r : Replica} {o : D.AppOp}
    (rel : ConfigRelS V.R C Ĉ) (aux : V.Aux C Ĉ)
    (hstep : Step3 D C (.apply t r o) C') :
    ∃ Ĉ', Step3 D Ĉ (.apply t r o) Ĉ' ∧
      ConfigRelS V.R C' Ĉ' ∧ V.Aux C' Ĉ' := by
  cases hstep with
  | @apply _ _ _ v s ev vnew h_head h_ver h_fresh_t h_fresh_store h_vnew
      h_rank C' hN hL hvis hver hhead hparents =>
  obtain ⟨ŝ, hĉv, hR⟩ := rel.ver_some h_ver
  have hR' : V.R (D.update s (t, r, o)) (D.update ŝ (t, r, o)) :=
    V.vc_step rel aux h_head h_ver hĉv h_fresh_t h_fresh_store hR
  have h0ne : (0 : Version) ≠ vnew := by
    intro h
    rw [← h] at h_vnew
    rw [C.ver_init] at h_vnew
    cases h_vnew
  have hE : ∀ w,
      ((fun w => if w = vnew
        then some (D.update ŝ (t, r, o), ev ∪ {(t, r, o)})
        else Ĉ.ver w) w).map Prod.snd = (C'.ver w).map Prod.snd := by
    intro w
    rw [hver]
    dsimp only
    by_cases hw : w = vnew
    · rw [if_pos hw, if_pos hw]
      rfl
    · rw [if_neg hw, if_neg hw]
      exact rel.ver_events w
  have h0 : (fun w => if w = vnew
      then some (D.update ŝ (t, r, o), ev ∪ {(t, r, o)})
      else Ĉ.ver w) 0 = some (D.init, ∅) := by
    dsimp only
    rw [if_neg h0ne]
    exact Ĉ.ver_init
  have hInvV : ∀ w sw ew, (fun w => if w = vnew
      then some (D.update ŝ (t, r, o), ev ∪ {(t, r, o)})
      else Ĉ.ver w) w = some (sw, ew) → D.Inv sw := by
    intro w sw ew hw
    dsimp only at hw
    by_cases hwn : w = vnew
    · rw [if_pos hwn] at hw
      injection hw with hw
      have hsw : sw = D.update ŝ (t, r, o) := (congrArg Prod.fst hw).symm
      rw [hsw]
      refine V.vc_inv hR' (C'.ver_inv vnew (D.update s (t, r, o))
        (ev ∪ {(t, r, o)}) ?_)
      rw [hver]
      simp
    · rw [if_neg hwn] at hw
      exact Ĉ.ver_inv w sw ew hw
  have hNd : ∀ r', updateRep Ĉ.N r (D.update ŝ (t, r, o)) r' = none ↔
      C'.N r' = none := by
    intro r'
    rw [hN]
    unfold updateRep
    by_cases hr : r' = r
    · rw [if_pos hr, if_pos hr]
      simp
    · rw [if_neg hr, if_neg hr]
      exact rel.N_none_iff r'
  have hcoh : ∀ r' w, C'.head r' = some w →
      ((fun w => if w = vnew
        then some (D.update ŝ (t, r, o), ev ∪ {(t, r, o)})
        else Ĉ.ver w) w).map Prod.fst
        = updateRep Ĉ.N r (D.update ŝ (t, r, o)) r' := by
    intro r' w hw
    simp only [hhead] at hw
    dsimp only
    unfold updateRep
    by_cases hr : r' = r
    · rw [if_pos hr] at hw ⊢
      injection hw with hw
      subst hw
      rw [if_pos rfl]
      rfl
    · rw [if_neg hr] at hw ⊢
      have hwne : w ≠ vnew := by
        intro h
        have := rel.heads_alloc r' w hw
        rw [h, h_vnew] at this
        cases this
      rw [if_neg hwne]
      have hĥ : Ĉ.head r' = some w := by rw [rel.head_eq]; exact hw
      exact (Ĉ.head_coherent r' w hĥ).1
  let Ĉ' : Configuration D :=
    restate C' (updateRep Ĉ.N r (D.update ŝ (t, r, o)))
      (fun w => if w = vnew
        then some (D.update ŝ (t, r, o), ev ∪ {(t, r, o)})
        else Ĉ.ver w) hE h0 hInvV hNd hcoh
  have hstep' : Step3 D Ĉ (.apply t r o) Ĉ' := by
    refine Step3.apply (v := v) (s := ŝ) (ev := ev) (vnew := vnew)
      ?_ hĉv ?_ ?_ (rel.ver_none h_vnew) h_rank _ rfl ?_ ?_ rfl ?_ ?_
    · rw [rel.head_eq]; exact h_head
    · intro e' he'
      rw [rel.events_eq] at he'
      exact h_fresh_t e' he'
    · intro w sw Ew hw
      obtain ⟨sw', hCw⟩ := rel.ver_some' hw
      exact h_fresh_store w sw' Ew hCw
    · show C'.L = updateRep Ĉ.L r (ev ∪ {(t, r, o)})
      rw [hL, rel.L_eq]
    · show C'.vis = fun a b => Ĉ.vis a b ∨ (ev a ∧ b = (t, r, o))
      rw [hvis, rel.vis_eq]
    · show C'.head = fun r' => if r' = r then some vnew else Ĉ.head r'
      rw [hhead, rel.head_eq]
    · show C'.parents = fun w => if w = vnew then [v] else Ĉ.parents w
      rw [hparents, rel.parents_eq]
  have hrel' : ConfigRelS V.R C' Ĉ' := by
    refine ⟨rfl, rfl, rfl, rfl, ?_, ?_, hE, ?_⟩
    · intro r' w hw
      simp only [hhead] at hw
      rw [hver]
      dsimp only
      by_cases hr : r' = r
      · rw [if_pos hr] at hw
        injection hw with hw
        subst hw
        rw [if_pos rfl]
        rfl
      · rw [if_neg hr] at hw
        have hwne : w ≠ vnew := by
          intro h
          have := rel.heads_alloc r' w hw
          rw [h, h_vnew] at this
          cases this
        rw [if_neg hwne]
        exact rel.heads_alloc r' w hw
    · intro r' hw
      simp only [hhead] at hw
      by_cases hr : r' = r
      · rw [if_pos hr] at hw
        cases hw
      · rw [if_neg hr] at hw
        rw [hN]
        show updateRep C.N r (D.update s (t, r, o)) r' = none
        unfold updateRep
        rw [if_neg hr]
        exact rel.head_none r' hw
    · intro w sw Ew ŝw Êw hw hŵ
      rw [hver] at hw
      dsimp only at hw
      by_cases hwn : w = vnew
      · rw [if_pos hwn] at hw
        have hŵ' : (if w = vnew
            then some (D.update ŝ (t, r, o), ev ∪ {(t, r, o)})
            else Ĉ.ver w) = some (ŝw, Êw) := hŵ
        rw [if_pos hwn] at hŵ'
        injection hw with hw
        injection hŵ' with hŵ'
        have h1 : sw = D.update s (t, r, o) := (congrArg Prod.fst hw).symm
        have h2 : ŝw = D.update ŝ (t, r, o) := (congrArg Prod.fst hŵ').symm
        rw [h1, h2]
        exact hR'
      · rw [if_neg hwn] at hw
        have hŵ' : (if w = vnew
            then some (D.update ŝ (t, r, o), ev ∪ {(t, r, o)})
            else Ĉ.ver w) = some (ŝw, Êw) := hŵ
        rw [if_neg hwn] at hŵ'
        exact rel.ver_rel w sw Ew ŝw Êw hw hŵ'
  exact ⟨Ĉ', hstep', hrel', V.aux_apply rel aux
    (Step3.apply h_head h_ver h_fresh_t h_fresh_store h_vnew h_rank C'
      hN hL hvis hver hhead hparents)
    hstep' hrel'⟩

/-- Merge is matched verbatim: same heads, same LCA version, same fresh slot;
the merged payloads are related by **VC-S4** (`vc_merge`), which fires exactly
at the reachable-pair premises threaded here. -/
theorem stability_match_merge {C Ĉ C' : Configuration D} {r₁ r₂ : Replica}
    (rel : ConfigRelS V.R C Ĉ) (aux : V.Aux C Ĉ)
    (hstep : Step3 D C (.merge r₁ r₂) C') :
    ∃ Ĉ', Step3 D Ĉ (.merge r₁ r₂) Ĉ' ∧
      ConfigRelS V.R C' Ĉ' ∧ V.Aux C' Ĉ' := by
  cases hstep with
  | @merge _ _ v₁ v₂ vT vm s₁ s₂ sT ev₁ ev₂ evT h_head₁ h_head₂ h_ver₁
      h_ver₂ h_lca h_verT h_vm h_rank₁ h_rank₂ C' hN hL hvis hver hhead
      hparents =>
  obtain ⟨ŝ₁, hĉ₁, hR₁⟩ := rel.ver_some h_ver₁
  obtain ⟨ŝ₂, hĉ₂, hR₂⟩ := rel.ver_some h_ver₂
  obtain ⟨ŝT, hĉT, hRT⟩ := rel.ver_some h_verT
  have hRm : V.R (D.mergeL sT s₁ s₂) (D.mergeL ŝT ŝ₁ ŝ₂) :=
    V.vc_merge rel aux h_head₁ h_head₂ h_ver₁ h_ver₂ h_lca h_verT hĉ₁ hĉ₂ hĉT
  have h0ne : (0 : Version) ≠ vm := by
    intro h
    rw [← h] at h_vm
    rw [C.ver_init] at h_vm
    cases h_vm
  have hE : ∀ w,
      ((fun w => if w = vm then some (D.mergeL ŝT ŝ₁ ŝ₂, ev₁ ∪ ev₂)
        else Ĉ.ver w) w).map Prod.snd = (C'.ver w).map Prod.snd := by
    intro w
    rw [hver]
    dsimp only
    by_cases hw : w = vm
    · rw [if_pos hw, if_pos hw]
      rfl
    · rw [if_neg hw, if_neg hw]
      exact rel.ver_events w
  have h0 : (fun w => if w = vm then some (D.mergeL ŝT ŝ₁ ŝ₂, ev₁ ∪ ev₂)
      else Ĉ.ver w) 0 = some (D.init, ∅) := by
    dsimp only
    rw [if_neg h0ne]
    exact Ĉ.ver_init
  have hInvV : ∀ w sw ew, (fun w => if w = vm
      then some (D.mergeL ŝT ŝ₁ ŝ₂, ev₁ ∪ ev₂)
      else Ĉ.ver w) w = some (sw, ew) → D.Inv sw := by
    intro w sw ew hw
    dsimp only at hw
    by_cases hwn : w = vm
    · rw [if_pos hwn] at hw
      injection hw with hw
      have hsw : sw = D.mergeL ŝT ŝ₁ ŝ₂ := (congrArg Prod.fst hw).symm
      rw [hsw]
      refine V.vc_inv hRm (C'.ver_inv vm (D.mergeL sT s₁ s₂) (ev₁ ∪ ev₂) ?_)
      rw [hver]
      simp
    · rw [if_neg hwn] at hw
      exact Ĉ.ver_inv w sw ew hw
  have hNd : ∀ r', updateRep Ĉ.N r₁ (D.mergeL ŝT ŝ₁ ŝ₂) r' = none ↔
      C'.N r' = none := by
    intro r'
    rw [hN]
    unfold updateRep
    by_cases hr : r' = r₁
    · rw [if_pos hr, if_pos hr]
      simp
    · rw [if_neg hr, if_neg hr]
      exact rel.N_none_iff r'
  have hcoh : ∀ r' w, C'.head r' = some w →
      ((fun w => if w = vm then some (D.mergeL ŝT ŝ₁ ŝ₂, ev₁ ∪ ev₂)
        else Ĉ.ver w) w).map Prod.fst
        = updateRep Ĉ.N r₁ (D.mergeL ŝT ŝ₁ ŝ₂) r' := by
    intro r' w hw
    simp only [hhead] at hw
    dsimp only
    unfold updateRep
    by_cases hr : r' = r₁
    · rw [if_pos hr] at hw ⊢
      injection hw with hw
      subst hw
      rw [if_pos rfl]
      rfl
    · rw [if_neg hr] at hw ⊢
      have hwne : w ≠ vm := by
        intro h
        have := rel.heads_alloc r' w hw
        rw [h, h_vm] at this
        cases this
      rw [if_neg hwne]
      have hĥ : Ĉ.head r' = some w := by rw [rel.head_eq]; exact hw
      exact (Ĉ.head_coherent r' w hĥ).1
  let Ĉ' : Configuration D :=
    restate C' (updateRep Ĉ.N r₁ (D.mergeL ŝT ŝ₁ ŝ₂))
      (fun w => if w = vm then some (D.mergeL ŝT ŝ₁ ŝ₂, ev₁ ∪ ev₂)
        else Ĉ.ver w) hE h0 hInvV hNd hcoh
  have hstep' : Step3 D Ĉ (.merge r₁ r₂) Ĉ' := by
    refine Step3.merge (v₁ := v₁) (v₂ := v₂) (vT := vT) (vm := vm)
      ?_ ?_ hĉ₁ hĉ₂ ?_ hĉT (rel.ver_none h_vm) h_rank₁ h_rank₂ _
      rfl ?_ ?_ rfl ?_ ?_
    · rw [rel.head_eq]; exact h_head₁
    · rw [rel.head_eq]; exact h_head₂
    · rw [rel.parents_eq]; exact h_lca
    · show C'.L = updateRep Ĉ.L r₁ (ev₁ ∪ ev₂)
      rw [hL, rel.L_eq]
    · show C'.vis = Ĉ.vis
      rw [hvis, rel.vis_eq]
    · show C'.head = fun r' => if r' = r₁ then some vm else Ĉ.head r'
      rw [hhead, rel.head_eq]
    · show C'.parents = fun w => if w = vm then [v₁, v₂] else Ĉ.parents w
      rw [hparents, rel.parents_eq]
  have hrel' : ConfigRelS V.R C' Ĉ' := by
    refine ⟨rfl, rfl, rfl, rfl, ?_, ?_, hE, ?_⟩
    · intro r' w hw
      simp only [hhead] at hw
      rw [hver]
      dsimp only
      by_cases hr : r' = r₁
      · rw [if_pos hr] at hw
        injection hw with hw
        subst hw
        rw [if_pos rfl]
        rfl
      · rw [if_neg hr] at hw
        have hwne : w ≠ vm := by
          intro h
          have := rel.heads_alloc r' w hw
          rw [h, h_vm] at this
          cases this
        rw [if_neg hwne]
        exact rel.heads_alloc r' w hw
    · intro r' hw
      simp only [hhead] at hw
      by_cases hr : r' = r₁
      · rw [if_pos hr] at hw
        cases hw
      · rw [if_neg hr] at hw
        rw [hN]
        show updateRep C.N r₁ (D.mergeL sT s₁ s₂) r' = none
        unfold updateRep
        rw [if_neg hr]
        exact rel.head_none r' hw
    · intro w sw Ew ŝw Êw hw hŵ
      rw [hver] at hw
      dsimp only at hw
      by_cases hwn : w = vm
      · rw [if_pos hwn] at hw
        have hŵ' : (if w = vm then some (D.mergeL ŝT ŝ₁ ŝ₂, ev₁ ∪ ev₂)
            else Ĉ.ver w) = some (ŝw, Êw) := hŵ
        rw [if_pos hwn] at hŵ'
        injection hw with hw
        injection hŵ' with hŵ'
        have h1 : sw = D.mergeL sT s₁ s₂ := (congrArg Prod.fst hw).symm
        have h2 : ŝw = D.mergeL ŝT ŝ₁ ŝ₂ := (congrArg Prod.fst hŵ').symm
        rw [h1, h2]
        exact hRm
      · rw [if_neg hwn] at hw
        have hŵ' : (if w = vm then some (D.mergeL ŝT ŝ₁ ŝ₂, ev₁ ∪ ev₂)
            else Ĉ.ver w) = some (ŝw, Êw) := hŵ
        rw [if_neg hwn] at hŵ'
        exact rel.ver_rel w sw Ew ŝw Êw hw hŵ'
  exact ⟨Ĉ', hstep', hrel', V.aux_merge rel aux
    (Step3.merge h_head₁ h_head₂ h_ver₁ h_ver₂ h_lca h_verT h_vm h_rank₁
      h_rank₂ C' hN hL hvis hver hhead hparents)
    hstep' hrel'⟩

/-- Query is matched by the compacted side's own readback; configurations are
unchanged on both sides. -/
theorem stability_match_query {C Ĉ : Configuration D} {r : Replica}
    {q : D.Query} {val : D.Value}
    (rel : ConfigRelS V.R C Ĉ) (_aux : V.Aux C Ĉ)
    (hstep : Step3 D C (.query r q val) C) :
    ∃ val', Step3 D Ĉ (.query r q val') Ĉ := by
  cases hstep with
  | @query _ _ _ s h_s h_val =>
    obtain ⟨ŝ, hNc, hR⟩ := rel.N_some h_s
    exact ⟨D.query ŝ q, Step3.query hNc rfl⟩

/-! ## §4 Compaction is a stuttering step -/

/-- `IsLCA` is reflexive: the merge rule accepts `r₁ = r₂`, which is what lets
the full side *stutter* through a genuine `Step3.merge r r` while the
compacted side installs the callback's result. -/
theorem isLCA_self (parents : Version → List Version) (v : Version) :
    IsLCA parents v v v :=
  ⟨Relation.ReflTransGen.refl, Relation.ReflTransGen.refl, fun _ h₁ _ => h₁⟩

/-- The full-side stuttering target: a self-merge at `r`'s head `v`, allocated
at the fresh slot `vm`. The causal core is untouched: the merged event set is
`E ∪ E = E`, so `L` is even pointwise unchanged. -/
def selfMergeCfg (C : Configuration D) (r : Replica) (v vm : Version)
    (s : D.State) (E : Set (Op D.AppOp))
    (h_head : C.head r = some v) (h_ver : C.ver v = some (s, E))
    (h_vm : C.ver vm = none) (h_rank : v < vm)
    (hInvM : D.Inv (D.mergeL s s s))
    (hStore : StoreInv C.ver C.parents)
    (hHA : ∀ r' w, C.head r' = some w → (C.ver w).isSome) :
    Configuration D where
  N := updateRep C.N r (D.mergeL s s s)
  L := C.L
  vis := C.vis
  dom_eq := by
    intro r'
    have hL_r : C.L r = some E := by
      have h2 := (C.head_coherent r v h_head).2
      rw [h_ver] at h2
      exact h2.symm
    unfold updateRep
    by_cases hr : r' = r
    · rw [if_pos hr, hr, hL_r]
      simp
    · rw [if_neg hr]
      exact C.dom_eq r'
  vis_src := C.vis_src
  vis_tgt := C.vis_tgt
  vis_causal := C.vis_causal
  timestamps_distinct := C.timestamps_distinct
  causal_mono := C.causal_mono
  vis_total_same_replica := C.vis_total_same_replica
  ver := fun w => if w = vm then some (D.mergeL s s s, E) else C.ver w
  head := fun r' => if r' = r then some vm else C.head r'
  parents := fun w => if w = vm then [v, v] else C.parents w
  parents_lt := by
    intro w p hp
    by_cases hw : w = vm
    · rw [if_pos hw] at hp
      subst hw
      have hpv : p = v := by
        rcases List.mem_cons.mp hp with h | h
        · exact h
        · exact List.mem_singleton.mp h
      rw [hpv]
      exact h_rank
    · rw [if_neg hw] at hp
      exact C.parents_lt w p hp
  ver_init := by
    have h0ne : (0 : Version) ≠ vm := by
      intro h
      rw [← h] at h_vm
      rw [C.ver_init] at h_vm
      cases h_vm
    rw [if_neg h0ne]
    exact C.ver_init
  head_coherent := by
    intro r' w hw
    unfold updateRep
    by_cases hr : r' = r
    · rw [if_pos hr] at hw ⊢
      injection hw with hw
      subst hw
      rw [if_pos rfl]
      have hL_r : C.L r = some E := by
        have h2 := (C.head_coherent r v h_head).2
        rw [h_ver] at h2
        exact h2.symm
      rw [hr, hL_r]
      exact ⟨rfl, rfl⟩
    · rw [if_neg hr] at hw ⊢
      have hwne : w ≠ vm := by
        intro h
        have := hHA r' w hw
        rw [h, h_vm] at this
        cases this
      rw [if_neg hwne]
      exact C.head_coherent r' w hw
  ver_inv := by
    intro w sw ew hw
    by_cases hwn : w = vm
    · rw [if_pos hwn] at hw
      injection hw with hw
      have hsw : sw = D.mergeL s s s := (congrArg Prod.fst hw).symm
      rw [hsw]
      exact hInvM
    · rw [if_neg hwn] at hw
      exact C.ver_inv w sw ew hw
  lca_events := by
    intro w₁ w₂ wT t₁ F₁ t₂ F₂ tT FT hlca h1 h2 hT
    exact merged_store_lca_events
      (ver' := fun w => if w = vm then some (D.mergeL s s s, E) else C.ver w)
      (parents' := fun w => if w = vm then [v, v] else C.parents w)
      (sm := D.mergeL s s s)
      hStore h_vm h_ver h_ver
      (by simp)
      (fun w hw => by simp [hw])
      (by simp)
      (fun w hw => by simp [hw])
      hlca h1 h2 hT

/-- **The compaction diamond**: under the gate, the full side takes
the stuttering self-merge and the compacted side installs `compact ŝ` at the
same fresh slot; the lifted relation and the instance invariant survive. The
compacted side's move is the GC callback itself, deliberately *not* a `Step3`
step. -/
theorem stability_compact {C Ĉ : Configuration D} {r : Replica}
    {v vm : Version} {s ŝ : D.State} {E : Set (Op D.AppOp)}
    (rel : ConfigRelS V.R C Ĉ) (aux : V.Aux C Ĉ)
    (hgate : V.gate C Ĉ r v)
    (h_head : C.head r = some v) (h_ver : C.ver v = some (s, E))
    (hĉv : Ĉ.ver v = some (ŝ, E))
    (h_vm : C.ver vm = none) (h_rank : v < vm)
    (hInvM : D.Inv (D.mergeL s s s))
    (hStore : StoreInv C.ver C.parents) :
    ∃ C' Ĉ', Step3 D C (.merge r r) C' ∧
      C'.ver = (fun w => if w = vm then some (D.mergeL s s s, E ∪ E)
        else C.ver w) ∧
      Ĉ'.ver = (fun w => if w = vm then some (V.compact ŝ, E ∪ E)
        else Ĉ.ver w) ∧
      ConfigRelS V.R C' Ĉ' ∧ V.Aux C' Ĉ' := by
  have hL_r : C.L r = some E := by
    have h2 := (C.head_coherent r v h_head).2
    rw [h_ver] at h2
    exact h2.symm
  have h0ne : (0 : Version) ≠ vm := by
    intro h
    rw [← h] at h_vm
    rw [C.ver_init] at h_vm
    cases h_vm
  have hcpt : V.R (D.mergeL s s s) (V.compact ŝ) :=
    V.vc_entry rel aux hgate h_head h_ver hĉv
  let C' : Configuration D :=
    selfMergeCfg C r v vm s E h_head h_ver h_vm h_rank hInvM hStore
      rel.heads_alloc
  have hE : ∀ w,
      ((fun w => if w = vm then some (V.compact ŝ, E) else Ĉ.ver w) w).map
        Prod.snd = (C'.ver w).map Prod.snd := by
    intro w
    show _ = ((fun w => if w = vm then some (D.mergeL s s s, E)
      else C.ver w) w).map Prod.snd
    dsimp only
    by_cases hw : w = vm
    · rw [if_pos hw, if_pos hw]
      rfl
    · rw [if_neg hw, if_neg hw]
      exact rel.ver_events w
  have h0 : (fun w => if w = vm then some (V.compact ŝ, E) else Ĉ.ver w) 0
      = some (D.init, ∅) := by
    dsimp only
    rw [if_neg h0ne]
    exact Ĉ.ver_init
  have hInvV : ∀ w sw ew,
      (fun w => if w = vm then some (V.compact ŝ, E) else Ĉ.ver w) w
        = some (sw, ew) → D.Inv sw := by
    intro w sw ew hw
    dsimp only at hw
    by_cases hwn : w = vm
    · rw [if_pos hwn] at hw
      injection hw with hw
      have hsw : sw = V.compact ŝ := (congrArg Prod.fst hw).symm
      rw [hsw]
      exact V.vc_inv hcpt hInvM
    · rw [if_neg hwn] at hw
      exact Ĉ.ver_inv w sw ew hw
  have hNd : ∀ r', updateRep Ĉ.N r (V.compact ŝ) r' = none ↔
      C'.N r' = none := by
    intro r'
    show _ ↔ updateRep C.N r (D.mergeL s s s) r' = none
    unfold updateRep
    by_cases hr : r' = r
    · rw [if_pos hr, if_pos hr]
      simp
    · rw [if_neg hr, if_neg hr]
      exact rel.N_none_iff r'
  have hcoh : ∀ r' w, C'.head r' = some w →
      ((fun w => if w = vm then some (V.compact ŝ, E) else Ĉ.ver w) w).map
        Prod.fst = updateRep Ĉ.N r (V.compact ŝ) r' := by
    intro r' w hw
    have hw' : (if r' = r then some vm else C.head r') = some w := hw
    dsimp only
    unfold updateRep
    by_cases hr : r' = r
    · rw [if_pos hr] at hw' ⊢
      injection hw' with hw'
      subst hw'
      rw [if_pos rfl]
      rfl
    · rw [if_neg hr] at hw' ⊢
      have hwne : w ≠ vm := by
        intro h
        have := rel.heads_alloc r' w hw'
        rw [h, h_vm] at this
        cases this
      rw [if_neg hwne]
      have hĥ : Ĉ.head r' = some w := by rw [rel.head_eq]; exact hw'
      exact (Ĉ.head_coherent r' w hĥ).1
  let Ĉ' : Configuration D :=
    restate C' (updateRep Ĉ.N r (V.compact ŝ))
      (fun w => if w = vm then some (V.compact ŝ, E) else Ĉ.ver w)
      hE h0 hInvV hNd hcoh
  have hverC' : C'.ver = (fun w => if w = vm
      then some (D.mergeL s s s, E ∪ E) else C.ver w) := by
    funext w
    show (if w = vm then some (D.mergeL s s s, E) else C.ver w) = _
    by_cases hw : w = vm
    · rw [if_pos hw, if_pos hw, Set.union_self]
    · rw [if_neg hw, if_neg hw]
  have hverĈ' : Ĉ'.ver = (fun w => if w = vm
      then some (V.compact ŝ, E ∪ E) else Ĉ.ver w) := by
    funext w
    show (if w = vm then some (V.compact ŝ, E) else Ĉ.ver w) = _
    by_cases hw : w = vm
    · rw [if_pos hw, if_pos hw, Set.union_self]
    · rw [if_neg hw, if_neg hw]
  have hLeq : C'.L = updateRep C.L r (E ∪ E) := by
    show C.L = updateRep C.L r (E ∪ E)
    funext r'
    unfold updateRep
    by_cases hr : r' = r
    · rw [if_pos hr, hr, hL_r, Set.union_self]
    · rw [if_neg hr]
  have hstepC : Step3 D C (.merge r r) C' :=
    Step3.merge h_head h_head h_ver h_ver (isLCA_self C.parents v)
      h_ver h_vm h_rank h_rank C' rfl hLeq rfl hverC' rfl rfl
  have hrel' : ConfigRelS V.R C' Ĉ' := by
    refine ⟨rfl, rfl, rfl, rfl, ?_, ?_, hE, ?_⟩
    · intro r' w hw
      have hw' : (if r' = r then some vm else C.head r') = some w := hw
      show ((fun w => if w = vm then some (D.mergeL s s s, E)
        else C.ver w) w).isSome
      dsimp only
      by_cases hr : r' = r
      · rw [if_pos hr] at hw'
        injection hw' with hw'
        subst hw'
        rw [if_pos rfl]
        rfl
      · rw [if_neg hr] at hw'
        have hwne : w ≠ vm := by
          intro h
          have := rel.heads_alloc r' w hw'
          rw [h, h_vm] at this
          cases this
        rw [if_neg hwne]
        exact rel.heads_alloc r' w hw'
    · intro r' hw
      have hw' : (if r' = r then some vm else C.head r') = none := hw
      show updateRep C.N r (D.mergeL s s s) r' = none
      unfold updateRep
      by_cases hr : r' = r
      · rw [if_pos hr] at hw'
        cases hw'
      · rw [if_neg hr] at hw' ⊢
        exact rel.head_none r' hw'
    · intro w sw Ew ŝw Êw hw hŵ
      have hw' : (if w = vm then some (D.mergeL s s s, E) else C.ver w)
          = some (sw, Ew) := hw
      have hŵ' : (if w = vm then some (V.compact ŝ, E) else Ĉ.ver w)
          = some (ŝw, Êw) := hŵ
      by_cases hwn : w = vm
      · rw [if_pos hwn] at hw' hŵ'
        injection hw' with hw'
        injection hŵ' with hŵ'
        have h1 : sw = D.mergeL s s s := (congrArg Prod.fst hw').symm
        have h2 : ŝw = V.compact ŝ := (congrArg Prod.fst hŵ').symm
        rw [h1, h2]
        exact hcpt
      · rw [if_neg hwn] at hw' hŵ'
        exact rel.ver_rel w sw Ew ŝw Êw hw' hŵ'
  have haux' : V.Aux C' Ĉ' :=
    V.aux_compact rel aux hgate h_head h_ver hĉv h_vm h_rank hstepC
      hverC' rfl hLeq rfl rfl rfl rfl rfl rfl rfl hverĈ' hrel'
  exact ⟨C', Ĉ', hstepC, hverC', hverĈ', hrel', haux'⟩

/-- **The umbrella matching lemma**: every full `Step3` step is matched by a
compacted step with a `LabelSim`-related label, preserving relation and
invariant. Creates are gated by the bundle's `canCreate` policy (scope note 2:
open membership). -/
theorem stability_match {C Ĉ C' : Configuration D} {ℓ : Label3 D}
    (rel : ConfigRelS V.R C Ĉ) (aux : V.Aux C Ĉ)
    (hcc : ∀ r, ℓ = .createReplica r → V.canCreate C Ĉ r)
    (hstep : Step3 D C ℓ C') :
    ∃ Ĉ' ℓ', Step3 D Ĉ ℓ' Ĉ' ∧ LabelSim D ℓ ℓ' ∧
      ConfigRelS V.R C' Ĉ' ∧ V.Aux C' Ĉ' := by
  cases ℓ with
  | createReplica r =>
    obtain ⟨Ĉ', h1, h2, h3⟩ :=
      stability_match_create V rel aux (hcc r rfl) hstep
    exact ⟨Ĉ', _, h1, LabelSim.create r, h2, h3⟩
  | apply t r o =>
    obtain ⟨Ĉ', h1, h2, h3⟩ := stability_match_apply V rel aux hstep
    exact ⟨Ĉ', _, h1, LabelSim.apply t r o, h2, h3⟩
  | merge r₁ r₂ =>
    obtain ⟨Ĉ', h1, h2, h3⟩ := stability_match_merge V rel aux hstep
    exact ⟨Ĉ', _, h1, LabelSim.merge r₁ r₂, h2, h3⟩
  | query r q val =>
    have hC' : C' = C := by cases hstep; rfl
    subst hC'
    obtain ⟨val', h1⟩ := stability_match_query V rel aux hstep
    exact ⟨Ĉ, _, h1, LabelSim.query r q val val', rel, aux⟩

/-! ## §5 The paired run and the metatheorem -/

/-- **The paired (twin) run**: the full run on the left, the compacted run on
the right. `step` records a matched `Step3` pair (produced by
`stability_match`); `compact` records a gated compaction, the full side's
stuttering self-merge (a genuine `Step3`, so the left projection of a
`StabReach` trace is an ordinary reachable run) against the compacted side's
callback move (produced by `stability_compact`). -/
inductive StabReach (V : StabilityVC D) (hInit : D.Inv D.init) :
    Configuration D → Configuration D → Prop where
  | init : StabReach V hInit (initConfig D hInit) (initConfig D hInit)
  | step {C Ĉ C' Ĉ' : Configuration D} {ℓ ℓ' : Label3 D} :
      StabReach V hInit C Ĉ → Step3 D C ℓ C' → Step3 D Ĉ ℓ' Ĉ' →
      LabelSim D ℓ ℓ' → ConfigRelS V.R C' Ĉ' → V.Aux C' Ĉ' →
      StabReach V hInit C' Ĉ'
  | compact {C Ĉ C' Ĉ' : Configuration D} {r : Replica} :
      StabReach V hInit C Ĉ → Step3 D C (.merge r r) C' →
      ConfigRelS V.R C' Ĉ' → V.Aux C' Ĉ' →
      StabReach V hInit C' Ĉ'

open LabeledTS in
/-- **The stability metatheorem**: along every paired run, the
lifted relation and the instance invariant hold, and the full side is an
ordinary `Step3`-reachable configuration (compactions project to stuttering
self-merges). With `stability_match` / `stability_compact` supplying the
inductive steps, every version of every reachable pair reads identically
(`stability_reads_equal`) and the compacted run inherits RA-linearizability
observationally (`stability_ra_inherited`). -/
theorem stability_simulation {V : StabilityVC D} {hInit : D.Inv D.init}
    {C Ĉ : Configuration D} (h : StabReach V hInit C Ĉ) :
    ConfigRelS V.R C Ĉ ∧ V.Aux C Ĉ ∧
      (labeledTS3 D).ReachableFrom (initConfig D hInit) C := by
  induction h with
  | init =>
    exact ⟨relS_init V.vc_refl hInit, V.aux_init hInit,
      Relation.ReflTransGen.refl⟩
  | @step C Ĉ C' Ĉ' ℓ ℓ' _ hstep hstep' hsim hrel haux ih =>
    exact ⟨hrel, haux, Relation.ReflTransGen.tail ih.2.2 ⟨ℓ, hstep⟩⟩
  | @compact C Ĉ C' Ĉ' r _ hstep hrel haux ih =>
    exact ⟨hrel, haux, Relation.ReflTransGen.tail ih.2.2 ⟨_, hstep⟩⟩

/-- **Reads equal at every version**: a version allocated on the
compacted side carries the full side's event set verbatim and reads
identically through the datatype's read interface. -/
theorem stability_reads_equal {V : StabilityVC D} {hInit : D.Inv D.init}
    {C Ĉ : Configuration D} (h : StabReach V hInit C Ĉ)
    {v : Version} {s ŝ : D.State} {E Ê : Set (Op D.AppOp)}
    (hv : C.ver v = some (s, E)) (hvc : Ĉ.ver v = some (ŝ, Ê)) :
    Ê = E ∧ V.obs ŝ = V.obs s := by
  obtain ⟨rel, -, -⟩ := stability_simulation h
  obtain ⟨ŝ', hĉ, hR⟩ := rel.ver_some hv
  rw [hvc] at hĉ
  injection hĉ with hĉ
  have h1 : ŝ = ŝ' := congrArg Prod.fst hĉ
  have h2 : Ê = E := congrArg Prod.snd hĉ
  subst h1
  exact ⟨h2, (V.vc_obs hR).symm⟩

/-- Replica readback agrees observationally (the query-label guarantee). -/
theorem reads_replica_equal {V : StabilityVC D} {hInit : D.Inv D.init}
    {C Ĉ : Configuration D} (h : StabReach V hInit C Ĉ)
    {r : Replica} {s ŝ : D.State}
    (hN : C.N r = some s) (hNc2 : Ĉ.N r = some ŝ) :
    V.obs ŝ = V.obs s := by
  obtain ⟨rel, -, -⟩ := stability_simulation h
  obtain ⟨ŝ', hĉ, hR⟩ := rel.N_some hN
  rw [hNc2] at hĉ
  injection hĉ with hĉ
  subst hĉ
  exact (V.vc_obs hR).symm

/-- **RA-linearizability inherited observationally**: every version
of the compacted run has a permutation witness of its (shared) event set,
respecting the linearization order of the compacted run's own causal core,
whose fold reads exactly as the compacted state, transported from the full
side's per-version RA-linearizability. -/
theorem stability_ra_inherited {V : StabilityVC D} {hInit : D.Inv D.init}
    {C Ĉ : Configuration D} (h : StabReach V hInit C Ĉ)
    (hRA : IsRALinearizable3 C) :
    ∀ (v : Version) (ŝ : D.State) (Ê : Set (Op D.AppOp)),
      Ĉ.ver v = some (ŝ, Ê) →
      ∃ π : List (Op D.AppOp),
        listPermOf π Ê ∧
        respects π (Sal.Emulation.lo (Configuration.core Ĉ)) ∧
        V.obs (applySeq D.toCRDTSig D.init π) = V.obs ŝ := by
  obtain ⟨rel, -, -⟩ := stability_simulation h
  intro v ŝ Ê hvc
  obtain ⟨s, hv⟩ := rel.ver_some' hvc
  obtain ⟨π, hperm, hresp, happ⟩ := hRA v s Ê hv
  have hlo : Sal.Emulation.lo (Configuration.core Ĉ)
      = Sal.Emulation.lo (Configuration.core C) := by
    funext e₁ e₂
    unfold Sal.Emulation.lo
    rw [core_vis, core_vis, rel.vis_eq]
  have hR : V.R s ŝ := rel.ver_rel v s Ê ŝ Ê hv hvc
  refine ⟨π, hperm, ?_, ?_⟩
  · rw [hlo]
    exact hresp
  · rw [happ]
    exact V.vc_obs hR

end Matching

/-! ## Axiom audit (framework layer) -/

#print axioms settledAtOn_of_evidence
#print axioms settledAt_of_evidence_reachableV
#print axioms evidenceCommit_of_witness_good
#print axioms stability_match
#print axioms stability_compact
#print axioms stability_simulation
#print axioms stability_reads_equal
#print axioms stability_ra_inherited

end Sal.ConditionedMRDTs
