--- name: stemedb-lens description: 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 ```rust // 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_async` impl MUST have `#[instrument]`. ## Tracing Pattern (Required) Every lens resolve method must be instrumented: ```rust 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 `Default` for standard lenses. * Document the ranking logic clearly. * Add `#[instrument]` with `candidates_count` and `lens` fields. * Use `Resolution::with_winner()` for consistent output. ## Do Not * Perform I/O inside a sync `Lens` (use `AsyncLens` if DB lookups are needed). * Use `unwrap()` or `expect()` — workspace lints deny these.