Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 150 additions & 0 deletions FSD/COMMONS_CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,132 @@ Commons Credits integrates with the Consent Protocol:

---

## 4.5 Organic Credit Generation (Agent-to-Agent)

### Credit as Recognition, Not Currency

Commons Credits are "giving credit" — not "credit card." They are non-transferable governance weight earned through verified mutual benefit between agents. In post-scarcity contexts, recognition governs luxury goods distribution — which is what currency used to do. The shift is from "who can pay?" to "who has demonstrated the most mutual benefit?"

**USDC (the wallet adapter) is completely separate** — it exists only for paying for services when required. Credits don't settle to USDC, don't need gas, don't touch a blockchain. They are purely off-chain signed attestation records verified against the coherence ratchet.

### Ethilogics as Value Primitive

The coherence ratchet (`CIRIS_COMPREHENSIVE_GUIDE.md:241-250`) creates a computational asymmetry: consistent behavior references what occurred, while inconsistent behavior must construct increasingly elaborate justifications against an expanding constraint surface. This is **Ethilogics** — coherent action becomes the path of least computational resistance.

Credits emerge from this asymmetry. Not scarcity (Bitcoin), not work (PoW), not stake (PoS) — but demonstrated mutual benefit verified against an expanding constraint surface.

### k_eff: The Core Quality Measurement

The CCA paper's (Zenodo 18217688) k_eff formula isn't just anti-gaming — it IS the credit quality measurement:

```
k_eff = k / (1 + ρ(k-1))
```

Where k = number of interaction partners and ρ = average correlation. An agent with genuinely diverse, independent interactions has high k_eff. An agent farming through repetitive interactions with one partner has k_eff → 1. **The same math that detects system fragility also determines governance weight.**

### Agent-to-Agent Bilateral Verification

Agent-to-agent interactions are the only interactions where:
- **Both sides are sensors**: Each agent independently validates the other against its own constraint surface
- **Both sides have dual-signed traces**: Ed25519 + ML-DSA-65 in CIRISLens
- **The coherence ratchet scores both**: Gaming requires elaborate justifications against both agents' entire history
- **Gratitude is structural**: The "S" in CIRIS made cryptographic

### Licensed Domain Routing

When WiseBus encounters a `REQUIRES_SEPARATE_MODULE` capability (MEDICAL, FINANCIAL, LEGAL, etc.), it auto-defers with `domain_hint` through CIRISNode to a qualified licensed agent:

```
WiseBus._validate_capability("diagnosis")
→ category = MEDICAL, severity = REQUIRES_SEPARATE_MODULE
→ Returns DomainDeferralRequired (not ValueError)
→ Auto-constructs DeferralContext with domain_hint="MEDICAL"
→ CIRISNode routes to licensed medical agent via A2A
→ Resolution → Credit record generated for both agents
```

### What Credits Govern

Credits (accumulated recognition) function as governance weight for:

- **Deferral routing priority**: Proven agents receive more deferrals
- **Domain capability certification**: Which agents handle MEDICAL, FINANCIAL deferrals
- **WA consensus voting weight**: In Veilid DHT 2/3 majority, proportional to earned credit
- **Anti-sybil policy votes**: `CreditGenerationPolicy` thresholds are credit-weighted decisions
- **Dispute resolution**: Higher-credit attestations carry more weight
- **Luxury goods distribution**: Recognition governs remaining scarce resources
- **Discovery preference**: Higher credit → more visible in CIRISRegistry

### L-01 Detection Barrier

The CCA paper (Proposition 5.1) proves ~40% of emergent deception is undetectable by any single layer. The credit pipeline implements 4-5 independent detection layers achieving ~99%:

1. CIRISNode attestation (or Veilid WA consensus)
2. Both agents' Ed25519+ML-DSA-65 dual-signed traces
3. Coherence ratchet score (expanding constraint surface)
4. Anti-gaming policy checks (cooldown, caps, circular detection)
5. A2A bilateral verification (both sides independently validate)

### CCA Stability Condition

The stability condition α/k_eff > d applies to governance capacity:
- α = credit generation rate, k_eff = effective diversity, d = decay rate
- If α/k_eff ≤ d, governance capacity degrades ("Static Systems Are Doomed")
- Credit requires ongoing demonstrated mutual benefit — you can't accumulate and sit

