Grounded answers, their citations, which retrieval runtime answered, and when the system abstains.

How an answer is built

Ask retrieves regions from the active World and answers from them. Every answer carries the regions it used, with the source version, page and bounding box of each. The answer text is those regions' excerpts, concatenated in the order the retriever ranked them — answerMode is evidence_excerpts, and no language model writes any part of it. That is a deliberate boundary, not a gap waiting to be filled quietly: the day a model does generate an answer, answerMode will say a different word, and you will be able to tell from the response rather than from a changelog.

Abstention, and why it is a result

When no region matched the question, the response is an abstention with a reason. That is a result, not a failure: an answer with no evidence behind it is the failure. A region can also be retrieved and still not be citable — if it carries no evidence binding it is dropped, and an answer left with no citations abstains rather than claiming something no region supports.

Which runtime answered

Two retrieval runtimes can answer, and the response always says which one did. retrievalPath is the field; both values are real and neither is a placeholder.

retrievalPathWhat answered, and when you see it
compiled-retrieval-v1The compiled hybrid pipeline: lexical, dense and structure retrieval, RRF-fused, reranked, World Gate filtered. Also returns contextPacket and retrieval diagnostics. This is the path when the active World has a completed retrieval compile run.
excerpt-concatenation-fallbackExcerpt concatenation over the active artifact, scored lexically with graph and temporal signals. Answers are still evidence-bound and citations are built directly from evidence, so this path cannot invent one — but it runs neither dense nor structure retrieval and it is not reranked. You see it whenever the active World has no queryable compiled index.

The fallback is not a rare edge. A World activated before its index was compiled, a compile that failed on an unreachable embedder, and a run still in flight all land here, and the response distinguishes them: retrievalIndex.status is missing, compiled or failed, retrievalIndex.errorClass names the failure class, and retrievalNotice says the same thing in a sentence. An index that exists but has not finished is reported as missing — an incomplete index is not queryable, and half an index is not a smaller index.

Both paths return answer, reason, citations, receipt, activeWorld, freshness, answerMode and retrievalPath. What differs is the per-citation scoring, and it is not normalized across the two: the fallback reports relevance with its lexical, graph, temporal and authority breakdown, while the compiled path reports each source's rank and the reranker score. Presenting one as the other would mean inventing a number neither path measured.

The two paths differ in retrieval quality, so read retrievalPath before comparing answers across Worlds: a difference between two answers can be a difference between two runtimes rather than between two corpora.

The freshness clocks

freshnessWhich clock it is
observedAtWhen the source bytes were first observed. Null where the source ledger has no row for this World's documents.
processedAtWhen the compile job reached a terminal state.
reviewedAtWhen a person answered a compile blocker. This is the only review instant recorded — it is not a general 'someone reviewed this World' timestamp, and it stays null when a compile had no blockers.
activatedAtWhen a person made this version the active World.
activeManifestDigestThe version this answer came from.
candidateAwaitingActivation / candidateManifestDigestTrue, with the digest, when a newer compiled version exists that nobody has activated. You are reading the previous active World until a person activates it.

Note A null in the freshness block means that value is not recorded, or could not be read. It is never a substitute drawn from one of the other clocks. candidateAwaitingActivation is also conservative: it is computed from versions the workspace has activated at least once, the manifest digest the latest compile recorded, and the candidate this request already loaded, so it can read false for a compile that ran before that digest was recorded.

POST/collections/{id}/askScope ask:read

Grounded answer with exact page and bbox citations, or an explicit abstention. Both retrieval paths return the same fields: `answer`, `reason`, `citations`, `receipt`, `activeWorld`, `freshness`, `answerMode` and `retrievalPath`. `answerMode` is `evidence_excerpts` on both -- the answer is the cited excerpts, concatenated in rank order, and no language model writes any part of it. `retrievalPath` names which runtime answered: `compiled-retrieval-v1` (lexical + dense + structure, RRF-fused, reranked and World Gate filtered; also returns `contextPacket` and `retrieval` diagnostics) or `excerpt-concatenation-fallback` when the active World has no queryable compiled index, which also returns `retrievalIndex` and a human-readable `retrievalNotice`. Per-citation scoring differs by path and is not normalized across them: the fallback carries `relevance` with its lexical/graph/temporal/authority breakdown, the compiled path carries per-source ranks and the reranker score. An abstention is a 200 with `code: ANSWER_ABSTAINED` — a result, not a failure.

curl -sS -X POST https://tavonel.com/api/v1/collections/{id}/ask \
  -H "Authorization: Bearer $TAVONEL_API_KEY" \
  -H "content-type: application/json" \
  -d '{ "question": "<question>" }'
Request body
{
  "question": "<question>"
}
StatusResponse
200{ code, answer, reason, citations, receipt, activeWorld, freshness, answerMode, retrievalPath }. answerMode is evidence_excerpts on both paths. retrievalPath is compiled-retrieval-v1 (which also returns contextPacket and retrieval) or excerpt-concatenation-fallback (which also returns retrievalIndex and retrievalNotice). An abstention is a 200 with code ANSWER_ABSTAINED and a reason — a result, not a failure. Read retrievalPath before comparing answers across Worlds: a difference between two answers can be a difference between two runtimes rather than between two corpora.
400QUESTION_INVALID — The question was absent, or shorter than the minimum. RETRIEVAL_QUESTION_INVALID — The retrieval runtime refused the question text itself. COLLECTION_ID_INVALID — The collection id did not match collection-<32 hex>. INVALID_JSON — The body was not parseable JSON.
401AUTH_REQUIRED — No credential was presented, or the bearer token is not a key TAVONEL issued. This is what an unauthenticated request to any scoped route returns.
403API_SCOPE_REQUIRED — The key authenticated and does not carry the scope this operation requires. The request was refused rather than answered with less. PILOT_ACCESS_REQUIRED — The credential is valid and the workspace it names is not admitted to TAVONEL.
409ACTIVE_WORLD_NOT_FOUND — Nothing has been activated for this collection, so there is no World to read, index or answer from. A candidate nobody accepted is not a smaller answer — it is a different one. ACTIVE_WORLD_CHANGED_RETRY — The active version changed while the request was in flight.
413QUESTION_TOO_LARGE — The question exceeded 500 characters.
429API_RATE_LIMITED — The key has used its per-minute allowance for this scope. The window is a fixed clock minute per key and scope; the allowances are on /docs/billing-and-limits.
503ACTIVE_WORLD_STORE_UNAVAILABLE — The World store could not be reached. WORLD_STORE_READ_FAILED — The World store could not be read.

API version 2026-09-02.1 · reviewed 11 September 2026

Something here out of date or wrong? Report an issue with this page.