# Record context assembly

> Record metadata-only evidence for the sources, compactions, and cache outcomes behind an agent model call.

Canonical page: https://anectico.com/docs/agents/context/


Context assembly evidence answers three questions about a model step: which sources were considered
and included, whether the context overflowed or was compacted, and whether a provider cache reused
input tokens. It travels as span events on the model-call span, keeping the model step itself a model
step.

## What is recorded

- An ordered source list containing kind, stable ID, optional version/digest/owner, sensitivity,
  token count, position, visibility, and an optional reason code.
- The input budget, reserved output budget, assembled token count, overflow outcome, and an assembly
  SHA-256 digest.
- Compaction trigger and strategy, before/after counts and digests, summarizer identity, retained
  overlap, and IDs removed.
- Cache provider, outcome, optional cache/config digests, and optional measured savings.

Source IDs form the lineage. Use a document ID, memory item key, tool call ID, or other stable
identifier—not text. A source with `kind = memory` must use its `memory_item_key`, which lets
Anectico connect the model input back to memory provenance.

## What is never recorded

These events do not accept prompt text, retrieved document bodies, memory content, generated
summaries, or tool-result bytes. They are metadata-only even when the project's content policy would
permit content. Prompt/completion and tool content remain separate, opt-in capture paths.

## Record from an SDK

Start an agent run, make a model-category span current, and call the run handle's assembly,
compaction, or cache method inside that span. The SDK refuses a call when no recording model span is
active and validates the whole event before recording any part of it.

- Go: `run.RecordContextAssembly(modelCtx, value)`, `RecordContextCompaction`, and
  `RecordContextCache`. Go takes `modelCtx` explicitly because its OpenTelemetry API has no ambient
  current-span accessor.
- JavaScript: `run.recordContextAssembly(value)`, `recordContextCompaction`, and
  `recordContextCache` inside `context.with(modelContext, ...)`.
- Python: `run.record_context_assembly(value)`, `record_context_compaction`, and
  `record_context_cache` inside the current model span's context manager.

See the [Go SDK](/docs/reference/go-sdk#context-assembly-events),
[JavaScript SDK](/docs/reference/javascript-sdk#context-assembly-events), and
[Python SDK](/docs/reference/python-sdk#context-assembly-events) for examples and
[Agent span and event attributes](/docs/reference/agent-attributes#context-events) for every bound.

The OpenAI and Anthropic auto-instrumentation wrappers record cache evidence without an explicit
cache call when their response includes the provider cache field. Reused tokens greater than zero
produce `hit`; a reported zero produces `miss`; absence produces no cache event. Providers do not
report the ordered source list or compaction decision, so those two events remain explicit.

## Read context evidence

All read surfaces return the same metadata-only fields; none resolves a digest or source ID into
content.

- REST: `GET /api/v1/agent-runs/{runId}/graph` includes `context` on every model step. Use
  `GET /api/v1/agent-events?run_id={runId}&category=context` for the individual assembly,
  compaction, and cache rows. Add `context_source_id={stable-id}` to keep assembly events whose
  ordered source list contains that lineage ID.
- MCP: `get_agent_run_graph` includes the same step summary. The gatewayed
  `list_context_events` read takes `run_id` and optional `context_source_id`; it requires
  `mcp:read` plus `agents:read` and returns bounded identifiers, hashes, counts, and outcomes only.
- CLI: `anectico agent-runs context <run-id> -o json` prints the model-step summaries and all three
  context event kinds. Use `-o table` for a deterministic path/value view.

`context.instrumented` is the instrumentation answer. It is `true` only when at least one valid
context event was accepted for that model step. A model step from an older producer, or one whose
only context event was rejected, returns a summary with `instrumented: false`; its empty counters do
not mean a measured zero. Conversely, `instrumented: true` with `assembled_tokens: 0` is a real
measured zero. Never infer instrumentation from a number or from `provenance.normalizer_version`.

The storage schema preserves that step/event presence bit, but not a separate presence bit for each
optional numeric member inside an accepted event. Consequently an accepted event can return numeric
zero for a member the producer omitted. Treat those member-level zeroes as the V1 stored projection;
only `instrumented` distinguishes an uninstrumented step from an instrumented one.

## How to verify

Choose a run whose model span recorded assembly, compaction, and cache events. The following three
reads must name the same model span and the same three accepted events:

```bash
curl -sS -H "Authorization: Bearer $ANECTICO_TOKEN" \
  "$ANECTICO_URL/api/v1/agent-events?project_id=$ANECTICO_PROJECT&run_id=$RUN_ID&category=context"

curl -sS -H "Authorization: Bearer $ANECTICO_TOKEN" \
  "$ANECTICO_URL/api/v1/agent-runs/$RUN_ID/graph?project_id=$ANECTICO_PROJECT"

anectico agent-runs context "$RUN_ID" --project "$ANECTICO_PROJECT" -o json
```

For MCP, call the read gateway twice: `execute_read_action` with action
`list_context_events` and arguments `{"run_id":"<run-id>"}`, then with action
`get_agent_run_graph` and the same run ID. The MCP credential needs `mcp:read` and `agents:read`.

Verify exact values rather than presence alone:

- `assembly.sources` has the expected IDs, positions, token counts, visibilities, and reason codes;
  `assembly_sha256` is the lowercase SHA-256 of each source ordered by position as
  `position<TAB>id<TAB>visibility<NEWLINE>`.
- A truncated assembly has `overflow: "truncated"`, at least one source with
  `visibility: "truncated"`, and a bounded reason such as `budget`. Its assembled count is below
  `budget_tokens - reserved_output_tokens`.
- A compaction's `ratio` equals `after_tokens / before_tokens`; the producer should omit the ratio
  because Anectico derives it. Its removed source IDs and before/after hashes must match the
  producer's decision.
- A cache hit's `reused_tokens` equals the model step's `model.usage.cache_read_tokens`; a reported
  miss is a separate outcome and may carry a measured zero.
- `steps[].context.instrumented` is `true`, and its assembled-token, overflow, compaction-count,
  and cache-outcome summary agrees with the event rows. The CLI JSON is the REST graph projected
  onto those context fields, without renaming or recomputing them.

To verify one lineage link, add `context_source_id=<stable-id>` to the REST event request or to the
MCP `list_context_events` arguments. For a memory source, use the exact 64-character
`memory_item_key`, then read:

```bash
curl -sS -H "Authorization: Bearer $ANECTICO_TOKEN" \
  "$ANECTICO_URL/api/v1/memory-items/$MEMORY_ITEM_KEY/propagation?project_id=$ANECTICO_PROJECT"
```

The context source ID must equal `memory_item_key`, and the propagation point at the model run's
instant must carry the trust label then in force. Source IDs containing whitespace or more than 128
bytes are refused as a whole event; they never appear as partially accepted lineage.
