index

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 29, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

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

View Source
const FileName = "index.db"

FileName is the SQLite index file inside the log dir.

View Source
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

func CanonicalDump(db *DB) (string, error)

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

func Reconstruct(ctx context.Context, db *DB, logDir, runID string, after int64, w io.Writer) error

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

func Open(ctx context.Context, dir string) (*DB, error)

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) Close

func (db *DB) Close() error

Close closes the underlying database.

func (*DB) Keys

func (db *DB) Keys() (map[string]string, []string, error)

Keys returns all registered keys as jkt -> JWK JSON, plus the jkts in ascending order (deterministic header order for exports).

func (*DB) LogOrigin

func (db *DB) LogOrigin() (string, error)

LogOrigin returns the checkpoint origin of the log this index follows ("" until the first Rebuild/Follow pass records it).

func (*DB) LookupCanonical

func (db *DB) LookupCanonical(receiptID string) (*Row, error)

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

func (db *DB) Record(row Row) (*Row, error)

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

func (db *DB) RegisterKey(jkt, jwkJSON string) error

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

func (db *DB) RunRows(runID string) ([]Row, error)

RunRows returns the canonical rows for runID in log-index order — the run view, excluding duplicates by default (Q46, Q82).

func (*DB) TreeSizeIndexed

func (db *DB) TreeSizeIndexed() (uint64, error)

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

func Extract(envelope []byte) (Row, error)

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

func Follow(ctx context.Context, logDir string) (*Stats, error)

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

func Rebuild(ctx context.Context, logDir string) (*Stats, error)

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).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL