RememberStackdocs.remember.dev

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)

FieldMeaning
fact_id, kind, labelRelation or observation identity
evidence_countDistinct current-testimony lineages
validity{valid_from, valid_until, ingested_at, invalidated_at}
contradiction / contradiction_groupLive co-members package
supportcurrent | withdrawn

There is no confidence field on the shipped fact record.

EvidenceResult (evidence grain)

FieldMeaning
claim_id, doc_id, chunk_idAnchors
claim_text, source_span, char_start, char_endText + grounding
is_current_testimonyCurrency filter result
asserted_at, claim_valid_*Source-asserted testimony times (not system belief)
corroboration_count, grouped_claim_idsDuplicate 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 answer
  • evidence_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

GrainMay answerMust not pretend to answer
factWhat we currently hold true (validity-filtered)Source gossip as verdict
evidenceWhat sources asserted (claims) / current source text (chunks)“Is it true now?” without adjudication
compiledPre-paid synthesis with citationsLive confirmed fact
compositeOne operation's cohesive mixed typed payloadA 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)

FieldWhat it tells the agent
pg_live_tsLive spine clock for confirmed rows
p1_written_inlineWhether P1 was written on the inline path (lag measurement evolves)
p1_believed_at_horizonOldest system-time P1 can answer (null = unbounded)
kCompile 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

kindMeaningCorrect agent move
unknown_entityNothing resolvesWiden resolve / spelling / search
known_emptyEntity exists; no matching factsTrust absence within freshness
boundaryStated capability limitRead 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

supportMeaning
currentAt least one current-testimony lineage supports
withdrawnFact 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

  1. Read grain first — refuse load-bearing action on wrong grain.
  2. If negative non-null — branch on kind.
  3. If contradiction — report all sides (or fetch continuation).
  4. If truncated — decide whether to continue.
  5. If dropped_by_hydration high — consider re-query / freshness.
  6. Prefer fact_evidence + evidence_totals when using fact_context.
  7. For ContextBundle/v1, inspect both complete child envelopes separately.
  8. If using K — check freshness.k.