Response envelope
Most systems return rows. RememberStack returns rows plus a machine-readable account of the answer itself — because the caller is an agent that must decide whether to act, re-query, or escalate to a human.
This page documents the shipped wire shape for assured operations (and primitive compositions that emit the same envelope). Open SQL uses QueryResult/v1 instead; see Open query.
Envelope: one cohesive typed response
An Envelope is flat. Top-level grain selects which result tuples are
populated, and temporal_scope states the exact selection applied:
{
grain: fact | evidence | compiled | composite,
temporal_scope:
| { mode: current, evaluated_at, believed_at, identity_regime }
| { mode: at, at, evaluated_at, believed_at, identity_regime }
| { mode: overlap, from, to, evaluated_at, believed_at, identity_regime }
| { mode: history, evaluated_at, believed_at, identity_regime }
| { mode: as_of, valid_at, evaluated_at, believed_at, identity_regime },
// result tuples (populated by grain / operation)
entities: [ EntityCandidate… ],
facts: [ FactResult… ],
evidence: [ EvidenceResult… ],
fact_evidence: [ { fact_kind, fact_id, claim_id, stance: supports|contradicts }… ],
evidence_totals: [ { fact_kind, fact_id, stance, returned, total }… ],
chunks: [ ChunkEvidenceResult… ],
sources: [ SourceRecord… ],
transcript: [ … ],
nodes / paths / edges / ranking / changes / aggregate / pages: …,
freshness: {
pg_live_ts,
p1_written_inline,
p1_believed_at_horizon,
k: { compiled_at, stale, open_flags } | null
},
truncation: { truncated, returned, estimated_total, total_is_exact, continuation, reason } | null,
dropped_by_hydration: n,
excluded_unstamped: n,
negative: null | { kind, explanation, workaround }
}
FactResult (fact grain)
| Field | Meaning |
|---|---|
fact_id, kind, label | Relation or observation identity |
evidence_count | Distinct current-testimony lineages |
validity | {valid_from, valid_until, ingested_at, invalidated_at} |
contradiction / contradiction_group | Live co-members package |
support | current | withdrawn |
There is no confidence field on the shipped fact record.
EvidenceResult (evidence grain)
| Field | Meaning |
|---|---|
claim_id, doc_id, chunk_id | Anchors |
claim_text, source_span, char_start, char_end | Text + grounding |
is_current_testimony | Currency filter result |
asserted_at, claim_valid_* | Source-asserted testimony times (not system belief) |
corroboration_count, grouped_claim_ids | Duplicate collapse metadata when present |
Provenance is flat on the claim (and via top-level sources[]), not a nested provenance: { hydrate_handle, derivation } object.
fact_evidence + evidence_totals
How fact_context binds facts to testimony without blending grains:
fact_evidence[]— explicit fact↔claim stance edges returned with the answerevidence_totals[]— exact per-fact stance counts (returned/total) so caps stay honest
Both arrays identify a fact by (fact_kind, fact_id). Relation and observation
UUIDs are separate namespaces and may contain the same UUID, so consumers must
never join or group these records by fact_id alone.
ContextBundle/v1: both authorities, still separate
answer_context is the sole side-by-side testimony/fact response. It does not
use grain = composite, and it does not nest parts inside an envelope:
{
contract: "ContextBundle/v1",
testimony: Envelope, // complete evidence-grain testimony_context response
facts: Envelope // complete fact-grain fact_context response
}Each child retains its own temporal scope, freshness, truncation, drops, and
typed negative. The wrapper adds no retrieval, ranking, or transformation. A
schema or execution failure in either child fails the whole request; a typed
negative is a valid completed child and remains inside the bundle. There is no
EnvelopePart, Envelope.parts, or compatibility wire shape.
Grain discipline
| Grain | May answer | Must not pretend to answer |
|---|---|---|
| fact | What we currently hold true (validity-filtered) | Source gossip as verdict |
| evidence | What sources asserted (claims) / current source text (chunks) | “Is it true now?” without adjudication |
| compiled | Pre-paid synthesis with citations | Live confirmed fact |
| composite | One operation's cohesive mixed typed payload | A container for independent responses |
Evidence envelopes may carry both evidence[] (claims) and chunks[] (confirmed source-text). Different semantics — never fuse as one unlabeled UUID soup.
Default evidence mode: current testimony only. Opt in for superseded testimony; historical operations declare history explicitly.
Three non-negotiable rules
1. Contradiction co-members are never silently absent
Returning one side of a live contradiction group without indication of the others is a contract violation.
- Co-members return inline up to a guaranteed cap.
- Beyond cap: still always
group_id,returned,total,continuation.
2. No silent caps
Hub neighborhoods and large sets return ranked pages with truncation markers and continuations. total_is_exact tells you whether the estimated total itself hit a cap; reason carries a machine-readable budget cause when the producer can distinguish one (for example expansion_budget or result_budget).
3. Hydration drops are counted
Projections may nominate candidates the spine rejects. dropped_by_hydration keeps ranking honest. Compound structures (paths) drop as units.
Freshness block (shipped field names)
| Field | What it tells the agent |
|---|---|
pg_live_ts | Live spine clock for confirmed rows |
p1_written_inline | Whether P1 was written on the inline path (lag measurement evolves) |
p1_believed_at_horizon | Oldest system-time P1 can answer (null = unbounded) |
k | Compile time, stale flag, open evidence-change flags when K was consumed |
The graph has no separate freshness stamp: SQL/PGQ and recursive helpers read the same PostgreSQL repeatable-read snapshot as hydration.
Finite believed_at horizons → query before horizon yields typed boundary, not partial silent history.
Typed negatives
| kind | Meaning | Correct agent move |
|---|---|---|
unknown_entity | Nothing resolves | Widen resolve / spelling / search |
known_empty | Entity exists; no matching facts | Trust absence within freshness |
boundary | Stated capability limit | Read workaround; re-plan |
Hard-forgotten content is not a separate kind — it is indistinguishable from never-existed. There is no content-level denied in the library.
Media derivation fields (open query, not envelope)
derivation_kind / evidence_mode / rich source locators for media are available on the SQL query-space occurrence views, not as nested envelope provenance objects on EvidenceResult. Use Open query for those columns; use claim source_span / char offsets on the envelope for grounded text.
Support marker
| support | Meaning |
|---|---|
current | At least one current-testimony lineage supports |
withdrawn | Fact still present but current testimony support hit zero via toolchain path — caveat + audit |
Temporal scope
temporal_scope is required and discriminated by mode. fact_context
returns current, at, overlap, or history; each response includes its
evaluation and belief instant plus the requested world-time coordinates.
These modes use current system belief. A historical system-belief audit uses
the separate facts_as_of(valid_at, believed_at, …)/open-SQL path and returns
an as_of scope where applicable.
identity_regime prevents silently mixing today’s merge map with yesterday’s
beliefs when an explicit identity-as-of audit is requested.
Agent consumption checklist
- Read
grainfirst — refuse load-bearing action on wrong grain. - If
negativenon-null — branch on kind. - If
contradiction— report all sides (or fetch continuation). - If
truncated— decide whether to continue. - If
dropped_by_hydrationhigh — consider re-query / freshness. - Prefer
fact_evidence+evidence_totalswhen usingfact_context. - For
ContextBundle/v1, inspect both complete child envelopes separately. - If using K — check
freshness.k.