stemedb/.claude/skills/stemedb-lens/SKILL.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.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_async impl 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 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.