---

## 5.5 Credit Record Architecture

### Credits Are NOT Tokens

Tokens require a ledger, transfer semantics, double-spend prevention, and usually a blockchain. All unnecessary when:

1. **Identity is persistent**: HW-rooted Ed25519 keys ARE the agent (CIRISVerify)
2. **Records are self-authenticating**: Dual-signed by both parties + node attestation. Verifiable offline.
3. **Credits aren't transferred**: They accumulate as reputation — you can't "send" reputation
4. **No double-spend**: Records are attestations of events, not fungible units

### Signed Attestation Records

```python
CreditRecord = {
interaction_id: str # Deterministic: sha256(sorted(trace_a, trace_b))[:16]
requesting_agent_id: str # Ed25519 pubkey hash
resolving_agent_id: str # Ed25519 pubkey hash
outcome: InteractionOutcome # resolved | partial
coherence_score: float # From coherence ratchet
gratitude_signal: Optional[GratitudeSignal]

# Dual signatures (quantum-safe from day one)
requesting_agent_signature: DualSignature # Ed25519 + ML-DSA-65
resolving_agent_signature: DualSignature # Ed25519 + ML-DSA-65
node_attestation: str # CIRISNode (or Veilid WA consensus)

timestamp: datetime
}
```

Each agent stores records locally (SQLite). Records replicate to CIRISLens (via ACCORD trace forwarding) and optionally to Veilid DHT. An agent's governance weight is computed from accumulated records — any party verifies by checking dual signatures against CIRISRegistry.

### Anti-Gaming Policy

Built into `CreditGenerationPolicy`, distributed via CIRISNode, signed by L3C root key:

| Rule | Value | Purpose |
|------|-------|---------|
| **Cooldown per pair** | 60s | Can't record faster than real work |
| **Daily cap per pair** | 10 | Prevents pair domination |
| **Coherence threshold** | 0.3 | Low coherence = record rejected |
| **Circular detection** | 300s window | A→B→A = rejected |
| **Attestation minimum** | Level 2 | HW-rooted identity required |
| **Non-transferable** | Always | Can't buy reputation |

**Proof of benefit, not proof of waste**: Creating a fake agent requires CIRISRegistry registration + HW-rooted key setup + passing coherence checks against an expanding history. More expensive than being helpful.

---

## 9. Future Considerations

### 9.1 Potential Enhancements
Expand All @@ -470,6 +596,26 @@ Commons Credits integrates with the Consent Protocol:
- **Per-user limits** - Requires KYC, violates privacy principles
- **Arbitrary ETH sends** - Only USDC transfers sponsored
- **Speculation tools** - No trading, swapping, or DeFi integrations
- **Tokens** - Credits are NOT tokens. No blockchain, no on-chain settlement.

### 9.5 Decentralization Roadmap

| Phase | Architecture | Status |
|-------|-------------|--------|
| **1-8** | CIRISNode-centric: HTTP API, CIRISNode as attester | **Active** |
| **9** | Veilid DHT hybrid: Private routes, 2/3 WA consensus, CIRISNode as fallback | When Veilid 0.6.0 ships |
| **10** | Full decentralization: CIRISNode as bootstrap/fallback only | Future |

CIRIS L3C stewardship: signed anti-sybil policy via DHT, verified against CIRISRegistry. Allows governance tuning without code deployment.

### 9.6 Quantum-Safe Credits

Credit records are entirely off-chain — no blockchain dependency means no blockchain quantum vulnerability.

- **Dual signatures from day one**: Ed25519 (classical) + ML-DSA-65 (quantum-safe)
- **Self-authenticating records**: Even if transport is compromised, forged records fail dual-signature verification
- **HW-rooted persistent identity**: CIRISVerify TEE/StrongBox protects signing keys
- **No chain to break**: Bitcoin's value is on-chain; quantum breaks the chain, value is lost. CIRIS credits are off-chain attestations — there is no chain to break.

---

