Metadata-Version: 2.4
Name: arxo
Version: 0.2.0
Summary: Open a pinned canon, ask a closed question, receive the evaluation document with proof.
License-Expression: Apache-2.0
Project-URL: Homepage, https://arxo.io
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
Requires-Dist: wasmtime>=14
Dynamic: license-file

# Arxo Law (Python)

Open a pinned canon, ask a closed question, receive the evaluation document
with proof.

```python
from arxo import open

fristen = open("de.bgb.fristen@0.1.0")
r = fristen.truth("frist_ende", ["frist", "2026-03-20"], {
    "legalTime": "2026-09-17",
    "timezone": "Europe/Berlin",
    "deadlinePolicy": "urn:de:corpus:clir:bgb-fristen#BGB_FRISTEN_TAG",
    "answers": [
        {"predicate": "frist_ereignis", "args": ["frist", "2026-03-06"]},
        {"predicate": "frist_dauer_tage", "args": ["frist", "14 calendar_day"]},
    ],
})
r.evaluationStatus  # "COMPUTED"
r.truthStatus       # "TRUE_ONLY"
r.sources; r.proof; r.hashes; r.document
```

Bare values are wrapped by the declared parameter type of the canon:
`"2026-03-06"` is a `Date`, `"14 calendar_day"` a `Quantity`,
`"730000 KZT"` a `Money`, `"Abschlagszahlung"` the enum constant of the world,
`"frist"` a short entity id in the case namespace (`urn:…:entity:frist`),
`"urn:x:y"` an entity id as given. Exact types (`Decimal`, `Money`,
`Quantity`) take strings only; a number is a `FactError`. `Arg` objects
(`{"kind": …}`) pass through. `state` defaults to `"yes"`; `"unknown"` leaves
no assertion. Wrong names raise `FactError` with `path` and `nearest`.

## Canons

```
pip install arxo arxo-canon-bgb-fristen     # de.bgb.fristen
pip install arxo-canon-ogpo-vts             # kz.corpus.ogpovts
pip install arxo-canon-unidroit-picc        # unidroit.picc
```

An installed canon is trusted by hash, not by name: the CLIR bytes are checked
against `contentHash` of its `package-meta.json` before use; a mismatch is an
`IntegrityError`.

## Questions

`truth`, `why_not`, `collect`, `deadline`, `calc`, and `positions` are thin
wrappers over `ask`. There is no second evaluator.

```python
fristen.why_not("frist_ende", ["frist", "2026-03-20"], case_input)
fristen.collect("frist_ende", ["frist", "?ende"], case_input)   # free position
fristen.deadline({"date": "2026-03-06", "days": 14, "unit": "calendar_day"}, case_input)
fristen.positions(case_input).positions
```

## Answer

`evaluationStatus` is the discriminant. `truthStatus` is a separate field.
Refusal is a value. `document` is always the engine's canonical bytes;
`hashes` carries `program`, `semantic`, `result`. `via` is `"local"`.

## Explain

`fristen.explain(answer, node_id=None)` hands the answer's own evaluation
document to the host's `law_explain` (`https://mcp.arxo.io/mcp`, or
`mcpEndpoint` in `open` options) and returns `{"text", …structuredContent,
"via": "mcp"}`. A package opened with `offline=True` refuses with
`TransportError`.

## Passport

`pkg.passport()` repeats the committed formalization measure of the package
(`EXECUTABLE`, `ANCHORED`, …) and `in_model(predicate)` tells whether a name
is in the CLIR.

## Boundaries of this release

The wheel embeds `law_wasm_core.wasm`; Python 3.12+ and `wasmtime` are
required. Execution is local only: `remote=True` (execution on the host),
the registry source, the router and `questions()` are not in this release.
Everything else mirrors `@arxo/law` 0.2.0.
