Evidence and classification
How agents send evidence as exact excerpts, how Felspar reads numbers, dates and text, and what "needs evidence" means.
Agents never tell Felspar the answer. They send what their sources say, word for word, and Felspar decides what that means under your policy.
Excerpts
An excerpt is the shortest passage from a source that answers a question, with where it came from:
{
"text": "Give your users wallets with three lines of code.",
"source": {
"class": "company-site",
"id": "https://tidewell.example",
"locator": "https://tidewell.example/#hero",
"observedAt": "2026-10-21T09:00:00Z"
}
}
| Field | Meaning |
|---|---|
text |
The source’s exact words. At most 2,000 characters. Never a label or a summary. |
source.class |
The kind of source, one the question accepts (see below). |
source.id |
Which source: a URL, a record ID, a ticket number. |
source.locator |
Where in the source: a URL with a section anchor, a field name. Optional, but give each distinct passage its own locator. |
source.observedAt |
When the evidence was true, in ISO 8601. For a web page, when the agent read it. For a record, its own last-updated time. Never a date printed on the page, such as a copyright year. |
source.revision, source.sensitivity |
Optional. A revision of the source, and a sensitivity label. |
A question can take one excerpt, or a list of up to three from different places. The same words can answer several questions; send them under each one.
Source classes
A pack lists the kinds of evidence it accepts, such as company-site, crm-record or carrier-tracking. Each question accepts some of them. An excerpt whose class the question doesn’t accept is refused with source_class_not_accepted. The job’s brief lists the accepted classes for each question.
Freshness
A pack sets how old evidence may be, such as 90 days. Age is counted from each excerpt’s observedAt to the time of the decision. Evidence older than that doesn’t count, and the result says the case is stale. The result’s explanation.evidenceFreshUntil says when the evidence behind a decision stops being fresh. The pre-action gate refuses to act on a decision past that time.
How Felspar reads each question
| Question type | How it is read | Model? |
|---|---|---|
| Number | Read exactly from the text. “1,200 employees” is 1200. | No |
| Date | Read exactly from the text, as a calendar date. | No |
| Answer choice | Classified against the pack’s definitions for each answer. | Yes, bounded |
| Yes/no | Classified the same way, when the policy defines yes and no. | Yes, bounded |
A number or date question may also take a typed value, { "value": 1200, "source": { ... } }, when the agent already has it from a structured record. Answer-choice and yes/no questions always need text: a typed label such as "payments_api" is refused with label_needs_mapping.
When a number or date can’t be read exactly, the question stays open with a reason: value_not_found, value_ambiguous (more than one candidate), unit_mismatch or not_integer.
Classification
For answer-choice and yes/no questions, Felspar’s managed classifier reads one excerpt and the question’s released definition: the meaning, each answer with its inclusions, exclusions and examples, and always a “cannot determine” option. It returns how likely each answer is.
Felspar accepts the leading answer only if its probability is at or above the pack’s threshold. Otherwise the question stays open. The reasons you may see on an excerpt are:
| Reason | Meaning |
|---|---|
probability_below_threshold |
The best answer wasn’t likely enough. Usually the text is vague, or the definitions need clearer wording. |
probability_tie |
Two answers were equally likely. |
normalization_abstained |
The classifier chose “cannot determine”: the text doesn’t say. |
classification_unsupported |
The pack has no classification material for this question. |
classification_failed |
Classification didn’t finish in time. Retrying may help. |
classification_disabled |
Classification is temporarily switched off. The question stays open; try again later. |
classification_ceiling_reached |
The workspace or caller reached its daily classification ceiling. |
Every result shows how each excerpt was read, under result.interpretation: the method, the value, the leading answer, its probability, the threshold, close alternatives, and whether the answer came from cache.
What keeps classification bounded
- It only chooses among answers your policy defines. It can’t invent an outcome.
- It only runs for questions the decision needs, given the answers known so far.
- Each excerpt is answered at most once per job. Identical requests are answered from a cache for 30 days. The cache is keyed by a fingerprint of the request, not by the text.
- A job’s classification has a 10-second deadline. Anything unanswered by then is
classification_failed. - Each job, each workspace and each caller has a ceiling on classification work per day.
- Replay never calls a model. Verifying a receipt rebuilds the decision from the recorded classifications.
Writing definitions that classify well
Classification quality depends mostly on how the policy words each answer. In short: one judgment per question; describe each answer by what the text says, never by an absence; give every common kind of text its own answer; include a “none of these” answer; prefer several positively worded answers over yes/no; and test both sides. See Draft a pack.
Gaps, conflicts and “needs evidence”
When Felspar can’t decide, it says why instead of guessing. The decision’s status is one of:
| Status | Meaning |
|---|---|
ready |
A rule matched. There is an outcome. |
gap |
A question the decision needs has no accepted answer. |
stale |
The only evidence for a question is too old. |
conflict |
Evidence for a question disagrees. |
review_required |
The pack requires a person to review. |
blocked |
The decision can’t proceed. |
result.explanation.needs lists each open question with its accepted source classes, maximum age, and how each excerpt was read. result.retry turns that into instructions for the agent. See Retries and attempts.
What Felspar keeps
Felspar keeps the excerpts, every classification and the result with the case, for 30 days, so a receipt can be verified and backtests can re-decide real cases. See Security, privacy and data.