Read this chapter directly, or use the reading guide and dependency map to choose another route.

Reading guide · Dependency map

Internal reasoning about syntax begins with a set of formula keys inside L. This chapter compares such a candidate domain with the external formula grammar in two directions: every member merely decodes to a formula key, and every genuine formula key belongs to the domain. These claims concern code membership, not the truth or satisfaction of the encoded formulas.

{-# OPTIONS --cubical --safe --guardedness #-}

The argument uses excluded middle together with propositional truncation. Truncation records that a decoding witness exists without choosing one, and it may be eliminated only when the target is again a proposition.

open import Base.Prelude
open import Base.Classical using ( LEM )

Assume lem : LEM (ℓ-suc ℓ). Every construction in the chapter is relative to this hypothesis, but the hypothesis does not strengthen the decoding conclusion: witnesses to decoded formulas remain propositionally truncated.

module L.Coding.CodeDomainAdequacy { : Level} (lem : LEM (ℓ-suc )) where

The chapter speaks about the full first-order language of set theory: formulas with the two bounded quantifiers as well as the unbounded ones, and terms built from variables and constants. These are the objects whose codes the domain must gather and describe.

open import FOL.ZFStructure using ( module hPropStructure )
open import FOL.Syntax using
  ( Formula; Term; var; con; _∈̇_; _≐_; _∧̇_; _∨̇_; _⇒̇_; ⊥̇; ∃̇_; ∀̇_; ∃̇∈; ∀̇∈ )
import FOL.Absoluteness
open import V.Hierarchy {} using ( 𝒮ᵥ )

Formula keys are nested ordered pairs, so injectivity of pairing recovers their arity, tag, and payload from an equality of keys. Natural-number arities are represented by von Neumann numerals, and constructible environment sets provide internal representatives for finite parameter vectors.

open import V.Coding {} using ( pr; pr-inj; #-inj′; #mono )
open import L.Constructible {} using ( 𝒮ʟ; isL; isL-trans )
open import L.Coding.Environment {} using ( env )
open import L.Coding.EnvironmentSet {} lem using ( envSet )
open import L.Axioms.Numerals {} using ( numeralL-fst; sucʟ; sucʟ-fst )

The object language can express that a structurally assembled key belongs to a candidate domain. Ordered-pair expressions build the nested key, and their adequacy theorem identifies satisfaction of the resulting formula with membership of the corresponding host-level pair code.

open import L.Coding.Model {} using ( appAt; appAt-adequate )
open import L.Coding.Expressions {} using ( sucAtL )
open import L.Coding.Model {} using ( container )
import L.Coding.Expressions {} as CodingExpressions
module E = CodingExpressions.PairExpression

Quantifier codes change arity. The body of either kind of quantifier is a key at the successor arity, while a bounded quantifier also carries a term legal at the current arity. The semantic lemmas for pairs, successors, and extended environments express precisely these changes under binders.

open import L.Coding.Quantification {} using
  ( i0; i1; i2; i3; i4; i5; i6; i7; i8; sh
  ; pr-out; pr-in; down; fstS; sndS; suc-out; suc-in
  ; sndEx; sndAll; bothEx
  ; sndEx-out; sndAll-in; bothEx-out; bothAll-in

Existential payload descriptions are propositionally truncated, sometimes through two nested witnesses. Their inward and outward readings preserve that truncation. The ten constructor tags are represented by the numerals zero through nine, and a separate environment tower records the arity at which each code is read.

  ; fillSnd; fillBoth; useSnd; useBoth
  ; f0; f1; f2; f3; f4; f5; f6; f7; f8; f9
  ; bigOr-in; bigOr-out )
open import L.Coding.EnvironmentTower {} lem using ( module Tower; nn )
open import L.Coding.CodeDomain {} using

The description codesAt has two complementary halves. shapeAt reads an existing domain member as one of the ten constructor shapes and, for composite codes, requires its immediate subkeys to remain in the domain. closeAt goes in the generating direction: legal terms and existing subkeys produce the corresponding new key.

  ( isTm; keyUp; keyExpr; atomKeyExpr; bndKeyExpr
  ; unKey; binKey; atomKey; bndKey
  ; Tags; shN; module Shape; shapeAt; module Close; closeAt; codesAt )
open import L.Coding.CodeAlphabet {} using ( module Alphabet )

A constructor tag is an element of Fin 10; its natural-number value selects one of the ten payload predicates and is automatically less than ten. Environments are finite vectors, while the codes stored in the hierarchy are nested set-theoretic pairs.

open import Cubical.Data.Nat using ( _+_ )
open import Cubical.Data.FinData using ( toℕ )
open import Cubical.Data.FinData.Properties using ( toℕ<n )
open import Cubical.Data.Vec using ( _∷_; lookup )
open import Cubical.Data.Sigma using ( _×_ )

Decoding branches over disjoint constructor cases and often returns only a propositionally truncated witness. Pair equalities are transported componentwise, and impossible tags lead to the empty type. None of these operations turns a merely existing formula into a globally chosen decoder.

open import Cubical.Data.Sum using ( _⊎_; inl; inr )
open import Cubical.Foundations.Prelude using ( subst2 )
import Cubical.Data.Empty as Empty
import Cubical.HITs.PropositionalTruncation as PT
open PT using ( ∥_∥₁; ∣_∣₁; squash₁ )

The cumulative hierarchy supplies set-valued ordered-pair codes, von Neumann numerals, and the successor operation on arities. Membership has a small fibre presentation, and equality of hierarchy sets is a proposition; these facts justify the truncated decompositions and their elimination into membership or equality claims.

open import Cubical.HITs.CumulativeHierarchy.Base using ( V; _∈_; setIsSet )
open import Cubical.HITs.CumulativeHierarchy.Properties using ( ⟪_⟫; ∈-asFiber )
open import Cubical.HITs.CumulativeHierarchy.Constructions
  using ( module InfinitySet )
open InfinitySet {} using ( #_; sucV )

The carrier of the constructible structure is fixed as S, so every environment and every formula reading below lives over it.

open hPropStructure 𝒮ʟ using ( S )

All code descriptions are interpreted in the first-order structure carried by L. Thus“this assembled key belongs to C”has both an object-language formulation and a host-level membership reading; the adequacy lemmas identify these two forms of the same assertion.

module AbsL = FOL.Absoluteness.Single 𝒮ᵥ isL isL-trans using ( _^_; _⊨ᵐ_ )
open AbsL using ( _^_ ) renaming ( _⊨ᵐ_ to _⊨_ )

Reading the description

Term codes are described first. A set t is a term code at arity ar when, merely, it is the pair of the tag zero with an element of the working set Wv, or the pair of the tag one with an element of the set ar. Note that ar is still an arbitrary set here; only when it is known to be a numeral does the second branch recover a bounded variable index.

IsTmV : V   V   V   Type (ℓ-suc )
IsTmV Wv t ar =  (Σ[ x  V  ] ((t  pr (# 0) x) ×  x  Wv ))
                 (Σ[ i  V  ] ((t  pr (# 1) i) ×  i  ar )) ∥₁

The first three payload predicates cover atomic formulas, binary connectives, and falsity. An atomic payload merely decomposes into two legal term codes; a binary payload merely decomposes into two same-arity subkeys already in the candidate domain; the falsity payload is directly the equality r = # 0 and carries no existential witness.

module CodesSem (Wv Cv : V ) where
  AtomP BinP ConP QuP BqP : V   V   Type (ℓ-suc )
  AtomP ar r =  Σ[ t  V  ] Σ[ u  V  ] ((r  pr t u) × (IsTmV Wv t ar × IsTmV Wv u ar)) ∥₁
  BinP ar r =  Σ[ a  V  ] Σ[ b  V  ] ((r  pr a b) × ( pr ar a  Cv  ×  pr ar b  Cv )) ∥₁
  ConP ar r = r  # 0

The quantifier payloads complete the list. An unbounded-quantifier payload is a subkey at the successor arity. A bounded-quantifier payload pairs a term code legal at the current arity with such a subkey. This asymmetry comes from the grammar itself: the body has successor arity, whereas the bounding term has the arity of the quantified formula.

  QuP ar r =  pr (sucV ar) r  Cv 
  BqP ar r =  Σ[ t  V  ] Σ[ a  V  ] ((r  pr t a) × (IsTmV Wv t ar ×  pr (sucV ar) a  Cv )) ∥₁

The payload table begins: tags zero and one carry the two atom shapes, and tags two and three carry the binary shapes of conjunction and disjunction.

  PayN :   V   V   Type (ℓ-suc )
  PayN 0 = AtomP
  PayN 1 = AtomP
  PayN 2 = BinP
  PayN 3 = BinP

The table continues: tag four carries implication, tag five the constant falsity, tags six and seven the two unbounded quantifiers, and tag eight the bounded universal.

  PayN 4 = BinP
  PayN 5 = ConP
  PayN 6 = QuP
  PayN 7 = QuP
  PayN 8 = BqP

Tag nine carries the bounded existential payload. The auxiliary family PayN is empty at every natural number at least ten, but a legal Key chooses its tag from Fin 10; hence only the ten cases zero through nine can occur in a key.

  PayN 9 = BqP
  PayN (suc (suc (suc (suc (suc (suc (suc (suc (suc (suc _)))))))))) _ _ = Empty.⊥*

A key at arity ar is, merely, a tag from the ten together with a payload of the matching shape. Note what a key is not: it is not an inductive syntax tree, and the decomposition is not claimed to be unique data. A key is the truncated evidence that a set-coded pair splits into one of ten known shapes.

  Key : V   V   Type (ℓ-suc )
  Key ar p =  Σ[ k  Fin 10 ] Σ[ r  V  ] ((p  pr (# (toℕ k)) r) × PayN (toℕ k) ar r) ∥₁

Fix an environment containing a proposed term code t, an arity set ar, a working set Wv, and two entries known to be the numerals zero and one. Under these tag equations, the object-language predicate isTm can be compared exactly with the ambient predicate IsTmV Wv t ar.

module _ {k : } (t ar w N0 N1 : Fin k) (δ : S ^ k)
  (q0 : fst (lookup N0 δ)  # 0) (q1 : fst (lookup N1 δ)  # 1) where
  private
    Wv = fst (lookup w δ)

The outward reading eliminates the truncated disjunction of the object-language formula. In the constant branch, the existential recovers the second component of the pair, the numeral equation aligns the tag, and the membership travels into IsTmV; the result is the left branch of the truncated definition.

  isTm-out :  δ  isTm t ar w N0 N1   IsTmV Wv (fst (lookup t δ)) (fst (lookup ar δ))
  isTm-out = PT.rec squash₁
     { (inl h)  PT.map
            { (v , s , (e , v∈))  inl (fst v , (e  cong  a  pr a (fst v)) q0 , v∈)) })
           (sndEx-out t N0 (var i0 ∈̇ var (sh 2 w)) δ h)

The variable branch repeats the same three moves with the numeral one and the arity set, producing the right branch. Together the two branches say the object-language recognition and the set-level IsTmV are exactly equivalent.

       ; (inr h)  PT.map
            { (v , s , (e , v∈))  inr (fst v , (e  cong  a  pr a (fst v)) q1 , v∈)) })
           (sndEx-out t N1 (var i0 ∈̇ var (sh 2 ar)) δ h) })

The inward reading runs the conversion the other way. In the constant branch, the filling lemma places the witness x under the existential at slot zero, and the pair equation is transported along the reversed numeral equation so that the satisfaction matches the shape of the object-language formula.

  isTm-in : IsTmV Wv (fst (lookup t δ)) (fst (lookup ar δ))   δ  isTm t ar w N0 N1 
  isTm-in = PT.rec (snd (δ  isTm t ar w N0 N1))
     { (inl (x , (e , x∈))) 
            inl (fillSnd t δ (lookup N0 δ) (down (lookup w δ) x x∈)
                    (e  cong  a  pr a x) (sym q0)) (var i0 ∈̇ var (sh 2 w)) x∈ N0 refl) ∣₁

The variable branch fills the witness i under the existential at the numeral-one slot, transported by the corresponding reversed equation. The two branches close the equivalence in both directions.

       ; (inr (i , (e , i∈))) 
            inr (fillSnd t δ (lookup N1 δ) (down (lookup ar δ) i i∈)
                    (e  cong  a  pr a i) (sym q1)) (var i0 ∈̇ var (sh 2 ar)) i∈ N1 refl) ∣₁ })

The predicate keyUp C ar r expresses one precise membership statement: the pair (suc ar,r) belongs to C. Its bounded existential presentation chooses an actual member of C and then exposes enough of that member to verify both its pair shape and the successor equation.

module _ {k : } (C ar r : Fin k) (δ : S ^ k) where
  keyUp-out :  δ  keyUp C ar r    pr (sucV (fst (lookup ar δ))) (fst (lookup r δ))  fst (lookup C δ) 
  keyUp-out = PT.rec (snd (pr (sucV (fst (lookup ar δ))) (fst (lookup r δ))  fst (lookup C δ)))
     { (c' , (c'∈ , h))  PT.rec (snd (pr (sucV (fst (lookup ar δ))) (fst (lookup r δ))  fst (lookup C δ)))
       { (s , (s∈ , h'))  PT.rec (snd (pr (sucV (fst (lookup ar δ))) (fst (lookup r δ))  fst (lookup C δ)))

In the outward direction, the pair formula identifies the chosen member of C with (ar',r), while the successor formula identifies ar' with suc ar. Transporting membership along these two equalities yields (suc ar,r) ∈ C. All truncated witnesses are eliminated only into this membership proposition.

         { (ar' , (ar'∈ , (e , hs))) 
          subst  u   u  fst (lookup C δ) )
            (pr-out i2 i0 (sh 3 r) (ar'  s  c'  δ) e
              cong  a  pr a (fst (lookup r δ))) (suc-out (sh 3 ar) i0 (ar'  s  c'  δ) hs))
            c'∈ })

The three bounded witnesses therefore serve only to certify the displayed member of C; after their truncations are eliminated, keyUp-out has exactly the ambient membership statement (suc ar,r) ∈ C.

        h' })
      h })

For the inward direction, start with (suc ar,r) ∈ C. Present the successor arity as a constructible set, package the ordered pair with r, and use these objects as the three bounded witnesses. The pair and successor formulas then reconstruct satisfaction of keyUp C ar r.

  keyUp-in :  pr (sucV (fst (lookup ar δ))) (fst (lookup r δ))  fst (lookup C δ)    δ  keyUp C ar r 
  keyUp-in h =  c' , (h ,  c .fst , (c .snd .fst ,  ar' , (c .snd .snd .fst
    , ( pr-in i2 i0 (sh 3 r) (ar'  c .fst  c'  δ) (sym (cong  a  pr a (fst (lookup r δ))) (sucʟ-fst (lookup ar δ))))
      , suc-in (sh 3 ar) i0 (ar'  c .fst  c'  δ) (sucʟ-fst (lookup ar δ)) )) ∣₁) ∣₁) ∣₁
    where

Concretely, ar' represents suc ar, c' represents the member (suc ar,r) of C, and the containing set supplied with c' witnesses the bounded-membership chain used by the formula. Their underlying-set equations ensure that the internal witnesses denote the intended ambient pair.

    ar' : S
    ar' = sucʟ (lookup ar δ)
    c' : S
    c' = down (lookup C δ) (pr (sucV (fst (lookup ar δ))) (fst (lookup r δ))) h
    c = container c' ar' (lookup r δ) (cong  a  pr a (fst (lookup r δ))) (sym (sucʟ-fst (lookup ar δ))))

Fix a candidate domain C, an arity value A, a tag value N, and a payload a. The unary key assembled from these data is the nested pair (A,(N,a)).

module _ {k : } (C ar N a : Fin k) (δ : S ^ k) where
  private
    Cv = fst (lookup C δ)
    A = fst (lookup ar δ)
    Nv = fst (lookup N δ)

The outward reading of unKey states precisely that the nested key (A,(N,a)) belongs to C. Adequacy of the ordered-pair expression turns object-language membership into this host-level set-membership statement.

  unKey-out :  δ  unKey C ar N a    pr A (pr Nv (fst (lookup a δ)))  Cv 
  unKey-out = E.member-out (keyExpr ar N (E.slot a)) (var C) δ

Adequacy works in the reverse direction as well: membership (A,(N,a)) ∈ C yields satisfaction of the object-language predicate unKey. The key clause and its host-level reading therefore agree in both directions.

  unKey-in :  pr A (pr Nv (fst (lookup a δ)))  Cv    δ  unKey C ar N a 
  unKey-in = E.member-in (keyExpr ar N (E.slot a)) (var C) δ

For a binary constructor, fix two payload components a and b. Their ordered pair P=(a,b) becomes the payload of the key (A,(N,P)); the arity and tag occupy the same outer positions as in the unary case.

module _ {k : } (C ar N a b : Fin k) (δ : S ^ k) where
  private
    Cv = fst (lookup C δ)
    A = fst (lookup ar δ)
    Nv = fst (lookup N δ)

The two argument values form the ordered pair P = (a,b). This pair is the payload in the nested binary key (A,(N,P)).

    P = pr (fst (lookup a δ)) (fst (lookup b δ))

The outward reading of binKey is precisely the membership (A,(N,(a,b))) ∈ C. It preserves the three logical levels of the encoding: arity, constructor tag, and the paired arguments.

  binKey-out :  δ  binKey C ar N a b    pr A (pr Nv P)  Cv 
  binKey-out = E.member-out (keyExpr ar N (E.pair (E.slot a) (E.slot b))) (var C) δ

The inward reading is its reverse, and the two together identify the formula statement with the set membership, as with every key clause.

  binKey-in :  pr A (pr Nv P)  Cv    δ  binKey C ar N a b 
  binKey-in = E.member-in (keyExpr ar N (E.pair (E.slot a) (E.slot b))) (var C) δ

An atomic key has two term codes as its payload. Each term code carries its own term tag and argument, and the pair of these two term codes is placed beneath the atomic constructor tag and the common arity.

module _ {k : } (C ar N Nx x Ny y : Fin k) (δ : S ^ k) where
  private
    Cv = fst (lookup C δ)
    A = fst (lookup ar δ)
    Nv = fst (lookup N δ)

Write the two term codes as T=(Nx,x) and U=(Ny,y). At this stage Nx and Ny are arbitrary tag values from the environment; their being zero or one is imposed when the atomic closure cases are instantiated.

    T = pr (fst (lookup Nx δ)) (fst (lookup x δ))
    U = pr (fst (lookup Ny δ)) (fst (lookup y δ))

The atomic clause reads outward as (A,(N,(T,U))) ∈ C, where T and U are the two term codes. Thus the outer pair records the arity, the next records the atomic tag, and the innermost pair records the two terms.

  atomKey-out :  δ  atomKey C ar N Nx x Ny y    pr A (pr Nv (pr T U))  Cv 
  atomKey-out = E.member-out (atomKeyExpr ar N Nx x Ny y) (var C) δ

The inward reading is its reverse, closing the atomic case in both directions like every key clause before it.

  atomKey-in :  pr A (pr Nv (pr T U))  Cv    δ  atomKey C ar N Nx x Ny y 
  atomKey-in = E.member-in (atomKeyExpr ar N Nx x Ny y) (var C) δ

A bounded-quantifier key carries two different components in its payload: a term code for the bound and a subformula code for the body. The common outer data are again the current arity A and the bounded-quantifier tag N.

module _ {k : } (C ar N Nx x a : Fin k) (δ : S ^ k) where
  private
    Cv = fst (lookup C δ)
    A = fst (lookup ar δ)
    Nv = fst (lookup N δ)

Write the bound-term code as T=(Nx,x) and the body code as Av. The term is checked at the current arity, whereas the body key is checked at the successor arity; keeping them as separate payload components records this grammatical asymmetry.

    T = pr (fst (lookup Nx δ)) (fst (lookup x δ))
    Av = fst (lookup a δ)

The bounded-key clause reads outward as (A,(N,(T,Av))) ∈ C. The innermost pair contains the bound-term code and the body code in that order; it is not itself a claim that either component is already legal.

  bndKey-out :  δ  bndKey C ar N Nx x a    pr A (pr Nv (pr T Av))  Cv 
  bndKey-out = E.member-out (bndKeyExpr ar N Nx x a) (var C) δ

Conversely, membership of (A,(N,(T,Av))) in C yields satisfaction of bndKey. Together the two readings establish only the structural membership equivalence; legality of T and successor-arity membership of Av are supplied by the surrounding payload predicate.

  bndKey-in :  pr A (pr Nv (pr T Av))  Cv    δ  bndKey C ar N Nx x a 
  bndKey-in = E.member-in (bndKeyExpr ar N Nx x a) (var C) δ

Now fix a candidate code domain C, a working set W, and ten environment entries certified to be the numerals zero through nine. For each tag, the object-language payload description can then be compared with its ambient predicate AtomP, BinP, ConP, QuP, or BqP.

module PayRead {m : } (C w : Fin m) (N : Fin 10  Fin m) (δ : S ^ (9 + m))
  (tg : Tags δ (shN 9 N)) where
  private
    Cv = fst (lookup (sh 9 C) δ)
    Wv = fst (lookup (sh 9 w) δ)

In each payload reading, A denotes the recorded arity and R the raw payload. The equations for tags zero and one are singled out because both atomic and bounded-quantifier payloads must recognize term codes, whose two legal shapes use precisely these tags.

    A = fst (lookup i5 δ)
    R = fst (lookup i0 δ)
    q0 = tg f0
    q1 = tg f1
    rS = lookup i0 δ

Both sides of the comparison use the same underlying sets Wv and Cv. The syntactic payload formulas therefore describe term membership in Wv and subkey membership in Cv, exactly matching the parameters of the five ambient payload predicates.

    module Sh = Shape C w N
  open CodesSem Wv Cv

The atomic body requires both components of the payload to satisfy the term-code predicate at the recorded arity. The binary body instead requires both components to occur as keys of that same arity in the candidate domain. These are different conditions even though both payloads are encoded as pairs.

  private
    tmBody : Formula S (12 + m)
    tmBody = isTm i1 i8 (sh 12 w) (sh 12 (N f0)) (sh 12 (N f1)) ∧̇ isTm i0 i8 (sh 12 w) (sh 12 (N f0)) (sh 12 (N f1))
    binBody : Formula S (12 + m)
    binBody = appAt (sh 12 C) i8 i1 ∧̇ appAt (sh 12 C) i8 i0

The last payload shape covers the two bounded quantifiers. Its body requires a legal term at the current arity for the bound and a body key in the code set at the successor arity.

    bqBody : Formula S (12 + m)
    bqBody = isTm i1 i8 (sh 12 w) (sh 12 (N f0)) (sh 12 (N f1)) ∧̇ keyUp (sh 12 C) i8 i0

Reading an atomic payload outward removes the two existential binders and produces terms t and u, an equation R ≡ pr t u, and proofs that both terms are legal at arity A. The term reader uses the tag equations for zero and one to turn the two satisfaction claims into the corresponding truncated term shapes.

  atom-out :  δ  Sh.atomPay   AtomP A R
  atom-out h = PT.map
     { (t , u , s , (e , (ht , hu)))  fst t , fst u
       , ( e , ( isTm-out i1 i8 (sh 12 w) (sh 12 (N f0)) (sh 12 (N f1)) (u  t  s  δ) q0 q1 ht
               , isTm-out i0 i8 (sh 12 w) (sh 12 (N f0)) (sh 12 (N f1)) (u  t  s  δ) q0 q1 hu ) ) })

The consumption itself is one application of the two-fold existential elimination: the witnesses t, u and the container are extracted, and the remaining conjunction is discharged into the payload data.

    (bothEx-out i0 tmBody δ h)

Reading inward rebuilds the satisfaction from the data. The truncated legality proofs are eliminated, since the goal is again a truncated satisfaction, and each of the two terms enters its legality atom through the shifted context.

  atom-in : AtomP A R   δ  Sh.atomPay 
  atom-in = PT.rec (snd (δ  Sh.atomPay))
     { (t , u , (e , (ht , hu))) 
      fillBoth i0 δ (fstS rS t u e) (sndS rS t u e) e tmBody
        ( isTm-in i1 i8 (sh 12 w) (sh 12 (N f0)) (sh 12 (N f1)) (δ12 t u e) q0 q1 ht

The second legality claim is inserted in the same way. The auxiliary environment δ12 consists of the two components selected by R ≡ pr t u, a container witnessing that pairing, and the original environment; this is exactly the environment in which both term atoms are interpreted.

        , isTm-in i0 i8 (sh 12 w) (sh 12 (N f0)) (sh 12 (N f1)) (δ12 t u e) q0 q1 hu ) })
    where
    δ12 : (t u : V ) (e : R  pr t u)  S ^ (12 + m)
    δ12 t u e = sndS rS t u e  fstS rS t u e  container rS (fstS rS t u e) (sndS rS t u e) e .fst  δ

Reading a binary payload outward yields payloads a and b, an equation R ≡ pr a b, and membership of both pr A a and pr A b in the code set. Adequacy of the two application atoms identifies those memberships in the extended environment.

  bin-out :  δ  Sh.binPay   BinP A R
  bin-out h = PT.map
     { (a , b , s , (e , (ha , hb)))  fst a , fst b
       , ( e , ( subst ⟨_⟩ (appAt-adequate (sh 12 C) i8 i1 (b  a  s  δ)) ha
               , subst ⟨_⟩ (appAt-adequate (sh 12 C) i8 i0 (b  a  s  δ)) hb ) ) })