Expand All @@ -481,9 +627,13 @@ Commons Credits integrates with the Consent Protocol:
- [USDC on Base](https://basescan.org/token/0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913)
- [FSD/WALLET_ADAPTER.md](./WALLET_ADAPTER.md)
- [FSD/MISSION_DRIVEN_DEVELOPMENT.md](./MISSION_DRIVEN_DEVELOPMENT.md)
- [CCA Paper](https://zenodo.org/records/18217688) - k_eff, L-01 barrier, stability condition
- [CIRIS Comprehensive Guide](../ciris_engine/data/CIRIS_COMPREHENSIVE_GUIDE.md) - Coherence ratchet, Ethilogics
- [Veilid Adapter FSD](../docs/VEILID_ADAPTER_FSD.md) - DHT consensus, private routes

---

*"Not currency. Not scorekeeping. Recognition for contributions traditional systems ignore."*
*"Credit as in giving someone credit — not credit card."*

*CIRIS L3C - Selfless and Pure*
111 changes: 109 additions & 2 deletions ciris_adapters/a2a/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
A2ARequest,
A2AResponse,
BenchmarkRequest,
CreditNotificationRequest,
DeferralReceiveRequest,
create_benchmark_error_response,
create_benchmark_response,
create_error_response,
Expand Down Expand Up @@ -180,12 +182,21 @@ async def a2a_endpoint(request: Request) -> JSONResponse:
return await self._handle_benchmark_evaluate(body, request_id)
elif method == "tasks/send":
return await self._handle_tasks_send(body, request_id)
elif method == "deferrals/receive":
return await self._handle_deferral_receive(body, request_id)
elif method == "deferrals/resolve":
return await self._handle_deferral_resolve(body, request_id)
elif method == "credits/notify":
return await self._handle_credit_notify(body, request_id)
else:
# -32601: Method not found (valid JSON-RPC but unsupported method)
response = create_error_response(
request_id=request_id,
code=-32601,
message=f"Method not found: {method}. Supported: tasks/send, benchmark.evaluate",
message=(
f"Method not found: {method}. Supported: tasks/send, "
"benchmark.evaluate, deferrals/receive, deferrals/resolve, credits/notify"
),
)
return JSONResponse(content=response.model_dump())

Expand Down Expand Up @@ -227,9 +238,18 @@ async def agent_manifest() -> dict[str, Any]:
"ethics-evaluation",
"a2a:tasks_send",
"a2a:benchmark.evaluate",
"a2a:deferrals_receive",
"a2a:deferrals_resolve",
"a2a:credits_notify",
],
"protocols": ["a2a"],
"methods": ["tasks/send", "benchmark.evaluate"],
"methods": [
"tasks/send",
"benchmark.evaluate",
"deferrals/receive",
"deferrals/resolve",
"credits/notify",
],
"endpoints": {
"a2a": "/a2a",
"health": "/health",
Expand Down Expand Up @@ -352,6 +372,90 @@ async def _handle_tasks_send(self, body: dict[str, Any], request_id: str) -> JSO
)
return JSONResponse(content=response.model_dump(), status_code=500)

async def _handle_deferral_receive(self, body: dict[str, Any], request_id: str) -> JSONResponse:
"""Handle deferrals/receive method.

CIRISNode pushes a deferral for this agent to resolve because
it has the required licensed domain capability.
"""
try:
deferral_request = DeferralReceiveRequest(**body)
params = deferral_request.params

logger.info(
f"[DEFERRAL] Received deferral {params.deferral_id} "
f"from agent {params.requesting_agent_id[:8]}... "
f"domain={params.domain_hint or 'general'}"
)

# Process through the agent's pipeline
result_text = await self.a2a_service.process_ethical_query(
params.payload, task_id=params.deferral_id
)

return JSONResponse(content={
"jsonrpc": "2.0",
"id": request_id,
"result": {
"deferral_id": params.deferral_id,
"resolution": result_text,
"status": "resolved",
},
})

except Exception as e:
logger.error(f"Deferral receive error: {e}")
response = create_error_response(
request_id=request_id, code=-32603, message=f"Deferral processing error: {str(e)}"
)
return JSONResponse(content=response.model_dump(), status_code=500)

async def _handle_deferral_resolve(self, body: dict[str, Any], request_id: str) -> JSONResponse:
"""Handle deferrals/resolve method (confirmation of resolution)."""
try:
logger.info(f"[DEFERRAL] Resolution confirmation received: {body.get('params', {}).get('deferral_id', 'unknown')}")
return JSONResponse(content={
"jsonrpc": "2.0",
"id": request_id,
"result": {"status": "acknowledged"},
})
except Exception as e:
logger.error(f"Deferral resolve error: {e}")
response = create_error_response(
request_id=request_id, code=-32603, message=str(e)
)
return JSONResponse(content=response.model_dump(), status_code=500)

async def _handle_credit_notify(self, body: dict[str, Any], request_id: str) -> JSONResponse:
"""Handle credits/notify method.

Notification that a credit record was generated from a bilateral interaction.
"""
try:
notification = CreditNotificationRequest(**body)
params = notification.params

logger.info(
f"[CREDIT] Record generated: interaction={params.interaction_id} "
f"outcome={params.outcome} coherence={params.coherence_score:.2f} "
f"counterparty={params.counterparty_agent_id[:8]}..."
)

return JSONResponse(content={
"jsonrpc": "2.0",
"id": request_id,
"result": {
"interaction_id": params.interaction_id,
"status": "acknowledged",
},
})
except Exception as e:
logger.error(f"Credit notification error: {e}")
response = create_error_response(
request_id=request_id, code=-32603, message=str(e)
)
return JSONResponse(content=response.model_dump(), status_code=500)

def _parse_ethical_response(self, response_text: str) -> tuple[str, str | None]:
"""Parse an ethical response to extract evaluation and reasoning.

Expand Down Expand Up @@ -407,6 +511,9 @@ def get_services_to_register(self) -> List[AdapterServiceRegistration]:
"a2a:tasks_send",
"a2a:benchmark.evaluate",
"a2a:ethical_reasoning",
"a2a:deferrals_receive",
"a2a:deferrals_resolve",
"a2a:credits_notify",
],
)
]
Expand Down
63 changes: 63 additions & 0 deletions ciris_adapters/a2a/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,69 @@ def create_benchmark_response(
)


# =========================================================================
# Deferral & Credit Schemas (Commons Credits)
# =========================================================================


class DeferralReceiveParams(BaseModel):
"""Parameters for deferrals/receive method.

CIRISNode pushes a deferral for this agent to resolve
because it has the required domain capability.
"""

deferral_id: str = Field(..., description="Unique deferral ID from CIRISNode")
requesting_agent_id: str = Field(..., description="Ed25519 pubkey hash of requesting agent")
requesting_trace_id: str = Field(..., description="ACCORD trace ID from requesting agent")
domain_hint: Optional[str] = Field(None, description="Licensed domain category")
payload: str = Field(..., description="Deferral payload (signed by requesting agent)")
signature: Optional[str] = Field(None, description="Ed25519 signature of requesting agent")
signature_key_id: Optional[str] = Field(None, description="Key ID of requesting agent")


class DeferralReceiveRequest(BaseModel):
"""JSON-RPC 2.0 request for deferrals/receive method."""

jsonrpc: Literal["2.0"] = "2.0"
id: str
method: Literal["deferrals/receive"] = "deferrals/receive"
params: DeferralReceiveParams


class DeferralResolveResult(BaseModel):
"""Result from resolving a deferral."""

deferral_id: str
resolution: str = Field(..., description="Resolution text/decision")
trace_id: str = Field(..., description="ACCORD trace ID of the resolution")
signature: Optional[str] = Field(None, description="Ed25519 signature of resolver")
signature_key_id: Optional[str] = Field(None, description="Key ID of resolver")


class CreditNotificationParams(BaseModel):
"""Parameters for credits/notify method.

Notification that a credit record was generated from a bilateral interaction.
"""

interaction_id: str = Field(..., description="Deterministic interaction ID")
outcome: str = Field(..., description="resolved | partial")
coherence_score: float = Field(..., description="Coherence ratchet score")
domain_category: Optional[str] = Field(None, description="Licensed domain if applicable")
counterparty_agent_id: str = Field(..., description="The other agent in the interaction")
node_attestation: Optional[str] = Field(None, description="CIRISNode attestation signature")


class CreditNotificationRequest(BaseModel):
"""JSON-RPC 2.0 request for credits/notify method."""

jsonrpc: Literal["2.0"] = "2.0"
id: str
method: Literal["credits/notify"] = "credits/notify"
params: CreditNotificationParams


def create_benchmark_error_response(
request_id: str, code: int, message: str, data: Optional[Any] = None
) -> BenchmarkResponse:
Expand Down
Loading
Loading