stemedb/ai-lookup/services/meter.md
jordan 1ce4004807 feat: Complete Phase 2 (The Cortex) - query, lens, and API layers
This commit adds the read path (Cortex) to complement the write path (Spine):

## Crates
- stemedb-api: HTTP API with axum + utoipa OpenAPI
  - /v1/assert, /v1/query, /v1/epoch, /v1/skeptic, /v1/trace, /v1/audit
  - Metered endpoints with quota enforcement
  - Ed25519 signature verification
- stemedb-lens: Truth resolution lenses
  - RecencyLens, ConsensusLens, ConfidenceLens
  - VoteAwareConsensusLens (Ballot Box pattern)
  - TrustAwareAuthorityLens (The Hive pattern)
  - SkepticLens (conflict analysis)
  - EpochAwareLens (paradigm-safe queries)
- stemedb-query: Query engine with materialized views

## Storage Extensions
- VoteStore: Vote aggregation with cached counts
- TrustRankStore: Agent reputation with decay
- AuditStore: Query audit trail
- IndexStore: SP/P/S index structures
- SupersessionStore: Epoch supersession chains

## SDKs
- sdk/go/steme: Go HTTP client with Ed25519 signing
- sdk/go/adk: ADK-Go tools for AI agents

## Documentation
- Updated CLAUDE.md, architecture.md, roadmap.md
- New ai-lookup entries for all services
- Use case docs for consumer health intelligence
- Arena roadmap for simulation advancement

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 13:22:44 -07:00

3.5 KiB

The Meter (Economic Throttling)

Overview

The Meter implements per-agent per-hour quota enforcement using a Token Bucket algorithm. This prevents runaway agents from exhausting system resources while allowing bursty behavior.

Cost Model

Operation Base Cost Notes
Assert 10 tokens Writing truth is expensive
Vote 1 token Voting is cheap
Query 5 tokens + 1 per Lens applied
Payload +1/KB Prevents spamming massive blobs

Default quota: 10,000 tokens per agent per hour.

Components

QuotaStore (stemedb-storage/src/quota_store.rs)

Storage abstraction for quota tracking.

Key Types:

  • QuotaRecord - Per-agent per-hour usage record
  • CostConfig - Operation cost configuration
  • QuotaCheckResult - Result of quota check (allowed, remaining, reset_at)
  • OperationType - Assert, Vote, or Query

Storage Layout:

QT:{agent_id}:{hour} -> QuotaRecord (serialized)
QL:{agent_id} -> u64 (custom limit override)

Key Methods:

async fn check_and_record(&self, agent_id, operation, payload_bytes, timestamp) -> QuotaCheckResult;
async fn get_quota_status(&self, agent_id, timestamp) -> QuotaCheckResult;
async fn set_quota_limit(&self, agent_id, limit) -> Result<()>;

MeterLayer (stemedb-api/src/middleware/meter.rs)

Tower middleware that intercepts requests and enforces quotas.

Request Flow:

  1. Extract X-Agent-Id header (hex-encoded 32-byte public key)
  2. Determine operation type from path
  3. Calculate cost based on operation + payload size
  4. Check quota and reject with 429 if exceeded
  5. Record cost and forward request
  6. Add quota headers to response

Headers:

Header Direction Description
X-Agent-Id Request Agent's Ed25519 public key (hex, 64 chars)
X-Quota-Remaining Response Remaining tokens in current window
X-Quota-Limit Response Total tokens allowed per hour
X-Quota-Reset Response Unix timestamp when window resets

API Endpoints

GET /v1/meter/quota Check quota status for an agent.

Query params:

  • agent_id - Hex-encoded agent public key

Response:

{
  "agent_id": "...",
  "remaining": 9500,
  "limit": 10000,
  "reset_at": 1705317600,
  "used": 500,
  "window_start": 1705314000
}

POST /v1/meter/quota/limit Set custom quota limit (admin operation).

Request:

{
  "agent_id": "...",
  "limit": 50000
}

Configuration

Environment variable: STEMEDB_METER_ENABLED

  • true (default): Enable economic throttling
  • false or 0: Disable (all requests pass through)

Bypass Paths

These paths bypass metering:

  • /v1/health
  • /swagger-ui/*
  • /api-docs/*

Usage Example

# Check quota before operations
curl "http://localhost:3000/v1/meter/quota?agent_id=$(xxd -p -l 32 /dev/urandom)"

# Make request with agent ID
curl -X POST http://localhost:3000/v1/assert \
  -H "Content-Type: application/json" \
  -H "X-Agent-Id: 0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20" \
  -d '{"subject": "test", ...}'

# Response headers include quota info
# X-Quota-Remaining: 9989
# X-Quota-Limit: 10000
# X-Quota-Reset: 1705317600

Implementation Notes

  • Quota windows are hour-aligned (truncated to the start of the hour)
  • Quotas reset automatically at the start of each hour
  • On storage errors, requests are allowed (fail open for availability)
  • Anonymous requests (no X-Agent-Id) bypass metering
  • Token bucket allows burst behavior while enforcing long-term limits