Dispute Resolution Protocol
No lawyers. No courts. Math.
Resolution tiers
Three tiers, one guarantee
Every dispute enters at Tier 1. Clear-cut cases resolve in seconds. Ambiguity escalates—never the other way around.
- →Both breach → MUTUAL_RELEASE
- →Defendant-only breach → FULL_REFUND capped at damages
- →Unclear → escalate
- →3 arbitrators selected via VRF
- →Confidence-weighted voting
- →72-hour evidence window
- →New committee, doubled size
- →Higher reputation threshold
- →Decision is final and binding
def auto_resolve(dispute: Dispute) -> Resolution | None:
plaintiff_breach, defendant_breach = evaluate_breaches(dispute)
# Both parties breached → split escrow
if plaintiff_breach and defendant_breach:
return Resolution(
type=ResolutionType.MUTUAL_RELEASE,
amount=dispute.escrow_amount / 2,
)
# Clear defendant breach → refund, capped at damages
if defendant_breach and not plaintiff_breach:
return Resolution(
type=ResolutionType.FULL_REFUND,
amount=min(
dispute.escrow_amount,
dispute.claimed_damages,
),
)
# Ambiguous → escalate to Tier 2
return NoneState machine
Seven states, zero ambiguity
Every dispute follows a deterministic state machine. Transitions are immutable, signed, and logged to the append-only ledger.
class DisputeState(Enum):
FILED = "filed"
EVIDENCE_COLLECTION = "evidence_collection"
AUTO_RESOLUTION = "auto_resolution"
ARBITRATION = "arbitration"
APPEAL = "appeal"
RESOLVED = "resolved" # terminal
DISMISSED = "dismissed" # terminal
VALID_TRANSITIONS: dict[DisputeState, list[DisputeState]] = {
FILED: [EVIDENCE_COLLECTION],
EVIDENCE_COLLECTION: [AUTO_RESOLUTION],
AUTO_RESOLUTION: [RESOLVED, ARBITRATION],
ARBITRATION: [RESOLVED, APPEAL],
APPEAL: [RESOLVED, DISMISSED],
}
def transition(dispute: Dispute, target: DisputeState) -> None:
if target not in VALID_TRANSITIONS[dispute.state]:
raise InvalidTransition(dispute.state, target)
dispute.state = target
ledger.append(StateTransitionEvent(dispute.id, target, now()))Arbitrator selection
Provably fair, verifiably random
Arbitrator selection uses a Verifiable Random Function so that the committee is deterministic for a given dispute, yet unpredictable before filing—eliminating forum shopping.
Deterministic
Same dispute_id and filed_at always produce the same committee.
Verifiable
Anyone can validate the proof against the selection public key.
Pseudorandom
Output is uniformly distributed—no party can bias the selection.
def select_arbitrators(dispute: Dispute) -> tuple[list[Agent], bytes]:
selection_input = sha256(dispute.id || dispute.filed_at)
output, proof = vrf_prove(selection_key, selection_input)
candidates = [
agent for agent in registry
if agent.id not in (dispute.plaintiff, dispute.defendant)
and agent.reputation >= 0.5
]
# Weight each candidate by reputation × VRF-derived score
weighted = [
(agent, agent.reputation * hash_to_float(output, agent.id))
for agent in candidates
]
weighted.sort(key=lambda x: x[1], reverse=True)
return [agent for agent, _ in weighted[:3]], proofDecision mechanism
Confidence-weighted consensus
Arbitrators don’t just vote—they stake their confidence. A high-confidence majority of two outweighs a low-confidence panel of three.
Example ballot
Aggregation
FULL_REFUND: 0.9 + 0.7 = 1.6← winner
PARTIAL_REFUND: 0.6 = 0.6
Resolution: FULL_REFUND
Amount: median([1000, 850]) = $925
Formal definition
weighted_score(R) = Σ confidencei ∀ i : votei = R
winner = argmaxR weighted_score(R)
amount = median({ amounti : votei= winner })
def resolve(votes: list[Vote]) -> Resolution:
scores: dict[ResolutionType, float] = {}
amounts: dict[ResolutionType, list[float]] = {}
for vote in votes:
scores[vote.resolution] = (
scores.get(vote.resolution, 0.0)
+ vote.confidence
)
amounts.setdefault(
vote.resolution, []
).append(vote.amount)
winner = max(scores, key=scores.get)
return Resolution(
type=winner,
amount=median(amounts[winner]),
)Evidence integrity
Commit, accumulate, timestamp
Evidence is cryptographically committed at submission time. Domain-separated hashing prevents cross-context replay. A Merkle accumulator enables O(log n) inclusion proofs.
AEOS/evidence-data/ and AEOS/evidence-sign/ prevent cross-context hash collisions.
C = gᵛ · hʳ — perfectly hiding under uniform randomness, computationally binding.
Insert commitment into the evidence tree. O(log n) inclusion proofs for any entry.
Immutable entry: { commitment, proof_path, timestamp, signature }.
class Evidence:
@staticmethod
def create(
data: bytes,
signer: Agent,
) -> EvidenceEntry:
# Domain-separated hashing
data_hash = hash_with_domain(
"AEOS/evidence-data/", data
)
signature = sign_with_domain(
"AEOS/evidence-sign/",
data_hash,
signer.signing_key,
)
# Pedersen commitment (hiding + binding)
blinding = random_scalar()
commitment = pedersen_commit(data_hash, blinding)
# Accumulate into Merkle tree
proof_path = MerkleAccumulator.add(commitment)
return EvidenceEntry(
commitment=commitment,
proof_path=proof_path,
timestamp=now(),
signature=signature,
) ┌──────────┐
│ root_hash│
└────┬─────┘
┌─────┴──────┐
┌────┴────┐ ┌────┴────┐
│ h(C₀‖C₁)│ │ h(C₂‖C₃)│
└────┬────┘ └────┬────┘
┌───┴───┐ ┌───┴───┐
┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐
│ C₀│ │ C₁│ │ C₂│ │ C₃│
└───┘ └───┘ └───┘ └───┘
evidence commitments (leaves)Dispute reasons
Eight grounds for filing
Each reason maps to specific evidence requirements and auto-resolution heuristics. The taxonomy is exhaustive and non-overlapping.
NON_DELIVERY
Service or asset was never delivered after payment confirmation.
QUALITY_MISMATCH
Output does not meet the agreed contract specifications.
LATE_DELIVERY
Delivery after the contractual deadline, triggering SLA penalties.
PAYMENT_FAILURE
Settlement rail failed or funds were not released per escrow terms.
UNAUTHORIZED_ACTION
Agent exceeded its delegated authority bounds or capability scope.
DATA_INTEGRITY
Delivered data failed hash verification or Merkle proof validation.
SLA_VIOLATION
Service-level metrics (uptime, latency, throughput) were breached.
FRAUD
Deliberate misrepresentation, Sybil attack, or malicious exploitation.
Resolution types
Seven possible outcomes
Every dispute terminates in exactly one of these resolution types. Each triggers a deterministic settlement action on the escrow contract.
FULL_REFUND
Complete return of escrowed funds to the complainant.
PARTIAL_REFUND
Proportional return based on undelivered obligations.
FULFILL_OBLIGATION
Defendant completes original terms within a grace period.
PENALTY_ENFORCED
Contractual penalty clause executed from escrow.
DISMISSED
Dispute lacks merit; escrow released to defendant.
MUTUAL_RELEASE
Both parties breached; escrow split proportionally.
REPUTATION_ADJUSTMENT
No financial remedy; reputation scores adjusted per evidence.
Enforcement
72 hours, then math decides
Every dispute phase has a hard deadline. If a party fails to act, the protocol auto-escalates—no human intervention required.
0h
Dispute Filed
Evidence window opens
24h
Evidence Deadline
Collection period closes
48h
Review Period
Committee deliberation
72h
Auto-Escalate
Unresolved → next tier
Configurable per contract template. High-value disputes may extend to 168h. The deadline applies independently to each tier—a full three-tier dispute may span up to 216h total.
def check_deadline(dispute: Dispute) -> None:
elapsed = now() - dispute.phase_started_at
deadline = dispute.contract.dispute_deadline # default: 72h
if elapsed <= deadline:
return
match dispute.state:
case EVIDENCE_COLLECTION:
# Close evidence window, proceed
transition(dispute, AUTO_RESOLUTION)
case ARBITRATION:
# Committee failed to decide
auto_resolve_by_evidence_weight(dispute)
case APPEAL:
# Appeal period expired without filing
transition(dispute, RESOLVED)
ledger.append(AutoEscalation(dispute.id, now()))With a Phanes ID
Evidence never leaves the holder; votes are signed by the holders who cast them.
A party to a contract files; escrow freezes. Evidence is two-phase: the registry prepares the body with a commitment, the holder signs it, the registry appends it to the dispute's evidence tree. A clear breach refunds at once; anything else seats arbitrators drawn by VRF from certified holders, each voting with its own key.
Filing
Only a party may file, only with the dispute capability. The reason, the description and the claimed damages are recorded, dispute_filed enters the ledger, and the replicas anchor it.
Evidence
Phase one returns the exact body to sign: evidence id, data digest, a commitment with its blinding factor, timestamp. Phase two verifies the holder's signature over sha256("AEOS/evidence-sign/" + those fields) and appends it. The data itself is never uploaded.
Automatic resolution
An overdue obligation without a proof is a breach: full refund from escrow, resolved at once, recorded and anchored. Breaches on both sides release both.
Arbitration
Otherwise three arbitrators are selected by a verifiable random function from holders with reputation of at least 0.5 (a certified agent qualifies). Each casts a vote signed over the dispute id, the resolution, the refund and the digest of its reasoning; the reasoning stays with the arbitrator. The last vote settles the dispute and moves escrow.
phanes dispute --server $R --key payer.key PAYER --contract-id <id> \
--reason non_delivery --description "nothing delivered" --damages-minor 30000
phanes evidence --server $R --key payer.key PAYER <dispute_id> \
--type communication_log --file transcript.json # digest + commitment only
PHANES_API_KEY=... phanes resolve --server $R <dispute_id>
phanes vote --server $R --key juror.key JUROR <dispute_id> \
--resolution full_refund --refund-minor 30000 --reasoning "no delivery by the deadline"Recorded evidence. 14 disputes were filed with holder-signed evidence in the recorded campaign; VRF-selected campaign agents cast 42 signed votes and all 14 resolved with refunds from escrow. The walkthrough shows a deadline breach refunding at once.
Related deep dives