Theory Multitape_Alphabet_Enlargement.AlphabetEnlargement_Reverse

theory AlphabetEnlargement_Reverse
  imports AlphabetEnlargement
begin

text ‹This theory holds the reverse-arm machinery for the
  alphabet_enlarge› simulation chain, together with the
  biconditional language theorem alphabet_enlarge_language›
  --- which closes via that machinery for every well-formed
  M›, with ‹no determinism hypothesis› --- and the
  nondeterministic corollary alphabet_enlarge_nae›.

  Contents, in dependency order:

   Three reverse-arm lifts of the buffered compute:
    m_step_buffered_lift_to_tape_general›,
    m_step_buffered_chain_lift_to_tape›,
    m_steps_buffered_lift_to_tape›.

   ae_step_ss4_ss5_destruct_to_buffered›:
    reverse-arm SS4→›SS5 step destructor.

   The four reverse-arm chain peel lemmas
    ae_backward_stage_load_chain›,
    ae_backward_stage_compute_extract›,
    ae_backward_stage_writeback_chain›, and
    ae_backward_stage_decompose›, and the reverse-arm
    top-level wrapper ae_backward_stage›.

   A chain-uniqueness lemma for
    alphabet_enlarge_delta› derived from the 16
    per-substep functionality lemmas in
    AlphabetEnlargement_Delta›.

   The biconditional language theorem
    alphabet_enlarge_language›, for every well-formed
    M› (no determinism hypothesis).  The forward direction
    delegates to alphabet_enlarge_language_forward› (in
    AlphabetEnlargement›); the reverse direction is proved
    here determinism-free, via the validation-phase uniqueness
    and the window-inversion kernel.

   The nondeterministic corollary
    alphabet_enlarge_nae›: the biconditional and the time
    bound packaged for an arbitrary, possibly nondeterministic,
    well-formed M›.

  The reverse direction does not require det_mttm M›.  The
  natural route would close by chain uniqueness of
  alphabet_enlarge_delta›, which a nondeterministic
  M› does not supply (its compute substep is multi-valued);
  the determinism-bound step is instead discharged by the
  unconditional window-inversion kernel (the det›-free
  SS5→›SS8 subsection below).  The biconditional and the
  corollary alphabet_enlarge_nae› therefore hold for
  nondeterministic M› as well.›


subsection ‹Reverse direction: buffered →› tape lift›

subsubsection ‹Single-step lift to per-tape›

text ‹Per-tape regime-dispatching single-step lift.  Takes the
  per-tape unified ae_window_invariant_general› (with the
  regime selector pos_n :: nat ⇒ nat› that can differ across
  tapes) and produces a substrate-side mttm_step› with the
  per-tape unified invariant preserved on the post-step config.

  The proof factors out the regime-independent structure
  (cM› unpack, δ›-tuple extraction, per-tape
  read-match via read_bp_via_window_general›,
  mttm_step.step› packaging) from the regime-specific
  window-preservation step, which dispatches per tape on
  pos_n k› into ae_window_invariant_step› /
  _le1_step› / _le0_step›.

  The hypothesis bundle for the regime-specific side conditions
  is the same per-regime form as the forward direction's
  ae_m_steps_buffered_correct_trace_general› uses, so
  Step 2b can pass these through directly.›

