contextstate

package
v0.4.0 Latest Latest
Warning

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

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

Documentation

Overview

Package contextstate holds the durable context contract. Sessions, checkpoints, commit validation, retention classes, and volume Limits live here.

Map: contracts.go = shape bounds, sentinels, ValidationError, ContentRef, PayloadRecord, Reassemble; ContentRef delegates to contextref for the canonical reference form. checkpoint.go = SourceID through Session. commit.go = CommitRequest and its validators. limits.go = Limits. store.go = MemStore. Rationale: ../docs/plans/contextstate.md. Contribution rules: ../AGENTS.md.

Index

Constants

View Source
const (
	// MaxIdentifierBytes bounds every identifier string.
	MaxIdentifierBytes = 128
	// MaxPayloadReferenceBytes bounds a payload reference string.
	MaxPayloadReferenceBytes = 256
	// MaxSourceRangeEvents bounds a source range's event span.
	MaxSourceRangeEvents = 100_000
)

Shape bounds pin the FORM of a durable value, not its volume. Volume bounds are caller-owned; see limits.go.

Variables

View Source
var (
	// ErrInvalidRecord wraps every validation failure.
	ErrInvalidRecord = errors.New("invalid context record")
	// ErrSessionNotFound marks a read of an unknown session.
	ErrSessionNotFound = errors.New("session not found")
	// ErrStaleRevision marks a commit against a moved revision.
	ErrStaleRevision = errors.New("stale revision")
	// ErrStaleBinding marks a commit against a moved binding.
	ErrStaleBinding = errors.New("stale binding")
	// ErrCheckpointConflict marks a reused operation key that carries
	// a different request.
	ErrCheckpointConflict = errors.New("checkpoint conflict")
	// ErrPayloadNotFound marks a read of an unknown payload.
	ErrPayloadNotFound = errors.New("payload not found")
	// ErrPayloadRevoked marks a Get of a payload MemStore.Revoke marked
	// revoked. Get denies the content; MemStore.Status still answers.
	ErrPayloadRevoked = errors.New("payload revoked")
	// ErrOverLimit marks a commit that breaks a volume bound.
	ErrOverLimit = errors.New("commit over volume limit")
)

Sentinels. ErrInvalidRecord wraps every validation failure; each sentinel has a producer in this package.

Functions

This section is empty.

Types

type BindingRevision

type BindingRevision struct {
	Provider   string `json:"provider"`
	Model      string `json:"model"`
	Generation uint64 `json:"generation"`
}

BindingRevision names the provider-model pair and its generation.

func (BindingRevision) Validate

func (b BindingRevision) Validate() error

Validate bounds both identifiers and requires a positive generation.

type Checkpoint

type Checkpoint struct {
	ID            CheckpointID    `json:"id"`
	Revision      Revision        `json:"revision"`
	Binding       BindingRevision `json:"binding"`
	ActiveContext []byte          `json:"active_context"`
	TurnID        uint64          `json:"turn_id"`
}

Checkpoint is one committed state of a session.

func (Checkpoint) Validate

func (c Checkpoint) Validate() error

Validate enforces a valid ID, a valid Binding, a non-empty ActiveContext, and a positive TurnID.

type CheckpointID

type CheckpointID struct {
	SessionID      string      `json:"session_id"`
	SourceRange    SourceRange `json:"source_range"`
	Algorithm      string      `json:"algorithm"`
	SchemaVersion  uint32      `json:"schema_version"`
	IdempotencyKey string      `json:"idempotency_key"`
}

CheckpointID identifies one checkpoint within a session.

func (CheckpointID) Validate

func (c CheckpointID) Validate() error

Validate enforces the identifier bounds, a valid same-session SourceRange, an Algorithm bounded at 64 bytes, a positive SchemaVersion, and a bounded IdempotencyKey.

type CommitRequest

type CommitRequest struct {
	OperationID       string          `json:"operation_id"`
	SessionID         string          `json:"session_id"`
	Expected          Revision        `json:"expected"`
	ExpectedBinding   BindingRevision `json:"expected_binding"`
	NewSourceEvents   []SourceEvent   `json:"new_source_events"`
	Payloads          []PayloadRecord `json:"payloads,omitempty"`
	Checkpoint        Checkpoint      `json:"checkpoint"`
	NewSession        uint64          `json:"new_session"`
	NewDurable        uint64          `json:"new_durable"`
	NewSourceSequence uint64          `json:"new_source_sequence"`
	NewBinding        BindingRevision `json:"new_binding"`
	TurnID            uint64          `json:"turn_id"`
}

