Documentation
¶
Overview ¶
Package sessionruntime implements the private coordinator that constructs, restores, and owns live sessions for package rig. Public consumers use package session contracts.
Index ¶
- Constants
- type AcceptAllDecider
- type AcquireCanceledError
- type AgentNameMismatchError
- type CheckpointError
- type CheckpointErrorKind
- type CompactionInputTooLargeError
- type ConfigMismatchError
- type DefaultPolicyDecider
- type DelegateError
- type DelegateErrorKind
- type FingerprintProvider
- type GateCaps
- type GateError
- type GateErrorKind
- type HustleConstructionError
- type HustleConstructionReason
- type HustleLimits
- type HustleModelResolveError
- type HustleModelResolveReason
- type HustleShutdownReentryError
- type InterruptReleasePolicy
- type InvalidWorkspaceOperationError
- type LeaseHealth
- type Lifecycle
- type LifecycleOption
- func WithLifecycleAllowConfigMismatch() LifecycleOption
- func WithLifecycleFingerprint(fingerprint event.ConfigFingerprint) LifecycleOption
- func WithLifecycleFingerprintProvider(provider FingerprintProvider) LifecycleOption
- func WithLifecycleForeignBuilderRegistry(registry *foreign.BuilderRegistry) LifecycleOption
- func WithLifecycleForeignBuilders(b foreign.Builder, rb foreign.RestoredBuilder) LifecycleOption
- func WithLifecycleForeignServicesBuilders(b foreign.ServicesBuilder, rb foreign.ServicesRestoredBuilder) LifecycleOption
- func WithLifecycleGateCaps(caps GateCaps) LifecycleOption
- func WithLifecycleHooks(runner *hook.Runner) LifecycleOption
- func WithLifecycleHustles(definitions []hustle.Definition, limits HustleLimits) LifecycleOption
- func WithLifecycleLimits(l Limits) LifecycleOption
- func WithLifecycleManifest(manifest event.ConfigManifest) LifecycleOption
- func WithLifecycleOffloadGC(policy OffloadGCPolicy) LifecycleOption
- func WithLifecyclePermissionReview(classifiers gate.PermissionClassifierSet, policy gate.PermissionReviewPolicy) LifecycleOption
- func WithLifecyclePermissionReviewBreaker(limits PermissionReviewBreakerLimits) LifecycleOption
- func WithLifecyclePermissionReviewEvidence(access gate.EvidenceAccessEvaluator, ...) LifecycleOption
- func WithLifecyclePermissionReviewObservations(verifier gate.EvidenceObservationVerifier) LifecycleOption
- func WithLifecyclePermissionReviewSecurityCeiling(ceiling string) LifecycleOption
- func WithLifecyclePlacement(p WorkspacePlacement) LifecycleOption
- func WithLifecycleRestoreDecider(decider RestoreDecider) LifecycleOption
- func WithLifecycleRuntimeCatalog(catalog loop.RuntimeCatalog) LifecycleOption
- func WithLifecycleRuntimeCatalogProvider(provider RuntimeCatalogProvider) LifecycleOption
- func WithLifecycleRuntimeRestoreResolver(resolver RuntimeRestoreResolver) LifecycleOption
- func WithLifecycleSessionResourceStorage(resolve SessionResourceStorageResolver) LifecycleOption
- func WithLifecycleSnapshotPolicy(policy SnapshotPolicy) LifecycleOption
- func WithLifecycleWorkspaceCheckpointing(ws *workspacestore.Store, root string) LifecycleOption
- type Limits
- type MissingFingerprintProviderError
- type MissingStoreError
- type MissingTopologyError
- type NewSessionError
- type NewSessionErrorKind
- type OffloadGCPolicy
- type Option
- func WithAllowConfigMismatch() Option
- func WithCommandAppender(a commandAppender) Option
- func WithEventAppender(a eventAppender) Option
- func WithFingerprint(fingerprint event.ConfigFingerprint) Option
- func WithFingerprintProvider(provider FingerprintProvider) Option
- func WithForeignBuilderRegistry(registry *foreign.BuilderRegistry) Option
- func WithForeignBuilders(b foreign.Builder, rb foreign.RestoredBuilder) Option
- func WithForeignServicesBuilders(b foreign.ServicesBuilder, rb foreign.ServicesRestoredBuilder) Option
- func WithGateAppender(a gateAppender) Option
- func WithGateCaps(caps GateCaps) Option
- func WithHooks(runner *hook.Runner) Option
- func WithInterruptReleasePolicy(p InterruptReleasePolicy) Option
- func WithLeaseRelease(release func(context.Context) error) Option
- func WithLimits(l Limits) Option
- func WithManifest(manifest event.ConfigManifest) Option
- func WithRestoreDecider(decider RestoreDecider) Option
- func WithRuntimeCatalog(catalog loop.RuntimeCatalog) Option
- func WithRuntimeCatalogProvider(provider RuntimeCatalogProvider) Option
- func WithRuntimeRestoreResolver(resolver RuntimeRestoreResolver) Option
- func WithSessionID(id uuid.UUID) Option
- func WithSnapshotPolicy(policy SnapshotPolicy) Option
- func WithWorkspaceCheckpointing(ws *workspacestore.Store, root string) Option
- type PermissionReviewBreakerLimits
- type PermissionReviewSessionBreakerLimits
- type PlacementResolutionError
- type ProcessLifecycleOwnerMismatchError
- type ProcessNotificationDeliveryStoppedError
- type ProcessNotificationOwnerMismatchError
- type ProcessNotificationUnsupportedError
- type ProcessServicesUnsupportedError
- type RestoreDecider
- type RestoreDecision
- type RestoreDiscoveryError
- type RestoreDiscoveryErrorKind
- type RestoreError
- type RestoreErrorKind
- type RestoreRejectedError
- type RestoreRuntimeMismatchError
- type RestoreRuntimeMismatchKind
- type RestoredContextModelMismatchError
- type RuntimeCatalogProvider
- type RuntimeRestoreRequest
- type RuntimeRestoreResolver
- type Session
- func (s *Session) ActivateGate(ctx context.Context, id gate.ID, route gate.Route) error
- func (s *Session) ActiveLoop() loop.Handle
- func (s *Session) ActiveLoopID() uuid.UUID
- func (s *Session) AdmissionFaultErr() error
- func (s *Session) AwaitGateAnswer(ctx context.Context, id gate.ID) (gate.Answer, error)
- func (s *Session) CheckpointWorkspace(ctx context.Context) (workspacestore.Ref, error)
- func (s *Session) CloseGate(ctx context.Context, id gate.ID, reason gate.CloseReason) error
- func (s *Session) CommitBoundary(ctx context.Context, ev event.Event) error
- func (s *Session) CommitContextBoundary(ctx context.Context, ev event.Event) (bool, error)
- func (s *Session) CommitSessionIdle(ctx context.Context, idle event.SessionIdle, commit func() error) error
- func (s *Session) Compact(ctx context.Context) (uuid.UUID, error)
- func (s *Session) CompactToLoop(ctx context.Context, loopID uuid.UUID) (uuid.UUID, error)
- func (s *Session) Done() <-chan struct{}
- func (s *Session) EnterExecution(ctx context.Context, loopID uuid.UUID) (func(), error)
- func (s *Session) EnterTurnStart(ctx context.Context, loopID uuid.UUID) (loopruntime.TurnStartCapability, error)
- func (s *Session) FaultErr() error
- func (s *Session) Interrupt(ctx context.Context) (bool, error)
- func (s *Session) ListGates(context.Context) []gate.Gate
- func (s *Session) Loop(id uuid.UUID) (loop.Handle, bool)
- func (s *Session) LoopController(id uuid.UUID) (loop.Controller, bool)
- func (s *Session) NewLoop(parent loop.Provenance, cfg loop.Definition) (uuid.UUID, error)
- func (s *Session) NotifyProcessCompletion(ctx context.Context, n tool.ProcessCompletionNotification) error
- func (s *Session) OpenHostGate(ctx context.Context, loopID uuid.UUID, g gate.Gate, payload gate.Payload) (gate.ID, error)
- func (s *Session) PrepareGateOpen(ctx context.Context, loopID uuid.UUID, g gate.Gate, payload gate.Payload) (gate.ID, error)
- func (s *Session) PublishEvent(ctx context.Context, ev event.Event) error
- func (s *Session) PublishEventChecked(ctx context.Context, ev event.Event) error
- func (s *Session) ReportFault(_ context.Context, fault *hub.SessionPersistenceFault)
- func (s *Session) RespondGate(ctx context.Context, response gate.GateResponse) error
- func (s *Session) RestoreWorkspace(ctx context.Context, ref workspacestore.Ref) error
- func (s *Session) RunAgent(ctx context.Context, parent loop.Provenance, cfg loop.Definition, ...) (string, error)
- func (s *Session) SessionActivated()
- func (s *Session) SessionID() uuid.UUID
- func (s *Session) SetActiveLoop(ctx context.Context, id uuid.UUID) error
- func (s *Session) Shutdown(ctx context.Context) error
- func (s *Session) StartPermissionReview(ctx context.Context, req loopruntime.PermissionReviewRequest)
- func (s *Session) Submit(ctx context.Context, input []content.Block) (uuid.UUID, error)
- func (s *Session) SubmitToLoop(ctx context.Context, loopID uuid.UUID, blocks []content.Block) (uuid.UUID, error)
- func (s *Session) SubscribeEvents(filter event.EventFilter) (event.Subscription, error)
- func (s *Session) WaitIdle(ctx context.Context) error
- type SessionError
- type SessionErrorKind
- type SessionResourceStorageError
- type SessionResourceStorageErrorKind
- type SessionResourceStorageResolver
- type ShutdownCleanupPhase
- type ShutdownCleanupTimeoutError
- type SnapshotPolicy
- type Topology
- type TurnRejectedError
- type WorkflowActivityOwnerMismatchError
- type WorkspaceLifetimeAccessError
- type WorkspaceNotConfiguredError
- type WorkspacePathError
- type WorkspacePlacement
- type WorkspacePlacementMode
- type WorkspaceRecoveryError
- type WorkspaceRestoreError
- type WorkspaceRestoreErrorKind
- type WorkspaceRootBusyError
- type WorkspaceRootLeaseLostError
- type WorkspaceSeedError
Constants ¶
const ( SnapshotManual = checkpointManual SnapshotOnIdle = checkpointOnIdle SnapshotOnTurnDone = checkpointOnTurnDone SnapshotOnStepDone = checkpointOnStepDone SnapshotBestEffort = checkpointBestEffort SnapshotRequired = checkpointRequired )
const ( SessionIDGenerationFailed = sessionapi.SessionIDGenerationFailed SessionLoopIDGenerationFailed = sessionapi.SessionLoopIDGenerationFailed SessionLoopExited = sessionapi.SessionLoopExited SessionLoopNotFound = sessionapi.SessionLoopNotFound SessionEventChannelClosed = sessionapi.SessionEventChannelClosed SessionContextDone = sessionapi.SessionContextDone SessionClosing = sessionapi.SessionClosing SessionFaulted = sessionapi.SessionFaulted SessionLoopDepthExceeded = sessionapi.SessionLoopDepthExceeded SessionLoopQuotaExceeded = sessionapi.SessionLoopQuotaExceeded SessionForeignBuilderMissing = sessionapi.SessionForeignBuilderMissing SessionCompactionUnsupported = sessionapi.SessionCompactionUnsupported SessionDelegateIntentAppendFailed = sessionapi.SessionDelegateIntentAppendFailed SessionDelegateAdmissionCommitFailed = sessionapi.SessionDelegateAdmissionCommitFailed RestoreNoSessionStarted = sessionapi.RestoreNoSessionStarted RestoreNoPrimerLoop = sessionapi.RestoreNoPrimerLoop RestoreRuntimeMissing = sessionapi.RestoreRuntimeMissing RestoreRuntimeTargetMismatch = sessionapi.RestoreRuntimeTargetMismatch RestoreRuntimeCredentialMismatch = sessionapi.RestoreRuntimeCredentialMismatch RestoreRuntimeEffortMismatch = sessionapi.RestoreRuntimeEffortMismatch RestoreLeaseFailed = sessionapi.RestoreLeaseFailed RestoreJournalFailed = sessionapi.RestoreJournalFailed RestoreReplayFailed = sessionapi.RestoreReplayFailed RestoreAppendFailed = sessionapi.RestoreAppendFailed RestoreAdoptionInvalid = sessionapi.RestoreAdoptionInvalid RestoreLoopFailed = sessionapi.RestoreLoopFailed RestoreContextDone = sessionapi.RestoreContextDone RestoreIDGenerationFailed = sessionapi.RestoreIDGenerationFailed RestoreForeignSIDMissing = sessionapi.RestoreForeignSIDMissing RestoreForeignBuilderMissing = sessionapi.RestoreForeignBuilderMissing RestoreMaterializeFailed = sessionapi.RestoreMaterializeFailed GateNotFound = sessionapi.GateNotFound GateNotReady = sessionapi.GateNotReady GateKindMismatch = sessionapi.GateKindMismatch GateActionInvalid = sessionapi.GateActionInvalid GateCapacity = sessionapi.GateCapacity GateAppendFailed = sessionapi.GateAppendFailed )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AcceptAllDecider ¶
type AcceptAllDecider = sessionapi.AcceptAllDecider
type AcquireCanceledError ¶
type AcquireCanceledError struct{ Cause error }
AcquireCanceledError reports that an Acquire returned because its ctx was done before or during the wait. Cause is the ctx error (context.Canceled or context.DeadlineExceeded). No permit was granted; no waiter remains queued.
func (*AcquireCanceledError) Error ¶
func (e *AcquireCanceledError) Error() string
func (*AcquireCanceledError) Unwrap ¶
func (e *AcquireCanceledError) Unwrap() error
type AgentNameMismatchError ¶
type AgentNameMismatchError = sessionapi.AgentNameMismatchError
type CheckpointError ¶
type CheckpointError struct {
Kind CheckpointErrorKind
Cause error
}
func (*CheckpointError) Error ¶
func (e *CheckpointError) Error() string
func (*CheckpointError) Unwrap ¶
func (e *CheckpointError) Unwrap() error
type CheckpointErrorKind ¶
type CheckpointErrorKind string
const ( CheckpointNotIdle CheckpointErrorKind = "not_idle" CheckpointFaulted CheckpointErrorKind = "faulted" CheckpointFailed CheckpointErrorKind = "failed" CheckpointTimeout CheckpointErrorKind = "timeout" CheckpointCanceled CheckpointErrorKind = "canceled" CheckpointTriggerAppendFailed CheckpointErrorKind = "trigger_append_failed" CheckpointAppendFailed CheckpointErrorKind = "append_failed" CheckpointIDGenerationFailed CheckpointErrorKind = "id_generation_failed" )
type CompactionInputTooLargeError ¶
CompactionInputTooLargeError reports a serialized compaction request that remains over the bound after every old tool-result body has been omitted. User and assistant prose is protected and is never removed to make a fit.
func (*CompactionInputTooLargeError) Error ¶
func (*CompactionInputTooLargeError) Error() string
type ConfigMismatchError ¶
type ConfigMismatchError = sessionapi.ConfigMismatchError
type DefaultPolicyDecider ¶
type DefaultPolicyDecider = sessionapi.DefaultPolicyDecider
type DelegateError ¶
type DelegateError struct {
Kind DelegateErrorKind
Agent identity.AgentName
Mode loop.ModeName
DelegateID uuid.UUID
}
DelegateError is the typed delegation refusal. Callers errors.As to inspect Kind and the offending agent, mode, or delegate ID.
func (*DelegateError) Error ¶
func (e *DelegateError) Error() string
func (*DelegateError) ModelFacingError ¶
func (e *DelegateError) ModelFacingError() string
ModelFacingError exposes only the fixed, bounded category needed by the model-facing agent result. It deliberately omits all request fields; ordinary delegation errors continue to use the generic tool-result error.
type DelegateErrorKind ¶
type DelegateErrorKind uint8
DelegateErrorKind classifies a delegation refusal. Every refusal denies by default (fail-secure); the model-facing tool renders it as a tool-result string.
const ( DelegateUnknownAgent DelegateUnknownMode DelegateNotOwned DelegateMissingDelegateID DelegateUnknownOperation // DelegateInterruptPending: the parent loop is under an interrupt admission barrier, so a // NEW machine-delegate request (start/send) is flushed (refused) until the barrier releases. // This is the machine-side of the interrupt queue policy: user input stays queued, but a // parent whose interrupted delegate wait resolves cannot open a fresh delegate step. DelegateInterruptPending DelegateRuntimeInvalid DelegateClosed )
type FingerprintProvider ¶
type FingerprintProvider func(loop.BoundDefinition) event.ConfigFingerprint
FingerprintProvider projects a bound loop into the immutable behavior fingerprint used for both SessionStarted and restore validation. It must be deterministic and safe for concurrent calls from separate sessions.
type GateCaps ¶
GateCaps bounds the live gate directory. The cap counts preparing + open + claiming so failed activations cannot accumulate invisible prepared entries. Zero means no cap.
type GateError ¶
type GateError = sessionapi.GateError
type GateErrorKind ¶
type GateErrorKind = sessionapi.GateErrorKind
type HustleConstructionError ¶
type HustleConstructionError struct {
Reason HustleConstructionReason
Name hustle.Name
Index int
Field string
Cause error
}
HustleConstructionError reports a transactional hustle composition failure.
func (*HustleConstructionError) Error ¶
func (e *HustleConstructionError) Error() string
func (*HustleConstructionError) Unwrap ¶
func (e *HustleConstructionError) Unwrap() error
type HustleConstructionReason ¶
type HustleConstructionReason string
HustleConstructionReason classifies the frozen-definition binding stage.
const ( HustleConstructionBindFailed HustleConstructionReason = "bind_failed" HustleConstructionRuntimeFailed HustleConstructionReason = "runtime_failed" HustleConstructionMissingCollaborator HustleConstructionReason = "missing_collaborator" HustleConstructionAlreadyBound HustleConstructionReason = "already_bound" )
type HustleLimits ¶
type HustleLimits struct {
BlockingConcurrent int
BlockingQueued int
BackgroundConcurrent int
BackgroundQueued int
AuditTimeout time.Duration
FinalizationTimeout time.Duration
WorkerDrainTimeout time.Duration
}
HustleLimits is sessionruntime's narrow, rig-independent copy of the hustle lane and cleanup bounds.
type HustleModelResolveError ¶
type HustleModelResolveError struct {
Reason HustleModelResolveReason
LoopID uuid.UUID
Cause error
}
HustleModelResolveError reports why the originating loop cannot supply its current inference binding.
func (*HustleModelResolveError) Error ¶
func (e *HustleModelResolveError) Error() string
func (*HustleModelResolveError) Unwrap ¶
func (e *HustleModelResolveError) Unwrap() error
type HustleModelResolveReason ¶
type HustleModelResolveReason string
HustleModelResolveReason classifies an exact current-loop lookup failure.
const ( HustleModelResolveInvalidContext HustleModelResolveReason = "invalid_context" HustleModelResolveInvalidLoopID HustleModelResolveReason = "invalid_loop_id" HustleModelResolveLoopNotFound HustleModelResolveReason = "loop_not_found" HustleModelResolveForeignLoop HustleModelResolveReason = "foreign_loop" HustleModelResolveLoopExited HustleModelResolveReason = "loop_exited" )
type HustleShutdownReentryError ¶
type HustleShutdownReentryError struct{}
HustleShutdownReentryError refuses the structurally circular operation in which a session-owned finalizer passes its supplied trusted context to the shutdown that is itself waiting for that finalizer. The private marker is exact-context defense in depth, not goroutine identity: a callback that drops the context cannot be detected. Production adapters therefore receive focused product capability only, never Session/Shutdown, and must preserve the callback context just as they must honor its deadline.
func (*HustleShutdownReentryError) Error ¶
func (*HustleShutdownReentryError) Error() string
type InterruptReleasePolicy ¶
type InterruptReleasePolicy interface {
// AwaitRelease blocks until the interrupt admission barrier should release. ctx is the
// session lifetime. The returned error is advisory: the marks are cleared once AwaitRelease
// returns regardless of the error (fail-open on RELEASE, so a barrier can never wedge
// admission forever). Implementations must be safe for concurrent use.
AwaitRelease(ctx context.Context) error
}
InterruptReleasePolicy is the pluggable admission-barrier release seam (Dependency Inversion). After an interrupt fan-out cancels at least one running turn, the session holds every target's interrupt-pending mark until AwaitRelease returns, then clears them. The default policy (sessionIdleRelease) releases once the session reaches idle — WaitIdle returns only after the hub has durably appended SessionIdle, so "release after idle" and "release after SessionIdle is appended" are the same edge. Workspace-backed sessions use checkpoint-controller sweep outcomes directly; this seam remains for headless/custom session-runtime composition.
type InvalidWorkspaceOperationError ¶
type InvalidWorkspaceOperationError struct{ Operation tool.WorkspaceOperation }
InvalidWorkspaceOperationError reports an Acquire with an operation value the coordinator does not recognize (fail-secure: no permit is granted).
func (*InvalidWorkspaceOperationError) Error ¶
func (e *InvalidWorkspaceOperationError) Error() string
type LeaseHealth ¶
type LeaseHealth interface {
Healthy() error
}
LeaseHealth reports whether the workspace lease that underpins harness-managed mutations is currently healthy. A structured mutator MUST NOT commit when Healthy returns an error (fail-secure). A nil LeaseHealth means "no lease to verify" and is treated as always healthy (the bare/no-lease deployment).
type Lifecycle ¶
type Lifecycle struct {
// contains filtered or unexported fields
}
Lifecycle binds a design-time loop topology and durable backend into an immutable, reusable factory for live sessions. NewTopologyLifecycle captures the caller-facing options once; NewSession mints a fresh session id and brings up a brand-new session over per-session durable dependencies; RestoreSession rebuilds a prior session from its journal. Everything the narrow serve.Rig interface needs is fixed at NewTopologyLifecycle, so NewSession/RestoreSession take no per-call knobs.
A Lifecycle is safe to reuse across many sessions. Each NewSession/RestoreSession builds its OWN durable wiring (lease, journal, appenders) from the shared store, so two live sessions never share a lease or a journal.
func NewTopologyLifecycle ¶
func NewTopologyLifecycle(topology Topology, store *sessionstore.Store, opts ...LifecycleOption) (*Lifecycle, error)
NewTopologyLifecycle binds an immutable, validated multi-primer graph to storage.
func (*Lifecycle) NewSession ¶
NewSession mints a fresh session ID and brings up a brand-new live session over per-session durable deps built from the Lifecycle's store: a single-writer lease, the session journal, and the three checked appenders (event — carrying the catalog — command, and gate). It returns the minted id, the live session, and a typed *NewSessionError on any failure. On ANY failure after the lease is acquired the lease is released best-effort, so a failed NewSession never strands single-writer ownership.
func (*Lifecycle) RestoreSession ¶
RestoreSession rebuilds a live session from its durable journal under the id it was created with, delegating to runtime restoration with the Lifecycle's captured cfg, store, and base options. runtime restoration holds the store, so it builds its OWN lease/journal/appenders (and installs the lease-release hook) internally — the Lifecycle supplies only the captured caller options, NOT the per-session appenders NewSession builds. It refuses a config-fingerprint mismatch (typed *ConfigMismatchError) unless WithLifecycleAllowConfigMismatch was compiled in, and surfaces runtime restoration's typed errors unchanged (a *RestoreDiscoveryError for a session with no history, a *RestoreError for a lease/journal/replay failure), never a panic.
type LifecycleOption ¶
type LifecycleOption func(*Lifecycle)
LifecycleOption configures a Lifecycle at NewTopologyLifecycle time. Every caller-facing knob is captured here (the runtime NewSession/RestoreSession take none), mirroring flow's LifecycleOption model. A nil/zero argument is ignored (the default is kept), mirroring the session options' own fail-safe convention.
func WithLifecycleAllowConfigMismatch ¶
func WithLifecycleAllowConfigMismatch() LifecycleOption
WithLifecycleAllowConfigMismatch captures the restore-only opt-in to resume a session whose persisted config fingerprint no longer matches the live config. AMBIGUITY A2: classified NewTopologyLifecycle-time (fixed for the Lifecycle's lifetime) so the narrow serve.Rig interface exposes no per-call knob. NewSession ignores it; only RestoreSession honors it.
func WithLifecycleFingerprint ¶
func WithLifecycleFingerprint(fingerprint event.ConfigFingerprint) LifecycleOption
WithLifecycleFingerprint captures a rig-time frozen compatibility fingerprint.
func WithLifecycleFingerprintProvider ¶
func WithLifecycleFingerprintProvider(provider FingerprintProvider) LifecycleOption
WithLifecycleFingerprintProvider captures the deterministic projection used by both NewSession and RestoreSession. The provider may be called concurrently for different sessions and must be concurrency-safe.
func WithLifecycleForeignBuilderRegistry ¶
func WithLifecycleForeignBuilderRegistry(registry *foreign.BuilderRegistry) LifecycleOption
WithLifecycleForeignBuilderRegistry forwards profile-keyed foreign routing to every live/restored session while preserving the legacy builder pair option.
func WithLifecycleForeignBuilders ¶
func WithLifecycleForeignBuilders(b foreign.Builder, rb foreign.RestoredBuilder) LifecycleOption
WithLifecycleForeignBuilders captures the composition-root seams that construct foreign- engine loops (live + restored). Either seam being nil leaves foreign engines unsupported, so both are captured together. Forwarded to both NewSession and RestoreSession as WithForeignBuilders.
func WithLifecycleForeignServicesBuilders ¶
func WithLifecycleForeignServicesBuilders(b foreign.ServicesBuilder, rb foreign.ServicesRestoredBuilder) LifecycleOption
WithLifecycleForeignServicesBuilders captures the additive foreign builder seams for every live/restored session. Session construction starts one private broker only when a foreign loop uses this opt-in seam, then mints a fresh descriptor for each origin loop. Native and legacy builders remain zero-services paths.
func WithLifecycleGateCaps ¶
func WithLifecycleGateCaps(caps GateCaps) LifecycleOption
WithLifecycleGateCaps captures the live gate-directory bounds. Zero (the default) means no cap. Forwarded to both NewSession and RestoreSession as WithGateCaps.
func WithLifecycleHooks ¶
func WithLifecycleHooks(runner *hook.Runner) LifecycleOption
WithLifecycleHooks captures one immutable compiled runner for every native loop and journal built by NewSession or RestoreSession.
func WithLifecycleHustles ¶
func WithLifecycleHustles(definitions []hustle.Definition, limits HustleLimits) LifecycleOption
WithLifecycleHustles captures immutable hustle registrations for both NewSession and RestoreSession composition.
func WithLifecycleLimits ¶
func WithLifecycleLimits(l Limits) LifecycleOption
WithLifecycleLimits captures the in-session agent-spawn safety caps (depth + quota) the session enforces. Forwarded to both NewSession and RestoreSession as WithLimits.
func WithLifecycleManifest ¶
func WithLifecycleManifest(manifest event.ConfigManifest) LifecycleOption
WithLifecycleManifest captures the rig-assembled ConfigManifest counterpart to the frozen fingerprint. It is stamped onto the construction-time SessionStarted's additive Manifest field, giving a newly created session a real (SchemaVersion>=1) manifest baseline.
func WithLifecycleOffloadGC ¶
func WithLifecycleOffloadGC(policy OffloadGCPolicy) LifecycleOption
WithLifecycleOffloadGC captures the session offload-blob GC cadence. An unconfigured (zero) policy is ignored. Forwarded to both NewSession and RestoreSession, which wire the journal-admission gate + GC runner over the session lease.
func WithLifecyclePermissionReview ¶
func WithLifecyclePermissionReview(classifiers gate.PermissionClassifierSet, policy gate.PermissionReviewPolicy) LifecycleOption
WithLifecyclePermissionReview installs the registered classifier set and local decision policy every session in this lifecycle uses for automatic permission-gate review (design §20), mirroring WithLifecycleHustles' capture-once-forward-to-both shape. Both NewSession and RestoreSession apply it via the private withPermissionReview Option (gates.go). Omitting this option leaves every session's permissionClassifiers at its zero value, preserving StartPermissionReview's pre-Task-16 no-op default exactly.
func WithLifecyclePermissionReviewBreaker ¶
func WithLifecyclePermissionReviewBreaker(limits PermissionReviewBreakerLimits) LifecycleOption
WithLifecyclePermissionReviewBreaker installs the bounded circuit-breaker thresholds every session in this lifecycle applies to automatic permission review (design §18). Both NewSession and RestoreSession apply it via the private withPermissionReviewBreaker Option (review_state.go). Omitting this option leaves every session's breaker limits at their zero value (every counter disabled), matching withPermissionReviewBreaker's own zero-preserves-behavior default.
func WithLifecyclePermissionReviewEvidence ¶
func WithLifecyclePermissionReviewEvidence(access gate.EvidenceAccessEvaluator, containment gate.EvidenceContainmentVerifier, allowedKinds []string) LifecycleOption
WithLifecyclePermissionReviewEvidence installs the consumer-supplied read-only evidence-tool access boundary every registered permission classifier's evidence tools authorize against (design §13.1), mirroring WithLifecyclePermissionReview's capture-once-forward-to-both shape. Both NewSession and RestoreSession apply it via the private withPermissionReviewEvidence Option (gates.go). Omitting this option leaves every session's evidence collaborators at their zero value; newHustleController (hustle.go) then fails CONSTRUCTION closed — never silently permissive — for any registered classifier whose definition actually needs evidence tools.
func WithLifecyclePermissionReviewObservations ¶
func WithLifecyclePermissionReviewObservations(verifier gate.EvidenceObservationVerifier) LifecycleOption
WithLifecyclePermissionReviewObservations installs the consumer-supplied, OPTIONAL recheck seam (design §13.4, TOCTOU) every classifier-originated auto-approval's recorded observations are verified against immediately before the gate is claimed, mirroring WithLifecyclePermissionReviewEvidence's capture-once-forward-to-both shape. Both NewSession and RestoreSession apply it via the private withPermissionReviewObservationVerifier Option (gates.go) — but, unlike Evidence/SecurityCeiling, ONLY when this option was actually called: omitting it leaves every session's permissionReviewObservationVerifier at its nil zero value, which respondFromClassifier's verifyPermissionReviewObservations then handles as a fully supported terminal state whenever no observation was ever recorded, and as a fail-closed (stale) outcome whenever one was — see that method's own doc comment for the full reasoning, including why this cannot be a Define()-time "missing" pairing error the way WithLifecyclePermissionReviewEvidence's absence is.
func WithLifecyclePermissionReviewSecurityCeiling ¶
func WithLifecyclePermissionReviewSecurityCeiling(ceiling string) LifecycleOption
WithLifecyclePermissionReviewSecurityCeiling installs the consumer-supplied effective security posture (design §13.1/§21) every registered permission classifier's ReviewContext/ReviewBasis carries as SecurityCeiling, mirroring WithLifecyclePermissionReviewEvidence's capture-once-forward-to-both shape. Both NewSession and RestoreSession apply it via the private withPermissionReviewSecurityCeiling Option (gates.go). Omitting this option leaves every session's permissionReviewSecurityCeiling at its zero value; loopReviewContext (gates.go) then returns nil for that session (capture stays off) rather than ever falling back to a Harness-invented placeholder — see withPermissionReviewSecurityCeiling's doc comment for why a fixed sentinel is exactly the bug this option exists to close (Finding 2, Phase 6 spec-compliance review).
func WithLifecyclePlacement ¶
func WithLifecyclePlacement(p WorkspacePlacement) LifecycleOption
WithLifecyclePlacement captures the managed-workspace placement the rig declared. The unconfigured zero value is ignored (no managed workspace). Forwarded to NewSession and RestoreSession, which resolve it per-session after acquiring the session lease.
func WithLifecycleRestoreDecider ¶
func WithLifecycleRestoreDecider(decider RestoreDecider) LifecycleOption
WithLifecycleRestoreDecider captures the restore-only application policy that answers a configuration-drift assessment (the successor seam to WithLifecycleAllowConfigMismatch). A nil decider is ignored, leaving RestoreSession on the fail-secure DefaultPolicyDecider{} default. NewSession ignores it; only RestoreSession forwards it (as WithRestoreDecider).
func WithLifecycleRuntimeCatalog ¶
func WithLifecycleRuntimeCatalog(catalog loop.RuntimeCatalog) LifecycleOption
WithLifecycleRuntimeCatalog forwards the immutable parent-scoped runtime snapshot to every session constructed by this lifecycle.
func WithLifecycleRuntimeCatalogProvider ¶
func WithLifecycleRuntimeCatalogProvider(provider RuntimeCatalogProvider) LifecycleOption
WithLifecycleRuntimeCatalogProvider forwards parent-specific runtime catalog selection to every live/restored session.
func WithLifecycleRuntimeRestoreResolver ¶ added in v0.27.0
func WithLifecycleRuntimeRestoreResolver(resolver RuntimeRestoreResolver) LifecycleOption
WithLifecycleRuntimeRestoreResolver captures the optional composition-owned runtime reconstruction fallback for restored sessions.
func WithLifecycleSessionResourceStorage ¶
func WithLifecycleSessionResourceStorage(resolve SessionResourceStorageResolver) LifecycleOption
WithLifecycleSessionResourceStorage captures the durable process-resource storage resolver for both new and restored live constructions.
func WithLifecycleSnapshotPolicy ¶
func WithLifecycleSnapshotPolicy(policy SnapshotPolicy) LifecycleOption
WithLifecycleSnapshotPolicy captures the validated native checkpoint policy and forwards it to every new/restored session. Rig enforces that it is paired with a managed placement.
func WithLifecycleWorkspaceCheckpointing ¶
func WithLifecycleWorkspaceCheckpointing(ws *workspacestore.Store, root string) LifecycleOption
WithLifecycleWorkspaceCheckpointing captures the workspace snapshot store and root the session checkpoints into (and RestoreSession materializes from). A nil store is ignored. Forwarded to both NewSession and RestoreSession as WithWorkspaceCheckpointing.
type Limits ¶
type Limits struct {
// Depth is the maximum spawn-chain nesting depth (sub-loops below the primary). Zero
// → defaultDepth. A spawn whose parent chain is already this deep is refused.
Depth int
// Quota is the maximum total number of sub-loops the session may spawn over its
// lifetime. Zero → defaultQuota. A spawn once this many have been reserved is refused.
Quota int
}
Limits are the in-session agent-spawn safety caps applied by NewLoop: Depth bounds the spawn-chain nesting and Quota bounds the total sub-loops a session may spawn. A zero (or negative — a wiring slip) field adopts the package default via withDefaults, so a caller can never accidentally disable a cap; an explicit positive value overrides it.
type MissingFingerprintProviderError ¶
type MissingFingerprintProviderError struct{}
MissingFingerprintProviderError reports incomplete composition wiring.
func (*MissingFingerprintProviderError) Error ¶
func (*MissingFingerprintProviderError) Error() string
type MissingStoreError ¶
type MissingStoreError struct{}
MissingStoreError reports that NewTopologyLifecycle was handed a nil *sessionstore.Store. The durable backend is a required dependency (DIP): the Lifecycle mints per-session leases/journals/ appenders from it, so a nil store is rejected at NewTopologyLifecycle rather than deferring a nil-deref to the first NewSession/RestoreSession.
func (*MissingStoreError) Error ¶
func (*MissingStoreError) Error() string
type MissingTopologyError ¶
type MissingTopologyError struct{}
func (*MissingTopologyError) Error ¶
func (*MissingTopologyError) Error() string
type NewSessionError ¶
type NewSessionError struct {
Kind NewSessionErrorKind
Cause error
}
NewSessionError is the typed wrapper for a NewSession failure. Kind classifies the stage; Cause chains the underlying typed error (a *journal.LeaseHeldError, a *SessionError, etc.) so a caller can errors.As both this and the cause. On any failure after the lease is acquired the Lifecycle releases it best-effort before returning, so a failed NewSession never strands single-writer ownership.
func (*NewSessionError) Error ¶
func (e *NewSessionError) Error() string
func (*NewSessionError) Unwrap ¶
func (e *NewSessionError) Unwrap() error
type NewSessionErrorKind ¶
type NewSessionErrorKind string
NewSessionErrorKind classifies a NewSession failure before the live session exists — the per-session durable wiring the Lifecycle builds itself (lease, journal, checked appenders) or the session construction that consumes them.
const ( // NewSessionContextDone: the NewSession context was already cancelled. NewSessionContextDone NewSessionErrorKind = "context_done" // NewSessionIDGenerationFailed: a crypto/rand failure minting the fresh session id. NewSessionIDGenerationFailed NewSessionErrorKind = "id_generation_failed" // NewSessionLeaseFailed: the single-writer lease could not be acquired (another owner holds // it, or a backend read failed). The session must not come up. NewSessionLeaseFailed NewSessionErrorKind = "lease_failed" // NewSessionJournalFailed: the SessionJournal could not be opened (its opening fence was // rejected, or stream setup failed). NewSessionJournalFailed NewSessionErrorKind = "journal_failed" // NewSessionAppenderFailed: a checked journal appender (event/command/gate) could not be // constructed over the opened journal. NewSessionAppenderFailed NewSessionErrorKind = "appender_failed" // NewSessionRuntimeFailed: NewSession refused to build the live session over the wired dependencies. NewSessionRuntimeFailed NewSessionErrorKind = "session_failed" )
type OffloadGCPolicy ¶
OffloadGCPolicy is the validated cadence for one session's offload-blob GC: how often a pass runs (Interval) and the per-pass deadline (Timeout). The rig validates the fields before constructing it; a zero value means "off". This is SESSION OFFLOAD GC only — it reaps orphaned content-addressed offload blobs (a crash gap of the writer's blob-durable-before-pointer discipline), never workspace snapshots.
func (OffloadGCPolicy) Configured ¶
func (p OffloadGCPolicy) Configured() bool
Configured reports whether the policy is armed (both fields positive). An unarmed policy wires no gate and no runner, leaving the journal undecorated (unchanged behavior).
type Option ¶
type Option func(*Session)
Option configures an optional session dependency at construction. The bare New(ctx, cfg) installs the nop command appender; an Option overrides it. This mirrors the hub's Option pattern so the composition root injects the durable intent-log appender (Phase 10) without New growing a positional parameter.
func WithAllowConfigMismatch ¶
func WithAllowConfigMismatch() Option
WithAllowConfigMismatch is the restore-only opt-in to resume a session whose persisted config fingerprint no longer matches the live config (a different model, system prompt, or tool policy). Restore is fail-secure by DEFAULT — a mismatch rejects with *ConfigMismatchError so a conversation never silently resumes under behavior it never ran with — so this option exists for an operator who knowingly accepts the drift. New ignores it (only Restore checks fingerprints).
func WithCommandAppender ¶
func WithCommandAppender(a commandAppender) Option
WithCommandAppender injects the intent-log appender (the composition root's adapter over SessionJournal). A nil appender is ignored (the nop default stays installed) so a caller can never accidentally null out the field and nil-deref the dispatch path.
func WithEventAppender ¶
func WithEventAppender(a eventAppender) Option
WithEventAppender injects the hub's REQUIRED durable event tap (the composition root's adapter over SessionJournal — journal.JournalEventAppender). New forwards it into the hub (hub.WithAppender) so every Enduring event is durably appended before fan-out (fail-secure: an append failure faults the session). A nil appender is ignored (the hub's nop default stays installed) so a caller can never null out the tap and silently persist nothing. This is the event-side counterpart to WithCommandAppender (the audit-only intent log).
func WithFingerprint ¶
func WithFingerprint(fingerprint event.ConfigFingerprint) Option
WithFingerprint installs a definition-time frozen compatibility fingerprint. Unlike a provider, it is available before any loop definition is bound during restore.
func WithFingerprintProvider ¶
func WithFingerprintProvider(provider FingerprintProvider) Option
WithFingerprintProvider installs the composition root's immutable projection.
func WithForeignBuilderRegistry ¶
func WithForeignBuilderRegistry(registry *foreign.BuilderRegistry) Option
WithForeignBuilderRegistry injects profile-keyed foreign construction while retaining the legacy function-pair seam for EngineForeignClaude/Codex.
func WithForeignBuilders ¶
func WithForeignBuilders(b foreign.Builder, rb foreign.RestoredBuilder) Option
WithForeignBuilders wires the composition-root seam that constructs foreign-engine loops (live + restored). Without it, a foreign-engine definition fails closed at newLoop (SessionForeignBuilderMissing) and at restore (RestoreForeignBuilderMissing) — a foreign engine never silently resolves to a native loop. The two seams travel together (a live build and a restored build of the same agent), so they are wired as one option; either being nil leaves foreign engines unsupported for that path.
func WithForeignServicesBuilders ¶
func WithForeignServicesBuilders(b foreign.ServicesBuilder, rb foreign.ServicesRestoredBuilder) Option
WithForeignServicesBuilders wires the additive foreign-engine seam. Runtime supplies a fresh Services snapshot for the exact session+loop construction: the broker descriptor is minted for that origin loop and Delivery remains a loop-scoped hook. Legacy builders remain on the zero-services adapter.
func WithGateAppender ¶
func WithGateAppender(a gateAppender) Option
WithGateAppender injects the strict durable append seam for gate prepare/open/resolve. A nil appender is ignored (the nop default stays installed). It is the gate-directory counterpart to WithCommandAppender.
func WithGateCaps ¶
WithGateCaps injects the live gate directory bounds. Zero (the default) means no cap. The cap counts preparing + open + claiming.
func WithInterruptReleasePolicy ¶
func WithInterruptReleasePolicy(p InterruptReleasePolicy) Option
WithInterruptReleasePolicy installs the pluggable admission-barrier release policy (the Dependency-Inversion seam of the interrupt machinery). After an interrupt cancels a running turn, the session holds the interrupt-pending marks until the policy's AwaitRelease returns, then clears them. Without this option the session uses the default (sessionIdleRelease): release once the session next reaches idle (SessionIdle durably appended). Task 16 injects a workspace-aware policy that may hold the barrier through a checkpoint. A nil policy is ignored (the default stays installed). See interrupt.go.
func WithLeaseRelease ¶
WithLeaseRelease installs the single-writer-lease release hook the session calls ONCE at the end of Shutdown (after the loops have drained, so the journal's last append is durable before ownership is relinquished). The composition root passes lease.Release for a NEW session; Restore installs it from the lease it acquired, so both paths free ownership on a clean exit and a successor can re-acquire without waiting out the TTL. A nil hook is ignored (headless mode stays a no-op). It takes a context so the release I/O is bounded by Shutdown's ctx.
func WithLimits ¶
WithLimits sets the in-session agent-spawn safety caps (depth + quota) NewLoop enforces. A zero (or negative) field in the supplied Limits adopts the package default (Depth 3 / Quota 64) when newSession applies withDefaults, so a caller can never disable a cap with a missing or bad value. Without this option a session uses the defaults. It applies on both New and Restore (the restore path re-seeds the spawn counter from the durable log, then enforces these caps against it).
func WithManifest ¶
func WithManifest(manifest event.ConfigManifest) Option
WithManifest installs the rig-assembled ConfigManifest counterpart to the frozen fingerprint. The session stamps it onto the construction-time SessionStarted's additive Manifest field.
func WithRestoreDecider ¶
func WithRestoreDecider(decider RestoreDecider) Option
WithRestoreDecider installs the restore-only application policy that answers a configuration-drift assessment (the successor seam to WithAllowConfigMismatch). A nil decider is ignored so a wiring slip cannot null the field — the session then keeps its fail-secure DefaultPolicyDecider{} default. New ignores the decider (only Restore assesses drift); a later task consumes it in the restore path.
func WithRuntimeCatalog ¶
func WithRuntimeCatalog(catalog loop.RuntimeCatalog) Option
WithRuntimeCatalog installs one immutable parent-scoped catalog snapshot. The same value feeds agent schema/preparation and controller revalidation.
func WithRuntimeCatalogProvider ¶
func WithRuntimeCatalogProvider(provider RuntimeCatalogProvider) Option
WithRuntimeCatalogProvider installs parent-specific catalog snapshots. It takes precedence over WithRuntimeCatalog when both are supplied.
func WithRuntimeRestoreResolver ¶ added in v0.27.0
func WithRuntimeRestoreResolver(resolver RuntimeRestoreResolver) Option
WithRuntimeRestoreResolver installs the optional composition-owned runtime reconstruction fallback. A nil resolver preserves the fail-closed default.
func WithSessionID ¶
WithSessionID injects an externally-minted sessionID for New to adopt instead of minting its own. It resolves the journal chicken-and-egg: the durable journal needs the sessionID (to bind the per-session stream and write the opening LeaseFence) BEFORE the session exists, so the composition root mints the id first, builds the journal/lease/appenders from it, then hands the SAME id to New here. A zero id is ignored (New mints one) so a wiring slip can never produce a zero-id session. Restore takes the sessionID positionally and ignores this option.
func WithSnapshotPolicy ¶
func WithSnapshotPolicy(policy SnapshotPolicy) Option
WithSnapshotPolicy carries the already-validated rig policy into one session. It is meaningful only with a managed placement; rig enforces that pairing.
func WithWorkspaceCheckpointing ¶
func WithWorkspaceCheckpointing(ws *workspacestore.Store, root string) Option
WithWorkspaceCheckpointing wires the workspace snapshot store and the workspace root this session checkpoints. Both are required for CheckpointWorkspace; without this option the capability is unconfigured and CheckpointWorkspace fails closed with a typed *WorkspaceNotConfiguredError. The composition root decides WHEN to checkpoint (a quiescence point); looprig only exposes the capability. A nil store is ignored (the default unconfigured state stays), so a wiring slip can never install a store the capability would nil-deref on.
type PermissionReviewBreakerLimits ¶
type PermissionReviewBreakerLimits struct {
MaxConsecutiveNeedsHuman int
MaxInvalidOrFailed int
MaxIdenticalSubjects int
MaxStaleResponses int
InterruptOnTrip bool
Session PermissionReviewSessionBreakerLimits
}
PermissionReviewBreakerLimits are the consumer-configurable bounded per-turn and per-session circuit-breaker thresholds (design §18). A zero value disables the corresponding counter — see reviewCircuitBreakerLimits' doc comment (review_state.go) for why the turn-scoped and session-scoped thresholds are deliberately separate configuration surfaces.
type PermissionReviewSessionBreakerLimits ¶
type PermissionReviewSessionBreakerLimits struct {
MaxConsecutiveNeedsHuman int
MaxInvalidOrFailed int
MaxIdenticalSubjects int
MaxStaleResponses int
}
PermissionReviewSessionBreakerLimits is PermissionReviewBreakerLimits' session-scoped counterpart (design §18: "track per-turn AND per-session bounded counters"), mirroring reviewSessionCircuitBreakerLimits.
type PlacementResolutionError ¶
type PlacementResolutionError struct {
Reason string
}
PlacementResolutionError reports an invalid placement resolution (e.g. a per-session placement with a zero session id). It is a construction-time, fail-closed failure.
func (*PlacementResolutionError) Error ¶
func (e *PlacementResolutionError) Error() string
type ProcessLifecycleOwnerMismatchError ¶
ProcessLifecycleOwnerMismatchError reports that a Tools-supplied ProcessLifecycleMetadata named a session other than the one the checked publisher was attached to. A process resource is bound to exactly one session for its whole lifetime, so metadata naming a different session can only be a bug or a forged call — never a legitimate publish — and is rejected fail-secure before it ever reaches the durable journal or the hub.
func (*ProcessLifecycleOwnerMismatchError) Error ¶
func (e *ProcessLifecycleOwnerMismatchError) Error() string
type ProcessNotificationDeliveryStoppedError ¶
ProcessNotificationDeliveryStoppedError reports that a durably-appended (or deduplicated) ProcessNotification could not be delivered to its owning loop right now: the loop's bounded live notification set is full, or the loop exited concurrently with dispatch. The durable command remains authoritative — the caller (Tools' supervisor) retries dispatch later with the SAME CommandID; no re-append happens on that retry (24A's idempotency index already recognizes the id).
func (*ProcessNotificationDeliveryStoppedError) Error ¶
func (e *ProcessNotificationDeliveryStoppedError) Error() string
type ProcessNotificationOwnerMismatchError ¶
ProcessNotificationOwnerMismatchError reports that a Tools-supplied ProcessCompletionNotification named a session other than the one this Session was constructed for. A process resource is bound to exactly one session for its whole lifetime, so a notification naming a different session can only be a bug or a forged call — never a legitimate delivery — and is rejected fail-secure before it ever reaches the durable journal or a loop's command sink.
func (*ProcessNotificationOwnerMismatchError) Error ¶
func (e *ProcessNotificationOwnerMismatchError) Error() string
type ProcessNotificationUnsupportedError ¶
ProcessNotificationUnsupportedError reports that a process completion notification was addressed to a loop whose bound definition is not EngineNative. Foreign engines never receive process notifications — they have no backend arm to deliver one to, so accepting it would either block forever or silently drop it; this refuses structurally, on the ENGINE, mirroring loopHandle.ReplaceExternalTools' identical foreign-engine guard (see loop_tools.go) rather than testing bindings or backend shape.
func (*ProcessNotificationUnsupportedError) Error ¶
func (e *ProcessNotificationUnsupportedError) Error() string
type ProcessServicesUnsupportedError ¶
ProcessServicesUnsupportedError rejects process-enabled definitions on engines whose lifecycle events cannot be published by Harness.
func (*ProcessServicesUnsupportedError) Error ¶
func (e *ProcessServicesUnsupportedError) Error() string
type RestoreDecider ¶
type RestoreDecider = sessionapi.RestoreDecider
type RestoreDecision ¶
type RestoreDecision = sessionapi.RestoreDecision
type RestoreDiscoveryError ¶
type RestoreDiscoveryError = sessionapi.RestoreDiscoveryError
type RestoreDiscoveryErrorKind ¶
type RestoreDiscoveryErrorKind = sessionapi.RestoreDiscoveryErrorKind
type RestoreError ¶
type RestoreError = sessionapi.RestoreError
type RestoreErrorKind ¶
type RestoreErrorKind = sessionapi.RestoreErrorKind
type RestoreRejectedError ¶
type RestoreRejectedError = sessionapi.RestoreRejectedError
type RestoreRuntimeMismatchError ¶
type RestoreRuntimeMismatchError = sessionapi.RestoreRuntimeMismatchError
type RestoreRuntimeMismatchKind ¶
type RestoreRuntimeMismatchKind = string
type RestoredContextModelMismatchError ¶
RestoredContextModelMismatchError reports a replay projection that would seed a current measurement under a different restored runtime model.
func (*RestoredContextModelMismatchError) Error ¶
func (e *RestoredContextModelMismatchError) Error() string
type RuntimeCatalogProvider ¶
type RuntimeCatalogProvider func(parent loop.Definition) (loop.RuntimeCatalog, bool)
RuntimeCatalogProvider returns the immutable runtime catalog visible to one parent definition. Returning false preserves the native/no-choice surface for that parent. A provider is composition-root policy and must not derive entries from model-controlled request data.
type RuntimeRestoreRequest ¶ added in v0.27.0
type RuntimeRestoreRequest = sessionapi.RuntimeRestoreRequest
type RuntimeRestoreResolver ¶ added in v0.27.0
type RuntimeRestoreResolver = sessionapi.RuntimeRestoreResolver
type Session ¶
type Session struct {
// contains filtered or unexported fields
}
func New ¶
New constructs a Session and starts its zero-parent root loop's actor goroutine. It owns the session fan-in hub and emits the session-scoped SessionStarted through it.
This SessionStarted (the s.hub.PublishEvent below) is the SOLE SessionStarted: the session publishes it through the HUB to its SUBSCRIBERS (TUI/CLI fan-in), and the loop never emits one. It is published before any subscriber attaches, so a subscriber that connects later does not observe it; reliable delivery of the session start to late subscribers is a separate future follow-on.
func NewTopology ¶
NewTopology constructs every configured primer as an independent root loop.
func RestoreTopology ¶
func RestoreTopology(ctx context.Context, topology Topology, sessionID uuid.UUID, store *sessionstore.Store, opts ...Option) (*Session, error)
RestoreTopology reconstructs the durable loop topology and brings it up idle. It does not publish SessionStarted.
Order (per the design — RestoreStarted is the FIRST restore mutation, after the lease fence the journal writes at construction):
- Acquire the single-writer lease, construct the SessionJournal (writes the opening LeaseFence — the handover boundary) and the EventReplayer.
- Replay the stream; read the persisted config fingerprint and compare to the live config. On mismatch → *ConfigMismatchError UNLESS WithAllowConfigMismatch is set.
- Append RestoreStarted (the first restore mutation).
- Validate, bind, and independently fold every durable declared loop.
- Append checked crash closures for every open turn.
- Materialize the workspace, build all loops, and validate the active loop.
- Append RestoreDone as the final commit point and return the controller.
On ANY failure in steps 2–7 (a config mismatch, a discovery/replay/decode/object failure, or an append failure) Restore durably records a RestoreErrored and returns a typed error; the session does NOT come up (fail-secure / no silent drift). On a FAILED restore the acquired lease is released here before returning (so a successor can re-acquire). On SUCCESS the journal HOLDS the lease for the live session's lifetime; releasing it at session teardown is the Phase-10 composition root's wiring (mirroring how the lease is composition-root-owned in the durable-tap path), out of scope here. RestoreTopology reconstructs the entire topology in one leased replay transaction.
func (*Session) ActivateGate ¶
ActivateGate is called by the owner after its local blocker/continuation exists. It requires a preparing gate, appends the public GateOpened event via the strict gateAppender, stores the private route, and flips the entry to open so ListGates returns it. A failed append leaves the gate preparing. An unknown or non-preparing gate returns a typed *GateError.
func (*Session) ActiveLoop ¶
func (*Session) ActiveLoopID ¶
ActiveLoopID returns the session's mutable active loop id, the default target for Submit. It is safe to call concurrently.
func (*Session) AdmissionFaultErr ¶
AdmissionFaultErr is the loop actor's last-moment admission probe, closing the Session submit check→send race without changing the narrower change-event FaultErr seam.
func (*Session) AwaitGateAnswer ¶
AwaitGateAnswer blocks until a HOST-OWNED gate is answered and returns the validated answer, including the form values that are deliberately absent from every durable record.
It is the host's half of the loop's command dispatch: the opener of a form or open-url gate calls PrepareGateOpen, ActivateGate, then this. It returns a typed *GateError{GateNotFound} for a gate that is not host-owned, was never prepared, or whose answer was already taken — an answer is delivered exactly once.
The opener MUST either await or CloseGate, which is the same obligation ActivateGate already places on it. Both paths free the slot.
A ctx cancellation abandons the wait and frees the slot; it does NOT close the gate, because the gate is durable state and ctx is the caller's. An opener that gives up should CloseGate.
func (*Session) CheckpointWorkspace ¶
CheckpointWorkspace durably snapshots the session's configured workspace root and records a WorkspaceCheckpointed enduring event pointing at the snapshot — the resume token the restore path materializes from. It returns the snapshot Ref (also carried on the event) so the caller can correlate the checkpoint.
Snapshot-before-append: the archive bytes are durable (Snapshot's Blobs.Put has returned) BEFORE the event is appended, so a crash between the two leaks an unreferenced blob (GC's job) — never a dangling ref. That ordering is guaranteed by call order here (Snapshot returns before PublishEvent runs), not by any stronger signal.
The WorkspaceCheckpointed is Enduring, so it flows through the hub's REQUIRED durable tap: the event is appended synchronously BEFORE fan-out, and a durable-append failure surfaces as a SESSION FAULT (the hub latches it via ReportFault) exactly like every other enduring event — PublishEvent itself returns nil on that path. This method adds no stronger durability signal; on the happy path the event IS durably appended by the time it returns.
WHEN to call this — a quiescence point (a turn done, a user question, about to suspend) — is the composition root's decision, consistent with looprig-as-SDK and the foreign-loop quiescence model; the session only exposes the capability. Without WithWorkspaceCheckpointing the capability is unconfigured and this fails closed with a typed *WorkspaceNotConfiguredError, having touched nothing. ctx bounds the snapshot I/O and the durable append.
func (*Session) CloseGate ¶
CloseGate closes or abandons a session-owned gate without dispatching an answer to the resolver. Preparing gates were never public, so they are removed without a public GateResolved. Open gates are durably resolved before removal.
func (*Session) CommitBoundary ¶
CommitBoundary is the native loop-actor boundary seam. Without a configured workspace policy it preserves ordinary publication; with one it delegates the already-stamped StepDone/turn terminal to the session checkpoint controller.
func (*Session) CommitContextBoundary ¶
CommitContextBoundary is the context-mutating boundary seam. The committed result distinguishes an event append failure from a later checkpoint failure, so the loop actor can keep live history aligned with durable restore state.
func (*Session) CommitSessionIdle ¶
func (s *Session) CommitSessionIdle(ctx context.Context, idle event.SessionIdle, commit func() error) error
CommitSessionIdle is the hub's narrow derived-idle collaborator. The hub retains append/fanout ownership in commit; the controller brackets it with the workspace permit and accepted checkpoint walk when idle is the configured trigger.
func (*Session) Compact ¶
Compact requests manual compaction of the currently active loop. The active id is sampled once, then routed through the exact-target implementation.
func (*Session) CompactToLoop ¶
CompactToLoop requests manual compaction of one exact live native loop. The trusted session boundary owns user agency and command coordinates; callers receive only the correlation id used by durable waiter outcomes.
func (*Session) Done ¶ added in v0.30.0
func (s *Session) Done() <-chan struct{}
Done reports session liveness: the returned channel is closed once Shutdown has BEGUN (teardown admits no new work) and never reopens. It is the signal an out-of-process observer needs, because a shut-down session is otherwise indistinguishable from a live one from outside: Hub.SubscribeEvents still succeeds after the hub is stopped, so an event stream over a dead session would heartbeat forever, pinning its handler goroutine, its subscription and this whole Session.
A receive on it must never be read as "cleanup finished" — it fires at the start of teardown, deliberately.
The channel is minted here on first use under the same shutdownMu that Shutdown closes it under, so every Session reports liveness however it was built. Done takes only shutdownMu and calls nothing, and Shutdown never calls Done, so the two cannot deadlock.
func (*Session) EnterExecution ¶
EnterExecution is the inference-step session-wide checkpoint and loop-scoped interrupt admission seam.
func (*Session) EnterTurnStart ¶
func (s *Session) EnterTurnStart(ctx context.Context, loopID uuid.UUID) (loopruntime.TurnStartCapability, error)
EnterTurnStart reserves the Hub activity transition before acquiring the first checkpoint reader. Its returned capability publishes the exact opening event and releases the checkpoint reader when the first inference step ends.
func (*Session) FaultErr ¶
FaultErr is the loop actor's post-emit durable-fault probe (loopruntime type-asserts the session for it). It returns the latched persistence fault (a required Enduring append failed) or nil. After emitting a mode/inference change event, the actor calls it: because the hub raises the fault INLINE (synchronously on the same actor goroutine, via ReportFault) when the append fails, a non-nil result here means the change event did not persist, so the actor declines to apply the change (fail-secure, no partial apply).
func (*Session) Interrupt ¶
Interrupt is the human "stop everything": it cancels the running turn of EVERY live loop in the session — every registered loop — marking each interrupt-pending before fanning the command.Interrupt out to all of them CONCURRENTLY (design: "Session.Interrupt marks every live loop interrupt-pending before concurrently sending commands"). Idle loops ack false and are harmless; Interrupt returns true iff ANY loop reported it cancelled a running turn. A fully-idle interrupt is fail-quiet: it returns false and appends no events. ctx bounds the fan-out so a slow actor cannot wedge it.
Unlike Shutdown, Interrupt does NOT latch closing and does NOT tear loops down. It stamps Agency=AgencyUser (a human pressed interrupt). Selection + marking + concurrent delivery + the admission barrier live in interrupt.go (runInterrupt); this is the session-wide scope.
func (*Session) ListGates ¶
ListGates returns the public envelopes of all open gates — preparing, claiming, and closed entries are excluded. The returned slice is a snapshot; mutating it does not affect the directory.
func (*Session) LoopController ¶
func (*Session) NewLoop ¶
func (s *Session) NewLoop(parent loop.Provenance, cfg loop.Definition) (uuid.UUID, error)
NewLoop creates another loop inside this session. The new loop shares SessionID but receives its own loop id and loop goroutine. parent is the provenance of the spawning turn/step (zero for a root loop); the session records it in the registry and passes it to loopruntime.New. The session stores the loop handle and returns only the loop id, because callers route through session methods rather than writing to a loop command channel directly.
func (*Session) NotifyProcessCompletion ¶
func (s *Session) NotifyProcessCompletion(ctx context.Context, n tool.ProcessCompletionNotification) error
NotifyProcessCompletion is Task 24C's real implementation of tool.ProcessCompletionNotifier, attached behind the session-owned sessionProcessServiceBridge exactly like 24B's checked lifecycle publisher (see process_services.go's attachProcessCompletionNotifier). It reports only the boundary contract's plain error (nil on ACCEPTED or DUPLICATE, the durable append's typed collision on COLLISION, and a typed reason on STOPPED); notifyProcessCompletion below carries the richer command.ProcessNotificationResult a caller inspecting the disposition (tests, and a future retry policy) needs.
func (*Session) OpenHostGate ¶
func (s *Session) OpenHostGate(ctx context.Context, loopID uuid.UUID, g gate.Gate, payload gate.Payload) (gate.ID, error)
OpenHostGate opens a HOST-OWNED gate and returns its id, ready to be awaited.
It is the ONLY gate-opening entry point on the published session.GateHost contract, and it is deliberately not PrepareGateOpen. PrepareGateOpen takes an arbitrary kind, resolver, payload, and — through the ActivateGate route that must follow it — an arbitrary target loop, which together are exactly the loop-owned command path (dispatchGateCommand). A host must not be able to reach that: minting an "approve this tool call" gate against someone else's loop is not a capability an integration should acquire by being able to ask a human a question. This entry point takes the same arguments minus the route and refuses everything that is not host-owned, so the loop path is unreachable through it by construction rather than by convention.
It collapses prepare and activate into one call, which is safe precisely because the gate is host-owned. The two phases exist so a LOOP can install its blocker while the gate is still private; a host's blocker is the answer slot, and PrepareGateOpen installs that itself. There is no window here for the opener to miss.
Every rejection is a *GateError{GateKindMismatch}, checked BEFORE anything is journaled:
- hostOwnedGate — the same predicate that governs answer time, so open time and answer time cannot drift apart. A form gate declaring ResolverLoop is refused here rather than accepted and then refused after a human has already answered it.
- the payload must match the kind, so a form gate cannot be opened with an open-url payload (which would strand its answer at ParseFormAnswers).
- the payload's own invariants (ValidateFormSchema / ValidateOpenURLPayload) must hold, because an unanswerable or targetless prompt should never reach a human.
It then DERIVES the trusted half of the public projection from the validated payload (projectHostGatePrompt), so the envelope a renderer sees cannot disagree with the payload a response is validated against.
The caller MUST either AwaitGateAnswer or CloseGate; both free the slot.
func (*Session) PrepareGateOpen ¶
func (s *Session) PrepareGateOpen(ctx context.Context, loopID uuid.UUID, g gate.Gate, payload gate.Payload) (gate.ID, error)
PrepareGateOpen durably commits the public envelope plus private payload as a private GatePreparedRecord. It mints the GateID, stamps the GatePrepared event with the session's coordinates and the caller's loopID, appends the record via the strict gateAppender, and — only on success — inserts a non-listable preparing entry. A failed append returns a typed *GateError{GateAppendFailed} and does not mutate the directory. loopID is the producing loop's id (the GatePrepared event is loopScoped); TurnID/StepID are read from the gate's Subject.
func (*Session) PublishEvent ¶
PublishEvent is the session's eventPublisher implementation passed to loopruntime.New. It delegates to the hub, which fans the event out to matching subscribers and applies any quiescence transition the event implies. The loop depends only on the narrow eventPublisher interface; it never sees the hub, its subscriber set, or its shutdown state (Interface Segregation / least privilege).
func (*Session) PublishEventChecked ¶
PublishEventChecked is the transactional publication path for state transitions whose caller must not mutate live state unless the required append commits. Delegate acceptance, public gate open/resolve transitions, and native checkpoint boundaries use it to receive append failures directly while retaining durable-first fan-out.
func (*Session) ReportFault ¶
func (s *Session) ReportFault(_ context.Context, fault *hub.SessionPersistenceFault)
ReportFault is the session's fail-secure response to a hub persistence fault (a required durable append failed): it latches the faulted state (so every new Submit/NewLoop is refused) and wakes every blocked WaitIdle waiter with the fault. It is the hub's FaultReporter — the hub calls it inline (outside the hub lock) when AppendEvent fails the durable tap. It is idempotent: the FIRST fault latches and records the cause; a later fault still wakes any new waiters but keeps the first recorded cause (the root failure). The session is NOT torn down here — restore / operator action owns recovery; this only stops admitting new work and unblocks callers stuck waiting on a session that can no longer reach idle durably.
func (*Session) RespondGate ¶
RespondGate claims an open gate, durably appends GateResolved, and dispatches the translated command to the owning loop. It is durable-first: the GateResolved append happens BEFORE the command dispatch, so a crash after the append leaves the gate closed (not re-answerable) even if the command was not yet consumed. A failed append reverts the in-memory claim and leaves the gate answerable. Command dispatch uses s.sessionCtx (not the caller's ctx) so a client disconnect after the durable commit does not cancel delivery.
A caller-supplied response whose Source.Kind is gate.ResponseFromClassifier is rejected outright, before any locking or validation: only the private respondFromClassifier method (called exclusively from the permission-review adapter once gate.CombinePermissionAssessments reports eligibility) may produce that provenance. gate.ResponseSource's fields are exported — a public caller CAN construct one with Kind set to ResponseFromClassifier — so this is a runtime, defense-in-depth check rather than a type-system guarantee; respondFromClassifier reaches the shared core below directly and is not subject to it.
func (*Session) RestoreWorkspace ¶
RestoreWorkspace rewinds the managed workspace to ref. It fails closed with *WorkspaceNotConfiguredError when no placement is configured, and with a typed *WorkspaceRestoreError on any admission, staging, or commit failure.
func (*Session) RunAgent ¶
func (s *Session) RunAgent(ctx context.Context, parent loop.Provenance, cfg loop.Definition, blocks []content.Block, parentToolUseID string) (string, error)
RunAgent creates an in-session sub-loop, runs one turn on it for the given blocks (machine-originated), and returns the sub-loop's final assistant text. It is the SOLE exported entry point of the agent composition: it wires together the unexported building blocks (NewLoop + SubscribeEvents + submitToLoop + drainToFinalText + interruptLoopID) so the agent collaboration tools' injected capability (a later task) has one method to call and the blocks stay package-private.
cfg is the sub-loop's loop.Definition — the CALLER builds a FRESH cfg per call (its own ToolSet and access gate) so each sub-loop has independent approval state; RunAgent never reuses a shared ToolSet. parent is the spawning loop/turn/step provenance (recorded on the sub-loop's registry entry and stamped on its LoopStarted). The submit is stamped Agency=AgencyMachine — an agent turn is a machine action, never falsely attributed to a human.
The sub-loop PERSISTS idle after the turn (loops are never deleted, design §8): RunAgent closes only the SUBSCRIPTION, never the loop. The ordering is load-bearing: it subscribes (scoped to the new sub-loop) BEFORE submitting, so the opening TurnStarted the drain correlates on cannot be missed — the hub has no replay (design §4).
Errors propagate from the first block that fails: NewLoop (e.g. SessionClosing while shutting down, or id-gen failure), SubscribeEvents, the submit, or the drain's typed §5 failures (*drainFailedError / *TurnRejectedError / *drainInterruptedError / *drainLostError). ctx is the calling turn's context; because submits carry no ctx, a ctx cancel cannot reach the sub-loop's turn — the drain translates it into a single loop-targeted Interrupt (the closure below) and drains to the resulting TurnInterrupted terminal.
func (*Session) SessionActivated ¶
func (s *Session) SessionActivated()
SessionActivated lets the hub cancel an active best-effort quiescent walk before newly active work proceeds. Required and shared-fuzzy policies ignore activation.
func (*Session) SetActiveLoop ¶
func (*Session) Shutdown ¶
Shutdown drives the WHOLE session to its stopped phase and blocks until every loop's actor exits. Sub-loops are retained (each runs its own goroutine and loopCtx), so Shutdown must reach every loop. The order is deliberate:
- Latch closing AND snapshot the loops in ONE loopsMu critical section. This is the atomicity NewLoop's registration check pairs with (it re-tests closing under the same lock): a loop is either already in this snapshot or refused by NewLoop — never registered after the snapshot is taken.
- Close hustle admission and cancel queued/executing inference. Keep the checkpoint controller, hub, and session context open for owned cleanup.
- Send command.Shutdown to EVERY loop in the snapshot, recording each reached loop's (loop, ack) pair. Per loop: mint a CommandID; on id-gen failure SKIP that loop's graceful shutdown (the final sessionCancel hard-cancels it) rather than aborting the whole Shutdown. A loop already exited is skipped.
- Wait for every recorded ack, then join hustle terminal audit, finalizers, and blocking activity release through Controller.Drained.
- Stop/join checkpoints and offload GC, append SessionStopped/stop the hub, release root/session leases, and cancel sessionCtx last.
- Loop/checkpoint/hub phases have private deadlines derived from validated component bounds. Hustle audit, finalization, and worker drain use their own trusted inner bounds and are always joined; an outer deadline never detaches owned cleanup. Caller cancellation is diagnostic only.
Concurrent and repeated calls join one teardown owner and receive the same cleanup result, augmented with each caller's own context error after cleanup completes.
func (*Session) StartPermissionReview ¶
func (s *Session) StartPermissionReview(ctx context.Context, req loopruntime.PermissionReviewRequest)
StartPermissionReview implements the loop actor's private permissionReviewStarter seam (internal/loopruntime/gate.go): the ONLY thing the actor calls, inline and fire-and-forget, after a gatePermission registration activates and the runner has been acked (design §14.2/§14.3). It MUST return promptly — the actor never wraps this call in a goroutine of its own, so classifier inference is moved onto a fresh goroutine here (`go adapter.review(...)`) before this method returns.
StartPermissionReview no-ops (starts no review) whenever:
- no permission classifiers are configured for this session (s.permissionClassifiers is the zero PermissionClassifierSet); or
- the session's shared Hustle runtime is not yet bound (s.hustleController == nil — cannot happen once a session has finished construction, but is checked rather than assumed); or
- the classifier/policy configuration itself is invalid (newPermissionReviewAdapter's own validation).
Every one of those is a "nothing to review" outcome, never a denial or an approval: this method has no path to RespondGate at all (see permissionReviewAdapter's type doc), so the human gate this handoff accompanies is always preserved regardless of what happens here.
func (*Session) Submit ¶
Submit is the HUMAN-ONLY submit entry point: it stamps Agency=AgencyUser (a person authored this input). Programmatic/machine callers go through submitToLoop with Agency=AgencyMachine (the agent path).
Submit sends input as a queueable UserInput to the active loop, FIRE-AND-FORGET: it returns the InputID (the submit command's id, == the Cause.CommandID on the resulting Reply events) and a transport error only if the command could not be handed to the loop. The outcome — InputQueued / TurnStarted / TurnFoldedInto / TurnRejected / InputCancelled — is observed on the event fan-in (each Reply carries Cause.CommandID == this returned id), NOT returned here.
A submit while a turn is running QUEUES rather than rejecting; a submit while idle starts a turn. Submit never reads a reply, so it returns the instant the command is accepted by the loop.
The send carries the standard escapes: ctx.Done() → SessionContextDone, the loop's Done → SessionLoopExited, and a missing active loop → SessionLoopNotFound. On any of those the returned id is the zero UUID, because nothing was sent and there is no correlation to hand back.
func (*Session) SubmitToLoop ¶
func (s *Session) SubmitToLoop(ctx context.Context, loopID uuid.UUID, blocks []content.Block) (uuid.UUID, error)
SubmitToLoop is the loop-targeted counterpart of Submit: it sends human-authored (AgencyUser) input to a SPECIFIC loop's CommandSink rather than the active selection. It is the modern viewport's "submit to the FOCUSED loop" primitive — a submit while focused on a agent runs a NEW turn on THAT loop (accepted: a submit to an idle-but-tracked agent starts a fresh turn on it), while a submit to the active loop id behaves exactly like Submit.
Like Submit it stamps command.UserInput with Agency=AgencyUser and is FIRE-AND-FORGET: it returns the minted InputID (the Cause.CommandID the resulting Reply events carry on the session fan-in) and a transport error only; the turn outcome — InputQueued / TurnStarted / TurnFoldedInto / TurnRejected / InputCancelled — is observed on the event fan-in, never returned here. The send carries the same escapes as Submit: ctx.Done() → SessionContextDone, the loop's Done → SessionLoopExited, and an unknown loop id → SessionLoopNotFound. On any of those the returned id is the zero UUID, because nothing was sent and there is no correlation to hand back. It delegates to the shared loop-targeted core submitToLoop with AgencyUser, exactly as Submit does for the active loop.
func (*Session) SubscribeEvents ¶
func (s *Session) SubscribeEvents(filter event.EventFilter) (event.Subscription, error)
SubscribeEvents attaches a consumer to the session fan-in with the given filter. The returned subscription's Events() channel yields the filtered stream; the caller must Close it when done. It delegates to the hub.
type SessionError ¶
type SessionError = sessionapi.SessionError
type SessionErrorKind ¶
type SessionErrorKind = sessionapi.SessionErrorKind
type SessionResourceStorageError ¶
type SessionResourceStorageError struct {
Kind SessionResourceStorageErrorKind
Path string
Cause error
}
SessionResourceStorageError preserves a stable classification while wrapping provider and filesystem causes.
func (*SessionResourceStorageError) Error ¶
func (e *SessionResourceStorageError) Error() string
func (*SessionResourceStorageError) Unwrap ¶
func (e *SessionResourceStorageError) Unwrap() error
type SessionResourceStorageErrorKind ¶
type SessionResourceStorageErrorKind string
SessionResourceStorageErrorKind classifies fail-closed durable root and identity-anchor validation failures.
const ( SessionResourceStorageInvalid SessionResourceStorageErrorKind = "invalid" SessionResourceStorageIdentityMismatch SessionResourceStorageErrorKind = "identity_mismatch" SessionResourceStorageAnchorMissing SessionResourceStorageErrorKind = "anchor_missing" SessionResourceStorageAnchorCorrupt SessionResourceStorageErrorKind = "anchor_corrupt" SessionResourceStorageWorkspaceOverlap SessionResourceStorageErrorKind = "workspace_overlap" )
type SessionResourceStorageResolver ¶
type SessionResourceStorageResolver func(context.Context, uuid.UUID) (root, identity string, err error)
SessionResourceStorageResolver is the narrow lifecycle seam adapted from the public rig provider. It returns a durable root and provider-owned identity for the supplied non-zero session ID.
type ShutdownCleanupPhase ¶
type ShutdownCleanupPhase string
ShutdownCleanupPhase identifies the session-owned teardown phase that exceeded its private cleanup deadline.
const ( ShutdownCleanupLoopSend ShutdownCleanupPhase = "loop_send" ShutdownCleanupLoopDrain ShutdownCleanupPhase = "loop_drain" ShutdownCleanupCheckpointDrain ShutdownCleanupPhase = "checkpoint_drain" ShutdownCleanupCollabBroker ShutdownCleanupPhase = "collab_broker" ShutdownCleanupSessionResources ShutdownCleanupPhase = "session_resources" ShutdownCleanupHubStop ShutdownCleanupPhase = "hub_stop" )
type ShutdownCleanupTimeoutError ¶
type ShutdownCleanupTimeoutError struct {
Phase ShutdownCleanupPhase
Timeout time.Duration
Cause error
}
ShutdownCleanupTimeoutError reports a finite session-owned teardown deadline. Cause remains inspectable with errors.Is(err, context.DeadlineExceeded).
func (*ShutdownCleanupTimeoutError) Error ¶
func (e *ShutdownCleanupTimeoutError) Error() string
func (*ShutdownCleanupTimeoutError) Unwrap ¶
func (e *ShutdownCleanupTimeoutError) Unwrap() error
type SnapshotPolicy ¶
type SnapshotPolicy struct {
Trigger checkpointTrigger
Priority checkpointPriority
Timeout time.Duration
}
SnapshotPolicy is the internal composition form of rig.SnapshotPolicy. pkg/rig owns the public API and converts its validated values into this dependency-only shape.
type Topology ¶
type Topology struct {
Definitions []loop.Definition
Primers []identity.AgentName
ActivePrimer identity.AgentName
}
Topology is the immutable set of loop definitions and roots captured by a Lifecycle. Callers must pass already-validated, uniquely named definitions.
type TurnRejectedError ¶
type TurnRejectedError = sessionapi.TurnRejectedError
type WorkflowActivityOwnerMismatchError ¶
WorkflowActivityOwnerMismatchError reports a workflow activity addressed to a session other than the one that owns the resource. A session resource never gets a generic cross-session event publisher.
func (*WorkflowActivityOwnerMismatchError) Error ¶
func (e *WorkflowActivityOwnerMismatchError) Error() string
type WorkspaceLifetimeAccessError ¶
type WorkspaceLifetimeAccessError struct {
Kind tool.WorkspaceAccessKind
Reason string
}
WorkspaceLifetimeAccessError reports an invalid authoritative access summary. Invalid and non-canonical scope sets fail secure without enqueuing a waiter.
func (*WorkspaceLifetimeAccessError) Error ¶
func (e *WorkspaceLifetimeAccessError) Error() string
type WorkspaceNotConfiguredError ¶
type WorkspaceNotConfiguredError = sessionapi.WorkspaceNotConfiguredError
type WorkspacePathError ¶
type WorkspacePathError struct {
Operation tool.WorkspaceOperation
Reason string
}
WorkspacePathError reports an Acquire whose canonicalPath does not match its operation (a path mutation with an empty path, or a whole-workspace operation with a non-empty path).
func (*WorkspacePathError) Error ¶
func (e *WorkspacePathError) Error() string
type WorkspacePlacement ¶
type WorkspacePlacement struct {
Mode WorkspacePlacementMode
Store *workspacestore.Store
Root string
BaseDir string
Leaser storage.Leaser
LeaseName string
}
WorkspacePlacement is the resolved-at-Define descriptor the Lifecycle carries to bring up a session's managed workspace. rig builds it from its placement options and validates the persistence-overlap invariant before constructing the Lifecycle. Store is the blob store checkpoints/restores go through; Root is the canonical fixed root (exclusive and shared); BaseDir is the canonical per-session base (session mode); Leaser + LeaseName are the exclusive root lease (exclusive mode only).
func (WorkspacePlacement) Configured ¶
func (p WorkspacePlacement) Configured() bool
Configured reports whether the placement provisions a managed workspace.
type WorkspacePlacementMode ¶
type WorkspacePlacementMode uint8
WorkspacePlacementMode selects how a session's managed workspace root is provisioned.
const ( // PlacementNone is the zero value: no managed workspace. PlacementNone WorkspacePlacementMode = iota // PlacementExclusive fences one canonical fixed root with an exclusive root lease. PlacementExclusive // PlacementSession derives an isolated baseDir/<sessionID> root per session. PlacementSession PlacementShared )
type WorkspaceRecoveryError ¶
type WorkspaceRecoveryError = sessionapi.WorkspaceRecoveryError
type WorkspaceRestoreError ¶
type WorkspaceRestoreError struct {
Kind WorkspaceRestoreErrorKind
Cause error
}
WorkspaceRestoreError is the typed failure of a workspace rewind. Kind classifies the stage; Cause chains the underlying error (a *workspacestore error, a filesystem error, or the coordinator's typed acquisition/health error).
func (*WorkspaceRestoreError) Error ¶
func (e *WorkspaceRestoreError) Error() string
func (*WorkspaceRestoreError) Unwrap ¶
func (e *WorkspaceRestoreError) Unwrap() error
type WorkspaceRestoreErrorKind ¶
type WorkspaceRestoreErrorKind string
WorkspaceRestoreErrorKind classifies a RestoreWorkspace failure.
const ( WorkspaceRestoreContextDone WorkspaceRestoreErrorKind = "context_done" WorkspaceRestoreFaulted WorkspaceRestoreErrorKind = "faulted" WorkspaceRestoreClosing WorkspaceRestoreErrorKind = "closing" WorkspaceRestorePermitFailed WorkspaceRestoreErrorKind = "permit_failed" WorkspaceRestoreLeaseUnhealthy WorkspaceRestoreErrorKind = "lease_unhealthy" WorkspaceRestoreSymlinkRoot WorkspaceRestoreErrorKind = "symlink_root" WorkspaceRestoreSymlinkComponent WorkspaceRestoreErrorKind = "symlink_component" WorkspaceRestoreEscape WorkspaceRestoreErrorKind = "path_escape" WorkspaceRestoreSwapFailed WorkspaceRestoreErrorKind = "swap_failed" WorkspaceRestoreRollbackFailed WorkspaceRestoreErrorKind = "rollback_failed" WorkspaceRestoreAppendFailed WorkspaceRestoreErrorKind = "append_failed" )
type WorkspaceRootBusyError ¶
type WorkspaceRootBusyError = sessionapi.WorkspaceRootBusyError
type WorkspaceRootLeaseLostError ¶
type WorkspaceRootLeaseLostError = sessionapi.WorkspaceRootLeaseLostError
type WorkspaceSeedError ¶
WorkspaceSeedError reports an invalid or failed workspace seed: a shared placement, a non-empty root, or a materialize failure (a ref that does not resolve). It is a fail-closed NewSession failure — the session never comes up on a bad seed.
func (*WorkspaceSeedError) Error ¶
func (e *WorkspaceSeedError) Error() string
func (*WorkspaceSeedError) Unwrap ¶
func (e *WorkspaceSeedError) Unwrap() error
Source Files
¶
- checkpoint.go
- checkpoint_admission.go
- checkpoint_controller.go
- collab_broker.go
- collab_broker_linux.go
- collab_broker_unix.go
- command_journal.go
- command_priority.go
- compaction_adapter.go
- delegation.go
- doc.go
- drain.go
- errors.go
- foreign_delivery_coordinator.go
- foreign_delivery_hook.go
- gates.go
- hooks.go
- hustle.go
- hustle_activity.go
- interrupt.go
- lifecycle.go
- limits.go
- loop_change.go
- loop_tools.go
- offload_gc.go
- process_lifecycle.go
- process_services.go
- restore.go
- restore_constructor.go
- restore_gates.go
- review_adapter.go
- review_state.go
- session.go
- session_resource_storage_other.go
- session_resource_storage_security.go
- session_resources.go
- shutdown_cleanup.go
- topology.go
- workflow_activity.go
- workspace_coordinator.go
- workspace_placement.go
- workspace_restore.go