[Conway] Property : voteDelegs range lies in VDelegs of registered DReps (#1233) - #1290
[Conway] Property : voteDelegs range lies in VDelegs of registered DReps (#1233)#1290williamdemeo wants to merge 4 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR upgrades the “vote delegation targets are valid” statement from an informal claim to a formally proved theorem, ensuring post-CERTS states only contain vote delegations to registered DReps (or the two special constants).
Changes:
- Replaces an informal claim with a theorem statement in the Conway spec properties overview.
- Adds a full formalization and proof that
CERTSsteps leave only “active”VDelegvalues invoteDelegs. - Introduces a supporting set-theory lemma about corestriction range containment and records the change in the changelog.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/Ledger/Conway/Specification/Properties.lagda.md | Updates the high-level spec statement from “Claim” to “Theorem” with a refined description. |
| src/Ledger/Conway/Specification/Certs/Properties/VoteDelegsVDeleg.lagda.md | Defines activeVDelegs, restates the property over CertState, and adds a proof for the CERTS step. |
| src-lib-exts/abstract-set-theory/Axiom/Set/Map/Extra.agda | Adds lemma cores-range-⊆ used by the new proof. |
| CHANGELOG.md | Documents the newly stated/proved voteDelegs property. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| Let `s`{.AgdaBound}, `s'`{.AgdaBound} be `CertStates`{.AgdaRecord} and | ||
| `certs`{.AgdaBound} a list of `DCerts`{.AgdaDatatype} such that `s`{.AgdaBound} | ||
| `⇀⦇`{.AgdaDatatype} `certs`{.AgdaBound} `,CERTS⦈`{.AgdaDatatype} `s'`{.AgdaBound}. |
There was a problem hiding this comment.
Keeping these, because the pluralization is a repo-wide prose convention rather than something local to this entry. It occurs 19 times under src/, including the two neighbouring bullets in this same file and the modules this bullet links to (Certs/Properties/PoV.lagda.md L61-62, Certs/Properties/PoVLemmas.lagda.md L50 and L215-218). Aligning only this entry would make it the odd one out.
You are right on the underlying point, though: CertStates and DCerts are not identifiers, so tagging them {.AgdaRecord} / {.AgdaDatatype} applies Agda-identifier styling to non-identifiers. That is pre-existing and repo-wide, so it belongs in its own pass over the prose rather than here.
| --- | ||
|
|
||
| ## Claim: <span class="AgdaField">voteDelegs</span> field values are <span class="AgdaDatatype">VDelegs</span> constructed from their keys {#clm:VDelegsInRegDReps} | ||
| ## Theorem: <span class="AgdaField">voteDelegs</span> values point at registered <span class="AgdaFunction">DReps</span> {#clm:VDelegsInRegDReps} |
There was a problem hiding this comment.
Deliberately keeping the anchor:
- It is referenced from
build-tools/static/mkdocs/includes/links.mdand is a published-docs URL fragment, so renaming breaks existing external links to#clm:VDelegsInRegDReps. - There is already in-repo precedent for a proved theorem retaining a
clm:anchor:src/Ledger/Conway/Specification/Gov/Properties/LastVoteApplied.lagda.mdL6 is## Theorem: ... {#clm:LastVoteApplied}. - Preserving this anchor was an explicit requirement for this change.
Your point stands that the clm: / thm: prefixes are no longer a reliable classification signal. With two files now in this state, the fix is one pass over every anchor plus links.md (and ideally redirects for the published fragments), not a one-off rename here.
| cores-range-⊆ : ∀ {A B : Type} ⦃ _ : DecEq B ⦄ (m : A ⇀ B) {X : ℙ B} → range (m ∣^ X) ⊆ X | ||
| cores-range-⊆ _ b∈range with Equivalence.from ∈-map b∈range | ||
| ... | _ , refl , ab∈cores = proj₁ (Equivalence.from ∈-filter ab∈cores) |
There was a problem hiding this comment.
Two separate points here; the first rests on a misreading.
cores-range-⊆ is not inside the module _ {A B : Type} ... block that opens at L64. It starts at column 0, which closes that block, so the ∀ {A B : Type} is required rather than redundant. It also must stay: that module's parameters include ⦃ CommutativeMonoid _ _ B ⦄ and ⦃ IsCommutativeSemigroup _◇_ ⦄, and a corestriction lemma has no business carrying a commutative-monoid constraint. The form used matches the adjacent top-level lemmas (lookupᵐ?-insert, ∈-insert-≢, lookupᵐ?-insert-≢), which are all ∀ {A B : Type} ⦃ _ : DecEq _ ⦄.
The naming nit is fair, and is fixed in 9dd24fb: cores-range-⊆ _ b∈range is now cores-range-⊆ m b∈range. m stays unused in the body (the proof only inspects the membership proof), but naming it saves the reader a trip to the signature to recover the argument order.
9dd24fb to
fcc8747
Compare
fcc8747 to
222f36c
Compare
|
Rebased onto master ( That rule was load-bearing here. It corestricted CERTS-voteDelegsVDeleg : LedgerInvariant _⊢_⇀⦇_,CERTS⦈_ voteDelegsVDelegThis is the honest correction rather than a simplification: the statement is the more useful one (a real invariant), but the proof grew, since the containment is now maintained incrementally by Two notes for anyone re-reading the earlier review threads:
Verified with |
690f9ef to
385048f
Compare
e293798 to
b45abca
Compare
…DReps
The property in Certs.Properties.VoteDelegsVDeleg was false as stated. It
claimed the range of voteDelegs is contained in the VDelegs built from the
*domain* of voteDelegs, but the domain holds delegator stake credentials while
the range holds VDelegs wrapping DRep credentials (or vDelegAbstain /
vDelegNoConfidence). The module anchor {#clm:VDelegsInRegDReps} records the
intended claim: vote delegations point at registered DReps.
Restate it as a property of the CERTS rule and prove it:
Gamma |- s ->(certs ,CERTS) s' -> range (VoteDelegsOf s') subset-of activeVDelegs s'
where
activeVDelegs s = mapS vDelegCredential (dom (DRepsOf s))
union fromList (vDelegNoConfidence :: vDelegAbstain :: [])
is the set POST-CERT corestricts to. Nothing is assumed about the initial
state: POST-CERT ends every CERTS batch with voteDelegs |^ activeVDelegs, so
the property holds unconditionally of the output state.
The proof inverts the CERTS step, inducts over the CERT trace, and closes the
run-[] case with a new lemma cores-range-subset (range (m |^ X) subset-of X)
added to Axiom.Set.Map.Extra; agda-sets carries nothing about _|^_ beyond
cores-subset. Its map argument is explicit because _|^_ goes through
subset-map, which mentions the map only under proj1, so it is not recoverable
by unification.
Also promote the prose entry in Conway/Specification/Properties.lagda.md from
Claim to Theorem and restate it, and add a CHANGELOG entry.
AI-assisted development: Claude Opus 5 (Anthropic)
Address a review nit: the clause head now mirrors the type signature. `m` is unused in the body (the proof only inspects the membership proof), but naming it saves the reader a trip to the signature to recover the argument order. AI-assisted development: Claude Opus 5 (Anthropic)
Master removed the POST-CERT rule; delegated voting stake is now dropped by
GOVCERT at the moment a DRep is deregistered. POST-CERT used to corestrict
voteDelegs to the active VDelegs at the end of every batch, which is what made
the property an unconditional postcondition of CERTS and its proof a one-liner.
That sweep is gone, so an arbitrary input state may already violate the
containment and nothing in a CERTS step would repair it.
Restate the property as a genuine CERTS invariant and prove it:
CERTS-voteDelegsVDeleg : LedgerInvariant _|-_->(_,CERTS)_ voteDelegsVDeleg
The containment is now maintained incrementally by the two rules that could
break it. DELEG-delegate may install only a VDeleg that is already active for
the current delegatees, and GOVCERT-deregdrep, the one rule that shrinks the
registered DReps, deletes every delegation to the credential it deregisters in
the same step. The remaining rules either leave both fields alone or only grow
the DRep domain, for which activeVDelegs is monotone.
The proof establishes invariance for DELEG, GOVCERT, CERT and PRE-CERT, then
lifts the CERT lemma along RTC-preserves-inv. In Axiom.Set.Map.Extra, drop
cores-range-|_ (nothing corestricts any more) and add what the new proof needs:
coex-|-in, for reading a pair back out of a complement corestriction, and
dom-cup-l-supset-r with its corollaries dom-insert-supset and
dom-mapValueRestricted-supset, for the two left-biased unions that refresh and
extend the DReps. Each takes the map whose keys are preserved explicitly, since
it sits under proj1 and unification cannot recover it.
Also restate the prose entry in Conway/Specification/Properties.lagda.md and
restore the changelog line dropped in an earlier rebase.
AI-assisted development: Claude Opus 5 (Anthropic)
8e8d680 to
ffe741d
Compare
Every value of
voteDelegsis aVDelegof a registeredDRep,vDelegAbstain, orvDelegNoConfidence, andCERTSpreserves that.The original statement was corrected. It said
which is well typed (
mapˢ vDelegCredentiallifts the domain intoℙ VDeleg) but false, for two independent reasons:vDelegAbstainandvDelegNoConfidenceare legalvoteDelegsvalues and neither isvDelegCredential cfor anyc; and the range wraps DRep credentials, whileregdrepnever adds a key tovoteDelegs, so a delegatee need not lie indom voteDelegs.It is now an invariant rather than a postcondition, because master removed
POST-CERTin the meantime. That rule used to corestrictvoteDelegsto the activeVDelegs at the end of every batch, which made the containment unconditional on the output ofCERTS. With the final sweep gone, an input state may already violate it and noCERTSstep would repair it, so the property is stated and proved as preservation instead.The containment is now maintained incrementally by the two rules that could break it:
DELEG-delegatemay install only aVDelegthat is already active for the current delegatees, andGOVCERT-deregdrep, the one rule that shrinks the registeredDReps, deletes every delegation to the credential it deregisters in the same step. The proof establishes invariance forDELEG,GOVCERT,CERTandPRE-CERT, then lifts theCERTlemma alongRTC-preserves-inv.Four small lemmas go to
Axiom.Set.Map.Extra:coex-∈⁻, anddom-∪ˡ-⊇ʳwith its corollariesdom-insert-⊇anddom-mapValueRestricted-⊇.Closes #1233