Bounded Storage Architecture

QNTX implements a configurable bounded storage strategy to prevent unbounded database growth. The system enforces limits, evicts oldest attestations when exceeded, and logs eviction events for observability.

Storage Limits (16/64/64 Strategy)

All limits configurable via am.toml. When exceeded, the oldest attestations for that constraint are deleted and the event is logged to storage_events.

Self-Certifying ASIDs

For bulk ingestion, self-certifying ASIDs are required. Without them, the 64-actor limit causes silent data loss once exceeded.

Using the same actor for all ingestion hits the 64-entity limit. Instead, use each attestation's own ASID as its actor — this bypasses the limit entirely.

// Self-certifying: ASID vouches for itself
asid, _ := id.GenerateASID(entity.ID, "processed", context, "")
attestation := &types.As{
    ID:     asid,
    Actors: []string{asid},  // Self-certifying
    // ...
}

Shared actors are appropriate for authority-based claims ("github@oauth") or source tracking, but be aware of the 64-actor limit.

Configuration

[database.bounded_storage]
actor_context_limit = 16   # attestations per (actor, context) pair
actor_contexts_limit = 64  # contexts per actor
entity_actors_limit = 64   # actors per entity (subject)

Zero or negative values fallback to defaults (16/64/64).

Observability

Database Glyph

The db symbol palette command opens the database glyph showing:

Evictions are broadcast in real-time via WebSocket (storage_eviction).

Storage Events Table

All eviction events are logged to storage_events with event type, actor/context/entity, deletion count, limit value, and eviction details (JSON).

# Query enforcement events
qntx db stats --limit 20

# Or directly
sqlite3 ~/.qntx/db/sqlite.db \
  "SELECT event_type, COUNT(*) FROM storage_events GROUP BY event_type"

Enforcement Flow

Enforcement runs through Rust's single rusqlite connection (avoids dual-driver SQLite corruption):

RustBackedStore.CreateAttestation()
  → Rust FFI: INSERT attestation
  → Rust: enforce_limits()
      ├─ actor_context_limit: DELETE oldest for (actor, context) if > limit
      ├─ actor_contexts_limit: DELETE least-used contexts if actor has too many
      └─ entity_actors_limit: DELETE least-recent actors if entity has too many
      (each logs to storage_events)

See Also