Diagnose memory consumers

Available in the 0.10.0 feature preview when the server exposes POST /api/v2/memory/consumers/diagnose. Check the served OpenAPI: earlier 0.10.0 preview images do not contain this route.

Use this read-only endpoint to inspect a consumer's saved progress, the current verified journal boundaries and an optional cursor retained by your application. Every observation comes from one storage snapshot. The operation does not create checkpoints, activate journals, acknowledge events or repair external state.

Permissions and ownership#

Supply a current bearer credential with both memory_read and memory_checkpoint for the exact project, mission, agent and visibility scope. The credential supplies the tenant and subject; the request cannot select another owner. A different subject can read a shared journal if authorized, but cannot inspect your checkpoint. Private journal boundaries are subject-specific too. Rotation to another credential for the same subject preserves ownership. Revocation applies to subsequent requests.

The endpoint inspects one consumer_id, not an unbounded registry of consumers. Its identifier must be 1–128 UTF-8 bytes, nonblank and free of control characters. Standard 64 KiB request limits and Cache-Control: no-store apply. Keep unsigned 64-bit sequences and distances lossless when using JavaScript clients.

Request current state#

curl --fail-with-body http://localhost:7474/api/v2/memory/consumers/diagnose \
  -H "Authorization: Bearer $QILBEE_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"contract_version":2,"scope":{"project_id":"project","mission_id":null,"agent_id":"agent","visibility":"shared"},"consumer_id":"search-cache","witness":null}'

witness is optional. To compare an earlier external observation, supply the complete opaque v2 cursor previously returned by the verified feed or activation endpoint. Copy all of its fields unchanged. Do not construct a cursor from a sequence number or fabricate a digest.

A successful response contains contract_version: 2, the authorized scope, and diagnostics:

Field Meaning
consumer_id The requested subject-owned consumer
active A verified journal exists in this scope
baseline First resumable verified position, or null before activation
high_watermark Current verified tip in this snapshot, or null before activation
checkpoint Intrinsically validated stored v2 progress, or null if absent
checkpoint_status missing, compatible, or history_incompatible
pending_positions Tip sequence minus compatible checkpoint sequence; null when progress is missing or incompatible
witness_status not_provided, compatible, or history_incompatible
checkpoint_relative_to_witness before, equal, or after when both cursors match current history; otherwise null

The checkpoint retains its revision, digest, cursor, authenticated author and update time. An incompatibility does not erase it. No memory bodies, embeddings or event list are returned. A malformed request or encountered storage failure returns an error instead of a partial diagnostic.

Interpret progress without hiding uncertainty#

A missing checkpoint returns 200, with checkpoint_status: "missing" and pending_positions: null. It does not mean zero backlog, an empty corpus or a new consumer. Check the selected scope and subject, then perform the required initial reconciliation before initializing progress.

For compatible stored progress, pending_positions is a sequence distance. It counts positions after the checkpoint up to the snapshot's tip, including updates, reviews and embedding events. It is not a count of distinct memories, currently eligible records or successfully audited events. Zero means the saved cursor reaches the observed tip; it does not prove that external effects were applied or that no new events arrived after the snapshot.

The checkpoint and witness statuses are independent. After a restore, the server may contain a compatible older checkpoint while an externally retained witness belongs to lost history. In that case the response can legitimately show checkpoint_status: "compatible", a numeric pending distance and witness_status: "history_incompatible". Stop incremental application and reconcile the external consumer before trusting that distance as operational progress. Do not silently replace the witness with the new tip.

If both positions are compatible, checkpoint_relative_to_witness compares their sequences in the same verified history. before can result from effects that were applied but not checkpointed, another worker's observation, intentional recovery or restore; the comparison alone does not establish the cause.

An incompatible witness can also come from selecting a different scope or an obsolete baseline. The response reports only the requested authorized scope; it does not probe or identify the witness's source scope. If the application restores its witness together with the database, the server cannot infer external effects that both restored copies have forgotten. Preserve witnesses with the consumer's durable effects when those effects must survive a database restore.

Reconcile incompatible stored progress explicitly#

A self-consistent checkpoint can refer to a history absent from a partially restored database. Diagnostics returns it as history_incompatible with unknown pending distance. Ordinary checkpoint reads and commits still fail closed for that stored state. Diagnosis itself never changes it.

Starting with this feature, the existing explicit recovery operation can reconcile this case. Coordinate workers and durably reconcile external state; then copy the exact revision and checkpoint_digest from the diagnostic, choose a valid cursor from the current journal and submit an explicit recovery command with a stable idempotency key and nonblank evidence_ref.

Recovery validates checkpoint ownership and integrity, both comparison fields and the target history. A stale comparison returns 409 without replacing progress. A target from lost history is also rejected. The successful recovery atomically retains the previous checkpoint, replacement and caller-declared evidence in an immutable receipt. Retrying that exact command returns its historical receipt; it does not overwrite later progress. The evidence reference is recorded, not fetched or externally verified. External effects are not rolled back by this API.

An invalid stored digest, broken journal boundary or missing encountered anchor still produces 500 storage_inconsistency. Recovery does not bypass those checks. Investigate storage or restore a consistent backup; a different idempotency key cannot repair corruption.

Errors and work limits#

Status Meaning and action
200 Inspect all statuses; success does not imply compatible history or completed effects
400 Invalid version, consumer identity, cursor encoding or request fields
401 / 403 Restore current authentication, both capabilities and the exact scope grant
413 Request exceeds the body limit
500 Encountered corrupt or inconsistent storage, or an internal failure; no partial diagnostic

Well-formed incompatible cursors are observations in this endpoint's 200 response. Unlike the verified feed, this diagnostic does not return 409 merely because the witness is incompatible. Missing consumers likewise use a status field, not 404. Common error envelopes retain contract_version: 1.

Application work is bounded by a fixed number of metadata and boundary lookups, independent of the reported distance. The endpoint does not walk the middle of the journal, enumerate all consumers or fetch memory payloads. Storage-engine work and latency are not constant-time guarantees. To check intermediate events, use the bounded journal audit and retain its explicit coverage. A successful diagnostic can coexist with unencountered middle-history corruption; it is not a full-volume integrity claim.

The lightweight Python consumer uses this diagnostic with a destination-owned durable witness before applying a bounded verified page. It treats incompatible history as a reconciliation condition and does not reset checkpoints automatically.