diff --git a/trustless-work-dev/skills/api/multi-release-escrow.md b/trustless-work-dev/skills/api/multi-release-escrow.md index 78fae83..367ab6c 100644 --- a/trustless-work-dev/skills/api/multi-release-escrow.md +++ b/trustless-work-dev/skills/api/multi-release-escrow.md @@ -468,7 +468,7 @@ export const approveMilestone = async ( **Endpoint:** `POST /escrow/multi-release/change-milestone-status` -Service Provider updates the status and evidence of a milestone. +Service Provider updates the status and evidence of a milestone. Rejected for a milestone that is released or resolved (`MilestoneAlreadyReleased`/`MilestoneAlreadyResolved`); still allowed while that milestone's dispute is open. (Contract lineage from 2026-09-15 onward.) ### Request Schema diff --git a/trustless-work-dev/skills/api/single-release-escrow.md b/trustless-work-dev/skills/api/single-release-escrow.md index 19e2657..7996e0e 100644 --- a/trustless-work-dev/skills/api/single-release-escrow.md +++ b/trustless-work-dev/skills/api/single-release-escrow.md @@ -300,7 +300,7 @@ export const fundEscrow = async (contractId: string, amount: number) => { **Endpoint:** `POST /escrow/single-release/change-milestone-status` -Service Provider updates the status and evidence of a milestone. +Service Provider updates the status and evidence of a milestone. Rejected once the escrow is released or resolved (`EscrowAlreadyReleased`/`EscrowAlreadyResolved`); still allowed while a dispute is open. (Contract lineage from 2026-09-15 onward.) ### Request Schema diff --git a/trustless-work-dev/skills/api/v2/multi-release.md b/trustless-work-dev/skills/api/v2/multi-release.md index 0339311..d4e495b 100644 --- a/trustless-work-dev/skills/api/v2/multi-release.md +++ b/trustless-work-dev/skills/api/v2/multi-release.md @@ -105,7 +105,7 @@ A new milestone's `receiver` must not be the `admin` or any `disputeResolver`. T } ``` -Same rules as single-release: `newStatus` max 50 chars, `newEvidence` optional, max 500. +Same rules as single-release: `newStatus` max 50 chars, `newEvidence` optional, max 500. Updates are **rejected for a milestone that is `released` or has its dispute `resolved`** (`MilestoneAlreadyReleased` = 16 / `MilestoneAlreadyResolved` = 17); they stay allowed while that milestone's dispute is open. ## Approve milestones diff --git a/trustless-work-dev/skills/api/v2/single-release.md b/trustless-work-dev/skills/api/v2/single-release.md index e9b9afb..8262466 100644 --- a/trustless-work-dev/skills/api/v2/single-release.md +++ b/trustless-work-dev/skills/api/v2/single-release.md @@ -100,7 +100,7 @@ Appends new milestones and edits existing descriptions (`newDescription` max 500 } ``` -Batched. Status is free text (max 50 chars) and moves no funds; convention is `pending → in_progress → completed`. `newEvidence` is optional, max 500 chars. +Batched. Status is free text (max 50 chars) and moves no funds; convention is `pending → in_progress → completed`. `newEvidence` is optional, max 500 chars. Updates are **rejected once the escrow is `released` or its dispute `resolved`** (`EscrowAlreadyReleased` = 16 / `EscrowAlreadyResolved` = 17); they stay allowed while a dispute is open. ## Approve milestones diff --git a/trustless-work-dev/skills/protocol/v1.md b/trustless-work-dev/skills/protocol/v1.md index 07ffd9f..2d3efe8 100644 --- a/trustless-work-dev/skills/protocol/v1.md +++ b/trustless-work-dev/skills/protocol/v1.md @@ -52,7 +52,7 @@ Actors without a role slot: - **Before funding — Multi Release:** the platform may update escrow properties subject to the validator; existing milestone flags must be preserved, and any newly appended milestone must start with all milestone flags false. - **After funding — both V1 types:** existing escrow properties and existing milestones are frozen. The only permitted structural change is appending new milestones that satisfy the initial/unset flag requirements. **Existing approved milestones do not by themselves prevent appending new milestones** as long as the funded escrow's existing state is preserved. -4. **[ENFORCED]** Completion ≠ approval: the `serviceProvider` marking a milestone complete moves no funds. Only the `approver` role assignment's separate approval satisfies the approval precondition. +4. **[ENFORCED]** Completion ≠ approval: the `serviceProvider` marking a milestone complete moves no funds. Only the `approver` role assignment's separate approval satisfies the approval precondition. Status/evidence updates stay allowed while a dispute is open (fresh evidence can help resolve it) but are rejected once the state is terminal — single-release: escrow `released`/`resolved` (`EscrowAlreadyReleased`/`EscrowAlreadyResolved`); multi-release: that milestone `released`/`resolved` (`MilestoneAlreadyReleased`/`MilestoneAlreadyResolved`). Added to the V1 lineage on 2026-09-15 (commits `22a0b23` single / `887182a` multi); deployments predating them still accept these updates. 5. **[ENFORCED]** Single-release: **all** milestones must be approved and no dispute active before `release-funds`; the contract then pays out the **configured escrow amount** minus fees in one payment (release requires the contract balance to cover it — payouts are computed from `escrow.amount`, not from arbitrary excess balance). diff --git a/trustless-work-dev/skills/protocol/v2.md b/trustless-work-dev/skills/protocol/v2.md index c790ddc..0c79c9f 100644 --- a/trustless-work-dev/skills/protocol/v2.md +++ b/trustless-work-dev/skills/protocol/v2.md @@ -82,6 +82,11 @@ Beyond the V1 set, V2 adds: - **Appending** new milestones stays allowed after funding, until the escrow is released, disputed or resolved. Only edits to existing milestones and property updates are blocked. - All of it is `admin`-only, updates are also rejected while a dispute is open, and `admin` and `platform` are immutable from initialization. Role mistakes are not recoverable after funding. +**[ENFORCED] Milestone status/evidence lifecycle.** A service provider may update a milestone's `status`/`evidence` **while a dispute is open** — fresh evidence is deliberately allowed because it can help resolve the dispute — but updates are rejected once the state is terminal: + +- Single-release rejects when the **escrow** is `released` or its dispute `resolved` (`MilestoneError::EscrowAlreadyReleased` = 16 / `EscrowAlreadyResolved` = 17). +- Multi-release rejects per **milestone** once it is `released` or its dispute `resolved` (`MilestoneError::MilestoneAlreadyReleased` = 16 / `MilestoneAlreadyResolved` = 17). + **[ENFORCED] `withdraw-remaining-funds`** narrows the V1 precondition. "Fully processed" in V2 means: - **Single Release:** `released || dispute.resolved`.