Markdown for LLMs
Read answers
The source Markdown for this article. Copy it into your assistant or download it as a text file.
# Read answers
An answer from an executable model is a document, not a sentence: the outcome, the rules that fired, diagnostics on what blocked a derivation, source addresses, legal time and hashes. This page is the single reference for reading it, including the status table other pages link to. The Guide pages on [silence](/guide/silence/) and [explain and doubt](/guide/explain-and-doubt/) cover the user's side.
## Keep the raw answer
Never flatten an answer to a boolean. Store the untouched response under the question that produced it, then derive views: a later step may need a field this one ignores, and reproduction needs the hashes as received.
```ts
type RawAnswer = {
bytes: Uint8Array; // untouched response, kept for replay
callOk: boolean; // transport and call shape accepted
evaluationStatus: string; // see the table below
truthStatus?: string; // TRUE_ONLY | FALSE_ONLY | BOTH | NEITHER
value?: unknown; // kind-specific payload
whyNot?: unknown; // absent, [] or a blocker list: three different facts
issues?: unknown[]; // engine messages, kept verbatim
provenance?: unknown; // rules, sources, hashes, legal time
};
```
Status: labeled pseudocode. Not executed; it defines no contract beyond the prose.
## The three axes
Read every answer on three axes, in order, and never merge them.
| Axis | Field | Question |
|---|---|---|
| Call | error flag, exception, refusal | did the call itself go through |
| Evaluation | `evaluationStatus` | did the engine finish the computation, and if not, why |
| Result | `truthStatus`, `value`, `positions` | what the finished computation establishes |
- `COMPUTED` is not a positive result. It says the computation finished; a computed answer can still support neither side.
- A refused call is not `NEITHER`. Fix the call (predicate name, arity, types, project) instead of reading silence into it.
Refusal shape from the local CLI, run from a directory without a case project:
```text
law: REFUSAL LPK-E0201: no law.toml here or above — pass the project via --project
```
Status: ran locally in an earlier authoring session (`law ask`); not re-run for this page.
## Evaluation status
The full set defined by the specification and the published SDK types. Read it before the truth status or values.
| `evaluationStatus` | Meaning | Allowed next step |
|---|---|---|
| `COMPUTED` | the evaluation finished | read the result axis |
| `MISSING_INPUT` | a required input snapshot (for example a calendar) or function input was not supplied or is invalid | supply the named input; do not invent it |
| `MISSING_POLICY` | a required policy (for example a deadline policy) is not set or is unusable | ask the human or the integrator which policy applies |
| `REQUIRES_JUDGMENT` | the canon routes an element to an authority's judgment | stop; record a human judgment (see [Human decisions](/agent-engineering/decisions-and-scenarios/)) |
| `INTERPRETATION_REQUIRED` | a disputed reading must be chosen | show the readings the canon names; a human selects one |
| `NON_EXECUTABLE` | the needed part of the model cannot run (opaque term, unknown function, non-exhaustive match, unstratifiable negation) | report it; this is a model limit, not a case fact |
| `EXTERNAL_UNAVAILABLE` | an external value or its snapshot is missing | supply the snapshot or report the gap |
| `SOURCE_RESOLUTION_FAILED` | a source or edition could not be resolved | check the pin and edition (see [Pin context](/agent-engineering/context-and-time/)) |
| `PRIORITY_CONFLICT` | a priority cycle arose in context; no tie-break is made | report the conflict group |
| `UNRESOLVED_NORMATIVE_CONFLICT` | two incompatible positions stand with no priority between them | show both; never pick one |
| `CONFLICTED_INPUTS` | accepted inputs conflict and the package's policy says halt; absent that policy this status does not arise | correct the inputs |
| `TYPE_ERROR` | a term failed on types, currency, dimension or date/instant mismatch | fix the submitted values or report the model defect |
| `RUNTIME_ERROR` | any other evaluation error | report the issue verbatim |
| `RESOURCE_LIMIT` | a limit stopped the computation | narrow the question or raise the limit, then re-ask |
Precedence and scope, as the specification states them:
- A truth or why-not `NEITHER` caused by a candidate rule's failed term names that failure. With several codes the order is `MISSING_INPUT`, `MISSING_POLICY`, `NON_EXECUTABLE`, `EXTERNAL_UNAVAILABLE`, `TYPE_ERROR`, `RUNTIME_ERROR`, `RESOURCE_LIMIT`. `INTERPRETATION_REQUIRED`, `UNRESOLVED_NORMATIVE_CONFLICT` and `REQUIRES_JUDGMENT` rank above term failures.
- `INTERPRETATION_REQUIRED` belongs to a result, not the document: an independent question in the same case stays `COMPUTED`.
- A dated parameter with no value on the date is the law's own silence: the result stays `COMPUTED` with a warning issue.
- For `collect` and `positions` a candidate's term failure need not surface as the status. Read `issues` too.
Observed: with the deadline policy left out, a collect over the German Civil Code periods canon returned `NON_EXECUTABLE`, an empty value, empty `missingInputs`, and an error issue coded `MISSING_POLICY`:
```text
evaluationStatus: NON_EXECUTABLE value: [] missingInputs: []
issue MISSING_POLICY (error): rule urn:de:corpus:clir:bgb-fristen#TagesfristEnde:
head computation — urn:de:corpus:clir:bgb-fristen#frist_ende.arg1: deadline:
DeadlinePolicy is set neither by request nor by context/profile (SPEC §86)
```
Status: ran locally (@arxo/law 0.3.3, de.bgb.fristen@0.1.0), 2026-10-04; the run also carried two `CONTEXT_FIELD_DEFAULTED` warnings. Route on the issue code, and never show the empty value as "no deadline".
## Truth status, NEITHER and silence
For a proposition the engine keeps a pair: is there an accepted positive support, is there an accepted negative one.
| `truthStatus` | Positive support | Negative support | Reading |
|---|---|---|---|
| `TRUE_ONLY` | yes | no | established |
| `FALSE_ONLY` | no | yes | the opposite is established |
| `BOTH` | yes | yes | both derived; show both proof lines |
| `NEITHER` | no | no | nothing derived either way |
`NEITHER` is neither "false" nor "the law is silent": the model derived nothing for this question on these facts, and a norm missing from the model is not a norm missing from the law.
Worked example: package `kz-labour-code` (Labour Code of the Republic of Kazakhstan), predicate `feeding_break_too_short`, legal time 2026-09-01. A 25-minute break with one child is `TRUE_ONLY` (`resultHash` `sha256:3e75a474…`, shortened). A 30-minute break with one child is `NEITHER`:
```text
Не установлено ни что «перерыв для кормления ребёнка короче установленного
минимума», ни обратное. Это не утверждение ложности и не заключение о
молчании права: в модели нет вывода ни в одну сторону.
```
A 30-minute break with two children is `TRUE_ONLY` again: the one-hour rule for two or more children fires where the thirty-minute rule stays silent. A rule that does not fire proves nothing about the opposite.
Status: ran via the public MCP endpoint (root route), 2026-10-03, all `COMPUTED`.
## Each kind on its own terms
`law_ask` serves six kinds: `truth`, `collect`, `calc`, `deadline`, `positions`, `why_not`. Each has its own value shape and its own meaning of "empty"; do not read them with one helper.
**Collect** returns the distinct values satisfying the condition. One can be bound into a later step; several mean none is chosen; none is the absence of a derivation, not zero. Over MCP, break minutes for the known parties returned `25`; for unknown parties, a computed empty list:
```text
Значение: пустой перечень: в модели не найдено ни одного подходящего значения.
```
Status: ran via the public MCP endpoint (root route), 2026-10-03.
Over `de.bgb.fristen` with the duration left out, `collect` on `frist_ende` returned an empty list with `COMPUTED`, `truth` returned `NEITHER`, and `missingInputs` was empty in both. So an empty, computed collection can still mean "a fact was not given"; the why-not report tells which.
Status: ran locally (@arxo/law 0.3.3, de.bgb.fristen@0.1.0), 2026-10-04.
**Calc** evaluates an arithmetic tree: `(2 + 3)` computed to `5` with `resultHash` `sha256:6ce72afd202dacd139e47ca63a6d9db82f2914a7196bd30f6e6dc76feb244f68`. An unfinished calc is not a number. **Deadline** computes on the pinned calendar: 10 calendar days after 2026-09-01 expire on 2026-09-11; without its policy and calendar snapshot it is incomplete.
Status (calc, deadline): ran via the public MCP endpoint (root route), 2026-10-03.
**Positions** lists normative positions that arose from the facts, each with a `modality`, a `status`, a bearer, often a beneficiary, source anchors and the creating rule. The executable modalities are duty, liberty, power and immunity; a prohibition is a duty of forbearance, and other surface forms lower to these four. Show every position with its modality. With the feeding-break facts the answer held two positions of modality duty, status `ACTIVE`, each with an achievement goal and a window from 2016-01-01.
Status: ran via the public MCP endpoint (root route), 2026-10-03.
An empty positions list does not by itself establish a cause: facts may be missing, the canon may not model the position, a reading may be unselected. Read `evaluationStatus` and `issues` before saying why.
**Why-not** takes the truth question's shape; its root carries the same statuses, judgment requests and missing inputs as the matching truth question, and its value is the blocker report below.
## Missing versus conflicting information
When a derivation is absent, read status, then the diagnostic fields the answer actually has, then the next step they allow. The explanation may be incomplete; do not fill the gap with a guess.
### Diagnostic fields
| What the answer carries | What it says | Allowed next step |
|---|---|---|
| `whyNot` absent | no report was built (not requested, or not built for this kind) | ask `why_not` explicitly before explaining |
| `whyNot: []` | the report was built and no rule head matches the goal | say the model has no rule for this goal on this pin; check `interpretationGated` |
| `whyNot` with blockers | per-rule conjuncts marked `SATISFIED`, `UNDETERMINED` or not satisfied, with continuations | collect the undetermined facts, or stop on a failed guard |
| `whyNotError` | building the report failed | report the error; no cause is known |
| `whyNotTermErrors` | a candidate rule's term failed (rule, code, message) | follow the code, as in the status table |
| `interpretationGated` | rules for the goal exist but are switched off because their reading is not selected | show the readings; a human selects |
| `missingInputs` | input-side requirements (rule, code), such as a missing snapshot | supply them |
| `judgmentRequests` | a judgment the canon reserves for an authority | stop for a human judgment |
| `truthStatus: BOTH` | both supports derived; not an absence | isolate both derivations |
| `issues` | engine messages, including warnings that did not change the status | keep verbatim, route by code |
The MCP server attaches a report to a `NEITHER` truth answer (and to answers over facts with document provenance); the `why_not` kind always builds one. In the SDK run above, `truth` held no report and a separate `whyNot` call built it.
`missingInputs` is input-side ("not supplied"); blockers are derivation-side ("this conjunct did not hold"). An unsubmitted case fact usually appears only as an undetermined blocker.
The specification names the blocker kinds a why-not graph may show: false body, missing fact, conflicting premise, defeated rule, source not in force, unselected interpretation, missing judgment, unresolved reference. An answer shows some, not necessarily all; undetermined is never false.
### Missing facts
Over `de.bgb.fristen` with the duration left out, the report for `frist_ende` held two strict, undetermined blockers: `TagesfristEnde` with one continuation (`frist_ereignis` satisfied, `frist_dauer_tage` undetermined) and `Verlegung193` with none.
Status: ran locally (@arxo/law 0.3.3, de.bgb.fristen@0.1.0), 2026-10-04.
The same shape over the labour code, with only the child count submitted:
```text
по фактам дела (v3 = 2): тело не определено — фактов не хватает
? v2 < 60 — variables are not bound by the goal: v2
? child_feeding_break_minutes(urn:kz:tk:employee:1, urn:kz:tk:employer:1, v2)
✓ children_under_eighteen_months(urn:kz:tk:employee:1, 2)
✓ v3 ≥ 2 — comparison satisfied
```
Status: ran via MCP in the authoring session on a regional route that has since been retired; not re-run on the root route.
Next step: ask for the undetermined fact (`law_rules` with `contract: true` names the inputs). Stop when answered or when the person has no such fact; record it as unknown to the case.
### A failed guard
With 30 minutes and one child, the first rule reads both facts and fails only its comparison:
```text
по фактам дела (v2 = 30, v3 = 1): тело не выполнено
✓ child_feeding_break_minutes(urn:kz:tk:employee:1, urn:kz:tk:employer:1, 30)
✓ children_under_eighteen_months(urn:kz:tk:employee:1, 1)
✓ v3 = 1 — comparison satisfied
✗ v2 < 30 — comparison not satisfied
```
Status: as above (retired regional route, authoring session).
Nothing is left to collect, and no rule derives "the break is sufficient". Pass `NEITHER` on; re-asking cannot change it.
### Exceptions, readings and conflicts
- **Defeat.** A body holds but a prioritized exception removes the conclusion; the blocker's `strength` separates defeasible rules from defeaters. Only facts or a competent decision change it.
- **Unselected reading.** `interpretationGated` or `INTERPRETATION_REQUIRED`: a human chooses, never the agent.
- **Both sides.** For `BOTH`, check the case facts for a contradiction first; if they are consistent, report both derivations. Report the two conflict statuses the same way. Never resolve a conflict by preference.
Status: NOT RUN for this page; no defeat, gated reading or `BOTH` instance was captured. Reproduction: a case satisfying both a rule and its exception; a canon with an interpretation group left unselected; facts satisfying two rules with opposite heads.
### Empty search is not absence
An empty search or an empty `whyNot` says nothing about the act's text. Never conclude "the norm was never formalized": search ranks by similarity, and the rule may sit under another predicate, package or unselected reading. Say what was searched on which pin; see [Empty search results](/agent-engineering/connect-and-discover/#empty-search-results).
## Issues and limits
Keep engine messages verbatim and route by code and severity. Over the measurement-uncertainty example case, a computation stopped on a type error while the unfinished record showed an empty collection:
```text
Вычисление прервано ошибкой типов.
Запись незавершённого результата (это не окончательный ответ): Значение:
пустой перечень: в модели не найдено ни одного подходящего значения.
## Сообщения движка
- Ошибка `TYPE_ERROR`: rule urn:jcgm:clir:gum#CombinedStandardUncertainty:
head computation — sqrt_bounds: the argument is Integer, Decimal or Rational,
got number — связанных узлов: 1.
```
Status: ran locally in an earlier authoring session (`law ask` in the example project); not re-run.
An unfinished record is not the answer; passing its values on reports a crash as a finding. A why-not blocker lists at most eight continuations per rule and sets `truncated: true` when it cut any; stop claims at every limit marker.
## Sources, proofs and hashes
"Established" is always relative to a support, and four supports answer four questions.
**What the text says.** `law_sources` with a fragment from a rule's anchors returns an excerpt, language, status and the hash of the full pinned source:
```text
urn:kz:corpus:clir:labour-code#TK_ART82 (article/82, ru-KZ/official), выдержка:
Статья 82. Внутрисменные и специальные перерывы
1. На отдельных видах работ работникам предоставляются внутрисменные
перерывы, обусловленные технологией и организацией производства и труда,
которые включаются в рабочее время. ...
hash полного источника: sha256:b9fc7d308b57c2a0ffa7f47de7686115432c77c6247e68f03aaa5b98272c2be6
```
Status: ran via MCP in the authoring session on the retired regional route; not re-run.
An anchor is an address, not proof that the rule renders the text faithfully. **Match is not derivation**; the search tool says so on every call:
```text
Это кандидаты ПОИСКА, не ответ права: сходство текста не устанавливает
ни факта, ни нормы.
```
Status: ran via MCP in the authoring session (top score 0.4027); not re-run.
**What derives it.** Ask with `proof: true` to get the evaluation document with its proof graph. `law_explain` takes that document, or the `question` with `resultHash` and `codeHash` for a verified recomputation, and returns the rule-to-premises chain with a fingerprint a repeat must reproduce. `law_inspect` reads a saved document without recomputing: hash checks, slices by query, rule, position or node, and diffs.
Status: parameter set of `law_explain` read from the live tool list, 2026-10-03; NOT RUN as calls. Reproduction: ask the feeding-break question with `proof: true` and pass the result to both tools.
**Will it stand.** `law_argue` returns one of four classes: unassailable, merely defensible, rejected, no arguments. Read it with the skipped-rules list: the dispute profile covers less of the language, so "no arguments" with the decisive rule skipped means robustness was not measured. On a cap refusal raise `limits.maxArguments`; report a merge refusal verbatim:
```text
мир не слить: пакет "calc-obligations" объявляет семантику 0.2.2, остальные — 0.2.4
```
Status: ran via MCP on the retired regional route; refused twice before analysis.
| Support | Question | Tool | Failure looks like |
|---|---|---|---|
| Derivability | does the engine derive it | `law_ask` with proof | silence with its diagnostics |
| Admissibility | is the evidence admitted | the package's evidence policy | unadmitted or refuted support |
| Robustness | does it stand in dispute | `law_argue` with limits | rejected, or unmeasured when decisive rules were skipped |
| Fidelity | does the model render the source | human review via a mismatch report | a filed report, not a derived value |
For protected predicates admission controls derivation: a rejected support grounds nothing (see [Collect facts and evidence](/agent-engineering/collect-facts/)). Robustness reads derivation's output, not the world. Fidelity conditions all three; a suspected mismatch goes to a report naming the package, fragment or predicate and the answer's call id.
## Validation record
| Check | Where | Result |
|---|---|---|
| Status set (14 values) | specification; `@arxo/law-types` 0.3.3 `EvaluationDocumentEvaluationStatus` | identical |
| `whyNot` / `whyNotError` / `interpretationGated` semantics | MCP server source, read 2026-10-04 | as described |
| Feeding-break truth, collect, calc, deadline, positions, why-not | public MCP endpoint, root route, 2026-10-03 | as quoted |
| BGB empty collect, `NEITHER`, blockers, `NON_EXECUTABLE` with `MISSING_POLICY` | @arxo/law 0.3.3, de.bgb.fristen@0.1.0, 2026-10-04 | as described |
| Blocker shapes, source excerpt, search notice, argue refusal | MCP, authoring session, retired regional route | carried over, not re-run |
| Type-error record, CLI refusal | local CLI, authoring session | carried over, not re-run |
| Eight-continuation cap | specification only | not observed live |
Previous: [Collect facts and evidence](/agent-engineering/collect-facts/)
Next: [Human decisions, interpretations and scenarios](/agent-engineering/decisions-and-scenarios/)
Related: [Silence](/guide/silence/) · [Explain and doubt](/guide/explain-and-doubt/)