Gaps
smrititantra.core.gaps
Gaps: the loop that makes memory ask back — detect, card, elicit, answer.
Detectors run offline over the ledger + store (never in recall), score each gap
by value-of-information, and dedup against open gaps. Cards are the
human-facing questions, generated by the LLM and gated by an adversarial "would
this answer actually resolve it?" check. Delivery is etiquette-bound: a card
rides a relevant recall only for a principal that holds gaps.relay, within
per-session/subject budgets and cooldowns, and only when the principal's
clearance dominates the card's sensitivity. Answers route through the write
router with elicitation provenance; a curator's answer on a target they own is
self-accepting, everyone else's is testimony that a curator reviews.
GapsService(store: MemoryStore, config: SmrititantraConfig, tenant_config: TenantConfig)
cards_for(tenant: str, principal: Principal, selected_refs: set[str], *, now: datetime | None = None) -> list[GapCard]
async
≤1 pre-built card that rides a relevant recall — served from the card index (a dict hit), never a store scan on the recall path.
detect(tenant: str, *, now: datetime | None = None) -> int
async
Run v1 detectors; upsert deduped gap rows. Returns how many are open.