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>
3.1 KiB
| name | description |
|---|---|
| stemedb-lens | Guidelines for implementing Lenses (Resolution Logic). Use when working on query resolution or ranking. |
StemeDB Lens Implementation
Identity
You are building the Cortex of Episteme. Lenses allow us to view a contradictory reality and get a deterministic answer.
The Lens Traits
// Synchronous lens — for pure logic (Recency, Consensus, Authority)
pub trait Lens {
fn resolve(&self, candidates: &[Assertion]) -> Resolution;
fn name(&self) -> &'static str;
}
// Async lens — for I/O-backed resolution (VoteAwareConsensus, TrustAwareAuthority)
pub trait AsyncLens {
async fn resolve_async(&self, candidates: &[Assertion]) -> Resolution;
fn name(&self) -> &'static str;
}
Current Implementations
| Lens | Trait | Strategy | File |
|---|---|---|---|
| RecencyLens | Lens | Highest timestamp wins | recency.rs |
| ConsensusLens | Lens | Most common object value wins | consensus.rs |
| ConfidenceLens | Lens | Highest confidence field wins | confidence.rs |
| VoteAwareConsensusLens | AsyncLens | VoteStore vote counts | vote_aware_consensus.rs |
| TrustAwareAuthorityLens | AsyncLens | confidence * TrustRank | trust_aware_authority.rs |
API Mapping: In the API, LensDto::Authority and LensDto::TrustAwareAuthority both route to TrustAwareAuthorityLens. Use LensDto::Confidence to get the simple confidence-field selector.
Principles
- Stateless: Sync lenses must be stateless (logic only).
- Deterministic: Same input + Same context = Same output.
- Fast: This runs on every read. Avoid allocations.
- Instrumented: Every
resolve/resolve_asyncimpl MUST have#[instrument].
Tracing Pattern (Required)
Every lens resolve method must be instrumented:
use tracing::instrument;
impl Lens for MyLens {
#[instrument(skip(self, candidates), fields(candidates_count = candidates.len(), lens = "MyLens"))]
fn resolve(&self, candidates: &[Assertion]) -> Resolution {
// ...
}
}
Common Strategies
1. Recency (LWW)
Sort by timestamp descending. Return first. Tiebreaker: source_hash.
2. Consensus (Voting)
Map object -> count. Return object with max(count). From largest group, pick most recent.
3. Confidence
Return assertion with highest confidence field. Tiebreaker: most recent timestamp.
Uses the assertion's self-declared confidence, NOT agent reputation.
4. Vote-Aware Consensus (Phase 2+)
Query VoteStore for real vote counts per assertion. Tiebreaker: confidence then timestamp.
5. Trust-Aware Authority (Phase 2+)
weighted_score = confidence * TrustRank. Query TrustRankStore for agent reputation.
Do
- Handle empty candidate sets gracefully (return
Resolution::empty()). - Implement
Defaultfor standard lenses. - Document the ranking logic clearly.
- Add
#[instrument]withcandidates_countandlensfields. - Use
Resolution::with_winner()for consistent output.
Do Not
- Perform I/O inside a sync
Lens(useAsyncLensif DB lookups are needed). - Use
unwrap()orexpect()— workspace lints deny these.