CommitRequest is one atomic session advance: events, payloads, and the new active checkpoint under an idempotent operation key.

func NewCommitRequest

func NewCommitRequest(sessionID string, expected Revision, expectedBinding BindingRevision, events []SourceEvent, payloads []PayloadRecord, checkpoint Checkpoint, newBinding BindingRevision, turnID uint64) (CommitRequest, error)

NewCommitRequest builds one complete request. It sets OperationID from the checkpoint's idempotency key, derives the three new revision fields from expected and the event count, validates, and wraps ErrInvalidRecord on failure.

func (CommitRequest) Validate

func (r CommitRequest) Validate() error

Validate enforces shape only, in this order: identity, revision, events, payloads, checkpoint. Volume bounds live in the store (limits.go, store.go).

type ContentRef

type ContentRef struct {
	Ref         string `json:"ref"`
	Namespace   string `json:"namespace"`
	SHA256      string `json:"sha256"`
	WorkspaceID string `json:"workspace_id"`
	SessionID   string `json:"session_id"`
	SubjectID   string `json:"subject_id"`
	Size        int    `json:"size"`
}

ContentRef is the durable address of one shared context blob. Ref is the address a caller hands around; SHA256 is the bare digest the payload checks compare against; Size is the whole-payload byte count. The three owner strings replace the source's Principal.

func NewContentRef

func NewContentRef(namespace string, workspaceID string, sessionID string, subjectID string, chunks ...[]byte) (ContentRef, error)

NewContentRef mints a ContentRef over the concatenation of chunks. It fills the namespace and owner fields, validates the result, and wraps ErrInvalidRecord on failure.

func (ContentRef) Validate

func (r ContentRef) Validate() error

Validate enforces the canonical Ref form, its match with SHA256, the identifier bounds on Namespace and the owner strings, and a non-negative Size. Namespace is caller-owned; no SDK constant is compared against it.

type Limits

type Limits struct {
	CheckpointBytes  int
	CommitEvents     int
	CommitEventBytes int
}

Limits is the caller-owned set of volume bounds for one store. A zero field means uncapped, matching contextbudget.Limits. The MemStore enforces these at write time; Validate stays shape-only.

func (Limits) Validate

func (l Limits) Validate() error

Validate rejects a negative field and names it. CheckpointBytes is checked first, then CommitEvents, then CommitEventBytes.

type MemStore

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

MemStore is the shipped in-memory store: payloads by content address, sessions by id, committed operations by key. Mutex-guarded and safe for concurrent use; built through New. The zero value is not usable.

func New

func New(limits Limits) (*MemStore, error)

New builds an empty MemStore under limits. A negative field wraps ErrInvalidRecord.

func (*MemStore) Checkpoint

func (m *MemStore) Checkpoint(req CommitRequest) error

Checkpoint applies one commit atomically. A reused OperationID with an equal request is a no-op success; a different request wraps ErrCheckpointConflict, before any other check. A new key runs req.Validate, the volume bounds, and the stale guards. An unknown session commits only against a zero Expected. A payload under a ref already revoked is skipped, matching Put.

func (*MemStore) Get

func (m *MemStore) Get(ref ContentRef) (PayloadRecord, error)

Get returns a copy of the record stored under ref.Ref. Every error case returns the zero PayloadRecord: an unknown ref wraps ErrPayloadNotFound; a revoked record wraps ErrPayloadRevoked and denies Data. Status is the path for a revoked ref's metadata.

func (*MemStore) Put

func (m *MemStore) Put(record PayloadRecord) error

Put validates record and stores a copy under record.Ref.Ref. Content-addressed, so a repeat Put of equal bytes overwrites in place. A Put under a ref already revoked is a no-op: it returns nil and leaves the stored record, including Revoked == true, untouched.

func (*MemStore) Revoke

func (m *MemStore) Revoke(ref ContentRef) error

