# §54.7 Reserve Attestation — Operator Guide

## Overview

Reserve Attestation (§54.7) is the periodic Proof-of-Reserves publication pipeline. It demonstrates that on-chain COSR supply is fully backed by USDC reserves at all times (I3: reserve_ratio >= 100%). A qualified auditor or regulatory authority issues a signed attestation every ≤ 30 days covering on-chain supply, USDC reserve balances, minimum ratio during the period, and yield venue allocation details. The THREAD bridge stores the attestation and marks it for GossipSub broadcast on topic class `0x0020 RESERVE_ATTESTATIONS`.

---

## Lifecycle

```
Operator: publish_reserve_attestation  →  broadcast_status=0 (pending)
Pub svc:  scans pending rows           →  broadcast_status=1 (broadcast_ok)   ← §0x0020 GossipSub
                                        →  broadcast_status=2 (broadcast_failed) ← retry
Regulator: get_latest_reserve_attestation / query_reserve_attestation / list_reserve_attestations
```

---

## Tools

### `thread.publish_reserve_attestation`

Publish a new cleartext reserve attestation for a completed attestation period.

**Required params:**

| Param | Type | Description |
|---|---|---|
| `secret_key_hex` | string | 32-byte Ed25519 signing key (hex). Used to derive `attestor_id` and sign dev stub. |
| `period_start_slot` | number | Start of attestation period (slot). |
| `period_end_slot` | number | End of attestation period (must be > start). |
| `cosr_supply_micro` | string | On-chain COSR supply at period end (micro-units, as string). |
| `usdc_reserve_micro` | string | On-chain USDC reserve at period end (micro-units, as string). |
| `reserve_ratio_bps` | number | Reserve ratio bps at period end. Must == `(usdc_reserve_micro × 10000) / cosr_supply_micro` (±1 bps tolerance). Must be >= 10000 (I3). |
| `reserve_genesis_seed_usdc` | string | Genesis seed USDC equivalent at period end. |
| `min_reserve_ratio_bps` | number | Minimum reserve ratio observed during period (bps). Must be >= 10000 (I3). |
| `authority_signature_material_hex` | string | Attestor's COSE_Sign1 signature bytes (hex). Dev mode: 64-byte stub accepted. |
| `issued_slot` | number | Slot at which the attestation was issued (>= period_start_slot). |

**Optional params:**

| Param | Type | Default | Description |
|---|---|---|---|
| `reserve_attestation_id_hex` | string | random | 32-byte attestation ID (hex). Auto-generated if omitted. |
| `platform_issuer_id_hex` | string | derived | 32-byte platform issuer agent ID (hex). Defaults to key derived from `secret_key_hex`. |
| `yield_program_usdc_outside_reserve` | string | `"0"` | USDC deployed to yield venues (§51.5). Must == sum of `venue_allocations[*].allocated_usdc_micro`. |
| `venue_allocations` | array | `[]` | Array of `{venue_id, allocated_usdc_micro, yield_earned_micro, liquidity_tier}`. |
| `auditor_methodology_hash_hex` | string | null | SHA-256 of methodology document (64-char hex). |
| `auditor_methodology_uri` | string | null | URI of methodology document. |
| `audit_type` | number | `0` | Enum 0-6: SOC_1_Type_II(0), ISAE_3000(1), Big4_AUP(2), MAS_CPE_S3(3), VARA_PoR(4), MiCA_EMT(5), BIS_Cryptoasset(6). |
| `public_registry_inclusion_proof_hex` | string | null | Public registry inclusion proof bytes (hex). |
| `auditor_conflict_filter_hex` | string | null | SHA-256 of disqualifying relationships (64-char hex). |
| `opinion_type` | number | null | Enum 0-3: unqualified(0), qualified(1), adverse(2), disclaimer(3). |
| `materiality_threshold_bps` | number | null | Materiality threshold (1-500 bps). |
| `quorum_signatures` | array | null | K-of-N quorum entries: `{peer_auditor_agent_id, cose_sign1_signature, peer_auditor_jurisdiction}`. |

**Success response:**

```json
{
  "reserve_attestation_id_hex": "<64-char hex>",
  "broadcast_status": 0,
  "issued_slot": 1234567
}
```

---

### `thread.query_reserve_attestation`

Fetch a single attestation by ID.

**Params:** `{ "reserve_attestation_id_hex": "<64-char hex>" }`

**Success response:** Full attestation row (all BYTEA fields as hex strings, all NUMERIC fields as strings, JSONB fields as objects).

**Error:** `reserve_attestation_not_found` if ID not found.

---

### `thread.list_reserve_attestations`

List attestations with optional filters. Results ordered by `period_end_slot DESC`.

**Optional params:**

| Param | Type | Description |
|---|---|---|
| `broadcast_status` | number | Filter by broadcast_status (0, 1, or 2). |
| `attestor_id_hex` | string | Filter by attestor agent ID (64-char hex). |
| `period_end_slot_min` | number | Filter: period_end_slot >= value. |
| `period_end_slot_max` | number | Filter: period_end_slot <= value. |
| `limit` | number | Max rows (default 20, max 100). |
| `offset` | number | Pagination offset (default 0). |

**Success response:** `{ "attestations": [...], "count": N }`

---

### `thread.get_latest_reserve_attestation`

Convenience accessor returning the most recent attestation (by `period_end_slot`) with `broadcast_status IN (0, 1)`.

**Params:** none

**Success response:** Full attestation row (same format as query).

**Error:** `reserve_attestation_not_found` if no attestations exist.

