Skip to main content
gb_edges holds the final state of a fact. It cannot say what a remember call did to it: a closed fact keeps no trace of its old invalid_at, and a fact that was merely stated again leaves only a link in gb_edge_artifacts. The edge event log, gb_edge_events, keeps the steps: an append-only table, one row for each fact a call touched, written in the same transaction as the artifact. It is what the admin UI plots in the Temporal changes view. The model of the two timelines and the invalidation rule are in Temporal facts; this page is only about the log. Code: storeEdges and contradict in internal/memory/memory_remember/temporal.go (the writers), model.EdgeEvent in internal/db/graph/model/model.go, InsertEdgeEvent and ListEdgeEvents in internal/db/graph/{sqlite,postgres}/db.go, the endpoint in internal/api/admin/remember_runs.go (RememberRunTemporalOf).

The table

valid_at never changes once an edge is inserted, so the edge’s valid_at together with invalid_at_before and invalid_at_after is the whole before and after of the fact in event time. The table is created automatically in an existing database (CREATE TABLE IF NOT EXISTS, no migration); calls made before it existed have no events.

Events

Facts of the call that need no change (a repeat inside the same artifact, a contradiction whose periods do not overlap) write nothing. One fact can have two events in one call: created, then superseded.

Example

“Alice works at Acme” (reference time 2023-01-01, run A), then “Alice started working at Globex” (2024-03-01, run B), as in Temporal facts:

Reading it

  • Go: graph.ListEdgeEvents(ctx, db, artifactID) returns the events of the artifact and of every artifact below it through parent_id (the chunks of a long text, its web searches and series observations), oldest first, each with its fact in its current state (Edge, with the endpoint names).
  • Admin UI endpoint: GET /v1/gb/admin/api/remember-run-temporal?run_id=<id>[&db=<name>], described in Remember. It uses the artifact of the run (gb_remember_runs.artifact_id), so a run that stored nothing has no events.
  • SQL, for the history of one fact: SELECT * FROM gb_edge_events WHERE edge_id = ? ORDER BY id (indexed, like artifact_id).

Limitations

  • Only facts are logged. Entities have no valid_at or invalid_at, so nothing about them can be invalidated.
  • The log records what remember does. A fact that is closed or deleted some other way (SQL, deleting a dataset) gets no event.
  • The log is not pruned: it grows with the number of facts a call touches. Deleting a dataset’s edges removes their events.