This is the contract the proof commits to. It is deliberately narrower than "the paper's Fig. 4 verbatim"; the deviations are listed and justified below.
Let ⟶ be the single-step reduction relation: the compatible (congruence)
closure of the eleven rule schemas below, over Term (formations ⟦B⟧,
applications e(τ↦e'), dispatches e.τ, the locators Φ/ξ, and the terminator
⊥). Let ⟶∗ be its reflexive-transitive closure.
Confluence (Church–Rosser). For all well-formed
e(WF e) and alle₁, e₂: ife ⟶∗ e₁ande ⟶∗ e₂, then there existse₃withe₁ ⟶∗ e₃ande₂ ⟶∗ e₃.
In Lean: a WF-relativized confluence, WF e → e ⟶∗ e₁ → e ⟶∗ e₂ → ∃ e₃, …
(WF is PhiConfluence.WF from WellFormed.lean: a formation's domain is duplicate-free
and free of positional αᵢ keys). It is proved by the diamond property of a
parallel-reduction relation Par (Takahashi complete development) transported via
Relation.church_rosser. The system is non-terminating, so this is not done with
Newman's lemma.
Why WF-scoped (and not the unconditional Confluent Step). WF has two clauses, and they
carry different weight — worth stating precisely:
legalKey(no positionalαᵢas a formation key) is necessary for confluence. The counterexample that makes unconditionalConfluent Stepfalse oncealphais present is alegalKeyviolation: a malformed⟦B₁, αᵢ↦e₁, B₂⟧(αᵢ↦e₂)whose void slot sits at ordinaliletsalpharename the argument (→ an object) whileoverfires (→⊥), and object vs⊥never join (deviation #8). The diamond proof consumes exactly this clause (lookup_alpha_absent_of_wf, thealphacase ofpar_triangle). Faithful, too: phino's parser barsαᵢformation keys.Nodup(unique keys, Def. Binding 4.8) is a faithfulness clause, not a demonstrated confluence-necessity. No duplicate-key non-joinable fork is known, and the diamond proof binds theNodupfield ofWF.formbut never uses it (onlylegalKey).Nodupis carried because it matches the paper's Def. Binding and makes our first-matchlookupcoincide with phino's matcher (deviation #6) — and becauseWF.step/WF.parpreserve it. So "WFis necessary" is precise forlegalKey; forNodupit is faithfulness, not necessity.
So WF-scoping re-imposes exactly the paper's own grammar restrictions our looser Binding drops.
(Note the paper proves no confluence theorem at all; it presupposes confluence when defining ≡ as
"normal forms are syntactically identical". We prove it, WF-scoped because our encoding is looser
than the grammar.)
phino's duplicate-ρ printer bug — resolved (phino #748). Earlier, phino's printer injected a
duplicate void ρ, so ⟦ρ↦⟦⟧⟧ printed as ⟦ρ↦⟦ρ↦∅⟧, ρ↦∅⟧ (two ρ keys) — non-Nodup,
contradicting the Def. Binding its own parser enforces. Fixed in phino #748 ("dont inject
duplicate void rho in salty printing"); phino now emits the single-ρ form our model already
produces (canon ⟦ρ↦⟦⟧⟧ = ⟦ρ↦⟦ρ↦∅⟧⟧). We never reproduced the bug (it would break Nodup and the
lookup-vs-matcher agreement), so model and phino now agree here.
(As of
M4.2b, alpha IS in Step, so WF is now load-bearing: the headline confluence carries
WF e and is proved via the WF-relativized diamond ParWF a b := WF a ∧ Par a b. The
earlier alpha-free fragment was unconditionally confluent; that unconditional
step_confluent was retired when alpha landed.)
Source of truth: the paper (reduction figure, operators.tex); phino's
resources/*.yaml (phino explain --normalize) is the secondary interpretation that
renders into it. nf e means "e is in normal form" (no rule matches anywhere in
e); |B₁| is the number of bindings before the focus; C(·⊳·) is contextualization
(Fig. "Contextualization by induction").
phino rule |
Lean Step constructor |
Pattern → result | Side condition |
|---|---|---|---|
dot |
Step.dot |
⟦B₁,τ↦e₁,B₂⟧.τ → C(e₁⊳⟦…⟧)(ρ↦…) |
nf e₁ |
copy |
Step.copy |
⟦B₁,τ↦∅,B₂⟧(τ↦e₁) → ⟦B₁,τ↦e₁,B₂⟧ |
ξFree e₁ ∧ nf e₁ (ξ-free KEPT; scope/contextualize vacuous — dev. #7) |
alpha |
Step.alpha |
⟦B₁,τ₁↦∅,B₂⟧(τ₂↦e) → ⟦B₁,τ₁↦∅,B₂⟧(τ₁↦e) |
index τ₂ = domain(B₁) (†) |
phi |
Step.phi |
⟦B⟧.τ → ⟦B⟧.φ.τ |
φ∈B ∧ τ∉B |
stay |
Step.stay |
⟦B₁,ρ↦e₁,B₂⟧(ρ↦e₂) → ⟦B₁,ρ↦e₁,B₂⟧ |
— |
over |
Step.over |
⟦B₁,τ↦e₁,B₂⟧(τ↦e₂) → ⊥ |
τ≠ρ (attached slot) |
stop |
Step.stop |
⟦B⟧.τ → ⊥ |
τ∉B ∧ φ∉B ∧ λ∉B |
null |
Step.null |
⟦B₁,τ↦∅,B₂⟧.τ → ⊥ |
— (void slot) |
miss |
Step.miss |
⟦B⟧(τ↦e) → ⊥ |
τ∉B ∧ τ not positional αᵢ |
dd |
Step.dd |
⊥.τ → ⊥ |
— |
dc |
Step.dc |
⊥(τ↦e) → ⊥ |
— |
(†) alpha's index counts the domain (assets excluded) — phino #749. Step.alpha matches
voidAtOrdinal bs i = the key of the i-th non-asset binding when that binding is void, so a
Δ/λ asset before the void slot does not shift the ordinal. This is the paper's Def. Ordinal /
Def. Domain (the domain excludes assets) and phino post-#749 ("count alpha index over domain
excluding assets" — alpha.yaml's index = domain condition). Earlier phino (and its generated
figure) counted assets raw (|B₁| = length bds), contradicting the paper's own prose and worked
example (tab:ordinals: ordinal of x in ⟦L>Fn, x↦…⟧ is 0); #749 fixed phino to match the
prose, and Step.alpha matches the fixed semantics. The regenerated Rules.lean now shows
index(τ₂) = domain(B₁).
Plus the four congruence constructors Step.congDispatch, Step.congAppFn,
Step.congAppArg, Step.congForm — covering every recursive Term position (dispatch
subject, application subject, application argument, and a formation binding's value),
so reduction may occur anywhere, matching the paper (operators.tex: "rules may be
applied in any order"). Step.congForm uses the paper's ⟦B₁,τ↦e,B₂⟧ splitting.
Disjointness (the root rules are mutually exclusive on a given redex, with the noted exceptions):
- dispatch
⟦B⟧.τis split bydot(τ attached) /null(τ void) /phi(τ absent, φ present) /stop(τ absent, φ,λ absent);⊥.τisdd. Terms outside all cases (e.g.Φ.τ,ξ.τ) are stuck — this is a partition of reducible dispatch redexes, not of all terms. - application
⟦B⟧(τ↦e)is split bystay(τ=ρ attached) /over(τ≠ρ attached) /copy(τ void, args normal) /alpha(positionalαᵢ, void at ordinali) /miss(τ absent, non-α);⊥(…)isdc. Exception:alphaandcopycan both match when the applied attribute is a positionalαᵢwhose ordinal slot is void — a genuine (and expected-joinable) critical pair, not a clean partition.
We match the current paper, whose Fig. 4 is generated from current phino
(phino explain --normalize). The items below record (a) where older/published
forms differed, (b) scoping choices for the confluence theorem, and (c) standing
assumptions — not gaps against the current paper.
overrequires an attachedτ. The current Fig. 4 (generated from phino) and ouroverboth use the disjoint attached-slot form⟦B₁,τ↦e₁,B₂⟧(τ↦e₂). A naive reading of the membership predicateτ∈b(defined in Def. 4.9, Formation — it holds for void keys too) would license a looseroveroverlappingcopyon a void slot (object vs⊥, which never join); the published arXiv v9 PDF, built with an older phino, rendered exactly that looser form. We follow the current, disjoint form. (Worth keeping the∈-based prose from suggesting the loose reading.)dot/copyarenf-guarded. They fire only when the relevant sub-expression is already normal. This forces an inner-first order, makes each rule single-path, and removes thedot↔copyordering ambiguity. It also makes⟶a conditional relation with non-monotone guards — the main proof subtlety.- Small-step
copy(not big-step). The current paper'scopy(generated from phino) is already the small-stepnf-guarded form we use. Older/published forms (arXiv v9) had a big-stepRcopythat normalizes its argument toninside the rule (C(e⊳eς) ⟶∗ n), presupposing uniqueness of normal forms (= confluence). We follow the current small-step form, avoiding the circularity; against the current paper there is nothing to reconcile, and the superseded big-step form is not modelled. λ/Δatoms are outside the normalization relation⟶. They have no rule among the eleven (phino'sresources/*.yamlhas none). Their reduction is the paper's separate Morphing (fig:morphing—Mlambdacalls a host atomfby value) and Dataization (fig:dataization) partial functions: stateful, side-effecting, host-dependent — functions, not a term-rewriting relation (so the relevant property there is determinism, not confluence). Confluence of⟶therefore neither needs nor includes them;λ/Δare represented as inert atoms (Binding.lambda/Binding.delta) that never fire. This is a permanent scope boundary set by the paper's own structure (normalization vs. morphing/dataization are separate sections), not unfinished work.ρ-feedback (landed).dot'sρ-introduction (which makes the system non-terminating) landed inStep/Parat M4.3 with thenf-guard andcontextualize(receiver = the dispatched formation, so noscope).copylanded at M4.4 (see #7).alphalanded at M4.2b (positional; now modelled byvoidAtOrdinal— the domain ordinal, assets skipped, matching the paper and phino post-#749 — see note †). So all eleven rules are now inStep/Par, andconfluencecovers them. (Earlier drafts said "M1–M2 use a simplifieddot" — there was never a simplifieddot; it arrived at M4.3 with full ρ-feedback.)- Unique-key well-formedness (Def. 4.8). Formations are assumed to have unique
attribute keys; under that invariant our first-match
lookupcoincides with phino's any-position match. Documented inAttributes.lean; to be carried as a hypothesis / indexed type once formation-rebuilding rules arrive. (This is deviation #6 above; the design rationale is indocs/DESIGN.md§4/§6.) copy's guards areξFree e₁∧nf e₁— we KEEP phino'sξ-free (this REVERSES the earlier draft of this note, settled at M4.4 by the author).Step.copy(Step.lean) is the local slot-fill⟦B₁,τ↦∅,B₂⟧(τ↦e₁) → ⟦B₁,τ↦e₁,B₂⟧guarded byξFree e₁thennf e₁— noscope, nocontextualize. Rationale: phino's printed figure renderscopywithnf(e₁)only (its renderer strips theξcondition), but phino's engine enforcesξ-free; and underξ-freeness,contextualize(e₁, scope) = e₁is proved (contextualize_eq_self,Parallel.lean,[propext]), so the figure'sscope/contextualizeare operationally vacuous and dropping them is exact, not a weakening. Keepingξ-free also (a) keepscopya local rule needing no context-dependentscope, (b) putscopyinside the de-risked/fuzzed fragment (the de-risk assumedξ-freeness), and (c) makesdifftestvalid (theξ-droppedcopydiverges on⟦x↦∅⟧(x↦ξ)viascopere-injection). The author is correcting the paper figure + phino to this form, so this is a 1:1 match, not a deviation. The singlenfisξFree-aware in its void-application case (it is not acopy-specificnf— it is the onenfencodingcopy's guard, exactly as phino's oneisNFdoes).- Formation keys are non-positional attributes only. The paper grammar
(
syntax.tex) puts positionalαᵢsolely in application-argument pairs; a formation binding's key is anAttribute∈ {φ,ρ, label}. OurBindingaccepts anyAttr(includingAttr.alpha), so a malformed formation with anαᵢkey is representable. Harmless in the⊥-fragment (no rule builds one;lookupis key-agnostic); to be enforced as a well-formedness side-condition alongside the unique-key invariant whenalpha/copy/dotarrive. - Every formation carries an implicit parent
ρ(modelled, not a deviation). The paper (foundations.tex, Def. Parent) and phino give every formation a parentρ, void until set — the paper grammar does not mandate it, so it is supplied semantically (phino appendsρ↦∅where absent, recursively). We model this withcanon(Canonical.lean), which injectsρexactly as phino does;canon_canonical/wf_canon/step_canonicalprove it is established,WF-preserving, and closed under reduction. Canonical terms areWF, so the headline governs them — the result is confluence of phino's actual calculus,ρincluded (not aρ-free fragment).difftestconfirms the match on real formation results. Full account:DESIGN.md§9.