As with the atoms, the two existentials of the binary condition are consumed by a single elimination.

    (bothEx-out i0 binBody δ h)

Reading inward fills the two existentials with the named sub-codes. The two application atoms are satisfied by transporting along the adequacy in the reverse direction, back into the shifted context.

  bin-in : BinP A R   δ  Sh.binPay 
  bin-in = PT.rec (snd (δ  Sh.binPay))
     { (a , b , (e , (ha , hb))) 
      fillBoth i0 δ (fstS rS a b e) (sndS rS a b e) e binBody
        ( subst ⟨_⟩ (sym (appAt-adequate (sh 12 C) i8 i1 (δ12 a b e))) ha

The binary helper records the same shifted-context shape, now built from the two ambient values a and b.

        , subst ⟨_⟩ (sym (appAt-adequate (sh 12 C) i8 i0 (δ12 a b e))) hb ) })
    where
    δ12 : (a b : V ) (e : R  pr a b)  S ^ (12 + m)
    δ12 a b e = sndS rS a b e  fstS rS a b e  container rS (fstS rS a b e) (sndS rS a b e) e .fst  δ

The falsity payload contains no subordinate data. Its formula says that R is the value stored in the zero-tag slot, while ConP A R says R ≡ # 0; composing with the zero-tag equation gives the outward direction.

  con-out :  δ  Sh.conPay   ConP A R
  con-out h = h  q0

