[Dijkstra] LEDGER-pov: fix deposit-accounting bugs + assembly interface note + Agda tooling#1219
Merged
williamdemeo merged 4 commits intoJun 18, 2026
Conversation
…unted gov deposits) Both bugs are present on master@bd56c87. Only the prerequisites (#1208 hoist, #1214 GovActionState.deposit) are merged; the fixes themselves were still open. Verified against the trusted Conway spec and the Dijkstra GOV rule. Finding A (deposit sign-swap, Utxo.lagda.md): `consumed` carried newCertDeposits (posPart of depositsChange) and `consumedTx` carried govProposalsDeposits, while `produced` carried refundCertDeposits (negPart). Trusted Conway (Conway/Specification/Utxo.lagda.md:431-447) is the opposite under the identical depositsChange = after - before convention: posPart/newDeposits on PRODUCED, negPart/refunds on CONSUMED. The swapped sides let a transaction create value (e.g. a stake-key registration could output its deposit amount in excess of inputs). Fix: move newCertDeposits and govProposalsDeposits to produced, refundCertDeposits to consumed. Finding B (gov deposits uncounted, Ledger.lagda.md): getCoin LedgerState summed getCoin(UTxOState) + rewardsBalance(DState) + coinFromDeposits(CertState), with no governance term. Post-#1214 the GOV rule records gov-action deposits in GovActionState.deposit (Gov.lagda.md:451-453), never in GState.deposits, so coinFromDeposits (which sums the now-vacant GState.deposits pot) misses them. Added coinFromGovDeposit : GovState -> Coin (sum of GovActionState.deposit) to getCoin LedgerState. With Finding A charging govProposalsDeposits = pp.govActionDeposit on produced and GOV-Propose storing exactly that amount, the LEDGER-pov equation balances. The stale "GState growth" comment is rewritten. https://claude.ai/code/session_0174ZBS1RKAGSbBXDsESUwoA
The Ledger/Properties/PoV chain is the previous session's draft, written against the pre-fix spec, and is not yet wired into the build (Ledger/Properties.lagda.md imports only Computational). It predates both soundness fixes: - getCoin LedgerState now has a fourth summand coinFromGovDeposit (GovStateOf s); the chain still models the old three-summand total and uses the now-renamed coinFromDeposit (-> coinFromDeposits). - the Utxo deposit sides were swapped to match Conway. Re-deriving the LEDGER-V chain to thread the gov summand and the swapped sides requires Agda (the project typechecks only via the Nix flake, unavailable in this environment), so the chain body is left unchanged. Recorded as an in-file resume note: corrected the getCoin recall, and specified the two new module parameters a future Gov.Properties.PoV must provide (rmOrphanDRepVotes-coinFromGovDeposit and GOVS-coinFromGovDeposit). posNeg-deposits is a pure posPart/negPart cancellation, verified correct and unaffected by the fixes. https://claude.ai/code/session_0174ZBS1RKAGSbBXDsESUwoA
The project typechecks only via its Nix flake; there is no system agda. To make Agda checking available to Claude Code (this repo, web sessions): - .claude/skills/agda-typecheck/SKILL.md: documents the `nix develop --command agda <file>` workflow, common Agda error triage, and the project quality gate. - .claude/hooks/session-start.sh + .claude/settings.json: a SessionStart hook that installs nix, enables flakes, points at the cache.nixos.org/cache.iog.io substituters (keys from ci.yml), and pre-warms `nix develop`. Guarded by CLAUDE_CODE_REMOTE; non-fatal and clearly logged if it can't proceed. NETWORK PREREQUISITE: the hook needs the environment network policy to allow nixos.org, cache.nixos.org, cache.iog.io and github.com. The default policy in this session returns 403 for nixos.org and cache.iog.io, so the hook currently logs that and exits 0 without provisioning. Once the policy permits those hosts, the toolchain installs and is cached for subsequent sessions. https://claude.ai/code/session_0174ZBS1RKAGSbBXDsESUwoA
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes two preservation-of-value soundness issues in the Dijkstra ledger spec (deposit-side accounting and governance-action deposits missing from getCoin LedgerState), updates a draft LEDGER-PoV document to reflect the new accounting interface, and adds Claude Code tooling to typecheck Agda via the repo’s Nix flake.
Changes:
- Correct deposit-side placement in
UTxOconsumed/produced (new deposits + gov proposal deposits on produced; refunds on consumed). - Extend
getCoin LedgerStatewithcoinFromGovDeposit(summingGovActionState.deposit) and update accompanying prose. - Add Claude Code Agda typechecking skill + SessionStart hook to provision Nix/flakes and warm
nix develop.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Ledger/Dijkstra/Specification/Utxo.lagda.md | Fix consumed/produced deposit accounting sides; add Conway-alignment note. |
| src/Ledger/Dijkstra/Specification/Ledger.lagda.md | Add coinFromGovDeposit and include it in getCoin LedgerState; update explanatory prose. |
| src/Ledger/Dijkstra/Specification/Ledger/Properties/PoV.lagda.md | Update prose to reflect new getCoin summand and record updated proof interface notes. |
| CHANGELOG.md | Record the two PoV soundness fixes. |
| .claude/skills/agda-typecheck/SKILL.md | Document the nix develop --command agda … workflow and Agda triage/gates. |
| .claude/settings.json | Register SessionStart hook for Claude Code. |
| .claude/hooks/session-start.sh | Provision Nix + flakes + caches and pre-warm dev shell in remote sessions. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Ledger.lagda.md: HasCoin-CertState counts only the rewards balance (getCoin = rewardsBalance ∘ DStateOf), not the deposit pots; correct the prose to say components 3 and 4 (coinFromDeposits, coinFromGovDeposit) are added at the LedgerState level. - CHANGELOG.md: the HasCoin-LedgerState entry now also lists the coinFromGovDeposit summand, not just the three CertState deposit fields. - session-start.sh: enabling flakes keyed only on the presence of any experimental-features line, so a bare `experimental-features = nix-command` would skip flakes. Check for `flakes` specifically and append via extra-experimental-features (which doesn't clobber an existing setting). https://claude.ai/code/session_0174ZBS1RKAGSbBXDsESUwoA
154601e
into
1187-dijkstra-NEW-ENTITIES-ledger-pov
2 checks passed
williamdemeo
pushed a commit
that referenced
this pull request
Jun 25, 2026
- Ledger.lagda.md: HasCoin-CertState counts only the rewards balance (getCoin = rewardsBalance ∘ DStateOf), not the deposit pots; correct the prose to say components 3 and 4 (coinFromDeposits, coinFromGovDeposit) are added at the LedgerState level. - CHANGELOG.md: the HasCoin-LedgerState entry now also lists the coinFromGovDeposit summand, not just the three CertState deposit fields. - session-start.sh: enabling flakes keyed only on the presence of any experimental-features line, so a bare `experimental-features = nix-command` would skip flakes. Check for `flakes` specifically and append via extra-experimental-features (which doesn't clobber an existing setting). https://claude.ai/code/session_0174ZBS1RKAGSbBXDsESUwoA
williamdemeo
pushed a commit
that referenced
this pull request
Jun 25, 2026
- Ledger.lagda.md: HasCoin-CertState counts only the rewards balance (getCoin = rewardsBalance ∘ DStateOf), not the deposit pots; correct the prose to say components 3 and 4 (coinFromDeposits, coinFromGovDeposit) are added at the LedgerState level. - CHANGELOG.md: the HasCoin-LedgerState entry now also lists the coinFromGovDeposit summand, not just the three CertState deposit fields. - session-start.sh: enabling flakes keyed only on the presence of any experimental-features line, so a bare `experimental-features = nix-command` would skip flakes. Check for `flakes` specifically and append via extra-experimental-features (which doesn't clobber an existing setting). https://claude.ai/code/session_0174ZBS1RKAGSbBXDsESUwoA
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Folds the work from
claude/peaceful-carson-u3ojhcinto the LEDGER-pov branch (#1203): two preservation-of-value soundness fixes, a resume note pinning down the post-fix assembly interface, and tooling so Claude Code (web) can typecheck Agda.Soundness fixes
Both bugs are present on master@
bd56c87. Only the prerequisites (#1208 hoist, #1214GovActionState.deposit) are merged there; the fixes themselves were still open — verified by direct read ofbd56c87against the trusted Conway spec and the DijkstraGOVrule.A — deposit sign-swap (
Utxo.lagda.md)Certs.lagda.mddefinesdepositsChange = coinFromDeposits(after) − coinFromDeposits(before),newCertDeposits = posPart,refundCertDeposits = negPart— identical to Conway. Trusted Conway (Conway/Specification/Utxo.lagda.md:441-447) putsnegPart/refunds on consumed andposPart/new deposits on produced. Dijkstra had them swapped (andgovProposalsDepositson consumed), which lets a transaction create value — e.g. a stake-key registration could output its deposit amount in excess of its inputs.Fix: move
newCertDepositsandgovProposalsDepositsto produced,refundCertDepositsto consumed. Added a convention comment citing Conway to guard against regression.B — governance-action deposits uncounted (
Ledger.lagda.md)getCoin LedgerStatesummedgetCoin(UTxOState) + rewardsBalance(DState) + coinFromDeposits(CertState), with no governance term. Post-#1214 theGOVrule records gov-action deposits inGovActionState.deposit(Gov.lagda.md:451-453), never inGState.deposits(the rule's type isGovState → GovState— it has no access toGState). SocoinFromDeposits, which sums the now-vacantGState.depositspot, misses them.Fix: add
coinFromGovDeposit : GovState → Coin(sum ofGovActionState.deposit) and the+ coinFromGovDeposit (GovStateOf s)summand togetCoin LedgerState; rewrite the stale "GState growth" prose. With A charginggovProposalsDeposits = pp.govActionDepositon produced andGOV-Proposestoring exactly that amount, the LEDGER-pov equation balances.Both changes are recorded in
CHANGELOG.md.Assembly interface note (doc-only)
Ledger/Properties/PoV.lagda.mdis the prior LEDGER-pov draft and is not on the build path (Ledger/Properties.lagda.mdimports onlyComputational). It predates both fixes (models the old three-summandgetCoin, uses the renamedcoinFromDeposit, pre-swap sides), and re-deriving itsLEDGER-Vchain needs the typechecker. This commit therefore changes only prose: it corrects thegetCoinrecall and records, as a resume note, the exact interface the corrected proof needs — in particular two new module parameters for a futureGov.Properties.PoV:rmOrphanDRepVotes-coinFromGovDeposit— invariance ofcoinFromGovDepositunderrmOrphanDRepVotes(it only rewritesvotes.gvDRep, neverdeposit).GOVS-coinFromGovDeposit— top-level and per-sub-tx GOVS deposit accounting, tying gov-deposit growth to the produced-sidegovProposalsDeposits.posNeg-depositsis a pureposPart/negPartcancellation; it is verified correct and unaffected by the fixes.Agda toolchain tooling
.claude/skills/agda-typecheck/SKILL.md— thenix develop --command agda <file>workflow, Agda error triage, and the project quality gate..claude/hooks/session-start.sh+.claude/settings.json— a SessionStart hook that installs nix, enables flakes, points atcache.nixos.org/cache.iog.io(keys fromci.yml), and pre-warmsnix develop. Guarded byCLAUDE_CODE_REMOTE; non-fatal and clearly logged if it cannot proceed.nixos.organdcache.iog.io(the rest —*.nixos.org, GitHub — are already in the Trusted defaults).Verification status
nix build) will typecheck on push.src/Ledger.lagda.md; the changedconsumed/produced/getCoindefinitions are consumed opaquely by built modules, and the only file asserting their concrete structure (Ledger/Properties/PoV.lagda.md) is not on the build path — so these changes should not break the typechecked set.Checklist
CHANGELOG.md🤖 Generated with Claude Code
https://claude.ai/code/session_0174ZBS1RKAGSbBXDsESUwoA