Revoke sets Revoked on the stored record under ref.Ref, the only way a caller revokes a record after Put or Checkpoint. An unknown ref wraps ErrPayloadNotFound. A second Revoke on an already-revoked record is a no-op success.

func (*MemStore) Session

func (m *MemStore) Session(id string) (Session, error)

Session returns the session's revision, binding, active checkpoint, and a copy of its events. An unknown id wraps ErrSessionNotFound.

func (*MemStore) Status

func (m *MemStore) Status(ref ContentRef) (PayloadRecord, error)

Status returns a copy of the record stored under ref.Ref with Data always cleared, whether or not it is revoked. It never wraps ErrPayloadRevoked: revocation is reported through the returned record's Revoked field. An unknown ref wraps ErrPayloadNotFound.

type PayloadRecord

type PayloadRecord struct {
	Ref       ContentRef     `json:"ref"`
	Retention RetentionClass `json:"retention"`
	Revoked   bool           `json:"revoked"`
	Data      []byte         `json:"data,omitempty"`
}

PayloadRecord is one stored payload under its content address.

func Reassemble

func Reassemble(ref ContentRef, retention RetentionClass, chunks ...[]byte) (PayloadRecord, error)

Reassemble concatenates the chunks in order under one ref and returns the record with Data set. It fails closed on a size or digest mismatch. The whole-payload digest is the contract; chunk boundaries are storage granularity.

func (PayloadRecord) Validate

func (p PayloadRecord) Validate() error

Validate enforces a valid Ref, a non-empty Retention, and, when Data is present, a length and a digest that match Ref.

type RetentionClass

type RetentionClass string

RetentionClass labels how long a payload is kept. PayloadRecord accepts any non-empty class, so a caller may define its own.

const (
	// RetentionSession keeps a payload for the session's lifetime.
	RetentionSession RetentionClass = "session"
	// RetentionCompliance keeps a payload past session deletion.
	RetentionCompliance RetentionClass = "compliance"
)

type Revision

type Revision struct {
	Session uint64 `json:"session"`
	Durable uint64 `json:"durable"`
	Source  uint64 `json:"source"`
}

Revision is a session's three counters. It carries no Validate; the commit rules compare it as a whole.

type Session

type Session struct {
	Revision Revision        `json:"revision"`
	Binding  BindingRevision `json:"binding"`
	Active   Checkpoint      `json:"active"`
	Source   []SourceEvent   `json:"source"`
}

Session is the read model of one session. It carries no Validate, because every part carries its own.

type SourceEvent

type SourceEvent struct {
	ID              SourceID `json:"id"`
	Kind            string   `json:"kind"`
	Role            string   `json:"role"`
	ToolCallID      string   `json:"tool_call_id,omitempty"`
	PayloadRef      string   `json:"payload_ref,omitempty"`
	Provenance      string   `json:"provenance"`
	RedactionStatus string   `json:"redaction_status"`
	Size            int      `json:"size"`
}

SourceEvent is one durable event in a session's source log. PayloadRef stays a bounded string, not a forced canonical form, so app-side key schemes stay legal.

func (SourceEvent) Validate

func (e SourceEvent) Validate() error

Validate bounds the four required text fields at 256 bytes, the two optional fields when set, and rejects a negative Size.

type SourceID

type SourceID struct {
	SessionID string `json:"session_id"`
	Sequence  uint64 `json:"sequence"`
}

SourceID names one event: a session and a sequence number.

func (SourceID) Validate

func (id SourceID) Validate() error

Validate bounds the identifier.

type SourceRange

type SourceRange struct {
	Start SourceID `json:"start"`
	End   SourceID `json:"end"`
}

SourceRange spans events of one session, inclusive of both ends.

func (SourceRange) Validate

func (r SourceRange) Validate() error

Validate enforces one session, an ordered span, and a span under MaxSourceRangeEvents.

type ValidationError

type ValidationError struct {
	Field  string
	Reason string
}

ValidationError names the field that made a record invalid. Match with errors.Is(err, ErrInvalidRecord) through Unwrap.

func (*ValidationError) Error

func (e *ValidationError) Error() string

Error renders the sentinel, the field, and the reason.

func (*ValidationError) Unwrap

func (e *ValidationError) Unwrap() error

Unwrap reports the sentinel under every validation failure.

Jump to

Keyboard shortcuts

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