Documentation
¶
Overview ¶
Package index is the SQLite follower index of the behalf log: a derived, rebuildable projection of the Tessera tile directory (D1, Q55, Q56). The log is the source of truth; everything here is a materialised view replayable from the entry bundles, which is Tessera's own follower pattern. The index is never restored from backup — always rebuilt from the log (Q76) — and the authoritative order everywhere is the log index (Q58, Q82).
Column discipline (Q26, receipt-schema-v1.md §1): every receipts column is an ingest-side projection of fields read out of the stored envelope's payload span. The payload bytes themselves are never re-serialized — the read path extracts scalar fields and, for reconstruction, splices the exact stored span back out (the span rule).
Duplicate collapse (Q46): the index collapses on receipt_id. A duplicate leaf — the same receipt_id appearing again at a later log index, which only the crash race can produce — is recorded with duplicate_of pointing at the first occurrence, and run views exclude duplicates by default. The canonical row for a receipt_id is always its lowest log index.
Index ¶
- Constants
- func CanonicalDump(db *DB) (string, error)
- func Reconstruct(ctx context.Context, db *DB, logDir, runID string, after int64, w io.Writer) error
- type DB
- func (db *DB) Close() error
- func (db *DB) Keys() (map[string]string, []string, error)
- func (db *DB) LogOrigin() (string, error)
- func (db *DB) LookupCanonical(receiptID string) (*Row, error)
- func (db *DB) Record(row Row) (*Row, error)
- func (db *DB) RegisterKey(jkt, jwkJSON string) error
- func (db *DB) RunRows(runID string) ([]Row, error)
- func (db *DB) TreeSizeIndexed() (uint64, error)
- type Row
- type RunSummary
- type Stats
Constants ¶
const FileName = "index.db"
FileName is the SQLite index file inside the log dir.
const SchemaVersion = "behalf.sh/index/v1"
SchemaVersion is the follower index schema this package reads and writes. An index.db carrying an unknown version is refused: the fix is always to delete it and rebuild from the log (Q76), never to migrate data forward by hand.
Variables ¶
This section is empty.
Functions ¶
func CanonicalDump ¶
CanonicalDump renders the receipts table as deterministic text, ordered by log index, one row per line with columns tab-separated in schema order (duplicate_of renders as "-" when NULL). This is the comparison form for the rebuild-determinism guarantee: two rebuilds of the same log must produce byte-identical dumps.
func Reconstruct ¶
Reconstruct streams one run as NDJSON in log-index order (Q82): the global total order filtered to the run view, duplicates excluded (Q46). Each line is
{"log_index":N,"leaf_hash":"<hex>","payload":<verbatim receipt JSON>}
where payload is the exact stored payload span spliced out of the entry bundle — the signed bytes, never re-serialized (the span rule). Assembly is byte concatenation.
after is the pagination cursor: only rows with log_index > after are emitted (pass a negative value for the start of the run; the last line's log_index is the next cursor). An unknown run errors only on an uncursored call — a cursor past the end of a run legitimately yields nothing.
Before splicing, every envelope is re-hashed and checked against the indexed leaf hash, so a reconstruction never emits bytes the index does not vouch for.
Types ¶
type DB ¶
type DB struct {
// contains filtered or unexported fields
}
DB is an open follower index.
func Open ¶
Open opens (creating or migrating as needed) the follower index inside the log dir. A pre-existing minimal seed schema (the Week-2 log service's dedup window) is migrated in place: the dedup columns are carried over so the Q46 window is never lost, and the remaining columns are re-derived by replaying the log up to the published checkpoint — rebuilt, not restored (Q76).
func (*DB) Keys ¶
Keys returns all registered keys as jkt -> JWK JSON, plus the jkts in ascending order (deterministic header order for exports).
func (*DB) LogOrigin ¶
LogOrigin returns the checkpoint origin of the log this index follows ("" until the first Rebuild/Follow pass records it).
func (*DB) LookupCanonical ¶
LookupCanonical returns the canonical row for receiptID, or (nil, nil) if the receipt_id has never been indexed. This is the ingest dedup lookup (Q46).
func (*DB) Record ¶
Record writes one extracted row (see record). The ingest path calls this as each durability ack resolves, so the follower stays current without a replay; Rebuild and Follow produce byte-identical rows from the log.
func (*DB) RegisterKey ¶
RegisterKey stores (or refreshes) a public key JWK by its RFC 7638 thumbprint, for the export bridge's header. Note: the keys table is the one part of index.db that is NOT reconstructible from the entry bundles (envelopes carry only thumbprints); keys are re-registered by the log service and ingest paths on next use after a rebuild.
func (*DB) RunRows ¶
RunRows returns the canonical rows for runID in log-index order — the run view, excluding duplicates by default (Q46, Q82).
func (*DB) TreeSizeIndexed ¶
TreeSizeIndexed returns the tree size the last Rebuild/Follow pass covered: every log index below it is indexed. Ingest-time Record calls do not advance it — only a replay pass does, after walking the bundles.
type Row ¶
type Row struct {
LogIndex uint64
ReceiptID string
LeafHash string // hex, RFC 6962 leaf hash of the stored envelope bytes
Kind string
RunID string
RunIDProvenance string // which Q7 fallback produced run_id — grouping stays honest
TraceID string
SessionID string
Txn string
Acti string
ConversationID string
CapturedAt string
EmitterJKT string
EmitterCounter int64
ActorJKT string
OperationName string
OperationTarget string
OutcomeStatus string
AttributionVerification string
AttributionClass string
StepKey string
// DuplicateOf is nil for a canonical row; for a duplicate leaf it is
// the log index of the first occurrence of this receipt_id (Q46).
DuplicateOf *uint64
}
Row is one receipts-table row: the indexed projection of one log leaf. All six correlation keys are columns; only run_id is required at ingest (Q7). String fields are stored as written by Extract — empty string for an absent optional field.
func Extract ¶
Extract derives an index Row from one stored envelope's bytes: the leaf hash over the exact envelope bytes (RFC 6962, the same hash Tessera's tree covers) and the indexed columns read from the payload span. It is a pure function of the envelope bytes, which is what makes rebuilds deterministic: replaying the log re-derives byte-identical rows.
LogIndex and DuplicateOf are left zero/nil — they are assigned where the row meets the log (ingest ack or replay), not by extraction.
Only receipt_id is required (Q7 requires run_id of receipts, but ingest hygiene is append-and-flag per Q45 — the index projects what is there).
type RunSummary ¶
type RunSummary struct {
RunID string
Receipts int64
FirstCapturedAt string
LastCapturedAt string
Verified int64
Asserted int64
Broken int64
}
RunSummary is one row of ListRuns: a run's receipt count, capture-time range, and attribution rollup (the stored receipt-level verification state, Q12/Q86). Duplicates are excluded (Q46).
func ListRuns ¶
func ListRuns(db *DB) ([]RunSummary, error)
ListRuns summarises every run in the index, ordered by each run's first log index — the log's own order (Q58), not alphabetical.
type Stats ¶
type Stats struct {
Origin string // checkpoint origin of the log
From uint64 // first log index this pass walked
To uint64 // checkpoint tree size: the pass covered [From, To)
// Indexed is the number of rows written by this pass (To - From).
Indexed int
// Duplicates is how many of those rows were duplicate leaves,
// recorded with duplicate_of pointing at the first occurrence (Q46).
Duplicates int
}
Stats describes one replay pass over the entry bundles.
func Follow ¶
Follow runs one incremental catch-up pass: from tree_size_indexed to the current published checkpoint size, over the same code path as Rebuild's loop. Rows the ingest path already wrote are re-derived idempotently (identical bytes), so following after live ingest is safe.
func Rebuild ¶
Rebuild wipes the receipts table and reconstructs the entire index by streaming the entry bundles from log index 0 to the published checkpoint tree size. This is the Q76 restore path in its entirety: the index is never restored from backup, always rebuilt from the log. Deterministic — two rebuilds of the same log produce byte-identical table contents.
The keys table is preserved: registered JWKs are the one thing the entry bundles do not carry (envelopes name keys by thumbprint only).