Conversely, an equation R ≡ # 0 composes with the zero-tag equation in reverse to prove that R equals the value of the zero-tag slot, which is precisely satisfaction of the falsity payload.

  con-in : ConP A R   δ  Sh.conPay 
  con-in h = h  sym q0

For either unbounded quantifier, the payload is a body key at the successor arity. The successor-key reader turns satisfaction of this payload formula into membership of pr (sucV A) R in the code set.

  qu-out :  δ  Sh.quPay   QuP A R
  qu-out = keyUp-out (sh 9 C) i5 i0 δ

In the reverse direction, membership of pr (sucV A) R in the code set supplies the witnesses required by the successor-key formula and hence proves the quantifier payload.

  qu-in : QuP A R   δ  Sh.quPay 
  qu-in = keyUp-in (sh 9 C) i5 i0 δ

Reading a bounded-quantifier payload outward yields a term t, a body payload a, and an equation R ≡ pr t a. It also proves that t is legal at arity A and that the body key pr (sucV A) a belongs to the code set.

  bq-out :  δ  Sh.bqPay   BqP A R
  bq-out h = PT.map
     { (t , a , s , (e , (ht , ha)))  fst t , fst a
       , ( e , ( isTm-out i1 i8 (sh 12 w) (sh 12 (N f0)) (sh 12 (N f1)) (a  t  s  δ) q0 q1 ht
               , keyUp-out (sh 12 C) i8 i0 (a  t  s  δ) ha ) ) })

The two existentials of the bounded body are consumed by the same two-fold elimination as everywhere else.

    (bothEx-out i0 bqBody δ h)

Reading inward, the bounding term enters its legality atom through the shifted context.

  bq-in : BqP A R   δ  Sh.bqPay 
  bq-in = PT.rec (snd (δ  Sh.bqPay))
     { (t , a , (e , (ht , ha))) 
      fillBoth i0 δ (fstS rS t a e) (sndS rS t a e) e bqBody
        ( isTm-in i1 i8 (sh 12 w) (sh 12 (N f0)) (sh 12 (N f1)) (δ12 t a e) q0 q1 ht

The body key enters through the successor-key lemma, and the helper records the shifted context built from the bounding value and its container.

        , keyUp-in (sh 12 C) i8 i0 (δ12 t a e) ha ) })
    where
    δ12 : (t a : V ) (e : R  pr t a)  S ^ (12 + m)
    δ12 t a e = sndS rS t a e  fstS rS t a e  container rS (fstS rS t a e) (sndS rS t a e) e .fst  δ

The reader for a label is selected by recursion on the label. Labels zero and one are the two atoms, and labels two, three and four are the three binary connectives.

  payN-out : (k : )   δ  Sh.payN k   PayN k A R
  payN-out 0 = atom-out
  payN-out 1 = atom-out
  payN-out 2 = bin-out
  payN-out 3 = bin-out

Labels five, six and seven cover falsity and the two unbounded quantifiers; label eight is the bounded universal.

  payN-out 4 = bin-out
  payN-out 5 = con-out
  payN-out 6 = qu-out
  payN-out 7 = qu-out
  payN-out 8 = bq-out

Label nine is the bounded existential. Labels ten and beyond name no constructor: their payload is empty, so the reader is the identity on that empty data.

  payN-out 9 = bq-out
  payN-out (suc (suc (suc (suc (suc (suc (suc (suc (suc (suc _)))))))))) h = h

The inward reader is selected by the same recursion, one clause per label.

  payN-in : (k : )  PayN k A R   δ  Sh.payN k 
  payN-in 0 = atom-in
  payN-in 1 = atom-in
  payN-in 2 = bin-in
  payN-in 3 = bin-in

Labels four through seven continue the list: the last binary connective, falsity, and the two unbounded quantifiers.

  payN-in 4 = bin-in
  payN-in 5 = con-in
  payN-in 6 = qu-in
  payN-in 7 = qu-in
  payN-in 8 = bq-in

Label nine completes the list; beyond ten there is nothing to read, since no legitimate key carries such a label.

  payN-in 9 = bq-in
  payN-in (suc (suc (suc (suc (suc (suc (suc (suc (suc (suc _)))))))))) h = h

The ten-way reader interprets a tagged payload in a seven-entry extension of the ambient environment. It reads the code set and constant alphabet from the ambient entries, while N selects ten ambient positions whose values are identified with the numerals zero through nine by the tag hypothesis.

module TenRead {m : } (C w : Fin m) (N : Fin 10  Fin m) (δ : S ^ (7 + m))
  (tg : Tags δ (shN 7 N)) where
  private
    Cv = fst (lookup (sh 7 C) δ)
    Wv = fst (lookup (sh 7 w) δ)

Among the newly bound entries, A is the arity and P is the tagged payload to be recognized as a key. Retaining the set-level representative of P allows the equation P ≡ pr (# (toℕ j)) r to be realized when a tag and its payload r are chosen.

    A = fst (lookup i3 δ)
    P = fst (lookup i0 δ)
    pS = lookup i0 δ
    module Sh = Shape C w N
  open CodesSem Wv Cv

The tag reader converts satisfaction of the j-th tag atom into a key. The truncated witness pairs an index r with a container; the coding equation is transported along the tag equation, which says that the j-th tag slot names the numeral of j, and the payload is read by the label reader at j.

  at-out : (j : Fin 10)   δ  Sh.at j   Key A P
  at-out j h = PT.map
     { (r , s , (e , hp))  j , fst r
       , ( e  cong  a  pr a (fst r)) (tg j)
         , PayRead.payN-out C w N (r  s  δ) tg (toℕ j) hp ) })

The two existentials of the tag atom are consumed by its own elimination, so the reader never chooses an index: it only unpacks the one that satisfaction provides.

    (sndEx-out i0 (sh 7 (N j)) (Sh.pay j) δ h)

