import Sal.ConditionedMRDTs.MRDT_Instances.EmbedRGA.EmbedRGA_Recoding
import Sal.MRDTs.RGA_Embed.RunTable

/-!
# The run table at the instance: display identity, T-epoch, SPOTs

The kernel theory (`Sal/MRDTs/RGA_Embed/RunTable.lean`: T-tail, T-repr,
T-cmp, T-walk, T-mut) is state-level and hypothesis-free. This file:

* **display identity** (`runTable_display_identity`): the table walk over a
  version's birth chains reproduces the canonical document's coordinate
  sequence exactly, `whiteboard/run-table-note.md` §8's walk-order gate as
  a theorem;
* **T-epoch** (`runTable_epoch`): composition with the re-coding cluster.
  This is the ONLY theorem in the whole run-table stack that carries a
  settled-cut hypothesis (the `StablePrefixMap` bundle + `Dom` coverage it
  inherits from the epoch map it composes with). Its absence everywhere
  else (T-tail, T-repr, T-cmp, T-walk, T-mut are unconditioned) is the
  formal content of the **no-stability-gate** property: the run table
  exists for every state, unsettled suffixes included;
* **SPOTs** (PASS + FAIL, hand-derived, matching the Python's directed
  cases): the typing table with `(run-id, offset)` addresses, D1's mid-run
  split with the no-split rival pinned to the wrong display
  (`abcdefX`-shaped), D2's liveness split, D4's coalesce necessity (the
  drifted two-entry table re-canonicalizes to ONE entry), D5's
  vanished-anchor materialization, and the comparator against `keyLt`.
-/

namespace Sal.ConditionedMRDTs

open Sal.Emulation
open Sal.EmbedRGA (OrderedPrefixCode keyLt keyLe key unaryCode coordOf
  PosChain keyLt_total keyLt_irrefl keyLt_asymm key_inj)
open Sal.EmbedRGA.RunTable

set_option linter.unusedSectionVars false

variable {α : Type} [DecidableEq α] [Inhabited α]

/-! ## §1  The chain representation of a document -/

/-- The version's records carry exactly the coordinates of a positive,
nonempty birth-chain list (what `EHonestCore.chain_gen` supplies, record for
record, in document order). -/
def ChainRep (Γ : OrderedPrefixCode) (s : EState α)
    (Lc : List (List ℕ)) : Prop :=
  s.map (fun r => r.2.2) = Lc.map (coordOf Γ)
  ∧ (∀ c ∈ Lc, PosChain c) ∧ ([] : List ℕ) ∉ Lc

