Deep Dive

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.

1
AUTO-RESOLUTION~seconds
  • Both breach → MUTUAL_RELEASE
  • Defendant-only breach → FULL_REFUND capped at damages
  • Unclear → escalate
escalate
2
VRF ARBITRATIONcommittee of 3
  • 3 arbitrators selected via VRF
  • Confidence-weighted voting
  • 72-hour evidence window
appeal
3
APPEALfinal & binding
  • New committee, doubled size
  • Higher reputation threshold
  • Decision is final and binding
Auto-resolution rules
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 None

State machine

Seven states, zero ambiguity

Every dispute follows a deterministic state machine. Transitions are immutable, signed, and logged to the append-only ledger.

FILED
EVIDENCE_COLLECTION
AUTO_RESOLUTION
ARBITRATION
APPEAL
RESOLVED
DISMISSED
DisputeState transitions
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.

1
Hash Inputdispute_id ‖ filed_at
2
VRF ComputeVRF(sk, input) → (out, proof)
3
FilterExclude parties · rep ≥ 0.5
4
WeightScore by reputation
5
SelectTop 3 candidates

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.

VRF arbitrator 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]], proof

Decision 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

A
FULL_REFUND · $1,0000.9
B
FULL_REFUND · $8500.7
C
PARTIAL_REFUND · $4000.6

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 })

Confidence-weighted resolve
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.

1
Domain Separation

AEOS/evidence-data/ and AEOS/evidence-sign/ prevent cross-context hash collisions.

2
Pedersen Commitment

C = gᵛ · hʳ — perfectly hiding under uniform randomness, computationally binding.

3
Merkle Accumulator

Insert commitment into the evidence tree. O(log n) inclusion proofs for any entry.

4
Timestamped Seal

Immutable entry: { commitment, proof_path, timestamp, signature }.

Evidence.create()
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,
        )
Merkle evidence tree
           ┌──────────┐
           │ 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

Default deadline
72hours per phase

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.

Auto-escalation logic
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()))