Help us shape the future of Go! Take the 2026 Go Developer Survey

eventlog

package
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Sep 22, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

Documentation

Overview

Package eventlog is the reference in-memory event log for the agentsessions walking skeleton. It realizes three parts of the durable-log & replay contract:

  • single-writer enforcement via compare-and-swap on the log head (expected_last_seq);
  • an incarnation fencing token that rejects writes from a superseded incarnation;
  • a per-record hash-chain (tamper-evident; becomes a hash-tree at a fork).

content_hash is the language-neutral value from package canon (RFC 8785 JCS over proto3-JSON), so the chain is verifiable by any implementation — not only this Go host — and the integrity definition lives in exactly one place. A sqlite/Durable Task backend implements the same shape later. See agentsessions-replay-determinism-contract.md (§1, §5, §7).

Index

Constants

This section is empty.

Variables

View Source
var ErrConflict = errors.New("eventlog: seq conflict (single-writer compare-and-swap failed)")

ErrConflict is returned when Append's expectedLastSeq does not equal the log head (another writer advanced the log). This is the single-writer CAS.

View Source
var ErrFenced = errors.New("eventlog: stale fencing token (incarnation superseded)")

ErrFenced is returned when Append is called with a fencing token older than the current one — a superseded (zombie) incarnation trying to write.

Functions

func RecordToProto

func RecordToProto(r Record) *v1.LogRecord

RecordToProto wraps a committed Record as a wire LogRecord: the host-assigned envelope (seq, prev_hash, content_hash, fence) plus the hash-free Event. content_hash is the language-neutral hash from package canon (carried verbatim; not recomputed here).

Types

type Log

type Log struct {
	// contains filtered or unexported fields
}

Log is an append-only, single-writer event log with a hash-chain and fencing.

func New

func New() *Log

New returns an empty log.

func NewFrom

func NewFrom(prefix []Record) *Log

NewFrom returns a log seeded with a prefix (used to realize a replay-fork: the child starts from a copy of the parent's records up to the fork point).

func (*Log) Append

func (l *Log) Append(expectedLastSeq, fence int64, ev api.Event) (Record, error)

Append commits ev as the next record iff expectedLastSeq == head (CAS) and fence is current. It assigns Seq and links the hash-chain. The caller must not rely on ev.Seq.

func (*Log) Head

func (l *Log) Head() int64

Head returns the seq of the last committed record (0 if empty).

func (*Log) NewFence

func (l *Log) NewFence() int64

NewFence advances and returns the current fencing token. A new incarnation calls this to take over; older incarnations holding a smaller token can no longer Append.

func (*Log) Read

func (l *Log) Read(fromSeq int64) []Record

Read returns a copy of all records with Seq >= fromSeq, in order. Replay reads from a baseline (or 0) up to the resume point.

func (*Log) Snapshot

func (l *Log) Snapshot() []Record

Snapshot returns a copy of the full record slice (used to seed a fork).

func (*Log) Verify

func (l *Log) Verify() error

Verify walks the chain and returns an error if any link is broken.

type Record

type Record struct {
	Seq      int64
	PrevHash string
	Hash     string
	Fence    int64
	Event    api.Event
}

Record is one committed log entry: the payload plus ordering, integrity, and fencing metadata. Hash = SHA-256(prevHash || canonical(payload)); a fork sets a child's first prevHash to the parent record's Hash, turning the chain into a tree.

func RecordFromProto

func RecordFromProto(p *v1.LogRecord) Record

RecordFromProto converts a wire LogRecord back to a Record.

type Store

type Store interface {
	// Append commits ev as the next record iff expectedLastSeq == head (single-writer CAS) and
	// fence is current.
	Append(expectedLastSeq, fence int64, ev api.Event) (Record, error)
	// Head returns the seq of the last committed record (0 if empty).
	Head() (int64, error)
	// NewFence advances and returns the incarnation fencing token.
	NewFence() (int64, error)
	// Read returns all records with seq >= fromSeq, in order.
	Read(fromSeq int64) ([]Record, error)
	// Verify walks the chain and reports the first integrity violation.
	Verify() error
}

Store is the error-returning event-log contract the controller depends on, so it can run against either the in-memory Log (via AsStore) or the persistent sqlitelog.Log interchangeably. Every operation can fail because a durable backend does I/O; the in-memory adapter simply never returns an error. The unified shape is the error-returning one because the controller must handle read/head/fence failures from the persistent backend.

func AsStore

func AsStore(l *Log) Store

AsStore adapts the in-memory Log (whose reads cannot fail) to the error-returning Store.

Jump to

Keyboard shortcuts

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