The Receipt That Tells You What It Couldn't Find
When the answer is incomplete, NAOMS tells you what it couldn't reach โ instead of pretending it found everything
You ask your device a question โ "show me the photos from the trip last May" โ and an empty answer comes back. What does that empty answer mean? It could mean there are no such photos. It could also mean the system didn't bother to look in the one place they live. Most software cannot tell you which. The answer set is empty either way, and the silhouette of what's missing looks identical to the silhouette of what was never there.
We think that's a quiet kind of dishonesty, and we built the system to refuse it.
flowchart LR A[your question] --> B[answer] B --> C[what it found] B --> D[receipt: what it couldn't reach, and why]
Two extra surfaces on every answer
When you ask your memory a question, the answer comes back with two surfaces that most systems don't give you. The first is a list of what is missing โ and why it couldn't be reached. The second is a record of when the rest was gathered, and from whom. We call the pair a receipt.
The reason they exist is simple to state and hard to honour. A being asking her own knowledge graph a question deserves either a complete answer or an honest one. Partial knowledge is treated here as a first-class result, not a failure to paper over. When the system cannot answer fully, it returns what it has and a structured account of what it could not reach. Your right to know what's missing is no less important than your right to know what's present.
This is the difference between "the friend has no photos from that trip" and "we did not ask the friend." Those two sentences describe completely different states of the world. When the answer set is empty, they look the same on screen. The receipt makes them distinguishable โ and once you've seen them distinguished, you can't go back to trusting a bare empty result again.
A closed taxonomy of ignorance
The list of what's missing isn't free-form text. It's drawn from a closed, fixed vocabulary โ a closed taxonomy of ignorance. Every way the system can fail to know something fully has a name. There are exactly ten names, and they split into two kinds.
Four of them are serious. They mean the system refused to look, or wasn't ready to accept the evidence, or hit a deliberate limit on how much it would do at once, or had every candidate row denied at the access gate. These are the kinds of gap you'd want to act on: a privacy posture that blocked the search, a verifier that isn't up yet, a concurrency cap that filled, a wholesale denial.
The other six are soft. They mean the system tried but is still waiting โ a cold cache it hasn't warmed yet, a background expansion still running, a peer's record that hasn't replicated to your device, a wait window that elapsed before the data arrived, a filter that happened to exclude everything this time, an exhausted search where every reachable peer was asked and none had it yet. These are the kinds of gap you can wait through.
The closedness is the entire point. An open list โ one that allowed "unknown reason" โ would quietly absorb every new failure mode the system grows into, and you'd never see them. A closed list forces every new shape of ignorance to either map onto one of the ten existing names or surface as a registered, visible new one. Nothing about why an answer came back thin gets to hide in a catch-all.
And the serious-versus-soft split is itself a kindness. Telling you which kind of not-knowing you're looking at lets you respond proportionally. A soft gap says "try again in a moment." A serious gap says "the answer you're seeing has been shaped by a refusal or a limit โ read it as such." An empty result that says nothing about which of those produced it is asking you to guess, and guessing about your own memory is exactly what we wanted to eliminate.
One detail matters here: the system itself owns the classification of serious-versus-soft, not the app reading the answer. If each reader re-derived seriousness on its own from the name of the gap, the readers would slowly drift apart, and drift would become silent disagreement between what you see and what the system means. So the judgment travels with the answer, decided once, at the source.
Where the rest came from
The second surface is about provenance. When part of an answer was gathered from a trusted peer rather than from your own device, that part arrives with a freshness record: a snapshot of which records were drained at the exact instant the answer was emitted, which peers contributed, and what state each peer reported itself to be in.
That record is signed by the peer who answered, and verified on your side against the very question you asked โ so the proof is bound to the question, not just floating loose. The upshot is that you can trace every claim in a composed answer back to a device, a record, and a position in that record's history. This is trust you can withdraw coherently. If a peer who once contributed later revokes its relationship with you, the next answer carrying that peer's name flips its status from "ok" to "revoked." If a peer answered but was in a degraded, half-updated state, the status says so, and anything building on top can decline to compose over a shaky foundation.
The freshness record is also honest about its own limits. It carries a fixed caveat, emitted with every single receipt: the wall-clock time in it is local only โ your device's clock, not a universal one โ and cross-device comparisons should use record position, not timestamps. The system does not pretend its clock is everyone's clock. It says so, on the wire, in the same envelope as the data: this time is mine; use the record's sequence if you want to line things up across devices. A system that quietly assumed its own clock was authoritative would be lying by omission. This one declines to.
The shape of the search
There's a third thing the receipt gives you, almost as a side effect: the shape of the search that produced the answer. When you ask a question, the system runs a small, bounded cascade on your behalf. Your own device first. If that's enough, the search ends there. If it isn't, and your privacy posture allows it, the question travels to a ranked set of trusted peers, each of whom answers from their own records, shares only what their own policy permits, and signs what they send. The results are folded together, deduplicated, and verified.
Every step of that cascade is bounded โ there is no "ask everyone, forever." There's a limit on how wide it fans out, a window it's willing to wait, an admission control on how many requests run at once. And crucially, those bounds can themselves appear among the ten names: too many requests at once, the wait elapsed before the data arrived, every reachable peer was asked and none had it yet. You see not just the answer but the silhouette of the looking that produced it.
What this is really for
Underneath all of it is one of the three principles the whole system is built on, the one we call Mystery: the system respects what it cannot know, and it is honest about the limits of its own knowledge. Forgetting is a feature here, not a bug; not-knowing is a state to report, not to hide. A receipt is what Mystery looks like when you make it concrete and put it on the wire.
What a person needs from a system she's meant to trust with her memory is three honest things: the answer she sees, with the means to verify each piece of it; the shape of the silence, so an empty result is never confused with a refusal or a limit or a privacy choice; and the source of every claim, so trust extended to a peer can be taken back cleanly when something changes. The receipt gives her all three. The cascade gives her a search she can reason about. The fixed vocabulary of gaps gives her words for what she doesn't know.
Together they make partial knowledge legible. And legible partial knowledge โ an honest account of the edges of what the system found โ is, we think, exactly what separates a tool you can trust with your memory from one that merely returns results and hopes you won't ask what's behind them.
Written by AI agents from real project logs; owned and edited by Mujo.