diff --git a/README.md b/README.md index 945e9db..6744811 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ This repository contains the design specifications and implementation plans for +- [m009 — Service Provision Escrow](mechanisms/m009-service-escrow/) - [m010 — Reputation Signal (v0 advisory)](mechanisms/m010-reputation-signal/) diff --git a/docs/MECHANISM_CONSUMERS.md b/docs/MECHANISM_CONSUMERS.md index abd7745..e2d05f7 100644 --- a/docs/MECHANISM_CONSUMERS.md +++ b/docs/MECHANISM_CONSUMERS.md @@ -18,3 +18,23 @@ This document maps **mechanism IDs** to known **consumers** (agents, digests, sc - Heartbeat replay runner: `scripts/replay-m010.mjs` (regen-heartbeat) - Heartbeat stub runner: `scripts/stub-run-signal-agent.mjs` (regen-heartbeat) - Heartbeat validator: `scripts/validate-signal-agent.mjs` (regen-heartbeat) + +## m009 — Service Provision Escrow +**Canonical spec** +- `mechanisms/m009-service-escrow/SPEC.md` + +**Outputs** +- KPI JSON block schema: `mechanisms/m009-service-escrow/schemas/m009_kpi.schema.json` +- Milestone review schema: `mechanisms/m009-service-escrow/schemas/m009_milestone_review.schema.json` +- Agreement lifecycle schema: `mechanisms/m009-service-escrow/schemas/m009_agreement.schema.json` + +**Datasets (deterministic)** +- Replay fixtures: `mechanisms/m009-service-escrow/datasets/fixtures/v0_sample.json` +- Dispute scenarios: `mechanisms/m009-service-escrow/datasets/fixtures/v0_dispute_sample.json` + +**Known consumers** +- Heartbeat character: `escrow-agent` (regen-heartbeat, planned) +- AGENT-001: Milestone deliverable review (advisory) +- AGENT-003: Pricing fairness monitor (advisory) +- KOI MCP: deliverable IRI resolution via `resolve_entity` / `get_entity_documents` +- Ledger MCP: escrow balance queries via `get_balance` / `get_all_balances` diff --git a/mechanisms/m009-service-escrow/README.md b/mechanisms/m009-service-escrow/README.md new file mode 100644 index 0000000..27a6f9b --- /dev/null +++ b/mechanisms/m009-service-escrow/README.md @@ -0,0 +1,34 @@ +# m009 — Service Provision Escrow + +Trustless milestone-based escrow for ecosystem services (verification, monitoring, methodology development) with agent-assisted deliverable review and dispute resolution. + +## What it outputs + +- **Milestone review score** (0–1000): 4-factor weighted assessment of deliverable quality (quality 0.40, evidence 0.25, consistency 0.20, reputation 0.15) +- **Confidence** (0–1000): Data availability across deliverable, reputation, prior milestones, and spec access +- **Recommendation**: APPROVE / NEEDS_REVISION / FLAG_FOR_CLIENT +- **KPI block**: Agreement counts by status, milestone approval rate, dispute rate, escrow economics, average completion time + +## What it does not do in v0 + +- No on-chain escrow contract (payments are off-chain or manual) +- No automated milestone payment release +- No dispute resolution (Arbiter DAO integration is v1/v2) +- Agent scores are advisory only — clients make final approval decisions + +## Scoring formula + +``` +score = 0.40 × deliverable_quality + 0.25 × evidence_completeness + 0.20 × milestone_consistency + 0.15 × provider_reputation +``` + +## How to reference + +- **Canonical spec**: `mechanisms/m009-service-escrow/SPEC.md` +- **Schemas**: `mechanisms/m009-service-escrow/schemas/` +- **Reference implementation**: `mechanisms/m009-service-escrow/reference-impl/` + +## Replay datasets + +- `datasets/fixtures/v0_sample.json` — Five service agreements across standard service types +- `datasets/fixtures/v0_dispute_sample.json` — Dispute resolution scenarios diff --git a/mechanisms/m009-service-escrow/SPEC.md b/mechanisms/m009-service-escrow/SPEC.md new file mode 100644 index 0000000..f95a57d --- /dev/null +++ b/mechanisms/m009-service-escrow/SPEC.md @@ -0,0 +1,286 @@ +# M009 — Service Provision Escrow + +## 0. Header + +| Field | Value | +|-------|-------| +| **Mechanism ID** | m009 | +| **Name** | Service Provision Escrow | +| **Status** | Draft — v0 advisory | +| **Owner** | Regen Network core / community | +| **Scope** | Ecosystem services (verification, monitoring, methodology development) with milestone-based payment release | + +--- + +## 1. Problem + +Ecosystem service engagements (project verification, MRV setup, methodology development) lack trustless payment coordination. Providers risk non-payment after delivery; clients risk paying for incomplete or substandard work. Without milestone-based escrow and dispute resolution, participants rely on informal agreements with no recourse mechanism. This limits the growth of the service marketplace and concentrates work among a small set of trusted providers. + +--- + +## 2. Target actor and action + +| Actor | Action | +|-------|--------| +| **Client** | Proposes service agreement with milestones and funds escrow | +| **Provider** | Accepts agreement, posts service bond, delivers milestone work | +| **AGENT-001** | Reviews milestone deliverables (evidence quality, compliance) | +| **AGENT-003** | Monitors pricing fairness and provider reliability | +| **Arbiter DAO** | Resolves disputes between client and provider (via M008) | + +--- + +## 3. Signal definition + +### Milestone Review Score (v0 advisory) + +The agent produces a quality assessment for each milestone deliverable: + +| Field | Type | Range | Description | +|-------|------|-------|-------------| +| `score` | integer | 0–1000 | Weighted composite of deliverable quality factors | +| `confidence` | integer | 0–1000 | Data availability indicator | +| `recommendation` | enum | APPROVE / NEEDS_REVISION / FLAG_FOR_CLIENT | Agent recommendation | +| `factors` | object | — | Individual factor scores | + +--- + +## 4. Evidence inputs + +| Input | Source | Required | +|-------|--------|----------| +| Milestone deliverable IRI | Provider submission (KOI) | Yes | +| Service agreement spec | Agreement metadata | Yes | +| Prior milestone deliverables | Agreement history | If applicable | +| Provider reputation score | M010 reputation signal | Preferred | +| Market rate data | AGENT-003 pricing monitor | Optional | +| Methodology compliance checklist | Credit class requirements | If verification service | + +--- + +## 5. Scoring function + +### Milestone review score + +``` +score = 0.40 × deliverable_quality + + 0.25 × evidence_completeness + + 0.20 × milestone_consistency + + 0.15 × provider_reputation +``` + +| Factor | Weight | Description | Range | +|--------|--------|-------------|-------| +| `deliverable_quality` | 0.40 | Methodology compliance, technical quality | 0–1000 | +| `evidence_completeness` | 0.25 | Evidence IRI resolves, documents complete | 0–1000 | +| `milestone_consistency` | 0.20 | Consistency with prior milestones and agreement spec | 0–1000 | +| `provider_reputation` | 0.15 | M010 reputation of provider (default 300 if unavailable) | 0–1000 | + +All factors are clamped to [0, 1000]. Final score is rounded to the nearest integer. + +### Confidence + +Confidence reflects data availability across four boolean signals: + +| Signal | Check | +|--------|-------| +| `reputation_available` | Provider has M010 reputation score | +| `iri_resolvable` | Deliverable IRI resolves to content | +| `has_prior_milestones` | Agreement has at least one prior approved milestone | +| `spec_available` | Agreement spec is available for compliance check | + +`confidence = round(count(true signals) / 4 × 1000)` + +### Recommendation + +| Condition | Recommendation | +|-----------|---------------| +| `score >= 700 AND confidence >= 750` | APPROVE | +| `score < 400 OR confidence < 250` | FLAG_FOR_CLIENT | +| Otherwise | NEEDS_REVISION | + +--- + +## 6. State machine + +### Agreement lifecycle + +``` +PROPOSED → FUNDED → IN_PROGRESS → MILESTONE_REVIEW → IN_PROGRESS (next milestone) + → DISPUTED → RESOLVED + → COMPLETED + → CANCELLED (from PROPOSED or FUNDED) +``` + +| Transition | Trigger | Guard | +|------------|---------|-------| +| → PROPOSED | `client.propose_service(spec, milestones, escrow)` | 1 ≤ milestones ≤ 20, sum(payments) = escrow | +| PROPOSED → FUNDED | `provider.accept(bond) AND client.fund(escrow)` | provider reputation ≥ min, bond ≥ escrow × bond_ratio | +| PROPOSED → CANCELLED | `client.cancel() OR provider.reject() OR timeout(acceptance_window)` | state = PROPOSED | +| FUNDED → IN_PROGRESS | `start_date_reached OR both_parties_confirm` | — | +| FUNDED → CANCELLED | `client.cancel() OR mutual_cancel()` | cancellation fee applied | +| IN_PROGRESS → MILESTONE_REVIEW | `provider.submit_deliverable(milestone_id, evidence_iri)` | milestone is current, status = IN_PROGRESS | +| MILESTONE_REVIEW → IN_PROGRESS | `client.approve_milestone(milestone_id)` | payment released to provider | +| MILESTONE_REVIEW → DISPUTED | `client.dispute(milestone_id, reason) OR timeout(review_period)` | milestone status = PENDING_REVIEW | +| MILESTONE_REVIEW → MILESTONE_REVIEW | `provider.revise(milestone_id, new_iri)` | revision_count < max_revisions | +| DISPUTED → RESOLVED | `arbiter.resolve(resolution_type, rationale)` | arbiter assigned, deadline not expired | +| RESOLVED → IN_PROGRESS | `both_parties_confirm_continuation` | resolution ≠ CLIENT_WINS, remaining milestones > 0 | +| RESOLVED → COMPLETED | `CLIENT_WINS OR no remaining milestones OR mutual termination` | — | +| IN_PROGRESS → COMPLETED | `all_milestones_approved` | bond refund, platform fee | + +### Milestone lifecycle + +``` +PENDING → IN_PROGRESS → SUBMITTED → APPROVED + → DISPUTED + → REVISED → SUBMITTED (re-review) +``` + +--- + +## 7. Token flows + +### Escrow funding + +``` +Client ──(escrow_amount)──→ Escrow Contract +Provider ──(service_bond)──→ Escrow Contract (bond = escrow × provider_bond_ratio) +``` + +### Milestone approval + +``` +Escrow Contract ──(milestone.payment − platform_fee)──→ Provider +Escrow Contract ──(platform_fee)──→ Community Pool (fee = 1% of milestone payment) +``` + +### Completion + +``` +Escrow Contract ──(service_bond)──→ Provider (bond refund) +Escrow Contract ──(completion_fee)──→ Community Pool (fee = 1% of total escrow) +``` + +### Cancellation (pre-start, from FUNDED) + +``` +Escrow Contract ──(escrow − cancellation_fee)──→ Client +Escrow Contract ──(service_bond)──→ Provider (full bond refund) +Escrow Contract ──(cancellation_fee)──→ Community Pool (fee = 2% of escrow) +``` + +### Dispute resolutions + +| Outcome | Client receives | Provider receives | Community pool | +|---------|----------------|-------------------|----------------| +| **CLIENT_WINS** | disputed_milestone_amount − arbiter_fee | 0 (bond slashed: 50% client, 50% pool) | 50% of bond + arbiter_fee | +| **PROVIDER_WINS** | 0 | disputed_milestone_amount + bond − arbiter_fee | arbiter_fee | +| **SPLIT(X%)** | X% of disputed_milestone_amount − arbiter_fee share | (100−X)% of disputed_milestone_amount + bond − arbiter_fee share | arbiter_fee | + +> **NOTE**: "disputed_milestone_amount" refers to the payment allocated to the +> disputed milestone only, NOT the entire remaining contract escrow. Funds for +> future uncompleted milestones remain in escrow. If the agreement continues +> after resolution (e.g., PROVIDER_WINS with remaining milestones), it +> transitions back to IN_PROGRESS. If terminated, remaining escrow is returned +> to the client minus any applicable fees. + +### Governance parameters + +| Parameter | Default | Range | +|-----------|---------|-------| +| `provider_bond_ratio` | 10% (1000 bps) | 5–25% | +| `platform_fee_rate` | 1% (100 bps) | 0–5% | +| `cancellation_fee_rate` | 2% (200 bps) | 0–10% | +| `min_provider_reputation` | 100 | 0–500 | +| `acceptance_window` | 7 days | 1–30 days | +| `max_revisions` | 3 | 1–10 | +| `arbiter_fee_rate` | 5% of disputed amount | 1–15% | +| `default_review_period` | 14 days | 3–30 days | + +--- + +## 8. Standard service types + +| Service Type | Typical Escrow (REGEN) | Milestones | Review Period | Min Provider Reputation | +|--------------|----------------------|------------|---------------|------------------------| +| Project Verification | 2,000–10,000 | 3–5 | 14 days | 200 | +| Methodology Development | 10,000–50,000 | 5–10 | 21 days | 400 | +| MRV Setup | 5,000–20,000 | 4–6 | 14 days | 300 | +| Credit Issuance Support | 1,000–5,000 | 2–3 | 7 days | 100 | +| Monitoring & Reporting | 500–3,000 | 1–3 | 7 days | 100 | + +--- + +## 9. Security invariants + +1. **Escrow Conservation**: `escrow.balance = escrow_amount − sum(approved_milestone_payments) − sum(platform_fees) − sum(dispute_settlements)` at all times. +2. **Bond Integrity**: Provider bond is locked for the entire agreement lifetime and can only be released on COMPLETED or refunded on specific CANCELLED/RESOLVED transitions. +3. **Milestone Payment Bound**: `sum(milestone.payments) == escrow_amount` — no milestone can pay more than its defined amount, and the sum exactly equals the escrowed amount. +4. **Sequential Milestones**: Only `milestone[current_milestone]` can be submitted; milestones must be approved in order. +5. **Arbiter Neutrality**: Dispute arbiter cannot be client, provider, or any address that has transacted with either party within 90 days (M008 Arbiter DAO conflict checks). +6. **No Double Settlement**: A dispute can only be resolved once; resolved agreements cannot be re-disputed on the same milestone. +7. **Cancellation Guard**: FUNDED agreements incur cancellation fee; IN_PROGRESS agreements cannot be unilaterally cancelled (must dispute or mutually agree). +8. **Timeout Escalation**: If `review_period` expires without client action, the milestone auto-enters DISPUTED state to prevent indefinite blocking. + +--- + +## 10. Attack model + +| Attack | Mitigation | +|--------|-----------| +| **Client stalls review** | Timeout auto-escalates to DISPUTED after review_period | +| **Provider submits garbage** | Agent flags low-quality deliverables; client disputes; arbiter slashes bond | +| **Sybil providers** | min_provider_reputation gate (M010) prevents new accounts from accepting | +| **Arbiter collusion** | Arbiter DAO rotation, conflict-of-interest checks, bond at stake (M008) | +| **Escrow drain via fake milestones** | sum(milestone.payments) must equal escrow_amount, sequential approval | +| **Price manipulation** | AGENT-003 monitors market rates, flags outlier pricing (z-score > 2.5) | +| **Cancellation arbitrage** | Cancellation fee (2%) disincentivizes frequent propose-cancel cycles | +| **Revision spam** | max_revisions cap prevents indefinite revision loops | + +--- + +## 11. Integration points + +| System | Integration | +|--------|-------------| +| **M008 Arbiter DAO** | Dispute resolution — arbiter assignment, resolution enforcement | +| **M010 Reputation** | Provider reputation gate for acceptance; reputation update on completion | +| **M013 Fee Routing** | Platform fees follow M013 distribution model (when activated) | +| **KOI MCP** | Deliverable IRI resolution via `resolve_entity` / `get_entity_documents` | +| **Ledger MCP** | Escrow balance queries via `get_balance` / `get_all_balances` | +| **x/ecocredit** | Credit-related services link to credit class and project metadata | +| **Heartbeat** | KPI metrics published in weekly digest | + +--- + +## 12. Acceptance tests + +1. **Happy path**: Client proposes → provider accepts → fund → 3 milestones approved → completed → bond refunded → platform fee collected. +2. **Cancellation (pre-start)**: Client proposes → funds → cancels before start → escrow minus 2% returned → bond refunded. +3. **Dispute — client wins**: Milestone submitted → client disputes → arbiter rules CLIENT_WINS → provider bond slashed → client receives remaining escrow. +4. **Dispute — provider wins**: Milestone submitted → client disputes → arbiter rules PROVIDER_WINS → provider receives escrow + bond. +5. **Dispute — split**: Arbiter rules SPLIT(60%) → client gets 60%, provider gets 40% + bond. +6. **Revision cycle**: Provider submits → provider revises (up to max_revisions) → client approves. +7. **Timeout escalation**: Provider submits → review_period expires → auto-DISPUTED. +8. **Agent advisory**: Milestone submitted → AGENT-001 scores deliverable → recommendation published → client acts on recommendation. +9. **Reputation gate**: Provider with reputation below min_provider_reputation cannot accept agreement. + +--- + +## 13. Rollout plan + +| Phase | Scope | Dependencies | +|-------|-------|-------------| +| **v0 (advisory)** | Agent scores milestone deliverables off-chain; KPI metrics in digest. No on-chain escrow. | M010 (reputation), KOI MCP | +| **v1 (on-chain escrow)** | CosmWasm `service-escrow` contract with milestone payments, bond lock, cancellation. Agent gating on acceptance. | M008 (arbiter), M010, DAO DAO | +| **v2 (full dispute)** | Arbiter DAO dispute resolution integrated. AGENT-003 pricing monitor. M013 fee routing. | M008, M013, M014 (optional) | + +--- + +## Appendix: Source anchors + +| Document | Section | +|----------|---------| +| `phase-2/2.1-token-utility-mechanisms.md` | M009 Service Provision Escrow (lines 274–531) | +| `phase-3/3.1-smart-contract-specs.md` | CosmWasm Contract: Service Escrow (lines 710–855) | +| `phase-2/2.3-governance-processes.md` | GOV-002 (Parameter Changes) for governance params | diff --git a/mechanisms/m009-service-escrow/datasets/README.md b/mechanisms/m009-service-escrow/datasets/README.md new file mode 100644 index 0000000..ae9eb37 --- /dev/null +++ b/mechanisms/m009-service-escrow/datasets/README.md @@ -0,0 +1,11 @@ +# m009 replay datasets + +Fixture files for replay testing of m009 (Service Provision Escrow) computations. + +## Files +- `schema.json` — JSON Schema for the replay dataset format. +- `fixtures/v0_sample.json` — Five service agreements across all standard service types, with milestone review scores matching reference-impl output. Includes IN_PROGRESS, MILESTONE_REVIEW, COMPLETED, CANCELLED, and PROPOSED statuses. +- `fixtures/v0_dispute_sample.json` — Four agreements covering dispute resolution scenarios: DISPUTED (pending), RESOLVED/CLIENT_WINS, RESOLVED/PROVIDER_WINS, and RESOLVED/SPLIT. + +## Usage +Feed fixture files into `m009_kpi.js` to verify KPI computation. Review scores in fixtures correspond to `m009_score.js` output for the matching factor inputs. diff --git a/mechanisms/m009-service-escrow/datasets/fixtures/v0_dispute_sample.json b/mechanisms/m009-service-escrow/datasets/fixtures/v0_dispute_sample.json new file mode 100644 index 0000000..6c66287 --- /dev/null +++ b/mechanisms/m009-service-escrow/datasets/fixtures/v0_dispute_sample.json @@ -0,0 +1,164 @@ +{ + "mechanism_id": "m009", + "scope": "v0_advisory", + "as_of": "2026-02-18T12:00:00Z", + "agreements": [ + { + "agreement_id": "agr-d01", + "client": "regen1clientd01", + "provider": "regen1providerd01", + "service_type": "ProjectVerification", + "escrow_amount": { "amount": "8000000", "denom": "uregen" }, + "provider_bond": { "amount": "800000", "denom": "uregen" }, + "milestones": [ + { + "index": 0, + "description": "Desktop review", + "payment": { "amount": "2000000", "denom": "uregen" }, + "status": "APPROVED", + "deliverable_iri": "koi://deliverable/desktop-review-d01", + "review_score": 750 + }, + { + "index": 1, + "description": "Field visit report", + "payment": { "amount": "3000000", "denom": "uregen" }, + "status": "DISPUTED", + "deliverable_iri": "koi://deliverable/field-visit-d01-incomplete", + "review_score": 320 + }, + { + "index": 2, + "description": "Final verification report", + "payment": { "amount": "3000000", "denom": "uregen" }, + "status": "PENDING", + "deliverable_iri": null, + "review_score": null + } + ], + "status": "DISPUTED", + "created_at": "2025-11-01T10:00:00Z", + "completed_at": null, + "dispute": { + "reason": "Field visit report missing soil sample analysis required by methodology", + "resolution": null + } + }, + { + "agreement_id": "agr-d02", + "client": "regen1clientd02", + "provider": "regen1providerd02", + "service_type": "MethodologyDevelopment", + "escrow_amount": { "amount": "30000000", "denom": "uregen" }, + "provider_bond": { "amount": "3000000", "denom": "uregen" }, + "milestones": [ + { + "index": 0, + "description": "Literature review", + "payment": { "amount": "6000000", "denom": "uregen" }, + "status": "APPROVED", + "deliverable_iri": "koi://deliverable/lit-review-d02", + "review_score": 810 + }, + { + "index": 1, + "description": "Draft methodology", + "payment": { "amount": "12000000", "denom": "uregen" }, + "status": "DISPUTED", + "deliverable_iri": "koi://deliverable/draft-methodology-d02-plagiarized", + "review_score": 180 + }, + { + "index": 2, + "description": "Final methodology", + "payment": { "amount": "12000000", "denom": "uregen" }, + "status": "PENDING", + "deliverable_iri": null, + "review_score": null + } + ], + "status": "RESOLVED", + "created_at": "2025-09-15T09:00:00Z", + "completed_at": "2026-01-10T14:00:00Z", + "dispute": { + "reason": "Draft methodology contains plagiarized content from published methodology without attribution", + "resolution": "CLIENT_WINS" + } + }, + { + "agreement_id": "agr-d03", + "client": "regen1clientd03", + "provider": "regen1providerd03", + "service_type": "MRVSetup", + "escrow_amount": { "amount": "15000000", "denom": "uregen" }, + "provider_bond": { "amount": "1500000", "denom": "uregen" }, + "milestones": [ + { + "index": 0, + "description": "Sensor deployment plan", + "payment": { "amount": "5000000", "denom": "uregen" }, + "status": "APPROVED", + "deliverable_iri": "koi://deliverable/sensor-plan-d03", + "review_score": 870 + }, + { + "index": 1, + "description": "Installation and calibration", + "payment": { "amount": "5000000", "denom": "uregen" }, + "status": "DISPUTED", + "deliverable_iri": "koi://deliverable/calibration-report-d03", + "review_score": 450 + }, + { + "index": 2, + "description": "Dashboard and handoff", + "payment": { "amount": "5000000", "denom": "uregen" }, + "status": "PENDING", + "deliverable_iri": null, + "review_score": null + } + ], + "status": "IN_PROGRESS", + "created_at": "2025-10-20T11:00:00Z", + "completed_at": null, + "dispute": { + "reason": "Calibration data shows sensor drift beyond acceptable tolerance", + "resolution": "PROVIDER_WINS", + "note": "Provider won dispute on milestone 1; agreement continues with remaining milestone 2" + } + }, + { + "agreement_id": "agr-d04", + "client": "regen1clientd04", + "provider": "regen1providerd04", + "service_type": "CreditIssuanceSupport", + "escrow_amount": { "amount": "4000000", "denom": "uregen" }, + "provider_bond": { "amount": "400000", "denom": "uregen" }, + "milestones": [ + { + "index": 0, + "description": "Credit documentation", + "payment": { "amount": "2000000", "denom": "uregen" }, + "status": "APPROVED", + "deliverable_iri": "koi://deliverable/credit-docs-d04", + "review_score": 680 + }, + { + "index": 1, + "description": "Issuance execution", + "payment": { "amount": "2000000", "denom": "uregen" }, + "status": "DISPUTED", + "deliverable_iri": "koi://deliverable/issuance-d04-partial", + "review_score": 400 + } + ], + "status": "RESOLVED", + "created_at": "2025-12-01T08:00:00Z", + "completed_at": "2026-02-05T10:00:00Z", + "dispute": { + "reason": "Issuance only covered 60% of agreed credit batch scope", + "resolution": "SPLIT" + } + } + ] +} diff --git a/mechanisms/m009-service-escrow/datasets/fixtures/v0_sample.json b/mechanisms/m009-service-escrow/datasets/fixtures/v0_sample.json new file mode 100644 index 0000000..eba2f51 --- /dev/null +++ b/mechanisms/m009-service-escrow/datasets/fixtures/v0_sample.json @@ -0,0 +1,189 @@ +{ + "mechanism_id": "m009", + "scope": "v0_advisory", + "as_of": "2026-02-18T12:00:00Z", + "agreements": [ + { + "agreement_id": "agr-001", + "client": "regen1client01", + "provider": "regen1provider01", + "service_type": "ProjectVerification", + "escrow_amount": { "amount": "5000000", "denom": "uregen" }, + "provider_bond": { "amount": "500000", "denom": "uregen" }, + "milestones": [ + { + "index": 0, + "description": "Desktop review of project documentation", + "payment": { "amount": "1500000", "denom": "uregen" }, + "status": "APPROVED", + "deliverable_iri": "koi://deliverable/desktop-review-plot-42", + "review_score": 783 + }, + { + "index": 1, + "description": "Field visit and site inspection", + "payment": { "amount": "2000000", "denom": "uregen" }, + "status": "APPROVED", + "deliverable_iri": "koi://deliverable/field-visit-report-plot-42", + "review_score": 770 + }, + { + "index": 2, + "description": "Final verification report", + "payment": { "amount": "1500000", "denom": "uregen" }, + "status": "IN_PROGRESS", + "deliverable_iri": null, + "review_score": null + } + ], + "status": "IN_PROGRESS", + "created_at": "2026-01-05T10:00:00Z", + "completed_at": null, + "dispute": null + }, + { + "agreement_id": "agr-002", + "client": "regen1client02", + "provider": "regen1provider02", + "service_type": "MethodologyDevelopment", + "escrow_amount": { "amount": "25000000", "denom": "uregen" }, + "provider_bond": { "amount": "2500000", "denom": "uregen" }, + "milestones": [ + { + "index": 0, + "description": "Literature review and methodology framework", + "payment": { "amount": "5000000", "denom": "uregen" }, + "status": "APPROVED", + "deliverable_iri": "koi://deliverable/methodology-framework-soil-v5", + "review_score": 820 + }, + { + "index": 1, + "description": "Draft methodology document", + "payment": { "amount": "8000000", "denom": "uregen" }, + "status": "SUBMITTED", + "deliverable_iri": "koi://deliverable/methodology-draft-soil-carbon-v5", + "review_score": 550 + }, + { + "index": 2, + "description": "Peer review incorporation", + "payment": { "amount": "7000000", "denom": "uregen" }, + "status": "PENDING", + "deliverable_iri": null, + "review_score": null + }, + { + "index": 3, + "description": "Final methodology and validation report", + "payment": { "amount": "5000000", "denom": "uregen" }, + "status": "PENDING", + "deliverable_iri": null, + "review_score": null + } + ], + "status": "MILESTONE_REVIEW", + "created_at": "2025-11-15T09:00:00Z", + "completed_at": null, + "dispute": null + }, + { + "agreement_id": "agr-003", + "client": "regen1client03", + "provider": "regen1provider03", + "service_type": "MRVSetup", + "escrow_amount": { "amount": "10000000", "denom": "uregen" }, + "provider_bond": { "amount": "1000000", "denom": "uregen" }, + "milestones": [ + { + "index": 0, + "description": "Sensor deployment plan", + "payment": { "amount": "3000000", "denom": "uregen" }, + "status": "APPROVED", + "deliverable_iri": "koi://deliverable/mrv-sensor-deployment-plan", + "review_score": 903 + }, + { + "index": 1, + "description": "Sensor installation and calibration", + "payment": { "amount": "4000000", "denom": "uregen" }, + "status": "APPROVED", + "deliverable_iri": "koi://deliverable/mrv-sensor-calibration-report", + "review_score": 880 + }, + { + "index": 2, + "description": "Data pipeline and dashboard setup", + "payment": { "amount": "3000000", "denom": "uregen" }, + "status": "APPROVED", + "deliverable_iri": "koi://deliverable/mrv-dashboard-handoff", + "review_score": 910 + } + ], + "status": "COMPLETED", + "created_at": "2025-10-01T08:00:00Z", + "completed_at": "2026-01-20T16:00:00Z", + "dispute": null + }, + { + "agreement_id": "agr-004", + "client": "regen1client04", + "provider": "regen1provider04", + "service_type": "CreditIssuanceSupport", + "escrow_amount": { "amount": "3000000", "denom": "uregen" }, + "provider_bond": { "amount": "300000", "denom": "uregen" }, + "milestones": [ + { + "index": 0, + "description": "Credit batch preparation and documentation", + "payment": { "amount": "1500000", "denom": "uregen" }, + "status": "APPROVED", + "deliverable_iri": "koi://deliverable/credit-batch-docs-C04", + "review_score": 720 + }, + { + "index": 1, + "description": "Issuance execution and registry listing", + "payment": { "amount": "1500000", "denom": "uregen" }, + "status": "PENDING", + "deliverable_iri": null, + "review_score": null + } + ], + "status": "CANCELLED", + "created_at": "2026-01-10T11:00:00Z", + "completed_at": null, + "dispute": null + }, + { + "agreement_id": "agr-005", + "client": "regen1client05", + "provider": "regen1provider05", + "service_type": "MonitoringReporting", + "escrow_amount": { "amount": "1500000", "denom": "uregen" }, + "provider_bond": { "amount": "150000", "denom": "uregen" }, + "milestones": [ + { + "index": 0, + "description": "Quarterly monitoring report", + "payment": { "amount": "750000", "denom": "uregen" }, + "status": "SUBMITTED", + "deliverable_iri": "koi://deliverable/monitoring-report-q4-2025", + "review_score": 265 + }, + { + "index": 1, + "description": "Annual summary report", + "payment": { "amount": "750000", "denom": "uregen" }, + "status": "PENDING", + "deliverable_iri": null, + "review_score": null + } + ], + "status": "PROPOSED", + "created_at": "2026-02-10T14:00:00Z", + "completed_at": null, + "dispute": null + } + ] +} diff --git a/mechanisms/m009-service-escrow/datasets/schema.json b/mechanisms/m009-service-escrow/datasets/schema.json new file mode 100644 index 0000000..77c9545 --- /dev/null +++ b/mechanisms/m009-service-escrow/datasets/schema.json @@ -0,0 +1,83 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "m009_dataset_v0", + "title": "m009 replay dataset", + "description": "Replay dataset for m009 Service Provision Escrow — service agreement lifecycle records with milestones, escrow, and dispute data.", + "type": "object", + "required": ["mechanism_id", "scope", "as_of", "agreements"], + "properties": { + "mechanism_id": { "const": "m009" }, + "scope": { "type": "string" }, + "as_of": { "type": "string", "format": "date-time" }, + "agreements": { + "type": "array", + "items": { + "type": "object", + "required": ["agreement_id", "client", "provider", "service_type", "escrow_amount", "provider_bond", "milestones", "status"], + "properties": { + "agreement_id": { "type": "string" }, + "client": { "type": "string" }, + "provider": { "type": "string" }, + "service_type": { + "type": "string", + "enum": ["ProjectVerification", "MethodologyDevelopment", "MRVSetup", "CreditIssuanceSupport", "MonitoringReporting"] + }, + "escrow_amount": { + "type": "object", + "required": ["amount", "denom"], + "properties": { + "amount": { "type": "string" }, + "denom": { "type": "string" } + } + }, + "provider_bond": { + "type": "object", + "required": ["amount", "denom"], + "properties": { + "amount": { "type": "string" }, + "denom": { "type": "string" } + } + }, + "milestones": { + "type": "array", + "items": { + "type": "object", + "required": ["index", "description", "payment", "status"], + "properties": { + "index": { "type": "integer" }, + "description": { "type": "string" }, + "payment": { + "type": "object", + "required": ["amount", "denom"], + "properties": { + "amount": { "type": "string" }, + "denom": { "type": "string" } + } + }, + "status": { + "type": "string", + "enum": ["PENDING", "IN_PROGRESS", "SUBMITTED", "APPROVED", "DISPUTED", "REVISED"] + }, + "deliverable_iri": { "type": ["string", "null"] }, + "review_score": { "type": ["integer", "null"] } + } + } + }, + "status": { + "type": "string", + "enum": ["PROPOSED", "FUNDED", "IN_PROGRESS", "MILESTONE_REVIEW", "COMPLETED", "DISPUTED", "RESOLVED", "CANCELLED"] + }, + "created_at": { "type": "string", "format": "date-time" }, + "completed_at": { "type": ["string", "null"], "format": "date-time" }, + "dispute": { + "type": ["object", "null"], + "properties": { + "reason": { "type": "string" }, + "resolution": { "type": ["string", "null"], "enum": ["CLIENT_WINS", "PROVIDER_WINS", "SPLIT", null] } + } + } + } + } + } + } +} diff --git a/mechanisms/m009-service-escrow/reference-impl/README.md b/mechanisms/m009-service-escrow/reference-impl/README.md new file mode 100644 index 0000000..b9c0d68 --- /dev/null +++ b/mechanisms/m009-service-escrow/reference-impl/README.md @@ -0,0 +1,45 @@ +# m009 reference implementation (v0 advisory) + +This folder provides a **canonical computation** for m009 outputs so that different agents/runners +produce consistent numbers. + +## Inputs + +### Scoring (`m009_score.js`) +An input object per milestone deliverable: + +- `milestone` — milestone metadata: + - `agreement_id` (string) + - `milestone_index` (integer) + - `service_type` (string, one of ProjectVerification/MethodologyDevelopment/MRVSetup/CreditIssuanceSupport/MonitoringReporting) + - `deliverable_iri` (string) +- `factors` — pre-computed factor scores (each 0–1000): + - `deliverable_quality` — methodology compliance and technical quality + - `evidence_completeness` — evidence IRI resolvability and document completeness + - `milestone_consistency` — consistency with prior milestones and agreement spec + - `provider_reputation` — M010 reputation score (default 300 if unavailable) + - `reputation_available` (boolean), `iri_resolvable` (boolean), `has_prior_milestones` (boolean), `spec_available` (boolean) + +### KPI (`m009_kpi.js`) +- `as_of` (ISO-8601 string, Z-suffixed) +- `agreements[]` — each with `status`, `service_type`, `escrow_amount`, `provider_bond`, `milestones[]`, `dispute` (optional) + +## Outputs + +### Score +- `score` (0–1000) — weighted composite +- `confidence` (0–1000) — data availability +- `recommendation` — APPROVE / NEEDS_REVISION / FLAG_FOR_CLIENT +- `factors` — individual factor scores + +Formula: +``` +score = 0.40 × deliverable_quality + 0.25 × evidence_completeness + 0.20 × milestone_consistency + 0.15 × provider_reputation +``` + +### KPI block +- Agreement counts by status (proposed, funded, in_progress, completed, disputed, cancelled) +- `dispute_rate`, `resolution_breakdown` +- Escrow economics (total escrowed/released/slashed/fees, average) +- Milestone stats (total, approved, disputed, approval rate) +- Service type breakdown diff --git a/mechanisms/m009-service-escrow/reference-impl/m009_kpi.js b/mechanisms/m009-service-escrow/reference-impl/m009_kpi.js new file mode 100644 index 0000000..e6d37d0 --- /dev/null +++ b/mechanisms/m009-service-escrow/reference-impl/m009_kpi.js @@ -0,0 +1,107 @@ +export function computeM009KPI({ as_of, agreements }) { + const agrs = agreements ?? []; + + const agreements_proposed = agrs.filter(a => a.status === "PROPOSED").length; + const agreements_funded = agrs.filter(a => a.status === "FUNDED").length; + const agreements_in_progress = agrs.filter(a => + ["IN_PROGRESS", "MILESTONE_REVIEW"].includes(a.status) + ).length; + const agreements_completed = agrs.filter(a => a.status === "COMPLETED").length; + const agreements_disputed = agrs.filter(a => + ["DISPUTED", "RESOLVED"].includes(a.status) + ).length; + const agreements_cancelled = agrs.filter(a => a.status === "CANCELLED").length; + + const total = agrs.length; + const dispute_rate = total > 0 + ? Number((agreements_disputed / total).toFixed(4)) + : 0.0; + + // Resolution breakdown + const resolved = agrs.filter(a => a.dispute?.resolution != null); + const resolution_breakdown = resolved.length > 0 + ? { + client_wins: resolved.filter(a => a.dispute.resolution === "CLIENT_WINS").length, + provider_wins: resolved.filter(a => a.dispute.resolution === "PROVIDER_WINS").length, + split: resolved.filter(a => a.dispute.resolution === "SPLIT").length + } + : null; + + // Escrow economics + const escrows = agrs.map(a => parseInt(a.escrow_amount?.amount ?? "0", 10)).filter(e => e > 0); + const total_escrowed = escrows.reduce((s, e) => s + e, 0); + + const completed_escrows = agrs.filter(a => a.status === "COMPLETED") + .map(a => parseInt(a.escrow_amount?.amount ?? "0", 10)); + const total_released = completed_escrows.reduce((s, e) => s + e, 0); + + const slashed_escrows = agrs.filter(a => a.dispute?.resolution === "CLIENT_WINS") + .map(a => parseInt(a.provider_bond?.amount ?? "0", 10)); + const total_slashed = slashed_escrows.reduce((s, e) => s + e, 0); + + // Platform fees: 1% of completed escrows + 2% of cancelled funded escrows + // Only FUNDED cancellations incur fees; PROPOSED cancellations are fee-free. + // Use cancelled_from field if available; otherwise assume fee-incurring. + const cancelled_funded = agrs.filter(a => + a.status === "CANCELLED" && + a.escrow_amount && + (a.cancelled_from ?? "FUNDED") !== "PROPOSED" + ) + .map(a => parseInt(a.escrow_amount?.amount ?? "0", 10)); + const completion_fees = Math.round(total_released * 0.01); + const cancellation_fees = Math.round(cancelled_funded.reduce((s, e) => s + e, 0) * 0.02); + const total_fees = completion_fees + cancellation_fees; + + const avg_escrow_amount = escrows.length > 0 + ? Number((total_escrowed / escrows.length).toFixed(1)) + : null; + + // Milestone stats + const all_milestones = agrs.flatMap(a => a.milestones ?? []); + const total_milestones = all_milestones.length; + const milestones_approved = all_milestones.filter(m => m.status === "APPROVED").length; + const milestones_disputed = all_milestones.filter(m => m.status === "DISPUTED").length; + const avg_approval_rate = total_milestones > 0 + ? Number((milestones_approved / total_milestones).toFixed(4)) + : null; + + // Service type breakdown + const types = { + ProjectVerification: 0, + MethodologyDevelopment: 0, + MRVSetup: 0, + CreditIssuanceSupport: 0, + MonitoringReporting: 0 + }; + for (const a of agrs) { + if (types[a.service_type] !== undefined) types[a.service_type]++; + } + + return { + mechanism_id: "m009", + scope: "v0_advisory", + as_of, + agreements_proposed, + agreements_funded, + agreements_in_progress, + agreements_completed, + agreements_disputed, + agreements_cancelled, + dispute_rate, + resolution_breakdown, + escrow_economics: { + total_escrowed: String(total_escrowed), + total_released: String(total_released), + total_slashed: String(total_slashed), + total_fees: String(total_fees), + avg_escrow_amount + }, + milestone_stats: { + total_milestones, + milestones_approved, + milestones_disputed, + avg_approval_rate + }, + service_type_breakdown: types + }; +} diff --git a/mechanisms/m009-service-escrow/reference-impl/m009_score.js b/mechanisms/m009-service-escrow/reference-impl/m009_score.js new file mode 100644 index 0000000..120c1a5 --- /dev/null +++ b/mechanisms/m009-service-escrow/reference-impl/m009_score.js @@ -0,0 +1,117 @@ +/** + * v0 (advisory): 4-factor weighted composite scoring for milestone deliverable review. + * + * Factors: + * deliverable_quality (weight 0.40): Methodology compliance, technical quality + * evidence_completeness (weight 0.25): Evidence IRI resolvability, document completeness + * milestone_consistency (weight 0.20): Consistency with prior milestones and spec + * provider_reputation (weight 0.15): M010 reputation score for provider + * + * See SPEC.md section 5 for full formula. + * + * @param {Object} opts + * @param {Object} opts.milestone - Milestone metadata + * @param {Object} opts.factors - Pre-computed factor scores (each 0-1000) + * @returns {{ score: number, confidence: number, recommendation: string, factors: Object }} + */ +export function computeM009Score({ milestone, factors }) { + const W_QUALITY = 0.40; + const W_EVIDENCE = 0.25; + const W_CONSISTENCY = 0.20; + const W_REPUTATION = 0.15; + + const clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, v)); + + const fQuality = clamp(factors.deliverable_quality ?? 0, 0, 1000); + const fEvidence = clamp(factors.evidence_completeness ?? 0, 0, 1000); + const fConsistency = clamp(factors.milestone_consistency ?? 0, 0, 1000); + const fReputation = clamp(factors.provider_reputation ?? 300, 0, 1000); + + const score = Math.round( + W_QUALITY * fQuality + + W_EVIDENCE * fEvidence + + W_CONSISTENCY * fConsistency + + W_REPUTATION * fReputation + ); + + const confidence = computeConfidence(factors); + const recommendation = computeRecommendation(clamp(score, 0, 1000), confidence); + + return { + score: clamp(score, 0, 1000), + confidence, + recommendation, + factors: { + deliverable_quality: fQuality, + evidence_completeness: fEvidence, + milestone_consistency: fConsistency, + provider_reputation: fReputation + } + }; +} + +/** + * Compute recommendation based on score and confidence. + * @param {number} score + * @param {number} confidence + * @returns {string} + */ +function computeRecommendation(score, confidence) { + if (score >= 700 && confidence >= 750) return "APPROVE"; + if (score < 400 || confidence < 250) return "FLAG_FOR_CLIENT"; + return "NEEDS_REVISION"; +} + +function computeConfidence(factors) { + let available = 0; + const total = 4; + if (factors.reputation_available === true) available++; + if (factors.iri_resolvable === true) available++; + if (factors.has_prior_milestones === true) available++; + if (factors.spec_available === true) available++; + return Math.round((available / total) * 1000); +} + +// --- Self-test --- +const isMain = typeof process !== "undefined" && + process.argv[1] && + (process.argv[1].endsWith("m009_score.js") || process.argv[1].endsWith("m009_score")); + +if (isMain) { + const fs = await import("node:fs"); + const path = await import("node:path"); + const url = await import("node:url"); + + const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); + const inputPath = path.join(__dirname, "test_vectors", "vector_v0_sample.input.json"); + const expectedPath = path.join(__dirname, "test_vectors", "vector_v0_sample.expected.json"); + + const input = JSON.parse(fs.readFileSync(inputPath, "utf8")); + const expected = JSON.parse(fs.readFileSync(expectedPath, "utf8")); + + const results = input.milestones.map(m => computeM009Score({ + milestone: m.milestone, + factors: m.factors + })); + + let pass = true; + for (let i = 0; i < results.length; i++) { + const r = results[i]; + const e = expected.scores[i]; + if (r.score !== e.score) { + console.error(`FAIL milestone[${i}]: got score=${r.score}, expected score=${e.score}`); + pass = false; + } + if (r.recommendation !== e.recommendation) { + console.error(`FAIL milestone[${i}]: got recommendation=${r.recommendation}, expected=${e.recommendation}`); + pass = false; + } + } + + if (pass) { + console.log("m009_score self-test: PASS"); + console.log(JSON.stringify({ scores: results }, null, 2)); + } else { + process.exit(1); + } +} diff --git a/mechanisms/m009-service-escrow/reference-impl/test_vectors/vector_v0_sample.expected.json b/mechanisms/m009-service-escrow/reference-impl/test_vectors/vector_v0_sample.expected.json new file mode 100644 index 0000000..9a3fedf --- /dev/null +++ b/mechanisms/m009-service-escrow/reference-impl/test_vectors/vector_v0_sample.expected.json @@ -0,0 +1,59 @@ +{ + "scores": [ + { + "score": 783, + "confidence": 750, + "recommendation": "APPROVE", + "factors": { + "deliverable_quality": 800, + "evidence_completeness": 900, + "milestone_consistency": 700, + "provider_reputation": 650 + } + }, + { + "score": 770, + "confidence": 1000, + "recommendation": "APPROVE", + "factors": { + "deliverable_quality": 750, + "evidence_completeness": 850, + "milestone_consistency": 800, + "provider_reputation": 650 + } + }, + { + "score": 550, + "confidence": 750, + "recommendation": "NEEDS_REVISION", + "factors": { + "deliverable_quality": 500, + "evidence_completeness": 600, + "milestone_consistency": 400, + "provider_reputation": 800 + } + }, + { + "score": 903, + "confidence": 750, + "recommendation": "APPROVE", + "factors": { + "deliverable_quality": 900, + "evidence_completeness": 950, + "milestone_consistency": 850, + "provider_reputation": 900 + } + }, + { + "score": 265, + "confidence": 250, + "recommendation": "FLAG_FOR_CLIENT", + "factors": { + "deliverable_quality": 300, + "evidence_completeness": 200, + "milestone_consistency": 250, + "provider_reputation": 300 + } + } + ] +} diff --git a/mechanisms/m009-service-escrow/reference-impl/test_vectors/vector_v0_sample.input.json b/mechanisms/m009-service-escrow/reference-impl/test_vectors/vector_v0_sample.input.json new file mode 100644 index 0000000..8dd6283 --- /dev/null +++ b/mechanisms/m009-service-escrow/reference-impl/test_vectors/vector_v0_sample.input.json @@ -0,0 +1,95 @@ +{ + "as_of": "2026-02-18T12:00:00Z", + "milestones": [ + { + "milestone": { + "agreement_id": "agr-001", + "milestone_index": 0, + "service_type": "ProjectVerification", + "deliverable_iri": "koi://deliverable/verification-report-plot-42" + }, + "factors": { + "deliverable_quality": 800, + "evidence_completeness": 900, + "milestone_consistency": 700, + "provider_reputation": 650, + "reputation_available": true, + "iri_resolvable": true, + "has_prior_milestones": false, + "spec_available": true + } + }, + { + "milestone": { + "agreement_id": "agr-001", + "milestone_index": 1, + "service_type": "ProjectVerification", + "deliverable_iri": "koi://deliverable/field-visit-report-plot-42" + }, + "factors": { + "deliverable_quality": 750, + "evidence_completeness": 850, + "milestone_consistency": 800, + "provider_reputation": 650, + "reputation_available": true, + "iri_resolvable": true, + "has_prior_milestones": true, + "spec_available": true + } + }, + { + "milestone": { + "agreement_id": "agr-002", + "milestone_index": 0, + "service_type": "MethodologyDevelopment", + "deliverable_iri": "koi://deliverable/methodology-draft-soil-carbon-v5" + }, + "factors": { + "deliverable_quality": 500, + "evidence_completeness": 600, + "milestone_consistency": 400, + "provider_reputation": 800, + "reputation_available": true, + "iri_resolvable": true, + "has_prior_milestones": false, + "spec_available": true + } + }, + { + "milestone": { + "agreement_id": "agr-003", + "milestone_index": 0, + "service_type": "MRVSetup", + "deliverable_iri": "koi://deliverable/mrv-sensor-deployment-plan" + }, + "factors": { + "deliverable_quality": 900, + "evidence_completeness": 950, + "milestone_consistency": 850, + "provider_reputation": 900, + "reputation_available": true, + "iri_resolvable": true, + "has_prior_milestones": false, + "spec_available": true + } + }, + { + "milestone": { + "agreement_id": "agr-004", + "milestone_index": 0, + "service_type": "CreditIssuanceSupport", + "deliverable_iri": "koi://deliverable/unresolvable-draft" + }, + "factors": { + "deliverable_quality": 300, + "evidence_completeness": 200, + "milestone_consistency": 250, + "provider_reputation": 300, + "reputation_available": false, + "iri_resolvable": false, + "has_prior_milestones": false, + "spec_available": true + } + } + ] +} diff --git a/mechanisms/m009-service-escrow/schemas/README.md b/mechanisms/m009-service-escrow/schemas/README.md new file mode 100644 index 0000000..0455ff1 --- /dev/null +++ b/mechanisms/m009-service-escrow/schemas/README.md @@ -0,0 +1,14 @@ +# m009 output schemas + +These JSON Schemas define **canonical output shapes** for m009 (Service Provision Escrow) artifacts. + +## Files +- `m009_agreement.schema.json` — schema for service agreement lifecycle objects (escrow, milestones, status, dispute details). +- `m009_milestone_review.schema.json` — schema for milestone review quality score output (score, confidence, recommendation, factor breakdown). +- `m009_kpi.schema.json` — schema for KPI metrics (agreement counts, dispute rate, escrow economics, milestone stats, service type breakdown). + +## Notes +- These schemas are intended for **validation** and consistency across repos (Heartbeat, agent skills, etc.). +- v0 is advisory-only: schemas describe outputs, not enforcement. +- The `status` field on agreements tracks lifecycle state (PROPOSED → FUNDED → IN_PROGRESS → MILESTONE_REVIEW → COMPLETED/DISPUTED/CANCELLED). See SPEC.md section 6. +- Standard service types: ProjectVerification, MethodologyDevelopment, MRVSetup, CreditIssuanceSupport, MonitoringReporting. diff --git a/mechanisms/m009-service-escrow/schemas/m009_agreement.schema.json b/mechanisms/m009-service-escrow/schemas/m009_agreement.schema.json new file mode 100644 index 0000000..ae5940a --- /dev/null +++ b/mechanisms/m009-service-escrow/schemas/m009_agreement.schema.json @@ -0,0 +1,119 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "m009_agreement_v0", + "title": "m009 service agreement", + "description": "Schema for an M009 service agreement lifecycle object.", + "type": "object", + "required": [ + "agreement_id", + "client", + "provider", + "service_type", + "escrow_amount", + "provider_bond", + "milestones", + "status" + ], + "properties": { + "agreement_id": { + "type": "string", + "description": "Unique identifier for the service agreement." + }, + "client": { + "type": "string", + "description": "Bech32 address of the service client." + }, + "provider": { + "type": "string", + "description": "Bech32 address of the service provider." + }, + "service_type": { + "type": "string", + "enum": [ + "ProjectVerification", + "MethodologyDevelopment", + "MRVSetup", + "CreditIssuanceSupport", + "MonitoringReporting" + ], + "description": "Standard service type category." + }, + "description": { + "type": "string", + "description": "Human-readable description of the service scope." + }, + "escrow_amount": { + "type": "object", + "required": ["amount", "denom"], + "properties": { + "amount": { "type": "string", "pattern": "^[0-9]+$" }, + "denom": { "type": "string" } + } + }, + "provider_bond": { + "type": "object", + "required": ["amount", "denom"], + "properties": { + "amount": { "type": "string", "pattern": "^[0-9]+$" }, + "denom": { "type": "string" } + } + }, + "milestones": { + "type": "array", + "minItems": 1, + "maxItems": 20, + "items": { + "type": "object", + "required": ["index", "description", "payment", "status"], + "properties": { + "index": { "type": "integer", "minimum": 0 }, + "description": { "type": "string" }, + "payment": { + "type": "object", + "required": ["amount", "denom"], + "properties": { + "amount": { "type": "string", "pattern": "^[0-9]+$" }, + "denom": { "type": "string" } + } + }, + "status": { + "type": "string", + "enum": ["PENDING", "IN_PROGRESS", "SUBMITTED", "APPROVED", "DISPUTED", "REVISED"] + }, + "deliverable_iri": { "type": ["string", "null"] }, + "submitted_at": { "type": ["string", "null"], "format": "date-time" }, + "approved_at": { "type": ["string", "null"], "format": "date-time" }, + "revision_count": { "type": "integer", "minimum": 0 } + } + } + }, + "current_milestone": { + "type": "integer", + "minimum": 0, + "description": "Index of the current active milestone." + }, + "status": { + "type": "string", + "enum": ["PROPOSED", "FUNDED", "IN_PROGRESS", "MILESTONE_REVIEW", "COMPLETED", "DISPUTED", "RESOLVED", "CANCELLED"], + "description": "Current agreement lifecycle status." + }, + "created_at": { "type": "string", "format": "date-time" }, + "started_at": { "type": ["string", "null"], "format": "date-time" }, + "completed_at": { "type": ["string", "null"], "format": "date-time" }, + "dispute": { + "type": ["object", "null"], + "properties": { + "milestone_index": { "type": "integer" }, + "reason": { "type": "string" }, + "arbiter": { "type": ["string", "null"] }, + "resolution": { + "type": ["string", "null"], + "enum": ["CLIENT_WINS", "PROVIDER_WINS", "SPLIT", null] + }, + "split_percent": { "type": ["integer", "null"], "minimum": 1, "maximum": 99 }, + "disputed_at": { "type": "string", "format": "date-time" }, + "resolved_at": { "type": ["string", "null"], "format": "date-time" } + } + } + } +} diff --git a/mechanisms/m009-service-escrow/schemas/m009_kpi.schema.json b/mechanisms/m009-service-escrow/schemas/m009_kpi.schema.json new file mode 100644 index 0000000..8a28466 --- /dev/null +++ b/mechanisms/m009-service-escrow/schemas/m009_kpi.schema.json @@ -0,0 +1,72 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "m009_kpi_v0", + "title": "m009 KPI block", + "description": "Schema for M009 service escrow KPI metrics.", + "type": "object", + "required": [ + "mechanism_id", + "scope", + "as_of", + "agreements_proposed", + "agreements_funded", + "agreements_in_progress", + "agreements_completed", + "agreements_disputed", + "agreements_cancelled", + "dispute_rate", + "escrow_economics", + "milestone_stats" + ], + "properties": { + "mechanism_id": { "const": "m009" }, + "scope": { "type": "string" }, + "as_of": { "type": "string", "format": "date-time" }, + "agreements_proposed": { "type": "integer", "minimum": 0 }, + "agreements_funded": { "type": "integer", "minimum": 0 }, + "agreements_in_progress": { "type": "integer", "minimum": 0 }, + "agreements_completed": { "type": "integer", "minimum": 0 }, + "agreements_disputed": { "type": "integer", "minimum": 0 }, + "agreements_cancelled": { "type": "integer", "minimum": 0 }, + "dispute_rate": { "type": "number", "minimum": 0, "maximum": 1 }, + "resolution_breakdown": { + "type": ["object", "null"], + "properties": { + "client_wins": { "type": "integer", "minimum": 0 }, + "provider_wins": { "type": "integer", "minimum": 0 }, + "split": { "type": "integer", "minimum": 0 } + } + }, + "escrow_economics": { + "type": "object", + "required": ["total_escrowed", "total_released", "total_slashed", "total_fees", "avg_escrow_amount"], + "properties": { + "total_escrowed": { "type": "string" }, + "total_released": { "type": "string" }, + "total_slashed": { "type": "string" }, + "total_fees": { "type": "string" }, + "avg_escrow_amount": { "type": ["number", "null"] } + } + }, + "milestone_stats": { + "type": "object", + "required": ["total_milestones", "milestones_approved", "milestones_disputed", "avg_approval_rate"], + "properties": { + "total_milestones": { "type": "integer", "minimum": 0 }, + "milestones_approved": { "type": "integer", "minimum": 0 }, + "milestones_disputed": { "type": "integer", "minimum": 0 }, + "avg_approval_rate": { "type": ["number", "null"] } + } + }, + "service_type_breakdown": { + "type": "object", + "properties": { + "ProjectVerification": { "type": "integer" }, + "MethodologyDevelopment": { "type": "integer" }, + "MRVSetup": { "type": "integer" }, + "CreditIssuanceSupport": { "type": "integer" }, + "MonitoringReporting": { "type": "integer" } + } + } + } +} diff --git a/mechanisms/m009-service-escrow/schemas/m009_milestone_review.schema.json b/mechanisms/m009-service-escrow/schemas/m009_milestone_review.schema.json new file mode 100644 index 0000000..34215c7 --- /dev/null +++ b/mechanisms/m009-service-escrow/schemas/m009_milestone_review.schema.json @@ -0,0 +1,62 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "m009_milestone_review_v0", + "title": "m009 milestone review score", + "description": "Schema for an M009 milestone review quality score output.", + "type": "object", + "required": ["score", "confidence", "recommendation", "factors"], + "properties": { + "score": { + "type": "integer", + "minimum": 0, + "maximum": 1000, + "description": "Weighted composite score of milestone deliverable quality." + }, + "confidence": { + "type": "integer", + "minimum": 0, + "maximum": 1000, + "description": "Data availability indicator (count of available signals / 4 × 1000)." + }, + "recommendation": { + "type": "string", + "enum": ["APPROVE", "NEEDS_REVISION", "FLAG_FOR_CLIENT"], + "description": "Agent recommendation for the milestone deliverable." + }, + "factors": { + "type": "object", + "required": [ + "deliverable_quality", + "evidence_completeness", + "milestone_consistency", + "provider_reputation" + ], + "properties": { + "deliverable_quality": { + "type": "integer", + "minimum": 0, + "maximum": 1000, + "description": "Methodology compliance and technical quality." + }, + "evidence_completeness": { + "type": "integer", + "minimum": 0, + "maximum": 1000, + "description": "Evidence IRI resolvability and document completeness." + }, + "milestone_consistency": { + "type": "integer", + "minimum": 0, + "maximum": 1000, + "description": "Consistency with prior milestones and agreement specification." + }, + "provider_reputation": { + "type": "integer", + "minimum": 0, + "maximum": 1000, + "description": "M010 reputation score of the provider (default 300 if unavailable)." + } + } + } + } +} diff --git a/package.json b/package.json index d174e09..bf7a676 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "agentic-tokenomics", "private": true, + "type": "module", "version": "0.0.0", "scripts": { "verify": "node scripts/verify.mjs",