design: milestone revocation — decided, no revocation - #35
Merged
Conversation
Closes #17. A met milestone cannot be un-met. Milestone state is monotonic and Met is terminal. The deciding argument is arithmetic. Re-locking a tranche after a withdrawal has settled charges the shortfall against the recipient's other tranches, because withdrawn is one stream-wide counter. Run against the concepts.md worked example, revoking at day 19 puts claimable at -6,600,000,000 and it stays negative until it reaches exactly zero on day 30 - so the recipient receives nothing for the stream's remaining twelve days, on a base tranche that was never gated. Money they were entitled to when they withdrew it becomes a debt against future earnings. Restricting revocation to before-any-withdrawal avoids that and instead makes the outcome a race between approver and recipient, decided by who submits first. Keeping Met terminal also keeps the approver's power one-directional, which is what makes concepts.md's no-custody claim structurally true rather than merely currently true, and keeps the milestone struct small - a revocable milestone needs a released-amount field and a revocation counter per milestone, pushing against the read budget and restore cost the milestone cap exists to manage. Gives up: no in-protocol remedy for an approval that was wrong. Recorded plainly. Disputes belong in an escrow that has a dispute process, which is the Trustless Work split architecture.md already describes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K4KmSPBuq484Zt65qsK177
3 tasks
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.
Closes #17. First of Track A (#34).
Decision: a met milestone cannot be revoked. Milestone state is monotonic and
Metis terminal.The deciding argument is arithmetic, not preference
The intuitive option — revocation re-locks the tranche, prior withdrawals stand — sounds fair and isn't. Run it against the worked example, with the approver revoking at day 19:
streamed_totalheldclaimableClaimable goes negative and only reaches zero on the final day. Clamped at zero, as any implementation must, Bob receives nothing for the remaining twelve days — on a base tranche that was never gated.
The mechanism is that
withdrawnis a single stream-wide counter, so re-imposingheldafter a withdrawal has settled charges the shortfall against whatever the recipient's other tranches earn next. A milestone decision reaches across tranche boundaries and cancels income the milestone never governed. Money Bob was unambiguously entitled to when he withdrew it becomes a debt against his future earnings.Restricting revocation to "before anything is withdrawn" avoids that, and replaces it with a race between approver and recipient decided by who submits first — which rewards whoever is running a bot rather than whoever is right.
What it protects
concepts.mdwould need amending to something much weaker.MAX_MILESTONES_PER_STREAMexists to manage.claimableis non-decreasing in approvals.What it gives up, stated plainly
No in-protocol remedy for an approval that turns out to be wrong. That was never StelFlow's to handle —
architecture.mdalready draws the line where Trustless Work decides whether a condition is met and StelFlow decides how fast money moves. A grant program needing disputes names a TW escrow as approver, and that escrow withholds approval until its process concludes. Revocation's real use case, solved by not approving yet, in the contract that has the machinery.Changes
docs/research/milestone-revocation.md— decision, four options considered, the arithmetic, and what's given updocs/concepts.md— rule stated in Milestone gates;TODO(maintainer)removed; "flips a flag" sharpened to "flips a flag, once, in one direction"docs/architecture.md— open question 2 marked settled; storage consequence recordeddocs/specs/behaviour.md—UNDECIDEDdocs: write the three use-case pages #3 resolved, and it narrows design: settle the four remaining UNDECIDED cases in behaviour.md #32's case 1Acceptance criteria
concepts.mdstates the rule; TODO removedarchitecture.mdreflects the storage consequenceMakes T3 more urgent, not less. With no revocation and no deadline, a non-cancelable stream whose approver disappears has no recovery path for anyone. Deciding deadlines is now the outstanding half of the milestone lifecycle.