---

## I3 Invariant

Both `reserve_ratio_bps` and `min_reserve_ratio_bps` MUST be >= 10000 (100%). The bridge enforces this pre-flight; the DB CHECK constraint is the final backstop. An attestation with `min_reserve_ratio_bps < 10000` triggers an emergency pause signal in production (§35.2 scope; v0.2.105 dev mode logs a warning).

---

## Reserve Ratio Formula

```
reserve_ratio_bps = (usdc_reserve_micro × 10000) / cosr_supply_micro
```

The bridge validates this to ±1 bps tolerance. Mismatches are rejected with an error identifying the computed vs. submitted values.

---

## Error catalog

| Error message | Cause |
|---|---|
| `reserve_attestation_not_found` | ID not found in DB (query/get_latest). |
| `reserve_attestation_i3_violated: reserve_ratio_bps=... < 10000` | Submitted ratio below 100%. |
| `reserve_attestation_i3_violated: min_reserve_ratio_bps=... < 10000` | Minimum ratio below 100%. |
| `reserve_ratio_bps=... does not match computed value ...` | Submitted ratio inconsistent with supply/reserve amounts. |
| `reserve_attestation_period_overlap` | DB unique constraint on period range (if enforced). |
| `secret_key_hex must be a 64-char hex string (32 bytes)` | Bad signing key format. |
| `period_end_slot must be > period_start_slot` | DB CHECK chk_reserve_period_order. |
| `issued_slot must be >= period_start_slot` | DB CHECK chk_issued_within_period. |
| `audit_type must be 0-6` | Out-of-range audit type. |
| `opinion_type must be 0-3` | Out-of-range opinion type. |
| `materiality_threshold_bps must be 1-500` | Out-of-range materiality. |

---

## Broadcast status values

| Value | Name | Meaning |
|---|---|---|
| `0` | `pending_broadcast` | Row created; publication service has not yet published to GossipSub. |
| `1` | `broadcast_ok` | Successfully published to GossipSub `0x0020 RESERVE_ATTESTATIONS`. |
| `2` | `broadcast_failed` | Last broadcast attempt failed; service will retry. |

Publication service (v0.2.106) transitions `0 → 1` or `0 → 2` on each cycle.

---

## Typical operator flow

```bash
# 1. Publish attestation (dev stub key)
curl -s http://127.0.0.1:9401 -d '{
  "method": "thread.publish_reserve_attestation",
  "params": {
    "secret_key_hex": "<32-byte-hex>",
    "period_start_slot": 4400000000,
    "period_end_slot":   4407776000,
    "cosr_supply_micro": "1000000000000",
    "usdc_reserve_micro": "1000000000000",
    "reserve_ratio_bps": 10000,
    "reserve_genesis_seed_usdc": "100000000000",
    "min_reserve_ratio_bps": 10000,
    "authority_signature_material_hex": "'$(python3 -c "print('ab' * 32)")'",
    "issued_slot": 4407776001,
    "audit_type": 0
  }
}'

# 2. Get latest attestation
curl -s http://127.0.0.1:9401 -d '{"method": "thread.get_latest_reserve_attestation", "params": {}}'

# 3. List pending (broadcast_status=0)
curl -s http://127.0.0.1:9401 -d '{"method": "thread.list_reserve_attestations", "params": {"broadcast_status": 0}}'
```

---

## Cross-region visibility

`reserve_attestations` is included in `pub_discovery_global` (v0.2.104, ADR-2026-0143). Any regulator or operator connecting to any region sees the same latest attestation. The region running the publication service (v0.2.106) is the single writer; other regions consume via logical replication.

---

## Operator publish script (v0.2.107)

`platform/scripts/publish-reserve-attestation.ts` is the manual operator trigger for publishing a new reserve attestation. It submits via the HL tool and optionally polls for broadcast confirmation from the v0.2.106 publication service.

```bash
# Minimal: submit a new attestation (1:1 USDC backing, 30-day period)
tsx platform/scripts/publish-reserve-attestation.ts \
  --bridge http://127.0.0.1:9401 \
  --signer-key-hex <32-byte-hex> \
  --period-start-slot 4437990752 \
  --period-end-slot   4445766752 \
  --cosr-supply       1000000000000 \
  --usdc-reserve      1000000000000 \
  --genesis-seed-usdc 100000000000 \
  --issued-slot       4445766752 \
  --wait

# Dry-run: print computed params without submitting
tsx platform/scripts/publish-reserve-attestation.ts \
  [required flags...] \
  --dry-run
```

The script auto-computes `reserve_ratio_bps` from `cosr_supply` and `usdc_reserve` if omitted. Audit log written to `platform/var/publish-reserve-attestation/<attestation_id>.json`.

**Automated broadcast:** the v0.2.106 in-bridge broadcaster cron scans for `broadcast_status=0` rows every 15s and transitions them to `broadcast_status=1`. Use `--wait` to poll until broadcast confirms.

---

## Protocol anchors

- §54.7: `thread/31-documents-identity-consumer.md`
- ADR-2026-0143 (v0.2.104): schema + cross-region pub
- ADR-2026-0144 (v0.2.105): HL tool surface
- ADR-2026-0145 (v0.2.106): publication service (in-bridge cron)
- ADR-2026-0146 (v0.2.107): operator publish script
- §46.5 SLO table: cadence ≤ 7,776,000 slots (~30 days)
- §15b ZK: `sample_vrf_proof` reserved; Bulletproof-over-Ristretto255 out of scope for chunk-5