lemma m_step_buffered_lift_to_tape_general:
  fixes M :: "('q, 'a) mttm"
    and cM :: "('a, 'q) mt_config"
    and q q' :: 'q
    and blocks blocks' ::
          "nat  (('c :: enum  'a) × ('c  'a) × ('c  'a))"
    and pos_bp pos_bp' :: "nat  'c bp"
    and pos_n :: "nat  nat"
  assumes vM:        "valid_mttm M"
      and lu:        "le_unique M"
      and cM_valid:  "valid_config_mttm M cM"
      and step:      "((q, blocks, pos_bp), (q', blocks', pos_bp'))
                          m_step_buffered M"
      and st_eq:     "mt_state cM = q"
      and window:    "k<k_tm M. ae_window_invariant_general
                            (mt_tape cM k) (mt_pos cM k)
                            (pos_bp k) (blocks k) (pos_n k)
                            (le_tm M)"
      and bp_lt:     "k. bp_linear (pos_bp k)
                              < 3 * card (UNIV :: 'c set) - 1"
      and bp_pos:    "k. 0 < bp_linear (pos_bp k)"
      and no_le:     "k<k_tm M. (pos_n k = 0
                               (i. 0 < i
                                           i  card (UNIV :: 'c set)
                                        mt_tape cM k i  le_tm M))
                            (pos_n k = 1
                                 (i. 0 < i
                                             i  2 * card (UNIV :: 'c set)
                                          mt_tape cM k i  le_tm M))
                            (pos_n k  2
                                 mt_tape cM k (mt_pos cM k)  le_tm M)"
  shows "cM'.
            (cM, cM')  mttm_step (delta_tm M)
             mt_state cM' = q'
             (k<k_tm M. ae_window_invariant_general
                      (mt_tape cM' k) (mt_pos cM' k)
                      (pos_bp' k) (blocks' k) (pos_n k) (le_tm M))"
proof -
  obtain ts_pre n_pre where
      cM_eq: "cM = ConfigM q ts_pre n_pre"
  proof -
    obtain q0 ts0 n0 where cM_form: "cM = ConfigM q0 ts0 n0"
      by (cases cM) auto
    from st_eq cM_form have "q0 = q" by simp
    with cM_form show thesis using that by simp
  qed
  have tp_eq: "mt_tape cM = ts_pre" using cM_eq by simp
  have ps_eq: "mt_pos cM = n_pre"   using cM_eq by simp
  from step obtain a a' d where
      delta_mem: "(q, a, q', a', d)  delta_tm M"
    and read_eq:  "k. a k = read_bp (blocks k) (pos_bp k)"
    and write_eq: "k. blocks' k = write_bp (blocks k) (pos_bp k) (a' k)"
    and adv_eq:   "k. bp_advance_le (le_tm M) (a k) (pos_bp k) (d k)
                          = Some (pos_bp' k)"
    unfolding m_step_buffered_def by auto
  have read_match: "k. a k = ts_pre k (n_pre k)"
  proof (intro allI)
    fix k
    show "a k = ts_pre k (n_pre k)"
    proof (cases "k < k_tm M")
      case True
      from window True have wi_k:
          "ae_window_invariant_general (mt_tape cM k) (mt_pos cM k)
              (pos_bp k) (blocks k) (pos_n k) (le_tm M)" by blast
      hence wi_k': "ae_window_invariant_general (ts_pre k) (n_pre k)
                       (pos_bp k) (blocks k) (pos_n k) (le_tm M)"
        using tp_eq ps_eq by simp
      have "read_bp (blocks k) (pos_bp k) = ts_pre k (n_pre k)"
        by (rule read_bp_via_window_general[OF wi_k'])
      thus "a k = ts_pre k (n_pre k)"
        using read_eq by simp
    next
      case False
      hence kge: "k  k_tm M" by simp
      ― ‹Padding tape: no window invariant available; the
          read-match holds because both sides are the substrate
          blank bl_tm M› --- a k› by δ›-support, the actual
          tape read by cM›'s blank-tail.›
      have a_bl: "a k = bl_tm M"
        using valid_mttm_delta_support[OF vM delta_mem kge] by simp
      have ts_bl: "ts_pre k (n_pre k) = bl_tm M"
        using valid_config_mttm_blank_tail[OF cM_valid kge] tp_eq by simp
      show "a k = ts_pre k (n_pre k)" using a_bl ts_bl by simp
    qed
  qed
  have read_match_fun: "(λk. ts_pre k (n_pre k)) = a"
    using read_match by (auto intro!: ext)
  let ?cM' = "ConfigM q' (λk. (ts_pre k)(n_pre k := a' k))
                           (λk. go_dir (d k) (n_pre k))"
  have delta_tuple: "(q, λk. ts_pre k (n_pre k), q', a', d)
                        delta_tm M"
    using delta_mem read_match_fun by simp
  have step_mttm: "(cM, ?cM')  mttm_step (delta_tm M)"
  proof -
    have "(ConfigM q ts_pre n_pre, ?cM')  mttm_step (delta_tm M)"
      by (rule mttm_step.step
            [where ts=ts_pre and n=n_pre and a=a' and dir=d,
             OF delta_tuple])
    thus ?thesis using cM_eq by simp
  qed
  have st_new: "mt_state ?cM' = q'" by simp
  have new_window:
      "k<k_tm M. ae_window_invariant_general
              (mt_tape ?cM' k) (mt_pos ?cM' k)
              (pos_bp' k) (blocks' k) (pos_n k) (le_tm M)"
  proof (intro allI impI)
    fix k assume klt: "k < k_tm M"
    let ?c = "card (UNIV :: 'c set)"
    have tape_k: "mt_tape ?cM' k = (ts_pre k)(n_pre k := a' k)" by simp
    have pos_k:  "mt_pos ?cM' k  = go_dir (d k) (n_pre k)" by simp
    have blocks'_k: "blocks' k = write_bp (blocks k) (pos_bp k) (a' k)"
      using write_eq by blast
    have adv_k_buf: "bp_advance_le (le_tm M) (a k) (pos_bp k) (d k)
                        = Some (pos_bp' k)"
      using adv_eq by blast
    have read_a_k: "a k = ts_pre k (n_pre k)" using read_match by blast
    have adv_k: "bp_advance_le (le_tm M) (ts_pre k (n_pre k))
                    (pos_bp k) (d k) = Some (pos_bp' k)"
      using adv_k_buf read_a_k by simp
    have wi_gen_k: "ae_window_invariant_general
        (ts_pre k) (n_pre k) (pos_bp k) (blocks k) (pos_n k) (le_tm M)"
      using window klt tp_eq ps_eq by simp
    have bp_lt_k:  "bp_linear (pos_bp k) < 3 * ?c - 1" using bp_lt by blast
    have bp_pos_k: "0 < bp_linear (pos_bp k)" using bp_pos by blast
    ― ‹LE-discipline side conditions, derived from
      valid_mttm M›; used in le0› and le1›
      branches.›
    have a_le_k: "ts_pre k (n_pre k) = le_tm M
                     a' k = le_tm M  d k  {dir.N, dir.R}"
    proof -
      assume LE: "ts_pre k (n_pre k) = le_tm M"
      have a_LE: "a k = le_tm M" using read_a_k LE by simp
      show "a' k = le_tm M  d k  {dir.N, dir.R}"
        by (rule valid_mttm_deltaLE[OF vM delta_mem a_LE])
    qed
    have a_not_le_k: "ts_pre k (n_pre k)  le_tm M  a' k  le_tm M"
    proof
      assume nLE: "ts_pre k (n_pre k)  le_tm M" and LE': "a' k = le_tm M"
      have a_LE: "a k = le_tm M"
        by (rule valid_mttm_deltaLE_no_write[OF lu delta_mem LE'])
      from a_LE read_a_k nLE show False by simp
    qed
    ― ‹Dispatch on pos_n k› regime.›
    consider (steady) "pos_n k  2" | (le1) "pos_n k = 1" | (le0) "pos_n k = 0"
      by linarith
    then show "ae_window_invariant_general
                 (mt_tape ?cM' k) (mt_pos ?cM' k)
                 (pos_bp' k) (blocks' k) (pos_n k) (le_tm M)"
    proof cases
      case steady
      have wi_st: "ae_window_invariant (ts_pre k) (n_pre k)
                      (pos_bp k) (blocks k) ((pos_n k - 2) * ?c + 1)"
        using wi_gen_k steady
        unfolding ae_window_invariant_general_def by simp
      have no_le_k: "ts_pre k (n_pre k)  le_tm M"
        using no_le klt steady tp_eq ps_eq by force
      have wi_post: "ae_window_invariant
                        ((ts_pre k)(n_pre k := a' k))
                        (go_dir (d k) (n_pre k))
                        (pos_bp' k)
                        (write_bp (blocks k) (pos_bp k) (a' k))
                        ((pos_n k - 2) * ?c + 1)"
        by (rule ae_window_invariant_step
                [OF wi_st adv_k bp_lt_k bp_pos_k no_le_k])
      have wi_post_gen:
          "ae_window_invariant_general
              ((ts_pre k)(n_pre k := a' k))
              (go_dir (d k) (n_pre k))
              (pos_bp' k)
              (write_bp (blocks k) (pos_bp k) (a' k))
              (pos_n k) (le_tm M)"
        using wi_post steady
        unfolding ae_window_invariant_general_def by simp
      show ?thesis using wi_post_gen tape_k pos_k blocks'_k by simp
    next
      case le1
      have wi_l1: "ae_window_invariant_le1 (ts_pre k) (n_pre k)
                      (pos_bp k) (blocks k) (le_tm M)"
        using wi_gen_k le1
        unfolding ae_window_invariant_general_def by simp
      have no_le_win_k: "i. 0 < i  i  2 * ?c
                                 ts_pre k i  le_tm M"
        using no_le klt le1 tp_eq by simp
      have wi_post: "ae_window_invariant_le1
                        ((ts_pre k)(n_pre k := a' k))
                        (go_dir (d k) (n_pre k))
                        (pos_bp' k)
                        (write_bp (blocks k) (pos_bp k) (a' k))
                        (le_tm M)"
        by (rule ae_window_invariant_le1_step
                [OF wi_l1 adv_k bp_lt_k bp_pos_k
                    a_le_k a_not_le_k no_le_win_k])
      have wi_post_gen:
          "ae_window_invariant_general
              ((ts_pre k)(n_pre k := a' k))
              (go_dir (d k) (n_pre k))
              (pos_bp' k)
              (write_bp (blocks k) (pos_bp k) (a' k))
              (pos_n k) (le_tm M)"
        using wi_post le1
        unfolding ae_window_invariant_general_def by simp
      show ?thesis using wi_post_gen tape_k pos_k blocks'_k by simp
    next
      case le0
      have wi_l0: "ae_window_invariant_le0 (ts_pre k) (n_pre k)
                      (pos_bp k) (blocks k) (le_tm M)"
        using wi_gen_k le0
        unfolding ae_window_invariant_general_def by simp
      have no_le_win_k: "i. 0 < i  i  ?c
                                 ts_pre k i  le_tm M"
        using no_le klt le0 tp_eq by simp
      have wi_post: "ae_window_invariant_le0
                        ((ts_pre k)(n_pre k := a' k))
                        (go_dir (d k) (n_pre k))
                        (pos_bp' k)
                        (write_bp (blocks k) (pos_bp k) (a' k))
                        (le_tm M)"
        by (rule ae_window_invariant_le0_step
                [OF wi_l0 adv_k bp_lt_k bp_pos_k
                    a_le_k a_not_le_k no_le_win_k])
      have wi_post_gen:
          "ae_window_invariant_general
              ((ts_pre k)(n_pre k := a' k))
              (go_dir (d k) (n_pre k))
              (pos_bp' k)
              (write_bp (blocks k) (pos_bp k) (a' k))
              (pos_n k) (le_tm M)"
        using wi_post le0
        unfolding ae_window_invariant_general_def by simp
      show ?thesis using wi_post_gen tape_k pos_k blocks'_k by simp
    qed
  qed
  show ?thesis using step_mttm st_new new_window by blast
qed


text ‹Auxiliary induction for the reverse lift: given an
  n›-step m_step_buffered› chain (with n ≤ c›)
  starting from a canonical SS4-entry buffered state and the
  per-tape ae_window_invariant_general› + side conditions
  on a substrate-side initial config cM›, produces an
  n›-step substrate mttm_step› trace from cM› to
  some cM_n› with matching state, preserved window
  invariant, preserved no-LE windows, preserved
  left_not_le_pos0›, and the
  bp_linear›-bound conjunct (c ≤ bp_linear + n›,
  bp_linear < 2c + n›).

  Mirror of the forward induction ae_coupled_run_aux_general›
  with trace ⟷› chain flipped.  The single-step lift
  m_step_buffered_lift_to_tape_general› does the per-step
  substrate-side construction; this lemma threads the invariants
  across the chain.

  Used inside the smaller wrapper
  m_steps_buffered_lift_to_tape›, which exposes the result
  via m_steps_buffered›.›

lemma m_step_buffered_chain_lift_to_tape:
  fixes M :: "('q, 'a) mttm"
    and qM :: 'q
    and ofs :: "nat  'c :: enum"
    and buf_full ::
          "nat  (('c  'a) × ('c  'a) × ('c  'a))"
    and pos :: "nat  nat"
    and n :: nat
    and qM_n :: 'q
    and buf_n ::
          "nat  (('c  'a) × ('c  'a) × ('c  'a))"
    and end_pos_n :: "nat  'c bp"
    and cM :: "('a, 'q) mt_config"
  assumes vM:    "valid_mttm M"
      and lu:    "le_unique M"
      and cM_valid: "valid_config_mttm M cM"
      and qM_in: "qM  Q_tm M"
      and chain: "((qM, buf_full, λk. (AE_Home, ofs k)),
                   (qM_n, buf_n, end_pos_n))
                       (m_step_buffered M) ^^ n"
      and st_eq: "mt_state cM = qM"
      and window:
            "k<k_tm M. ae_window_invariant_general
                    (mt_tape cM k) (mt_pos cM k)
                    (AE_Home, ofs k) (buf_full k) (pos k) (le_tm M)"
      and n_bound: "n  card (UNIV :: 'c set)"
      and no_le:
            "k. (pos k = 0
                     (i. i < card (UNIV :: 'c set)
                               mt_tape cM k (Suc i)  le_tm M))
                  (pos k = 1
                       (i. i < 2 * card (UNIV :: 'c set)
                                 mt_tape cM k (Suc i)  le_tm M))
                  (pos k  2
                       (i. i < 3 * card (UNIV :: 'c set)
                                 mt_tape cM k
                                      ((pos k - 2) * card (UNIV :: 'c set)
                                        + 1 + i)
                                     le_tm M))"
      and left_not_le_pos0:
            "k<k_tm M. pos k = 0  fst (buf_full k)  LE_block (le_tm M)"
  shows "cM_n.
            (cM, cM_n)  mttm_step (delta_tm M) ^^ n
             mt_state cM_n = qM_n
             (k<k_tm M. ae_window_invariant_general
                      (mt_tape cM_n k) (mt_pos cM_n k)
                      (end_pos_n k) (buf_n k) (pos k) (le_tm M))
             (k. (pos k = 0
                        (i. i < card (UNIV :: 'c set)
                                   mt_tape cM_n k (Suc i)  le_tm M))
                     (pos k = 1
                           (i. i < 2 * card (UNIV :: 'c set)
                                     mt_tape cM_n k (Suc i)  le_tm M))
                     (pos k  2
                           (i. i < 3 * card (UNIV :: 'c set)
                                     mt_tape cM_n k
                                          ((pos k - 2) * card (UNIV :: 'c set)
                                            + 1 + i)
                                         le_tm M)))
             (k<k_tm M. pos k = 0
                        fst (buf_n k)  LE_block (le_tm M))
             (k. card (UNIV :: 'c set)  bp_linear (end_pos_n k) + n
                     bp_linear (end_pos_n k)
                          < 2 * card (UNIV :: 'c set) + n)"
  using chain n_bound
proof (induction n arbitrary: qM_n buf_n end_pos_n)
  case 0
  ― ‹Base case: zero buffered steps means the chain endpoint
    (qM_n, buf_n, end_pos_n)› equals the start
    (qM, buf_full, AE_Home offsets)›; witness cM_n = cM›
    and the substrate trace of length 0 is trivial.  All six
    output conjuncts lift directly from the lemma's input
    hypotheses.›
  from "0.prems"(1) have eq:
      "(qM_n, buf_n, end_pos_n) = (qM, buf_full, λk. (AE_Home, ofs k))"
    by simp
  have qM_n_eq:     "qM_n = qM"             using eq by simp
  have buf_n_eq:    "buf_n = buf_full"      using eq by simp
  have end_pos_eq:  "end_pos_n = (λk. (AE_Home, ofs k))" using eq by simp
  show ?case
  proof (intro exI [where x = cM] conjI)
    show "(cM, cM)  mttm_step (delta_tm M) ^^ 0" by simp
    show "mt_state cM = qM_n" using st_eq qM_n_eq by simp
    show "k<k_tm M. ae_window_invariant_general
                  (mt_tape cM k) (mt_pos cM k)
                  (end_pos_n k) (buf_n k) (pos k) (le_tm M)"
      using window buf_n_eq end_pos_eq by simp
    show "k. (pos k = 0
                  (i. i < card (UNIV :: 'c set)
                             mt_tape cM k (Suc i)  le_tm M))
               (pos k = 1
                    (i. i < 2 * card (UNIV :: 'c set)
                              mt_tape cM k (Suc i)  le_tm M))
               (pos k  2
                    (i. i < 3 * card (UNIV :: 'c set)
                              mt_tape cM k
                                   ((pos k - 2) * card (UNIV :: 'c set)
                                     + 1 + i)
                                  le_tm M))"
      using no_le by simp
    show "k<k_tm M. pos k = 0  fst (buf_n k)  LE_block (le_tm M)"
      using left_not_le_pos0 buf_n_eq by simp
    show "k. card (UNIV :: 'c set)  bp_linear (end_pos_n k) + 0
                 bp_linear (end_pos_n k) < 2 * card (UNIV :: 'c set) + 0"
    proof (intro allI conjI)
      fix k
      have lin_eq: "bp_linear (end_pos_n k)
                       = card (UNIV :: 'c set) + c_idx (ofs k)"
        using end_pos_eq unfolding bp_linear_def by simp
      have idx_lt: "c_idx (ofs k) < card (UNIV :: 'c set)"
        by (rule c_idx_lt_card)
      show "card (UNIV :: 'c set)  bp_linear (end_pos_n k) + 0"
        using lin_eq by simp
      show "bp_linear (end_pos_n k) < 2 * card (UNIV :: 'c set) + 0"
        using lin_eq idx_lt by simp
    qed
  qed
next
  case (Suc n')
  ― ‹Inductive step.  Peel the LAST m_step_buffered› step
    via relpow_Suc_E› to an intermediate
    (qM_n', buf_n', end_pos_n')›.  Apply the IH at n'›
    to obtain an intermediate substrate config cM_n'› with
    mt_state cM_n' = qM_n'›, the window invariant, and the
    four threaded conjuncts.  Use Step 2a's
    m_step_buffered_lift_to_tape_general› to extract one
    substrate mttm_step› from cM_n'› to a fresh
    cM_n›; compose via relpow_Suc_I›.  Re-derive the
    four threaded conjuncts at length Suc n'›.›
  have n'_bound: "n'  card (UNIV :: 'c set)"
    using Suc.prems(2) by linarith
  from Suc.prems(1) obtain s_n' where
      chain_n':  "((qM, buf_full, λk. (AE_Home, ofs k)), s_n')
                       (m_step_buffered M) ^^ n'"
    and last_step_raw: "(s_n', (qM_n, buf_n, end_pos_n))
                           m_step_buffered M"
    by (rule relpow_Suc_E)
  obtain qM_n' buf_n' end_pos_n' where
      s_n'_eq: "s_n' = (qM_n', buf_n', end_pos_n')"
    by (cases s_n') auto
  have chain_n'_unp:
      "((qM, buf_full, λk. (AE_Home, ofs k)),
        (qM_n', buf_n', end_pos_n'))  (m_step_buffered M) ^^ n'"
    using chain_n' s_n'_eq by simp
  have last_step:
      "((qM_n', buf_n', end_pos_n'), (qM_n, buf_n, end_pos_n))
           m_step_buffered M"
    using last_step_raw s_n'_eq by simp
  ― ‹Invoke the IH at length n'›.›
  from Suc.IH[OF chain_n'_unp n'_bound]
  obtain cM_n' where
      trace_n': "(cM, cM_n')  mttm_step (delta_tm M) ^^ n'"
    and st_n':  "mt_state cM_n' = qM_n'"
    and window_n':
          "k<k_tm M. ae_window_invariant_general
                  (mt_tape cM_n' k) (mt_pos cM_n' k)
                  (end_pos_n' k) (buf_n' k) (pos k) (le_tm M)"
    and no_le_n':
          "k. (pos k = 0
                    (i. i < card (UNIV :: 'c set)
                              mt_tape cM_n' k (Suc i)  le_tm M))
                 (pos k = 1
                      (i. i < 2 * card (UNIV :: 'c set)
                                mt_tape cM_n' k (Suc i)  le_tm M))
                 (pos k  2
                      (i. i < 3 * card (UNIV :: 'c set)
                                mt_tape cM_n' k
                                     ((pos k - 2) * card (UNIV :: 'c set)
                                       + 1 + i)
                                    le_tm M))"
    and left_n':
          "k<k_tm M. pos k = 0
                    fst (buf_n' k)  LE_block (le_tm M)"
    and bp_bound_n':
          "k. card (UNIV :: 'c set)  bp_linear (end_pos_n' k) + n'
                 bp_linear (end_pos_n' k)
                       < 2 * card (UNIV :: 'c set) + n'"
    by blast
  ― ‹Validity of the intermediate config cM_n'›, threaded
    along the IH's n'›-step trace; supplies the leaf lift's
    blank-tail read-match on padding tapes.›
  have cM_n'_valid: "valid_config_mttm M cM_n'"
    by (rule valid_reach_relpow_mttm[OF vM cM_valid trace_n'])
  ― ‹Per-tape strict bounds at n'›: n' ≤ c - 1›
    gives 0 < bp_linear < 3c - 1›.›
  have c_pos: "1  card (UNIV :: 'c set)"
    using Suc.prems(2) by linarith
  have bp_lt_n':
      "k. bp_linear (end_pos_n' k) < 3 * card (UNIV :: 'c set) - 1"
  proof (intro allI)
    fix k
    have lin_lt: "bp_linear (end_pos_n' k) < 2 * card (UNIV :: 'c set) + n'"
      using bp_bound_n' by blast
    show "bp_linear (end_pos_n' k) < 3 * card (UNIV :: 'c set) - 1"
      using lin_lt Suc.prems(2) c_pos by linarith
  qed
  have bp_pos_n':
      "k. 0 < bp_linear (end_pos_n' k)"
  proof (intro allI)
    fix k
    have low: "card (UNIV :: 'c set)  bp_linear (end_pos_n' k) + n'"
      using bp_bound_n' by blast
    show "0 < bp_linear (end_pos_n' k)"
      using low Suc.prems(2) c_pos by linarith
  qed
  ― ‹Per-tape no-LE-at-head at cM_n'›, regime-dispatched
    (steady: read at head is not LE; le0/le1: window-wide no-LE
    on [1, c]› or [1, 2c]›).  Derived from the IH's
    no_le_n'› conjunct.  The steady-regime case requires
    one extra step: mt_pos cM_n' k = (pos k - 2)c + 1
    + bp_linear (end_pos_n' k)› (from the window invariant),
    and bp_linear < 3c› places the head inside the no-LE
    window.›
  ― ‹Per-tape no-LE-at-head at cM_n'›, regime-dispatched,
    derived from the IH's no_le_n'› conjunct.  Split into
    three regime sublemmas, combined via blast›.›
  have head_le0:
      "k. pos k = 0
               (i. 0 < i  i  card (UNIV :: 'c set)
                           mt_tape cM_n' k i  le_tm M)"
  proof (intro allI impI allI impI)
    fix k i
    assume pos_0: "pos k = 0"
       and i_bnd: "0 < i  i  card (UNIV :: 'c set)"
    then obtain j where i_eq: "i = Suc j"
                    and j_lt: "j < card (UNIV :: 'c set)"
      by (metis Suc_le_eq Suc_pred')
    from no_le_n' pos_0 j_lt
    have "mt_tape cM_n' k (Suc j)  le_tm M" by blast
    thus "mt_tape cM_n' k i  le_tm M" using i_eq by simp
  qed
  have head_le1:
      "k. pos k = 1
               (i. 0 < i  i  2 * card (UNIV :: 'c set)
                           mt_tape cM_n' k i  le_tm M)"
  proof (intro allI impI allI impI)
    fix k i
    assume pos_1: "pos k = 1"
       and i_bnd: "0 < i  i  2 * card (UNIV :: 'c set)"
    then obtain j where i_eq: "i = Suc j"
                    and j_lt: "j < 2 * card (UNIV :: 'c set)"
      by (metis Suc_le_eq Suc_pred')
    from no_le_n' pos_1 j_lt
    have "mt_tape cM_n' k (Suc j)  le_tm M" by blast
    thus "mt_tape cM_n' k i  le_tm M" using i_eq by simp
  qed
  have head_steady:
      "k<k_tm M. pos k  2
               mt_tape cM_n' k (mt_pos cM_n' k)  le_tm M"
  proof (intro allI impI impI)
    fix k
    assume klt: "k < k_tm M" and pos_ge: "pos k  2"
    let ?c = "card (UNIV :: 'c set)"
    have wi_k: "ae_window_invariant_general
                    (mt_tape cM_n' k) (mt_pos cM_n' k)
                    (end_pos_n' k) (buf_n' k) (pos k) (le_tm M)"
      using window_n' klt by blast
    have wi_steady: "ae_window_invariant
                        (mt_tape cM_n' k) (mt_pos cM_n' k)
                        (end_pos_n' k) (buf_n' k)
                        ((pos k - 2) * ?c + 1)"
      using wi_k pos_ge
      unfolding ae_window_invariant_general_def by simp
    have head_eq: "mt_pos cM_n' k
                       = (pos k - 2) * ?c + 1
                         + bp_linear (end_pos_n' k)"
      using wi_steady unfolding ae_window_invariant_def by simp
    have lin_lt_3c: "bp_linear (end_pos_n' k) < 3 * ?c"
    proof -
      have step: "bp_linear (end_pos_n' k) < 3 * ?c - 1"
        using bp_lt_n' by blast
      show ?thesis using step c_pos by linarith
    qed
    from no_le_n' pos_ge lin_lt_3c
    have "mt_tape cM_n' k
              ((pos k - 2) * ?c + 1 + bp_linear (end_pos_n' k))
             le_tm M" by blast
    thus "mt_tape cM_n' k (mt_pos cM_n' k)  le_tm M"
      using head_eq by simp
  qed
  have no_le_step2a:
      "k<k_tm M. (pos k = 0
               (i. 0 < i  i  card (UNIV :: 'c set)
                           mt_tape cM_n' k i  le_tm M))
            (pos k = 1
                 (i. 0 < i  i  2 * card (UNIV :: 'c set)
                             mt_tape cM_n' k i  le_tm M))
            (pos k  2
                 mt_tape cM_n' k (mt_pos cM_n' k)  le_tm M)"
    using head_le0 head_le1 head_steady by blast
  ― ‹Apply Step 2a (single-step lift) to extract the substrate
    step from last_step›.›
  obtain cM_n where
      step_extracted:
        "(cM_n', cM_n)  mttm_step (delta_tm M)
          mt_state cM_n = qM_n
          (k<k_tm M. ae_window_invariant_general
                    (mt_tape cM_n k) (mt_pos cM_n k)
                    (end_pos_n k) (buf_n k) (pos k) (le_tm M))"
    using m_step_buffered_lift_to_tape_general
            [OF vM lu cM_n'_valid last_step st_n' window_n' bp_lt_n' bp_pos_n'
                no_le_step2a] by blast
  have step_one:  "(cM_n', cM_n)  mttm_step (delta_tm M)"
    using step_extracted by simp
  have st_n_eq:   "mt_state cM_n = qM_n"
    using step_extracted by simp
  have window_n:
      "k<k_tm M. ae_window_invariant_general
              (mt_tape cM_n k) (mt_pos cM_n k)
              (end_pos_n k) (buf_n k) (pos k) (le_tm M)"
    using step_extracted by simp
  have trace_n:
      "(cM, cM_n)  mttm_step (delta_tm M) ^^ (Suc n')"
    using trace_n' step_one by (rule relpow_Suc_I)
  ― ‹Re-derive the cM_n› / cM_n'› relation in
    mttm_step›-shape: mttm_step.cases› on
    step_one› unpacks the delta tuple and the tape
    update.›
  obtain ts_pre n_pre q_post a_step dir_step where
      cM_n'_eq: "cM_n' = ConfigM qM_n' ts_pre n_pre"
    and cM_n_eq:
        "cM_n = ConfigM q_post
                  (λk. (ts_pre k)(n_pre k := a_step k))
                  (λk. go_dir (dir_step k) (n_pre k))"
    and delta_mem:
        "(qM_n', λk. ts_pre k (n_pre k),
            q_post, a_step, dir_step)  delta_tm M"
  proof -
    from step_one obtain q_pre' ts_pre' n_pre' q_post' a_step' dir_step'
      where step_unp:
        "cM_n' = ConfigM q_pre' ts_pre' n_pre'"
        "cM_n = ConfigM q_post'
                  (λk. (ts_pre' k)(n_pre' k := a_step' k))
                  (λk. go_dir (dir_step' k) (n_pre' k))"
        "(q_pre', λk. ts_pre' k (n_pre' k),
              q_post', a_step', dir_step')  delta_tm M"
      by (rule mttm_step.cases)
    have q_pre'_eq: "q_pre' = qM_n'"
      using step_unp(1) st_n' by simp
    show thesis using step_unp q_pre'_eq that by simp
  qed
  have tp_n':  "mt_tape cM_n' = ts_pre" using cM_n'_eq by simp
  have ps_n':  "mt_pos  cM_n' = n_pre"  using cM_n'_eq by simp
  have tp_n:   "k. mt_tape cM_n k
                       = (ts_pre k)(n_pre k := a_step k)"
    using cM_n_eq by auto
  have q_post_eq: "q_post = qM_n"
    using cM_n_eq st_n_eq by simp
  ― ‹Conjunct 3 threading: new no_le› at cM_n›.
    Mirrors the forward direction.  Three regime branches; for
    each cell in the window, case-split on whether the M-step's
    update site n_pre k› coincides; if it does, use the
    LE-write contrapositive valid_mttm_deltaLE_no_write›.›
  have no_le_contra:
      "k. ts_pre k (n_pre k)  le_tm M
               a_step k  le_tm M"
  proof (intro allI impI)
    fix k
    assume rd_not_le: "ts_pre k (n_pre k)  le_tm M"
    show "a_step k  le_tm M"
    proof
      assume a_le: "a_step k = le_tm M"
      have "(λk. ts_pre k (n_pre k)) k = le_tm M"
        by (rule valid_mttm_deltaLE_no_write[OF lu delta_mem a_le])
      hence "ts_pre k (n_pre k) = le_tm M" by simp
      with rd_not_le show False ..
    qed
  qed
  have no_le0_n:
      "k. pos k = 0
               (i. i < card (UNIV :: 'c set)
                         mt_tape cM_n k (Suc i)  le_tm M)"
  proof (intro allI impI allI impI)
    fix k i
    assume pos_0: "pos k = 0"
       and i_bd: "i < card (UNIV :: 'c set)"
    have ih_at: "ts_pre k (Suc i)  le_tm M"
    proof -
      from no_le_n' pos_0 i_bd
      have "mt_tape cM_n' k (Suc i)  le_tm M" by blast
      thus ?thesis using tp_n' by simp
    qed
    show "mt_tape cM_n k (Suc i)  le_tm M"
    proof (cases "Suc i = n_pre k")
      case False
      hence "mt_tape cM_n k (Suc i) = ts_pre k (Suc i)"
        using tp_n by simp
      thus ?thesis using ih_at by simp
    next
      case True
      hence tape_eq: "mt_tape cM_n k (Suc i) = a_step k"
        using tp_n by simp
      from True have "ts_pre k (n_pre k) = ts_pre k (Suc i)"
        by simp
      with ih_at have "ts_pre k (n_pre k)  le_tm M" by simp
      hence "a_step k  le_tm M" using no_le_contra by blast
      thus ?thesis using tape_eq by simp
    qed
  qed
  have no_le1_n:
      "k. pos k = 1
               (i. i < 2 * card (UNIV :: 'c set)
                         mt_tape cM_n k (Suc i)  le_tm M)"
  proof (intro allI impI allI impI)
    fix k i
    assume pos_1: "pos k = 1"
       and i_bd: "i < 2 * card (UNIV :: 'c set)"
    have ih_at: "ts_pre k (Suc i)  le_tm M"
    proof -
      from no_le_n' pos_1 i_bd
      have "mt_tape cM_n' k (Suc i)  le_tm M" by blast
      thus ?thesis using tp_n' by simp
    qed
    show "mt_tape cM_n k (Suc i)  le_tm M"
    proof (cases "Suc i = n_pre k")
      case False
      hence "mt_tape cM_n k (Suc i) = ts_pre k (Suc i)"
        using tp_n by simp
      thus ?thesis using ih_at by simp
    next
      case True
      hence tape_eq: "mt_tape cM_n k (Suc i) = a_step k"
        using tp_n by simp
      from True have "ts_pre k (n_pre k) = ts_pre k (Suc i)"
        by simp
      with ih_at have "ts_pre k (n_pre k)  le_tm M" by simp
      hence "a_step k  le_tm M" using no_le_contra by blast
      thus ?thesis using tape_eq by simp
    qed
  qed
  have no_le2_n:
      "k. pos k  2
               (i. i < 3 * card (UNIV :: 'c set)
                         mt_tape cM_n k
                              ((pos k - 2) * card (UNIV :: 'c set) + 1 + i)
                             le_tm M)"
  proof (intro allI impI allI impI)
    fix k i
    assume pos_ge: "pos k  2"
       and i_bd: "i < 3 * card (UNIV :: 'c set)"
    let ?j = "(pos k - 2) * card (UNIV :: 'c set) + 1 + i"
    have ih_at: "ts_pre k ?j  le_tm M"
    proof -
      from no_le_n' pos_ge i_bd
      have "mt_tape cM_n' k ?j  le_tm M" by blast
      thus ?thesis using tp_n' by simp
    qed
    show "mt_tape cM_n k ?j  le_tm M"
    proof (cases "?j = n_pre k")
      case False
      hence "mt_tape cM_n k ?j = ts_pre k ?j"
        using tp_n by simp
      thus ?thesis using ih_at by simp
    next
      case True
      hence tape_eq: "mt_tape cM_n k ?j = a_step k"
        using tp_n by simp
      from True have "ts_pre k (n_pre k) = ts_pre k ?j"
        by simp
      with ih_at have "ts_pre k (n_pre k)  le_tm M" by simp
      hence "a_step k  le_tm M" using no_le_contra by blast
      thus ?thesis using tape_eq by simp
    qed
  qed
  have no_le_n:
      "k. (pos k = 0
               (i. i < card (UNIV :: 'c set)
                         mt_tape cM_n k (Suc i)  le_tm M))
            (pos k = 1
                 (i. i < 2 * card (UNIV :: 'c set)
                           mt_tape cM_n k (Suc i)  le_tm M))
            (pos k  2
                 (i. i < 3 * card (UNIV :: 'c set)
                           mt_tape cM_n k
                                ((pos k - 2) * card (UNIV :: 'c set)
                                  + 1 + i)
                               le_tm M))"
    using no_le0_n no_le1_n no_le2_n by blast
  ― ‹Conjunct 4 threading: left_not_le_pos0› at buf_n›.
    The buffered write at end_pos_n' k› changes
    buf_n' k› at the AE_Left› / AE_Home› / AE_Right› block
    depending on fst (end_pos_n' k)›.  For pos k = 0›,
    the regime invariant ae_window_invariant_le0› forces
    the buffered head to be in the Home block (so the Left
    block is unchanged), giving fst (buf_n k) = fst (buf_n' k)›;
    apply the IH (left_n'›).›
  from last_step obtain a_buf a'_buf d_buf where
      delta_buf: "(qM_n', a_buf, qM_n, a'_buf, d_buf)  delta_tm M"
    and read_buf: "k. a_buf k = read_bp (buf_n' k) (end_pos_n' k)"
    and write_buf: "k. buf_n k
                            = write_bp (buf_n' k) (end_pos_n' k) (a'_buf k)"
    and adv_buf: "k. bp_advance_le (le_tm M) (a_buf k)
                              (end_pos_n' k) (d_buf k)
                          = Some (end_pos_n k)"
    unfolding m_step_buffered_def by auto
  have left_n:
      "k<k_tm M. pos k = 0  fst (buf_n k)  LE_block (le_tm M)"
  proof (intro allI impI impI)
    fix k
    assume klt: "k < k_tm M" and pos_0: "pos k = 0"
    have wi_k: "ae_window_invariant_general
                    (mt_tape cM_n' k) (mt_pos cM_n' k)
                    (end_pos_n' k) (buf_n' k) (pos k) (le_tm M)"
      using window_n' klt by blast
    have wi_l0: "ae_window_invariant_le0
                    (mt_tape cM_n' k) (mt_pos cM_n' k)
                    (end_pos_n' k) (buf_n' k) (le_tm M)"
      using wi_k pos_0
      unfolding ae_window_invariant_general_def by simp
    have head_home_or_right:
        "fst (end_pos_n' k)  {AE_Home, AE_Right}"
    proof (cases "fst (end_pos_n' k)")
      case AE_Left
      have "False"
        using wi_l0 AE_Left
        unfolding ae_window_invariant_le0_def by simp
      thus ?thesis ..
    qed auto
    obtain l h r where buf_n'_eq:
        "buf_n' k = (l, h, r)" by (cases "buf_n' k") auto
    obtain b off where end_eq:
        "end_pos_n' k = (b, off)" by (cases "end_pos_n' k") auto
    from head_home_or_right end_eq have b_in: "b  {AE_Home, AE_Right}" by simp
    have fst_buf_n:
        "fst (buf_n k) = fst (buf_n' k)"
    proof -
      have wb_eq: "buf_n k
                    = write_bp (buf_n' k) (end_pos_n' k) (a'_buf k)"
        using write_buf by blast
      consider (home) "b = AE_Home" | (right) "b = AE_Right"
        using b_in by blast
      thus ?thesis
      proof cases
        case home
        have "write_bp (buf_n' k) (end_pos_n' k) (a'_buf k)
                = (l, h(off := a'_buf k), r)"
          using buf_n'_eq end_eq home
          unfolding write_bp_def by simp
        thus ?thesis using wb_eq buf_n'_eq by simp
      next
        case right
        have "write_bp (buf_n' k) (end_pos_n' k) (a'_buf k)
                = (l, h, r(off := a'_buf k))"
          using buf_n'_eq end_eq right
          unfolding write_bp_def by simp
        thus ?thesis using wb_eq buf_n'_eq by simp
      qed
    qed
    show "fst (buf_n k)  LE_block (le_tm M)"
      using fst_buf_n left_n' klt pos_0 by simp
  qed
  ― ‹Conjunct 5 threading: bp_bound› at end_pos_n›.
    One m_step_buffered› step shifts bp_linear› by at most 1
    (R: +1, L: -1, N: 0), via bp_advance_le›.  The new
    bounds follow from the IH bounds and the advance equation.
    Helper: bp_advance_le_lin_bounded› (in Setup).›
  have bp_bound_n:
      "k. card (UNIV :: 'c set)  bp_linear (end_pos_n k) + Suc n'
             bp_linear (end_pos_n k)
                 < 2 * card (UNIV :: 'c set) + Suc n'"
  proof (intro allI)
    fix k
    have low_n':
        "card (UNIV :: 'c set)  bp_linear (end_pos_n' k) + n'"
      using bp_bound_n' by blast
    have high_n':
        "bp_linear (end_pos_n' k) < 2 * card (UNIV :: 'c set) + n'"
      using bp_bound_n' by blast
    have pos_n': "0 < bp_linear (end_pos_n' k)"
      using bp_pos_n' by blast
    have adv_k: "bp_advance_le (le_tm M) (a_buf k) (end_pos_n' k) (d_buf k)
                    = Some (end_pos_n k)"
      using adv_buf by blast
    show "card (UNIV :: 'c set)  bp_linear (end_pos_n k) + Suc n'
             bp_linear (end_pos_n k)
                  < 2 * card (UNIV :: 'c set) + Suc n'"
      by (rule bp_advance_le_lin_bounded
              [OF adv_k pos_n' high_n' low_n'])
  qed
  ― ‹Assemble the six output conjuncts.›
  show ?case
  proof (intro exI [where x = cM_n] conjI)
    show "(cM, cM_n)  mttm_step (delta_tm M) ^^ Suc n'"
      using trace_n .
    show "mt_state cM_n = qM_n" using st_n_eq .
    show "k<k_tm M. ae_window_invariant_general
                  (mt_tape cM_n k) (mt_pos cM_n k)
                  (end_pos_n k) (buf_n k) (pos k) (le_tm M)"
      using window_n .
    show "k. (pos k = 0
                  (i. i < card (UNIV :: 'c set)
                             mt_tape cM_n k (Suc i)  le_tm M))
               (pos k = 1
                    (i. i < 2 * card (UNIV :: 'c set)
                              mt_tape cM_n k (Suc i)  le_tm M))
               (pos k  2
                    (i. i < 3 * card (UNIV :: 'c set)
                              mt_tape cM_n k
                                   ((pos k - 2) * card (UNIV :: 'c set)
                                     + 1 + i)
                                  le_tm M))"
      using no_le_n .
    show "k<k_tm M. pos k = 0
                  fst (buf_n k)  LE_block (le_tm M)"
      using left_n .
    show "k. card (UNIV :: 'c set)  bp_linear (end_pos_n k) + Suc n'
                 bp_linear (end_pos_n k)
                      < 2 * card (UNIV :: 'c set) + Suc n'"
      using bp_bound_n .
  qed
qed


text ‹User-facing reverse lift on
  m_steps_buffered›.  Wraps Step 2b-aux
  (m_step_buffered_chain_lift_to_tape›) by unfolding
  the existential n› in m_steps_buffered M›,
  applying the aux induction, and exposing the result via an
  obtains›-form interface.  Preserves the halt-exit
  disjunction (n = c ∨ final state ∈ {t, r}›) on
  the substrate side.

  Consumed by ae_backward_stage› to extract the substrate
  M-side trace from an SS4→›SS5 buffered chunk.›

lemma m_steps_buffered_lift_to_tape:
  fixes M :: "('q, 'a) mttm"
    and qM :: 'q
    and ofs :: "nat  'c :: enum"
    and buf_full ::
          "nat  (('c  'a) × ('c  'a) × ('c  'a))"
    and pos :: "nat  nat"
    and qM_end :: 'q
    and buf_end ::
          "nat  (('c  'a) × ('c  'a) × ('c  'a))"
    and end_pos_bp :: "nat  'c bp"
    and cM :: "('a, 'q) mt_config"
  assumes vM:    "valid_mttm M"
      and lu:    "le_unique M"
      and cM_valid: "valid_config_mttm M cM"
      and qM_in: "qM  Q_tm M"
      and steps: "((qM, buf_full, λk. (AE_Home, ofs k)),
                   (qM_end, buf_end, end_pos_bp))
                       m_steps_buffered M"
      and st_eq: "mt_state cM = qM"
      and window:
            "k<k_tm M. ae_window_invariant_general
                    (mt_tape cM k) (mt_pos cM k)
                    (AE_Home, ofs k) (buf_full k) (pos k) (le_tm M)"
      and no_le:
            "k. (pos k = 0
                     (i. i < card (UNIV :: 'c set)
                               mt_tape cM k (Suc i)  le_tm M))
                  (pos k = 1
                       (i. i < 2 * card (UNIV :: 'c set)
                                 mt_tape cM k (Suc i)  le_tm M))
                  (pos k  2
                       (i. i < 3 * card (UNIV :: 'c set)
                                 mt_tape cM k
                                      ((pos k - 2) * card (UNIV :: 'c set)
                                        + 1 + i)
                                     le_tm M))"
      and left_not_le_pos0:
            "k<k_tm M. pos k = 0  fst (buf_full k)  LE_block (le_tm M)"
  obtains cM_end n where
      "(cM, cM_end)  mttm_step (delta_tm M) ^^ n"
    and "n  card (UNIV :: 'c set)"
    and "n = card (UNIV :: 'c set)  mt_state cM_end  {t_tm M, r_tm M}"
    and "mt_state cM_end = qM_end"
    and "k<k_tm M. ae_window_invariant_general
                (mt_tape cM_end k) (mt_pos cM_end k)
                (end_pos_bp k) (buf_end k) (pos k) (le_tm M)"
    and "k. (pos k = 0
                  (i. i < card (UNIV :: 'c set)
                            mt_tape cM_end k (Suc i)  le_tm M))
               (pos k = 1
                    (i. i < 2 * card (UNIV :: 'c set)
                              mt_tape cM_end k (Suc i)  le_tm M))
               (pos k  2
                    (i. i < 3 * card (UNIV :: 'c set)
                              mt_tape cM_end k
                                   ((pos k - 2) * card (UNIV :: 'c set)
                                     + 1 + i)
                                  le_tm M))"
    and "k<k_tm M. pos k = 0
                 fst (buf_end k)  LE_block (le_tm M)"
proof -
  ― ‹Unfold m_steps_buffered›'s existential.›
  from steps obtain n where
      chain_n: "((qM, buf_full, λk. (AE_Home, ofs k)),
                 (qM_end, buf_end, end_pos_bp))
                     (m_step_buffered M) ^^ n"
    and n_bnd: "n  card (UNIV :: 'c set)"
    and halt_or_full:
        "n = card (UNIV :: 'c set)  qM_end  {t_tm M, r_tm M}"
    unfolding m_steps_buffered_def by auto
  ― ‹Invoke Step 2b-aux to obtain the substrate trace plus
    the threaded invariants at cM_n›.›
  from m_step_buffered_chain_lift_to_tape
        [OF vM lu cM_valid qM_in chain_n st_eq window n_bnd no_le
            left_not_le_pos0]
  obtain cM_end where
      trace_n:  "(cM, cM_end)  mttm_step (delta_tm M) ^^ n"
    and st_eq_n: "mt_state cM_end = qM_end"
    and window_n:
        "k<k_tm M. ae_window_invariant_general
                (mt_tape cM_end k) (mt_pos cM_end k)
                (end_pos_bp k) (buf_end k) (pos k) (le_tm M)"
    and no_le_n:
        "k. (pos k = 0
                  (i. i < card (UNIV :: 'c set)
                             mt_tape cM_end k (Suc i)  le_tm M))
               (pos k = 1
                    (i. i < 2 * card (UNIV :: 'c set)
                               mt_tape cM_end k (Suc i)  le_tm M))
               (pos k  2
                    (i. i < 3 * card (UNIV :: 'c set)
                               mt_tape cM_end k
                                    ((pos k - 2) * card (UNIV :: 'c set)
                                      + 1 + i)
                                   le_tm M))"
    and left_n:
        "k<k_tm M. pos k = 0  fst (buf_end k)  LE_block (le_tm M)"
    by blast
  have halt_or_full_substrate:
      "n = card (UNIV :: 'c set)  mt_state cM_end  {t_tm M, r_tm M}"
    using halt_or_full st_eq_n by simp
  show ?thesis
    by (rule that[OF trace_n n_bnd halt_or_full_substrate
                       st_eq_n window_n no_le_n left_n])
qed


subsubsection ‹SS4→›SS5 backward destruct›

text ‹Reverse-arm counterpart of
  ae_step_ss4_ss5_construct_from_buffered›.  Given an
  SS4→›SS5 substrate step, destructure it to
  expose the SS4 source structure, the SS5 target structure, and
  the inner buffered chain.  Consumed by
  ae_backward_stage_compute_extract›.

  No ae_inv_ss4› hypothesis is required: the relation
  ae_delta_ss4_ss5› itself pins the source state shape
  (substep_idx› = SS4, q ∈ Q_tm M›,
  q ≠ t_tm M›, q ≠ r_tm M›)
  and exposes the buffered chain. The destruct is therefore a
  purely structural elimination of mttm_step.cases›
  followed by an unfold of ae_delta_ss4_ss5_def›.›

lemma ae_step_ss4_ss5_destruct_to_buffered:
  fixes M :: "('q, 'a) mttm"
    and c c' :: "('c :: enum  'a,
                  'q × ('a, 'c) ae_stage) mt_config"
  assumes step: "(c, c')  mttm_step (ae_delta_ss4_ss5 M)"
  obtains q ofs buf dest_old ts n q_out buf' bufC end_pos where
      "c = ConfigM (q, ofs, buf, dest_old, SS4) ts n"
    and "mt_state c' = (q_out,
                        λk. if k < k_tm M then snd (end_pos k)
                              else init_offset k,
                        buf',
                        λk. if k < k_tm M then fst (end_pos k)
                              else init_dest k, SS5)"
    and "buf' = (λk. if k < k_tm M then bufC k
                       else init_buffer (le_tm M) k)"
    and "mt_tape c' = ts"
    and "mt_pos c'
           = (λk. go_dir (if k < k_tm M
                            then (if ts k (n k) = LE_block (le_tm M)
                                    then dir.N else dir.L)
                            else dir.N)
                         (n k))"
    and "q  Q_tm M"
    and "q  t_tm M"
    and "q  r_tm M"
    and "jk_tm M. ts j (n j) = bl_block (bl_tm M)"
    and "((q, λk. (fst (buf k),
                    if k < k_tm M then fst (snd (buf k)) else ts k (n k),
                    ts k (n k)),
            λk. (AE_Home, ofs k)),
           (q_out, bufC, end_pos))  m_steps_buffered M"
proof -
  from step obtain s tsP nP s' aP dP where
      cP_eq: "c = ConfigM s tsP nP"
      and c'_eq: "c' = ConfigM s' (λk. (tsP k)(nP k := aP k))
                                   (λk. go_dir (dP k) (nP k))"
      and rel: "(s, (λk. tsP k (nP k)), s', aP, dP)
                   ae_delta_ss4_ss5 M"
    by (auto elim: mttm_step.cases)
  from rel obtain q ofs buf dest_old q_out ofs' buf' dest'
                  buf_full end_pos bufC
    where s_eq: "s = (q, ofs, buf, dest_old, SS4)"
      and s'_eq: "s' = (q_out, ofs', buf', dest', SS5)"
      and a_eq: "aP = (λk. tsP k (nP k))"
      and q_in_Q: "q  Q_tm M"
      and q_neq_t_M: "q  t_tm M"
      and q_neq_r_M: "q  r_tm M"
      and supp: "jk_tm M. tsP j (nP j) = bl_block (bl_tm M)"
      and buf_full_eq: "buf_full
                         = (λk. (fst (buf k),
                                  if k < k_tm M then fst (snd (buf k))
                                    else tsP k (nP k),
                                  tsP k (nP k)))"
      and m_steps_raw: "((q, buf_full, λk. (AE_Home, ofs k)),
                          (q_out, bufC, end_pos))
                             m_steps_buffered M"
      and ofs'_eq: "ofs' = (λk. if k < k_tm M then snd (end_pos k)
                                  else init_offset k)"
      and buf'_eq: "buf' = (λk. if k < k_tm M then bufC k
                                  else init_buffer (le_tm M) k)"
      and dest'_eq: "dest' = (λk. if k < k_tm M then fst (end_pos k)
                                   else init_dest k)"
      and d_eq: "dP = (λk. if k < k_tm M
                             then (if tsP k (nP k) = LE_block (le_tm M)
                                     then dir.N else dir.L)
                             else dir.N)"
    by (auto simp: ae_delta_ss4_ss5_def)
  have ts_write_unchanged: "(λk. (tsP k)(nP k := aP k)) = tsP"
    using a_eq by (auto intro!: ext)
  show thesis
  proof (rule that[where q=q and ofs=ofs and buf=buf
                     and dest_old=dest_old and ts=tsP and n=nP
                     and q_out=q_out and buf'=buf' and bufC=bufC
                     and end_pos=end_pos])
    show "c = ConfigM (q, ofs, buf, dest_old, SS4) tsP nP"
      using cP_eq s_eq by simp
    show "mt_state c' = (q_out,
                         λk. if k < k_tm M then snd (end_pos k)
                               else init_offset k,
                         buf',
                         λk. if k < k_tm M then fst (end_pos k)
                               else init_dest k, SS5)"
      using c'_eq s'_eq ofs'_eq dest'_eq by simp
    show "buf' = (λk. if k < k_tm M then bufC k
                        else init_buffer (le_tm M) k)"
      by (rule buf'_eq)
    show "mt_tape c' = tsP"
      using c'_eq ts_write_unchanged by simp
    show "mt_pos c'
            = (λk. go_dir (if k < k_tm M
                             then (if tsP k (nP k) = LE_block (le_tm M)
                                     then dir.N else dir.L)
                             else dir.N)
                          (nP k))"
      using c'_eq d_eq by simp
    show "q  Q_tm M" by (rule q_in_Q)
    show "q  t_tm M" by (rule q_neq_t_M)
    show "q  r_tm M" by (rule q_neq_r_M)
    show "jk_tm M. tsP j (nP j) = bl_block (bl_tm M)" by (rule supp)
    show "((q, λk. (fst (buf k),
                     if k < k_tm M then fst (snd (buf k)) else tsP k (nP k),
                     tsP k (nP k)),
              λk. (AE_Home, ofs k)),
            (q_out, bufC, end_pos))  m_steps_buffered M"
      using m_steps_raw buf_full_eq by simp
  qed
qed


subsubsection ‹Backward stage: load, compute, writeback›

text ‹**Reverse-arm counterpart of ae_forward_stage_load_chain›.**
  Given a 3-step alphabet_enlarge_delta›-chain
  c' →^3 c3› with c'› at SS1 with the
  forward-arm invariants, identifies the three buffer-load
  substeps (SS1→›SS2, SS2→›SS3,
  SS3→›SS4), commits each peeled step to its
  canonical substep relation via
  mttm_step_ae_delta_ssN_only›, and propagates the
  invariant bundle (ae_inv_ss4›,
  ae_tape_in_gamma_block›,
  ae_buffer_in_gamma_block›, state preservation,
  ae_position_link›) to c3›.  Side-band
  preservation reuses the direction-agnostic lemmas
  (ae_step_alphabet_enlarge_gamma_preserve› etc.) from
  the forward arm.›

lemma ae_backward_stage_load_chain:
  fixes M :: "('q, 'a) mttm"
    and c' c3 :: "('c :: enum  'a,
                   'q × ('a, 'c) ae_stage) mt_config"
    and qM' :: 'q
    and ofs :: "nat  'c"
    and buf :: "nat  ('c  'a) × ('c  'a) × ('c  'a)"
    and dest :: "nat  ae_dest"
  assumes vM:          "valid_mttm M"
      and c'_state:    "mt_state c' = (qM', ofs, buf, dest, SS1)"
      and inv_ss1:     "ae_inv_ss1 M c'"
      and gamma_c':    "ae_tape_in_gamma_block M c'"
      and buf_gamma:   "ae_buffer_in_gamma_block M c'"
      and pos_link_c': "ae_position_link M c'"
      and qM'_neq_t:   "qM'  t_tm M"
      and qM'_neq_r:   "qM'  r_tm M"
      and run:         "(c', c3)
                           mttm_step (alphabet_enlarge_delta M) ^^ 3"
  obtains c1 c2 where
      "(c', c1)  mttm_step (ae_delta_ss1_ss2 M)"
    and "(c', c1)  mttm_step (alphabet_enlarge_delta M)"
    and "(c1, c2)  mttm_step (ae_delta_ss2_ss3 M)"
    and "(c1, c2)  mttm_step (alphabet_enlarge_delta M)"
    and "(c2, c3)  mttm_step (ae_delta_ss3_ss4 M)"
    and "(c2, c3)  mttm_step (alphabet_enlarge_delta M)"
    and "ae_inv_ss4 M c3"
    and "ae_tape_in_gamma_block M c3"
    and "ae_buffer_in_gamma_block M c3"
    and "fst (mt_state c3) = qM'"
    and "ae_position_link M c3"
proof -
  ― ‹Peel the 3-step chain into three alphabet-enlarge steps
      through intermediates c1›, c2›.›
  from run obtain c1 c2 where
      step1: "(c', c1)  mttm_step (alphabet_enlarge_delta M)"
    and step2: "(c1, c2)  mttm_step (alphabet_enlarge_delta M)"
    and step3: "(c2, c3)  mttm_step (alphabet_enlarge_delta M)"
    by (auto dest!: relpow_Suc_D2 simp: numeral_3_eq_3)

  ― ‹Substep 1: SS1→›SS2.  Commit step1 to
      ae_delta_ss1_ss2› via mttm_step_ae_delta_ss1_only›,
      then propagate the per-substep invariant and side-bands.›
  have c'_idx_ss1: "snd (snd (snd (snd (mt_state c')))) = SS1"
    using c'_state by simp
  have step1_sub: "(c', c1)  mttm_step (ae_delta_ss1_ss2 M)"
    by (rule mttm_step_ae_delta_ss1_only[OF step1 c'_idx_ss1])
  have inv_ss2: "ae_inv_ss2 M c1"
    using ae_step_ss1_ss2_invariant[OF vM inv_ss1 step1_sub] .
  have gamma_c1: "ae_tape_in_gamma_block M c1"
    using ae_step_alphabet_enlarge_gamma_preserve[OF gamma_c' step1] .
  have buf_gamma_c1: "ae_buffer_in_gamma_block M c1"
    using ae_step_alphabet_enlarge_buffer_gamma_preserve[OF vM buf_gamma
                                                            gamma_c' step1] .
  have c1_fst_eq: "fst (mt_state c1) = qM'"
    using step1_sub c'_state
    by (auto simp: ae_delta_ss1_ss2_def elim: mttm_step.cases)
  have aux_45_at_c': "(c', c1)  mttm_step (ae_delta_ss4_ss5 M)
                         ae_position_link M c1"
    using ae_pos_link_aux_void_ss4_ss5[where M = M and c_pre = c' and c_post = c1]
          c'_idx_ss1 by simp
  have aux_56_at_c': "(c', c1)  mttm_step (ae_delta_ss5_ss6 M)
                         ae_position_link M c1"
    using ae_pos_link_aux_void_ss5_ss6[where M = M and c_pre = c' and c_post = c1]
          c'_idx_ss1 by simp
  have aux_78_at_c': "(c', c1)  mttm_step (ae_delta_ss7_ss8 M)
                         ae_position_link M c1"
    using ae_pos_link_aux_void_ss7_ss8[where M = M and c_pre = c' and c_post = c1]
          c'_idx_ss1 by simp
  have pos_link_c1: "ae_position_link M c1"
    using ae_step_alphabet_enlarge_position_link_preserve[OF pos_link_c'
            step1 aux_45_at_c' aux_56_at_c' aux_78_at_c'] .

  ― ‹Substep 2: SS2→›SS3.›
  have c1_idx_ss2: "snd (snd (snd (snd (mt_state c1)))) = SS2"
    using inv_ss2 unfolding ae_inv_ss2_def by (cases "mt_state c1") auto
  have step2_sub: "(c1, c2)  mttm_step (ae_delta_ss2_ss3 M)"
    by (rule mttm_step_ae_delta_ss2_only[OF step2 c1_idx_ss2])
  have inv_ss3: "ae_inv_ss3 M c2"
    using ae_step_ss2_ss3_invariant[OF vM inv_ss2 step2_sub] .
  have gamma_c2: "ae_tape_in_gamma_block M c2"
    using ae_step_alphabet_enlarge_gamma_preserve[OF gamma_c1 step2] .
  have buf_gamma_c2: "ae_buffer_in_gamma_block M c2"
    using ae_step_alphabet_enlarge_buffer_gamma_preserve[OF vM buf_gamma_c1
                                                            gamma_c1 step2] .
  have c2_fst_eq: "fst (mt_state c2) = qM'"
    using step2_sub c1_fst_eq
    by (cases "mt_state c1")
       (auto simp: ae_delta_ss2_ss3_def elim: mttm_step.cases)
  have aux_45_at_c1: "(c1, c2)  mttm_step (ae_delta_ss4_ss5 M)
                         ae_position_link M c2"
    using ae_pos_link_aux_void_ss4_ss5[where M = M and c_pre = c1 and c_post = c2]
          c1_idx_ss2 by simp
  have aux_56_at_c1: "(c1, c2)  mttm_step (ae_delta_ss5_ss6 M)
                         ae_position_link M c2"
    using ae_pos_link_aux_void_ss5_ss6[where M = M and c_pre = c1 and c_post = c2]
          c1_idx_ss2 by simp
  have aux_78_at_c1: "(c1, c2)  mttm_step (ae_delta_ss7_ss8 M)
                         ae_position_link M c2"
    using ae_pos_link_aux_void_ss7_ss8[where M = M and c_pre = c1 and c_post = c2]
          c1_idx_ss2 by simp
  have pos_link_c2: "ae_position_link M c2"
    using ae_step_alphabet_enlarge_position_link_preserve[OF pos_link_c1
            step2 aux_45_at_c1 aux_56_at_c1 aux_78_at_c1] .

  ― ‹Substep 3: SS3→›SS4.›
  have c2_idx_ss3: "snd (snd (snd (snd (mt_state c2)))) = SS3"
    using inv_ss3 unfolding ae_inv_ss3_def by (cases "mt_state c2") auto
  have step3_sub: "(c2, c3)  mttm_step (ae_delta_ss3_ss4 M)"
    by (rule mttm_step_ae_delta_ss3_only[OF step3 c2_idx_ss3])
  have inv_ss4: "ae_inv_ss4 M c3"
    using ae_step_ss3_ss4_invariant[OF vM inv_ss3 step3_sub] .
  have gamma_c3: "ae_tape_in_gamma_block M c3"
    using ae_step_alphabet_enlarge_gamma_preserve[OF gamma_c2 step3] .
  have buf_gamma_c3: "ae_buffer_in_gamma_block M c3"
    using ae_step_alphabet_enlarge_buffer_gamma_preserve[OF vM buf_gamma_c2
                                                            gamma_c2 step3] .
  have c3_fst_eq: "fst (mt_state c3) = qM'"
    using step3_sub c2_fst_eq
    by (cases "mt_state c2")
       (auto simp: ae_delta_ss3_ss4_def elim: mttm_step.cases)
  have aux_45_at_c2: "(c2, c3)  mttm_step (ae_delta_ss4_ss5 M)
                         ae_position_link M c3"
    using ae_pos_link_aux_void_ss4_ss5[where M = M and c_pre = c2 and c_post = c3]
          c2_idx_ss3 by simp
  have aux_56_at_c2: "(c2, c3)  mttm_step (ae_delta_ss5_ss6 M)
                         ae_position_link M c3"
    using ae_pos_link_aux_void_ss5_ss6[where M = M and c_pre = c2 and c_post = c3]
          c2_idx_ss3 by simp
  have aux_78_at_c2: "(c2, c3)  mttm_step (ae_delta_ss7_ss8 M)
                         ae_position_link M c3"
    using ae_pos_link_aux_void_ss7_ss8[where M = M and c_pre = c2 and c_post = c3]
          c2_idx_ss3 by simp
  have pos_link_c3: "ae_position_link M c3"
    using ae_step_alphabet_enlarge_position_link_preserve[OF pos_link_c2
            step3 aux_45_at_c2 aux_56_at_c2 aux_78_at_c2] .

  show ?thesis
    by (rule that[OF step1_sub step1 step2_sub step2 step3_sub step3
                     inv_ss4 gamma_c3 buf_gamma_c3 c3_fst_eq pos_link_c3])
qed


text ‹**Reverse-arm SS4→›SS5 compute extract.**
  Counterpart of the forward arm's SS4→›SS5 step
  construction.  Given the load-chain output (the three buffer-load
  steps c'→›c3 plus standard SS1-boundary invariants)
  and a substrate step (c3, c4) ∈ mttm_step
  (alphabet_enlarge_delta M)› issuing from c3 at SS4, this
  lemma produces:

   Step commitment: (c3, c4)› lies in
    ae_delta_ss4_ss5› (via Step 3a's
    mttm_step_ae_delta_ss4_only›).

   Lifted cM› trace: (cM, cM_new) ∈ mttm_step
    (delta_tm M) ^^ n› for some n ≤ |c|›, with halt-or-full
    termination — produced by m_steps_buffered_lift_to_tape›
    (Step 2b-wrapper) from the m_steps_buffered› chain
    exposed by ae_step_ss4_ss5_destruct_to_buffered›.

   Threaded invariants at cM_new›/c4›: window
    invariant carrying through, regime-aware no-LE, and the
    fst (buf' k) ≠ LE_block› guard for pos=0 tapes.

  Composes the direction-agnostic helpers from the forward arm
  (ae_home_classification›,
  ae_ss1_to_ss4_buffer_chars_general›,
  ae_ss4_window_from_correspondence_general›) with the
  reverse-arm helpers
  (mttm_step_ae_delta_ss4_only›,
  ae_step_ss4_ss5_destruct_to_buffered›) and Step
  2b-wrapper.  Consumer: ae_backward_stage›'s body.›

lemma ae_backward_stage_compute_extract:
  fixes M :: "('q, 'a) mttm"
    and cM :: "('a, 'q) mt_config"
    and c' c1 c2 c3 c4 :: "('c :: enum  'a,
                              'q × ('a, 'c) ae_stage) mt_config"
    and qM' :: 'q
    and ofs :: "nat  'c"
    and buf :: "nat  ('c  'a) × ('c  'a) × ('c  'a)"
    and dest :: "nat  ae_dest"
  assumes vM:          "valid_mttm M"
      and lu:          "le_unique M"
      and cM_valid:    "valid_config_mttm M cM"
      and sim:         "ae_simulates M cM c'"
      and c'_state:    "mt_state c' = (qM', ofs, buf, dest, SS1)"
      and le_anchor:   "k<k_tm M. mt_tape c' k 0 = LE_block (le_tm M)"
      and le_neq_bl:   "le_tm M  bl_tm M"
      and no_le_per_tape:
            "k. (mt_pos c' k  2
                     (i. i < 3 * card (UNIV :: 'c set)
                               mt_tape cM k
                                    ((mt_pos c' k - 2) * card (UNIV :: 'c set)
                                       + 1 + i)
                                   le_tm M))
                  (mt_pos c' k = 1
                       (i. i < 2 * card (UNIV :: 'c set)
                                 mt_tape cM k (Suc i)  le_tm M))
                  (mt_pos c' k = 0
                       (i. i < card (UNIV :: 'c set)
                                 mt_tape cM k (Suc i)  le_tm M))"
      and step1_sub:   "(c', c1)  mttm_step (ae_delta_ss1_ss2 M)"
      and step2_sub:   "(c1, c2)  mttm_step (ae_delta_ss2_ss3 M)"
      and step3_sub:   "(c2, c3)  mttm_step (ae_delta_ss3_ss4 M)"
      and step4_full:  "(c3, c4)  mttm_step (alphabet_enlarge_delta M)"
      and c3_idx_ss4:  "snd (snd (snd (snd (mt_state c3)))) = SS4"
  obtains cM_new buf' end_pos n where
      "(c3, c4)  mttm_step (ae_delta_ss4_ss5 M)"
    and "(cM, cM_new)  mttm_step (delta_tm M) ^^ n"
    and "n  card (UNIV :: 'c set)"
    and "n = card (UNIV :: 'c set)
             mt_state cM_new  {t_tm M, r_tm M}"
    and "mt_state c4 = (mt_state cM_new,
                          λk. if k < k_tm M then snd (end_pos k)
                                else init_offset k,
                          buf',
                          λk. if k < k_tm M then fst (end_pos k)
                                else init_dest k, SS5)"
    and "mt_tape c4 = mt_tape c'"
    and "k<k_tm M. ae_window_invariant_general
                (mt_tape cM_new k) (mt_pos cM_new k)
                (end_pos k) (buf' k) (mt_pos c' k) (le_tm M)"
    and "k. (mt_pos c' k = 0
                   (i. i < card (UNIV :: 'c set)
                             mt_tape cM_new k (Suc i)  le_tm M))
               (mt_pos c' k = 1
                   (i. i < 2 * card (UNIV :: 'c set)
                             mt_tape cM_new k (Suc i)  le_tm M))
               (mt_pos c' k  2
                   (i. i < 3 * card (UNIV :: 'c set)
                             mt_tape cM_new k
                                  ((mt_pos c' k - 2) * card (UNIV :: 'c set)
                                     + 1 + i)
                                 le_tm M))"
    and "k<k_tm M. mt_pos c' k = 0
                 fst (buf' k)  LE_block (le_tm M)"
proof -
  ― ‹Commit step4 to ae_delta_ss4_ss5› via Step 3a's
      cross-phase exclusion lift.›
  have step4_sub: "(c3, c4)  mttm_step (ae_delta_ss4_ss5 M)"
    by (rule mttm_step_ae_delta_ss4_only[OF step4_full c3_idx_ss4])

  ― ‹Extract tape correspondence from the simulation invariant.›
  have tape_corr: "k<k_tm M. ae_tape_correspondence (le_tm M)
                          (mt_tape cM k) (mt_tape c' k)"
    using sim c'_state unfolding ae_simulates_def by auto

  ― ‹Home-cell LE classification (Step 3c.1 helper).›
  have home_classification:
      "k<k_tm M. (mt_pos c' k = 0
               mt_tape c' k (mt_pos c' k) = LE_block (le_tm M))
            (mt_pos c' k  1
               mt_tape c' k (mt_pos c' k)  LE_block (le_tm M))"
    by (rule ae_home_classification[OF le_anchor no_le_per_tape tape_corr])

  ― ‹SS4-entry buffer / tape / position characterisation
      (direction-agnostic, shared with forward arm).›
  have c3_state:
      "mt_state c3 = (qM', ofs,
                       (λk. if k < k_tm M
                              then (if mt_pos c' k = 0
                                     then (bl_block (bl_tm M),
                                           LE_block (le_tm M),
                                           snd (snd (buf k)))
                                     else (mt_tape c' k (mt_pos c' k - 1),
                                           mt_tape c' k (mt_pos c' k),
                                           snd (snd (buf k))))
                              else init_buffer (le_tm M) k),
                       dest, SS4)"
    using ae_ss1_to_ss4_buffer_chars_general(1)[OF c'_state step1_sub
                                                   step2_sub step3_sub
                                                   home_classification] .
  have c3_tape: "mt_tape c3 = mt_tape c'"
    using ae_ss1_to_ss4_buffer_chars_general(2)[OF c'_state step1_sub
                                                   step2_sub step3_sub
                                                   home_classification] .
  have c3_pos: "k. k < k_tm M  mt_pos c3 k = mt_pos c' k + 1"
    using ae_ss1_to_ss4_buffer_chars_general(3)[OF c'_state step1_sub
                                                   step2_sub step3_sub
                                                   home_classification] .

  ― ‹Per-tape SS4 window invariant at cM› via the unified
      from-correspondence helper.›
  have window_at_cM:
      "k<k_tm M. ae_window_invariant_general
              (mt_tape cM k) (mt_pos cM k)
              (AE_Home, ofs k)
              (if mt_pos c' k = 0
                 then (bl_block (bl_tm M),
                       LE_block (le_tm M),
                       mt_tape c' k 1)
               else if mt_pos c' k = 1
                 then (mt_tape c' k 0,
                       mt_tape c' k 1,
                       mt_tape c' k 2)
               else (mt_tape c' k (mt_pos c' k - 1),
                     mt_tape c' k (mt_pos c' k),
                     mt_tape c' k (mt_pos c' k + 1)))
              (mt_pos c' k)
              (le_tm M)"
    using ae_ss4_window_from_correspondence_general[OF sim c'_state
                                                       le_anchor
                                                       no_le_per_tape] .

  ― ‹Destructure the SS4→›SS5 step into its
      m_steps_buffered› chain.  Bind every obtained variable
      and every shows-conjunct, then discharge by direct
      rule-application to avoid blast› divergence on the
      large obtains›.›
  obtain qD ofsD bufD destD tsD nD q_out buf' bufC end_pos where
      c3_eq: "c3 = ConfigM (qD, ofsD, bufD, destD, SS4) tsD nD"
    and c4_state_raw:
        "mt_state c4 = (q_out,
                        λk. if k < k_tm M then snd (end_pos k)
                              else init_offset k,
                        buf',
                        λk. if k < k_tm M then fst (end_pos k)
                              else init_dest k, SS5)"
    and buf'_def: "buf' = (λk. if k < k_tm M then bufC k
                                 else init_buffer (le_tm M) k)"
    and c4_tape_raw: "mt_tape c4 = tsD"
    and c4_pos_raw:
        "mt_pos c4
           = (λk. go_dir (if k < k_tm M
                            then (if tsD k (nD k) = LE_block (le_tm M)
                                    then dir.N else dir.L)
                            else dir.N)
                         (nD k))"
    and qD_in: "qD  Q_tm M"
    and qD_neq_t: "qD  t_tm M"
    and qD_neq_r: "qD  r_tm M"
    and tsD_supp: "jk_tm M. tsD j (nD j) = bl_block (bl_tm M)"
    and m_steps:
        "((qD, λk. (fst (bufD k),
                     if k < k_tm M then fst (snd (bufD k)) else tsD k (nD k),
                     tsD k (nD k)),
            λk. (AE_Home, ofsD k)),
           (q_out, bufC, end_pos))  m_steps_buffered M"
    by (rule ae_step_ss4_ss5_destruct_to_buffered[OF step4_sub])

  ― ‹Identify destructed names with our load-chain view.›
  have qD_eq: "qD = qM'"
    using c3_eq c3_state by simp
  have ofsD_eq: "ofsD = ofs"
    using c3_eq c3_state by simp
  have bufD_eq:
      "bufD = (λk. if k < k_tm M
                     then (if mt_pos c' k = 0
                            then (bl_block (bl_tm M),
                                  LE_block (le_tm M),
                                  snd (snd (buf k)))
                            else (mt_tape c' k (mt_pos c' k - 1),
                                  mt_tape c' k (mt_pos c' k),
                                  snd (snd (buf k))))
                     else init_buffer (le_tm M) k)"
    using c3_eq c3_state by simp
  have tsD_eq: "tsD = mt_tape c'"
    using c3_eq c3_tape by simp
  have nD_eq: "k. k < k_tm M  nD k = mt_pos c' k + 1"
    using c3_eq c3_pos by simp

  ― ‹The destruct's m_steps› source is the guarded
      buf_full› home block; name it buf_full_src› so the
      Step 2b-wrapper unification is first-order.  On active tapes
      (k < k_tm M›) it collapses to the window helper's
      regime-aware buffer shape; padding tapes carry the frozen
      empty-tape shadow and never enter the wrapper's
      ∀k<k_tm M› obligations.›
  define buf_full_src ::
      "nat  ('c  'a) × ('c  'a) × ('c  'a)"
    where "buf_full_src =
             (λk. (fst (bufD k),
                   if k < k_tm M then fst (snd (bufD k)) else tsD k (nD k),
                   tsD k (nD k)))"

  ― ‹Active-tape alignment: for k < k_tm M› the guarded
      source coincides with the window helper's regime shape.›
  have src_align:
      "k<k_tm M. buf_full_src k
              = (if mt_pos c' k = 0
                   then (bl_block (bl_tm M), LE_block (le_tm M),
                         mt_tape c' k 1)
                 else if mt_pos c' k = 1
                   then (mt_tape c' k 0, mt_tape c' k 1, mt_tape c' k 2)
                 else (mt_tape c' k (mt_pos c' k - 1),
                       mt_tape c' k (mt_pos c' k),
                       mt_tape c' k (mt_pos c' k + 1)))"
  proof (intro allI impI)
    fix k assume klt: "k < k_tm M"
    have bufD_k: "bufD k
                    = (if mt_pos c' k = 0
                         then (bl_block (bl_tm M), LE_block (le_tm M),
                               snd (snd (buf k)))
                         else (mt_tape c' k (mt_pos c' k - 1),
                               mt_tape c' k (mt_pos c' k),
                               snd (snd (buf k))))"
      using bufD_eq klt by simp
    have tsD_k: "tsD k (nD k) = mt_tape c' k (mt_pos c' k + 1)"
      using tsD_eq nD_eq[OF klt] by simp
    have src_k: "buf_full_src k
                   = (fst (bufD k), fst (snd (bufD k)), tsD k (nD k))"
      using klt unfolding buf_full_src_def by simp
    show "buf_full_src k
            = (if mt_pos c' k = 0
                 then (bl_block (bl_tm M), LE_block (le_tm M),
                       mt_tape c' k 1)
               else if mt_pos c' k = 1
                 then (mt_tape c' k 0, mt_tape c' k 1, mt_tape c' k 2)
               else (mt_tape c' k (mt_pos c' k - 1),
                     mt_tape c' k (mt_pos c' k),
                     mt_tape c' k (mt_pos c' k + 1)))"
    proof (cases "mt_pos c' k")
      case 0
      thus ?thesis using src_k bufD_k tsD_k by simp
    next
      case (Suc m)
      show ?thesis
      proof (cases m)
        case 0
        with Suc src_k bufD_k tsD_k show ?thesis
          by (simp add: eval_nat_numeral)
      next
        case (Suc mm)
        with mt_pos c' k = Suc m src_k bufD_k tsD_k show ?thesis by simp
      qed
    qed
  qed

  ― ‹State alignment for cM›: simulation gives
      mt_state cM = qM'›, and destruct gives qD = qM'›.›
  have st_eq_cM: "mt_state cM = qD"
    using sim c'_state qD_eq unfolding ae_simulates_def by auto

  ― ‹m_steps› chain in the form expected by the
      Step 2b-wrapper, with the guarded source named and ofs›
      substituted for ofsD›.›
  have m_steps_src:
      "((qD, buf_full_src, λk. (AE_Home, ofs k)),
          (q_out, bufC, end_pos))  m_steps_buffered M"
    using m_steps ofsD_eq unfolding buf_full_src_def by simp

  ― ‹Window invariant at cM› for the guarded source, on
      active tapes, via the regime alignment.›
  have window_at_cM_src:
      "k<k_tm M. ae_window_invariant_general
              (mt_tape cM k) (mt_pos cM k)
              (AE_Home, ofs k) (buf_full_src k) (mt_pos c' k) (le_tm M)"
  proof (intro allI impI)
    fix k assume klt: "k < k_tm M"
    show "ae_window_invariant_general (mt_tape cM k) (mt_pos cM k)
            (AE_Home, ofs k) (buf_full_src k) (mt_pos c' k) (le_tm M)"
      using window_at_cM[rule_format, OF klt] src_align[rule_format, OF klt]
      by simp
  qed

  ― ‹Invoke Step 2b-wrapper.  The window invariant at cM›
      and the regime-keyed no_le› match the wrapper's
      hypotheses by construction.  Left-not-LE for pos=0 tapes
      is the bl_block ≠ LE_block› argument.›
  have bl_neq_le:
      "(bl_block (bl_tm M) :: 'c  'a)  LE_block (le_tm M)"
  proof
    assume eq: "(bl_block (bl_tm M) :: 'c  'a) = LE_block (le_tm M)"
    have "bl_block (bl_tm M) (SOME x :: 'c. True)
            = LE_block (le_tm M) (SOME x :: 'c. True)"
      using eq by simp
    hence "bl_tm M = le_tm M"
      unfolding bl_block_def LE_block_def by simp
    with le_neq_bl show False by simp
  qed
  have left_not_le_pos0_buf_full:
      "k<k_tm M. mt_pos c' k = 0
               fst (buf_full_src k)  LE_block (le_tm M)"
  proof (intro allI impI impI)
    fix k assume klt: "k < k_tm M" and pos0: "mt_pos c' k = 0"
    have "buf_full_src k
            = (bl_block (bl_tm M), LE_block (le_tm M), mt_tape c' k 1)"
      using src_align[rule_format, OF klt] pos0 by simp
    thus "fst (buf_full_src k)  LE_block (le_tm M)"
      using bl_neq_le by simp
  qed

  ― ‹Reorder the regime conjunction so it matches the
      Step 2b-wrapper's hypothesis shape (pos=0, pos=1, pos≥›2).
      The outer no_le_per_tape› uses the opposite order
      (pos≥›2, pos=1, pos=0) inherited from the forward-arm
      assumption convention.›
  have no_le_per_tape_reordered:
      "k. (mt_pos c' k = 0
               (i. i < card (UNIV :: 'c set)
                         mt_tape cM k (Suc i)  le_tm M))
            (mt_pos c' k = 1
                 (i. i < 2 * card (UNIV :: 'c set)
                           mt_tape cM k (Suc i)  le_tm M))
            (mt_pos c' k  2
                 (i. i < 3 * card (UNIV :: 'c set)
                           mt_tape cM k
                                ((mt_pos c' k - 2) * card (UNIV :: 'c set)
                                   + 1 + i)
                               le_tm M))"
    using no_le_per_tape by blast

  obtain cM_new n where
      cM_trace_n: "(cM, cM_new)  mttm_step (delta_tm M) ^^ n"
    and n_bnd: "n  card (UNIV :: 'c set)"
    and halt_or_full:
        "n = card (UNIV :: 'c set)
             mt_state cM_new  {t_tm M, r_tm M}"
    and cM_new_st: "mt_state cM_new = q_out"
    and new_window_C:
        "k<k_tm M. ae_window_invariant_general
                (mt_tape cM_new k) (mt_pos cM_new k)
                (end_pos k) (bufC k) (mt_pos c' k) (le_tm M)"
    and new_no_le:
        "k. (mt_pos c' k = 0
                   (i. i < card (UNIV :: 'c set)
                             mt_tape cM_new k (Suc i)  le_tm M))
               (mt_pos c' k = 1
                   (i. i < 2 * card (UNIV :: 'c set)
                             mt_tape cM_new k (Suc i)  le_tm M))
               (mt_pos c' k  2
                   (i. i < 3 * card (UNIV :: 'c set)
                             mt_tape cM_new k
                                  ((mt_pos c' k - 2) * card (UNIV :: 'c set)
                                     + 1 + i)
                                 le_tm M))"
    and new_left_C:
        "k<k_tm M. mt_pos c' k = 0
                 fst (bufC k)  LE_block (le_tm M)"
    by (rule m_steps_buffered_lift_to_tape
          [OF vM lu cM_valid qD_in m_steps_src st_eq_cM window_at_cM_src
              no_le_per_tape_reordered left_not_le_pos0_buf_full])
  ― ‹The SS5 buffer buf'› agrees with the chain target
      bufC› on active tapes; transport the per-active-tape
      window and left-not-LE facts.›
  have buf'_active: "k<k_tm M. buf' k = bufC k"
    using buf'_def by simp
  have new_window:
      "k<k_tm M. ae_window_invariant_general
              (mt_tape cM_new k) (mt_pos cM_new k)
              (end_pos k) (buf' k) (mt_pos c' k) (le_tm M)"
    using new_window_C buf'_active by simp
  have new_left_not_le_pos0:
      "k<k_tm M. mt_pos c' k = 0
               fst (buf' k)  LE_block (le_tm M)"
    using new_left_C buf'_active by simp

  ― ‹Tape preservation through SS4→›SS5: the substep
      writes the same letter it reads (a' = a›), so
      mt_tape c4 = mt_tape c3 = mt_tape c'›.›
  have c4_tape: "mt_tape c4 = mt_tape c'"
    using c4_tape_raw tsD_eq by simp

  ― ‹Rewrite c4_state_raw› to use mt_state cM_new›;
      offset / dest fields are guarded (frozen at init_*› beyond
      the tape count), mirroring the SS4→›SS5 δ›.›
  have c4_state:
      "mt_state c4 = (mt_state cM_new,
                       λk. if k < k_tm M then snd (end_pos k)
                             else init_offset k,
                       buf',
                       λk. if k < k_tm M then fst (end_pos k)
                             else init_dest k, SS5)"
    using c4_state_raw cM_new_st by simp

  show thesis
  proof (rule that[where cM_new = cM_new and buf' = buf'
                     and end_pos = end_pos and n = n])
    show "(c3, c4)  mttm_step (ae_delta_ss4_ss5 M)" by (rule step4_sub)
    show "(cM, cM_new)  mttm_step (delta_tm M) ^^ n"
      by (rule cM_trace_n)
    show "n  card (UNIV :: 'c set)" by (rule n_bnd)
    show "n = card (UNIV :: 'c set)
             mt_state cM_new  {t_tm M, r_tm M}"
      by (rule halt_or_full)
    show "mt_state c4 = (mt_state cM_new,
                          λk. if k < k_tm M then snd (end_pos k)
                                else init_offset k,
                          buf',
                          λk. if k < k_tm M then fst (end_pos k)
                                else init_dest k, SS5)"
      by (rule c4_state)
    show "mt_tape c4 = mt_tape c'" by (rule c4_tape)
    show "k<k_tm M. ae_window_invariant_general
                (mt_tape cM_new k) (mt_pos cM_new k)
                (end_pos k) (buf' k) (mt_pos c' k) (le_tm M)"
      by (rule new_window)
    show "k. (mt_pos c' k = 0
                   (i. i < card (UNIV :: 'c set)
                             mt_tape cM_new k (Suc i)  le_tm M))
               (mt_pos c' k = 1
                   (i. i < 2 * card (UNIV :: 'c set)
                             mt_tape cM_new k (Suc i)  le_tm M))
               (mt_pos c' k  2
                   (i. i < 3 * card (UNIV :: 'c set)
                             mt_tape cM_new k
                                  ((mt_pos c' k - 2) * card (UNIV :: 'c set)
                                     + 1 + i)
                                 le_tm M))"
      by (rule new_no_le)
    show "k<k_tm M. mt_pos c' k = 0
                 fst (buf' k)  LE_block (le_tm M)"
      by (rule new_left_not_le_pos0)
  qed
qed


text ‹**Reverse-arm SS5→›SS1 writeback chain peel.**
  Mirror of ae_backward_stage_load_chain› for the four
  write-back substeps (SS5→›SS6,
  SS6→›SS7, SS7→›SS8,
  SS8→›SS1).

  Given an SS5-boundary config c4› with the standard SS5
  invariants and a 4-step alphabet_enlarge_delta› chain
  to c''›, identifies each substep via Step 3a's
  mttm_step_ae_delta_ssN_only›, propagates the per-substep
  invariants ae_inv_ss› through the chain, carries
  ae_tape_in_gamma_block› and
  ae_buffer_in_gamma_block› via the direction-agnostic
  preserve lemmas, and exposes the halt-aware c'' status:

   non-halt branch (q_out ∉ {t_tm M, r_tm M}›):
    c''› lands at SS1 with the same q-component as c4 (preserved
    through all 4 substeps).

   halt branch (q_out ∈ {t_tm M, r_tm M}›):
    c''› lands at VFwd with halted q-component and
    init_stage le›.

  Position-link propagation through writeback substeps is NOT
  performed here — it requires the regime-aware buffer non-LE
  analysis that's better packaged with the final
  ae_simulates› assembly in Step 3f.›

lemma ae_backward_stage_writeback_chain:
  fixes M :: "('q, 'a) mttm"
    and c4 c'' :: "('c :: enum  'a,
                     'q × ('a, 'c) ae_stage) mt_config"
    and q_out :: 'q
  assumes vM:           "valid_mttm M"
      and c4_inv:       "ae_inv_ss5 M c4"
      and c4_q:         "fst (mt_state c4) = q_out"
      and q_out_in_Q:   "q_out  Q_tm M"
      and gamma_c4:     "ae_tape_in_gamma_block M c4"
      and buf_gamma_c4: "ae_buffer_in_gamma_block M c4"
      and run:          "(c4, c'')
                            mttm_step (alphabet_enlarge_delta M) ^^ 4"
  obtains c5 c6 c7 where
      "(c4, c5)  mttm_step (ae_delta_ss5_ss6 M)"
    and "(c4, c5)  mttm_step (alphabet_enlarge_delta M)"
    and "(c5, c6)  mttm_step (ae_delta_ss6_ss7 M)"
    and "(c5, c6)  mttm_step (alphabet_enlarge_delta M)"
    and "(c6, c7)  mttm_step (ae_delta_ss7_ss8 M)"
    and "(c6, c7)  mttm_step (alphabet_enlarge_delta M)"
    and "(c7, c'')  mttm_step (ae_delta_ss8_ss1 M)"
    and "(c7, c'')  mttm_step (alphabet_enlarge_delta M)"
    and "q_out  {t_tm M, r_tm M}  ae_inv_ss1 M c''"
    and "q_out  {t_tm M, r_tm M}
             (case mt_state c'' of (qH, _, _, _, idx)
                   qH  {t_tm M, r_tm M}  idx = VFwd)"
    and "fst (mt_state c'') = q_out"
    and "ae_tape_in_gamma_block M c''"
    and "ae_buffer_in_gamma_block M c''"
proof -
  ― ‹Peel the 4-step chain into four alphabet-enlarge steps
      through intermediates c5›, c6›, c7›.›
  from run obtain c5 c6 c7 where
      step5: "(c4, c5)  mttm_step (alphabet_enlarge_delta M)"
    and step6: "(c5, c6)  mttm_step (alphabet_enlarge_delta M)"
    and step7: "(c6, c7)  mttm_step (alphabet_enlarge_delta M)"
    and step8: "(c7, c'')  mttm_step (alphabet_enlarge_delta M)"
    by (auto dest!: relpow_Suc_D2 simp: numeral_eq_Suc)

  ― ‹Substep 5: SS5→›SS6.›
  have c4_idx_ss5: "snd (snd (snd (snd (mt_state c4)))) = SS5"
    using c4_inv unfolding ae_inv_ss5_def by (cases "mt_state c4") auto
  have step5_sub: "(c4, c5)  mttm_step (ae_delta_ss5_ss6 M)"
    by (rule mttm_step_ae_delta_ss5_only[OF step5 c4_idx_ss5])
  have inv_ss6: "ae_inv_ss6 M c5"
    using ae_step_ss5_ss6_invariant[OF vM c4_inv step5_sub] .
  have gamma_c5: "ae_tape_in_gamma_block M c5"
    using ae_step_alphabet_enlarge_gamma_preserve[OF gamma_c4 step5] .
  have buf_gamma_c5: "ae_buffer_in_gamma_block M c5"
    using ae_step_alphabet_enlarge_buffer_gamma_preserve[OF vM buf_gamma_c4
                                                            gamma_c4 step5] .
  have c5_fst_eq: "fst (mt_state c5) = q_out"
    using step5_sub c4_q
    by (cases "mt_state c4")
       (auto simp: ae_delta_ss5_ss6_def elim: mttm_step.cases)

  ― ‹Substep 6: SS6→›SS7.›
  have c5_idx_ss6: "snd (snd (snd (snd (mt_state c5)))) = SS6"
    using inv_ss6 unfolding ae_inv_ss6_def
    by (cases "mt_state c5") auto
  have step6_sub: "(c5, c6)  mttm_step (ae_delta_ss6_ss7 M)"
    by (rule mttm_step_ae_delta_ss6_only[OF step6 c5_idx_ss6])
  have inv_ss7: "ae_inv_ss7 M c6"
    using ae_step_ss6_ss7_invariant[OF vM inv_ss6 step6_sub] .
  have gamma_c6: "ae_tape_in_gamma_block M c6"
    using ae_step_alphabet_enlarge_gamma_preserve[OF gamma_c5 step6] .
  have buf_gamma_c6: "ae_buffer_in_gamma_block M c6"
    using ae_step_alphabet_enlarge_buffer_gamma_preserve[OF vM buf_gamma_c5
                                                            gamma_c5 step6] .
  have c6_fst_eq: "fst (mt_state c6) = q_out"
    using step6_sub c5_fst_eq
    by (cases "mt_state c5")
       (auto simp: ae_delta_ss6_ss7_def elim: mttm_step.cases)

  ― ‹Substep 7: SS7→›SS8.›
  have c6_idx_ss7: "snd (snd (snd (snd (mt_state c6)))) = SS7"
    using inv_ss7 unfolding ae_inv_ss7_def
    by (cases "mt_state c6") auto
  have step7_sub: "(c6, c7)  mttm_step (ae_delta_ss7_ss8 M)"
    by (rule mttm_step_ae_delta_ss7_only[OF step7 c6_idx_ss7])
  have inv_ss8: "ae_inv_ss8 M c7"
    using ae_step_ss7_ss8_invariant[OF vM inv_ss7 step7_sub] .
  have gamma_c7: "ae_tape_in_gamma_block M c7"
    using ae_step_alphabet_enlarge_gamma_preserve[OF gamma_c6 step7] .
  have buf_gamma_c7: "ae_buffer_in_gamma_block M c7"
    using ae_step_alphabet_enlarge_buffer_gamma_preserve[OF vM buf_gamma_c6
                                                            gamma_c6 step7] .
  have c7_fst_eq: "fst (mt_state c7) = q_out"
    using step7_sub c6_fst_eq
    by (cases "mt_state c6")
       (auto simp: ae_delta_ss7_ss8_def elim: mttm_step.cases)

  ― ‹Substep 8: SS8→›SS1 with halt-aware routing.
      The substep relation pins the q-component; the post-state
      stage'› is init_stage le› in the halt branch
      and (ofs, buf, init_dest, SS1)› in the non-halt
      branch.›
  have c7_idx_ss8: "snd (snd (snd (snd (mt_state c7)))) = SS8"
    using inv_ss8 unfolding ae_inv_ss8_def
    by (cases "mt_state c7") auto
  have step8_sub: "(c7, c'')  mttm_step (ae_delta_ss8_ss1 M)"
    by (rule mttm_step_ae_delta_ss8_only[OF step8 c7_idx_ss8])
  have c''_fst_eq: "fst (mt_state c'') = q_out"
    using step8_sub c7_fst_eq
    by (cases "mt_state c7")
       (auto simp: ae_delta_ss8_ss1_def elim: mttm_step.cases)
  have gamma_c'': "ae_tape_in_gamma_block M c''"
    using ae_step_alphabet_enlarge_gamma_preserve[OF gamma_c7 step8] .
  have buf_gamma_c'': "ae_buffer_in_gamma_block M c''"
    using ae_step_alphabet_enlarge_buffer_gamma_preserve[OF vM buf_gamma_c7
                                                            gamma_c7 step8] .

  ― ‹Halt-aware c'' invariant.  In the non-halt branch,
      ae_step_ss8_ss1_invariant› gives
      ae_inv_ss1 M c''›.  In the halt branch,
      ae_step_ss8_ss1_invariant_halt› gives the
      qH ∈ {t_tm M, r_tm M} ∧ idx = VFwd› state shape
      at c''.›
  have non_halt_inv:
      "q_out  {t_tm M, r_tm M}  ae_inv_ss1 M c''"
  proof
    assume nh: "q_out  {t_tm M, r_tm M}"
    have non_halt_at_c7:
        "case mt_state c7 of (qM', _, _, _, _) 
           qM'  t_tm M  qM'  r_tm M"
      using c7_fst_eq nh by (cases "mt_state c7") auto
    show "ae_inv_ss1 M c''"
      using ae_step_ss8_ss1_invariant[OF vM inv_ss8 non_halt_at_c7 step8_sub] .
  qed
  have halt_inv:
      "q_out  {t_tm M, r_tm M}
           (case mt_state c'' of (qH, _, _, _, idx)
                   qH  {t_tm M, r_tm M}  idx = VFwd)"
  proof
    assume h: "q_out  {t_tm M, r_tm M}"
    have halt_at_c7:
        "case mt_state c7 of (qM', _, _, _, _) 
           qM'  {t_tm M, r_tm M}"
      using c7_fst_eq h by (cases "mt_state c7") auto
    show "case mt_state c'' of (qH, _, _, _, idx)
             qH  {t_tm M, r_tm M}  idx = VFwd"
      using ae_step_ss8_ss1_invariant_halt[OF inv_ss8 halt_at_c7 step8_sub] .
  qed

  show ?thesis
    by (rule that[OF step5_sub step5 step6_sub step6 step7_sub step7
                     step8_sub step8 non_halt_inv halt_inv c''_fst_eq
                     gamma_c'' buf_gamma_c''])
qed

text ‹Reverse-arm dispatcher: unpack ae_simulates›
  *without* committing to the SS1-versus-halt disjunction.
  Companion to ae_forward_stage_unpack_sim› (which
  requires the SS1 branch via the non-halt M-state hypotheses).

  Where ae_forward_stage_unpack_sim› serves forward-arm
  proofs (M-state is mid-simulation by hypothesis, so SS1 is
  forced), ae_simulates_state_disjunction› serves
  reverse-arm proofs that walk an M'-chain to a canonical halt
  config: at each step the current paired c'› might be
  mid-simulation (SS1) or already at halt
  (init_stage le›), and the proof needs both branches
  exposed for case-analysis.›

lemma ae_simulates_state_disjunction:
  fixes M :: "('q, 'a) mttm"
    and cM :: "('a, 'q) mt_config"
    and c' :: "('c :: enum  'a,
                'q × ('a, 'c) ae_stage) mt_config"
  assumes sim: "ae_simulates M cM c'"
  obtains qM' ofs buf dest idx where
      "mt_state c' = (qM', ofs, buf, dest, idx)"
    and "mt_state cM = qM'"
    and "(idx = SS1  qM'  {t_tm M, r_tm M})
          (qM'  {t_tm M, r_tm M}
               (ofs, buf, dest, idx) = init_stage (le_tm M))"
    and "k<k_tm M. ae_tape_correspondence (le_tm M)
              (mt_tape cM k) (mt_tape c' k)"
    and "ae_tape_in_gamma_block M c'"
proof -
  obtain qM' ofs buf dest idx where
      state_comp: "mt_state c' = (qM', ofs, buf, dest, idx)"
    by (cases "mt_state c'")
  have sim_body:
      "((idx = SS1  qM'  {t_tm M, r_tm M})
           (qM'  {t_tm M, r_tm M}
                (ofs, buf, dest, idx) = init_stage (le_tm M)))
        mt_state cM = qM'
        (k<k_tm M. ae_tape_correspondence (le_tm M)
                 (mt_tape cM k) (mt_tape c' k))
        (idx = SS1
             (k<k_tm M. mt_pos cM k = ae_decode_pos (mt_pos c' k) (ofs k)))
        ae_tape_in_gamma_block M c'"
    using sim state_comp unfolding ae_simulates_def by simp
  have qM_eq: "mt_state cM = qM'" using sim_body by simp
  have state_disj:
      "(idx = SS1  qM'  {t_tm M, r_tm M})
         (qM'  {t_tm M, r_tm M}
               (ofs, buf, dest, idx) = init_stage (le_tm M))"
    using sim_body by simp
  have tape_corr:
      "k<k_tm M. ae_tape_correspondence (le_tm M)
              (mt_tape cM k) (mt_tape c' k)"
    using sim_body by simp
  have gamma_c': "ae_tape_in_gamma_block M c'"
    using sim_body by simp
  show ?thesis
    by (rule that[OF state_comp qM_eq state_disj tape_corr gamma_c'])
qed


subsubsection ‹Window-inversion kernel and SS5→›SS8 congruence (det›-free)›

text ‹The det-free replacement for the SS4→›SS5 chain-uniqueness
  used in ae_backward_stage›.  The det_mttm M› hypothesis was
  consumed only to identify the given backward chain's SS4→›SS5
  target with the forward arm's reconstruction.  Both targets satisfy
  ae_window_invariant_general› against the ‹same› extracted
  M-trace endpoint, so the identification is a functional inversion of the
  window invariant, not a use of determinism.  The kernel is two
  unconditional injectivity facts about the linearisation: (A)
  bp_linear› is injective --- the boundary position bp› is
  recovered from the head nM›; (B) the 3⋅card›-cell window
  buf_lin_at blocks› determines blocks› --- the buffer triple
  is recovered from the tape.  Combined, they give the full-window
  (pos ≥ 2›) inversion below.›

text c_idx› is injective: it has enum_class.enum ! c_idx x = x›
  as a section (c_idx_in_range›), so equal indices give equal
  elements.›

lemma c_idx_inj:
  fixes x y :: "'c :: enum"
  assumes "c_idx x = c_idx y"
  shows "x = y"
proof -
  have "x = (enum_class.enum :: 'c list) ! c_idx x"
    by (rule c_idx_in_range(2)[symmetric])
  also have " = (enum_class.enum :: 'c list) ! c_idx y"
    using assms by simp
  also have " = y" by (rule c_idx_in_range(2))
  finally show ?thesis .
qed

text ‹(A) bp_linear› injective.  The direction component lands the
  value in one of three disjoint length-card› intervals, so equal
  values force equal directions; c_idx›-injectivity then forces equal
  cells.›

lemma bp_linear_inj:
  fixes p q :: "('c :: enum) bp"
  assumes "bp_linear p = bp_linear q"
  shows "p = q"
proof -
  obtain d x where p: "p = (d, x)" by (cases p)
  obtain d' y where q: "q = (d', y)" by (cases q)
  have bx: "c_idx x < card (UNIV :: 'c set)" by (rule c_idx_lt_card)
  have by': "c_idx y < card (UNIV :: 'c set)" by (rule c_idx_lt_card)
  from assms have eq:
    "(case d of AE_Left  0 | AE_Home  card (UNIV :: 'c set)
        | AE_Right  2 * card (UNIV :: 'c set)) + c_idx x
     = (case d' of AE_Left  0 | AE_Home  card (UNIV :: 'c set)
        | AE_Right  2 * card (UNIV :: 'c set)) + c_idx y"
    by (simp add: p q bp_linear_def)
  have "d = d'  c_idx x = c_idx y"
    using eq bx by' by (cases d; cases d'; simp; linarith)
  hence "d = d'" and "x = y" using c_idx_inj by auto
  thus ?thesis by (simp add: p q)
qed

text ‹(B) the window buf_lin_at blocks› determines blocks›.  Each
  of the three blocks is read at every 'c›-cell as i› sweeps its
  third of the window, because enum_class.enum› enumerates the whole
  type.›

lemma buf_window_determines:
  fixes b1 b2 :: "(('c :: enum)  'a) × ('c  'a) × ('c  'a)"
  assumes "i < 3 * card (UNIV :: 'c set). buf_lin_at b1 i = buf_lin_at b2 i"
  shows "b1 = b2"
proof -
  obtain l1 h1 r1 where b1: "b1 = (l1, h1, r1)" by (cases b1)
  obtain l2 h2 r2 where b2: "b2 = (l2, h2, r2)" by (cases b2)
  let ?c = "card (UNIV :: 'c set)"
  have lE: "l1 = l2"
  proof (rule ext)
    fix x :: 'c
    have idx: "c_idx x < ?c" by (rule c_idx_lt_card)
    hence lt: "c_idx x < 3 * ?c" by simp
    have v1: "buf_lin_at b1 (c_idx x) = l1 x"
      using idx by (simp add: b1 buf_lin_at_def Let_def c_idx_in_range(2))
    have v2: "buf_lin_at b2 (c_idx x) = l2 x"
      using idx by (simp add: b2 buf_lin_at_def Let_def c_idx_in_range(2))
    from assms lt have "buf_lin_at b1 (c_idx x) = buf_lin_at b2 (c_idx x)" by blast
    with v1 v2 show "l1 x = l2 x" by simp
  qed
  have hE: "h1 = h2"
  proof (rule ext)
    fix x :: 'c
    have idx: "c_idx x < ?c" by (rule c_idx_lt_card)
    hence lt: "?c + c_idx x < 3 * ?c" by linarith
    have v1: "buf_lin_at b1 (?c + c_idx x) = h1 x"
      using idx by (simp add: b1 buf_lin_at_def Let_def c_idx_in_range(2))
    have v2: "buf_lin_at b2 (?c + c_idx x) = h2 x"
      using idx by (simp add: b2 buf_lin_at_def Let_def c_idx_in_range(2))
    from assms lt have "buf_lin_at b1 (?c + c_idx x) = buf_lin_at b2 (?c + c_idx x)" by blast
    with v1 v2 show "h1 x = h2 x" by simp
  qed
  have rE: "r1 = r2"
  proof (rule ext)
    fix x :: 'c
    have idx: "c_idx x < ?c" by (rule c_idx_lt_card)
    hence lt: "2 * ?c + c_idx x < 3 * ?c" by linarith
    have v1: "buf_lin_at b1 (2 * ?c + c_idx x) = r1 x"
      using idx by (simp add: b1 buf_lin_at_def Let_def c_idx_in_range(2))
    have v2: "buf_lin_at b2 (2 * ?c + c_idx x) = r2 x"
      using idx by (simp add: b2 buf_lin_at_def Let_def c_idx_in_range(2))
    from assms lt have "buf_lin_at b1 (2 * ?c + c_idx x) = buf_lin_at b2 (2 * ?c + c_idx x)" by blast
    with v1 v2 show "r1 x = r2 x" by simp
  qed
  show ?thesis using b1 b2 lE hE rE by simp
qed

text ‹Per-block reads of buf_lin_at›: the three thirds of the
  window read the left / home / right block respectively.›

lemma buf_lin_at_l:
  fixes b :: "(('c :: enum)  'a) × ('c  'a) × ('c  'a)"
  assumes "i < card (UNIV :: 'c set)"
  shows "buf_lin_at b i = fst b ((enum_class.enum :: 'c list) ! i)"
  using assms by (simp add: buf_lin_at_def case_prod_beta Let_def)

lemma buf_lin_at_h:
  fixes b :: "(('c :: enum)  'a) × ('c  'a) × ('c  'a)"
  assumes "card (UNIV :: 'c set)  i" and "i < 2 * card (UNIV :: 'c set)"
  shows "buf_lin_at b i = fst (snd b) ((enum_class.enum :: 'c list) ! (i - card (UNIV :: 'c set)))"
  using assms by (simp add: buf_lin_at_def case_prod_beta Let_def)

lemma buf_lin_at_r:
  fixes b :: "(('c :: enum)  'a) × ('c  'a) × ('c  'a)"
  assumes "2 * card (UNIV :: 'c set)  i" and "i < 3 * card (UNIV :: 'c set)"
  shows "buf_lin_at b i = snd (snd b) ((enum_class.enum :: 'c list) ! (i - 2 * card (UNIV :: 'c set)))"
  using assms by (simp add: buf_lin_at_def case_prod_beta Let_def)

text ‹Per-block determination from window reads over the block's third.›

lemma buf_left_window:
  fixes b1 b2 :: "(('c :: enum)  'a) × ('c  'a) × ('c  'a)"
  assumes "i < card (UNIV :: 'c set). buf_lin_at b1 i = buf_lin_at b2 i"
  shows "fst b1 = fst b2"
proof (rule ext)
  fix x :: 'c
  have idx: "c_idx x < card (UNIV :: 'c set)" by (rule c_idx_lt_card)
  have "fst b1 x = buf_lin_at b1 (c_idx x)"
    using idx by (simp add: buf_lin_at_l c_idx_in_range(2))
  also have " = buf_lin_at b2 (c_idx x)" using assms idx by blast
  also have " = fst b2 x"
    using idx by (simp add: buf_lin_at_l c_idx_in_range(2))
  finally show "fst b1 x = fst b2 x" .
qed

lemma buf_home_window:
  fixes b1 b2 :: "(('c :: enum)  'a) × ('c  'a) × ('c  'a)"
  assumes "i. card (UNIV :: 'c set)  i  i < 2 * card (UNIV :: 'c set)
                  buf_lin_at b1 i = buf_lin_at b2 i"
  shows "fst (snd b1) = fst (snd b2)"
proof (rule ext)
  fix x :: 'c
  let ?c = "card (UNIV :: 'c set)"
  have idx: "c_idx x < ?c" by (rule c_idx_lt_card)
  have lo: "?c  ?c + c_idx x" by simp
  have hi: "?c + c_idx x < 2 * ?c" using idx by linarith
  have "fst (snd b1) x = buf_lin_at b1 (?c + c_idx x)"
    using lo hi by (simp add: buf_lin_at_h c_idx_in_range(2))
  also have " = buf_lin_at b2 (?c + c_idx x)" using assms lo hi by blast
  also have " = fst (snd b2) x"
    using lo hi by (simp add: buf_lin_at_h c_idx_in_range(2))
  finally show "fst (snd b1) x = fst (snd b2) x" .
qed

lemma buf_right_window:
  fixes b1 b2 :: "(('c :: enum)  'a) × ('c  'a) × ('c  'a)"
  assumes "i. 2 * card (UNIV :: 'c set)  i  i < 3 * card (UNIV :: 'c set)
                  buf_lin_at b1 i = buf_lin_at b2 i"
  shows "snd (snd b1) = snd (snd b2)"
proof (rule ext)
  fix x :: 'c
  let ?c = "card (UNIV :: 'c set)"
  have idx: "c_idx x < ?c" by (rule c_idx_lt_card)
  have lo: "2 * ?c  2 * ?c + c_idx x" by simp
  have hi: "2 * ?c + c_idx x < 3 * ?c" using idx by linarith
  have "snd (snd b1) x = buf_lin_at b1 (2 * ?c + c_idx x)"
    using lo hi by (simp add: buf_lin_at_r c_idx_in_range(2))
  also have " = buf_lin_at b2 (2 * ?c + c_idx x)" using assms lo hi by blast
  also have " = snd (snd b2) x"
    using lo hi by (simp add: buf_lin_at_r c_idx_in_range(2))
  finally show "snd (snd b1) x = snd (snd b2) x" .
qed

text ‹Full-window inversion (pos ≥ 2›): the head and the window
  together determine both the boundary position and the buffer.›

lemma ae_window_invariant_determines:
  fixes tM :: "nat  'a"
  assumes h1: "ae_window_invariant tM nM bp1 b1 p_start"
      and h2: "ae_window_invariant tM nM bp2 b2 p_start"
  shows "bp1 = (bp2 :: ('c :: enum) bp)  b1 = b2"
proof
  from h1 h2 have "nM = p_start + bp_linear bp1" "nM = p_start + bp_linear bp2"
    unfolding ae_window_invariant_def by simp_all
  hence "bp_linear bp1 = bp_linear bp2" by simp
  thus "bp1 = bp2" by (rule bp_linear_inj)
next
  from h1 h2 have
      "i < 3 * card (UNIV :: 'c set). tM (p_start + i) = buf_lin_at b1 i"
      "i < 3 * card (UNIV :: 'c set). tM (p_start + i) = buf_lin_at b2 i"
    unfolding ae_window_invariant_def by simp_all
  hence "i < 3 * card (UNIV :: 'c set). buf_lin_at b1 i = buf_lin_at b2 i" by simp
  thus "b1 = b2" by (rule buf_window_determines)
qed

text ‹Boundary-position bp› inversions: the head nM› determines
  the position even in the pos = 1› / pos = 0› cases, where the
  encoding is a direction-case rather than a single bp_linear›
  equation.  The three directions still land nM› in disjoint ranges.›

lemma bp_le1_inj:
  fixes bp1 bp2 :: "('c :: enum) bp" and nM :: nat
  assumes A1: "case fst bp1 of AE_Left  snd bp1 = c_last  nM = 0
                 | AE_Home  nM = Suc (c_idx (snd bp1))
                 | AE_Right  nM = Suc (card (UNIV :: 'c set) + c_idx (snd bp1))"
      and A2: "case fst bp2 of AE_Left  snd bp2 = c_last  nM = 0
                 | AE_Home  nM = Suc (c_idx (snd bp2))
                 | AE_Right  nM = Suc (card (UNIV :: 'c set) + c_idx (snd bp2))"
  shows "bp1 = bp2"
proof -
  obtain d1 x1 where p1: "bp1 = (d1, x1)" by (cases bp1)
  obtain d2 x2 where p2: "bp2 = (d2, x2)" by (cases bp2)
  have b1: "c_idx x1 < card (UNIV :: 'c set)" by (rule c_idx_lt_card)
  have b2: "c_idx x2 < card (UNIV :: 'c set)" by (rule c_idx_lt_card)
  have "d1 = d2  x1 = x2"
    using A1[unfolded p1] A2[unfolded p2] b1 b2
    by (cases d1; cases d2; simp; (linarith | blast intro: c_idx_inj))
  thus ?thesis using p1 p2 by simp
qed

text ‹Full inversion at pos = 1›: every direction constrains the
  cell here, so the head pins bp›; the window plus the fixed left
  block (LE_block le›) pin all three blocks.›

lemma ae_window_invariant_le1_determines:
  fixes tM :: "nat  'a"
  assumes h1: "ae_window_invariant_le1 tM nM bp1 b1 le"
      and h2: "ae_window_invariant_le1 tM nM bp2 b2 le"
  shows "bp1 = (bp2 :: ('c :: enum) bp)  b1 = b2"
proof -
  let ?c = "card (UNIV :: 'c set)"
  have a1: "case fst bp1 of AE_Left  snd bp1 = c_last  nM = 0
              | AE_Home  nM = Suc (c_idx (snd bp1))
              | AE_Right  nM = Suc (?c + c_idx (snd bp1))"
    using h1 unfolding ae_window_invariant_le1_def by simp
  have a2: "case fst bp2 of AE_Left  snd bp2 = c_last  nM = 0
              | AE_Home  nM = Suc (c_idx (snd bp2))
              | AE_Right  nM = Suc (?c + c_idx (snd bp2))"
    using h2 unfolding ae_window_invariant_le1_def by simp
  have bp: "bp1 = bp2" by (rule bp_le1_inj[OF a1 a2])
  have lefts: "fst b1 = LE_block le" "fst b2 = LE_block le"
    using h1 h2 unfolding ae_window_invariant_le1_def by simp_all
  have e1: "i<2 * ?c. tM (Suc i) = buf_lin_at b1 (?c + i)"
    using h1 unfolding ae_window_invariant_le1_def by simp
  have e2: "i<2 * ?c. tM (Suc i) = buf_lin_at b2 (?c + i)"
    using h2 unfolding ae_window_invariant_le1_def by simp
  have home: "fst (snd b1) = fst (snd b2)"
  proof (rule buf_home_window, intro allI impI)
    fix i assume "?c  i  i < 2 * ?c"
    then have i1: "?c  i" and i2: "i < 2 * ?c" by auto
    from i2 have lt: "i - ?c < 2 * ?c" by linarith
    from i1 have eq: "?c + (i - ?c) = i" by linarith
    from e1 lt have "tM (Suc (i - ?c)) = buf_lin_at b1 (?c + (i - ?c))" by blast
    with eq have A: "tM (Suc (i - ?c)) = buf_lin_at b1 i" by simp
    from e2 lt have "tM (Suc (i - ?c)) = buf_lin_at b2 (?c + (i - ?c))" by blast
    with eq have B: "tM (Suc (i - ?c)) = buf_lin_at b2 i" by simp
    from A B show "buf_lin_at b1 i = buf_lin_at b2 i" by simp
  qed
  have right: "snd (snd b1) = snd (snd b2)"
  proof (rule buf_right_window, intro allI impI)
    fix i assume "2 * ?c  i  i < 3 * ?c"
    then have i1: "2 * ?c  i" and i2: "i < 3 * ?c" by auto
    from i2 have lt: "i - ?c < 2 * ?c" by linarith
    from i1 have eq: "?c + (i - ?c) = i" by linarith
    from e1 lt have "tM (Suc (i - ?c)) = buf_lin_at b1 (?c + (i - ?c))" by blast
    with eq have A: "tM (Suc (i - ?c)) = buf_lin_at b1 i" by simp
    from e2 lt have "tM (Suc (i - ?c)) = buf_lin_at b2 (?c + (i - ?c))" by blast
    with eq have B: "tM (Suc (i - ?c)) = buf_lin_at b2 i" by simp
    from A B show "buf_lin_at b1 i = buf_lin_at b2 i" by simp
  qed
  have "b1 = b2" using lefts home right by (cases b1; cases b2) auto
  with bp show ?thesis by simp
qed

text ‹General window inversion (all pos›).  The home and right
  blocks are determined by the tape window at every pos›.  For
  pos ≠ 0› the boundary position bp› and the whole buffer are
  determined.  At pos = 0› the left block and the home offset of
  bp› are off-trace (the absent left neighbour of the endmarker, and
  AE_Home ⟹ nM = 0› says nothing of the cell); they are carried from
  the source by the buffered simulation, not pinned by the window.›

lemma ae_window_invariant_general_determines:
  fixes tM :: "nat  'a"
  assumes h1: "ae_window_invariant_general tM nM bp1 b1 pos le"
      and h2: "ae_window_invariant_general tM nM bp2 b2 pos le"
  shows "fst (snd b1) = fst (snd (b2 :: (('c :: enum)  'a) × ('c  'a) × ('c  'a)))
          snd (snd b1) = snd (snd b2)
          (pos  0  bp1 = bp2  b1 = b2)"
proof (cases "pos  2")
  case True
  have w1: "ae_window_invariant tM nM bp1 b1 ((pos - 2) * card (UNIV :: 'c set) + 1)"
    using h1 True unfolding ae_window_invariant_general_def by simp
  have w2: "ae_window_invariant tM nM bp2 b2 ((pos - 2) * card (UNIV :: 'c set) + 1)"
    using h2 True unfolding ae_window_invariant_general_def by simp
  from ae_window_invariant_determines[OF w1 w2]
  have "bp1 = bp2" and "b1 = b2" by simp_all
  thus ?thesis by simp
next
  case False
  show ?thesis
  proof (cases "pos = 1")
    case True
    have l1: "ae_window_invariant_le1 tM nM bp1 b1 le"
      using h1 True unfolding ae_window_invariant_general_def by simp
    have l2: "ae_window_invariant_le1 tM nM bp2 b2 le"
      using h2 True unfolding ae_window_invariant_general_def by simp
    from ae_window_invariant_le1_determines[OF l1 l2]
    have "bp1 = bp2" and "b1 = b2" by simp_all
    thus ?thesis by simp
  next
    case False
    with ¬ 2  pos have pos0: "pos = 0" by simp
    have l1: "ae_window_invariant_le0 tM nM bp1 b1 le"
      using h1 pos0 unfolding ae_window_invariant_general_def by simp
    have l2: "ae_window_invariant_le0 tM nM bp2 b2 le"
      using h2 pos0 unfolding ae_window_invariant_general_def by simp
    let ?c = "card (UNIV :: 'c set)"
    have homes: "fst (snd b1) = LE_block le" "fst (snd b2) = LE_block le"
      using l1 l2 unfolding ae_window_invariant_le0_def by simp_all
    have f1: "i<?c. tM (Suc i) = buf_lin_at b1 (2 * ?c + i)"
      using l1 unfolding ae_window_invariant_le0_def by simp
    have f2: "i<?c. tM (Suc i) = buf_lin_at b2 (2 * ?c + i)"
      using l2 unfolding ae_window_invariant_le0_def by simp
    have right: "snd (snd b1) = snd (snd b2)"
    proof (rule buf_right_window, intro allI impI)
      fix i assume "2 * ?c  i  i < 3 * ?c"
      then have i1: "2 * ?c  i" and i2: "i < 3 * ?c" by auto
      from i2 have lt: "i - 2 * ?c < ?c" by linarith
      from i1 have eq: "2 * ?c + (i - 2 * ?c) = i" by linarith
      from f1 lt have "tM (Suc (i - 2 * ?c)) = buf_lin_at b1 (2 * ?c + (i - 2 * ?c))" by blast
      with eq have A: "tM (Suc (i - 2 * ?c)) = buf_lin_at b1 i" by simp
      from f2 lt have "tM (Suc (i - 2 * ?c)) = buf_lin_at b2 (2 * ?c + (i - 2 * ?c))" by blast
      with eq have B: "tM (Suc (i - 2 * ?c)) = buf_lin_at b2 i" by simp
      from A B show "buf_lin_at b1 i = buf_lin_at b2 i" by simp
    qed
    from homes right pos0 show ?thesis by auto
  qed
qed

text ‹Per-tape lift of the window inversion: across the active tapes
  k < K›, two buffered outputs that both window-correspond to the
  same per-tape trace endpoint agree on the home + right blocks at
  every pos›, and fully (boundary position and whole buffer) where
  pos k ≠ 0›.  This is the form consumed by the config-level
  SS4→›SS5 inversion: the SS4→›SS5 state's per-tape buffer / boundary
  components are exactly such families.›

lemma ae_window_general_indexed_determines:
  fixes tM :: "nat  nat  'a" and nM pos :: "nat  nat"
    and bp1 bp2 :: "nat  ('c :: enum) bp"
    and b1 b2 :: "nat  (('c  'a) × ('c  'a) × ('c  'a))"
    and le :: 'a and K :: nat
  assumes h1: "k<K. ae_window_invariant_general (tM k) (nM k)
                          (bp1 k) (b1 k) (pos k) le"
      and h2: "k<K. ae_window_invariant_general (tM k) (nM k)
                          (bp2 k) (b2 k) (pos k) le"
  shows "k<K. fst (snd (b1 k)) = fst (snd (b2 k))
               snd (snd (b1 k)) = snd (snd (b2 k))
               (pos k  0  bp1 k = bp2 k  b1 k = b2 k)"
proof (intro allI impI)
  fix k assume k: "k < K"
  from h1 k have g1: "ae_window_invariant_general (tM k) (nM k)
                          (bp1 k) (b1 k) (pos k) le" by blast
  from h2 k have g2: "ae_window_invariant_general (tM k) (nM k)
                          (bp2 k) (b2 k) (pos k) le" by blast
  show "fst (snd (b1 k)) = fst (snd (b2 k))
           snd (snd (b1 k)) = snd (snd (b2 k))
           (pos k  0  bp1 k = bp2 k  b1 k = b2 k)"
    by (rule ae_window_invariant_general_determines[OF g1 g2])
qed

subsubsection ‹SS4→›SS5 trace-functional›

text ‹The det-free replacement for ae_delta_ss4_ss5_functional›.
  The SS4→›SS5 macro-step's nondeterminism is confined to the state's
  buffer / boundary-position components (the m_steps_buffered›
  witness); the tape and head movements are functions of the source
  alone.  This first lemma isolates that: two SS4→›SS5 steps from a
  ‹common› source have identical tape and identical head positions,
  unconditionally (no trace correspondence needed).

  Reading the ae_delta_ss4_ss5› definition: the write symbol equals
  the read symbol (the step rewrites nothing, it only moves heads), and
  the per-tape direction d› is if a k = LE_block le then N else L›
  on active tapes and N› beyond the tape count --- a function of the read
  tuple a = λk. ts k (n k)›, which the shared source fixes.›

lemma ae_ss4_ss5_shared_source_tape:
  fixes M :: "('q, 'a) mttm"
    and c4 c5a c5b :: "('c :: enum  'a,
                        'q × ('a, 'c) ae_stage) mt_config"
  assumes stepa: "(c4, c5a)  mttm_step (ae_delta_ss4_ss5 M)"
      and stepb: "(c4, c5b)  mttm_step (ae_delta_ss4_ss5 M)"
  shows "mt_tape c5a = mt_tape c5b  mt_pos c5a = mt_pos c5b"
proof -
  obtain s ts n where c4_eq: "c4 = ConfigM s ts n" by (cases c4)
  from stepa c4_eq obtain s'a a'a da where
      a_eq: "c5a = ConfigM s'a (λk. (ts k)(n k := a'a k))
                                 (λk. go_dir (da k) (n k))"
    and rela: "(s, (λk. ts k (n k)), s'a, a'a, da)  ae_delta_ss4_ss5 M"
    by (auto elim: mttm_step.cases)
  from stepb c4_eq obtain s'b a'b db where
      b_eq: "c5b = ConfigM s'b (λk. (ts k)(n k := a'b k))
                                 (λk. go_dir (db k) (n k))"
    and relb: "(s, (λk. ts k (n k)), s'b, a'b, db)  ae_delta_ss4_ss5 M"
    by (auto elim: mttm_step.cases)
  ― ‹Write equals read and direction is canonical in the read, for
      both steps; hence both match the shared source.›
  have wa: "a'a = (λk. ts k (n k))"
   and dda: "da = (λk. if k < k_tm M
                          then (if ts k (n k) = LE_block (le_tm M)
                                  then dir.N else dir.L)
                          else dir.N)"
    using rela unfolding ae_delta_ss4_ss5_def by auto
  have wb: "a'b = (λk. ts k (n k))"
   and ddb: "db = (λk. if k < k_tm M
                          then (if ts k (n k) = LE_block (le_tm M)
                                  then dir.N else dir.L)
                          else dir.N)"
    using relb unfolding ae_delta_ss4_ss5_def by auto
  show ?thesis using a_eq b_eq wa dda wb ddb by simp
qed

subsubsection ‹SS5→›SS8 blindness to the pos=0 residual›

text ‹At pos = 0› the home block is uniformly LE_block le›
  (= (λ_. le)›; window le0›).  Every SS5→›SS8 action then routes
  through its h = LE_block le› branch, which reads only the current
  cell a›, the right block r›, and the boundary direction ds› ---
  never the left block l›.  And the actions never take the boundary
  ‹offset› as an argument at all.  So the two components the window
  inversion leaves free at pos = 0› (the left block and the
  AE_Home› offset) are invisible to SS5→›SS8: no source-carrying
  induction is needed.›

lemma ae_ss5_action_indep_left:
  "ae_ss5_action le a (l, LE_block le, r) ds
     = ae_ss5_action le a (l', LE_block le, r) ds"
  by simp

lemma ae_ss6_action_indep_left:
  "ae_ss6_action le a (l, LE_block le, r) ds
     = ae_ss6_action le a (l', LE_block le, r) ds"
  by simp

lemma ae_ss7_action_indep_left:
  "ae_ss7_action le a (l, LE_block le, r) ds
     = ae_ss7_action le a (l', LE_block le, r) ds"
  by simp

lemma ae_ss8_action_indep_left:
  "ae_ss8_action le a (l, LE_block le, r) ds
     = ae_ss8_action le a (l', LE_block le, r) ds"
  by simp

text ‹The boundary ‹direction› (the dest› the actions read) does
  agree at pos = 0›: against a fixed head nM›, le0› determines
  fst bp› (AE_Home› iff nM = 0›, else AE_Right›; never
  AE_Left›), and the whole bp› except the AE_Home› offset (the
  one genuine pos=0 don't-care).›

lemma ae_window_le0_dest_agree:
  fixes bp1 bp2 :: "('c :: enum) bp"
  assumes h1: "ae_window_invariant_le0 tM nM bp1 b1 le"
      and h2: "ae_window_invariant_le0 tM nM bp2 b2 le"
  shows "fst bp1 = fst bp2  (fst bp1  AE_Home  bp1 = bp2)"
proof -
  obtain d1 x1 where p1: "bp1 = (d1, x1)" by (cases bp1)
  obtain d2 x2 where p2: "bp2 = (d2, x2)" by (cases bp2)
  have key1: "(d1 = AE_Home  nM = 0)
                 (d1 = AE_Right  nM = Suc (c_idx x1))  d1  AE_Left"
    using h1[unfolded ae_window_invariant_le0_def p1] by (cases d1) auto
  have key2: "(d2 = AE_Home  nM = 0)
                 (d2 = AE_Right  nM = Suc (c_idx x2))  d2  AE_Left"
    using h2[unfolded ae_window_invariant_le0_def p2] by (cases d2) auto
  have dir: "d1 = d2"
  proof (cases "nM = 0")
    case True
    have "d1 = AE_Home" using key1 True by (cases d1) auto
    moreover have "d2 = AE_Home" using key2 True by (cases d2) auto
    ultimately show ?thesis by simp
  next
    case False
    have "d1 = AE_Right" using key1 False by (cases d1) auto
    moreover have "d2 = AE_Right" using key2 False by (cases d2) auto
    ultimately show ?thesis by simp
  qed
  have full: "d1  AE_Home  x1 = x2"
  proof
    assume nh: "d1  AE_Home"
    have r1: "d1 = AE_Right" using key1 nh by (cases d1) auto
    have "nM = Suc (c_idx x1)" using key1 r1 by simp
    moreover have "nM = Suc (c_idx x2)" using key2 dir r1 by simp
    ultimately have "c_idx x1 = c_idx x2" by simp
    thus "x1 = x2" by (rule c_idx_inj)
  qed
  show ?thesis using dir full p1 p2 by simp
qed

text ‹The per-block agreement the SS5→›SS8 actions are congruent under:
  home and right blocks agree, and the left block agrees ‹where the
  home block is not› LE_block le› (at the LE_block› home --- the
  pos=0 case --- the actions never read the left block, so it may
  differ).  Both clauses are delivered at every tape by the window
  inversion + le0›.›

definition ae_blk_agree ::
  "'a  (('c :: enum  'a) × ('c  'a) × ('c  'a))
        (('c  'a) × ('c  'a) × ('c  'a))  bool" where
  "ae_blk_agree le b1 b2 
     fst (snd b1) = fst (snd b2)
      snd (snd b1) = snd (snd b2)
      (fst (snd b1)  LE_block le  fst b1 = fst b2)"

lemma ae_blk_agree_action_eq:
  assumes "ae_blk_agree le b1 b2"
  shows "b1 = b2  (fst (snd b1) = LE_block le  fst (snd b2) = LE_block le
                       snd (snd b1) = snd (snd b2))"
proof (cases "fst (snd b1) = LE_block le")
  case False
  hence "fst b1 = fst b2" using assms unfolding ae_blk_agree_def by simp
  moreover have "fst (snd b1) = fst (snd b2)" "snd (snd b1) = snd (snd b2)"
    using assms unfolding ae_blk_agree_def by simp_all
  ultimately have "b1 = b2" by (cases b1; cases b2) auto
  thus ?thesis by simp
next
  case True
  thus ?thesis using assms unfolding ae_blk_agree_def by simp
qed

lemma ae_ss5_action_cong:
  assumes "ae_blk_agree le b1 b2"
  shows "ae_ss5_action le a b1 ds = ae_ss5_action le a b2 ds"
  using ae_blk_agree_action_eq[OF assms]
proof
  assume "b1 = b2" thus ?thesis by simp
next
  assume "fst (snd b1) = LE_block le  fst (snd b2) = LE_block le
             snd (snd b1) = snd (snd b2)"
  thus ?thesis
    by (cases b1; cases b2)
       (simp add: ae_ss5_action_indep_left)
qed

lemma ae_ss6_action_cong:
  assumes "ae_blk_agree le b1 b2"
  shows "ae_ss6_action le a b1 ds = ae_ss6_action le a b2 ds"
  using ae_blk_agree_action_eq[OF assms]
proof
  assume "b1 = b2" thus ?thesis by simp
next
  assume "fst (snd b1) = LE_block le  fst (snd b2) = LE_block le
             snd (snd b1) = snd (snd b2)"
  thus ?thesis
    by (cases b1; cases b2)
       (simp add: ae_ss6_action_indep_left)
qed

lemma ae_ss7_action_cong:
  assumes "ae_blk_agree le b1 b2"
  shows "ae_ss7_action le a b1 ds = ae_ss7_action le a b2 ds"
  using ae_blk_agree_action_eq[OF assms]
proof
  assume "b1 = b2" thus ?thesis by simp
next
  assume "fst (snd b1) = LE_block le  fst (snd b2) = LE_block le
             snd (snd b1) = snd (snd b2)"
  thus ?thesis
    by (cases b1; cases b2)
       (simp add: ae_ss7_action_indep_left)
qed

lemma ae_ss8_action_cong:
  assumes "ae_blk_agree le b1 b2"
  shows "ae_ss8_action le a b1 ds = ae_ss8_action le a b2 ds"
  using ae_blk_agree_action_eq[OF assms]
proof
  assume "b1 = b2" thus ?thesis by simp
next
  assume "fst (snd b1) = LE_block le  fst (snd b2) = LE_block le
             snd (snd b1) = snd (snd b2)"
  thus ?thesis
    by (cases b1; cases b2)
       (simp add: ae_ss8_action_indep_left)
qed

text ‹Config-level SS5→›SS6 congruence: two configs that agree on
  tape, head positions, state q› and dest›, and whose buffers
  are ae_blk_agree› per tape (offsets / buffers may otherwise differ),
  take an SS5→›SS6 step to configs that again agree on tape and head
  positions, with the state advanced to SS6 and q› / buf› / dest›
  carried unchanged.  The reads coincide (tape + pos equal), so the
  action-congruence makes the writes and moves coincide.›

lemma ae_ss5_ss6_cong:
  fixes M :: "('q, 'a) mttm"
    and c1 c2 c1' c2' :: "('c :: enum  'a,
                           'q × ('a, 'c) ae_stage) mt_config"
  assumes tape: "mt_tape c1 = mt_tape c2"
      and pos:  "mt_pos c1 = mt_pos c2"
      and st1:  "mt_state c1 = (q, ofs1, buf1, dest, SS5)"
      and st2:  "mt_state c2 = (q, ofs2, buf2, dest, SS5)"
      and blk:  "k. ae_blk_agree (le_tm M) (buf1 k) (buf2 k)"
      and s1:   "(c1, c1')  mttm_step (ae_delta_ss5_ss6 M)"
      and s2:   "(c2, c2')  mttm_step (ae_delta_ss5_ss6 M)"
  shows "mt_tape c1' = mt_tape c2'  mt_pos c1' = mt_pos c2'
          mt_state c1' = (q, ofs1, buf1, dest, SS6)
          mt_state c2' = (q, ofs2, buf2, dest, SS6)"
proof -
  obtain ts n where c1d: "c1 = ConfigM (q, ofs1, buf1, dest, SS5) ts n"
    using st1 by (cases c1) auto
  have c2d: "c2 = ConfigM (q, ofs2, buf2, dest, SS5) ts n"
    using st2 tape pos c1d by (cases c2) auto
  from s1[unfolded c1d] obtain s1' a'1 d1 where
      c1'd: "c1' = ConfigM s1' (λk. (ts k)(n k := a'1 k))
                                 (λk. go_dir (d1 k) (n k))"
    and rel1: "((q, ofs1, buf1, dest, SS5), (λk. ts k (n k)),
                s1', a'1, d1)  ae_delta_ss5_ss6 M"
    by (auto elim: mttm_step.cases)
  from s2[unfolded c2d] obtain s2' a'2 d2 where
      c2'd: "c2' = ConfigM s2' (λk. (ts k)(n k := a'2 k))
                                 (λk. go_dir (d2 k) (n k))"
    and rel2: "((q, ofs2, buf2, dest, SS5), (λk. ts k (n k)),
                s2', a'2, d2)  ae_delta_ss5_ss6 M"
    by (auto elim: mttm_step.cases)
  have e1: "s1' = (q, ofs1, buf1, dest, SS6)"
    and a1: "a'1 = (λk. if k < k_tm M
                          then fst (ae_ss5_action (le_tm M) (ts k (n k))
                                      (buf1 k) (dest k))
                          else bl_block (bl_tm M))"
    and d1: "d1 = (λk. if k < k_tm M
                          then snd (ae_ss5_action (le_tm M) (ts k (n k))
                                      (buf1 k) (dest k))
                          else dir.N)"
    using rel1 unfolding ae_delta_ss5_ss6_def by auto
  have e2: "s2' = (q, ofs2, buf2, dest, SS6)"
    and a2: "a'2 = (λk. if k < k_tm M
                          then fst (ae_ss5_action (le_tm M) (ts k (n k))
                                      (buf2 k) (dest k))
                          else bl_block (bl_tm M))"
    and d2: "d2 = (λk. if k < k_tm M
                          then snd (ae_ss5_action (le_tm M) (ts k (n k))
                                      (buf2 k) (dest k))
                          else dir.N)"
    using rel2 unfolding ae_delta_ss5_ss6_def by auto
  have act: "k. ae_ss5_action (le_tm M) (ts k (n k)) (buf1 k) (dest k)
                  = ae_ss5_action (le_tm M) (ts k (n k)) (buf2 k) (dest k)"
    by (rule ae_ss5_action_cong[OF blk[rule_format]])
  have "a'1 = a'2"
    by (rule ext) (simp add: a1 a2 act)
  moreover have "d1 = d2"
    by (rule ext) (simp add: d1 d2 act)
  ultimately show ?thesis using c1'd c2'd e1 e2 by simp
qed

lemma ae_ss6_ss7_cong:
  fixes M :: "('q, 'a) mttm"
    and c1 c2 c1' c2' :: "('c :: enum  'a,
                           'q × ('a, 'c) ae_stage) mt_config"
  assumes tape: "mt_tape c1 = mt_tape c2"
      and pos:  "mt_pos c1 = mt_pos c2"
      and st1:  "mt_state c1 = (q, ofs1, buf1, dest, SS6)"
      and st2:  "mt_state c2 = (q, ofs2, buf2, dest, SS6)"
      and blk:  "k. ae_blk_agree (le_tm M) (buf1 k) (buf2 k)"
      and s1:   "(c1, c1')  mttm_step (ae_delta_ss6_ss7 M)"
      and s2:   "(c2, c2')  mttm_step (ae_delta_ss6_ss7 M)"
  shows "mt_tape c1' = mt_tape c2'  mt_pos c1' = mt_pos c2'
          mt_state c1' = (q, ofs1, buf1, dest, SS7)
          mt_state c2' = (q, ofs2, buf2, dest, SS7)"
proof -
  obtain ts n where c1d: "c1 = ConfigM (q, ofs1, buf1, dest, SS6) ts n"
    using st1 by (cases c1) auto
  have c2d: "c2 = ConfigM (q, ofs2, buf2, dest, SS6) ts n"
    using st2 tape pos c1d by (cases c2) auto
  from s1[unfolded c1d] obtain s1' a'1 d1 where
      c1'd: "c1' = ConfigM s1' (λk. (ts k)(n k := a'1 k))
                                 (λk. go_dir (d1 k) (n k))"
    and rel1: "((q, ofs1, buf1, dest, SS6), (λk. ts k (n k)),
                s1', a'1, d1)  ae_delta_ss6_ss7 M"
    by (auto elim: mttm_step.cases)
  from s2[unfolded c2d] obtain s2' a'2 d2 where
      c2'd: "c2' = ConfigM s2' (λk. (ts k)(n k := a'2 k))
                                 (λk. go_dir (d2 k) (n k))"
    and rel2: "((q, ofs2, buf2, dest, SS6), (λk. ts k (n k)),
                s2', a'2, d2)  ae_delta_ss6_ss7 M"
    by (auto elim: mttm_step.cases)
  have e1: "s1' = (q, ofs1, buf1, dest, SS7)"
    and a1: "a'1 = (λk. if k < k_tm M
                          then fst (ae_ss6_action (le_tm M) (ts k (n k))
                                      (buf1 k) (dest k))
                          else bl_block (bl_tm M))"
    and d1: "d1 = (λk. if k < k_tm M
                          then snd (ae_ss6_action (le_tm M) (ts k (n k))
                                      (buf1 k) (dest k))
                          else dir.N)"
    using rel1 unfolding ae_delta_ss6_ss7_def by auto
  have e2: "s2' = (q, ofs2, buf2, dest, SS7)"
    and a2: "a'2 = (λk. if k < k_tm M
                          then fst (ae_ss6_action (le_tm M) (ts k (n k))
                                      (buf2 k) (dest k))
                          else bl_block (bl_tm M))"
    and d2: "d2 = (λk. if k < k_tm M
                          then snd (ae_ss6_action (le_tm M) (ts k (n k))
                                      (buf2 k) (dest k))
                          else dir.N)"
    using rel2 unfolding ae_delta_ss6_ss7_def by auto
  have act: "k. ae_ss6_action (le_tm M) (ts k (n k)) (buf1 k) (dest k)
                  = ae_ss6_action (le_tm M) (ts k (n k)) (buf2 k) (dest k)"
    by (rule ae_ss6_action_cong[OF blk[rule_format]])
  have "a'1 = a'2"
    by (rule ext) (simp add: a1 a2 act)
  moreover have "d1 = d2"
    by (rule ext) (simp add: d1 d2 act)
  ultimately show ?thesis using c1'd c2'd e1 e2 by simp
qed

lemma ae_ss7_ss8_cong:
  fixes M :: "('q, 'a) mttm"
    and c1 c2 c1' c2' :: "('c :: enum  'a,
                           'q × ('a, 'c) ae_stage) mt_config"
  assumes tape: "mt_tape c1 = mt_tape c2"
      and pos:  "mt_pos c1 = mt_pos c2"
      and st1:  "mt_state c1 = (q, ofs1, buf1, dest, SS7)"
      and st2:  "mt_state c2 = (q, ofs2, buf2, dest, SS7)"
      and blk:  "k. ae_blk_agree (le_tm M) (buf1 k) (buf2 k)"
      and s1:   "(c1, c1')  mttm_step (ae_delta_ss7_ss8 M)"
      and s2:   "(c2, c2')  mttm_step (ae_delta_ss7_ss8 M)"
  shows "mt_tape c1' = mt_tape c2'  mt_pos c1' = mt_pos c2'
          mt_state c1' = (q, ofs1, buf1, dest, SS8)
          mt_state c2' = (q, ofs2, buf2, dest, SS8)"
proof -
  obtain ts n where c1d: "c1 = ConfigM (q, ofs1, buf1, dest, SS7) ts n"
    using st1 by (cases c1) auto
  have c2d: "c2 = ConfigM (q, ofs2, buf2, dest, SS7) ts n"
    using st2 tape pos c1d by (cases c2) auto
  from s1[unfolded c1d] obtain s1' a'1 d1 where
      c1'd: "c1' = ConfigM s1' (λk. (ts k)(n k := a'1 k))
                                 (λk. go_dir (d1 k) (n k))"
    and rel1: "((q, ofs1, buf1, dest, SS7), (λk. ts k (n k)),
                s1', a'1, d1)  ae_delta_ss7_ss8 M"
    by (auto elim: mttm_step.cases)
  from s2[unfolded c2d] obtain s2' a'2 d2 where
      c2'd: "c2' = ConfigM s2' (λk. (ts k)(n k := a'2 k))
                                 (λk. go_dir (d2 k) (n k))"
    and rel2: "((q, ofs2, buf2, dest, SS7), (λk. ts k (n k)),
                s2', a'2, d2)  ae_delta_ss7_ss8 M"
    by (auto elim: mttm_step.cases)
  have e1: "s1' = (q, ofs1, buf1, dest, SS8)"
    and a1: "a'1 = (λk. if k < k_tm M
                          then fst (ae_ss7_action (le_tm M) (ts k (n k))
                                      (buf1 k) (dest k))
                          else bl_block (bl_tm M))"
    and d1: "d1 = (λk. if k < k_tm M
                          then snd (ae_ss7_action (le_tm M) (ts k (n k))
                                      (buf1 k) (dest k))
                          else dir.N)"
    using rel1 unfolding ae_delta_ss7_ss8_def by auto
  have e2: "s2' = (q, ofs2, buf2, dest, SS8)"
    and a2: "a'2 = (λk. if k < k_tm M
                          then fst (ae_ss7_action (le_tm M) (ts k (n k))
                                      (buf2 k) (dest k))
                          else bl_block (bl_tm M))"
    and d2: "d2 = (λk. if k < k_tm M
                          then snd (ae_ss7_action (le_tm M) (ts k (n k))
                                      (buf2 k) (dest k))
                          else dir.N)"
    using rel2 unfolding ae_delta_ss7_ss8_def by auto
  have act: "k. ae_ss7_action (le_tm M) (ts k (n k)) (buf1 k) (dest k)
                  = ae_ss7_action (le_tm M) (ts k (n k)) (buf2 k) (dest k)"
    by (rule ae_ss7_action_cong[OF blk[rule_format]])
  have "a'1 = a'2"
    by (rule ext) (simp add: a1 a2 act)
  moreover have "d1 = d2"
    by (rule ext) (simp add: d1 d2 act)
  ultimately show ?thesis using c1'd c2'd e1 e2 by simp
qed

text ‹The closing SS8→›SS1 step also resets dest› to init_dest›
  and the substep index to SS1› (non-halt branch, q ∉ {t, r}› ---
  the case the reverse arm runs in).  Otherwise as before: the action
  is congruent under ae_blk_agree›, so tape and head positions
  coincide, and q› / ofs› / buf› are carried.›

lemma ae_ss8_ss1_cong:
  fixes M :: "('q, 'a) mttm"
    and c1 c2 c1' c2' :: "('c :: enum  'a,
                           'q × ('a, 'c) ae_stage) mt_config"
  assumes tape: "mt_tape c1 = mt_tape c2"
      and pos:  "mt_pos c1 = mt_pos c2"
      and st1:  "mt_state c1 = (q, ofs1, buf1, dest, SS8)"
      and st2:  "mt_state c2 = (q, ofs2, buf2, dest, SS8)"
      and blk:  "k. ae_blk_agree (le_tm M) (buf1 k) (buf2 k)"
      and qnh:  "q  {t_tm M, r_tm M}"
      and s1:   "(c1, c1')  mttm_step (ae_delta_ss8_ss1 M)"
      and s2:   "(c2, c2')  mttm_step (ae_delta_ss8_ss1 M)"
  shows "mt_tape c1' = mt_tape c2'  mt_pos c1' = mt_pos c2'
          mt_state c1' = (q, ofs1, buf1, init_dest, SS1)
          mt_state c2' = (q, ofs2, buf2, init_dest, SS1)"
proof -
  obtain ts n where c1d: "c1 = ConfigM (q, ofs1, buf1, dest, SS8) ts n"
    using st1 by (cases c1) auto
  have c2d: "c2 = ConfigM (q, ofs2, buf2, dest, SS8) ts n"
    using st2 tape pos c1d by (cases c2) auto
  from s1[unfolded c1d] obtain s1' a'1 d1 where
      c1'd: "c1' = ConfigM s1' (λk. (ts k)(n k := a'1 k))
                                 (λk. go_dir (d1 k) (n k))"
    and rel1: "((q, ofs1, buf1, dest, SS8), (λk. ts k (n k)),
                s1', a'1, d1)  ae_delta_ss8_ss1 M"
    by (auto elim: mttm_step.cases)
  from s2[unfolded c2d] obtain s2' a'2 d2 where
      c2'd: "c2' = ConfigM s2' (λk. (ts k)(n k := a'2 k))
                                 (λk. go_dir (d2 k) (n k))"
    and rel2: "((q, ofs2, buf2, dest, SS8), (λk. ts k (n k)),
                s2', a'2, d2)  ae_delta_ss8_ss1 M"
    by (auto elim: mttm_step.cases)
  have e1: "s1' = (q, ofs1, buf1, init_dest, SS1)"
    and a1: "a'1 = (λk. if k < k_tm M
                          then fst (ae_ss8_action (le_tm M) (ts k (n k))
                                      (buf1 k) (dest k))
                          else bl_block (bl_tm M))"
    and d1: "d1 = (λk. if k < k_tm M
                          then snd (ae_ss8_action (le_tm M) (ts k (n k))
                                      (buf1 k) (dest k))
                          else dir.N)"
    using rel1 qnh unfolding ae_delta_ss8_ss1_def by auto
  have e2: "s2' = (q, ofs2, buf2, init_dest, SS1)"
    and a2: "a'2 = (λk. if k < k_tm M
                          then fst (ae_ss8_action (le_tm M) (ts k (n k))
                                      (buf2 k) (dest k))
                          else bl_block (bl_tm M))"
    and d2: "d2 = (λk. if k < k_tm M
                          then snd (ae_ss8_action (le_tm M) (ts k (n k))
                                      (buf2 k) (dest k))
                          else dir.N)"
    using rel2 qnh unfolding ae_delta_ss8_ss1_def by auto
  have act: "k. ae_ss8_action (le_tm M) (ts k (n k)) (buf1 k) (dest k)
                  = ae_ss8_action (le_tm M) (ts k (n k)) (buf2 k) (dest k)"
    by (rule ae_ss8_action_cong[OF blk[rule_format]])
  have "a'1 = a'2"
    by (rule ext) (simp add: a1 a2 act)
  moreover have "d1 = d2"
    by (rule ext) (simp add: d1 d2 act)
  ultimately show ?thesis using c1'd c2'd e1 e2 by simp
qed

text ‹Chaining the four congruences through the macro-cycle tail
  SS5→›SS6→›SS7→›SS8→›SS1: two SS5 configs agreeing on tape, head
  positions, q›, dest›, and ae_blk_agree› buffers reach SS1
  boundary configs that agree on tape and head positions, with q› and
  the (still ae_blk_agree›) buffers carried and dest› reset to
  init_dest›.  The buffers are carried unchanged, so the per-tape
  ae_blk_agree› hypothesis is reused verbatim at each step.›

lemma ae_ss5_ss8_segment_cong:
  fixes M :: "('q, 'a) mttm"
    and c5a c5b ca cb :: "('c :: enum  'a,
                           'q × ('a, 'c) ae_stage) mt_config"
  assumes tape: "mt_tape c5a = mt_tape c5b"
      and pos:  "mt_pos c5a = mt_pos c5b"
      and st1:  "mt_state c5a = (q, ofs1, buf1, dest, SS5)"
      and st2:  "mt_state c5b = (q, ofs2, buf2, dest, SS5)"
      and blk:  "k. ae_blk_agree (le_tm M) (buf1 k) (buf2 k)"
      and qnh:  "q  {t_tm M, r_tm M}"
      and a56:  "(c5a, d6a)  mttm_step (ae_delta_ss5_ss6 M)"
      and a67:  "(d6a, d7a)  mttm_step (ae_delta_ss6_ss7 M)"
      and a78:  "(d7a, d8a)  mttm_step (ae_delta_ss7_ss8 M)"
      and a81:  "(d8a, ca)   mttm_step (ae_delta_ss8_ss1 M)"
      and b56:  "(c5b, d6b)  mttm_step (ae_delta_ss5_ss6 M)"
      and b67:  "(d6b, d7b)  mttm_step (ae_delta_ss6_ss7 M)"
      and b78:  "(d7b, d8b)  mttm_step (ae_delta_ss7_ss8 M)"
      and b81:  "(d8b, cb)   mttm_step (ae_delta_ss8_ss1 M)"
  shows "mt_tape ca = mt_tape cb  mt_pos ca = mt_pos cb
          mt_state ca = (q, ofs1, buf1, init_dest, SS1)
          mt_state cb = (q, ofs2, buf2, init_dest, SS1)"
proof -
  from ae_ss5_ss6_cong[OF tape pos st1 st2 blk a56 b56]
  have t6: "mt_tape d6a = mt_tape d6b" and p6: "mt_pos d6a = mt_pos d6b"
   and s6a: "mt_state d6a = (q, ofs1, buf1, dest, SS6)"
   and s6b: "mt_state d6b = (q, ofs2, buf2, dest, SS6)" by simp_all
  from ae_ss6_ss7_cong[OF t6 p6 s6a s6b blk a67 b67]
  have t7: "mt_tape d7a = mt_tape d7b" and p7: "mt_pos d7a = mt_pos d7b"
   and s7a: "mt_state d7a = (q, ofs1, buf1, dest, SS7)"
   and s7b: "mt_state d7b = (q, ofs2, buf2, dest, SS7)" by simp_all
  from ae_ss7_ss8_cong[OF t7 p7 s7a s7b blk a78 b78]
  have t8: "mt_tape d8a = mt_tape d8b" and p8: "mt_pos d8a = mt_pos d8b"
   and s8a: "mt_state d8a = (q, ofs1, buf1, dest, SS8)"
   and s8b: "mt_state d8b = (q, ofs2, buf2, dest, SS8)" by simp_all
  from ae_ss8_ss1_cong[OF t8 p8 s8a s8b blk qnh a81 b81]
  show ?thesis by simp
qed

text ‹The ae_simulates› transfer (the congruence that closes the
  pos=0 don't-care).  A reconstructed boundary config c'''› with
  ae_simulates M cM c'''› hands its simulation to a given c''› that
  agrees on tape, head positions, and state ‹except› the offset ofs›,
  which need agree only where the simulated head mt_pos cM k› is
  non-zero.  At mt_pos cM k = 0› the position decode
  ae_decode_pos› ignores the offset (it returns 0› exactly when its
  AE-head argument is 0›), so the offset residual is invisible.  Both
  configs are at non-halt SS1, where ae_simulates› reads neither
  buf› nor dest›.›

lemma ae_decode_pos_eq_0:
  "ae_decode_pos s i = 0  s = 0"
  by (simp add: ae_decode_pos_def split: if_splits)

lemma ae_decode_pos_zero_eq: "ae_decode_pos 0 i = 0"
  by (simp add: ae_decode_pos_def)

lemma ae_simulates_transfer:
  fixes M :: "('q, 'a) mttm" and cM :: "('a, 'q) mt_config"
    and c'' c''' :: "('c :: enum  'a, 'q × ('a, 'c) ae_stage) mt_config"
  assumes sim':   "ae_simulates M cM c'''"
      and cM_inQ: "mt_state cM  Q_tm M"
      and cM_nt:  "mt_state cM  t_tm M"
      and cM_nr:  "mt_state cM  r_tm M"
      and tape:   "mt_tape c'' = mt_tape c'''"
      and pos:    "mt_pos c'' = mt_pos c'''"
      and st2:    "mt_state c'' = (q, ofs1, buf1, init_dest, SS1)"
      and st3:    "mt_state c''' = (q, ofs2, buf2, init_dest, SS1)"
      and qnh:    "q  {t_tm M, r_tm M}"
      and ofsh:   "k<k_tm M. mt_pos cM k = 0  ofs1 k = ofs2 k"
      and gam:    "ae_tape_in_gamma_block M c''"
  shows "ae_simulates M cM c''"
proof -
  obtain qM' ofs buf dest where
      ust: "mt_state c''' = (qM', ofs, buf, dest, SS1)"
    and qeq: "mt_state cM = qM'"
    and corr: "k<k_tm M. ae_tape_correspondence (le_tm M)
                            (mt_tape cM k) (mt_tape c''' k)"
    and dec0: "k<k_tm M. mt_pos cM k
                            = ae_decode_pos (mt_pos c''' k) (ofs k)"
    by (rule ae_forward_stage_unpack_sim[OF sim' cM_inQ cM_nt cM_nr])
  from ust st3 have qM'eq: "qM' = q" and ofeq: "ofs = ofs2" by auto
  have dec: "k<k_tm M. mt_pos cM k
                          = ae_decode_pos (mt_pos c''' k) (ofs2 k)"
    using dec0 ofeq by simp
  have corr2: "k<k_tm M. ae_tape_correspondence (le_tm M)
                            (mt_tape cM k) (mt_tape c'' k)"
    using corr tape by simp
  have qeq2: "mt_state cM = q" using qeq qM'eq by simp
  have dec2: "k<k_tm M. mt_pos cM k
                           = ae_decode_pos (mt_pos c'' k) (ofs1 k)"
  proof (intro allI impI)
    fix k assume k: "k < k_tm M"
    have d3: "mt_pos cM k = ae_decode_pos (mt_pos c''' k) (ofs2 k)"
      by (rule dec[rule_format, OF k])
    have ppos: "mt_pos c'' k = mt_pos c''' k" using pos by simp
    show "mt_pos cM k = ae_decode_pos (mt_pos c'' k) (ofs1 k)"
    proof (cases "mt_pos cM k = 0")
      case True
      have "ae_decode_pos (mt_pos c''' k) (ofs2 k) = 0"
        using d3[symmetric] True by simp
      from ae_decode_pos_eq_0[OF this] have "mt_pos c''' k = 0" .
      hence "ae_decode_pos (mt_pos c'' k) (ofs1 k) = 0"
        using ppos by (simp add: ae_decode_pos_zero_eq)
      thus ?thesis using True by simp
    next
      case False
      from ofsh[rule_format, OF k] False have "ofs1 k = ofs2 k" by simp
      hence "ae_decode_pos (mt_pos c'' k) (ofs1 k)
               = ae_decode_pos (mt_pos c''' k) (ofs2 k)"
        using ppos by simp
      thus ?thesis using d3 by simp
    qed
  qed
  show ?thesis
    unfolding ae_simulates_def Let_def st2
    using qeq2 corr2 dec2 gam qnh by simp
qed

text ‹The bridge from the window inversion to the segment congruence's
  hypotheses.  Two SS5 buffered families window-corresponding (per active
  tape) to the same trace endpoint give: their buffers are
  ae_blk_agree› (home + right agree at every pos› from the kernel;
  at pos = 0› the home is LE_block le› so the left clause is
  vacuous), and their boundary ‹directions› agree (full bp›
  agreement where pos ≠ 0›; le0› direction agreement at
  pos = 0›).  These are exactly the buf› / dest› congruence
  inputs the SS5→›SS8 chain consumes.›

lemma ae_ss5_window_blk_dest_agree:
  fixes tM :: "nat  nat  'a" and nM pos :: "nat  nat"
    and bp1 bp2 :: "nat  ('c :: enum) bp"
    and b1 b2 :: "nat  (('c  'a) × ('c  'a) × ('c  'a))"
    and le :: 'a and K :: nat
  assumes h1: "k<K. ae_window_invariant_general (tM k) (nM k)
                          (bp1 k) (b1 k) (pos k) le"
      and h2: "k<K. ae_window_invariant_general (tM k) (nM k)
                          (bp2 k) (b2 k) (pos k) le"
  shows "(k<K. ae_blk_agree le (b1 k) (b2 k))
          (k<K. fst (bp1 k) = fst (bp2 k))"
proof (intro conjI allI impI)
  fix k assume k: "k < K"
  from h1 k have g1: "ae_window_invariant_general (tM k) (nM k)
                          (bp1 k) (b1 k) (pos k) le" by blast
  from h2 k have g2: "ae_window_invariant_general (tM k) (nM k)
                          (bp2 k) (b2 k) (pos k) le" by blast
  from ae_window_invariant_general_determines[OF g1 g2]
  have hr1: "fst (snd (b1 k)) = fst (snd (b2 k))"
   and hr2: "snd (snd (b1 k)) = snd (snd (b2 k))"
   and full: "pos k  0  bp1 k = bp2 k  b1 k = b2 k" by simp_all
  show "ae_blk_agree le (b1 k) (b2 k)"
  proof (cases "pos k = 0")
    case True
    have le0_1: "ae_window_invariant_le0 (tM k) (nM k) (bp1 k) (b1 k) le"
      using g1 True unfolding ae_window_invariant_general_def by simp
    have "fst (snd (b1 k)) = LE_block le"
      using le0_1 unfolding ae_window_invariant_le0_def by simp
    thus ?thesis using hr1 hr2 unfolding ae_blk_agree_def by simp
  next
    case False
    with full have "b1 k = b2 k" by simp
    thus ?thesis unfolding ae_blk_agree_def by simp
  qed
next
  fix k assume k: "k < K"
  from h1 k have g1: "ae_window_invariant_general (tM k) (nM k)
                          (bp1 k) (b1 k) (pos k) le" by blast
  from h2 k have g2: "ae_window_invariant_general (tM k) (nM k)
                          (bp2 k) (b2 k) (pos k) le" by blast
  show "fst (bp1 k) = fst (bp2 k)"
  proof (cases "pos k = 0")
    case True
    have le0_1: "ae_window_invariant_le0 (tM k) (nM k) (bp1 k) (b1 k) le"
      using g1 True unfolding ae_window_invariant_general_def by simp
    have le0_2: "ae_window_invariant_le0 (tM k) (nM k) (bp2 k) (b2 k) le"
      using g2 True unfolding ae_window_invariant_general_def by simp
    from ae_window_le0_dest_agree[OF le0_1 le0_2] show ?thesis by simp
  next
    case False
    from ae_window_invariant_general_determines[OF g1 g2] False
    show ?thesis by simp
  qed
qed

text ‹Halt branch of the closing SS8→›SS1 step.  When
  q ∈ {t, r}› the builder resets the stage to the constant
  init_stage (le_tm M)›, ‹independent› of the buffers and
  offset --- so the two destination states are ‹identical› (not
  merely ae_blk_agree›), and only the tape write needs the
  action-congruence.  This is the halt-case companion of
  ae_ss8_ss1_cong›.›

lemma ae_ss8_ss1_cong_halt:
  fixes M :: "('q, 'a) mttm"
    and c1 c2 c1' c2' :: "('c :: enum  'a,
                           'q × ('a, 'c) ae_stage) mt_config"
  assumes tape: "mt_tape c1 = mt_tape c2"
      and pos:  "mt_pos c1 = mt_pos c2"
      and st1:  "mt_state c1 = (q, ofs1, buf1, dest, SS8)"
      and st2:  "mt_state c2 = (q, ofs2, buf2, dest, SS8)"
      and blk:  "k. ae_blk_agree (le_tm M) (buf1 k) (buf2 k)"
      and qh:   "q  {t_tm M, r_tm M}"
      and s1:   "(c1, c1')  mttm_step (ae_delta_ss8_ss1 M)"
      and s2:   "(c2, c2')  mttm_step (ae_delta_ss8_ss1 M)"
  shows "mt_tape c1' = mt_tape c2'  mt_pos c1' = mt_pos c2'
          mt_state c1' = (q, init_stage (le_tm M))
          mt_state c2' = (q, init_stage (le_tm M))"
proof -
  obtain ts n where c1d: "c1 = ConfigM (q, ofs1, buf1, dest, SS8) ts n"
    using st1 by (cases c1) auto
  have c2d: "c2 = ConfigM (q, ofs2, buf2, dest, SS8) ts n"
    using st2 tape pos c1d by (cases c2) auto
  from s1[unfolded c1d] obtain s1' a'1 d1 where
      c1'd: "c1' = ConfigM s1' (λk. (ts k)(n k := a'1 k))
                                 (λk. go_dir (d1 k) (n k))"
    and rel1: "((q, ofs1, buf1, dest, SS8), (λk. ts k (n k)),
                s1', a'1, d1)  ae_delta_ss8_ss1 M"
    by (auto elim: mttm_step.cases)
  from s2[unfolded c2d] obtain s2' a'2 d2 where
      c2'd: "c2' = ConfigM s2' (λk. (ts k)(n k := a'2 k))
                                 (λk. go_dir (d2 k) (n k))"
    and rel2: "((q, ofs2, buf2, dest, SS8), (λk. ts k (n k)),
                s2', a'2, d2)  ae_delta_ss8_ss1 M"
    by (auto elim: mttm_step.cases)
  have e1: "s1' = (q, init_stage (le_tm M))"
    and a1: "a'1 = (λk. if k < k_tm M
                          then fst (ae_ss8_action (le_tm M) (ts k (n k))
                                      (buf1 k) (dest k))
                          else bl_block (bl_tm M))"
    and d1: "d1 = (λk. if k < k_tm M
                          then snd (ae_ss8_action (le_tm M) (ts k (n k))
                                      (buf1 k) (dest k))
                          else dir.N)"
    using rel1 qh unfolding ae_delta_ss8_ss1_def by auto
  have e2: "s2' = (q, init_stage (le_tm M))"
    and a2: "a'2 = (λk. if k < k_tm M
                          then fst (ae_ss8_action (le_tm M) (ts k (n k))
                                      (buf2 k) (dest k))
                          else bl_block (bl_tm M))"
    and d2: "d2 = (λk. if k < k_tm M
                          then snd (ae_ss8_action (le_tm M) (ts k (n k))
                                      (buf2 k) (dest k))
                          else dir.N)"
    using rel2 qh unfolding ae_delta_ss8_ss1_def by auto
  have act: "k. ae_ss8_action (le_tm M) (ts k (n k)) (buf1 k) (dest k)
                  = ae_ss8_action (le_tm M) (ts k (n k)) (buf2 k) (dest k)"
    by (rule ae_ss8_action_cong[OF blk[rule_format]])
  have "a'1 = a'2"
    by (rule ext) (simp add: a1 a2 act)
  moreover have "d1 = d2"
    by (rule ext) (simp add: d1 d2 act)
  ultimately show ?thesis using c1'd c2'd e1 e2 by simp
qed

text ‹Halt-agnostic prefix of the macro-cycle tail: chaining the three
  non-branching congruences SS5→›SS6→›SS7→›SS8.  None of these
  three steps inspects the halt flag, so the conclusion carries
  q› / dest› / the ae_blk_agree› buffers unchanged
  whether or not q› is halting; the halt split re-enters only at the
  final SS8→›SS1 step.›

lemma ae_ss5_ss8_segment_to_ss8:
  fixes M :: "('q, 'a) mttm"
    and c5a c5b c8a c8b :: "('c :: enum  'a,
                            'q × ('a, 'c) ae_stage) mt_config"
  assumes tape: "mt_tape c5a = mt_tape c5b"
      and pos:  "mt_pos c5a = mt_pos c5b"
      and st1:  "mt_state c5a = (q, ofs1, buf1, dest, SS5)"
      and st2:  "mt_state c5b = (q, ofs2, buf2, dest, SS5)"
      and blk:  "k. ae_blk_agree (le_tm M) (buf1 k) (buf2 k)"
      and a56:  "(c5a, d6a)  mttm_step (ae_delta_ss5_ss6 M)"
      and a67:  "(d6a, d7a)  mttm_step (ae_delta_ss6_ss7 M)"
      and a78:  "(d7a, c8a)  mttm_step (ae_delta_ss7_ss8 M)"
      and b56:  "(c5b, d6b)  mttm_step (ae_delta_ss5_ss6 M)"
      and b67:  "(d6b, d7b)  mttm_step (ae_delta_ss6_ss7 M)"
      and b78:  "(d7b, c8b)  mttm_step (ae_delta_ss7_ss8 M)"
  shows "mt_tape c8a = mt_tape c8b  mt_pos c8a = mt_pos c8b
          mt_state c8a = (q, ofs1, buf1, dest, SS8)
          mt_state c8b = (q, ofs2, buf2, dest, SS8)"
proof -
  from ae_ss5_ss6_cong[OF tape pos st1 st2 blk a56 b56]
  have t6: "mt_tape d6a = mt_tape d6b" and p6: "mt_pos d6a = mt_pos d6b"
   and s6a: "mt_state d6a = (q, ofs1, buf1, dest, SS6)"
   and s6b: "mt_state d6b = (q, ofs2, buf2, dest, SS6)" by simp_all
  from ae_ss6_ss7_cong[OF t6 p6 s6a s6b blk a67 b67]
  have t7: "mt_tape d7a = mt_tape d7b" and p7: "mt_pos d7a = mt_pos d7b"
   and s7a: "mt_state d7a = (q, ofs1, buf1, dest, SS7)"
   and s7b: "mt_state d7b = (q, ofs2, buf2, dest, SS7)" by simp_all
  from ae_ss7_ss8_cong[OF t7 p7 s7a s7b blk a78 b78]
  show ?thesis by simp
qed

text ‹Halt-case ae_simulates› transfer.  When the simulated M-config
  cM› is halting, ae_simulates› reads only the M-state, the tape
  correspondence, and (via the halt disjunct) that the stage equals
  init_stage (le_tm M)› --- never the pos-decode.  So a given c''›
  whose stage is exactly init_stage (le_tm M)› and whose tape matches a
  reconstructed c'''› with ae_simulates M cM c'''› inherits the
  simulation.  Uses the halt-agnostic ae_simulates_state_disjunction›
  (not ae_forward_stage_unpack_sim›, which needs non-halt cM›).›

lemma ae_simulates_transfer_halt:
  fixes M :: "('q, 'a) mttm" and cM :: "('a, 'q) mt_config"
    and c'' c''' :: "('c :: enum  'a, 'q × ('a, 'c) ae_stage) mt_config"
  assumes sim':    "ae_simulates M cM c'''"
      and cM_halt: "mt_state cM  {t_tm M, r_tm M}"
      and tape:    "mt_tape c'' = mt_tape c'''"
      and st2:     "mt_state c'' = (mt_state cM, init_stage (le_tm M))"
      and gam:     "ae_tape_in_gamma_block M c''"
  shows "ae_simulates M cM c''"
proof -
  obtain qM' ofs buf dest idx where
      ust: "mt_state c''' = (qM', ofs, buf, dest, idx)"
    and qeq: "mt_state cM = qM'"
    and corr: "k<k_tm M. ae_tape_correspondence (le_tm M)
                            (mt_tape cM k) (mt_tape c''' k)"
    by (rule ae_simulates_state_disjunction[OF sim'])
  have corr2: "k<k_tm M. ae_tape_correspondence (le_tm M)
                            (mt_tape cM k) (mt_tape c'' k)"
    using corr tape by simp
  show ?thesis
    unfolding ae_simulates_def Let_def st2 init_stage_def
    using cM_halt corr2 gam by simp
qed

text ‹The offset-agreement bridge (the non-halt transfer's ofsh›).
  Two SS5 window-correspondences to the same trace endpoint agree on the
  boundary ‹offset› snd bp› ‹except› where the simulated head
  nM› is 0›.  Where pos ≠ 0› the kernel pins the full
  bp›.  Where pos = 0› the le0› dest-agreement splits on the
  direction: at AE_Home› the invariant forces nM = 0› (the left
  disjunct); otherwise (AE_Right›) it pins the full bp›, so the
  offset agrees.  This is precisely the residual being confined to the
  pos = 0 / AE_Home› corner, where ae_decode_pos› ignores the
  offset.›

lemma ae_ss5_window_ofs_agree:
  fixes tM :: "nat  nat  'a" and nM pos :: "nat  nat"
    and bp1 bp2 :: "nat  ('c :: enum) bp"
    and b1 b2 :: "nat  (('c  'a) × ('c  'a) × ('c  'a))"
    and le :: 'a and K :: nat
  assumes h1: "k<K. ae_window_invariant_general (tM k) (nM k)
                          (bp1 k) (b1 k) (pos k) le"
      and h2: "k<K. ae_window_invariant_general (tM k) (nM k)
                          (bp2 k) (b2 k) (pos k) le"
  shows "k<K. nM k = 0  snd (bp1 k) = snd (bp2 k)"
proof (intro allI impI)
  fix k assume k: "k < K"
  from h1 k have g1: "ae_window_invariant_general (tM k) (nM k)
                          (bp1 k) (b1 k) (pos k) le" by blast
  from h2 k have g2: "ae_window_invariant_general (tM k) (nM k)
                          (bp2 k) (b2 k) (pos k) le" by blast
  show "nM k = 0  snd (bp1 k) = snd (bp2 k)"
  proof (cases "pos k = 0")
    case False
    from ae_window_invariant_general_determines[OF g1 g2] False
    have "bp1 k = bp2 k" by simp
    thus ?thesis by simp
  next
    case True
    have le0_1: "ae_window_invariant_le0 (tM k) (nM k) (bp1 k) (b1 k) le"
      using g1 True unfolding ae_window_invariant_general_def by simp
    have le0_2: "ae_window_invariant_le0 (tM k) (nM k) (bp2 k) (b2 k) le"
      using g2 True unfolding ae_window_invariant_general_def by simp
    from ae_window_le0_dest_agree[OF le0_1 le0_2]
    have full: "fst (bp1 k)  AE_Home  bp1 k = bp2 k"
      by (rule conjunct2)
    have home_nM0: "fst (bp1 k) = AE_Home  nM k = 0"
      using le0_1[unfolded ae_window_invariant_le0_def]
      by (cases "fst (bp1 k)") auto
    show ?thesis
    proof (cases "fst (bp1 k) = AE_Home")
      case True
      thus ?thesis using home_nM0 by simp
    next
      case False
      with full have "bp1 k = bp2 k" by simp
      thus ?thesis by simp
    qed
  qed
qed

text ‹Integration prototype (non-halt branch).  This is the
  ae_sim_c''› derivation of ae_backward_stage› with the det›
  chain-uniqueness replaced by the det-free toolkit, stated against the
  hypotheses the strengthened ae_backward_stage_decompose› (run arm)
  and ae_simulates_forward_stage_general› (forward arm) will expose.
  Both SS4→›SS5 steps leave a ‹common› SS4 source c3› (the
  SS1→›SS4 builders are functional, matched in the real integration);
  both SS5 configs window-correspond to the same trace endpoint
  cM_new›.  The shared source pins tape+head; the window bridge pins
  the buf› (ae_blk_agree›), the dest› direction, and the
  offset-except-where-nM=0›; the inactive-tape tails come from both
  SS5 states being init› beyond k_tm M›.  The SS5→›SS1 segment
  congruence then transports the agreement to the SS1 boundary, and
  ae_simulates_transfer› hands the forward simulation across.›

lemma nae_sim_proto_nonhalt:
  fixes M :: "('q, 'a) mttm" and cM_new :: "('a, 'q) mt_config"
    and c3 c4 c5 c6 c7 c'' :: "('c :: enum  'a,
                               'q × ('a, 'c) ae_stage) mt_config"
    and c4f c5f c6f c7f c''' :: "('c :: enum  'a,
                                 'q × ('a, 'c) ae_stage) mt_config"
    and ofs_r ofs_f :: "nat  'c"
    and buf_r buf_f :: "nat  (('c  'a) × ('c  'a) × ('c  'a))"
    and dest_r dest_f :: "nat  ae_dest" and pos :: "nat  nat"
  assumes q_in_Q:  "mt_state cM_new  Q_tm M"
      and nonhalt: "mt_state cM_new  {t_tm M, r_tm M}"
      ― ‹common SS4 source›
      and run45: "(c3, c4)   mttm_step (ae_delta_ss4_ss5 M)"
      and fwd45: "(c3, c4f)  mttm_step (ae_delta_ss4_ss5 M)"
      ― ‹SS5 states + window correspondences (run / fwd)›
      and c4_state:  "mt_state c4  = (mt_state cM_new, ofs_r, buf_r, dest_r, SS5)"
      and c4f_state: "mt_state c4f = (mt_state cM_new, ofs_f, buf_f, dest_f, SS5)"
      and run_window: "k<k_tm M. ae_window_invariant_general
              (mt_tape cM_new k) (mt_pos cM_new k)
              (dest_r k, ofs_r k) (buf_r k) (pos k) (le_tm M)"
      and fwd_window: "k<k_tm M. ae_window_invariant_general
              (mt_tape cM_new k) (mt_pos cM_new k)
              (dest_f k, ofs_f k) (buf_f k) (pos k) (le_tm M)"
      ― ‹inactive-tape tails (both init› beyond k_tm M›)›
      and buf_tail:  "k. ¬ k < k_tm M
                          ae_blk_agree (le_tm M) (buf_r k) (buf_f k)"
      and dest_tail: "k. ¬ k < k_tm M  dest_r k = dest_f k"
      ― ‹run / forward SS5→›SS1 substep chains›
      and run5: "(c4, c5)   mttm_step (ae_delta_ss5_ss6 M)"
      and run6: "(c5, c6)   mttm_step (ae_delta_ss6_ss7 M)"
      and run7: "(c6, c7)   mttm_step (ae_delta_ss7_ss8 M)"
      and run8: "(c7, c'')  mttm_step (ae_delta_ss8_ss1 M)"
      and fwd5: "(c4f, c5f)   mttm_step (ae_delta_ss5_ss6 M)"
      and fwd6: "(c5f, c6f)   mttm_step (ae_delta_ss6_ss7 M)"
      and fwd7: "(c6f, c7f)   mttm_step (ae_delta_ss7_ss8 M)"
      and fwd8: "(c7f, c''')  mttm_step (ae_delta_ss8_ss1 M)"
      and sim_fwd: "ae_simulates M cM_new c'''"
      and gam:     "ae_tape_in_gamma_block M c''"
  shows "ae_simulates M cM_new c''"
proof -
  ― ‹Shared SS4 source: tape + head positions agree at SS5.›
  from ae_ss4_ss5_shared_source_tape[OF run45 fwd45]
  have tape45: "mt_tape c4 = mt_tape c4f"
   and pos45:  "mt_pos c4 = mt_pos c4f" by simp_all
  ― ‹Window bridge: buffers ae_blk_agree›, dest› direction agrees
      (active tapes).›
  from ae_ss5_window_blk_dest_agree[OF run_window fwd_window]
  have blk_act: "k<k_tm M. ae_blk_agree (le_tm M) (buf_r k) (buf_f k)"
   and dir_act: "k<k_tm M. dest_r k = dest_f k" by simp_all
  ― ‹Offset bridge: ofs› agrees except where the simulated head is
      0› --- this is the transfer's ofsh›.›
  from ae_ss5_window_ofs_agree[OF run_window fwd_window]
  have ofsh: "k<k_tm M. mt_pos cM_new k = 0  ofs_r k = ofs_f k" by simp
  ― ‹Lift blk› / dest› agreement to all tapes via the tails.›
  have blk_all: "k. ae_blk_agree (le_tm M) (buf_r k) (buf_f k)"
  proof
    fix k show "ae_blk_agree (le_tm M) (buf_r k) (buf_f k)"
      by (cases "k < k_tm M") (use blk_act buf_tail in blast)+
  qed
  have dest_eq: "dest_r = dest_f"
  proof
    fix k show "dest_r k = dest_f k"
      by (cases "k < k_tm M") (use dir_act dest_tail in blast)+
  qed
  have c4f_state': "mt_state c4f = (mt_state cM_new, ofs_f, buf_f, dest_r, SS5)"
    using c4f_state dest_eq by simp
  ― ‹Transport agreement SS5→›SS1 (non-halt branch).›
  from ae_ss5_ss8_segment_cong[OF tape45 pos45 c4_state c4f_state' blk_all
                                  nonhalt run5 run6 run7 run8
                                  fwd5 fwd6 fwd7 fwd8]
  have tcc: "mt_tape c'' = mt_tape c'''"
   and pcc: "mt_pos c'' = mt_pos c'''"
   and st_c'':  "mt_state c'' = (mt_state cM_new, ofs_r, buf_r, init_dest, SS1)"
   and st_c''': "mt_state c''' = (mt_state cM_new, ofs_f, buf_f, init_dest, SS1)"
    by simp_all
  ― ‹Transfer the forward simulation across the agreement.›
  have cM_nt: "mt_state cM_new  t_tm M" using nonhalt by simp
  have cM_nr: "mt_state cM_new  r_tm M" using nonhalt by simp
  show ?thesis
    by (rule ae_simulates_transfer[OF sim_fwd q_in_Q cM_nt cM_nr tcc pcc
                                      st_c'' st_c''' nonhalt ofsh gam])
qed

text ‹Integration prototype (halt branch).  When the simulated M-config
  halts within the macro-cycle (mt_state cM_new ∈ {t, r}›) the
  closing SS8→›SS1 step resets the stage to init_stage› instead of
  looping to SS1, so the non-halt segment congruence does not apply.  The
  shared source + window bridge are unchanged; the SS5→›SS8 prefix is
  halt-agnostic; the halt SS8→›SS1 congruence lands both boundary
  configs in the identical init_stage› state with agreeing tapes, and
  ae_simulates_transfer_halt› hands the (halt-disjunct) simulation
  across.  No offset reasoning: the halt disjunct never reads the
  pos-decode.›

lemma nae_sim_proto_halt:
  fixes M :: "('q, 'a) mttm" and cM_new :: "('a, 'q) mt_config"
    and c3 c4 c5 c6 c7 c'' :: "('c :: enum  'a,
                               'q × ('a, 'c) ae_stage) mt_config"
    and c4f c5f c6f c7f c''' :: "('c :: enum  'a,
                                 'q × ('a, 'c) ae_stage) mt_config"
    and ofs_r ofs_f :: "nat  'c"
    and buf_r buf_f :: "nat  (('c  'a) × ('c  'a) × ('c  'a))"
    and dest_r dest_f :: "nat  ae_dest" and pos :: "nat  nat"
  assumes halt: "mt_state cM_new  {t_tm M, r_tm M}"
      and run45: "(c3, c4)   mttm_step (ae_delta_ss4_ss5 M)"
      and fwd45: "(c3, c4f)  mttm_step (ae_delta_ss4_ss5 M)"
      and c4_state:  "mt_state c4  = (mt_state cM_new, ofs_r, buf_r, dest_r, SS5)"
      and c4f_state: "mt_state c4f = (mt_state cM_new, ofs_f, buf_f, dest_f, SS5)"
      and run_window: "k<k_tm M. ae_window_invariant_general
              (mt_tape cM_new k) (mt_pos cM_new k)
              (dest_r k, ofs_r k) (buf_r k) (pos k) (le_tm M)"
      and fwd_window: "k<k_tm M. ae_window_invariant_general
              (mt_tape cM_new k) (mt_pos cM_new k)
              (dest_f k, ofs_f k) (buf_f k) (pos k) (le_tm M)"
      and buf_tail:  "k. ¬ k < k_tm M
                          ae_blk_agree (le_tm M) (buf_r k) (buf_f k)"
      and dest_tail: "k. ¬ k < k_tm M  dest_r k = dest_f k"
      and run5: "(c4, c5)   mttm_step (ae_delta_ss5_ss6 M)"
      and run6: "(c5, c6)   mttm_step (ae_delta_ss6_ss7 M)"
      and run7: "(c6, c7)   mttm_step (ae_delta_ss7_ss8 M)"
      and run8: "(c7, c'')  mttm_step (ae_delta_ss8_ss1 M)"
      and fwd5: "(c4f, c5f)   mttm_step (ae_delta_ss5_ss6 M)"
      and fwd6: "(c5f, c6f)   mttm_step (ae_delta_ss6_ss7 M)"
      and fwd7: "(c6f, c7f)   mttm_step (ae_delta_ss7_ss8 M)"
      and fwd8: "(c7f, c''')  mttm_step (ae_delta_ss8_ss1 M)"
      and sim_fwd: "ae_simulates M cM_new c'''"
      and gam:     "ae_tape_in_gamma_block M c''"
  shows "ae_simulates M cM_new c''"
proof -
  from ae_ss4_ss5_shared_source_tape[OF run45 fwd45]
  have tape45: "mt_tape c4 = mt_tape c4f"
   and pos45:  "mt_pos c4 = mt_pos c4f" by simp_all
  from ae_ss5_window_blk_dest_agree[OF run_window fwd_window]
  have blk_act: "k<k_tm M. ae_blk_agree (le_tm M) (buf_r k) (buf_f k)"
   and dir_act: "k<k_tm M. dest_r k = dest_f k" by simp_all
  have blk_all: "k. ae_blk_agree (le_tm M) (buf_r k) (buf_f k)"
  proof
    fix k show "ae_blk_agree (le_tm M) (buf_r k) (buf_f k)"
      by (cases "k < k_tm M") (use blk_act buf_tail in blast)+
  qed
  have dest_eq: "dest_r = dest_f"
  proof
    fix k show "dest_r k = dest_f k"
      by (cases "k < k_tm M") (use dir_act dest_tail in blast)+
  qed
  have c4f_state': "mt_state c4f = (mt_state cM_new, ofs_f, buf_f, dest_r, SS5)"
    using c4f_state dest_eq by simp
  ― ‹Halt-agnostic SS5→›SS8 prefix.›
  from ae_ss5_ss8_segment_to_ss8[OF tape45 pos45 c4_state c4f_state' blk_all
                                    run5 run6 run7 fwd5 fwd6 fwd7]
  have t8: "mt_tape c7 = mt_tape c7f" and p8: "mt_pos c7 = mt_pos c7f"
   and s8:  "mt_state c7  = (mt_state cM_new, ofs_r, buf_r, dest_r, SS8)"
   and s8f: "mt_state c7f = (mt_state cM_new, ofs_f, buf_f, dest_r, SS8)"
    by simp_all
  ― ‹Halt SS8→›SS1: both boundary configs reach the identical
      init_stage›, tapes agree.›
  from ae_ss8_ss1_cong_halt[OF t8 p8 s8 s8f blk_all halt run8 fwd8]
  have tcc: "mt_tape c'' = mt_tape c'''"
   and st_c'': "mt_state c'' = (mt_state cM_new, init_stage (le_tm M))"
    by simp_all
  show ?thesis
    by (rule ae_simulates_transfer_halt[OF sim_fwd halt tcc st_c'' gam])
qed

text ‹Combined integration prototype: the full ae_sim_c''› of
  ae_backward_stage›, det›-free.  Takes the union of the two
  branches' exposure and case-splits on whether cM_new› halts.  This
  is the literal template for the real rewrite in
  AlphabetEnlargement_Reverse›: the only remaining integration work is
  to (a) strengthen ae_backward_stage_decompose› to expose the run
  arm's SS5 state c4_state› + run_window› (already derived
  internally as window_cM_new›) and the inactive tails, (b) strengthen
  ae_simulates_forward_stage_general› to expose its SS5 config
  c4f› + fwd_window› + the SS5→›SS1 substeps alongside the
  c'''› it already returns, and (c) match the two SS4 sources
  c3 = c3_fwd› via the SS1→›SS4 functional builders.  No new
  mathematics in the reverse arm.›

lemma nae_sim_proto:
  fixes M :: "('q, 'a) mttm" and cM_new :: "('a, 'q) mt_config"
    and c3 c4 c5 c6 c7 c'' :: "('c :: enum  'a,
                               'q × ('a, 'c) ae_stage) mt_config"
    and c4f c5f c6f c7f c''' :: "('c :: enum  'a,
                                 'q × ('a, 'c) ae_stage) mt_config"
    and ofs_r ofs_f :: "nat  'c"
    and buf_r buf_f :: "nat  (('c  'a) × ('c  'a) × ('c  'a))"
    and dest_r dest_f :: "nat  ae_dest" and pos :: "nat  nat"
  assumes q_in_Q:  "mt_state cM_new  Q_tm M"
      and run45: "(c3, c4)   mttm_step (ae_delta_ss4_ss5 M)"
      and fwd45: "(c3, c4f)  mttm_step (ae_delta_ss4_ss5 M)"
      and c4_state:  "mt_state c4  = (mt_state cM_new, ofs_r, buf_r, dest_r, SS5)"
      and c4f_state: "mt_state c4f = (mt_state cM_new, ofs_f, buf_f, dest_f, SS5)"
      and run_window: "k<k_tm M. ae_window_invariant_general
              (mt_tape cM_new k) (mt_pos cM_new k)
              (dest_r k, ofs_r k) (buf_r k) (pos k) (le_tm M)"
      and fwd_window: "k<k_tm M. ae_window_invariant_general
              (mt_tape cM_new k) (mt_pos cM_new k)
              (dest_f k, ofs_f k) (buf_f k) (pos k) (le_tm M)"
      and buf_tail:  "k. ¬ k < k_tm M
                          ae_blk_agree (le_tm M) (buf_r k) (buf_f k)"
      and dest_tail: "k. ¬ k < k_tm M  dest_r k = dest_f k"
      and run5: "(c4, c5)   mttm_step (ae_delta_ss5_ss6 M)"
      and run6: "(c5, c6)   mttm_step (ae_delta_ss6_ss7 M)"
      and run7: "(c6, c7)   mttm_step (ae_delta_ss7_ss8 M)"
      and run8: "(c7, c'')  mttm_step (ae_delta_ss8_ss1 M)"
      and fwd5: "(c4f, c5f)   mttm_step (ae_delta_ss5_ss6 M)"
      and fwd6: "(c5f, c6f)   mttm_step (ae_delta_ss6_ss7 M)"
      and fwd7: "(c6f, c7f)   mttm_step (ae_delta_ss7_ss8 M)"
      and fwd8: "(c7f, c''')  mttm_step (ae_delta_ss8_ss1 M)"
      and sim_fwd: "ae_simulates M cM_new c'''"
      and gam:     "ae_tape_in_gamma_block M c''"
  shows "ae_simulates M cM_new c''"
proof (cases "mt_state cM_new  {t_tm M, r_tm M}")
  case True
  show ?thesis
    by (rule nae_sim_proto_halt[OF True run45 fwd45 c4_state c4f_state
                                   run_window fwd_window buf_tail dest_tail
                                   run5 run6 run7 run8 fwd5 fwd6 fwd7 fwd8
                                   sim_fwd gam])
next
  case False
  show ?thesis
    by (rule nae_sim_proto_nonhalt[OF q_in_Q False run45 fwd45 c4_state
                                      c4f_state run_window fwd_window
                                      buf_tail dest_tail
                                      run5 run6 run7 run8 fwd5 fwd6 fwd7 fwd8
                                      sim_fwd gam])
qed

text ‹Config-level functionality of a substep relation from
  delta-level functionality: if the underlying δ›-relation
  R› is single-valued in (s', a', d)› given the source
  (s, a)›, then the induced mttm_step R› is a partial
  function on configurations.  The det›-free analogue of
  mttm_step_alphabet_enlarge_functional›, applied to the
  functional SS1→›SS4 substep builders to match the run and
  forward arms' shared SS4 source c3›.›

lemma mttm_step_functional_of_delta:
  assumes fnl: "s a s1 a1 d1 s2 a2 d2.
                  (s, a, s1, a1, d1)  R  (s, a, s2, a2, d2)  R
                     s1 = s2  a1 = a2  d1 = d2"
      and h1: "(c, c1)  mttm_step R"
      and h2: "(c, c2)  mttm_step R"
  shows "c1 = c2"
proof -
  from h1 obtain q ts n q1 a1 dir1 where
      c_eq1:  "c  = ConfigM q ts n"
    and c1_eq: "c1 = ConfigM q1 (λk. (ts k)(n k := a1 k))
                                  (λk. go_dir (dir1 k) (n k))"
    and tr1: "(q, λk. ts k (n k), q1, a1, dir1)  R"
    by (auto elim: mttm_step.cases)
  from h2 obtain q' ts' n' q2 a2 dir2 where
      c_eq2:  "c  = ConfigM q' ts' n'"
    and c2_eq: "c2 = ConfigM q2 (λk. (ts' k)(n' k := a2 k))
                                  (λk. go_dir (dir2 k) (n' k))"
    and tr2: "(q', λk. ts' k (n' k), q2, a2, dir2)  R"
    by (auto elim: mttm_step.cases)
  from c_eq1 c_eq2 have qq: "q = q'" and tsts: "ts = ts'" and nn: "n = n'"
    by auto
  from tr2 qq tsts nn
  have tr2': "(q, λk. ts k (n k), q2, a2, dir2)  R" by simp
  have "q1 = q2  a1 = a2  dir1 = dir2" by (rule fnl[OF tr1 tr2'])
  thus ?thesis using c1_eq c2_eq tsts nn by simp
qed


subsubsection ‹Backward stage orchestration›

text ‹**Reverse-arm chain orchestration (Step 3e).**  Combines
  ae_backward_stage_load_chain›,
  ae_backward_stage_compute_extract›, and
  ae_backward_stage_writeback_chain› into a single
  decomposition of an 8-step alphabet_enlarge_delta›-chain
  from an SS1 boundary configuration.  Exposes the 8 substep facts,
  the substrate trace, its termination disjunction, and halt-aware
  c'' status.

  Design choice: the outer obtains› exposes only first-order
  conjuncts — projection-level state shape (fst (mt_state c'')
  = mt_state cM_new›) rather than 5-tuple state equalities — to
  avoid the higher-order pattern unification that defeats an
  OF›-style discharge.  The c4 state-tuple is internal
  plumbing; the consumer only needs first-order projections.›

lemma ae_backward_stage_decompose:
  fixes M :: "('q, 'a) mttm"
    and cM :: "('a, 'q) mt_config"
    and c' c'' :: "('c :: enum  'a,
                     'q × ('a, 'c) ae_stage) mt_config"
    and qM' :: 'q
    and ofs :: "nat  'c"
    and buf :: "nat  ('c  'a) × ('c  'a) × ('c  'a)"
    and dest :: "nat  ae_dest"
  assumes vM:          "valid_mttm M"
      and lu:          "le_unique M"
      and sim:         "ae_simulates M cM c'"
      and val_cM:      "valid_config_mttm M cM"
      and c'_state:    "mt_state c' = (qM', ofs, buf, dest, SS1)"
      and inv_ss1:     "ae_inv_ss1 M c'"
      and gamma_c':    "ae_tape_in_gamma_block M c'"
      and buf_gamma:   "ae_buffer_in_gamma_block M c'"
      and pos_link_c': "ae_position_link M c'"
      and le_anchor:   "k<k_tm M. mt_tape c' k 0 = LE_block (le_tm M)"
      and le_neq_bl:   "le_tm M  bl_tm M"
      and qM'_neq_t:   "qM'  t_tm M"
      and qM'_neq_r:   "qM'  r_tm M"
      and no_le_per_tape:
            "k. (mt_pos c' k  2
                     (i. i < 3 * card (UNIV :: 'c set)
                               mt_tape cM k
                                    ((mt_pos c' k - 2) * card (UNIV :: 'c set)
                                       + 1 + i)
                                   le_tm M))
                  (mt_pos c' k = 1
                       (i. i < 2 * card (UNIV :: 'c set)
                                 mt_tape cM k (Suc i)  le_tm M))
                  (mt_pos c' k = 0
                       (i. i < card (UNIV :: 'c set)
                                 mt_tape cM k (Suc i)  le_tm M))"
      and run:         "(c', c'')
                           mttm_step (alphabet_enlarge_delta M) ^^ 8"
  obtains c1 c2 c3 c4 c5 c6 c7 cM_new n ofs_r buf_r dest_r where
      "(c', c1)  mttm_step (ae_delta_ss1_ss2 M)"
    and "(c1, c2)  mttm_step (ae_delta_ss2_ss3 M)"
    and "(c2, c3)  mttm_step (ae_delta_ss3_ss4 M)"
    and "(c3, c4)  mttm_step (ae_delta_ss4_ss5 M)"
    and "(c4, c5)  mttm_step (ae_delta_ss5_ss6 M)"
    and "(c5, c6)  mttm_step (ae_delta_ss6_ss7 M)"
    and "(c6, c7)  mttm_step (ae_delta_ss7_ss8 M)"
    and "(c7, c'')  mttm_step (ae_delta_ss8_ss1 M)"
    and "(cM, cM_new)  mttm_step (delta_tm M) ^^ n"
    and "n  card (UNIV :: 'c set)"
    and "n = card (UNIV :: 'c set)
             mt_state cM_new  {t_tm M, r_tm M}"
    and "fst (mt_state c'') = mt_state cM_new"
    and "mt_state cM_new  {t_tm M, r_tm M}
             ae_inv_ss1 M c''"
    and "mt_state cM_new  {t_tm M, r_tm M}
             snd (snd (snd (snd (mt_state c'')))) = VFwd"
    and "ae_tape_in_gamma_block M c''"
    and "ae_buffer_in_gamma_block M c''"
    and "mt_state c4 = (mt_state cM_new, ofs_r, buf_r, dest_r, SS5)"
    and "k<k_tm M. ae_window_invariant_general
              (mt_tape cM_new k) (mt_pos cM_new k)
              (dest_r k, ofs_r k) (buf_r k) (mt_pos c' k) (le_tm M)"
    and "ae_buffer_in_gamma_block M c4"
    and "mt_state cM_new  Q_tm M"
proof -
  let ?R = "mttm_step (alphabet_enlarge_delta M)"

  ― ‹Peel the 8-step chain into 8 individual full steps via
      numeral_eq_Suc›-driven Suc unfolding.  Then rebuild the
      R^^3 prefix and R^^4 suffix for the helper invocations.›
  from run obtain c1' c2' c3 c4 c5' c6' c7' where
      p1:         "(c', c1')  ?R"
    and p2:         "(c1', c2')  ?R"
    and p3:         "(c2', c3)  ?R"
    and step4_full: "(c3, c4)  ?R"
    and p5:         "(c4, c5')  ?R"
    and p6:         "(c5', c6')  ?R"
    and p7:         "(c6', c7')  ?R"
    and p8:         "(c7', c'')  ?R"
    by (auto dest!: relpow_Suc_D2 simp: numeral_eq_Suc)

  ― ‹Rebuild (c', c3) ∈ R^^3› via explicit Suc-form
      chain.›
  have a0: "(c', c1')  ?R ^^ Suc 0" using p1 by simp
  have a1: "(c', c2')  ?R ^^ Suc (Suc 0)"
    using relpow_Suc_I[OF a0 p2] .
  have a2: "(c', c3)  ?R ^^ Suc (Suc (Suc 0))"
    using relpow_Suc_I[OF a1 p3] .
  have eq3: "(3::nat) = Suc (Suc (Suc 0))" by (simp add: eval_nat_numeral)
  have load_run: "(c', c3)  ?R ^^ 3"
    using a2 unfolding eq3 .

  ― ‹Rebuild (c4, c'') ∈ R^^4›.›
  have b0: "(c4, c5')  ?R ^^ Suc 0" using p5 by simp
  have b1: "(c4, c6')  ?R ^^ Suc (Suc 0)"
    using relpow_Suc_I[OF b0 p6] .
  have b2: "(c4, c7')  ?R ^^ Suc (Suc (Suc 0))"
    using relpow_Suc_I[OF b1 p7] .
  have b3: "(c4, c'')  ?R ^^ Suc (Suc (Suc (Suc 0)))"
    using relpow_Suc_I[OF b2 p8] .
  have eq4: "(4::nat) = Suc (Suc (Suc (Suc 0)))" by (simp add: eval_nat_numeral)
  have writeback_run: "(c4, c'')  ?R ^^ 4"
    using b3 unfolding eq4 .

  ― ‹Invoke load_chain› on
      (c', c3) ∈ R^^3›.  Returns fresh
      c1, c2 (the substep intermediates) with the substep facts and
      c3 invariants.  These c1, c2 may differ syntactically from
      c1', c2' above, but we propagate forward using only c1, c2.›
  obtain c1 c2 where
      step1_sub: "(c', c1)  mttm_step (ae_delta_ss1_ss2 M)"
    and step1_full: "(c', c1)  ?R"
    and step2_sub: "(c1, c2)  mttm_step (ae_delta_ss2_ss3 M)"
    and step2_full: "(c1, c2)  ?R"
    and step3_sub: "(c2, c3)  mttm_step (ae_delta_ss3_ss4 M)"
    and step3_full: "(c2, c3)  ?R"
    and inv_ss4_c3: "ae_inv_ss4 M c3"
    and gamma_c3: "ae_tape_in_gamma_block M c3"
    and buf_gamma_c3: "ae_buffer_in_gamma_block M c3"
    and c3_q_eq: "fst (mt_state c3) = qM'"
    and pos_link_c3: "ae_position_link M c3"
    by (rule ae_backward_stage_load_chain
                [OF vM c'_state inv_ss1 gamma_c' buf_gamma pos_link_c'
                    qM'_neq_t qM'_neq_r load_run])

  ― ‹Recover c3_idx_ss4› for
      compute_extract›.›
  have c3_idx_ss4: "snd (snd (snd (snd (mt_state c3)))) = SS4"
    using inv_ss4_c3 unfolding ae_inv_ss4_def
    by (cases "mt_state c3") auto

  ― ‹Invoke compute_extract›.  Returns the cM
      trace, termination disjunction, c4 5-tuple state shape (used
      internally only), and tape/buffer/window propagation facts.›
  obtain cM_new buf' end_pos n where
      step4_sub: "(c3, c4)  mttm_step (ae_delta_ss4_ss5 M)"
    and cM_trace: "(cM, cM_new)  mttm_step (delta_tm M) ^^ n"
    and n_bnd: "n  card (UNIV :: 'c set)"
    and halt_or_full:
          "n = card (UNIV :: 'c set)
               mt_state cM_new  {t_tm M, r_tm M}"
    and c4_state:
          "mt_state c4 = (mt_state cM_new,
                            λk. if k < k_tm M then snd (end_pos k)
                                  else init_offset k,
                            buf',
                            λk. if k < k_tm M then fst (end_pos k)
                                  else init_dest k, SS5)"
    and c4_tape: "mt_tape c4 = mt_tape c'"
    and window_cM_new:
          "k<k_tm M. ae_window_invariant_general
                  (mt_tape cM_new k) (mt_pos cM_new k)
                  (end_pos k) (buf' k) (mt_pos c' k) (le_tm M)"
    and no_le_cM_new:
          "k. (mt_pos c' k = 0
                   (i. i < card (UNIV :: 'c set)
                             mt_tape cM_new k (Suc i)  le_tm M))
               (mt_pos c' k = 1
                   (i. i < 2 * card (UNIV :: 'c set)
                             mt_tape cM_new k (Suc i)  le_tm M))
               (mt_pos c' k  2
                   (i. i < 3 * card (UNIV :: 'c set)
                             mt_tape cM_new k
                                  ((mt_pos c' k - 2) * card (UNIV :: 'c set)
                                     + 1 + i)
                                 le_tm M))"
    and buf'_le_pos0:
          "k<k_tm M. mt_pos c' k = 0
                   fst (buf' k)  LE_block (le_tm M)"
    by (rule ae_backward_stage_compute_extract
                [OF vM lu val_cM sim c'_state le_anchor le_neq_bl no_le_per_tape
                    step1_sub step2_sub step3_sub step4_full c3_idx_ss4])

  ― ‹First-order projections from c4_state› —
      these are the inputs to writeback_chain›
      (q_out = mt_state cM_new›) and the bridge facts used
      in the final discharge.›
  have c4_q: "fst (mt_state c4) = mt_state cM_new"
    using c4_state by simp
  have c4_idx_ss5: "snd (snd (snd (snd (mt_state c4)))) = SS5"
    using c4_state by simp

  ― ‹Propagate valid_config_mttm M› through the
      n-step substrate trace to obtain
      mt_state cM_new ∈ Q_tm M›.  Inline induction since
      no packaged multi-step preservation lemma exists.›
  have val_cM_new: "valid_config_mttm M cM_new"
  proof -
    have preserve: "c_b n0. (cM, c_b)  mttm_step (delta_tm M) ^^ n0
                                 valid_config_mttm M c_b"
    proof -
      fix c_b n0
      assume "(cM, c_b)  mttm_step (delta_tm M) ^^ n0"
      thus "valid_config_mttm M c_b"
      proof (induction n0 arbitrary: c_b)
        case 0 thus ?case using val_cM by simp
      next
        case (Suc n0)
        from Suc.prems obtain c_mid where
            ih: "(cM, c_mid)  mttm_step (delta_tm M) ^^ n0"
          and step_last: "(c_mid, c_b)  mttm_step (delta_tm M)"
          by (auto elim: relpow_Suc_E)
        have val_mid: "valid_config_mttm M c_mid"
          using Suc.IH[OF ih] .
        show ?case by (rule valid_step_mttm[OF vM step_last val_mid])
      qed
    qed
    show ?thesis using preserve[OF cM_trace] .
  qed
  have q_in_Q: "mt_state cM_new  Q_tm M"
  proof -
    obtain Q Sg Gm bl le dt s t r kM where
        Mr: "M = MTTM Q Sg Gm bl le dt s t r kM" by (cases M)
    obtain q ts nn where cr: "cM_new = ConfigM q ts nn" by (cases cM_new)
    show ?thesis using val_cM_new Mr cr by simp
  qed

  ― ‹Push gamma / buffer-gamma through step4 to c4.›
  have gamma_c4: "ae_tape_in_gamma_block M c4"
    using ae_step_alphabet_enlarge_gamma_preserve[OF gamma_c3 step4_full] .
  have buf_gamma_c4: "ae_buffer_in_gamma_block M c4"
    using ae_step_alphabet_enlarge_buffer_gamma_preserve
            [OF vM buf_gamma_c3 gamma_c3 step4_full] .

  ― ‹Assemble ae_inv_ss5 M c4› for
      writeback_chain›.›
  have inv_ss5_c4: "ae_inv_ss5 M c4"
    unfolding ae_inv_ss5_def using c4_q c4_idx_ss5 q_in_Q
    by (cases "mt_state c4") auto

  ― ‹Invoke writeback_chain›.
      q_out = mt_state cM_new› (via c4_q›);
      writeback exposes c5, c6, c7 substep facts and the halt-aware
      c'' status keyed on q_out›.›
  obtain c5 c6 c7 where
      step5_sub: "(c4, c5)  mttm_step (ae_delta_ss5_ss6 M)"
    and step5_full: "(c4, c5)  ?R"
    and step6_sub: "(c5, c6)  mttm_step (ae_delta_ss6_ss7 M)"
    and step6_full: "(c5, c6)  ?R"
    and step7_sub: "(c6, c7)  mttm_step (ae_delta_ss7_ss8 M)"
    and step7_full: "(c6, c7)  ?R"
    and step8_sub: "(c7, c'')  mttm_step (ae_delta_ss8_ss1 M)"
    and step8_full: "(c7, c'')  ?R"
    and c''_non_halt:
          "mt_state cM_new  {t_tm M, r_tm M}
               ae_inv_ss1 M c''"
    and c''_halt:
          "mt_state cM_new  {t_tm M, r_tm M}
               (case mt_state c'' of (qH, _, _, _, idx)
                     qH  {t_tm M, r_tm M}  idx = VFwd)"
    and c''_q_eq: "fst (mt_state c'') = mt_state cM_new"
    and gamma_c'': "ae_tape_in_gamma_block M c''"
    and buf_gamma_c'': "ae_buffer_in_gamma_block M c''"
    by (rule ae_backward_stage_writeback_chain
                [OF vM inv_ss5_c4 c4_q q_in_Q gamma_c4 buf_gamma_c4
                    writeback_run])

  ― ‹Refine c''_halt›'s tuple-case form to a
      first-order projection on snd^4 (mt_state c'')›.›
  have halt_inv_idx:
      "mt_state cM_new  {t_tm M, r_tm M}
           snd (snd (snd (snd (mt_state c'')))) = VFwd"
  proof
    assume h: "mt_state cM_new  {t_tm M, r_tm M}"
    have shape:
        "case mt_state c'' of (qH, _, _, _, idx)
               qH  {t_tm M, r_tm M}  idx = VFwd"
      using mp[OF c''_halt h] .
    show "snd (snd (snd (snd (mt_state c'')))) = VFwd"
      using shape by (cases "mt_state c''") auto
  qed

  ― ‹Run-arm SS5 exposure for the det-free reverse arm.  Name the
      three SS5 stage fields (offset, buffer, dest) so the consumer can
      feed them to nae_sim_proto›; re-express the window
      correspondence in (dest, ofs)› bp form (the proto's shape).
      The inactive-tape tails travel inside buf_gamma_c4›
      (ae_buffer_in_gamma_block› ≡› ae_valid_stage›:
      buf› / dest› frozen to init› beyond k_tm M›).›
  define ofs_r where
    "ofs_r = (λk. if k < k_tm M then snd (end_pos k) else init_offset k)"
  define buf_r where "buf_r = buf'"
  define dest_r where
    "dest_r = (λk. if k < k_tm M then fst (end_pos k) else init_dest k)"
  have R_c4_state: "mt_state c4 = (mt_state cM_new, ofs_r, buf_r, dest_r, SS5)"
    using c4_state by (simp add: ofs_r_def buf_r_def dest_r_def)
  have R_run_window:
      "k<k_tm M. ae_window_invariant_general
              (mt_tape cM_new k) (mt_pos cM_new k)
              (dest_r k, ofs_r k) (buf_r k) (mt_pos c' k) (le_tm M)"
  proof (intro allI impI)
    fix k assume klt: "k < k_tm M"
    have bp_eq: "(dest_r k, ofs_r k) = end_pos k"
      using klt by (simp add: dest_r_def ofs_r_def)
    show "ae_window_invariant_general (mt_tape cM_new k) (mt_pos cM_new k)
            (dest_r k, ofs_r k) (buf_r k) (mt_pos c' k) (le_tm M)"
      using window_cM_new[rule_format, OF klt] bp_eq by (simp add: buf_r_def)
  qed

  ― ‹Final discharge: 19 first-order conjuncts, no HOU patterns.›
  show ?thesis
    by (rule that[OF step1_sub step2_sub step3_sub step4_sub
                     step5_sub step6_sub step7_sub step8_sub
                     cM_trace n_bnd halt_or_full c''_q_eq
                     c''_non_halt halt_inv_idx gamma_c'' buf_gamma_c''
                     R_c4_state R_run_window buf_gamma_c4 q_in_Q])
qed


text ‹**Reverse-arm top-level wrapper (Step 3f).**  Given the
  simulation invariant at an SS1 boundary configuration
  c'› and an 8-step
  alphabet_enlarge_delta›-chain
  (c', c'') ∈ R^^8›, produces the corresponding
  substrate trace (cM, cM_new) ∈ step^n› with
  n ≤ c› and asserts the simulation invariant at the
  new boundary configuration c''›.

  This is the reverse-arm counterpart to
  ae_simulates_forward_stage_general›.  The internal
  decomposition is handled by
  ae_backward_stage_decompose› (Step 3e); this wrapper
  unpacks the simulation invariant via
  ae_forward_stage_unpack_sim›, invokes the decompose
  lemma, and re-packages the conclusions in terms of the
  ae_simulates› invariant for the consumer (Step 4
  validation-trace-unique-to-SS1, ultimately
  alphabet_enlarge_language›'s reverse implication).

  The body has two substantive components beyond the decompose
  invocation:

   **le_anchor› preservation at c''›**:
    each of the 8 substeps preserves
    mt_tape c kk 0 = LE_block (le_tm M)›.  Discharged
    directly via the substrate's
    mttm_relpow_LE_pos0_preserve› applied to the
    enlarged machine (post [ae-drop-a-finite]›, this is a
    one-shot bridge with no per-substep derivation needed).

   **ae_simulates M cM_new c''›**: the full
    simulation invariant — tape correspondence, position decoding
    in the non-halt branch, halt-shape in the halt branch.
    Derived using the substep facts from Step 3e plus the same
    regime-aware writeback machinery the forward arm uses
    (pos_link› propagation, tape preservation across
    writeback writes, per-tape regime case-splits for position
    decoding).

  An earlier draft of this wrapper also exposed a position
  displacement disjunct (mt_pos c'' kk ∈ {p, p+1, p-1}›
  per tape).  Audit showed the consuming wrapper
  (ae_trace_decode›) doesn't need it; the forward arm's
  parallel disp_c8› was bound at its only call site
  (ae_simulation_phase_chunked›) but never referenced.
  Dropped as dead code.›

lemma ae_backward_stage:
  fixes M :: "('q, 'a) mttm"
    and cM :: "('a, 'q) mt_config"
    and c' c'' :: "('c :: enum  'a,
                     'q × ('a, 'c) ae_stage) mt_config"
  assumes vM:           "valid_mttm M"
      and lu:           "le_unique M"
      and sim:          "ae_simulates M cM c'"
      and val_cM:       "valid_config_mttm M cM"
      and q_neq_t:      "mt_state cM  t_tm M"
      and q_neq_r:      "mt_state cM  r_tm M"
      and buf_gamma:    "ae_buffer_in_gamma_block M c'"
      and le_anchor:    "kk<k_tm M. mt_tape c' kk 0 = LE_block (le_tm M)"
      and le_neq_bl:    "le_tm M  bl_tm M"
      and no_le_per_tape:
            "k. (mt_pos c' k  2
                     (i. i < 3 * card (UNIV :: 'c set)
                               mt_tape cM k
                                    ((mt_pos c' k - 2) * card (UNIV :: 'c set)
                                       + 1 + i)
                                   le_tm M))
                  (mt_pos c' k = 1
                       (i. i < 2 * card (UNIV :: 'c set)
                                 mt_tape cM k (Suc i)  le_tm M))
                  (mt_pos c' k = 0
                       (i. i < card (UNIV :: 'c set)
                                 mt_tape cM k (Suc i)  le_tm M))"
      and run:          "(c', c'')  mttm_step (alphabet_enlarge_delta M) ^^ 8"
  obtains cM_new n where
      "(cM, cM_new)  mttm_step (delta_tm M) ^^ n"
    and "n  card (UNIV :: 'c set)"
    and "n = card (UNIV :: 'c set)
             mt_state cM_new  {t_tm M, r_tm M}"
    and "ae_simulates M cM_new c''"
    and "ae_buffer_in_gamma_block M c''"
    and "kk<k_tm M. mt_tape c'' kk 0 = LE_block (le_tm M)"
proof -
  ― ‹Derive mt_state cM ∈ Q_tm M› from
      val_cM› for the sim-unpack invocation.›
  have qM_in_Q: "mt_state cM  Q_tm M"
  proof -
    obtain Q Sg Gm bl le dt s t r kM where
        Mr: "M = MTTM Q Sg Gm bl le dt s t r kM" by (cases M)
    obtain q ts nn where cr: "cM = ConfigM q ts nn" by (cases cM)
    show ?thesis using val_cM Mr cr by simp
  qed

  ― ‹Unpack the simulation invariant at c'›.›
  obtain qM' ofs buf dest where
      c'_state:     "mt_state c' = (qM', ofs, buf, dest, SS1)"
    and qM_eq:      "mt_state cM = qM'"
    and qM'_in_Q:   "qM'  Q_tm M"
    and qM'_neq_t:  "qM'  t_tm M"
    and qM'_neq_r:  "qM'  r_tm M"
    and tape_corr:  "k<k_tm M. ae_tape_correspondence (le_tm M)
                            (mt_tape cM k) (mt_tape c' k)"
    and pos_decode: "k<k_tm M. mt_pos cM k = ae_decode_pos (mt_pos c' k) (ofs k)"
    and gamma_c':   "ae_tape_in_gamma_block M c'"
    and inv_ss1:    "ae_inv_ss1 M c'"
    and pos_link_c': "ae_position_link M c'"
    by (rule ae_forward_stage_unpack_sim[OF sim qM_in_Q q_neq_t q_neq_r])

  ― ‹Invoke Step 3e to decompose the 8-step chain.›
  obtain c1 c2 c3 c4 c5 c6 c7 cM_new n ofs_r buf_r dest_r where
      step1_sub: "(c', c1)  mttm_step (ae_delta_ss1_ss2 M)"
    and step2_sub: "(c1, c2)  mttm_step (ae_delta_ss2_ss3 M)"
    and step3_sub: "(c2, c3)  mttm_step (ae_delta_ss3_ss4 M)"
    and step4_sub: "(c3, c4)  mttm_step (ae_delta_ss4_ss5 M)"
    and step5_sub: "(c4, c5)  mttm_step (ae_delta_ss5_ss6 M)"
    and step6_sub: "(c5, c6)  mttm_step (ae_delta_ss6_ss7 M)"
    and step7_sub: "(c6, c7)  mttm_step (ae_delta_ss7_ss8 M)"
    and step8_sub: "(c7, c'')  mttm_step (ae_delta_ss8_ss1 M)"
    and cM_trace: "(cM, cM_new)  mttm_step (delta_tm M) ^^ n"
    and n_bnd:    "n  card (UNIV :: 'c set)"
    and halt_or_full:
          "n = card (UNIV :: 'c set)
               mt_state cM_new  {t_tm M, r_tm M}"
    and c''_fst_eq: "fst (mt_state c'') = mt_state cM_new"
    and c''_non_halt:
          "mt_state cM_new  {t_tm M, r_tm M}
               ae_inv_ss1 M c''"
    and c''_halt_idx:
          "mt_state cM_new  {t_tm M, r_tm M}
               snd (snd (snd (snd (mt_state c'')))) = VFwd"
    and gamma_c'': "ae_tape_in_gamma_block M c''"
    and buf_gamma_c'': "ae_buffer_in_gamma_block M c''"
    and run_c4_state:
          "mt_state c4 = (mt_state cM_new, ofs_r, buf_r, dest_r, SS5)"
    and run_window:
          "k<k_tm M. ae_window_invariant_general
                  (mt_tape cM_new k) (mt_pos cM_new k)
                  (dest_r k, ofs_r k) (buf_r k) (mt_pos c' k) (le_tm M)"
    and run_buf_gamma_c4: "ae_buffer_in_gamma_block M c4"
    and run_q_in_Q: "mt_state cM_new  Q_tm M"
    by (rule ae_backward_stage_decompose
                [OF vM lu sim val_cM c'_state inv_ss1 gamma_c' buf_gamma
                    pos_link_c' le_anchor le_neq_bl qM'_neq_t qM'_neq_r
                    no_le_per_tape run])

  ― ‹The le_anchor›-at-c''› conclusion collapses to a
      direct invocation of the substrate-level
      mttm_relpow_LE_pos0_preserve› applied to the
      enlarged machine, with the delta_tm› /
      le_tm› bridges discharging the
      alphabet_enlarge_delta› ↔›
      delta_tm (alphabet_enlarge M)› and
      LE_block (le_tm M)› ↔›
      le_tm (alphabet_enlarge M)› identities.›
  have le_anchor_c'': "kk<k_tm M. mt_tape c'' kk 0 = LE_block (le_tm M)"
  proof (intro allI impI)
    fix kk
    assume kklt: "kk < k_tm M"
    let ?M' = "alphabet_enlarge M
                  :: ('q × ('a, 'c) ae_stage,
                      'c  'a) mttm"
    have vM': "valid_mttm ?M'"
      by (rule alphabet_enlarge_wf[OF vM])
    have run': "(c', c'')  mttm_step (delta_tm ?M') ^^ 8"
      using run by (simp add: delta_tm_alphabet_enlarge)
    have le_at_c'_kk: "mt_tape c' kk 0 = le_tm ?M'"
      using le_anchor[rule_format, OF kklt] by (simp add: le_tm_alphabet_enlarge)
    have "mt_tape c'' kk 0 = le_tm ?M'"
      by (rule mttm_relpow_LE_pos0_preserve[OF vM' run' le_at_c'_kk])
    then show "mt_tape c'' kk 0 = LE_block (le_tm M)"
      by (simp add: le_tm_alphabet_enlarge)
  qed
  ― ‹Sub-step ae_sim_c''› (det›-free): rather than
      identify the backward boundary c''› with the forward
      witness c'''› by chain uniqueness (which needs
      det_mttm M›), apply nae_sim_proto›.  The forward
      arm rebuilds a c'''› simulating the ‹same›
      extracted M-trace endpoint cM_new›, now exposing its SS5
      config; the two arms share the SS4 source c3› (the
      functional SS1→›SS4 builders force c1 = c1f›,
      c2 = c2f›, c3 = c3f›); the window invariant against
      the common cM_new› pins the SS5 outputs modulo the
      pos=›0 offset don't-care; and the inactive-tape tails agree
      because ae_buffer_in_gamma_block› freezes both arms'
      buf› / dest› to init› beyond k_tm M›.
      The forward arm's full ae_simulates› transports across
      the SS5→›SS1 congruence to c''›.›
  have ae_sim_c'': "ae_simulates M cM_new c''"
  proof -
    ― ‹Forward arm: a c'''› simulating the same cM_new›,
        with its full substep chain + SS5 exposure.›
    obtain c''' c1f c2f c3f c4f c5f c6f c7f ofs_f buf_f dest_f where
        fwd_chain: "(c', c''')
                        mttm_step (alphabet_enlarge_delta M) ^^ 8"
      and sim_c''': "ae_simulates M cM_new c'''"
      and fwd_bufg_c''': "ae_buffer_in_gamma_block M c'''"
      and fwd_le_c''': "kk<k_tm M. mt_tape c''' kk 0 = LE_block (le_tm M)"
      and f_step1: "(c', c1f)  mttm_step (ae_delta_ss1_ss2 M)"
      and f_step2: "(c1f, c2f)  mttm_step (ae_delta_ss2_ss3 M)"
      and f_step3: "(c2f, c3f)  mttm_step (ae_delta_ss3_ss4 M)"
      and f_step4: "(c3f, c4f)  mttm_step (ae_delta_ss4_ss5 M)"
      and f_step5: "(c4f, c5f)  mttm_step (ae_delta_ss5_ss6 M)"
      and f_step6: "(c5f, c6f)  mttm_step (ae_delta_ss6_ss7 M)"
      and f_step7: "(c6f, c7f)  mttm_step (ae_delta_ss7_ss8 M)"
      and f_step8: "(c7f, c''')  mttm_step (ae_delta_ss8_ss1 M)"
      and fwd_c4_state:
            "mt_state c4f = (mt_state cM_new, ofs_f, buf_f, dest_f, SS5)"
      and fwd_window:
            "kk<k_tm M. ae_window_invariant_general
                    (mt_tape cM_new kk) (mt_pos cM_new kk)
                    (dest_f kk, ofs_f kk) (buf_f kk) (mt_pos c' kk) (le_tm M)"
      and fwd_buf_gamma_c4f: "ae_buffer_in_gamma_block M c4f"
      by (rule ae_simulates_forward_stage_general
                  [OF vM lu sim qM_in_Q q_neq_t q_neq_r buf_gamma n_bnd
                      cM_trace halt_or_full le_anchor le_neq_bl
                      no_le_per_tape])

    ― ‹Shared SS4 source: both arms load SS1→›SS4 from c'›
        through the functional substep builders.›
    have c1_eq: "c1 = c1f"
      by (rule mttm_step_functional_of_delta
                  [OF ae_delta_ss1_ss2_functional step1_sub f_step1])
    have f_step2': "(c1, c2f)  mttm_step (ae_delta_ss2_ss3 M)"
      using f_step2 c1_eq by simp
    have c2_eq: "c2 = c2f"
      by (rule mttm_step_functional_of_delta
                  [OF ae_delta_ss2_ss3_functional step2_sub f_step2'])
    have f_step3': "(c2, c3f)  mttm_step (ae_delta_ss3_ss4 M)"
      using f_step3 c2_eq by simp
    have c3_eq: "c3 = c3f"
      by (rule mttm_step_functional_of_delta
                  [OF ae_delta_ss3_ss4_functional step3_sub f_step3'])
    have fwd45: "(c3, c4f)  mttm_step (ae_delta_ss4_ss5 M)"
      using f_step4 c3_eq by simp

    ― ‹Inactive-tape tails: ae_buffer_in_gamma_block› carries
        the ae_valid_stage› tail, freezing buf› / dest›
        to init› beyond k_tm M› on both arms, so they agree
        there.›
    have run_tails:
        "(jk_tm M. buf_r j = init_buffer (le_tm M) j)
           (jk_tm M. dest_r j = init_dest j)"
      using run_buf_gamma_c4[unfolded ae_buffer_in_gamma_block_def run_c4_state]
      by simp
    have fwd_tails:
        "(jk_tm M. buf_f j = init_buffer (le_tm M) j)
           (jk_tm M. dest_f j = init_dest j)"
      using fwd_buf_gamma_c4f[unfolded ae_buffer_in_gamma_block_def fwd_c4_state]
      by simp
    have buf_tail:
        "k. ¬ k < k_tm M
               ae_blk_agree (le_tm M) (buf_r k) (buf_f k)"
    proof (intro allI impI)
      fix k assume "¬ k < k_tm M"
      hence kge: "k_tm M  k" by simp
      have "buf_r k = buf_f k" using run_tails fwd_tails kge by simp
      thus "ae_blk_agree (le_tm M) (buf_r k) (buf_f k)"
        by (simp add: ae_blk_agree_def)
    qed
    have dest_tail: "k. ¬ k < k_tm M  dest_r k = dest_f k"
    proof (intro allI impI)
      fix k assume "¬ k < k_tm M"
      hence kge: "k_tm M  k" by simp
      show "dest_r k = dest_f k" using run_tails fwd_tails kge by simp
    qed

    show ?thesis
      by (rule nae_sim_proto[OF run_q_in_Q step4_sub fwd45 run_c4_state
                                fwd_c4_state run_window fwd_window
                                buf_tail dest_tail
                                step5_sub step6_sub step7_sub step8_sub
                                f_step5 f_step6 f_step7 f_step8
                                sim_c''' gamma_c''])
  qed

  show ?thesis
    by (rule that[OF cM_trace n_bnd halt_or_full ae_sim_c''
                     buf_gamma_c'' le_anchor_c''])
qed


subsubsection ‹Substep cycle progression›

text ‹Substep-cycle progression: a single full-delta step from a
  config whose substep idx is SS1› lands at SS2›.

  Mechanism: the full alphabet_enlarge_delta› is the union
  of 16 per-substep deltas, each of whose source tuple fixes the
  substep idx to its own SS⟨N⟩› / validation marker.
  From an SS1›-source step, only ae_delta_ss1_ss2›'s
  source matches.  Combined with
  ae_substep_state_shape›, the post-substep idx is forced
  to SS2›.

  Foundation for the substep-cycle tracking that
  forces m ≥ 8› in the reverse chunked-phase induction;
  without this, m ∈ ⦃1,...,7⦄›-paths from
  SS1› can't be ruled out as candidates for reaching
  VFwd›-halt.›

lemma ae_step_from_SS1_lands_at_SS2:
  fixes M :: "('q, 'a) mttm"
    and c' c'' :: "('c :: enum  'a,
                     'q × ('a, 'c) ae_stage) mt_config"
  assumes idx: "snd (snd (snd (snd (mt_state c')))) = SS1"
      and step: "(c', c'')  mttm_step (alphabet_enlarge_delta M)"
  shows "snd (snd (snd (snd (mt_state c'')))) = SS2"
proof -
  from step obtain s ts n s' a' d where
      c'_eq: "c' = ConfigM s ts n"
    and c''_eq: "c'' = ConfigM s' (λk. (ts k)(n k := a' k))
                                  (λk. go_dir (d k) (n k))"
    and rel: "(s, (λk. ts k (n k)), s', a', d)  alphabet_enlarge_delta M"
    by (auto elim: mttm_step.cases)
  obtain qS oS bS dS sxS where s_split: "s = (qS, oS, bS, dS, sxS)"
    by (cases s) auto
  from idx c'_eq s_split have sxS_SS1: "sxS = SS1" by simp
  have rel_in_ss1_ss2:
      "(s, (λk. ts k (n k)), s', a', d)  ae_delta_ss1_ss2 M"
    using rel s_split sxS_SS1
    unfolding alphabet_enlarge_delta_def
              ae_delta_val_fwd_advance_def
              ae_delta_val_fwd_to_padded_def
              ae_delta_val_fwd_reject_def
              ae_delta_val_fwd_to_ret_def
              ae_delta_val_pad_to_ret_def
              ae_delta_val_pad_reject_def
              ae_delta_val_ret_step_def
              ae_delta_val_ret_to_sim_def
              ae_delta_ss2_ss3_def
              ae_delta_ss3_ss4_def
              ae_delta_ss4_ss5_def
              ae_delta_ss5_ss6_def
              ae_delta_ss6_ss7_def
              ae_delta_ss7_ss8_def
              ae_delta_ss8_ss1_def
    by auto
  obtain qN oN bN dN where s'_split: "s' = (qN, oN, bN, dN, SS2)"
    using rel_in_ss1_ss2 unfolding ae_delta_ss1_ss2_def by blast
  show ?thesis using c''_eq s'_split by simp
qed

lemma ae_step_from_SS2_lands_at_SS3:
  fixes M :: "('q, 'a) mttm"
    and c' c'' :: "('c :: enum  'a,
                     'q × ('a, 'c) ae_stage) mt_config"
  assumes idx: "snd (snd (snd (snd (mt_state c')))) = SS2"
      and step: "(c', c'')  mttm_step (alphabet_enlarge_delta M)"
  shows "snd (snd (snd (snd (mt_state c'')))) = SS3"
proof -
  from step obtain s ts n s' a' d where
      c'_eq: "c' = ConfigM s ts n"
    and c''_eq: "c'' = ConfigM s' (λk. (ts k)(n k := a' k))
                                  (λk. go_dir (d k) (n k))"
    and rel: "(s, (λk. ts k (n k)), s', a', d)  alphabet_enlarge_delta M"
    by (auto elim: mttm_step.cases)
  obtain qS oS bS dS sxS where s_split: "s = (qS, oS, bS, dS, sxS)"
    by (cases s) auto
  from idx c'_eq s_split have sxS_SS2: "sxS = SS2" by simp
  have rel_in_ss2_ss3:
      "(s, (λk. ts k (n k)), s', a', d)  ae_delta_ss2_ss3 M"
    using rel s_split sxS_SS2
    unfolding alphabet_enlarge_delta_def
              ae_delta_val_fwd_advance_def
              ae_delta_val_fwd_to_padded_def
              ae_delta_val_fwd_reject_def
              ae_delta_val_fwd_to_ret_def
              ae_delta_val_pad_to_ret_def
              ae_delta_val_pad_reject_def
              ae_delta_val_ret_step_def
              ae_delta_val_ret_to_sim_def
              ae_delta_ss1_ss2_def
              ae_delta_ss3_ss4_def
              ae_delta_ss4_ss5_def
              ae_delta_ss5_ss6_def
              ae_delta_ss6_ss7_def
              ae_delta_ss7_ss8_def
              ae_delta_ss8_ss1_def
    by auto
  obtain qN oN bN dN where s'_split: "s' = (qN, oN, bN, dN, SS3)"
    using rel_in_ss2_ss3 unfolding ae_delta_ss2_ss3_def by blast
  show ?thesis using c''_eq s'_split by simp
qed

lemma ae_step_from_SS3_lands_at_SS4:
  fixes M :: "('q, 'a) mttm"
    and c' c'' :: "('c :: enum  'a,
                     'q × ('a, 'c) ae_stage) mt_config"
  assumes idx: "snd (snd (snd (snd (mt_state c')))) = SS3"
      and step: "(c', c'')  mttm_step (alphabet_enlarge_delta M)"
  shows "snd (snd (snd (snd (mt_state c'')))) = SS4"
proof -
  from step obtain s ts n s' a' d where
      c'_eq: "c' = ConfigM s ts n"
    and c''_eq: "c'' = ConfigM s' (λk. (ts k)(n k := a' k))
                                  (λk. go_dir (d k) (n k))"
    and rel: "(s, (λk. ts k (n k)), s', a', d)  alphabet_enlarge_delta M"
    by (auto elim: mttm_step.cases)
  obtain qS oS bS dS sxS where s_split: "s = (qS, oS, bS, dS, sxS)"
    by (cases s) auto
  from idx c'_eq s_split have sxS_SS3: "sxS = SS3" by simp
  have rel_in_ss3_ss4:
      "(s, (λk. ts k (n k)), s', a', d)  ae_delta_ss3_ss4 M"
    using rel s_split sxS_SS3
    unfolding alphabet_enlarge_delta_def
              ae_delta_val_fwd_advance_def
              ae_delta_val_fwd_to_padded_def
              ae_delta_val_fwd_reject_def
              ae_delta_val_fwd_to_ret_def
              ae_delta_val_pad_to_ret_def
              ae_delta_val_pad_reject_def
              ae_delta_val_ret_step_def
              ae_delta_val_ret_to_sim_def
              ae_delta_ss1_ss2_def
              ae_delta_ss2_ss3_def
              ae_delta_ss4_ss5_def
              ae_delta_ss5_ss6_def
              ae_delta_ss6_ss7_def
              ae_delta_ss7_ss8_def
              ae_delta_ss8_ss1_def
    by auto
  obtain qN oN bN dN where s'_split: "s' = (qN, oN, bN, dN, SS4)"
    using rel_in_ss3_ss4 unfolding ae_delta_ss3_ss4_def by blast
  show ?thesis using c''_eq s'_split by simp
qed

lemma ae_step_from_SS4_lands_at_SS5:
  fixes M :: "('q, 'a) mttm"
    and c' c'' :: "('c :: enum  'a,
                     'q × ('a, 'c) ae_stage) mt_config"
  assumes idx: "snd (snd (snd (snd (mt_state c')))) = SS4"
      and step: "(c', c'')  mttm_step (alphabet_enlarge_delta M)"
  shows "snd (snd (snd (snd (mt_state c'')))) = SS5"
proof -
  from step obtain s ts n s' a' d where
      c'_eq: "c' = ConfigM s ts n"
    and c''_eq: "c'' = ConfigM s' (λk. (ts k)(n k := a' k))
                                  (λk. go_dir (d k) (n k))"
    and rel: "(s, (λk. ts k (n k)), s', a', d)  alphabet_enlarge_delta M"
    by (auto elim: mttm_step.cases)
  obtain qS oS bS dS sxS where s_split: "s = (qS, oS, bS, dS, sxS)"
    by (cases s) auto
  from idx c'_eq s_split have sxS_SS4: "sxS = SS4" by simp
  have rel_in_ss4_ss5:
      "(s, (λk. ts k (n k)), s', a', d)  ae_delta_ss4_ss5 M"
    using rel s_split sxS_SS4
    unfolding alphabet_enlarge_delta_def
              ae_delta_val_fwd_advance_def
              ae_delta_val_fwd_to_padded_def
              ae_delta_val_fwd_reject_def
              ae_delta_val_fwd_to_ret_def
              ae_delta_val_pad_to_ret_def
              ae_delta_val_pad_reject_def
              ae_delta_val_ret_step_def
              ae_delta_val_ret_to_sim_def
              ae_delta_ss1_ss2_def
              ae_delta_ss2_ss3_def
              ae_delta_ss3_ss4_def
              ae_delta_ss5_ss6_def
              ae_delta_ss6_ss7_def
              ae_delta_ss7_ss8_def
              ae_delta_ss8_ss1_def
    by auto
  obtain qN oN bN dN where s'_split: "s' = (qN, oN, bN, dN, SS5)"
    using rel_in_ss4_ss5 unfolding ae_delta_ss4_ss5_def by blast
  show ?thesis using c''_eq s'_split by simp
qed

lemma ae_step_from_SS5_lands_at_SS6:
  fixes M :: "('q, 'a) mttm"
    and c' c'' :: "('c :: enum  'a,
                     'q × ('a, 'c) ae_stage) mt_config"
  assumes idx: "snd (snd (snd (snd (mt_state c')))) = SS5"
      and step: "(c', c'')  mttm_step (alphabet_enlarge_delta M)"
  shows "snd (snd (snd (snd (mt_state c'')))) = SS6"
proof -
  from step obtain s ts n s' a' d where
      c'_eq: "c' = ConfigM s ts n"
    and c''_eq: "c'' = ConfigM s' (λk. (ts k)(n k := a' k))
                                  (λk. go_dir (d k) (n k))"
    and rel: "(s, (λk. ts k (n k)), s', a', d)  alphabet_enlarge_delta M"
    by (auto elim: mttm_step.cases)
  obtain qS oS bS dS sxS where s_split: "s = (qS, oS, bS, dS, sxS)"
    by (cases s) auto
  from idx c'_eq s_split have sxS_SS5: "sxS = SS5" by simp
  have rel_in_ss5_ss6:
      "(s, (λk. ts k (n k)), s', a', d)  ae_delta_ss5_ss6 M"
    using rel s_split sxS_SS5
    unfolding alphabet_enlarge_delta_def
              ae_delta_val_fwd_advance_def
              ae_delta_val_fwd_to_padded_def
              ae_delta_val_fwd_reject_def
              ae_delta_val_fwd_to_ret_def
              ae_delta_val_pad_to_ret_def
              ae_delta_val_pad_reject_def
              ae_delta_val_ret_step_def
              ae_delta_val_ret_to_sim_def
              ae_delta_ss1_ss2_def
              ae_delta_ss2_ss3_def
              ae_delta_ss3_ss4_def
              ae_delta_ss4_ss5_def
              ae_delta_ss6_ss7_def
              ae_delta_ss7_ss8_def
              ae_delta_ss8_ss1_def
    by auto
  obtain qN oN bN dN where s'_split: "s' = (qN, oN, bN, dN, SS6)"
    using rel_in_ss5_ss6 unfolding ae_delta_ss5_ss6_def by blast
  show ?thesis using c''_eq s'_split by simp
qed

lemma ae_step_from_SS6_lands_at_SS7:
  fixes M :: "('q, 'a) mttm"
    and c' c'' :: "('c :: enum  'a,
                     'q × ('a, 'c) ae_stage) mt_config"
  assumes idx: "snd (snd (snd (snd (mt_state c')))) = SS6"
      and step: "(c', c'')  mttm_step (alphabet_enlarge_delta M)"
  shows "snd (snd (snd (snd (mt_state c'')))) = SS7"
proof -
  from step obtain s ts n s' a' d where
      c'_eq: "c' = ConfigM s ts n"
    and c''_eq: "c'' = ConfigM s' (λk. (ts k)(n k := a' k))
                                  (λk. go_dir (d k) (n k))"
    and rel: "(s, (λk. ts k (n k)), s', a', d)  alphabet_enlarge_delta M"
    by (auto elim: mttm_step.cases)
  obtain qS oS bS dS sxS where s_split: "s = (qS, oS, bS, dS, sxS)"
    by (cases s) auto
  from idx c'_eq s_split have sxS_SS6: "sxS = SS6" by simp
  have rel_in_ss6_ss7:
      "(s, (λk. ts k (n k)), s', a', d)  ae_delta_ss6_ss7 M"
    using rel s_split sxS_SS6
    unfolding alphabet_enlarge_delta_def
              ae_delta_val_fwd_advance_def
              ae_delta_val_fwd_to_padded_def
              ae_delta_val_fwd_reject_def
              ae_delta_val_fwd_to_ret_def
              ae_delta_val_pad_to_ret_def
              ae_delta_val_pad_reject_def
              ae_delta_val_ret_step_def
              ae_delta_val_ret_to_sim_def
              ae_delta_ss1_ss2_def
              ae_delta_ss2_ss3_def
              ae_delta_ss3_ss4_def
              ae_delta_ss4_ss5_def
              ae_delta_ss5_ss6_def
              ae_delta_ss7_ss8_def
              ae_delta_ss8_ss1_def
    by auto
  obtain qN oN bN dN where s'_split: "s' = (qN, oN, bN, dN, SS7)"
    using rel_in_ss6_ss7 unfolding ae_delta_ss6_ss7_def by blast
  show ?thesis using c''_eq s'_split by simp
qed

lemma ae_step_from_SS7_lands_at_SS8:
  fixes M :: "('q, 'a) mttm"
    and c' c'' :: "('c :: enum  'a,
                     'q × ('a, 'c) ae_stage) mt_config"
  assumes idx: "snd (snd (snd (snd (mt_state c')))) = SS7"
      and step: "(c', c'')  mttm_step (alphabet_enlarge_delta M)"
  shows "snd (snd (snd (snd (mt_state c'')))) = SS8"
proof -
  from step obtain s ts n s' a' d where
      c'_eq: "c' = ConfigM s ts n"
    and c''_eq: "c'' = ConfigM s' (λk. (ts k)(n k := a' k))
                                  (λk. go_dir (d k) (n k))"
    and rel: "(s, (λk. ts k (n k)), s', a', d)  alphabet_enlarge_delta M"
    by (auto elim: mttm_step.cases)
  obtain qS oS bS dS sxS where s_split: "s = (qS, oS, bS, dS, sxS)"
    by (cases s) auto
  from idx c'_eq s_split have sxS_SS7: "sxS = SS7" by simp
  have rel_in_ss7_ss8:
      "(s, (λk. ts k (n k)), s', a', d)  ae_delta_ss7_ss8 M"
    using rel s_split sxS_SS7
    unfolding alphabet_enlarge_delta_def
              ae_delta_val_fwd_advance_def
              ae_delta_val_fwd_to_padded_def
              ae_delta_val_fwd_reject_def
              ae_delta_val_fwd_to_ret_def
              ae_delta_val_pad_to_ret_def
              ae_delta_val_pad_reject_def
              ae_delta_val_ret_step_def
              ae_delta_val_ret_to_sim_def
              ae_delta_ss1_ss2_def
              ae_delta_ss2_ss3_def
              ae_delta_ss3_ss4_def
              ae_delta_ss4_ss5_def
              ae_delta_ss5_ss6_def
              ae_delta_ss6_ss7_def
              ae_delta_ss8_ss1_def
    by auto
  obtain qN oN bN dN where s'_split: "s' = (qN, oN, bN, dN, SS8)"
    using rel_in_ss7_ss8 unfolding ae_delta_ss7_ss8_def by blast
  show ?thesis using c''_eq s'_split by simp
qed

text ‹SS8 is the cycle-closure substep: post-state lands at
  SS1› (steady-state continuation) or VFwd›
  (halt-branch, when the simulated M›-state at SS8 is in
  ⦃t_tm M, r_tm M⦄›).  The looser
  SS1 ∨ VFwd› disjunction is what the reverse-arm
  chain-progression argument needs; the precise branch resolution
  is handled by ae_step_ss8_ss1_invariant› /
  ae_step_ss8_ss1_invariant_halt›.›

lemma ae_step_from_SS8_lands_at_SS1_or_VFwd:
  fixes M :: "('q, 'a) mttm"
    and c' c'' :: "('c :: enum  'a,
                     'q × ('a, 'c) ae_stage) mt_config"
  assumes idx: "snd (snd (snd (snd (mt_state c')))) = SS8"
      and step: "(c', c'')  mttm_step (alphabet_enlarge_delta M)"
  shows "snd (snd (snd (snd (mt_state c''))))  {SS1, VFwd}"
proof -
  from step obtain s ts n s' a' d where
      c'_eq: "c' = ConfigM s ts n"
    and c''_eq: "c'' = ConfigM s' (λk. (ts k)(n k := a' k))
                                  (λk. go_dir (d k) (n k))"
    and rel: "(s, (λk. ts k (n k)), s', a', d)  alphabet_enlarge_delta M"
    by (auto elim: mttm_step.cases)
  obtain qS oS bS dS sxS where s_split: "s = (qS, oS, bS, dS, sxS)"
    by (cases s) auto
  from idx c'_eq s_split have sxS_SS8: "sxS = SS8" by simp
  have rel_in_ss8_ss1:
      "(s, (λk. ts k (n k)), s', a', d)  ae_delta_ss8_ss1 M"
    using rel s_split sxS_SS8
    unfolding alphabet_enlarge_delta_def
              ae_delta_val_fwd_advance_def
              ae_delta_val_fwd_to_padded_def
              ae_delta_val_fwd_reject_def
              ae_delta_val_fwd_to_ret_def
              ae_delta_val_pad_to_ret_def
              ae_delta_val_pad_reject_def
              ae_delta_val_ret_step_def
              ae_delta_val_ret_to_sim_def
              ae_delta_ss1_ss2_def
              ae_delta_ss2_ss3_def
              ae_delta_ss3_ss4_def
              ae_delta_ss4_ss5_def
              ae_delta_ss5_ss6_def
              ae_delta_ss6_ss7_def
              ae_delta_ss7_ss8_def
    by auto
  obtain q ofs buf dest stage' where
      s_eq_full: "s = (q, ofs, buf, dest, SS8)"
    and s'_eq: "s' = (q, stage')"
    and stage'_eq: "stage' = (if q  {t_tm M, r_tm M}
                                then init_stage (le_tm M)
                                else (ofs, buf, init_dest, SS1))"
    using rel_in_ss8_ss1 unfolding ae_delta_ss8_ss1_def by auto
  have init_stage_substep_VFwd:
      "snd (snd (snd (init_stage (le_tm M) :: ('a, 'c) ae_stage))) = VFwd"
    unfolding init_stage_def by simp
  show ?thesis
  proof (cases "q  {t_tm M, r_tm M}")
    case True
    hence stage'_init: "stage' = init_stage (le_tm M)"
      using stage'_eq by simp
    have "snd (snd (snd (snd (mt_state c'')))) = VFwd"
      using c''_eq s'_eq stage'_init init_stage_substep_VFwd by simp
    thus ?thesis by simp
  next
    case False
    hence stage'_cont: "stage' = (ofs, buf, init_dest, SS1)"
      using stage'_eq by simp
    have "snd (snd (snd (snd (mt_state c'')))) = SS1"
      using c''_eq s'_eq stage'_cont by simp
    thus ?thesis by simp
  qed
qed


text ‹Chain-progression: from a config at substep SS1›,
  no chain of length 1 ≤ m ≤ 7› reaches a configuration
  at substep VFwd›.  The substep cycle SS1
  → SS2 → ... → SS8 →
  SS1 ∨ VFwd› takes exactly 8 steps from SS1› to
  reach VFwd›; shorter chains stay within
  ⦃SS2,...,SS8⦄›.

  Used by the reverse chunked-phase argument to force m ≥
  8› when an SS1-paired c'› has a chain ending in the
  canonical halt config (t_tm M, init_stage le)›.›

lemma ae_chain_from_SS1_short_not_VFwd:
  fixes M :: "('q, 'a) mttm"
    and c' c'' :: "('c :: enum  'a,
                     'q × ('a, 'c) ae_stage) mt_config"
    and m :: nat
  assumes idx_SS1: "snd (snd (snd (snd (mt_state c')))) = SS1"
      and m_lt_8:  "0 < m  m < 8"
      and chain:   "(c', c'')  mttm_step (alphabet_enlarge_delta M) ^^ m"
  shows "snd (snd (snd (snd (mt_state c''))))  VFwd"
proof -
  let ?R = "mttm_step (alphabet_enlarge_delta M)"
  let ?idx = "λc. snd (snd (snd (snd (mt_state c))))"
  consider (m1) "m = 1" | (m2) "m = 2" | (m3) "m = 3" | (m4) "m = 4"
         | (m5) "m = 5" | (m6) "m = 6" | (m7) "m = 7"
    using m_lt_8 by linarith
  thus ?thesis
  proof cases
    case m1
    have step1: "(c', c'')  ?R" using chain m1 by simp
    have "?idx c'' = SS2"
      by (rule ae_step_from_SS1_lands_at_SS2[OF idx_SS1 step1])
    thus ?thesis by simp
  next
    case m2
    from chain m2 obtain c1 where
        e1: "(c', c1)  ?R" and e2: "(c1, c'')  ?R"
      by (auto dest!: relpow_Suc_D2 simp: numeral_eq_Suc)
    have "?idx c1 = SS2"
      by (rule ae_step_from_SS1_lands_at_SS2[OF idx_SS1 e1])
    hence "?idx c'' = SS3"
      by (rule ae_step_from_SS2_lands_at_SS3[OF _ e2])
    thus ?thesis by simp
  next
    case m3
    from chain m3 obtain c1 c2 where
        e1: "(c', c1)  ?R" and e2: "(c1, c2)  ?R"
        and e3: "(c2, c'')  ?R"
      by (auto dest!: relpow_Suc_D2 simp: numeral_eq_Suc)
    have x1: "?idx c1 = SS2"
      by (rule ae_step_from_SS1_lands_at_SS2[OF idx_SS1 e1])
    have x2: "?idx c2 = SS3"
      by (rule ae_step_from_SS2_lands_at_SS3[OF x1 e2])
    hence "?idx c'' = SS4"
      by (rule ae_step_from_SS3_lands_at_SS4[OF _ e3])
    thus ?thesis by simp
  next
    case m4
    from chain m4 obtain c1 c2 c3 where
        e1: "(c', c1)  ?R" and e2: "(c1, c2)  ?R"
        and e3: "(c2, c3)  ?R" and e4: "(c3, c'')  ?R"
      by (auto dest!: relpow_Suc_D2 simp: numeral_eq_Suc)
    have x1: "?idx c1 = SS2"
      by (rule ae_step_from_SS1_lands_at_SS2[OF idx_SS1 e1])
    have x2: "?idx c2 = SS3"
      by (rule ae_step_from_SS2_lands_at_SS3[OF x1 e2])
    have x3: "?idx c3 = SS4"
      by (rule ae_step_from_SS3_lands_at_SS4[OF x2 e3])
    hence "?idx c'' = SS5"
      by (rule ae_step_from_SS4_lands_at_SS5[OF _ e4])
    thus ?thesis by simp
  next
    case m5
    from chain m5 obtain c1 c2 c3 c4 where
        e1: "(c', c1)  ?R" and e2: "(c1, c2)  ?R"
        and e3: "(c2, c3)  ?R" and e4: "(c3, c4)  ?R"
        and e5: "(c4, c'')  ?R"
      by (auto dest!: relpow_Suc_D2 simp: numeral_eq_Suc)
    have x1: "?idx c1 = SS2"
      by (rule ae_step_from_SS1_lands_at_SS2[OF idx_SS1 e1])
    have x2: "?idx c2 = SS3"
      by (rule ae_step_from_SS2_lands_at_SS3[OF x1 e2])
    have x3: "?idx c3 = SS4"
      by (rule ae_step_from_SS3_lands_at_SS4[OF x2 e3])
    have x4: "?idx c4 = SS5"
      by (rule ae_step_from_SS4_lands_at_SS5[OF x3 e4])
    hence "?idx c'' = SS6"
      by (rule ae_step_from_SS5_lands_at_SS6[OF _ e5])
    thus ?thesis by simp
  next
    case m6
    from chain m6 obtain c1 c2 c3 c4 c5 where
        e1: "(c', c1)  ?R" and e2: "(c1, c2)  ?R"
        and e3: "(c2, c3)  ?R" and e4: "(c3, c4)  ?R"
        and e5: "(c4, c5)  ?R" and e6: "(c5, c'')  ?R"
      by (auto dest!: relpow_Suc_D2 simp: numeral_eq_Suc)
    have x1: "?idx c1 = SS2"
      by (rule ae_step_from_SS1_lands_at_SS2[OF idx_SS1 e1])
    have x2: "?idx c2 = SS3"
      by (rule ae_step_from_SS2_lands_at_SS3[OF x1 e2])
    have x3: "?idx c3 = SS4"
      by (rule ae_step_from_SS3_lands_at_SS4[OF x2 e3])
    have x4: "?idx c4 = SS5"
      by (rule ae_step_from_SS4_lands_at_SS5[OF x3 e4])
    have x5: "?idx c5 = SS6"
      by (rule ae_step_from_SS5_lands_at_SS6[OF x4 e5])
    hence "?idx c'' = SS7"
      by (rule ae_step_from_SS6_lands_at_SS7[OF _ e6])
    thus ?thesis by simp
  next
    case m7
    from chain m7 obtain c1 c2 c3 c4 c5 c6 where
        e1: "(c', c1)  ?R" and e2: "(c1, c2)  ?R"
        and e3: "(c2, c3)  ?R" and e4: "(c3, c4)  ?R"
        and e5: "(c4, c5)  ?R" and e6: "(c5, c6)  ?R"
        and e7: "(c6, c'')  ?R"
      by (auto dest!: relpow_Suc_D2 simp: numeral_eq_Suc)
    have x1: "?idx c1 = SS2"
      by (rule ae_step_from_SS1_lands_at_SS2[OF idx_SS1 e1])
    have x2: "?idx c2 = SS3"
      by (rule ae_step_from_SS2_lands_at_SS3[OF x1 e2])
    have x3: "?idx c3 = SS4"
      by (rule ae_step_from_SS3_lands_at_SS4[OF x2 e3])
    have x4: "?idx c4 = SS5"
      by (rule ae_step_from_SS4_lands_at_SS5[OF x3 e4])
    have x5: "?idx c5 = SS6"
      by (rule ae_step_from_SS5_lands_at_SS6[OF x4 e5])
    have x6: "?idx c6 = SS7"
      by (rule ae_step_from_SS6_lands_at_SS7[OF x5 e6])
    hence "?idx c'' = SS8"
      by (rule ae_step_from_SS7_lands_at_SS8[OF _ e7])
    thus ?thesis by simp
  qed
qed


subsubsection ‹Reverse-arm dispatcher and substrate consequences›

text ‹Substrate consequence: from reachability of cM› from
  init_config_mttm M w›, every M›-tape cell at any positive
  index along that trace is not the left-end marker le_tm M›.
  Packaged as the no_le_per_tape› conjunct expected by
  ae_backward_stage› (forward chunked-phase derivation pattern
  at lines 8688+ of AlphabetEnlargement.thy›).  Factored out
  so the main chunked-reverse induction body stays under
  elaboration budget.›

lemma ae_no_le_per_tape_from_reach:
  fixes M :: "('q, 'a) mttm"
    and w :: "'a list"
    and cM :: "('a, 'q) mt_config"
    and c' :: "('c :: enum  'a,
                 'q × ('a, 'c) ae_stage) mt_config"
  assumes vM:        "valid_mttm M"
      and lu:        "le_unique M"
      and w_sub:     "set w  Sigma_tm M"
      and le_neq_bl: "le_tm M  bl_tm M"
      and reach_M:   "(init_config_mttm M w, cM)
                         (mttm_step (delta_tm M))*"
  shows "k. (mt_pos c' k  2
                 (i. i < 3 * card (UNIV :: 'c set)
                           mt_tape cM k
                                ((mt_pos c' k - 2)
                                    * card (UNIV :: 'c set)
                                   + 1 + i)
                               le_tm M))
              (mt_pos c' k = 1
                   (i. i < 2 * card (UNIV :: 'c set)
                             mt_tape cM k (Suc i)  le_tm M))
              (mt_pos c' k = 0
                   (i. i < card (UNIV :: 'c set)
                             mt_tape cM k (Suc i)  le_tm M))"
proof (intro allI conjI impI allI impI)
  fix k :: nat and i :: nat
  assume "2  mt_pos c' k"
     and "i < 3 * card (UNIV :: 'c set)"
  have idx_nz:
      "(mt_pos c' k - 2) * card (UNIV :: 'c set) + 1 + i  0"
    by simp
  show "mt_tape cM k
          ((mt_pos c' k - 2) * card (UNIV :: 'c set)
             + 1 + i)  le_tm M"
    using valid_reach_LE_only_pos0_mttm
            [OF vM lu w_sub reach_M idx_nz le_neq_bl[symmetric]] .
next
  fix k :: nat and i :: nat
  assume "mt_pos c' k = 1"
     and "i < 2 * card (UNIV :: 'c set)"
  have idx_nz: "Suc i  0" by simp
  show "mt_tape cM k (Suc i)  le_tm M"
    using valid_reach_LE_only_pos0_mttm
            [OF vM lu w_sub reach_M idx_nz le_neq_bl[symmetric]] .
next
  fix k :: nat and i :: nat
  assume "mt_pos c' k = 0"
     and "i < card (UNIV :: 'c set)"
  have idx_nz: "Suc i  0" by simp
  show "mt_tape cM k (Suc i)  le_tm M"
    using valid_reach_LE_only_pos0_mttm
            [OF vM lu w_sub reach_M idx_nz le_neq_bl[symmetric]] .
qed


text ‹Halt-branch contradiction: when mt_state c'› is at a
  halt-coerced state (qM', init_stage le)› with qM' ∈
  {t_tm M, r_tm M}›, the alphabet-enlarged accept/reject bridges
  identify the configuration's state with t_tm M'› /
  r_tm M'›, and mttm_step_src_neq_t› /
  mttm_step_src_neq_r› rule out any outgoing step.  Factored
  out so the chunked-reverse induction body's halt-branch
  dispatch is a single have False ...›.›

lemma ae_halt_c'_no_step:
  fixes M :: "('q, 'a) mttm"
    and qM' :: 'q
    and c' c'' :: "(('c :: enum)  'a,
                     'q × ('a, 'c) ae_stage) mt_config"
  assumes vM:        "valid_mttm M"
      and qM_in_tr:  "qM'  {t_tm M, r_tm M}"
      and state_c':  "mt_state c' = (qM', init_stage (le_tm M))"
      and step:      "(c', c'')
                           mttm_step (alphabet_enlarge_delta M)"
  shows "False"
proof -
  let ?M' = "alphabet_enlarge M
               :: ('q × ('a, 'c) ae_stage,
                   'c  'a) mttm"
  have valM': "valid_mttm ?M'"
    by (rule alphabet_enlarge_wf[OF vM])
  have step_M': "(c', c'')  mttm_step (delta_tm ?M')"
    using step by (simp add: delta_tm_alphabet_enlarge)
  from qM_in_tr have qM_cases: "qM' = t_tm M  qM' = r_tm M"
    by blast
  thus False
  proof
    assume "qM' = t_tm M"
    hence "mt_state c' = t_tm ?M'"
      using state_c' by (simp add: t_tm_alphabet_enlarge)
    thus False using mttm_step_src_neq_t[OF valM' step_M']
      by simp
  next
    assume "qM' = r_tm M"
    hence "mt_state c' = r_tm ?M'"
      using state_c' by (simp add: r_tm_alphabet_enlarge)
    thus False using mttm_step_src_neq_r[OF valM' step_M']
      by simp
  qed
qed


subsubsection ‹Chunked-reverse engine and language equivalence›

text ‹Chunked-induction engine for the reverse arm.  Given a
  finite M'›-chain (c', c_acc)› of length m› ending in the
  canonical halt configuration (t_tm M, init_stage le)›, plus an
  ae_simulates› invariant at c'› with the standard side-band
  invariants buf_gamma› and le_anchor›, deliver an accepting
  M›-path from cM›.  Mirror of ae_simulation_phase_chunked›
  (forward) but inducting on the M'›-side chain length rather
  than the M›-side: at each level we peel 8 M'›-steps via
  ae_backward_stage› and recurse.

  Three induction cases:
   ∙›m = 0› base: c' = c_acc›; the simulation's accept
     correspondence forces mt_state cM = t_tm M›.
   ∙›0 < m < 8›: contradiction via
     ae_chain_from_SS1_short_not_VFwd› (or trivial substep
     mismatch when c' = c_acc›'s sister case applies).
   ∙›m ≥ 8› peel: split m = 8 + (m - 8)› via relpow_add›,
     apply ae_backward_stage› to the first chunk, IH on m - 8›.

  The conclusion is in rtrancl› form (the n_M› step counter
  is forgotten via relpow_imp_rtrancl›) to ease the downstream
  Lang_mttm›-repacking in alphabet_enlarge_language›.›

lemma ae_simulation_phase_chunked_reverse:
  fixes M :: "('q, 'a) mttm"
    and w :: "'a list"
    and cM :: "('a, 'q) mt_config"
    and c' c_acc :: "('c :: enum  'a,
                'q × ('a, 'c) ae_stage) mt_config"
    and m :: nat
  assumes vM:         "valid_mttm M"
      and lu:         "le_unique M"
      and w_sub:      "set w  Sigma_tm M"
      and le_neq_bl:  "le_tm M  bl_tm M"
      and reach_M:    "(init_config_mttm M w, cM)
                           (mttm_step (delta_tm M))*"
      and trace:      "(c', c_acc)
                           mttm_step (alphabet_enlarge_delta M) ^^ m"
      and accept:     "mt_state c_acc
                          = (t_tm M, init_stage (le_tm M))"
      and sim:        "ae_simulates M cM c'"
      and buf_gamma:  "ae_buffer_in_gamma_block M c'"
      and le_anchor:  "kk<k_tm M. mt_tape c' kk 0 = LE_block (le_tm M)"
  shows "cM_final. (cM, cM_final)  (mttm_step (delta_tm M))*
                     mt_state cM_final = t_tm M"
  using reach_M trace sim buf_gamma le_anchor
proof (induction m arbitrary: cM c' rule: less_induct)
  case (less m)
  obtain qM' ofs buf dest idx where
      state_c': "mt_state c' = (qM', ofs, buf, dest, idx)"
    and qM_eq:   "mt_state cM = qM'"
    and state_disj: "(idx = SS1  qM'  {t_tm M, r_tm M})
                      (qM'  {t_tm M, r_tm M}
                          (ofs, buf, dest, idx)
                             = init_stage (le_tm M))"
    and "k<k_tm M. ae_tape_correspondence (le_tm M)
                (mt_tape cM k) (mt_tape c' k)"
    and "ae_tape_in_gamma_block M c'"
    by (rule ae_simulates_state_disjunction[OF less.prems(3)])
  consider (halt) "qM'  {t_tm M, r_tm M}
                    (ofs, buf, dest, idx) = init_stage (le_tm M)"
         | (ss1)  "idx = SS1  qM'  {t_tm M, r_tm M}"
    using state_disj by blast
  thus ?case
  proof cases
    case halt
    have state_full: "mt_state c' = (qM', init_stage (le_tm M))"
      using state_c' halt by simp
    show ?thesis
    proof (cases m)
      case 0
      from less.prems(2) 0 have c'_eq: "c' = c_acc" by simp
      have "mt_state c' = (t_tm M, init_stage (le_tm M))"
        using accept c'_eq by simp
      hence qM_t: "qM' = t_tm M" using state_full by simp
      have cM_state: "mt_state cM = t_tm M" using qM_eq qM_t by simp
      have refl: "(cM, cM)  (mttm_step (delta_tm M))*" by simp
      show ?thesis using refl cM_state by blast
    next
      case (Suc m')
      have trace_Suc:
          "(c', c_acc)  mttm_step (alphabet_enlarge_delta M)
                              ^^ Suc m'"
        using less.prems(2) Suc by simp
      obtain c'_1 where
          first_step:
              "(c', c'_1)  mttm_step (alphabet_enlarge_delta M)"
        and rest_trace:
              "(c'_1, c_acc)  mttm_step (alphabet_enlarge_delta M)
                                    ^^ m'"
        using relpow_Suc_D2[OF trace_Suc] by blast
      have qM_in_tr: "qM'  {t_tm M, r_tm M}" using halt by simp
      have False
        by (rule ae_halt_c'_no_step
                   [OF vM qM_in_tr state_full first_step])
      thus ?thesis by simp
    qed
  next
    case ss1
    from ss1 have idx_SS1: "idx = SS1" by simp
    have idx_snd4: "snd (snd (snd (snd (mt_state c')))) = SS1"
      using state_c' idx_SS1 by simp
    have qM_neq_t: "mt_state cM  t_tm M" using qM_eq ss1 by simp
    have qM_neq_r: "mt_state cM  r_tm M" using qM_eq ss1 by simp
    consider (m_zero) "m = 0"
           | (m_short) "0 < m  m < 8"
           | (m_long) "8  m"
      by linarith
    thus ?thesis
    proof cases
      case m_zero
      from less.prems(2) m_zero have c'_eq: "c' = c_acc" by simp
      have "mt_state c' = (t_tm M, init_stage (le_tm M))"
        using accept c'_eq by simp
      hence c'_VFwd: "snd (snd (snd (snd (mt_state c')))) = VFwd"
        unfolding init_stage_def by simp
      from c'_VFwd idx_snd4 have False by simp
      thus ?thesis by simp
    next
      case m_short
      have c_acc_VFwd:
          "snd (snd (snd (snd (mt_state c_acc)))) = VFwd"
        using accept by (simp add: init_stage_def)
      have not_VFwd:
          "snd (snd (snd (snd (mt_state c_acc))))  VFwd"
        by (rule ae_chain_from_SS1_short_not_VFwd
                   [OF idx_snd4 m_short less.prems(2)])
      from c_acc_VFwd not_VFwd have False by simp
      thus ?thesis by simp
    next
      case m_long
      define m_rem where "m_rem  m - 8"
      have m_split: "m = 8 + m_rem"
        using m_long m_rem_def by simp
      have rem_lt: "m_rem < m"
        using m_long m_rem_def by simp
      from less.prems(2) m_split have trace_compose:
          "(c', c_acc)
               (mttm_step (alphabet_enlarge_delta M) ^^ 8)
                  O (mttm_step (alphabet_enlarge_delta M) ^^ m_rem)"
        by (simp add: relpow_add)
      obtain c_8 where
          run_8:    "(c', c_8)
                         mttm_step (alphabet_enlarge_delta M) ^^ 8"
        and rest_8: "(c_8, c_acc)
                         mttm_step (alphabet_enlarge_delta M) ^^ m_rem"
        using trace_compose by auto
      have val_cM: "valid_config_mttm M cM"
        by (rule valid_reach_mttm[OF vM w_sub less.prems(1)])
      have no_le_per_tape:
          "k. (mt_pos c' k  2
                   (i. i < 3 * card (UNIV :: 'c set)
                             mt_tape cM k
                                  ((mt_pos c' k - 2)
                                      * card (UNIV :: 'c set)
                                     + 1 + i)
                                 le_tm M))
                (mt_pos c' k = 1
                     (i. i < 2 * card (UNIV :: 'c set)
                               mt_tape cM k (Suc i)  le_tm M))
                (mt_pos c' k = 0
                     (i. i < card (UNIV :: 'c set)
                               mt_tape cM k (Suc i)  le_tm M))"
        by (rule ae_no_le_per_tape_from_reach
                   [OF vM lu w_sub le_neq_bl less.prems(1)])
      obtain cM_new n_M where
          cM_run:    "(cM, cM_new)  mttm_step (delta_tm M) ^^ n_M"
        and n_M_le:   "n_M  card (UNIV :: 'c set)"
        and end_disj: "n_M = card (UNIV :: 'c set)
                           mt_state cM_new  {t_tm M, r_tm M}"
        and sim_new:  "ae_simulates M cM_new c_8"
        and buf_new:  "ae_buffer_in_gamma_block M c_8"
        and le_new:   "kk<k_tm M. mt_tape c_8 kk 0 = LE_block (le_tm M)"
        by (rule ae_backward_stage[OF vM lu less.prems(3) val_cM
                                       qM_neq_t qM_neq_r
                                       less.prems(4) less.prems(5)
                                       le_neq_bl no_le_per_tape run_8])
      have cM_to_new_star: "(cM, cM_new)  (mttm_step (delta_tm M))*"
        using cM_run by (rule relpow_imp_rtrancl)
      have reach_cM_new: "(init_config_mttm M w, cM_new)
                             (mttm_step (delta_tm M))*"
        using less.prems(1) cM_to_new_star by (rule rtrancl_trans)
      obtain cM_final where
          rest_run:  "(cM_new, cM_final)
                          (mttm_step (delta_tm M))*"
        and acc_final: "mt_state cM_final = t_tm M"
        using less.IH[OF rem_lt reach_cM_new rest_8 sim_new
                          buf_new le_new]
        by blast
      have cM_to_final:
          "(cM, cM_final)  (mttm_step (delta_tm M))*"
        using cM_to_new_star rest_run by (rule rtrancl_trans)
      show ?thesis using cM_to_final acc_final by blast
    qed
  qed
qed



text ‹Language-equivalence statement (biconditional) for every
  well-formed M› --- ‹with no determinism hypothesis›.
  Pairs with the forward inclusion
  alphabet_enlarge_language_forward› in
  AlphabetEnlargement.thy›: this theorem combines that
  forward leg with a determinism-free reverse leg.

  Both legs assume only well_formed_mttm M›.  The forward leg
  is unconditional in M›'s determinism by construction.  The
  reverse leg originally required det_mttm M›: the natural
  route identifies the post-validation point by chain uniqueness
  of alphabet_enlarge_delta›
  (mttm_step_alphabet_enlarge_relpow_functional›), which a
  nondeterministic M› does not supply --- its compute substep
  is multi-valued, so that full chain is not unique.  The
  refactoring removed the dependency.  The validation prefix is
  pinned instead by the ‹validation-phase› uniqueness
  mttm_step_alphabet_enlarge_val_relpow_functional› (the AE
  bookkeeping is deterministic whatever M› does), and the
  single determinism-supplied step in ae_backward_stage› ---
  the SS4→›SS5 identification --- is replaced by the
  unconditional window-inversion kernel (bp_linear›
  injectivity plus buffer-window inversion; the det›-free
  SS5→›SS8 kernel above), with the remainder discharged by
  ae_simulation_phase_chunked_reverse›.  The biconditional
  therefore holds for nondeterministic M› as well, which is
  what the nondeterministic corollary alphabet_enlarge_nae›
  packages with the time bound.  The Hopcroft--Ullman
  linear-speedup corollaries
  cite‹Theorems 12.3, 12.4› in "Hopcroft1979:introduction"
  reinstate det_mttm M› only for the same-alphabet wrap, not for this
  biconditional.›

theorem alphabet_enlarge_language:
  fixes M :: "('q, 'a) mttm"
  assumes wf:        "well_formed_mttm M"
  shows "w. set w  Sigma_tm M
               (encode_input (bl_tm M) w  Lang_mttm
                      (alphabet_enlarge M
                         :: ('q × ('a, ('c :: enum)) ae_stage,
                             'c  'a) mttm))
                  = (w  Lang_mttm M)"
proof -
  from wf have vM:        "valid_mttm M"
           and lu:        "le_unique M"
           and s_neq_t:   "s_tm M  t_tm M"
           and s_neq_r:   "s_tm M  r_tm M"
           and le_neq_bl: "le_tm M  bl_tm M"
    by auto

  let ?M' = "alphabet_enlarge M
               :: ('q × ('a, 'c) ae_stage, 'c  'a) mttm"

  have fwd: "w. set w  Sigma_tm M
                   w  Lang_mttm M
                   encode_input (bl_tm M) w  Lang_mttm ?M'"
    by (rule alphabet_enlarge_language_forward[OF wf])

  show ?thesis
  proof (intro allI impI)
    fix w :: "'a list"
    assume w_sub: "set w  Sigma_tm M"
    show "(encode_input (bl_tm M) w  Lang_mttm ?M')
            = (w  Lang_mttm M)"
    proof
      assume w_in_M: "w  Lang_mttm M"
      from fwd w_sub w_in_M
      show "encode_input (bl_tm M) w  Lang_mttm ?M'"
        by blast
    next
      ― ‹Reverse direction: encode_input w ∈ Lang_mttm M'›
          ⟹› w ∈ Lang_mttm M›.

          Strategy: unpack the M'›-accepting trace; peel
          validation via the strengthened
          ae_init_config_simulates_post_validation›; identify
          the post-validation point on the trace via
          validation-phase chain uniqueness
          (mttm_step_alphabet_enlarge_val_relpow_functional›,
          det›-free); invoke
          ae_simulation_phase_chunked_reverse› on the
          remainder; repack the resulting M-trace as
          Lang_mttm M›.›
      assume enc_in_M':
          "encode_input (bl_tm M) w  Lang_mttm ?M'"
      ― ‹Step 1: Unpack the M'-acceptance.›
      from enc_in_M' obtain wM' nM' where
          acc_path_M':
            "(init_config_mttm ?M' (encode_input (bl_tm M) w),
              ConfigM (t_tm ?M') wM' nM')
                 (mttm_step (delta_tm ?M'))*"
        unfolding Lang_mttm_def by blast
      define c_acc :: "('c  'a, 'q × ('a, 'c) ae_stage)
                          mt_config"
        where "c_acc  ConfigM (t_tm ?M') wM' nM'"
      ― ‹Step 2: Bridge ?M'› components to AE-side and
          convert rtrancl to relpow.›
      have c_acc_state:
          "mt_state c_acc = (t_tm M, init_stage (le_tm M))"
        unfolding c_acc_def by (simp add: t_tm_alphabet_enlarge)
      have acc_path_AE:
          "(ae_init_config M (encode_input (bl_tm M) w), c_acc)
               (mttm_step (alphabet_enlarge_delta M))*"
        using acc_path_M'
        by (simp add: init_config_alphabet_enlarge
                      delta_tm_alphabet_enlarge c_acc_def)
      obtain N where acc_pow:
          "(ae_init_config M (encode_input (bl_tm M) w), c_acc)
               mttm_step (alphabet_enlarge_delta M) ^^ N"
        using acc_path_AE rtrancl_imp_relpow by metis
      ― ‹Step 3: Peel validation.  Explicit type annotation
          on c'_post› to share 'c› with c_acc› (the
          validation-peel lemma is polymorphic over 'c›;
          without the annotation Isabelle freshens).›
      obtain n_val and c'_post :: "('c  'a,
                                     'q × ('a, 'c) ae_stage) mt_config" where
          val_run:    "(ae_init_config M (encode_input (bl_tm M) w),
                        c'_post)
                           mttm_step (alphabet_enlarge_delta M)
                                  ^^ n_val"
        and val_sim:  "ae_simulates M (init_config_mttm M w) c'_post"
        and val_buf:  "ae_buffer_in_gamma_block M c'_post"
        and val_le:   "kk<k_tm M. mt_tape c'_post kk 0 = LE_block (le_tm M)"
        and val_reach:
              "i<n_val. d :: ('c  'a,
                                  'q × ('a, 'c) ae_stage) mt_config.
                  (ae_init_config M (encode_input (bl_tm M) w), d)
                       mttm_step (alphabet_enlarge_delta M) ^^ i
                     snd (snd (snd (snd (mt_state d))))
                           {VFwd, VFwdPad, VRet}"
        by (rule ae_init_config_simulates_post_validation
                   [OF vM w_sub le_neq_bl])
      ― ‹Step 4: Identify chain remainder.  By
          mttm_step_alphabet_enlarge_val_relpow_functional› the
          validation endpoint sits on the unique chain from
          ae_init_config› to c_acc›.  Two cases on
          n_val› vs N›:
           ∙› n_val ≤ N›: extract remainder
              (c'_post, c_acc) ∈ step ^^ (N - n_val)›.
           ∙› n_val > N›: contradiction — a step from
              c_acc› is impossible since
              mt_state c_acc = t_tm M'›.›
      have n_val_le_N: "n_val  N"
      proof (rule ccontr)
        assume "¬ n_val  N"
        hence N_lt: "N < n_val" by simp
        have sum_eq: "N + (n_val - N) = n_val"
          using N_lt by simp
        have val_run_combined:
            "(ae_init_config M (encode_input (bl_tm M) w), c'_post)
                 mttm_step (alphabet_enlarge_delta M)
                      ^^ (N + (n_val - N))"
          using val_run sum_eq by simp
        hence val_compose:
            "(ae_init_config M (encode_input (bl_tm M) w), c'_post)
                 (mttm_step (alphabet_enlarge_delta M) ^^ N)
                    O (mttm_step (alphabet_enlarge_delta M)
                          ^^ (n_val - N))"
          by (simp add: relpow_add)
        obtain c_mid where
            step_to_mid:
              "(ae_init_config M (encode_input (bl_tm M) w), c_mid)
                   mttm_step (alphabet_enlarge_delta M) ^^ N"
          and step_from_mid:
              "(c_mid, c'_post)
                   mttm_step (alphabet_enlarge_delta M)
                        ^^ (n_val - N)"
          using val_compose by auto
        have inv_N: "i<N. d :: ('c  'a,
                                    'q × ('a, 'c) ae_stage) mt_config.
                        (ae_init_config M (encode_input (bl_tm M) w), d)
                             mttm_step (alphabet_enlarge_delta M) ^^ i
                           snd (snd (snd (snd (mt_state d))))
                                 {VFwd, VFwdPad, VRet}"
          using val_reach N_lt by (meson less_trans)
        have c_mid_eq: "c_mid = c_acc"
          by (rule mttm_step_alphabet_enlarge_val_relpow_functional
                     [OF le_neq_bl step_to_mid acc_pow inv_N])
        have step_from_acc:
            "(c_acc, c'_post)
                 mttm_step (alphabet_enlarge_delta M)
                      ^^ (n_val - N)"
          using step_from_mid c_mid_eq by simp
        have extra_pos: "0 < n_val - N" using N_lt by simp
        obtain m_extra_pred where m_extra_Suc:
            "n_val - N = Suc m_extra_pred"
          using extra_pos by (cases "n_val - N") auto
        have step_from_acc_Suc:
            "(c_acc, c'_post)
                 mttm_step (alphabet_enlarge_delta M)
                      ^^ Suc m_extra_pred"
          using step_from_acc m_extra_Suc by simp
        obtain c_acc_1 where
            first_step:
              "(c_acc, c_acc_1)
                   mttm_step (alphabet_enlarge_delta M)"
          and rest_step:
              "(c_acc_1, c'_post)
                   mttm_step (alphabet_enlarge_delta M)
                        ^^ m_extra_pred"
          using relpow_Suc_D2[OF step_from_acc_Suc] by blast
        have valM': "valid_mttm ?M'"
          by (rule alphabet_enlarge_wf[OF vM])
        have first_step_M':
            "(c_acc, c_acc_1)  mttm_step (delta_tm ?M')"
          using first_step by (simp add: delta_tm_alphabet_enlarge)
        have c_acc_state_M': "mt_state c_acc = t_tm ?M'"
          using c_acc_state by (simp add: t_tm_alphabet_enlarge)
        from mttm_step_src_neq_t[OF valM' first_step_M']
             c_acc_state_M'
          show False by simp
      qed
      have remainder:
          "(c'_post, c_acc)  mttm_step (alphabet_enlarge_delta M)
                                    ^^ (N - n_val)"
      proof -
        have sum_eq: "n_val + (N - n_val) = N"
          using n_val_le_N by simp
        have "(ae_init_config M (encode_input (bl_tm M) w), c_acc)
                 mttm_step (alphabet_enlarge_delta M)
                      ^^ (n_val + (N - n_val))"
          using acc_pow sum_eq by simp
        hence acc_compose:
            "(ae_init_config M (encode_input (bl_tm M) w), c_acc)
                 (mttm_step (alphabet_enlarge_delta M) ^^ n_val)
                    O (mttm_step (alphabet_enlarge_delta M)
                          ^^ (N - n_val))"
          by (simp add: relpow_add)
        obtain c_mid where
            run_to_mid:
              "(ae_init_config M (encode_input (bl_tm M) w), c_mid)
                   mttm_step (alphabet_enlarge_delta M) ^^ n_val"
          and run_from_mid:
              "(c_mid, c_acc)
                   mttm_step (alphabet_enlarge_delta M)
                        ^^ (N - n_val)"
          using acc_compose by auto
        have c_mid_eq: "c_mid = c'_post"
          by (rule mttm_step_alphabet_enlarge_val_relpow_functional
                     [OF le_neq_bl run_to_mid val_run val_reach])
        show ?thesis using run_from_mid c_mid_eq by simp
      qed
      ― ‹Step 5: Invoke chunked-reverse to extract an M-side
          accepting path.›
      have reach_refl:
          "(init_config_mttm M w, init_config_mttm M w)
               (mttm_step (delta_tm M))*"
        by simp
      obtain cM_final where
          M_path:    "(init_config_mttm M w, cM_final)
                           (mttm_step (delta_tm M))*"
        and M_acc:    "mt_state cM_final = t_tm M"
        using ae_simulation_phase_chunked_reverse
                [OF vM lu w_sub le_neq_bl reach_refl remainder
                    c_acc_state val_sim val_buf val_le]
        by blast
      ― ‹Step 6: Repack as w ∈ Lang_mttm M›.›
      obtain wM_acc nM_acc where
          cM_final_eq:
            "cM_final = ConfigM (t_tm M) wM_acc nM_acc"
        using M_acc by (cases cM_final) simp
      show "w  Lang_mttm M"
        unfolding Lang_mttm_def
        using w_sub M_path cM_final_eq by blast
    qed
  qed
qed


subsection ‹Nondeterministic alphabet enlargement›

text ‹The determinism-free building block for the nondeterministic
  linear speedup --- the ‹Form-2› statement (raw, no
  encoding_wrap›, tape count unchanged, over the enlarged
  alphabet).  For an arbitrary, ‹possibly nondeterministic›,
  well-formed M›, the enlargement alphabet_enlarge M›
  preserves the language (under the encode_input› block
  map) and the running time, with ‹no› det_mttm M›
  hypothesis and ‹no› det_mttm›-output conclusion; the
  witness alphabet_enlarge M› is nondeterministic exactly when
  M› is.

  Wrapping this in the inline plant-le› encoder yields the
  same-alphabet nondeterministic speedup corollaries
  linear_speedup_HU_12_3_nae› / 12_4_nae_B› --- the
  Hopcroft--Ullman page-291 corollary
  cite‹p.~291› in "Hopcroft1979:introduction" --- proved in
  Wrap_Speedup› alongside their deterministic
  counterparts linear_speedup_HU_12_3_dae› / 12_4_dae_B›,
  which assume det_mttm M› and additionally conclude output
  determinism via wrap_det›.›

theorem alphabet_enlarge_nae:
  fixes M :: "('q, 'a) mttm"
    and T :: "nat  nat"
  assumes wf: "well_formed_mttm M"
  obtains α f :: nat
  where "w. set w  Sigma_tm M
               (encode_input (bl_tm M) w  Lang_mttm
                      (alphabet_enlarge M
                         :: ('q × ('a, ('c :: enum)) ae_stage,
                             'c  'a) mttm))
                  = (w  Lang_mttm M)"
    and "w. set w  Sigma_tm M
               accepts_in_time_mttm M w (T (length w))
               accepts_in_time_mttm
                    (alphabet_enlarge M
                       :: ('q × ('a, 'c) ae_stage, 'c  'a) mttm)
                    (encode_input (bl_tm M) w)
                    (α * ((length w + card (UNIV :: 'c set) - 1)
                            div card (UNIV :: 'c set))
                     + 8 * ((T (length w) + card (UNIV :: 'c set) - 1)
                             div card (UNIV :: 'c set))
                     + f)"
proof -
  have lang:
    "w. set w  Sigma_tm M
             (encode_input (bl_tm M) w  Lang_mttm
                    (alphabet_enlarge M
                       :: ('q × ('a, ('c :: enum)) ae_stage,
                           'c  'a) mttm))
                = (w  Lang_mttm M)"
    by (rule alphabet_enlarge_language[OF wf])
  obtain α f :: nat where time:
    "w. set w  Sigma_tm M
             accepts_in_time_mttm M w (T (length w))
             accepts_in_time_mttm
                  (alphabet_enlarge M
                     :: ('q × ('a, 'c) ae_stage, 'c  'a) mttm)
                  (encode_input (bl_tm M) w)
                  (α * ((length w + card (UNIV :: 'c set) - 1)
                          div card (UNIV :: 'c set))
                   + 8 * ((T (length w) + card (UNIV :: 'c set) - 1)
                           div card (UNIV :: 'c set))
                   + f)"
    by (rule alphabet_enlarge_time[OF wf])
  show ?thesis by (rule that[OF lang time])
qed


end