/-- Strictly `keyLt`-descending coordinate lists with the same members are
equal (the `esorted_ext` argument, at the coordinate level). -/
theorem keyLt_sorted_ext : ∀ {l l' : List (List Bool)},
    l.Pairwise (fun c1 c2 => keyLt (key c2) (key c1) = true) →
    l'.Pairwise (fun c1 c2 => keyLt (key c2) (key c1) = true) →
    (∀ c, c ∈ l ↔ c ∈ l') → l = l'
  | [], [], _, _, _ => rfl
  | [], y :: ys, _, _, hmem =>
      absurd ((hmem y).mpr List.mem_cons_self) (by simp)
  | x :: xs, [], _, _, hmem =>
      absurd ((hmem x).mp List.mem_cons_self) (by simp)
  | x :: xs, y :: ys, hs, hs', hmem => by
      rcases List.pairwise_cons.mp hs with ⟨hx, hxs⟩
      rcases List.pairwise_cons.mp hs' with ⟨hy, hys⟩
      have hxy : x = y := by
        rcases List.mem_cons.mp ((hmem x).mp List.mem_cons_self) with h | h
        · exact h
        · rcases List.mem_cons.mp ((hmem y).mpr List.mem_cons_self)
            with h' | h'
          · exact h'.symm
          · have h1 := hy x h
            have h2 := hx y h'
            rw [keyLt_asymm h1] at h2
            exact Bool.noConfusion h2
      subst hxy
      have htails : ∀ z, z ∈ xs ↔ z ∈ ys := by
        intro z
        constructor
        · intro hz
          rcases List.mem_cons.mp ((hmem z).mp (List.mem_cons_of_mem _ hz))
            with rfl | h
          · exact absurd (hx z hz) (by rw [keyLt_irrefl]; simp)
          · exact h
        · intro hz
          rcases List.mem_cons.mp ((hmem z).mpr (List.mem_cons_of_mem _ hz))
            with rfl | h
          · exact absurd (hy z hz) (by rw [keyLt_irrefl]; simp)
          · exact h
      rw [keyLt_sorted_ext hxs hys htails]

/-! ## §2  Display identity: the walk reproduces the read -/

/-- **T-walk at the instance (walk = query order)**: over any canonical
document with a chain representation, the run-table walk's coordinate
sequence IS the document's coordinate sequence, the display, verbatim, in
order. No honesty, reachability, or stability hypothesis: only sortedness
(the canonical form) and the chain representation itself. -/
theorem runTable_display_identity (Γ : OrderedPrefixCode) (s : EState α)
    (Lc : List (List ℕ)) (hs : ESorted s) (hrep : ChainRep Γ s Lc) :
    (walk Lc).map (coordOf Γ) = s.map (fun r => r.2.2) := by
  obtain ⟨hmap, hpos, hnil⟩ := hrep
  rw [hmap]
  refine keyLt_sorted_ext ?_ ?_ ?_
  · rw [List.pairwise_map]
    exact walk_pairwise_keyLt Γ hpos hnil
  · have h1 : (s.map (fun r => r.2.2)).Pairwise
        (fun c1 c2 => keyLt (key c2) (key c1) = true) := by
      rw [List.pairwise_map]
      exact hs
    rwa [hmap] at h1
  · intro c
    rw [List.mem_map, List.mem_map]
    constructor
    · rintro ⟨x, hx, rfl⟩
      exact ⟨x, (mem_walk hnil).mp hx, rfl⟩
    · rintro ⟨x, hx, rfl⟩
      exact ⟨x, (mem_walk hnil).mpr hx, rfl⟩

/-! ## §3  T-epoch: composition with the re-coding cluster

The **only** settled-cut hypothesis in the run-table stack lives here: `F`
is a stable-prefix map (H2 = `ord`, H3 = `ext`) and `hdom` says the state at
rest is covered by the cut, exactly the contract `eRecode_*` inherits from
the epoch protocol. Everything else in this development holds at every
state, which is the formal content of the no-stability-gate property (run
table ≈ 21–27 b/ch with NO settled cut, `whiteboard/run-table-note.md` §8). -/

/-- **T-epoch**: after a re-coding epoch, rebuilding the run table over the
re-mapped chains again reproduces the (re-mapped) document verbatim, and the
read is the original read, display identity for the rebuilt table needs no
new order argument beyond H2 (`eRecode_sorted`), and the read identity is
T2 (`eRemapSt_query`). -/
theorem runTable_epoch (Γ : OrderedPrefixCode) (F : StablePrefixMap Γ)
    (s : EState α) (hs : ESorted s) (hdom : ∀ x ∈ s, F.Dom x.2.2)
    (Γ' : OrderedPrefixCode) (Lc' : List (List ℕ))
    (hrep : ChainRep Γ' (eRemapSt F.f s) Lc') :
    (walk Lc').map (coordOf Γ') = (eRemapSt F.f s).map (fun r => r.2.2)
    ∧ (E Γ α).query (eRemapSt F.f s) () = (E Γ α).query s () :=
  ⟨runTable_display_identity Γ' (eRemapSt F.f s) Lc'
      (eRecode_sorted F hs hdom) hrep,
    eRemapSt_query Γ F.f s⟩

/-- T-epoch at a registered version of an honestly reachable configuration:
the version's canonical sortedness is supplied by the recoding cluster
(`eRecode_version_sorted`), so the rebuilt table's walk identity follows for
every version state whose records the cut covers. -/
theorem runTable_epoch_version (Γ : OrderedPrefixCode)
    (F : StablePrefixMap Γ) {C : Configuration (E Γ ℕ)}
    (hReach : EReach Γ C) (hHon : EHonest Γ C)
    {v : Version} {s : EState ℕ}
    {Ev : Set (Op (EOp ℕ))}
    (hv : C.ver v = some (s, Ev))
    (hdom : ∀ x ∈ s, F.Dom x.2.2)
    (Γ' : OrderedPrefixCode) (Lc' : List (List ℕ))
    (hrep : ChainRep Γ' (eRemapSt F.f s) Lc') :
    (walk Lc').map (coordOf Γ') = (eRemapSt F.f s).map (fun r => r.2.2) :=
  runTable_display_identity Γ' (eRemapSt F.f s) Lc'
    (eRecode_version_sorted F hReach hHon hv hdom).2 hrep

/-! ## §4  Axiom audit (theorem layer) -/

#print axioms runTable_display_identity
#print axioms runTable_epoch
#print axioms runTable_epoch_version

/-! ## §5  SPOTs: concrete executions, PASS + FAIL, hand-derived

Chains at the kernel level (one label per keystroke, typing = delta-1
chains); expected tables and walks derived by hand from
`whiteboard/run-table-note.md` §2/§5, never `#eval`'d from the
implementation. The directed shapes match the Python harness's D1–D5. -/

namespace RunTableSPOT

/-- The default entry (out-of-range accessor). -/
def entryAt (T : Table) (j : ℕ) : RTEntry := T.getD j ⟨none, false, 0, 0⟩

/-- Attachments of entry `i`, newest label first, read from the table. -/
def attachedAt (T : Table) (i : ℕ) : List ℕ :=
  ((List.range T.length).filter
    (fun j => (entryAt T j).par.map Prod.fst == some i)).mergeSort
    (fun j k => decide ((entryAt T k).delta ≤ (entryAt T j).delta))

/-- The table-structural walk (Python `table_walk`, one-sided): live
members in offset order, then attachment subtrees newest first, consulting
the TABLE alone. -/
def walkT (T : Table) : ℕ → ℕ → List (List ℕ)
  | 0, _ => []
  | fuel + 1, i =>
      (if (entryAt T i).live
       then (List.range (entryAt T i).len).map
         (fun k => hsAt T i ++ List.replicate k 1)
       else [])
      ++ (attachedAt T i).flatMap (walkT T fuel)

def tableWalk (T : Table) : List (List ℕ) :=
  (((List.range T.length).filter
      (fun j => (entryAt T j).par == none)).mergeSort
    (fun j k => decide ((entryAt T k).delta ≤ (entryAt T j).delta))).flatMap
    (walkT T T.length)

/-- Typing `abcdef`: six keystrokes, each anchored at its predecessor. -/
def L6 : List (List ℕ) :=
  [[1], [1,1], [1,1,1], [1,1,1,1], [1,1,1,1,1], [1,1,1,1,1,1]]

/-- PASS: the typing document compiles to ONE run, six records, one
header, `(run-id, offset)` addresses. -/
theorem spot_typing : tableOf L6 = [⟨none, true, 1, 6⟩] := by native_decide

/-- PASS: the address of the fourth keystroke is `(0, 3)`. -/
theorem spot_typing_address :
    ((headsList L6).idxOf (headOf L6 [1,1,1,1]),
      ([1,1,1,1] : List ℕ).length - (headOf L6 [1,1,1,1]).length)
      = (0, 3) := by native_decide

/-- The same six records as six singleton entries (a member-by-member
delivery without coalesce, the D3 shape). -/
def naive6 : Table :=
  [⟨none, true, 1, 1⟩, ⟨some (0, 0), true, 1, 1⟩, ⟨some (1, 0), true, 1, 1⟩,
   ⟨some (2, 0), true, 1, 1⟩, ⟨some (3, 0), true, 1, 1⟩,
   ⟨some (4, 0), true, 1, 1⟩]

/-- PASS: the naive table denotes exactly the typing state. -/
theorem spot_naive_denotes : stateOf naive6 = L6 := by native_decide

/-- FAIL companion (D3): the naive table is NOT canonical, the rebuild
re-coalesces the six singletons into the single run. -/
theorem spot_naive_drifts :
    tableOf (stateOf naive6) = [⟨none, true, 1, 6⟩]
    ∧ tableOf (stateOf naive6) ≠ naive6 := by native_decide

/-- D1: a concurrent insert `X` (delta 4) after the third keystroke. -/
def L7 : List (List ℕ) := L6 ++ [[1,1,1,4]]

/-- PASS: the run splits into three entries, both children at the tail. -/
theorem spot_d1_split :
    tableOf L7 = [⟨none, true, 1, 3⟩, ⟨some (0, 2), true, 1, 3⟩,
      ⟨some (0, 2), true, 4, 1⟩] := by native_decide

/-- PASS: display = `abcXdef`. -/
theorem spot_d1_walk :
    walk L7 = [[1], [1,1], [1,1,1], [1,1,1,4],
      [1,1,1,1], [1,1,1,1,1], [1,1,1,1,1,1]] := by native_decide

/-- PASS: the table-structural walk agrees with the state walk. -/
theorem spot_d1_tableWalk : tableWalk (tableOf L7) = walk L7 := by
  native_decide

/-- PASS: the GENERIC table-direct walk (`RunTable.tableWalk`, the §7⅞
theorem-bearing definition, proved faithful in `tableWalk_tableOf`) agrees
on the D1 pin too, the SPOT and the generic theorem name the same reading
procedure. -/
theorem spot_d1_tableWalk_generic :
    Sal.EmbedRGA.RunTable.tableWalk (tableOf L7) = walk L7 := by
  native_decide

/-- The no-split rival: `abcdef` kept as ONE run, `X` hung at interior
offset 2, violating tail attachment. -/
def rival : Table := [⟨none, true, 1, 6⟩, ⟨some (0, 2), true, 4, 1⟩]

/-- PASS: the rival denotes the same seven records ... -/
theorem spot_rival_same_state : (stateOf rival).Perm L7 := by native_decide

/-- FAIL companion (the no-split rival pinned to the wrong display): its
structural walk misplaces `X` to the end, the `abcdefX` shape. -/
theorem spot_rival_wrong_display :
    tableWalk rival = [[1], [1,1], [1,1,1], [1,1,1,1], [1,1,1,1,1],
      [1,1,1,1,1,1], [1,1,1,4]]
    ∧ tableWalk rival ≠ walk L7 := by native_decide

/-- FAIL companion: and it is not canonical, the rebuild is the split
table. -/
theorem spot_rival_not_canonical :
    tableOf (stateOf rival) ≠ rival
    ∧ tableOf (stateOf rival) = tableOf L7 := by native_decide

/-- D2: delete the third keystroke, it has kept children, so it stays as
dead STRUCTURE (the liveness split). -/
def Ldel : List (List ℕ) :=
  [[1], [1,1], [1,1,1,1], [1,1,1,1,1], [1,1,1,1,1,1]]

/-- PASS: three entries, live `[a,b]`, dead `[c]` carved out, live
`[d,e,f]`, liveness uniform per entry. -/
theorem spot_d2_liveness_split :
    tableOf Ldel = [⟨none, true, 1, 2⟩, ⟨some (0, 1), false, 1, 1⟩,
      ⟨some (1, 0), true, 1, 3⟩] := by native_decide

/-- PASS + FAIL: display = `abdef`; the dead chain is structure, not text. -/
theorem spot_d2_walk :
    walk Ldel = [[1], [1,1], [1,1,1,1], [1,1,1,1,1], [1,1,1,1,1,1]]
    ∧ [1,1,1] ∉ walk Ldel := by native_decide

/-- D4 (coalesce is the FORCED delete-inverse): the two halves of the
typing run, what deleting a concurrent interloper leaves if the table does
NOT coalesce, denote exactly the typing document, yet the canonical table
re-fuses them: without the coalesce rule the incremental table has drifted
from canonical. This is also the pin for the `no_fuse` hypothesis of
`tableOf_stateOf`: `Tdrift` satisfies every other canonicity clause and
still fails the round trip. -/
def Tdrift : Table := [⟨none, true, 1, 3⟩, ⟨some (0, 2), true, 1, 3⟩]

theorem spot_d4_coalesce_necessity :
    stateOf Tdrift = L6
    ∧ tableOf (stateOf Tdrift) = [⟨none, true, 1, 6⟩]
    ∧ tableOf (stateOf Tdrift) ≠ Tdrift := by native_decide

/-- D5 (vanished-anchor materialization): after `abc` and a childless
delete of `c`, a delivered insert anchored at `c` carries `c`'s coordinate
level; the kept tree re-materializes `c` as a DEAD entry. -/
def Lmat : List (List ℕ) := [[1], [1,1], [1,1,1,1]]

theorem spot_d5_materialize :
    tableOf Lmat = [⟨none, true, 1, 2⟩, ⟨some (0, 1), false, 1, 1⟩,
      ⟨some (1, 0), true, 1, 1⟩] := by native_decide

/-- PASS + FAIL: display = `abX`; the materialized ancestor is dead
structure, and the table has three entries, not two. -/
theorem spot_d5_walk :
    walk Lmat = [[1], [1,1], [1,1,1,1]] ∧ [1,1,1] ∉ walk Lmat
    ∧ (tableOf Lmat).length = 3 := by native_decide

/-- T-cmp concretely: at the D1 divergence the newer label displays first,
in agreement with the coordinate keys under the unary code, both verdict
directions pinned. -/
theorem spot_cmp :
    cmpTable L7 [1,1,1,4] [1,1,1,1] = true
    ∧ cmpTable L7 [1,1,1,1] [1,1,1,4] = false
    ∧ keyLt (key (coordOf unaryCode [1,1,1,1]))
        (key (coordOf unaryCode [1,1,1,4])) = true := by native_decide

#print axioms spot_typing
#print axioms spot_d1_split
#print axioms spot_rival_wrong_display
#print axioms spot_d4_coalesce_necessity
#print axioms spot_d5_materialize
#print axioms spot_cmp

end RunTableSPOT

end Sal.ConditionedMRDTs
