---
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.
