unlob Docs
Browse documentation

Coverage receipts: what was searched, and what was not

Every ground answer carries a receipt, so an agent knows when the evidence is incomplete instead of inferring absence from a short list.

Why a receipt

A short answer and a complete answer look the same from the outside. On an exhaustive index, nothing found means the query was wrong; on an admission-controlled one, it may mean the index holds little on the topic — or that a slice of it was unreachable, or that the freshness window excluded everything, or that only one vertical was searched. An agent that cannot tell these apart concludes “there is nothing on this” and states it.

why_not answers that question for one URL. The receipt answers it for a whole request: every ground and changes response carries a coverage object saying what was searched, what was not, and whether the set is enough.

The fields

{
  "complete": false,
  "partial": false,
  "searched": {
    "objective": "…", "vertical": "news", "routed": true, "mode": "hybrid",
    "pool": 40, "stories": 17, "stories_expanded": 8,
    "filters_applied": ["collapse=story", "safe=true", "published_from=now-7d"]
  },
  "not_searched": {
    "shards_configured": 4, "shards_down": 0,
    "verticals_excluded": ["code", "science"],
    "explicit_dropped": true,
    "story_expansion_truncated": false,
    "stories_not_expanded": 9
  },
  "freshness": {
    "max_age": 604800, "newest_published_at": 1757790000, "oldest_published_at": 1757300000,
    "within_max_age": true, "undated_excluded": true
  },
  "independent_origins": 2, "origins": 3, "hosts": 11, "copies": 19,
  "source_roles_present": ["primary", "secondary"],
  "source_roles_missing": ["official", "aggregator", "ugc"],
  "known_gaps": [
    "9 lower-ranked stories were not expanded into their members",
    "only the news vertical was searched (chosen by the router; name one to override)",
    "passages that declare no publish date are excluded by max_age",
    "explicit content was dropped by the default safety gate",
    "no official source in the evidence set"
  ]
}
FieldMeaning
completefalse whenever any part of the index was unreachable, expansion was cut short, or lower-ranked stories were left unexpanded.
partialThe same flag a search carries: a slice of the corpus did not answer.
searchedThe objective, the vertical actually queried (and whether the router chose it), the mode, the size of the candidate pool, how many distinct stories it held and how many were expanded into their full membership, and the filters that applied.
not_searchedShard slots configured and down; verticals the index holds that this call did not query; whether explicit content was dropped; whether the latency budget stopped expansion; stories left unexpanded.
freshnessThe window asked for, the newest and oldest publish dates in the set, whether every item is inside the window, and whether undated passages were excluded.
independent_originsOrigins with distinct owners across the evidence — see Provenance.
origins, hosts, copiesDistinct origins, distinct hosts, and total passages seen across every expanded story, republishes included. hosts: 11, copies: 19, independent_origins: 2 is the shape of one story syndicated widely.
source_roles_present / _missingWhich source classes the evidence contains, and which it does not. A set with no official or primary source is reported as such rather than left to be noticed.
known_gapsThe same facts in plain language, for a model to read.

Reading it

Three checks cover most of what goes wrong:

  • partial — retry, or say the result is incomplete. Never treat it as evidence of absence.
  • independent_origins against your own bar — two outlets under one owner, or one wire dispatch and its reprints, are one origin. The number of hosts is not the number of independent sources.
  • source_roles_missing — if the roles you need are missing, the receipt has already told you, and next_actions on the response usually names the filter that would find them.

verticals_excluded matters when the router chose a vertical for you. Naming one yourself is the override; leaving it empty lets the router pick, and the receipt says which it picked.

What it does not report

The receipt reports what this request did and did not search. It does not report the criteria by which admission decides what the index holds — that is not a caller-observable property — and it cannot report passages that were removed before the request, which is what why_not is for on a per-URL basis.

Next