stemedb/ai-lookup/services/query.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

2.8 KiB

Query Engine

Last Updated: 2026-02-01 Confidence: High Status: Implemented in stemedb-query v0.1.0

Summary

The Query Engine provides lifecycle-aware filtering for reading assertions from the knowledge graph.

Key Facts:

  • Filters by subject, predicate, lifecycle, epoch
  • Fast path: checks MV:{subject}:{predicate} for pre-computed winner (O(1))
  • MV staleness control: max_stale parameter to reject stale materialized views
  • Compound index: SP:{subject}:{predicate} for subject+predicate lookups (O(1))
  • Subject index: S:{subject} for subject-only lookups (O(1))
  • Falls back to full scan when no index available

File Pointers:

  • crates/stemedb-query/src/engine.rs - QueryEngine with fast-path and staleness check
  • crates/stemedb-query/src/query.rs - Query and QueryResult types

Query Structure

pub struct Query {
    pub subject: Option<String>,
    pub predicate: Option<String>,
    pub lifecycle: Option<LifecycleStage>,
    pub epoch: Option<EpochId>,
    pub limit: Option<usize>,
    pub max_stale: Option<u64>,  // Maximum MV age in seconds
}

Usage

let query = Query::builder()
    .subject("Tesla")
    .predicate("revenue")
    .lifecycle(LifecycleStage::Approved)
    .max_stale(300)  // Only use MVs < 5 minutes old
    .limit(10)
    .build();

let result = engine.execute(&query).await?;

MV Staleness Control

The max_stale parameter controls whether the fast path (materialized view) is used:

max_stale Behavior
None (default) Accept any MV age (backward compatible)
Some(0) Only accept brand-new MVs (age = 0 seconds)
Some(60) Only use MV if materialized within last 60 seconds
Some(300) Only use MV if materialized within last 5 minutes

When the MV is stale, the query falls through to the slow path (SP index lookup + lens resolution).

Use cases:

  • Real-time dashboards: max_stale(60) for fresh data
  • Audit investigations: max_stale(0) to ensure current state
  • Batch processing: None for maximum performance

Query Execution Strategy

  1. Fast path (subject + predicate): MV:{subject}:{predicate}MaterializedView.winner (O(1))
    • Skips if MV doesn't exist
    • Skips if MV is too stale (max_stale check)
    • Skips if winner doesn't match filters (lifecycle, epoch)
  2. Compound index (subject + predicate): SP:{subject}:{predicate} → hashes (O(1))
  3. Subject index (subject only): S:{subject} → hashes (O(1))
  4. Full scan (no subject): Scan H: prefix (O(n))
  5. Filter: Apply lifecycle/epoch filters on candidates
  6. Limit: Truncate if limit specified