docs/contracts/README.md
Rama main · réplica de lectura del repositorio original.
# Crux Response Contract v1 (CRC-v1)
**Status:** M0 — spec frozen. Canonical home for the portfolio-wide response contract.
**Oracle:** [`crc-v1.schema.json`](crc-v1.schema.json) is the single source of truth. Every emitting endpoint serialises through it; CI validates real responses against it; the daemon serves it verbatim via `get_bootstrap(topic="tool-output")`.
## What it is
A unified, **pointer-first, progressively-hydrated** response envelope shared across CoreCrux `/v1/query/*`, VaultCrux `/v1/memory/retrieve`, and the Crux daemon HTTP + MCP surface. Instead of every endpoint stuffing full content in an ad-hoc JSON shape (~56K tok/q on the LME bench), a CRC-v1 response returns **cheap pointers + a cost_estimate + an agent_decision + a freshness/receipts envelope**, and the caller hydrates only what it needs (~1.6–7.5K tok/q at equal recall, measured on the agent-native LME benchmark).
## Default-on, with a legacy escape hatch
CRC-v1 is the **default** response contract — there are no legacy consumers to preserve, so every read endpoint returns the pointer-first envelope **by default**. A caller that can't yet parse it opts out to the old full payload:
| Surface | Opt OUT to legacy (full payload) |
|---|---|
| HTTP | `Accept-Contract: legacy` request header (also `v0`/`none`/`off`, or `?contract=legacy`) |
| MCP tool call | `contract: "legacy"` argument |
When opted out, the endpoint returns its **legacy shape, byte-identical** to pre-CRC-v1 — preserving CROWN receipt byte-identity for anyone who needs the old shape. The explicit opt-IN forms (`Accept-Contract: crc-v1` / `contract:"v1"`) still work but are redundant now that CRC-v1 is the default.
**Default hydration is `pointer`** (cheap epitomes); ask for `?hydrate=full|summary` to get content inline within the CRC-v1 envelope, or opt out to `legacy` for the old full payload.
## Shape (see the schema for the authority)
```jsonc
{
"contract": "crc-v1",
"kind": "search" | "addressed" | "fact" | "session",
"hydrate_tier": "pointer" | "summary" | "full", // CRC-v1 default = pointer
"pointers": [ { "id", "score", "epitome<=40tok", "reason" } ],
"content": [ { "id", "text", "token_count" } ], // ABSENT at pointer tier
"cost_estimate": { "pointer": N, "summary": N, "full": N },
"agent_decision": { "load_bearing_lane", "fused_confidence", "suggested_next_lane",
"lane_attribution", "read_pointers" } | null, // null unless kind=search
"envelope": { "freshness": {...}|null, "receipts_used", "memories_used",
"autonomy_consumed", "links": { "verify", "open_in_console" } },
"next": { "expand", "resolution_pointer", "canonical_slug" },
"meta": { ... per-endpoint diagnostics ... }
}
```
### Per-`kind` field presence
| field | search | addressed | fact | session |
|---|---|---|---|---|
| `pointers` | ✅ | ✅ | — | — |
| `content` (at summary/full) | ✅ | ✅ | ✅ (value) | ✅ (state) |
| `cost_estimate` | ✅ required | ✅ | optional | optional |
| `agent_decision` | ✅ non-null | null | null | null |
| `envelope.freshness` | — | optional | ✅ required | optional |
| `next.canonical_slug` | optional | optional | ✅ | ✅ |
`addressed` = content-pointer hydration (`fetch-content` / `query_expand`): chunk bodies don't decay, so freshness/slug are optional. `fact` = fact-store resolve where decay/supersession is the whole point, so `envelope.freshness` is required.
**Addressed recall is first-class:** `kind=addressed|fact|session` is an exact key resolve and is **never routed through the BM25 ranker**. It echoes `next.canonical_slug` so the next turn re-addresses by key (cheap, exact) instead of re-searching (fuzzy, lossy), and carries `envelope.freshness` so a re-verify turn is unnecessary.
## Invariants (enforced by the schema + per-repo tests)
1. `hydrate_tier=pointer` ⇒ `content` absent/empty (the cheap default actually stays cheap).
2. `kind=search` ⇒ `pointers` and `cost_estimate` present.
3. Opted-out responses (`Accept-Contract: legacy`) are **byte-identical** to pre-CRC-v1 (per-repo golden test; not expressible in this schema).
4. The schema served by `get_bootstrap("tool-output")` is **this exact file** — drift between schema, serializer, and bootstrap seed is the failure mode M4 guards.
## Vendoring
Repos that emit CRC-v1 (CoreCrux, VaultCrux) vendor a copy of `crc-v1.schema.json` and run `validate_crc_v1.py` against representative responses in CI. The canonical copy lives here; vendored copies are checked byte-equal in CI.
## Validate
```bash
python3 validate_crc_v1.py crc-v1.schema.json fixtures/*.json
```