runtimefence

package
v0.20.0 Latest Latest
Warning

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

Go to latest
Published: Sep 15, 2026 License: AGPL-3.0 Imports: 11 Imported by: 0

Documentation

Index

Constants

View Source
const (
	DecisionToolApproval = "tool_approval"
	DecisionUserInput    = "user_input"
)

Variables

View Source
var (
	ErrStale                        = errors.New("session runtime persistence fence is stale")
	ErrResetLeaseLost               = errors.New("session history reset lease was lost")
	ErrTransactionsUnsupported      = errors.New("session runtime persistence fencing requires real transactions")
	ErrPreservedDecisionUnavailable = errors.New("preserved runtime decision is no longer pending")
)

Functions

func Activate

func Activate(ctx context.Context, queries dbstore.Queries, fence Fence) error

Activate is the persistence ownership cutover. Redis may already reserve the successor as admitting, but a writer holding the previous token still linearizes before this transaction if it acquired the session lock first. Once activation commits, the previous token can never write again. Cleanup uses later statements in the same transaction so it sees rows committed by a writer that activation had to wait for.

func ActivateWithOptions

func ActivateWithOptions(ctx context.Context, queries dbstore.Queries, fence Fence, options ActivationOptions) error

func InResetTransaction

func InResetTransaction(
	ctx context.Context,
	queries dbstore.Queries,
	botID string,
	sessionID string,
	fn func(dbstore.Queries) error,
) error

InResetTransaction validates a tokenized reset lease under the bot parent lock and runs fn in that same real PostgreSQL transaction. Contexts without a reset fence retain the ordinary direct path for non-reset callers.

func InTransaction

func InTransaction(
	ctx context.Context,
	queries dbstore.Queries,
	botID string,
	sessionID string,
	fn func(dbstore.Queries) error,
) error

InTransaction locks and validates the durable token in the same real PostgreSQL transaction as fn. Redis admission reserves control ownership; token activation is the linearization point for persistence ownership.

func Lock

func Lock(ctx context.Context, queries dbstore.Queries, botID, sessionID string) error

Lock validates the current fence and serializes writers on the session row until the caller's transaction ends. A successor cannot activate its token until that write commits, and an older token cannot write after activation.

func LockBotForSessionWrite

func LockBotForSessionWrite(ctx context.Context, queries dbstore.Queries, botID string) error

LockBotForSessionWrite establishes parent-before-child lock ordering before a transaction locks a session and writes rows that reference its bot.

func NormalizeResetError

func NormalizeResetError(ctx context.Context, err error) error

NormalizeResetError preserves the stable lease-loss identity when context cancellation wins a race with a database call and the driver reports only context.Canceled or context.DeadlineExceeded.

func PublishBotRuntimeConfig

func PublishBotRuntimeConfig(
	ctx context.Context,
	queries dbstore.Queries,
	botID string,
	publishTimeout time.Duration,
	publish func(context.Context) error,
) (publishErr error, guardErr error)

PublishBotRuntimeConfig serializes a bot-scoped external runtime-config write against reset successors and stale ACP processes.

The epoch invalidation is intentionally committed in a short first transaction before any external side effect. A second transaction then holds the bot parent lock while publish runs. This two-phase order makes a partial workspace write safe even if the process crashes or the long transaction later rolls back: every process bound to the old epoch was already made permanently stale. The second transaction refreshes the exact reset token before committing, even when publish reports an error.

publishErr is the external callback result. guardErr means the reset/epoch boundary itself did not complete and must not be downgraded to a warning.

func ResetLeaseFailure

func ResetLeaseFailure(ctx context.Context, err error) error

ResetLeaseFailure reports whether a fenced mutation failed because its reset lease was lost, folding in the cause carried by the owner context (the renewer cancels the context, so the direct error may only say "context canceled"). It returns the error to surface, or nil when the failure is unrelated to the lease. Handlers use this instead of repeating the context.Cause / errors.Is dance at every call site.

func ValidateResetLocked

func ValidateResetLocked(ctx context.Context, queries dbstore.Queries, botID, sessionID string) error

ValidateResetLocked checks the reset token using a fresh statement while the caller's transaction already holds the bot parent lock.

func ValidateScope

func ValidateScope(ctx context.Context, botID, sessionID string) error

ValidateScope rejects a durable write that does not belong to the session represented by the context fence. Unfenced contexts remain unchanged.

func WithContext

func WithContext(ctx context.Context, fence Fence) context.Context

func WithResetContext

func WithResetContext(ctx context.Context, fence ResetFence) context.Context

Types

type ActivationOptions

type ActivationOptions struct {
	// PreserveDecisions carries every decision the reclaiming owner keeps
	// alive; a turn can park on several approvals and user inputs at once,
	// and any pending decision not listed here is superseded.
	PreserveDecisions      []PreservedDecision
	ReclaimWaitingDecision *WaitingDecisionReclaim
}

type Activator

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

Activator binds Activate to one persistence store so a caller can hand persistence ownership to a run without holding a database handle itself.

The session runtime owns the decision of when a token takes over; it must not also own a connection to the store that records it. Keeping the binding here is what lets the runtime declare the capability as an interface over (bot, session, token) and stay free of dbstore.

func NewActivator

func NewActivator(queries dbstore.Queries) *Activator

func (*Activator) Activate

func (a *Activator) Activate(ctx context.Context, botID, sessionID string, token int64) error

Activate promotes token to the session's persistence fence. Callers must have won the durable ownership claim first: activating a token whose run does not own the session would fence out the owner that legitimately holds an older one.

func (*Activator) ReclaimWaitingDecision

func (a *Activator) ReclaimWaitingDecision(
	ctx context.Context,
	botID, sessionID, runID, ownerID, liveGeneration string,
	previousToken, newToken int64,
	decisions []PreservedDecision,
) error

type Fence

type Fence struct {
	BotID     string
	SessionID string
	Token     int64
}

Fence identifies the PostgreSQL generation allowed to persist one runtime run. A newer run increments Token and permanently invalidates older fences.

func FromContext

func FromContext(ctx context.Context) (Fence, bool)

func (Fence) Valid

func (f Fence) Valid() bool

type PreservedDecision

type PreservedDecision struct {
	Kind string
	ID   string
}

type ResetFence

type ResetFence struct {
	Scope     string
	BotID     string
	SessionID string
	Token     string
	LeaseTTL  time.Duration
}

func ResetFromContext

func ResetFromContext(ctx context.Context) (ResetFence, bool)

func (ResetFence) Valid

func (f ResetFence) Valid() bool

type WaitingDecisionReclaim

type WaitingDecisionReclaim struct {
	RunID          string
	OwnerID        string
	PreviousToken  int64
	LiveGeneration string
}

WaitingDecisionReclaim is committed atomically with the persistence-fence and preserved-decision token update.

Jump to

Keyboard shortcuts

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