# The Ballot Box **Last Updated:** 2026-01-31 **Confidence:** High **Status:** Implemented ## Summary The Ballot Box is Episteme's high-velocity vote ingestion system. It separates votes from assertions to enable thousands of agents to vote simultaneously without lock contention. **Key Facts:** - Votes are append-only (immutable) - Content-addressed by BLAKE3 hash - O(1) vote counts via cached counters - O(1) aggregate weights for Materializer - Decoupled from Assertion mutations **File Pointer:** `crates/stemedb-storage/src/vote_store.rs` ## Storage Layout | Key Pattern | Value | Purpose | |-------------|-------|---------| | `V:{assertion_hash}:{vote_hash}` | Serialized `Vote` | Individual votes | | `VC:{assertion_hash}` | `u64` (LE bytes) | Vote count cache | | `VW:{assertion_hash}` | `f32` (LE bytes) | Aggregate weight cache | ## VoteStore Trait ```rust #[async_trait] pub trait VoteStore: Send + Sync { /// Store a vote and return its content-addressed hash async fn put_vote(&self, vote: &Vote) -> Result; /// Get a specific vote by hash async fn get_vote(&self, assertion_hash: &Hash, vote_hash: &Hash) -> Result>; /// Get all votes for an assertion (O(n)) async fn get_votes_for_assertion(&self, assertion_hash: &Hash) -> Result>; /// Get vote count (O(1) via cache) async fn get_vote_count(&self, assertion_hash: &Hash) -> Result; /// Get aggregate weight (O(1) via cache) async fn get_aggregate_weight(&self, assertion_hash: &Hash) -> Result; /// Check if any votes exist async fn has_votes(&self, assertion_hash: &Hash) -> Result; } ``` ## Usage Example ```rust use stemedb_storage::{HybridStore, GenericVoteStore, VoteStore}; use stemedb_core::types::Vote; // Create vote store backed by HybridStore (fjall + redb) let kv_store = HybridStore::open("./data")?; let vote_store = GenericVoteStore::new(kv_store); // High-velocity vote ingestion let vote = Vote { assertion_hash: [1u8; 32], agent_id: [2u8; 32], weight: 0.85, signature: sig_bytes, timestamp: now, }; let vote_hash = vote_store.put_vote(&vote).await?; // O(1) aggregation queries (for Materializer) let count = vote_store.get_vote_count(&assertion_hash).await?; let total_weight = vote_store.get_aggregate_weight(&assertion_hash).await?; ``` ## Design Rationale ### Why Separate Votes from Assertions? Traditional databases would store votes as a column or join table: ```sql -- Naive approach: votes as assertion metadata UPDATE assertions SET vote_count = vote_count + 1 WHERE hash = ?; ``` **Problems:** 1. Lock contention when many agents vote on same assertion 2. Lost history (can't see who voted when) 3. Violates append-only semantics **Ballot Box Solution:** 1. Votes are separate, immutable records 2. Each vote is content-addressed 3. Caches enable O(1) aggregation 4. Full audit trail preserved ### Cache Update Strategy When `put_vote()` is called: 1. Serialize vote with rkyv 2. Compute BLAKE3 hash (content address) 3. Store at `V:{assertion_hash}:{vote_hash}` 4. Increment `VC:{assertion_hash}` counter 5. Add weight to `VW:{assertion_hash}` sum The caches are updated atomically with the vote write, ensuring consistency. ### Duplicate Vote Handling The VoteStore does NOT prevent duplicate votes - it stores whatever is submitted. Duplicate detection is a higher-level concern (e.g., "one vote per agent per assertion") that should be enforced at the API layer. This design choice keeps the storage layer simple and lets policy be defined elsewhere. ## Integration with Materializer The Materializer (Phase 2) will use the VoteStore to update Materialized Views: ```rust // Materializer pseudocode for assertion in new_assertions { let votes = vote_store.get_votes_for_assertion(&assertion.hash).await?; let weighted_score = calculate_consensus(votes, trustrank); if should_update_mv(weighted_score, current_mv) { store.put( format!("MV:{}:{}", assertion.subject, assertion.predicate), assertion.serialize() ).await?; } } ``` ## Related Topics - [Storage](./storage.md) - [Assertion](./assertion.md) - [Architecture](../../../architecture.md) - [Vision - The Ballot Box](../../../vision.md#4-2-the-ballot-box-high-velocity-consensus)