The inward direction builds the satisfaction from a key: the witness entry is filled with the shifted value, the payload is read inward over the extended context, and the tag equation identifies the naming slot with the numeral of j.

  at-in : (j : Fin 10) (r : V ) (e : P  pr (# (toℕ j)) r)  PayN (toℕ j) A r   δ  Sh.at j 
  at-in j r e pay =
    fillSnd i0 δ (lookup (sh 7 (N j)) δ) rS e' (Sh.pay j)
      (PayRead.payN-in C w N (rS  container pS (lookup (sh 7 (N j)) δ) rS e' .fst  δ) tg (toℕ j) pay)
      (sh 7 (N j)) refl

The renamed value pairs the numeral of j with the chosen entry, and the coding equation is composed with the tag equation in reverse, so the extended naming mentions the right slot.

    where
    rS : S
    rS = sndS pS (# (toℕ j)) r e
    e' : P  pr (fst (lookup (sh 7 (N j)) δ)) (fst rS)
    e' = e  cong  a  pr a r) (sym (tg j))

The ten-way outward reader consumes the disjunction and quotes the tag reader at whichever tag the witness names.

  ten-out :  δ  Sh.ten   Key A P
  ten-out h = PT.rec squash₁  { (j , hj)  at-out j hj }) (bigOr-out δ 9 Sh.at h)

The inward reader enters the disjunction at the witnessed tag, with the payload read inward at that tag. Both directions together say: satisfaction of the ten-way disjunction is the same thing as carrying a legitimate key.

  ten-in : Key A P   δ  Sh.ten 
  ten-in = PT.rec (snd (δ  Sh.ten))
     { (j , r , (e , pay))  bigOr-in δ 9 Sh.at j (at-in j r e pay) })

The shape reader fixes three ambient sets: the candidate code set C, the constant alphabet w, and the tower E of arity-family pairs. Their underlying iterative sets are used respectively for code membership, legal constant terms, and witnesses (ar,F) belonging to the tower.

module ShapeRead {m : } (C w E : Fin m) (N : Fin 10  Fin m) (γ : S ^ m) (tg : Tags γ N) where
  private
    Cv = fst (lookup C γ)
    Wv = fst (lookup w γ)
    Ev = fst (lookup E γ)

For a chosen member c and a tower witness (ar,F), the remaining formula chooses a payload p, requires c ≡ pr ar p, and tests p against the ten possible tag shapes. Thus the nested witnesses expose the outer arity and the inner tagged payload separately.

    module Sh = Shape C w N
    inner : Formula S (5 + m)
    inner = sndEx i4 i1 Sh.ten
  open CodesSem Wv Cv

Shaped c records exactly the data extracted from the shape clause: there are ar, F, and p such that pr ar F belongs to E, c ≡ pr ar p, and p is a legitimate tagged payload at arity ar. All of this existence data is propositionally truncated; no unique decomposition is asserted.

  Shaped : V   Type (ℓ-suc )
  Shaped c =  Σ[ ar  V  ] Σ[ F  V  ] Σ[ p  V  ]
               ( pr ar F  Ev  × ((c  pr ar p) × Key ar p)) ∥₁

For each c in the code set, outward reading first obtains a member q of E. Decomposing q gives ar and F with q ≡ pr ar F; the inner existential then gives p with c ≡ pr ar p and satisfaction of the ten-way payload formula.

  shape-out :  γ  shapeAt C w E N   (c : S)   fst c  Cv   Shaped (fst c)
  shape-out h c c∈ = PT.rec squash₁
     { (q , (q∈ , hb))  PT.rec squash₁
       { (ar , F , s , (eq , hs))  PT.map
         { (p , s' , (ec , ht)) 

The equation q ≡ pr ar F transports the known membership of q in E to membership of pr ar F. The equation for c is retained, and the ten-way reader converts the remaining satisfaction proof into Key ar p.

          fst ar , fst F , fst p
          , ( subst  u   u  Ev ) eq q∈
            , ( ec , TenRead.ten-out C w N (p  s'  F  ar  s  q  c  γ) tg ht ) ) })
        (sndEx-out i4 i1 Sh.ten (F  ar  s  q  c  γ) hs) })
      (bothEx-out i0 inner (q  c  γ) hb) })

The original shape satisfaction is universally quantified over members of the code set. Applying it to c and its membership proof supplies the existential data consumed above, completing the construction of Shaped (fst c).

    (h c c∈)

For the inward direction, assume that every member c of the code set has truncated shape data. Eliminating that truncation yields ar, F, and p, together with membership of pr ar F in E, the equation for c, and Key ar p; the target is itself a proposition, so this elimination is valid.

  shape-in : ((c : S)   fst c  Cv   Shaped (fst c))   γ  shapeAt C w E N 
  shape-in k c c∈ = PT.rec (snd ((c  γ)  ∃̇∈ (var (sh 1 E)) (bothEx i0 inner)))
     { (ar , F , p , (q∈ , (ec , key))) 
      let qS = down (lookup E γ) (pr ar F) q∈
          arS = fstS qS ar F refl

Membership of pr ar F in E supplies a set-level representative qS, whose two components represent ar and F. Separately, the equation c ≡ pr ar p selects a representative pS of the payload inside c. The two pairing containers provide the environments required by the nested existential formulas.

          FS = sndS qS ar F refl
          δ2 = qS  c  γ
          cq = container qS arS FS refl
          δ5 = FS  arS  cq .fst  δ2
          pS = sndS c ar p ec

The inner formula is filled with the arity-table data, and the ten-way disjunction is filled with the key, so the full shape satisfaction is assembled from the honest data.

          cp = container c arS pS ec
          δ7 = pS  cp .fst  δ5
      in  qS , ( q∈ , fillBoth i0 δ2 arS FS refl inner
            (fillSnd i4 δ5 arS pS ec Sh.ten
              (TenRead.ten-in C w N δ7 tg key) i1 refl) ) ∣₁ })

Applying the assumed shape assignment to c and its membership supplies precisely the truncated witnesses used by the inward construction. Together with the outward direction, this identifies satisfaction of the shape formula with the proposition Shaped for every member of the code set.

    (k c c∈)

The closure clauses are interpreted after a tower member has been decomposed as q ≡ pr ar F. In the resulting four-entry extension, A is the fixed arity ar; the code set and constant alphabet remain available from the ambient environment, and the tag equations remain valid after the shift.

module CloseRead {m : } (C w : Fin m) (N : Fin 10  Fin m) (δ : S ^ (4 + m)) (tg : Tags δ (shN 4 N)) where
  private
    Cv = fst (lookup (sh 4 C) δ)
    A = fst (lookup i1 δ)
    arS = lookup i1 δ

At this fixed arity, the closure conditions say that applying any of the ten constructors to inputs of the required shapes produces another member of the code set. For each clause, the outward and inward readings identify its bounded formula with the corresponding closure property.

    CS = lookup (sh 4 C) δ
    module Cl = Close C w N

Outward reading of an atomic closure clause permits arbitrary x from the bound selected by X and arbitrary y from the bound selected by Y in the environment extended by x. It then yields membership in the code set of the atomic key at arity A, with constructor tag k and term-form tags Nx and Ny.

  atomClose-out : (k Nx Ny : Fin 10) (X : Fin (4 + m)) (Y : Fin (5 + m))
                  δ  Cl.atomClose k Nx Ny X Y 
                 (x y : S)   fst x  fst (lookup X δ)    fst y  fst (lookup Y (x  δ)) 
                  pr A (pr (# (toℕ k)) (pr (pr (# (toℕ Nx)) (fst x)) (pr (# (toℕ Ny)) (fst y))))  Cv 
  atomClose-out k Nx Ny X Y h x y x∈ y∈ =

The membership is transported along the tag equations, which rename the three slots to the numerals of the three tags, since the clause is stated at the tagged slots but the key is spelled with the numerals.

    subst  u   u  Cv )
      (cong (pr A) (cong₂ pr (tg k) (cong₂ pr (cong  a  pr a (fst x)) (tg Nx)) (cong  a  pr a (fst y)) (tg Ny)))))
      (atomKey-out (sh 6 C) i3 (sh 6 (N k)) (sh 6 (N Nx)) i1 (sh 6 (N Ny)) i0 (y  x  δ) (h x x∈ y y∈))

The inward direction rebuilds the clause: given the property for all pairs, it suffices to instantiate it at the given x and y, with the naming equations run in reverse.

  atomClose-in : (k Nx Ny : Fin 10) (X : Fin (4 + m)) (Y : Fin (5 + m))
                ((x y : S)   fst x  fst (lookup X δ)    fst y  fst (lookup Y (x  δ)) 
                    pr A (pr (# (toℕ k)) (pr (pr (# (toℕ Nx)) (fst x)) (pr (# (toℕ Ny)) (fst y))))  Cv )
                 δ  Cl.atomClose k Nx Ny X Y 
  atomClose-in k Nx Ny X Y g x x∈ y y∈ =

The membership is transported into the tagged slots by the reversed renamings, and the introduction rule of the closure clause finishes the case.

    atomKey-in (sh 6 C) i3 (sh 6 (N k)) (sh 6 (N Nx)) i1 (sh 6 (N Ny)) i0 (y  x  δ)
      (subst  u   u  Cv )
        (sym (cong (pr A) (cong₂ pr (tg k) (cong₂ pr (cong  a  pr a (fst x)) (tg Nx)) (cong  a  pr a (fst y)) (tg Ny))))))
        (g x y x∈ y∈))

The binary closure clause ranges over two members c₁ and c₂ of the code set. The equations fst c₁ ≡ pr A (fst a) and fst c₂ ≡ pr A (fst b) expose their payloads a and b at the fixed arity A; the clause then places the binary key with payload pr (fst a) (fst b) back in the code set.

  binClose-out : (k : Fin 10)   δ  Cl.binClose k 
                (c₁ c₂ a b : S)   fst c₁  Cv    fst c₂  Cv 
                fst c₁  pr A (fst a)  fst c₂  pr A (fst b)
                 pr A (pr (# (toℕ k)) (pr (fst a) (fst b)))  Cv 
  binClose-out k h c₁ c₂ a b c₁∈ c₂∈ e₁ e₂ =

The membership is transported along the tag renaming of the label, and the two nested universal layers are discharged by the elimination lemmas of the bounded quantifiers, each entry entering the inner clause through its own pairing container.

    subst  u   u  Cv ) (cong (pr A) (cong  v  pr v (pr (fst a) (fst b))) (tg k)))
      (binKey-out (sh 10 C) i7 (sh 10 (N k)) i3 i0 δ10
        (useSnd i0 δ8 arS b e₂ (binKey (sh 10 C) i7 (sh 10 (N k)) i3 i0) i5 refl
          (useSnd i0 (c₁  δ) arS a e₁ inner i2 refl (h c₁ c₁∈) c₂ c₂∈)))
    where

After c₁ has been chosen and written as pr A a, the inner formula quantifies over a second code c₂ in the code set and exposes it as pr A b. It then requires the binary key formed from tag k and the paired payload pr a b; the auxiliary environments record the two decompositions of c₁ and c₂.

    inner : Formula S (7 + m)
    inner = ∀̇∈ (var (sh 7 C)) (sndAll i0 i5 (binKey (sh 10 C) i7 (sh 10 (N k)) i3 i0))
    δ7 : S ^ (7 + m)
    δ7 = a  container c₁ arS a e₁ .fst  c₁  δ
    δ8 : S ^ (8 + m)

For the quantifier clauses, the environment must remember both a subkey and the data that determine its arity. The environment δ8 contains the candidate argument a, a proposed successor arity ar', the pair witnessing their relation, and the subkey c₁; δ10 adds the term used as the bound in a bounded quantifier.

    δ8 = c₂  δ7
    δ10 : S ^ (10 + m)
    δ10 = b  container c₂ arS b e₂ .fst  δ8

The inward direction for a binary closure clause starts from its mathematical closure rule: two subkeys of the same arity that belong to the domain determine a composite key that also belongs to it. The two universal quantifiers merely make the chosen subkeys explicit.

  binClose-in : (k : Fin 10)
               ((c₁ c₂ a b : S)   fst c₁  Cv    fst c₂  Cv 
                  fst c₁  pr A (fst a)  fst c₂  pr A (fst b)
                   pr A (pr (# (toℕ k)) (pr (fst a) (fst b)))  Cv )
                δ  Cl.binClose k 

Introducing the two quantified components extends the environment in the order prescribed by the formula. At the innermost implication, the assumed closure rule gives membership of the composite key; the tag equation tg k identifies its displayed tag with the numeral required by binKey.

  binClose-in k g c₁ c₁∈ = sndAll-in i0 i2 (∀̇∈ (var (sh 7 C)) (sndAll i0 i5 (binKey (sh 10 C) i7 (sh 10 (N k)) i3 i0))) (c₁  δ)  a s s∈ a∈ e₁ c₂ c₂∈ 
    sndAll-in i0 i5 (binKey (sh 10 C) i7 (sh 10 (N k)) i3 i0) (c₂  a  s  c₁  δ)  b s' s'∈ b∈ e₂ 
      binKey-in (sh 10 C) i7 (sh 10 (N k)) i3 i0 (b  s'  c₂  a  s  c₁  δ)
        (subst  u   u  Cv ) (sym (cong (pr A) (cong  v  pr v (pr (fst a) (fst b))) (tg k))))
          (g c₁ c₂ a b c₁∈ c₂∈ e₁ e₂))))

For falsity there is no subordinate code to inspect. Reading its closure clause outward therefore reduces to the equation identifying the payload with the zero numeral, followed by transport along the tag equations.

  conClose-out : (k : Fin 10)   δ  Cl.conClose k    pr A (pr (# (toℕ k)) (# 0))  Cv 
  conClose-out k h =
    subst  u   u  Cv ) (cong (pr A) (cong₂ pr (tg k) (tg f0)))
      (unKey-out (sh 4 C) i1 (sh 4 (N k)) (sh 4 (N f0)) δ h)

Conversely, membership of the falsity key is transported back along the same equations to satisfy the closure clause. This case has no recursive premise: the zero payload completely determines the key.

  conClose-in : (k : Fin 10)   pr A (pr (# (toℕ k)) (# 0))  Cv    δ  Cl.conClose k 
  conClose-in k h =
    unKey-in (sh 4 C) i1 (sh 4 (N k)) (sh 4 (N f0)) δ
      (subst  u   u  Cv ) (sym (cong (pr A) (cong₂ pr (tg k) (tg f0)))) h)

The unbounded-quantifier clause is read outward with the quantified components explicit: given a subkey c₁ of the domain, a presentation c₁ = pr ar' a, and the equation ar' = sucV A, the quantifier key at the current arity belongs to the domain. The three hypotheses are exactly the data of a predecessor slice member.

  quClose-out : (k : Fin 10)   δ  Cl.quClose k 
               (c₁ ar' a : S)   fst c₁  Cv   fst c₁  pr (fst ar') (fst a)  fst ar'  sucV A
                pr A (pr (# (toℕ k)) (fst a))  Cv 
  quClose-out k h c₁ ar' a c₁∈ e₁ es =
    subst  u   u  Cv ) (cong (pr A) (cong  v  pr v (fst a)) (tg k)))

The proof extends the environment by a, ar', and the container, opens the implication with the successor equation, and reads the unKey membership in the eight-slot environment. Transport along the tag equation then gives membership for the numeral represented by tag k.

      (unKey-out (sh 8 C) i5 (sh 8 (N k)) i0 δ8
        (useBoth i0 (c₁  δ) ar' a e₁ (sucAtL i5 i1 ⇒̇ unKey (sh 8 C) i5 (sh 8 (N k)) i0) (h c₁ c₁∈)
          (suc-in i5 i1 δ8 es)))
    where
    δ8 : S ^ (8 + m)

The extended environment packages the three quantified components with the original one, in the order the implication reads them.

    δ8 = a  ar'  container c₁ ar' a e₁ .fst  c₁  δ

For the inward direction, introduce the two quantified components of the clause. The extended environment contains the proposed successor arity ar' and the payload a; the successor equation then supplies the premise of the implication.

  quClose-in : (k : Fin 10)
              ((c₁ ar' a : S)   fst c₁  Cv   fst c₁  pr (fst ar') (fst a)  fst ar'  sucV A
                  pr A (pr (# (toℕ k)) (fst a))  Cv )
               δ  Cl.quClose k 
  quClose-in k g c₁ c₁∈ = bothAll-in i0 (sucAtL i5 i1 ⇒̇ unKey (sh 8 C) i5 (sh 8 (N k)) i0) (c₁  δ)  ar' a s s∈ ar'∈ a∈ e₁ hs 

Apply the assumed closure rule to these data, then transport the resulting membership along the tag equation to obtain the unKey conclusion. This completes the inward reading of the unbounded-quantifier clause.

    unKey-in (sh 8 C) i5 (sh 8 (N k)) i0 (a  ar'  s  c₁  δ)
      (subst  u   u  Cv ) (sym (cong (pr A) (cong  v  pr v (fst a)) (tg k))))
        (g c₁ ar' a c₁∈ e₁ (suc-out i5 i1 (a  ar'  s  c₁  δ) hs))))

The bounded-quantifier clause has one additional premise. Besides a body key at the successor arity, it requires a legal bounding term x at the current arity; the resulting payload records the quantifier tag, the term tag Nx, the term itself, and the body payload as nested pairs.

  bqClose-out : (k Nx : Fin 10) (X : Fin (8 + m))   δ  Cl.bqClose k Nx X 
               (c₁ ar' a : S)   fst c₁  Cv   (e₁ : fst c₁  pr (fst ar') (fst a))  fst ar'  sucV A
               (x : S)   fst x  fst (lookup X (a  ar'  container c₁ ar' a e₁ .fst  c₁  δ)) 
                pr A (pr (# (toℕ k)) (pr (pr (# (toℕ Nx)) (fst x)) (fst a)))  Cv 
  bqClose-out k Nx X h c₁ ar' a c₁∈ e₁ es x x∈ =

The proof extends the environment by the bounding term and applies bounded-key elimination there. The two tag equations, one for the quantifier constructor and one for the term constructor, transport the nested pair to the shape named in the conclusion.

    subst  u   u  Cv )
      (cong (pr A) (cong₂ pr (tg k) (cong  v  pr v (fst a)) (cong  v  pr v (fst x)) (tg Nx)))))
      (bndKey-out (sh 9 C) i6 (sh 9 (N k)) (sh 9 (N Nx)) i0 i1 (x  δ8)
        (useBoth i0 (c₁  δ) ar' a e₁ (sucAtL i5 i1 ⇒̇ ∀̇∈ (var X) (bndKey (sh 9 C) i6 (sh 9 (N k)) (sh 9 (N Nx)) i0 i1))
          (h c₁ c₁∈) (suc-in i5 i1 δ8 es) x x∈))

The eight-slot environment repeats the packaging used by the unbounded case, with the bound slot consumed by the elimination.

    where
    δ8 : S ^ (8 + m)
    δ8 = a  ar'  container c₁ ar' a e₁ .fst  c₁  δ

For the inward direction, assume the mathematical closure rule displayed in the type. It is quantified over an arbitrary extended environment s, because the set from which the bounding term is chosen is evaluated in that environment.

  bqClose-in : (k Nx : Fin 10) (X : Fin (8 + m))
              ((c₁ ar' a s : S)   fst c₁  Cv   fst c₁  pr (fst ar') (fst a)  fst ar'  sucV A
                 (x : S)   fst x  fst (lookup X (a  ar'  s  c₁  δ)) 
                  pr A (pr (# (toℕ k)) (pr (pr (# (toℕ Nx)) (fst x)) (fst a)))  Cv )
               δ  Cl.bqClose k Nx X 

Introduce the quantified subkey data and the bounding term, then apply the assumed closure rule in the resulting environment. Transport along the two tag equations turns its conclusion into the membership required by bndKey, completing the inward reading of the bounded-quantifier clause.

  bqClose-in k Nx X g c₁ c₁∈ = bothAll-in i0 (sucAtL i5 i1 ⇒̇ ∀̇∈ (var X) (bndKey (sh 9 C) i6 (sh 9 (N k)) (sh 9 (N Nx)) i0 i1)) (c₁  δ)  ar' a s s∈ ar'∈ a∈ e₁ hs x x∈ 
    bndKey-in (sh 9 C) i6 (sh 9 (N k)) (sh 9 (N Nx)) i0 i1 (x  a  ar'  s  c₁  δ)
      (subst  u   u  Cv )
        (sym (cong (pr A) (cong₂ pr (tg k) (cong  v  pr v (fst a)) (cong  v  pr v (fst x)) (tg Nx))))))
        (g c₁ ar' a s c₁∈ e₁ (suc-out i5 i1 (a  ar'  s  c₁  δ) hs) x x∈)))

Soundness: decoding every member

To prove soundness, we now connect three descriptions already available: numerical tags identify the ten constructors, shape and closure formulas describe their internal set codes, and AllCodes relates those codes back to the external formula grammar. Propositionality will allow truncated witnesses to be eliminated without choosing representatives.

open import L.Coding.Expressions {} using ( tagAtL-adequate )
open import L.Coding.Closure {} using ( closedAt; binSameClosed-in; unSuccClosed-in; binSuccClosed-in )
open import L.Coding.CodeShape {} using
  ( shapedAt; shaped-in; ShapeWit; BinWit; bothTm; fstTm; noneB; isTmAt )
open import L.Coding.CodeSet {} lem using

The canonical code set provides both directions of this comparison: a member can be read as a formula key, and every formula has a canonical key. The remaining imports supply the witnesses for recorded arities and the fact that conjunctions of propositions are again propositions.

  ( AllCodes; AllCodes-out; key∈AllCodes; keyS; codeS; witnessAt-out )
open import Cubical.Foundations.HLevels using ( isProp× )

Fix a working set Wv, whose elements may occur as constants, and a candidate code domain Cv. The following argument is parametric in these two sets; no assumption yet identifies Cv with the canonical domain AllCodes.

module _ (Wv Cv : V ) where
  open CodesSem Wv Cv

Every payload condition PayN n ar r is a proposition. For tags zero through four this follows immediately from propositional truncation: the condition asserts only that suitable components merely exist.

  isPropPayN : (n : ) (ar r : V )  isProp (PayN n ar r)
  isPropPayN 0 ar r = squash₁
  isPropPayN 1 ar r = squash₁
  isPropPayN 2 ar r = squash₁
  isPropPayN 3 ar r = squash₁

The remaining constructor tags use the same principle in the form appropriate to their payloads. Falsity has a unique zero payload; unbounded quantifiers require membership in Cv, which is proposition-valued; bounded quantifiers again use truncated existence.

  isPropPayN 4 ar r = squash₁
  isPropPayN 5 ar r = setIsSet r (# 0)
  isPropPayN 6 ar r = snd (pr (sucV ar) r  Cv)
  isPropPayN 7 ar r = snd (pr (sucV ar) r  Cv)
  isPropPayN 8 ar r = squash₁

Tag nine is handled by truncated existence as well. Any numeral beyond the ten constructor tags has an empty payload type, and an empty type is a proposition. Thus PayN is proposition-valued for every natural-number tag.

  isPropPayN 9 ar r = squash₁
  isPropPayN (suc (suc (suc (suc (suc (suc (suc (suc (suc (suc _)))))))))) ar r = Empty.isProp⊥*

The key-alignment lemma converts a Key at arity ar into a payload at any other decomposition p = (# n, r) of the same set. Pair injectivity and numeral injectivity align the tag and the payload separately, and because PayN n ar r is a proposition, the truncated key may be eliminated into it.

  keyAt : (ar p : V )  Key ar p  (n : ) (r : V )  p  pr (# n) r  PayN n ar r
  keyAt ar p key n r e = PT.rec (isPropPayN n ar r)
     { (k , r' , (e' , pay)) 
      let q = pr-inj (sym e  e')
      in subst2  j x  PayN j ar x) (sym (#-inj′ (q .fst))) (sym (q .snd)) pay })

Applying this elimination to key completes the alignment: the tag and payload obtained from Key have already been transported to the prescribed numeral n and payload r.

    key

The first recovery lemma converts a term-code statement into a satisfaction of the shape chapter's term predicate. It is stated for arbitrary slots and proved by eliminating the truncated IsTmV into the proposition-valued satisfaction.

tmWit :  {j} (ti Ni Ai : Fin j) (env : S ^ j)
       IsTmV (fst (lookup Ai env)) (fst (lookup ti env)) (fst (lookup Ni env))
        env  isTmAt ti Ni Ai 
tmWit ti Ni Ai env = PT.rec (snd (env  isTmAt ti Ni Ai))
   { (inl (x , (e , x∈))) 

In the constant branch, down presents the witness x as an element of the working set Wv. Tag adequacy transports the pair equation, while the original membership proof supplies the other conjunct. The resulting evidence enters the left disjunct of the shape predicate.

          inl  down (lookup Ai env) x x∈
           , ( subst ⟨_⟩ (sym (tagAtL-adequate (suc ti) 0 zero (down (lookup Ai env) x x∈  env))) e
             , x∈ ) ∣₁ ∣₁
     ; (inr (i , (e , i∈))) 
          inr  down (lookup Ni env) i i∈

The variable branch repeats the construction with the numeral slot presenting the index. Both branches together show that term codes convert into shape satisfactions without any choice.

           , ( subst ⟨_⟩ (sym (tagAtL-adequate (suc ti) 1 zero (down (lookup Ni env) i i∈  env))) e
             , i∈ ) ∣₁ ∣₁ })

We can now state soundness for a candidate domain C. Assume that the constant alphabet is the set W, that the ten tag slots contain the correct numerals, that every arity recorded in the environment set is a natural-number numeral, and that C satisfies the shape description. From these assumptions, every member of C will be recovered as a formula key.

module CodesSound {m : } (C w E : Fin m) (N : Fin 10  Fin m) (γ : S ^ m) (W : S)
  (qw : fst (lookup w γ)  fst W) (tg : Tags γ N)
  (arity : (n F : S)   pr (fst n) (fst F)  fst (lookup E γ)    Σ[ k   ] (fst n  # k) ∥₁)
  (hs :  γ  shapeAt C w E N ) where
  private

Write Cv for the underlying set of the candidate domain and CS for its representative in the constructible structure, which packages that set with a proof of constructibility. Similarly, Wv and Ev denote the underlying working set and environment set. These abbreviations distinguish host-level sets used in membership statements from their packaged representatives in first-order environments.

    Cv = fst (lookup C γ)
    CS = lookup C γ
    Wv = fst (lookup w γ)
    Ev = fst (lookup E γ)
    module SR = ShapeRead C w E N γ tg

The payload conditions are henceforth interpreted relative to the fixed working set Wv and candidate domain Cv.

  open CodesSem Wv Cv

The proof proceeds through auxiliary lemmas that recover the payload information hidden by the shape formula.

  private

For a chosen member c, the environment δ' c places the candidate domain and c before the original environment. This is the context in which the shape predicate for that member is interpreted.

    δ' : S  S ^ (2 + m)
    δ' c = CS  c  γ

The alignment lemma at is the core of soundness. From the shape satisfaction at a member c, it recovers a truncated shape witness, splits the pair equation against the target decomposition, and applies keyAt to move the payload to the numbered decomposition. The elimination is legitimate because payloads are propositions.

    at : (c : S)   fst c  Cv   (n : ) (ar r : V )  fst c  pr ar (pr (# n) r)
        PayN n ar r
    at c c∈ n ar r e = PT.rec (isPropPayN Wv Cv n ar r)
       { (ar' , F , p , (q∈ , (ec , key))) 
        let q = pr-inj (sym ec  e)

The arity equation is transported last, since the shape witness and the target decomposition may present the arity by different sets. The source of the payload is the shape reading of the chapter's hypothesis at the member.

        in subst  a  PayN n a r) (q .fst) (keyAt Wv Cv ar' p key n r (q .snd)) })
      (SR.shape-out hs c c∈)

The binary extractor converts a binary payload into the two subkeys of the same arity inside the domain. Its statement names the tag equation explicitly, because the payload was obtained at a numbered decomposition that must be aligned with the displayed pair.

    binAt : (k : )  PayN k  BinP  (c ar a b : S)   fst c  Cv 
           fst c  pr (fst ar) (pr (# k) (pr (fst a) (fst b)))
            pr (fst ar) (fst a)  Cv  ×  pr (fst ar) (fst b)  Cv 
    binAt k eq c ar a b c∈ e = PT.rec (isProp× (snd (pr (fst ar) (fst a)  Cv)) (snd (pr (fst ar) (fst b)  Cv)))
       { (a' , b' , (er , (ha , hb))) 

Pair injectivity splits the equation into the two component equations, and each subkey is transported into place. The source of the payload is the alignment lemma applied at the member with the numbered tag.

        let q = pr-inj er
        in subst  u   pr (fst ar) u  Cv ) (sym (q .fst)) ha
         , subst  u   pr (fst ar) u  Cv ) (sym (q .snd)) hb })
      (subst  P  P (fst ar) (pr (fst a) (fst b))) eq (at c c∈ k (fst ar) (pr (fst a) (fst b)) e))

The bounded-quantifier extractor turns a bounded payload into membership of its body key at the successor arity. Its proof eliminates the truncated payload and transports the inner membership along the equation for the second component of the pair.

    bqAt : (k : )  PayN k  BqP  (c ar a b : S)   fst c  Cv 
          fst c  pr (fst ar) (pr (# k) (pr (fst a) (fst b)))
           pr (sucV (fst ar)) (fst b)  Cv 
    bqAt k eq c ar a b c∈ e = PT.rec (snd (pr (sucV (fst ar)) (fst b)  Cv))
       { (t , a' , (er , (ht , ha))) 

Once the bounded payload has been aligned with the displayed nested pair, its body component is exactly a key at the successor arity. Transporting this membership along the component equation proves the desired conclusion.

        subst  u   pr (sucV (fst ar)) u  Cv ) (sym (pr-inj er .snd)) ha })
      (subst  P  P (fst ar) (pr (fst a) (fst b))) eq (at c c∈ k (fst ar) (pr (fst a) (fst b)) e))

These extraction lemmas give the downward closure required for recursion on codes. For each of the three binary connectives, membership of a composite key implies membership of both immediate subkeys at the same arity.

    hcl : (c : S)   δ' c  closedAt zero 
    hcl c =
        binSameClosed-in zero 2 (δ' c) (binAt 2 refl)
      , ( binSameClosed-in zero 3 (δ' c) (binAt 3 refl)
      , ( binSameClosed-in zero 4 (δ' c) (binAt 4 refl)

The same conclusion holds for quantifiers with the expected change of arity. An unbounded or bounded quantifier key at arity n contains a body key at successor arity; the bounded cases additionally discard the bounding-term component after verifying the payload shape.

      , ( unSuccClosed-in zero 6 (δ' c)  c' ar a c'∈ e  at c' c'∈ 6 (fst ar) (fst a) e)
      , ( unSuccClosed-in zero 7 (δ' c)  c' ar a c'∈ e  at c' c'∈ 7 (fst ar) (fst a) e)
      , ( binSuccClosed-in zero 8 (δ' c) (bqAt 8 refl)
      ,   binSuccClosed-in zero 9 (δ' c) (bqAt 9 refl) )))))

It remains to recover the full shape of an arbitrary member c' of the candidate domain. The shape description gives a truncated decomposition, the environment hypothesis identifies its arity with a natural-number numeral, and Key identifies its tag and payload. The result remains truncated throughout.

    wit : (c c' : S)   fst c'  Cv    ShapeWit (sh 2 w) (δ' c) c' ∥₁
    wit c c' c'∈ = PT.rec squash₁
       { (ar , F , p , (q∈ , (ec , key)))  PT.rec squash₁
         { (k , r , (e' , pay)) 
          let qS = down (lookup E γ) (pr ar F) q∈

The recovered data are represented inside the relevant sets: qS presents the environment entry, arS presents its arity, pS presents the coded payload, and rS presents the inner payload. Their equations compose to the key equation ek.

              arS = fstS qS ar F refl
              pS = sndS c' ar p ec
              rS = sndS pS (# (toℕ k)) r e'
              ek : fst c'  pr (fst arS) (pr (# (toℕ k)) (fst rS))
              ek = ec  cong (pr ar) e'

The lemma fill now analyzes the recovered tag. For each of the ten possible tags, it turns the corresponding payload condition into a witness for the appropriate branch of the shape formula.

          in fill k c' arS rS pay ek })
        key })
      (SR.shape-out hs c' c'∈)
      where
      env4 : (c' arS b a : S)  S ^ (6 + m)

The auxiliary environment records two payload components together with the successor arity. It provides precisely the variables needed to interpret the branches for binary connectives and quantified formulas.

      env4 c' arS b a = b  a  arS  c'  δ' c

A binary payload merely asserts the existence of two components whose ordered pair is the displayed payload and whose keys belong to the domain. The helper pairWit converts precisely these data into the witness required by the corresponding branch of the shape formula.

      pairWit : (k : ) (rel : Formula S (4 + (2 + m))) (c' arS rS : S)
               fst c'  pr (fst arS) (pr (# k) (fst rS))
               (t u : V )  fst rS  pr t u
               ((tS uS : S)  fst tS  t  fst uS  u   env4 c' arS uS tS  rel )
               BinWit k rel (δ' c) c'

Pair injectivity separates the payload equality into equations for its two components. Together with the arity presentation and the composite key equation, these equations place the two membership proofs in the four fields required by BinWit.

      pairWit k rel c' arS rS ek t u er g =
        arS , (fstS rS t u er , (sndS rS t u er
        , ( ek  cong  v  pr (fst arS) (pr (# k) v)) er
          , g (fstS rS t u er) (sndS rS t u er) refl refl )))

For atomic formulas, both payload components must be legal term codes at the recorded arity. Applying tmWit to each component turns these two semantic conditions into the two conjuncts of bothTm.

      both : (c' arS : S) (t u : V )  IsTmV Wv t (fst arS)  IsTmV Wv u (fst arS)
            (tS uS : S)  fst tS  t  fst uS  u   env4 c' arS uS tS  bothTm (sh 2 w) 
      both c' arS t u ht hu tS uS qt qu =
          tmWit (suc zero) (suc (suc zero)) (sh 4 (sh 2 w)) (env4 c' arS uS tS)
            (subst  x  IsTmV Wv x (fst arS)) (sym qt) ht)

The second component is treated identically, so the two recovered term witnesses establish the conjunction required for an atomic payload.

        , tmWit zero (suc (suc zero)) (sh 4 (sh 2 w)) (env4 c' arS uS tS)
            (subst  x  IsTmV Wv x (fst arS)) (sym qu) hu)

A bounded quantifier needs only its bounding term to be legal at the current arity. The corresponding helper therefore applies tmWit to the first payload component alone.

      first : (c' arS : S) (t u : V )  IsTmV Wv t (fst arS)
             (tS uS : S)  fst tS  t  fst uS  u   env4 c' arS uS tS  fstTm (sh 2 w) 
      first c' arS t u ht tS uS qt qu =
        tmWit (suc zero) (suc (suc zero)) (sh 4 (sh 2 w)) (env4 c' arS uS tS)
          (subst  x  IsTmV Wv x (fst arS)) (sym qt) ht)

Tag zero denotes membership. Its payload contains two legal term codes, so the binary helper supplies the leftmost branch of the shape formula with the recovered term evidence.

      fill : (k : Fin 10) (c' arS rS : S)  PayN (toℕ k) (fst arS) (fst rS)
            fst c'  pr (fst arS) (pr (# (toℕ k)) (fst rS))
             ShapeWit (sh 2 w) (δ' c) c' ∥₁
      fill zero c' arS rS pay ek = PT.map
         { (t , u , (er , (ht , hu)))  inl (pairWit 0 (bothTm (sh 2 w)) c' arS rS ek t u er (both c' arS t u ht hu)) })

Tag one denotes equality and is handled by the same two-term argument in the next branch. Tag two begins the binary connectives; there the same ordered-pair analysis is used, but the recovered components are subformula keys rather than term codes.

        pay
      fill (suc zero) c' arS rS pay ek = PT.map
         { (t , u , (er , (ht , hu)))  inr (inl (pairWit 1 (bothTm (sh 2 w)) c' arS rS ek t u er (both c' arS t u ht hu))) })
        pay
      fill (suc (suc zero)) c' arS rS pay ek = PT.map

The fill cases for the three binary connectives are uniform: the payload names two sub-codes a and b, and the witness is a pairWit at the label, with no bounding term and a vacuous payload condition, since the binary clauses impose none. The nesting depth of the disjunction tags the label's position in the ten-way sum.

         { (a , b , (er , _))  inr (inr (inl (pairWit 2 noneB c' arS rS ek a b er  _ _ _ _ b  b)))) })
        pay
      fill (suc (suc (suc zero))) c' arS rS pay ek = PT.map
         { (a , b , (er , _))  inr (inr (inr (inl (pairWit 3 noneB c' arS rS ek a b er  _ _ _ _ b  b))))) })
        pay

Implication occupies the fourth binary tag and follows the same pattern. Falsity is different: its payload is the numeral zero, so the witness consists of the arity and payload equations, with numeralL-fst supplying the equation for the underlying set of that numeral.

      fill (suc (suc (suc (suc zero)))) c' arS rS pay ek = PT.map
         { (a , b , (er , _))  inr (inr (inr (inr (inl (pairWit 4 noneB c' arS rS ek a b er  _ _ _ _ b  b)))))) })
        pay
      fill (suc (suc (suc (suc (suc zero))))) c' arS rS pay ek =
         inr (inr (inr (inr (inr (inl (arS , (rS , (ek , pay  sym (numeralL-fst 0))))))))) ∣₁

The two unbounded quantifiers are again uniform: their payload is the sub-key at the successor arity, and the witness condition is the identity on that data, since the quantifier clauses add no term requirements. Only the tag position distinguishes existence from universality.

      fill (suc (suc (suc (suc (suc (suc zero)))))) c' arS rS pay ek =
         inr (inr (inr (inr (inr (inr (inl (arS , (rS , (ek ,  b  b)))))))))) ∣₁
      fill (suc (suc (suc (suc (suc (suc (suc zero))))))) c' arS rS pay ek =
         inr (inr (inr (inr (inr (inr (inr (inl (arS , (rS , (ek ,  b  b))))))))))) ∣₁
      fill (suc (suc (suc (suc (suc (suc (suc (suc zero)))))))) c' arS rS pay ek = PT.map

The bounded universal adds the term layer: its payload contains a legal bounding term t besides the member a, and the witness uses the one-term reader first for that term, with fstTm naming the term slot of the bounded-key shape.

         { (t , a , (er , (ht , _)))  inr (inr (inr (inr (inr (inr (inr (inr (inl
          (pairWit 8 (fstTm (sh 2 w)) c' arS rS ek t a er (first c' arS t a ht)))))))))) })
        pay
      fill (suc (suc (suc (suc (suc (suc (suc (suc (suc zero))))))))) c' arS rS pay ek = PT.map
         { (t , a , (er , (ht , _)))  inr (inr (inr (inr (inr (inr (inr (inr (inr

The bounded existential has the same payload shape as the bounded universal, but occupies the final tag. The ten cases now cover exactly the constructors of formulas: four atomic forms, three binary connectives, falsity, and the bounded and unbounded quantifiers.

          (pairWit 9 (fstTm (sh 2 w)) c' arS rS ek t a er (first c' arS t a ht)))))))))) })
        pay

The shape-soundness lemma now packages the construction member by member. For each c in the code set, shaped-in turns the witness just built into satisfaction of shapedAt; these are precisely the local shape facts needed when a code is decoded.

    hsh : (c : S)   δ' c  shapedAt zero (sh 2 w) 
    hsh c = shaped-in zero (sh 2 w) (δ' c) (wit c)

The closure clause is proved for all seven non-atomic constructors at once. The three binary connectives are discharged by binAt, which reads the label's payload and extracts the two sub-codes' memberships through the injectivity of the pair coding.

  closed :  γ  closedAt C 
  closed =
      binSameClosed-in C 2 γ (binAt 2 refl)
    , ( binSameClosed-in C 3 γ (binAt 3 refl)
    , ( binSameClosed-in C 4 γ (binAt 4 refl)

The two unbounded quantifiers are discharged by quoting the reader at the successor arity, and the two bounded quantifiers by bqAt, which additionally reads off the bounding term. Together the seven entries certify closedAt C in the ambient environment.

    , ( unSuccClosed-in C 6 γ  c' ar a c'∈ e  at c' c'∈ 6 (fst ar) (fst a) e)
    , ( unSuccClosed-in C 7 γ  c' ar a c'∈ e  at c' c'∈ 7 (fst ar) (fst a) e)
    , ( binSuccClosed-in C 8 γ (bqAt 8 refl)
    ,   binSuccClosed-in C 9 γ (bqAt 9 refl) )))))

The decoding theorem is the chapter's first main result. Every member c of a code set satisfying the description yields, under propositional truncation, a natural number k and a formula ψ of arity k, with fst c ≡ fst (keyS W ψ). Thus the theorem asserts existence of a matching formula key, without choosing a decoder or asserting uniqueness.

  key-out : (c : S)   fst c  Cv 
            Σ[ k   ] Σ[ ψ  Formula  fst W  k ] (fst c  fst (keyS W ψ)) ∥₁
  key-out c c∈ = PT.rec squash₁
     { (ar , F , p , (q∈ , (ec , key)))  PT.rec squash₁
       { (k , qk)  PT.map  { (ψ , e)  k , ψ , e })

Start with the truncated shape data of c: an arity entry, a table, and a payload satisfying the appropriate key condition. The arity hypothesis identifies the recorded arity with a numeral # k. Together with the downward closure obtained above, witnessAt-out then recovers, still under truncation, a formula of arity k whose key has underlying set fst c.

        (witnessAt-out W (suc w) zero (c  γ) qw
           CS , (c∈ , (hcl c , hsh c)) ∣₁
          k (sndS c ar p ec) (ec  cong  a  pr a p) qk)) })
      (arity (fstS (down (lookup E γ) (pr ar F) q∈) ar F refl)
             (sndS (down (lookup E γ) (pr ar F) q∈) ar F refl) q∈) })

The required shape data is precisely the result of applying shape-out to the assumed shape clause and the membership proof for c.

    (SR.shape-out hs c c∈)

Completeness: encoding every formula

Two arithmetic facts about finite indices enter here: converting a natural number below n into a valid index of Fin n, and round-tripping an index through its own numeral.

open import L.Ordinal {} using ( ∈#-elim )
open import Cubical.Data.FinData.Properties using ( fromℕ'; toFromId' )

For completeness, assume a code-domain slot C, an alphabet slot w, and an arity-tower slot E, together with the correct tags. Assume also that every canonical tower entry belongs to E and that the upward closure clause holds. The aim is to prove that the key of every formula over the alphabet belongs to C.

module CodesComplete {m : } (C w E : Fin m) (N : Fin 10  Fin m) (γ : S ^ m) (W : S)
  (qw : fst (lookup w γ)  fst W) (tg : Tags γ N)
  (arity∈ : (n : )   pr (# n) (fst (envSet W n))  fst (lookup E γ) )
  (hc :  γ  closeAt C w E N ) where
  open Alphabet W

Write Cv for the underlying set named by the code-domain slot. Completeness will place every genuine formula key in this one set.

  private
    Cv = fst (lookup C γ)

Every constant of the alphabet belongs to the alphabet slot: the identification of the two carriers is what transports the embedding's memberships into the environment.

    ι∈w : (q : Ab)   ι q  fst (lookup w γ) 
    ι∈w q = subst  u   ι q  u ) (sym qw) (ι∈ q)

An alphabet entry is represented internally by an element of the slot w. The operation down packages its ambient representative together with the membership proof established above, producing the corresponding element ιS q : S.

    ιS : Ab  S
    ιS q = down (lookup w γ) (ι q) (ι∈w q)

The canonical tower entry at arity n, the pair of the numeral n with the environment set of length n, is lowered likewise, so the closure clauses can be quoted at it.

    qS :   S
    qS n = down (lookup E γ) (pr (# n) (fst (envSet W n))) (arity∈ n)

The four-slot context assembles the lowered tower entry, the numeral, their pairing container, and the lowered entry again, matching the frame the closure clauses expect.

    δ4 :   S ^ (4 + m)
    δ4 n = envSet W n  nn n  container (qS n) (nn n) (envSet W n) refl .fst  qS n  γ

The full closure clause is satisfied at that context, because the hypothesis says the closure clause holds at every canonical tower entry.

    frame : (n : )   δ4 n  Close.all C w N 
    frame n = useBoth i0 (qS n  γ) (nn n) (envSet W n) refl (Close.all C w N) (hc (qS n) (arity∈ n))

The closure reader is reopened at each numeral's own context, so every arity gets its own copy of the eighteen clauses.

    module CR (n : ) = CloseRead C w N (δ4 n) tg

Every variable index below n names a numeral below the numeral of n: the monotonicity of the von Neumann numerals is what lets a variable's index be recognized as a member of its arity's numeral.

    var∈ : (n : ) (i : Fin n)   # (toℕ i)  # n 
    var∈ n i = #mono (toℕ i) n (toℕ<n i)

The structural induction begins with the four possible membership atoms. In each case, the atomic closure clause is instantiated at the fixed arity n. Its two term entries come independently from an alphabet constant or an arity variable, and the preceding lemmas provide the corresponding membership proofs.

  key-in :  {n} (ψ : Formula Ab n)   fst (keyS W ψ)  Cv 
  key-in {n} (con x ∈̇ con y) = CR.atomClose-out n f0 f0 f0 (sh 4 w) (sh 5 w) (frame n .fst) (ιS x) (ιS y) (ι∈w x) (ι∈w y)
  key-in {n} (con x ∈̇ var j) = CR.atomClose-out n f0 f0 f1 (sh 4 w) i2 (frame n .snd .fst) (ιS x) (nn (toℕ j)) (ι∈w x) (var∈ n j)
  key-in {n} (var i ∈̇ con y) = CR.atomClose-out n f0 f1 f0 i1 (sh 5 w) (frame n .snd .snd .fst) (nn (toℕ i)) (ιS y) (var∈ n i) (ι∈w y)
  key-in {n} (var i ∈̇ var j) = CR.atomClose-out n f0 f1 f1 i1 i2 (frame n .snd .snd .snd .fst) (nn (toℕ i)) (nn (toℕ j)) (var∈ n i) (var∈ n j)

The four equality atoms follow the same argument with the equality tag. For conjunction, the induction hypotheses first place both subformula keys in C; the binary closure clause then places the paired conjunction key in C as well.

  key-in {n} (con x  con y) = CR.atomClose-out n f1 f0 f0 (sh 4 w) (sh 5 w) (frame n .snd .snd .snd .snd .fst) (ιS x) (ιS y) (ι∈w x) (ι∈w y)
  key-in {n} (con x  var j) = CR.atomClose-out n f1 f0 f1 (sh 4 w) i2 (frame n .snd .snd .snd .snd .snd .fst) (ιS x) (nn (toℕ j)) (ι∈w x) (var∈ n j)
  key-in {n} (var i  con y) = CR.atomClose-out n f1 f1 f0 i1 (sh 5 w) (frame n .snd .snd .snd .snd .snd .snd .fst) (nn (toℕ i)) (ιS y) (var∈ n i) (ι∈w y)
  key-in {n} (var i  var j) = CR.atomClose-out n f1 f1 f1 i1 i2 (frame n .snd .snd .snd .snd .snd .snd .snd .fst) (nn (toℕ i)) (nn (toℕ j)) (var∈ n i) (var∈ n j)
  key-in {n} (a ∧̇ b) = CR.binClose-out n f2 (frame n .snd .snd .snd .snd .snd .snd .snd .snd .fst) (keyS W a) (keyS W b) (codeS W a) (codeS W b) (key-in a) (key-in b) refl refl

Disjunction and implication use the same binary step at their respective tags, while falsity enters through the constant closure clause with payload zero. For either unbounded quantifier, the induction hypothesis concerns its body at arity suc n; the quantifier closure clause turns that body key into a key at arity n.

  key-in {n} (a ∨̇ b) = CR.binClose-out n f3 (frame n .snd .snd .snd .snd .snd .snd .snd .snd .snd .fst) (keyS W a) (keyS W b) (codeS W a) (codeS W b) (key-in a) (key-in b) refl refl
  key-in {n} (a ⇒̇ b) = CR.binClose-out n f4 (frame n .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .fst) (keyS W a) (keyS W b) (codeS W a) (codeS W b) (key-in a) (key-in b) refl refl
  key-in {n} ⊥̇ = CR.conClose-out n f5 (frame n .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .fst)
  key-in {n} (∃̇ a) = CR.quClose-out n f6 (frame n .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .fst) (keyS W a) (nn (suc n)) (codeS W a) (key-in a) refl refl
  key-in {n} (∀̇ a) = CR.quClose-out n f7 (frame n .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .fst) (keyS W a) (nn (suc n)) (codeS W a) (key-in a) refl refl

The bounded universal has two closure arguments: the sub-key at the successor arity and the legal bounding term at the current arity. When the bound is a constant, the term entry comes from the alphabet embedding; when it is a variable, from the numeral membership.

  key-in {n} (∀̇∈ (con x) a) =
    CR.bqClose-out n f8 f0 (sh 8 w) (frame n .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .fst) (keyS W a) (nn (suc n)) (codeS W a) (key-in a) refl refl (ιS x) (ι∈w x)
  key-in {n} (∀̇∈ (var i) a) =
    CR.bqClose-out n f8 f1 i5 (frame n .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .fst) (keyS W a) (nn (suc n)) (codeS W a) (key-in a) refl refl (nn (toℕ i)) (var∈ n i)
  key-in {n} (∃̇∈ (con x) a) =

The bounded existential repeats the same two arguments at its own tag, completing the structural induction: every formula of every arity has its key in the closed domain.

    CR.bqClose-out n f9 f0 (sh 8 w) (frame n .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .fst) (keyS W a) (nn (suc n)) (codeS W a) (key-in a) refl refl (ιS x) (ι∈w x)
  key-in {n} (∃̇∈ (var i) a) =
    CR.bqClose-out n f9 f1 i5 (frame n .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd .snd ) (keyS W a) (nn (suc n)) (codeS W a) (key-in a) refl refl (nn (toℕ i)) (var∈ n i)

The canonical closed code domain

It remains to show that the canonical domain really satisfies the description. Take the code slot to denote AllCodes W and the arity slot to denote the environment tower over W; the equations qC and qE record these two identifications.

module CodesHolds {m : } (C w E : Fin m) (N : Fin 10  Fin m) (γ : S ^ m) (W : S)
  (qw : fst (lookup w γ)  fst W) (qC : fst (lookup C γ)  fst (AllCodes W))
  (qE : fst (lookup E γ)  fst (Tower.tower W)) (tg : Tags γ N) where
  open Alphabet W
  private

Write Cv, Wv, and Ev for the underlying sets named by the code-domain, alphabet, and arity-tower slots. These names keep the three roles separate: formula keys are tested for membership in Cv, constant representatives in Wv, and canonical arity entries in Ev.

    Cv = fst (lookup C γ)
    Wv = fst (lookup w γ)
    Ev = fst (lookup E γ)
    open CodesSem Wv Cv

Suppose a set Wv′ contains the representative of every alphabet entry. Then every term has a legal code over Wv′. A constant uses the supplied membership proof for its representative; a variable uses the fact that the numeral of its index belongs to the numeral of the arity. The result is propositionally truncated because term legality is used only as a property of the code.

    tmV :  {n} (Wv′ : V )  ((q : Ab)   ι q  Wv′ )  (t : Term Ab n)  IsTmV Wv′ (ct t) (# n)
    tmV Wv′ into (con q) =  inl (ι q , (refl , into q)) ∣₁
    tmV {n} Wv′ into (var i) =  inr (# (toℕ i) , (refl , #mono (toℕ i) n (toℕ<n i))) ∣₁

The constants of the alphabet belong to the environment's alphabet slot, transported through the equality of the two carriers.

    ι∈w : (q : Ab)   ι q  Wv 
    ι∈w q = subst  u   ι q  u ) (sym qw) (ι∈ q)

By definition of AllCodes W, the key of every formula over the alphabet belongs to it. Transporting this membership along qC places the same key in the set Cv named by the code slot.

    mem :  {n} (ψ : Formula Ab n)   fst (keyS W ψ)  Cv 
    mem ψ = subst  u   fst (keyS W ψ)  u ) (sym qC) (key∈AllCodes W ψ)

Likewise, the tower contains the canonical entry pairing the numeral # n with the environment set envSet W n. Transport along qE shows that this entry belongs to the arity set Ev.

    entry∈ : (n : )   pr (# n) (fst (envSet W n))  Ev 
    entry∈ n = subst  u   pr (# n) (fst (envSet W n))  u ) (sym qE) (Tower.tower-in′ W n)

The term reader is the alphabet instance of the general term legality just proved.

    tm :  {n} (t : Term Ab n)  IsTmV Wv (ct t) (# n)
    tm = tmV Wv ι∈w

Every formula determines a legitimate key at its own arity. The proof proceeds by structural recursion: atomic formulas combine the legal codes of their two terms, while conjunction and disjunction combine the already established memberships of their two subformula keys.

    keyOf :  {n} (ψ : Formula Ab n)  Key (# n) (cd ψ)
    keyOf (t ∈̇ u) =  f0 , pr (ct t) (ct u) , (refl ,  ct t , ct u , (refl , (tm t , tm u)) ∣₁) ∣₁
    keyOf (t  u) =  f1 , pr (ct t) (ct u) , (refl ,  ct t , ct u , (refl , (tm t , tm u)) ∣₁) ∣₁
    keyOf (a ∧̇ b) =  f2 , pr (cd a) (cd b) , (refl ,  cd a , cd b , (refl , (mem a , mem b)) ∣₁) ∣₁
    keyOf (a ∨̇ b) =  f3 , pr (cd a) (cd b) , (refl ,  cd a , cd b , (refl , (mem a , mem b)) ∣₁) ∣₁

Implication repeats the pairing; falsity carries the zero payload with its definitional equation; the two unbounded quantifiers wrap the subformula key without any term requirement.

    keyOf (a ⇒̇ b) =  f4 , pr (cd a) (cd b) , (refl ,  cd a , cd b , (refl , (mem a , mem b)) ∣₁) ∣₁
    keyOf ⊥̇ =  f5 , # 0 , (refl , refl) ∣₁
    keyOf (∃̇ a) =  f6 , cd a , (refl , mem a) ∣₁
    keyOf (∀̇ a) =  f7 , cd a , (refl , mem a) ∣₁
    keyOf (∀̇∈ t a) =  f8 , pr (ct t) (cd a) , (refl ,  ct t , cd a , (refl , (tm t , mem a)) ∣₁) ∣₁

The bounded quantifiers pair the bounding term with the subformula key, completing the recursion: keyOf ψ is a legitimate key for every formula ψ, at ψ's own arity.

    keyOf (∃̇∈ t a) =  f9 , pr (ct t) (cd a) , (refl ,  ct t , cd a , (refl , (tm t , mem a)) ∣₁) ∣₁

The shape clause of the canonical instance follows: every member of AllCodes W decodes to a formula, whose arity-table pair belongs to the tower and whose payload is a legitimate key. The shape reader is fed this member by member.

    shape :  γ  shapeAt C w E N 
    shape = ShapeRead.shape-in C w E N γ tg  c c∈  PT.map
       { (n , ψ , e)  # n , fst (envSet W n) , cd ψ , (entry∈ n , (e , keyOf ψ)) })
      (AllCodes-out W c (subst  u   fst c  u ) qC c∈)))

The decoding helper fixes the arity explicitly. If a code-domain member c has underlying set pr (# n) z, then, under propositional truncation, there is a formula ψ of arity exactly n such that z ≡ cd ψ. The conclusion recovers the payload formula only after the outer numeral has fixed its arity.

    decodeAt : (c : S)   fst c  Cv   (n : ) (z : V )  fst c  pr (# n) z
               Σ[ ψ  Formula Ab n ] (z  cd ψ) ∥₁
    decodeAt c c∈ n z e = PT.map
       { (n₁ , ψ₁ , e₁) 
        let q = pr-inj (sym e₁  e)

The proof reads the member outward and aligns the two arities by the injectivity of the pair and of the numeral, transporting the formula along the arity equation. The equation of the coding is then reversed to identify the payload.

            nq = #-inj′ (q .fst)
        in subst (Formula Ab) nq ψ₁ , (sym (q .snd)  sym (cd-subst nq ψ₁)) })
      (AllCodes-out W c (subst  u   fst c  u ) qC c∈))

The term-decoding statement is parameterized by a bound set: every member of the bound decodes, up to truncation, to a term whose coding pairs the tag numeral with the member itself.

    TmDec :  {n}  Fin 10  V   Type (ℓ-suc )
    TmDec {n} Nx bound = (x : V )   x  bound    Σ[ t  Term Ab n ] (ct t  pr (# (toℕ Nx)) x) ∥₁

Constants decode through the fiber of the alphabet embedding: a member of the alphabet slot is the embedded image of some alphabet entry, and that entry is the constant wanted.

    conDec :  {n}  TmDec {n} f0 Wv
    conDec x x∈ =  con (fib .fst) , cong (pr (# 0)) (fib .snd) ∣₁
      where
      fib : Σ[ q  Ab ] (ι q  x)
      fib = ∈-asFiber {a = x} {b = fst W} (subst  u   x  u ) qw x∈)

Variables decode through the numeral elimination: a member of the arity numeral is a natural number below n, which converts back into a valid index, and the coding equation is transported along the round trip.

    varDec : (n : ) (A : V )  A  # n  TmDec {n} f1 A
    varDec n A qa x x∈ = PT.map
       { (j , (p , ex))  var (fromℕ' n j p) , cong (pr (# 1)) (cong #_ (toFromId' n j p)  sym ex) })
      (∈#-elim n x (subst  u   x  u ) qa x∈))

Fix one entry q of the environment tower and an equation identifying its recorded arity with # n. The local context δ4 supplies the four values expected by the closure formulas: the arity table, the numeral arity, a container relating the entry to that table, and the entry itself.

    module At (q : S) (q∈ :  fst q  Ev ) (ar F s : S) (n : ) (qa : fst ar  # n) where
      private
        δ4 : S ^ (4 + m)
        δ4 = F  ar  s  q  γ
        A = fst ar

Within this fixed context, CloseRead turns satisfaction of each closure formula into its corresponding mathematical closure property, while Close supplies the formulas themselves.

        module CR = CloseRead C w N δ4 tg
        module Cl = Close C w N

The helper in-key transports canonical membership along an equality. If x is equal to the underlying set of the key of a formula ψ, then the known membership of that canonical key in Cv yields x ∈ Cv.

        in-key :  {k} (ψ : Formula Ab k) (x : V )  x  fst (keyS W ψ)   x  Cv 
        in-key ψ x e = subst  u   u  Cv ) (sym e) (mem ψ)

For a tag Nx and an element x, TmAt Nx x is the Σ type of a term t together with an equation saying that t is coded by the pair of the numeral for Nx and x. Unlike the preceding decoding statements, this local type is not propositionally truncated.

        TmAt : (Nx : Fin 10) (x : V )  Type (ℓ-suc )
        TmAt Nx x = Σ[ t  Term Ab n ] (ct t  pr (# (toℕ Nx)) x)

Similarly, FoAt k z is the Σ type of a formula ψ of arity k together with an equation z ≡ cd ψ. It retains both the formula and its coding equation as usable data.

        FoAt : (k : ) (z : V )  Type (ℓ-suc )
        FoAt k z = Σ[ ψ  Formula Ab k ] (z  cd ψ)

The atomic closure clause is proved from the two term decodings. Given a decoding of the first coordinate's member and a decoding of the second coordinate's member, the atomic key is built from the two terms by the object-language constructor, and the coding equation identifies it with the named key.

        atomIn : (k Nx Ny : Fin 10) (X : Fin (4 + m)) (Y : Fin (5 + m))
                (op : Term Ab n  Term Ab n  Formula Ab n)
                ((t u : Term Ab n)  cd (op t u)  pr (# (toℕ k)) (pr (ct t) (ct u)))
                TmDec Nx (fst (lookup X δ4))  ((x : S)  TmDec Ny (fst (lookup Y (x  δ4))))
                 δ4  Cl.atomClose k Nx Ny X Y 

Decode the two coordinates separately. The first yields a term t and its coding equation; after that coordinate has been added to the context, the second yields a term u and its coding equation.

        atomIn k Nx Ny X Y op code dx dy = CR.atomClose-in k Nx Ny X Y  x y x∈ y∈ 
          let d1 :  TmAt Nx (fst x) ∥₁
              d1 = dx (fst x) x∈
              d2 :  TmAt Ny (fst y) ∥₁
              d2 = dy x (fst y) y∈

The set G is the candidate atomic key formed from the arity, the atomic tag, and the two coded coordinates. Because membership in Cv is a proposition, both truncated term decodings may be eliminated into this goal. Their coding equations identify G with the key of op t u, whose membership follows from in-key.

              G : V 
              G = pr A (pr (# (toℕ k)) (pr (pr (# (toℕ Nx)) (fst x)) (pr (# (toℕ Ny)) (fst y))))
          in PT.rec (snd (G  Cv))
             { (t , et)  PT.rec (snd (G  Cv))
               { (u , eu)  in-key (op t u) G

The final equality is assembled in three layers: qa aligns the outer arity, the two term-code equations align the paired payload, and the defining equation for op aligns the atomic tag. Transporting canonical membership along this equality completes the atomic closure proof.

                (cong₂ pr qa (cong (pr (# (toℕ k))) (cong₂ pr (sym et) (sym eu))  sym (code t u))) })
              d2 })
            d1)

For a binary connective, both immediate subformulas have the same arity n as the compound. The hypotheses present their keys with first component # n; after aligning that component with the recorded arity, decodeAt recovers each payload as the code of a formula of arity n.

        binIn : (k : Fin 10) (op : Formula Ab n  Formula Ab n  Formula Ab n)
               ((a b : Formula Ab n)  cd (op a b)  pr (# (toℕ k)) (pr (cd a) (cd b)))
                δ4  Cl.binClose k 
        binIn k op code = CR.binClose-in k  c₁ c₂ a b c₁∈ c₂∈ e₁ e₂ 
          let d1 :  FoAt n (fst a) ∥₁

The two applications of decodeAt yield, merely, formulas ψ₁ and ψ₂ whose codes are the two payload components. The set G is the composite key already assembled from the recorded arity, the chosen connective tag, and those components.

              d1 = decodeAt c₁ c₁∈ n (fst a) (e₁  cong  v  pr v (fst a)) qa)
              d2 :  FoAt n (fst b) ∥₁
              d2 = decodeAt c₂ c₂∈ n (fst b) (e₂  cong  v  pr v (fst b)) qa)
              G : V 
              G = pr A (pr (# (toℕ k)) (pr (fst a) (fst b)))

Eliminating the two truncated witnesses reduces the goal to genuine formulas ψ₁ and ψ₂. Their code equations identify G with the key of op ψ₁ ψ₂, so the canonical membership proof in-key establishes the required binary closure clause.

          in PT.rec (snd (G  Cv))
             { (ψ₁ , ea)  PT.rec (snd (G  Cv))
               { (ψ₂ , eb)  in-key (op ψ₁ ψ₂) G
                (cong₂ pr qa (cong (pr (# (toℕ k))) (cong₂ pr ea eb)  sym (code ψ₁ ψ₂))) })
              d2 })

The outer elimination supplies the first recovered formula and completes the proof that the domain is closed under the chosen binary connective.

            d1)

Falsity has no subformula: its payload is simply the numeral zero. Once the recorded arity and the chosen tag are aligned with the canonical code of c₀, in-key places the resulting key in the domain.

        conIn : (k : Fin 10) (c₀ : Formula Ab n)  cd c₀  pr (# (toℕ k)) (# 0)   δ4  Cl.conClose k 
        conIn k c₀ code = CR.conClose-in k (in-key c₀ (pr A (pr (# (toℕ k)) (# 0))) (cong₂ pr qa (sym code)))

Binding one variable changes the arity of the body from n to suc n. The quantifier closure hypothesis therefore presents its immediate subkey at the successor arity, and decodeAt recovers a formula body of precisely that arity.

        quIn : (k : Fin 10) (op : Formula Ab (suc n)  Formula Ab n)
              ((a : Formula Ab (suc n))  cd (op a)  pr (# (toℕ k)) (cd a))
               δ4  Cl.quClose k 
        quIn k op code = CR.quClose-in k  c₁ ar' a c₁∈ e₁ es 
          let d1 :  FoAt (suc n) (fst a) ∥₁

Let G be the key assembled from the outer arity, the quantifier tag, and the encoded body. After the truncated body has been recovered as ψ₁, its code equation identifies G with the key of op ψ₁; canonical membership then proves the quantifier closure clause.

              d1 = decodeAt c₁ c₁∈ (suc n) (fst a) (e₁  cong  v  pr v (fst a)) (es  cong sucV qa))
              G : V 
              G = pr A (pr (# (toℕ k)) (fst a))
          in PT.rec (snd (G  Cv))
             { (ψ₁ , ea)  in-key (op ψ₁) G (cong₂ pr qa (cong (pr (# (toℕ k))) ea  sym (code ψ₁))) })

Eliminating the recovered body completes the proof that the domain is closed under the chosen unbounded quantifier.

            d1)

A bounded quantifier carries both a body of arity suc n and a bounding term of arity n. Accordingly, bqIn receives a term-decoding hypothesis for the environment component in which the bound is stored, in addition to the decoder already available for the body key.

        bqIn : (k Nx : Fin 10) (X : Fin (8 + m))
              (op : Term Ab n  Formula Ab (suc n)  Formula Ab n)
              ((t : Term Ab n) (a : Formula Ab (suc n))  cd (op t a)  pr (# (toℕ k)) (pr (ct t) (cd a)))
              ((ar' a s' c₁ : S)  TmDec Nx (fst (lookup X (a  ar'  s'  c₁  δ4))))
               δ4  Cl.bqClose k Nx X 

The term-decoding hypothesis recovers the bound from its membership proof, while decodeAt recovers the body from the successor-arity subkey. Both results are propositionally truncated, since the closure goal requires only membership of the completed key rather than chosen decoders.

        bqIn k Nx X op code dx = CR.bqClose-in k Nx X  c₁ ar' a s' c₁∈ e₁ es x x∈ 
          let d1 :  TmAt Nx (fst x) ∥₁
              d1 = dx ar' a s' c₁ (fst x) x∈
              d2 :  FoAt (suc n) (fst a) ∥₁
              d2 = decodeAt c₁ c₁∈ (suc n) (fst a) (e₁  cong  v  pr v (fst a)) (es  cong sucV qa))

The key G now has a nested payload: first the code of the bounding term, then the code of the body. The first truncation elimination exposes a genuine term t; the second will expose the formula to which the body code belongs.

              G : V 
              G = pr A (pr (# (toℕ k)) (pr (pr (# (toℕ Nx)) (fst x)) (fst a)))
          in PT.rec (snd (G  Cv))
             { (t , et)  PT.rec (snd (G  Cv))
               { (ψ₁ , ea)  in-key (op t ψ₁) G

With the recovered term t and body ψ₁, their code equations identify G with the key of op t ψ₁. The canonical membership proof then supplies the bounded-quantifier clause, and the two truncation eliminations close in the reverse order in which their witnesses were introduced.

                (cong₂ pr qa (cong (pr (# (toℕ k))) (cong₂ pr (sym et) ea)  sym (code t ψ₁))) })
              d2 })
            d1)

The single formula Cl.all packages eighteen closure clauses. Its first eight clauses concern the two atomic relations: for each relation, the left and right terms may independently be constants or variables. Constants are decoded through membership in w, while variables are decoded through membership of their indices in the arity numeral.

      all :  δ4  Cl.all 
      all =
          atomIn f0 f0 f0 (sh 4 w) (sh 5 w) _∈̇_  _ _  refl) conDec  _  conDec)
        , ( atomIn f0 f0 f1 (sh 4 w) i2 _∈̇_  _ _  refl) conDec  _  varDec n A qa)
        , ( atomIn f0 f1 f0 i1 (sh 5 w) _∈̇_  _ _  refl) (varDec n A qa)  _  conDec)

Four clauses cover the constant-variable combinations for membership, and four parallel clauses cover them for equality. This accounts for all eight atomic closure clauses; the remaining ten concern logical connectives and quantifiers.

        , ( atomIn f0 f1 f1 i1 i2 _∈̇_  _ _  refl) (varDec n A qa)  _  varDec n A qa)
        , ( atomIn f1 f0 f0 (sh 4 w) (sh 5 w) _≐_  _ _  refl) conDec  _  conDec)
        , ( atomIn f1 f0 f1 (sh 4 w) i2 _≐_  _ _  refl) conDec  _  varDec n A qa)
        , ( atomIn f1 f1 f0 i1 (sh 5 w) _≐_  _ _  refl) (varDec n A qa)  _  conDec)
        , ( atomIn f1 f1 f1 i1 i2 _≐_  _ _  refl) (varDec n A qa)  _  varDec n A qa)

The next six clauses cover conjunction, disjunction, implication, falsity, and the two unbounded quantifiers. Each constructor is paired with its canonical tag and its definitional coding equation, so the corresponding helper can insert the constructed key directly.

        , ( binIn f2 _∧̇_  _ _  refl)
        , ( binIn f3 _∨̇_  _ _  refl)
        , ( binIn f4 _⇒̇_  _ _  refl)
        , ( conIn f5 ⊥̇ refl
        , ( quIn f6 ∃̇_  _  refl)

The last four clauses treat bounded universal and existential quantification. Each appears once with a constant bound and once with a variable bound; conDec and varDec verify that these are legal terms at the outer arity. The nested tuple now supplies every component of Cl.all.

        , ( quIn f7 ∀̇_  _  refl)
        , ( bqIn f8 f0 (sh 8 w) ∀̇∈  _ _  refl)  _ _ _ _  conDec)
        , ( bqIn f8 f1 i5 ∀̇∈  _ _  refl)  _ _ _ _  varDec n A qa)
        , ( bqIn f9 f0 (sh 8 w) ∃̇∈  _ _  refl)  _ _ _ _  conDec)
        ,   bqIn f9 f1 i5 ∃̇∈  _ _  refl)  _ _ _ _  varDec n A qa) ))))))))))))))))

It remains to establish the closure clauses at every entry q of the environment tower. The tower theorem expresses q, under propositional truncation, as the canonical entry (# n, envSet W n) for some n. Its first-component equation identifies the recorded arity with # n, so the eighteen clauses assembled in At.all apply at that entry.

    close :  γ  closeAt C w E N 
    close q q∈ = bothAll-in i0 (Close.all C w N) (q  γ)  ar F s s∈ ar∈ F∈ e 
      PT.rec (snd ((F  ar  s  q  γ)  Close.all C w N))
         { (n , qp)  At.all q q∈ ar F s n (pr-inj (sym e  qp) .fst) })
        (Tower.tower-out W q (subst  u   fst q  u ) qE q∈)))

The canonical domain AllCodes W now satisfies both halves of codesAt: shape shows that each of its members has a recorded arity and one of the ten permitted payload shapes, while close shows that every key assembled from legal immediate constituents belongs to the domain. This is the adequacy of the code domain itself: its syntactic description contains exactly the genuine formula keys.

  holds :  γ  codesAt C w E N 
  holds = shape , close

Recap

The two directions now coincide on the canonical domain. Soundness decodes each member of AllCodes W into a formula key at its recorded arity, while completeness places every genuine formula key back in that domain; CodesHolds verifies that the internal shape and closure description supports both conclusions.