Documentation

Linglib.Syntax.Case.Dependent

Dependent Case Theory #

[Mar91] [Bak15]

The dependent case algorithm: case is determined by the structural configuration of NPs within a Spell-Out domain, applied via a disjunctive priority hierarchy:

  1. Lexical case: assigned by a particular head (P, V) — highest priority
  2. Dependent case: assigned to an NP that stands in a c-command relation with another caseless NP in the same domain
    • Accusative languages: lower NP gets ACC
    • Ergative languages: higher NP gets ERG
    • Tripartite languages: higher NP gets ERG and lower gets ACC
  3. Unmarked case: default for any NP still without case
    • Accusative languages: NOM
    • Ergative languages: ABS
    • Tripartite languages: ABS

This file is the theory — the language-typology enum, the configural rules, and the case-assignment algorithm. Empirical applications, cross-linguistic validation, and competing analyses live in Studies/.

Where to Find What #

Companion Infrastructure #

The source of case assignment, ordered by priority. Lexical case (assigned by P, V) takes priority over dependent case, which takes priority over unmarked (default) case.

Instances For
    @[implicit_reducible]
    Equations
    Equations
    • One or more equations did not get rendered due to their size.
    Instances For

      The neutral provenance (Case.Source) of a dependent-case source: configural and Agree-valued cases are structural, lexical is inherent, unmarked is default. Dependent case is total, so it never maps to uncased (CaseSource.toNeutral_ne_uncased).

      Equations
      Instances For

        Marantz dependent case is total: no source it produces is the crash (uncased). The provenance-level contrast with Kalin hybrid licensing, which can crash (Licensing.LicensingOutcome.toNeutral_uncased_iff).

        Language type determines which dependent and unmarked cases are used.

        • Accusative: dependent = ACC (on lower NP), unmarked = NOM
        • Ergative: dependent = ERG (on higher NP), unmarked = ABS
        • Tripartite: dependent = ERG (on higher) + ACC (on lower), unmarked = ABS ([Sco23]: SJA Mam; cf. Nez Perce)
        Instances For
          @[implicit_reducible]
          Equations
          Equations
          • One or more equations did not get rendered due to their size.
          Instances For

            An NP within a Spell-Out domain, before case assignment. List position encodes structural height: earlier = higher = c-commands later.

            If a P head (e.g., Japanese kara) assigns lexical case to the NP, lexicalCase is some c; otherwise it is none.

            • label : String

              Label identifying this NP

            • lexicalCase : Option Case

              Lexical case pre-assigned by a P or V head (e.g., ABL from kara)

            Instances For
              def Syntax.Case.instDecidableEqNPInDomain.decEq (x✝ x✝¹ : NPInDomain) :
              Decidable (x✝ = x✝¹)
              Equations
              • One or more equations did not get rendered due to their size.
              Instances For
                Equations
                • One or more equations did not get rendered due to their size.
                Instances For

                  Result of case assignment: an NP with its case value and source.

                  Instances For
                    def Syntax.Case.instDecidableEqCasedNP.decEq (x✝ x✝¹ : CasedNP) :
                    Decidable (x✝ = x✝¹)
                    Equations
                    • One or more equations did not get rendered due to their size.
                    Instances For
                      def Syntax.Case.instReprCasedNP.repr :
                      CasedNPStd.Format
                      Equations
                      • One or more equations did not get rendered due to their size.
                      Instances For
                        @[implicit_reducible]
                        Equations
                        @[implicit_reducible]

                        A cased NP bears its assigned case.

                        Equations
                        def Syntax.Case.getCaseOf (label : String) (results : List CasedNP) :
                        Option Case

                        Look up the assigned case for an NP by label.

                        Equations
                        Instances For
                          def Syntax.Case.getSourceOf (label : String) (results : List CasedNP) :
                          Option CaseSource

                          Look up the case source for an NP by label.

                          Equations
                          Instances For
                            def Syntax.Case.anyLacksCaseIn (nps : List NPInDomain) :
                            Bool

                            Does any NP in the list lack lexical case? Used to check whether a dependent case competitor exists.

                            Equations
                            Instances For
                              def Syntax.Case.dependentAccusative (higherNPs : List NPInDomain) (np : NPInDomain) :
                              Option Case

                              Dependent accusative: assigned to an NP that is c-commanded by another caseless NP in the same domain.

                              In our list representation, NP at index i is c-commanded by all NPs at index j < i. So NP_i gets ACC if it has no lexical case and some NP before it also has no lexical case.

                              Equations
                              Instances For
                                def Syntax.Case.dependentErgative (np : NPInDomain) (lowerNPs : List NPInDomain) :
                                Option Case

                                Dependent ergative: assigned to an NP that c-commands another caseless NP. NP_i gets ERG if it has no lexical case and some NP after it also has no lexical case.

                                Equations
                                Instances For

                                  Unmarked (default) case for a given language type.

                                  • Accusative languages: NOM
                                  • Ergative languages: ABS
                                  • Tripartite languages: ABS (only intransitive S gets unmarked case)
                                  Equations
                                  Instances For
                                    def Syntax.Case.assignOneCase (lang : CaseLanguageType) (higherNPs lowerNPs : List NPInDomain) (np : NPInDomain) :

                                    Assign case to a single NP given the NPs structurally above and below it. Applies the three-step priority: lexical → dependent → unmarked.

                                    Equations
                                    • One or more equations did not get rendered due to their size.
                                    Instances For
                                      def Syntax.Case.assignCasesAux (lang : CaseLanguageType) (higher remaining : List NPInDomain) :
                                      List CasedNP

                                      Assign case to all NPs in a Spell-Out domain. Processes the list left-to-right, maintaining context of higher NPs and remaining lower NPs for each position.

                                      Equations
                                      Instances For

                                        Top-level case assignment for a list of NPs in a Spell-Out domain. List order encodes structural height: first = highest = c-commands all others.

                                        Equations
                                        Instances For

                                          ACC Variant #

                                          "Taro-ga mura-o hanare-ta" (Taro-NOM village-ACC leave-PAST)

                                          Two bare NPs in the TP Spell-Out domain:

                                          Equations
                                          Instances For

                                            ABL Variant #

                                            "Taro-ga mura-kara hanare-ta" (Taro-NOM village-from leave-PAST)

                                            One bare NP + one PP (lexical ABL from kara):

                                            Equations
                                            Instances For
                                              theorem Syntax.Case.lexical_bleeds_dependent (lang : CaseLanguageType) (c : Case) (higherNPs lowerNPs : List NPInDomain) :
                                              (assignOneCase lang higherNPs lowerNPs { label := "x", lexicalCase := some c }).source = CaseSource.lexical

                                              Lexical case bleeds dependent case: an NP with lexical case is never assigned dependent case, regardless of structural configuration.

                                              ACC variant: source (lower NP) gets dependent accusative.

                                              ACC variant: source case is dependent (not lexical or unmarked).

                                              ACC variant: leaver (higher NP) gets unmarked nominative.

                                              ACC variant: leaver case is unmarked.

                                              ABL variant: source gets lexical ablative (from kara).

                                              ABL variant: source case is lexical (from P head kara).

                                              ABL variant: leaver gets unmarked nominative.

                                              theorem Syntax.Case.no_voice_needed_for_acc :
                                              have nps := [{ label := "subj", lexicalCase := none }, { label := "obj", lexicalCase := none }]; getCaseOf "obj" (assignCases CaseLanguageType.accusative nps) = some Case.acc getSourceOf "obj" (assignCases CaseLanguageType.accusative nps) = some CaseSource.dependent

                                              Dependent ACC does not require agentive Voice — it only requires two caseless NPs in the same Spell-Out domain. The Voice head's flavor is irrelevant to the case algorithm.

                                              All NPs receive case in the ACC variant.

                                              All NPs receive case in the ABL variant.

                                              Tripartite: Theory-Level Properties #

                                              In a tripartite system, both dependent ergative and dependent accusative are active simultaneously: the higher NP gets ERG, the lower gets ACC, and an NP with no case competitor gets unmarked ABS. These are properties of the algorithm, not of any particular language. Language-specific derivations live in Studies files (e.g., SJA Mam in Studies/Scott2023).

                                              theorem Syntax.Case.tripartite_higher_gets_erg :
                                              have nps := [{ label := "higher", lexicalCase := none }, { label := "lower", lexicalCase := none }]; getCaseOf "higher" (assignCases CaseLanguageType.tripartite nps) = some Case.erg

                                              Tripartite transitive: higher NP gets dependent ERG.

                                              theorem Syntax.Case.tripartite_lower_gets_acc :
                                              have nps := [{ label := "higher", lexicalCase := none }, { label := "lower", lexicalCase := none }]; getCaseOf "lower" (assignCases CaseLanguageType.tripartite nps) = some Case.acc

                                              Tripartite transitive: lower NP gets dependent ACC.

                                              theorem Syntax.Case.tripartite_sole_gets_abs :
                                              have nps := [{ label := "sole", lexicalCase := none }]; getCaseOf "sole" (assignCases CaseLanguageType.tripartite nps) = some Case.abs

                                              Tripartite intransitive: sole NP gets unmarked ABS.

                                              theorem Syntax.Case.tripartite_three_distinct :
                                              have tr := assignCases CaseLanguageType.tripartite [{ label := "higher", lexicalCase := none }, { label := "lower", lexicalCase := none }]; have intr := assignCases CaseLanguageType.tripartite [{ label := "sole", lexicalCase := none }]; getCaseOf "higher" tr getCaseOf "lower" tr getCaseOf "higher" tr getCaseOf "sole" intr getCaseOf "lower" tr getCaseOf "sole" intr

                                              All three cases are distinct — the defining property of tripartite. ERG ≠ ACC ≠ ABS, derived purely from the algorithm.

                                              theorem Syntax.Case.tripartite_subsumes_both :
                                              have nps := [{ label := "higher", lexicalCase := none }, { label := "lower", lexicalCase := none }]; getCaseOf "higher" (assignCases CaseLanguageType.tripartite nps) = getCaseOf "higher" (assignCases CaseLanguageType.ergative nps) getCaseOf "lower" (assignCases CaseLanguageType.tripartite nps) = getCaseOf "lower" (assignCases CaseLanguageType.accusative nps)

                                              Tripartite subsumes both ergative and accusative dependent case: ERG on the higher NP matches pure ergative; ACC on the lower NP matches pure accusative.

                                              ACC and ABL are mutually exclusive on the source: the same structural position receives exactly one of ACC (dependent) or ABL (lexical), never both. This follows from the priority ordering — lexical case preempts dependent case entirely.

                                              The leaver gets NOM in both variants. The alternation affects only the source argument; the subject case is invariant.

                                              theorem Syntax.Case.ergative_mirror :
                                              have nps := [{ label := "higher", lexicalCase := none }, { label := "lower", lexicalCase := none }]; getCaseOf "higher" (assignCases CaseLanguageType.ergative nps) = some Case.erg getCaseOf "lower" (assignCases CaseLanguageType.ergative nps) = some Case.abs

                                              Ergative mirror: in an ergative language with two caseless NPs, the higher NP gets dependent ERG and the lower gets unmarked ABS. This is the typological inverse of the accusative pattern.

                                              theorem Syntax.Case.single_np_nom :
                                              have nps := [{ label := "sole", lexicalCase := none }]; getCaseOf "sole" (assignCases CaseLanguageType.accusative nps) = some Case.nom getSourceOf "sole" (assignCases CaseLanguageType.accusative nps) = some CaseSource.unmarked

                                              A single caseless NP in an accusative language gets NOM — the standard intransitive case. No dependent case arises because there is no case competitor.

                                              Case is purely configural: two NPs with identical labels but different lexical case inputs produce different outputs. The algorithm is sensitive only to the NP inventory, not to verb type or Voice flavor.

                                              The structural (non-lexical) cases that the dependent case algorithm can assign for each language type. These are exactly the cases that appear in the none (no lexical case) branch of assignOneCase.

                                              Equations
                                              Instances For
                                                theorem Syntax.Case.accusative_nonlexical_cases (higherNPs lowerNPs : List NPInDomain) (np : NPInDomain) (h : np.lexicalCase = none) :
                                                have result := assignOneCase CaseLanguageType.accusative higherNPs lowerNPs np; result.case = Case.nom result.case = Case.acc

                                                In an accusative language, any NP without lexical case receives either NOM (unmarked) or ACC (dependent).

                                                theorem Syntax.Case.ergative_nonlexical_cases (higherNPs lowerNPs : List NPInDomain) (np : NPInDomain) (h : np.lexicalCase = none) :
                                                have result := assignOneCase CaseLanguageType.ergative higherNPs lowerNPs np; result.case = Case.abs result.case = Case.erg

                                                In an ergative language, any NP without lexical case receives either ABS (unmarked) or ERG (dependent).

                                                theorem Syntax.Case.tripartite_nonlexical_cases (higherNPs lowerNPs : List NPInDomain) (np : NPInDomain) (h : np.lexicalCase = none) :
                                                have result := assignOneCase CaseLanguageType.tripartite higherNPs lowerNPs np; result.case = Case.abs result.case = Case.erg result.case = Case.acc

                                                In a tripartite language, any NP without lexical case receives ABS (unmarked), ERG (dependent on a lower NP), or ACC (dependent on a higher NP).

                                                How nominative case is assigned in a language. [BV10]: in Sakha (and Mongolian, per [Gon22]), NOM is assigned by finite T via Agree, not as an unmarked default. This distinction matters for Wholesale Late Merger: Agree-based NOM is tied to a specific functional head, while unmarked NOM is a last-resort default.

                                                Instances For
                                                  @[implicit_reducible]
                                                  Equations
                                                  Equations
                                                  • One or more equations did not get rendered due to their size.
                                                  Instances For

                                                    How dative case is assigned. [Gon22]: DAT is nonstructural in Mongolian — it does not participate in dependent case competition and is not available at intermediate scrambling positions for WLM.

                                                    Instances For
                                                      @[implicit_reducible]
                                                      Equations
                                                      Equations
                                                      • One or more equations did not get rendered due to their size.
                                                      Instances For

                                                        How accusative case is assigned. [BV10]: in Sakha (and Mongolian, per [Gon22]), ACC is dependent case (Marantz-style); the standard Chomskyan alternative is that ACC is assigned by v/Voice via Agree (often paired with Burzio's Generalization).

                                                        Instances For
                                                          @[implicit_reducible]
                                                          Equations
                                                          Equations
                                                          • One or more equations did not get rendered due to their size.
                                                          Instances For

                                                            How genitive case is assigned. [BV10]: in Sakha, GEN is assigned by D via Agree to the possessor (parallel to T-Agree NOM at the clausal level). Russian numeric and partitive GEN is nonstructural.

                                                            Instances For
                                                              @[implicit_reducible]
                                                              Equations
                                                              Equations
                                                              • One or more equations did not get rendered due to their size.
                                                              Instances For

                                                                A language-specific case system configuration. Bundles the alignment type with the per-case mechanism choices.

                                                                Each of the four structural cases (NOM, GEN, ACC, DAT) gets an independent mechanism plug-in. Marantz's purely-configurational picture, Chomsky's purely-Agree picture, and B&V's two-modality Sakha grammar all fall out as parameterizations of this single structure:

                                                                Theorynomgenaccdat
                                                                Marantz pureunmarkedDefault(—)dependentdependent
                                                                Chomsky pureagreeTagreeDagreeVnonstructural
                                                                Sakha (B&V)agreeTagreeDdependentdependent
                                                                MongolianagreeTagreeDdependentnonstructural

                                                                accMode and genMode default to the most common values across the library so that existing instances need not specify them.

                                                                Instances For
                                                                  def Syntax.Case.instDecidableEqCaseSystemConfig.decEq (x✝ x✝¹ : CaseSystemConfig) :
                                                                  Decidable (x✝ = x✝¹)
                                                                  Equations
                                                                  • One or more equations did not get rendered due to their size.
                                                                  Instances For
                                                                    Equations
                                                                    • One or more equations did not get rendered due to their size.
                                                                    Instances For

                                                                      Phased case assignment #

                                                                      [BV10] formalize Sakha case as cycling over two phases: VP (the smaller phase) and CP. Two configurational rules apply (paper (4a)/(4b), restated as (85)):

                                                                      (4a) bleeds (4b) on the VP cycle by Elsewhere ordering — its context (one specific phase) is more restrictive than (4b)'s (any phase).

                                                                      After dependent case has applied, Agree (paper (5)/(86)) values remaining unvalued NPs:

                                                                      Each NP carries a basePhase (where it was merged) and a shifted flag (did it move to a higher phase before evaluation). PIC: NPs that stayed inside VP are not visible on the CP cycle.

                                                                      Cycle in the [BV10] two-phase model. Distinct from the more articulated Minimalist.Phase structure in Phase.lean; this is just the binary VP-vs-CP distinction that the case algorithm cycles over.

                                                                      Instances For
                                                                        @[implicit_reducible]
                                                                        Equations
                                                                        def Syntax.Case.instReprCasePhase.repr :
                                                                        CasePhaseStd.Format
                                                                        Equations
                                                                        Instances For

                                                                          An NP equipped with phase information. basePhase records where the NP was merged; shifted marks NPs that have moved to a higher phase before case evaluation. isArgumental flags whether the NP bears a θ-role w.r.t. some case-assigning head — only argumental NPs are case competitors for rules (4a)/(4b). Bare-NP adverbs (e.g., 'yesterday', 'two kilometers') are non-argumental. [BV10] (8)–(9) and footnote 5.

                                                                          inDP flags NPs that participate only in DP-internal case assignment (possessors): these are skipped by every clausal pass and are valued by applyGenAgree when genMode := .agreeD.

                                                                          Instances For
                                                                            def Syntax.Case.instDecidableEqPhasedNP.decEq (x✝ x✝¹ : PhasedNP) :
                                                                            Decidable (x✝ = x✝¹)
                                                                            Equations
                                                                            • One or more equations did not get rendered due to their size.
                                                                            Instances For
                                                                              def Syntax.Case.instReprPhasedNP.repr :
                                                                              PhasedNPStd.Format
                                                                              Equations
                                                                              • One or more equations did not get rendered due to their size.
                                                                              Instances For

                                                                                Visible on the VP cycle: NPs whose basePhase is vp. Even shifted NPs are visible at this point — shift happens at the boundary between cycles.

                                                                                Equations
                                                                                Instances For

                                                                                  Visible on the CP cycle: NPs in cp, plus VP-base NPs that shifted out of VP. Unshifted VP NPs were transferred (PIC).

                                                                                  Equations
                                                                                  Instances For

                                                                                    Mutable state during phased case assignment. case = none means "not yet valued"; lexical case starts with the value pre-set.

                                                                                    Instances For
                                                                                      Equations
                                                                                      • One or more equations did not get rendered due to their size.
                                                                                      Instances For

                                                                                        An NP is "marked" iff its case has been valued (lexically, by dependent rule, or by agreement). The "unless...marked" clauses of (4a)/(4b) check this.

                                                                                        Equations
                                                                                        Instances For

                                                                                          Initialize: pre-fill lexical case from the NP's lexicalCase field; everything else starts unvalued.

                                                                                          Equations
                                                                                          Instances For
                                                                                            def Syntax.Case.setCaseAt (i : ) (c : Case) (src : CaseSource) (states : List PhasedState) :

                                                                                            Replace the case of the NP at index i with (c, src).

                                                                                            Equations
                                                                                            • One or more equations did not get rendered due to their size.
                                                                                            Instances For

                                                                                              The eligibility predicate used by unmarkedVisible: a state is eligible iff it is visible on the cycle, argumental, not DP- internal, and not yet marked. Factored out so structural proofs (e.g. applyAccRule_preserves_marked_at) can manipulate the condition without unfolding pattern lambdas.

                                                                                              Equations
                                                                                              Instances For
                                                                                                def Syntax.Case.unmarkedVisible (cycle : CasePhase) (states : List PhasedState) :
                                                                                                List

                                                                                                Indices of unmarked, argumental, clause-level NPs visible on a given cycle, in c-command order (highest first, since list-position encodes height). Non-argumental NPs (bare-NP adverbs) and DP- internal NPs (possessors) are filtered out: per [BV10] (8)–(9), rules (4a)/(4b) apply only between argumental NPs at the clausal level.

                                                                                                Equations
                                                                                                Instances For

                                                                                                  Apply the DAT rule (4a) on the VP cycle: if there are at least two unmarked NPs visible at vP, mark the highest as DAT.

                                                                                                  Equations
                                                                                                  • One or more equations did not get rendered due to their size.
                                                                                                  Instances For
                                                                                                    def Syntax.Case.applyAccRule (cfg : CaseSystemConfig) (cycle : CasePhase) (states : List PhasedState) :

                                                                                                    Apply the ACC rule (4b) on a given cycle: if there are at least two unmarked NPs visible, mark the lowest as ACC.

                                                                                                    Equations
                                                                                                    • One or more equations did not get rendered due to their size.
                                                                                                    Instances For

                                                                                                      Apply v-Agree: the lowest CP-visible unmarked argumental NP gets ACC via Agree. This is the standard Chomskyan picture ([Cho00]; [Cho01]): v probes downward into its complement and Agrees with the closest goal. The dependent- accusative algorithm (applyAccRule) is the alternative to this pass; the two are mutually exclusive on a given grammar via the accMode parameter.

                                                                                                      Equations
                                                                                                      • One or more equations did not get rendered due to their size.
                                                                                                      Instances For

                                                                                                        Apply T-Agree (paper (5)/(86)): the highest unmarked NP visible on the CP cycle gets NOM via Agree.

                                                                                                        Equations
                                                                                                        • One or more equations did not get rendered due to their size.
                                                                                                        Instances For

                                                                                                          Apply D-Agree (paper (5)/(86)): every unmarked DP-internal NP (possessor) is valued GEN by its dominating D head. The clausal algorithm sees DP-internals as opaque (filtered from unmarkedVisible); this pass is the DP-internal counterpart to applyNomAgree. The Russian numeric/partitive GEN, by contrast, is .nonstructural and lives in lexicalCase.

                                                                                                          Equations
                                                                                                          • One or more equations did not get rendered due to their size.
                                                                                                          Instances For

                                                                                                            Default case for any NP still unmarked at the end of the derivation. Uses unmarkedCaseFor from § 6.

                                                                                                            Equations
                                                                                                            • One or more equations did not get rendered due to their size.
                                                                                                            Instances For

                                                                                                              Materialize a PhasedState as a CasedNP (or omit if no case was ever assigned — caller should ensure applyDefault ran).

                                                                                                              Equations
                                                                                                              Instances For

                                                                                                                The B&V phased algorithm: VP cycle (DAT then ACC), CP cycle (ACC), v-Agree → ACC (only when accMode := .agreeV), T-Agree → NOM, D-Agree → GEN, then a default sweep.

                                                                                                                applyAccRule and applyAccAgree are mutually exclusive on the cases they touch (gated by accMode), so their relative order only matters when neither fires. The order chosen — dependent rules first, then Agree — mirrors the standard Chomskyan picture where v probes after VP-internal structure has been built.

                                                                                                                Equations
                                                                                                                • One or more equations did not get rendered due to their size.
                                                                                                                Instances For

                                                                                                                  Length preservation (one CasedNP per input PhasedNP) and totality (every input NP receives exactly one case) are the key well-formedness properties of assignCasesPhased. They fall out structurally: each per-pass operation preserves list length, and applyDefault guarantees no state escapes uncased.

                                                                                                                  theorem Syntax.Case.initStates_length (nps : List PhasedNP) :
                                                                                                                  (initStates nps).length = nps.length
                                                                                                                  theorem Syntax.Case.setCaseAt_length (i : ) (c : Case) (src : CaseSource) (states : List PhasedState) :
                                                                                                                  (setCaseAt i c src states).length = states.length
                                                                                                                  theorem Syntax.Case.applyDatRule_length (cfg : CaseSystemConfig) (states : List PhasedState) :
                                                                                                                  (applyDatRule cfg states).length = states.length
                                                                                                                  theorem Syntax.Case.applyAccRule_length (cfg : CaseSystemConfig) (cycle : CasePhase) (states : List PhasedState) :
                                                                                                                  (applyAccRule cfg cycle states).length = states.length
                                                                                                                  theorem Syntax.Case.applyAccAgree_length (cfg : CaseSystemConfig) (states : List PhasedState) :
                                                                                                                  (applyAccAgree cfg states).length = states.length
                                                                                                                  theorem Syntax.Case.applyNomAgree_length (cfg : CaseSystemConfig) (states : List PhasedState) :
                                                                                                                  (applyNomAgree cfg states).length = states.length
                                                                                                                  theorem Syntax.Case.applyGenAgree_length (cfg : CaseSystemConfig) (states : List PhasedState) :
                                                                                                                  (applyGenAgree cfg states).length = states.length
                                                                                                                  theorem Syntax.Case.applyDefault_length (cfg : CaseSystemConfig) (states : List PhasedState) :
                                                                                                                  (applyDefault cfg states).length = states.length
                                                                                                                  theorem Syntax.Case.applyDefault_all_some (cfg : CaseSystemConfig) (states : List PhasedState) (s : PhasedState) :
                                                                                                                  s applyDefault cfg statess.case.isSome = true

                                                                                                                  After the final default sweep, every state's case is valued.

                                                                                                                  theorem Syntax.Case.assignCasesPhased_length (cfg : CaseSystemConfig) (nps : List PhasedNP) :
                                                                                                                  (assignCasesPhased cfg nps).length = nps.length

                                                                                                                  Soundness (length preservation). The phased algorithm produces exactly one CasedNP per input PhasedNP. No NP is dropped or duplicated; the algorithm is total.

                                                                                                                  The Elsewhere ordering of (4a) over (4b) on the VP cycle is not a stipulated rule-ordering preference: it falls out from the fact that unmarkedVisible filters out marked NPs, so any pass that only modifies indices in unmarkedVisible cannot overwrite a previously- valued NP. We prove this once for applyAccRule (it never overwrites a marked state) and use it to derive the bleeding theorem for arbitrary inputs.

                                                                                                                  theorem Syntax.Case.applyAccRule_preserves_marked_at (cfg : CaseSystemConfig) (cycle : CasePhase) (states : List PhasedState) (i : ) (s : PhasedState) (h_get : states[i]? = some s) (h_marked : s.marked = true) :
                                                                                                                  (applyAccRule cfg cycle states)[i]? = some s

                                                                                                                  (4b) ACC never overwrites a marked NP. This is the structural content of the Elsewhere ordering: once a state has been valued (lexically, by (4a) DAT, or by Agree), unmarkedVisible no longer includes its index, so applyAccRule cannot touch it.

                                                                                                                  theorem Syntax.Case.applyAccAgree_preserves_marked_at (cfg : CaseSystemConfig) (states : List PhasedState) (i : ) (s : PhasedState) (h_get : states[i]? = some s) (h_marked : s.marked = true) :
                                                                                                                  (applyAccAgree cfg states)[i]? = some s

                                                                                                                  v-Agree, like (4b), only touches unmarkedVisible indices and so cannot overwrite a marked NP.

                                                                                                                  theorem Syntax.Case.applyNomAgree_preserves_marked_at (cfg : CaseSystemConfig) (states : List PhasedState) (i : ) (s : PhasedState) (h_get : states[i]? = some s) (h_marked : s.marked = true) :
                                                                                                                  (applyNomAgree cfg states)[i]? = some s

                                                                                                                  T-Agree only touches unmarkedVisible .cp indices.

                                                                                                                  theorem Syntax.Case.applyGenAgree_preserves_marked_at (cfg : CaseSystemConfig) (states : List PhasedState) (i : ) (s : PhasedState) (h_get : states[i]? = some s) (h_marked : s.marked = true) :
                                                                                                                  (applyGenAgree cfg states)[i]? = some s

                                                                                                                  D-Agree only modifies unmarked DP-internal states.

                                                                                                                  theorem Syntax.Case.applyDefault_preserves_marked_at (cfg : CaseSystemConfig) (states : List PhasedState) (i : ) (s : PhasedState) (h_get : states[i]? = some s) (h_marked : s.marked = true) :
                                                                                                                  (applyDefault cfg states)[i]? = some s

                                                                                                                  The default sweep only modifies unmarked states.

                                                                                                                  theorem Syntax.Case.dat_persists_through_vp_acc (cfg : CaseSystemConfig) (states : List PhasedState) (i : ) (s : PhasedState) (h_get : (applyDatRule cfg states)[i]? = some s) (h_dat : s.case = some (Case.dat, CaseSource.dependent)) :
                                                                                                                  (applyAccRule cfg CasePhase.vp (applyDatRule cfg states))[i]? = some s

                                                                                                                  DAT bleeds ACC on the VP cycle, structurally. For every input state list, the NP marked DAT by applyDatRule keeps its DAT case through the subsequent VP-cycle applyAccRule call.

                                                                                                                  theorem Syntax.Case.dat_persists_through_assignCasesPhased (cfg : CaseSystemConfig) (nps : List PhasedNP) (i : ) (s : PhasedState) (h_get : (applyDatRule cfg (initStates nps))[i]? = some s) (h_dat : s.case = some (Case.dat, CaseSource.dependent)) :
                                                                                                                  have s0 := initStates nps; have s1 := applyDatRule cfg s0; have s2 := applyAccRule cfg CasePhase.vp s1; have s3 := applyAccRule cfg CasePhase.cp s2; have s4 := applyAccAgree cfg s3; have s5 := applyNomAgree cfg s4; have s6 := applyGenAgree cfg s5; have s7 := applyDefault cfg s6; s7[i]? = some s

                                                                                                                  DAT marking persists all the way through assignCasesPhased. Whatever NP applyDatRule values DAT survives every subsequent pass — both ACC cycles, both Agree probes, and the default sweep — because each pass only modifies states it sees as unmarked. The Sakha-specific empirical theorem ditrans_goal_dat follows from this structural fact applied to the ditransitive input.