Documentation
¶
Index ¶
- Variables
- func LockLoopRequeue(loopID string) func()
- func LockLoopTarget(key string) func()
- func LoopTargetGuardKey(projectID, loopType, targetType, targetKey string) string
- func LoopTargetGuardKeyFromRecord(loop storage.LoopRecord) string
- func Start(ctx context.Context, deps bootstrap.RuntimeDependencies) (bootstrap.Runtime, error)
- type ActiveExecutionRegistry
- func (r *ActiveExecutionRegistry) AdmitOperation(ctx context.Context, meta OperationMeta) (OperationLease, error)
- func (r *ActiveExecutionRegistry) AdmitSpawn(ctx context.Context, meta agent.SpawnMeta) (agent.SpawnLease, error)
- func (r *ActiveExecutionRegistry) BeginLoopStop(loopID, reason string) (release func(), err error)
- func (r *ActiveExecutionRegistry) BeginShutdown(reason string) error
- func (r *ActiveExecutionRegistry) BoundOperationCount() int
- func (r *ActiveExecutionRegistry) ClearLoopStop(loopID string) (wasActive bool)
- func (r *ActiveExecutionRegistry) HasLiveHandle(loopID, runID, executionID string) bool
- func (r *ActiveExecutionRegistry) Kill(loopID, runID, executionID, reason string) (bool, error)
- func (r *ActiveExecutionRegistry) LiveCount() int
- func (r *ActiveExecutionRegistry) LoopStopActive(loopID string) bool
- func (r *ActiveExecutionRegistry) NonAgentDrainErr() error
- func (r *ActiveExecutionRegistry) OwnsQueueClaim(queueItemID string) bool
- func (r *ActiveExecutionRegistry) PendingCount() int
- func (r *ActiveExecutionRegistry) PendingOperationCount() int
- func (r *ActiveExecutionRegistry) Register(loopID, runID, executionID string, execution activeExecution) func()
- func (r *ActiveExecutionRegistry) ReportDrainFailure(err error)
- func (r *ActiveExecutionRegistry) ReportHardPersistFailure(err error)
- func (r *ActiveExecutionRegistry) RestoreLoopStop(loopID string) error
- func (r *ActiveExecutionRegistry) SetAllowSpawn(fn func() error)
- func (r *ActiveExecutionRegistry) SetOnHardPersistFailure(fn func(error))
- func (r *ActiveExecutionRegistry) Track(handle *processcontainment.Handle) (release func())
- type Admission
- func (a *Admission) AllowClaim() error
- func (a *Admission) AllowMutations() error
- func (a *Admission) AllowsReads() bool
- func (a *Admission) BeginShutdown(reason string) error
- func (a *Admission) BeginShutdownThen(reason string, then func()) error
- func (a *Admission) IsReady() bool
- func (a *Admission) MarkDegraded(reason string) error
- func (a *Admission) MarkReady(reason string) error
- func (a *Admission) Reason() string
- func (a *Admission) State() AdmissionState
- func (a *Admission) Transition(to AdmissionState, reason string) error
- func (a *Admission) TransitionThen(to AdmissionState, reason string, then func()) error
- func (a *Admission) WithAllowWork(fn func()) error
- type AdmissionState
- type ConfigPatch
- type ConfigPatchError
- type ConfigReloadError
- type ConfigReloadStatus
- type ContainmentClass
- type ContainmentClassification
- type OpenSQLiteCoordinatorFunc
- type OperationLease
- type OperationMeta
- type OperationPermit
- type Options
- type ReadProcessCommandFunc
- type RecoveryOrphanAgentCleanup
- type RecoverySummary
- type RunSchedulerTickFunc
- type Runtime
- func (r *Runtime) AdmissionState() AdmissionState
- func (r *Runtime) AllowClaim() error
- func (r *Runtime) AllowMutations() error
- func (r *Runtime) BeginShutdown(reason string)
- func (r *Runtime) CompleteStartup(ctx context.Context) error
- func (r *Runtime) Config() config.Config
- func (r *Runtime) ConfigReloadStatus() ConfigReloadStatus
- func (r *Runtime) ConfigSnapshot() (config.Config, ConfigReloadStatus)
- func (r *Runtime) ExecutionMatchesProcess(ctx context.Context, execution storage.AgentExecutionRecord, pid int) (matches bool, running bool, err error)
- func (r *Runtime) MarkDegraded(reason string) error
- func (r *Runtime) NetworkStatus() networkclient.Status
- func (r *Runtime) PatchConfig(ctx context.Context, patch ConfigPatch) error
- func (r *Runtime) ReconcileStaleRunningRuns(ctx context.Context) (StaleRunReconcileSummary, error)
- func (r *Runtime) ReconcileWebhookForwarders()
- func (r *Runtime) RecordWebhookDelivery(eventType, deliveryID string)
- func (r *Runtime) RecoverySummary() RecoverySummary
- func (r *Runtime) RefreshWebhookForwarders() error
- func (r *Runtime) ReloadConfig(ctx context.Context) error
- func (r *Runtime) Services() Services
- func (r *Runtime) ShutdownDrainError() error
- func (r *Runtime) Start(ctx context.Context) error
- func (r *Runtime) StartedAt() (time.Time, bool)
- func (r *Runtime) Stop(reason string)
- func (r *Runtime) StorageRetained() bool
- func (r *Runtime) TriggerSchedulerClaim()
- func (r *Runtime) TriggerSchedulerTick()
- func (r *Runtime) WaitForDeferredReviewerRecovery(ctx context.Context) error
- func (r *Runtime) WaitForShutdown()
- func (r *Runtime) WebhookForwarder() WebhookForwarder
- func (r *Runtime) WebhookStatus() WebhookStatus
- func (r *Runtime) WithAllowClaim(fn func()) error
- func (r *Runtime) WorktreeCleanupStatus() WorktreeCleanupStatus
- type Services
- type SignalProcessFunc
- type StaleRunReconcileSummary
- type SyncConfiguredProjectsFunc
- type WebhookCounters
- type WebhookForwarder
- type WebhookForwarderState
- type WebhookForwarderStatus
- type WebhookQueueStatus
- type WebhookRecentOutcome
- type WebhookRuntimeStatus
- type WebhookStatus
- type WebhookTunnelState
- type WorktreeCleanupStatus
Constants ¶
This section is empty.
Variables ¶
var ( ErrAdmissionNotReady = errors.New("daemon admission is not ready") ErrAdmissionStopping = errors.New("daemon admission is stopping") ErrAdmissionDegraded = errors.New("daemon admission is degraded") ErrAdmissionIllegalMove = errors.New("illegal admission state transition") )
ErrAdmissionNotReady is returned when a mutation or queue claim is refused because admission is not ready.
var ErrAgentLiveHandleMissing = errors.New("agent live containment handle is missing")
ErrAgentLiveHandleMissing is returned by stop paths when an in-scope agent execution has no live Supervisor handle. After #576 full agent coverage, live stop/kill must not reconstruct ownership from SQLite PID.
var ErrOperationAdmissionClosed = errors.New("queue operation admission is closed")
ErrOperationAdmissionClosed is returned when an operation lease is refused because Supervisor admission is closed (daemon shutdown / degraded).
var ErrOperationFinalizeFailed = errors.New("queue operation durable finalize failed")
ErrOperationFinalizeFailed is returned when durable complete/cancel/requeue of a claimed queue item fails. Ownership must be retained and admission degraded rather than treating release as success (ADR-0015 R6 / #579).
var ErrOperationLeaseCancelled = errors.New("queue operation lease cancelled before bind")
ErrOperationLeaseCancelled is returned by BindClaim when stop/shutdown (or another Supervisor cancel) closed the lease before the durable claim can be owned. Context cancel alone is insufficient — callers must treat this explicit error as "do not start the queue processor".
Functions ¶
func LockLoopRequeue ¶ added in v0.11.0
func LockLoopRequeue(loopID string) func()
LockLoopRequeue acquires the process-wide per-loop requeue mutex shared by API discard+retry and runtime requeue paths. See loops.LockLoopRequeue. Call order with LockLoopTarget: take the per-loop lock first, then the target lock.
func LockLoopTarget ¶ added in v0.11.0
func LockLoopTarget(key string) func()
LockLoopTarget acquires the process-wide same-target mutex. See loops.LockLoopTarget.
func LoopTargetGuardKey ¶ added in v0.11.0
LoopTargetGuardKey builds the process-wide target mutex key. See loops.LoopTargetGuardKey.
func LoopTargetGuardKeyFromRecord ¶ added in v0.11.0
func LoopTargetGuardKeyFromRecord(loop storage.LoopRecord) string
LoopTargetGuardKeyFromRecord derives LoopTargetGuardKey from a stored loop.
Types ¶
type ActiveExecutionRegistry ¶
type ActiveExecutionRegistry struct {
// contains filtered or unexported fields
}
ActiveExecutionRegistry is the in-process Supervisor registry for live agent executions and queue operation leases (ADR-0015 R3 / R6 / #576 / #579). It owns:
- spawn admission leases before cmd.Start
- containment handle binding after spawn
- stop/shutdown race linearization (kill+confirmed drain before Start success)
- Kill via bound handle for looper stop / haltLoop
- non-agent handle tracking for shutdown drain / retain-storage (#577)
- operation leases that span durable queue claims until durable finalize (#579)
Non-agent tracking is not a second agent lease registry: short shell/proxy jobs only register the live containment handle so BeginShutdown can wait or force-drain and surface failures for retain-storage.
func NewActiveExecutionRegistry ¶
func NewActiveExecutionRegistry() *ActiveExecutionRegistry
func (*ActiveExecutionRegistry) AdmitOperation ¶ added in v0.11.0
func (r *ActiveExecutionRegistry) AdmitOperation(ctx context.Context, meta OperationMeta) (OperationLease, error)
AdmitOperation acquires a Supervisor operation lease before durable ClaimNext* (ADR-0015 R6 / #579). Successful claim must BindClaim; miss/error releases immediately. Bound claims release only after durable finalize.
func (*ActiveExecutionRegistry) AdmitSpawn ¶ added in v0.11.0
func (r *ActiveExecutionRegistry) AdmitSpawn(ctx context.Context, meta agent.SpawnMeta) (agent.SpawnLease, error)
AdmitSpawn acquires a Supervisor spawn lease before cmd.Start (ADR-0015 / #576).
func (*ActiveExecutionRegistry) BeginLoopStop ¶ added in v0.11.0
func (r *ActiveExecutionRegistry) BeginLoopStop(loopID, reason string) (release func(), err error)
BeginLoopStop closes spawn admission for one loop, cancels both pending and bound (active) leases for that loop, and confirmed-drains every bound containment handle for the loop. Bound-lease cancel is required so native-resume fallback cannot re-spawn after the old handle is drained. Handle drain here covers the BindHandle→persistStatus window where the registry owns a live process but haltLoop may not yet see a durable AgentExecutionRecord to Kill by ID.
Successfully drained keys are recorded in stopDrained so a subsequent haltLoop Kill-by-id still returns killed=true when releaseLease removes the registry entry while handle.Kill is waiting (process exit → run finish).
Drain failures from processcontainment.Handle.Kill and pending spawn/rebind wait timeouts are returned so stop/close cannot report success when a just-started agent is only unconfirmed or still live. The release func is still returned on drain failure: the gate was opened and callers manage sticky vs temporary windows as before.
After a durable stop (pause/terminate), callers must keep the gate closed: do not invoke the returned release. In-flight runners that claimed work before stop may still reach AgentExecutor.Start after halt returns; reopening would let AdmitSpawn succeed and start a process after looper stop. Clear the gate only via ClearLoopStop when the loop is intentionally re-activated (API unpause/retry/handback). Do not clear from scheduler claim dispatch: a pre-stop claim can race past parked checks and would reopen admission.
For terminal close abort paths (before durable terminate), callers should invoke the returned release so a still-running loop can AdmitSpawn again.
Pending spawn windows (AdmitSpawn through BindHandle/Release) and native rebind windows are waited with the same handshake before stop returns, so a just-started process cannot outlive the stop response without confirmed drain.
The returned release is also used in tests and temporary windows.
func (*ActiveExecutionRegistry) BeginShutdown ¶ added in v0.11.0
func (r *ActiveExecutionRegistry) BeginShutdown(reason string) error
BeginShutdown closes spawn admission, cancels pending and bound (active) leases, and confirmed-drains every bound containment handle.
Also waits for Supervisor-owned non-agent handles (shell/trusted-review) to release after cancel, force-kills stragglers, and joins ReportDrainFailure results so retain-storage covers non-agent containment failures (#577).
Cancels pending queue operation leases so BindClaim cannot start processors after shutdown, and waits for bound operation leases to Release after durable finalize (ADR-0015 R6 / #579). Does not force-release operation leases on timeout — that would create unowned durable running claims.
Returns a non-nil error when any handle Kill fails or a spawn/rebind wait times out. ADR-0015 / #577: drain failure must not be reported as graceful success; Runtime.Stop retains SQLite when this returns an error.
func (*ActiveExecutionRegistry) BoundOperationCount ¶ added in v0.11.0
func (r *ActiveExecutionRegistry) BoundOperationCount() int
BoundOperationCount returns the number of bound (post-claim) operation leases.
func (*ActiveExecutionRegistry) ClearLoopStop ¶ added in v0.11.0
func (r *ActiveExecutionRegistry) ClearLoopStop(loopID string) (wasActive bool)
ClearLoopStop reopens spawn admission for a loop after intentional re-activation (API unpause, retry, or handback). Not for scheduler claim dispatch.
Returns whether a stop gate was active under the same lock that clears it. Callers that restore on abort must use this return value instead of a separate LoopStopActive check: a concurrent BeginLoopStop between those two calls would leave gateWasActive=false while this delete still removes the new gate, and a failed start/retry/reuse TX would skip RestoreLoopStop.
Outstanding BeginLoopStop release closures captured before this clear are invalidated via stopEpoch: deleting the refcount alone is not enough, because a temporary release (stopCandidateExecution) can still run after a failed reactivation's RestoreLoopStop and would otherwise drop the restored sticky gate when it sees count <= 1.
func (*ActiveExecutionRegistry) HasLiveHandle ¶ added in v0.11.0
func (r *ActiveExecutionRegistry) HasLiveHandle(loopID, runID, executionID string) bool
HasLiveHandle reports whether the registry holds a live entry for the key. Used by stop paths and contract tests.
func (*ActiveExecutionRegistry) Kill ¶
func (r *ActiveExecutionRegistry) Kill(loopID, runID, executionID, reason string) (bool, error)
Kill stops a live owned agent by containment handle (confirmed drain) when bound, otherwise via softKill. Returns (false, nil) when no live ownership entry exists — callers must not fall back to SQLite PID after #576.
When BeginLoopStop already confirmed-drained this key and releaseLease removed the entry during handle.Kill, returns (true, nil) so haltLoop does not treat the missing entry as ErrAgentLiveHandleMissing for a process stop just killed.
func (*ActiveExecutionRegistry) LiveCount ¶ added in v0.11.0
func (r *ActiveExecutionRegistry) LiveCount() int
LiveCount returns the number of bound/registered live agent executions.
func (*ActiveExecutionRegistry) LoopStopActive ¶ added in v0.11.0
func (r *ActiveExecutionRegistry) LoopStopActive(loopID string) bool
LoopStopActive reports whether spawn admission is closed for loopID.
func (*ActiveExecutionRegistry) NonAgentDrainErr ¶ added in v0.11.0
func (r *ActiveExecutionRegistry) NonAgentDrainErr() error
NonAgentDrainErr returns accumulated non-agent containment drain failures. Runtime.Stop re-reads this after producer waits so late shell/proxy reports still retain storage.
func (*ActiveExecutionRegistry) OwnsQueueClaim ¶ added in v0.11.0
func (r *ActiveExecutionRegistry) OwnsQueueClaim(queueItemID string) bool
OwnsQueueClaim reports whether a durable queue item id is currently owned by a live operation lease (bound, not released).
func (*ActiveExecutionRegistry) PendingCount ¶ added in v0.11.0
func (r *ActiveExecutionRegistry) PendingCount() int
PendingCount returns the number of pre-Start spawn leases.
func (*ActiveExecutionRegistry) PendingOperationCount ¶ added in v0.11.0
func (r *ActiveExecutionRegistry) PendingOperationCount() int
PendingOperationCount returns the number of pre-claim/pre-bind operation leases.
func (*ActiveExecutionRegistry) Register ¶
func (r *ActiveExecutionRegistry) Register(loopID, runID, executionID string, execution activeExecution) func()
Register is retained for tests and transitional paths that hold an activeExecution without a containment handle. Production agent spawns must use AdmitSpawn + BindHandle at the common executor boundary (#576). A contract test fails if only the worker role registers post-spawn.
func (*ActiveExecutionRegistry) ReportDrainFailure ¶ added in v0.11.0
func (r *ActiveExecutionRegistry) ReportDrainFailure(err error)
ReportDrainFailure implements processcontainment.LiveTracker. Callers report Kill/Drain failures from their ownership path so late cancel drains still feed retain-storage even when BeginShutdown already returned.
func (*ActiveExecutionRegistry) ReportHardPersistFailure ¶ added in v0.11.0
func (r *ActiveExecutionRegistry) ReportHardPersistFailure(err error)
ReportHardPersistFailure surfaces a hard agent_executions write failure into daemon admission. Safe to call from agent executor mid-life paths.
func (*ActiveExecutionRegistry) RestoreLoopStop ¶ added in v0.11.0
func (r *ActiveExecutionRegistry) RestoreLoopStop(loopID string) error
RestoreLoopStop re-closes spawn admission after a failed intentional reactivation that already called ClearLoopStop. Cancels pending/active leases and confirmed-drains bound handles admitted during the clear window so a failed retry/start/worker-reuse cannot leave a live agent for a loop that was never reactivated.
Always increments the stop-gate refcount (sticky restore reference) even when a temporary BeginLoopStop is already active for the same loop. Leaving the count unchanged would let that temporary release reopen AdmitSpawn after the failed reactivation; restore must outlive unrelated releases.
Returns cancelAndDrainLoop's error when kill or confirmed-drain fails so callers can join it with the original validation/TX failure; the gate is still closed even when drain fails.
func (*ActiveExecutionRegistry) SetAllowSpawn ¶ added in v0.11.0
func (r *ActiveExecutionRegistry) SetAllowSpawn(fn func() error)
SetAllowSpawn wires the daemon Admission projection for spawn decisions.
func (*ActiveExecutionRegistry) SetOnHardPersistFailure ¶ added in v0.11.0
func (r *ActiveExecutionRegistry) SetOnHardPersistFailure(fn func(error))
SetOnHardPersistFailure wires sticky admission degrade for hard execution observation write failures (initial/heartbeat/output/terminal). Soft cancel and conflict after terminal won must not invoke this callback.
func (*ActiveExecutionRegistry) Track ¶ added in v0.11.0
func (r *ActiveExecutionRegistry) Track(handle *processcontainment.Handle) (release func())
Track implements processcontainment.LiveTracker for Supervisor-owned non-agent handles (validation/shell, trusted review). release is idempotent.
type Admission ¶ added in v0.11.0
type Admission struct {
// contains filtered or unexported fields
}
Admission is the single Authority for live daemon admission. All gates must call AllowMutations / AllowClaim under the same mutex as state reads so there is no check-then-act dual flag that can disagree. Deletion attempt: remove separate ownershipAcquired readiness and trust only agent/process signals — insufficient for multi-PR rollout because recovery and ingress need a process-lifetime closed gate before Supervisor ownership.
func NewAdmission ¶ added in v0.11.0
func NewAdmission() *Admission
NewAdmission starts in starting; recovery/CompleteStartup must move it to ready.
func (*Admission) AllowClaim ¶ added in v0.11.0
AllowClaim is the atomic gate for work-producing scheduler activity (full tick and each durable ClaimNext*). Same Authority as AllowMutations — a projection, not a second decision.
func (*Admission) AllowMutations ¶ added in v0.11.0
AllowMutations is the atomic gate for HTTP mutating ingress. Callers must treat a nil error as admission to mutate; there is no separate ready flag.
func (*Admission) AllowsReads ¶ added in v0.11.0
AllowsReads reports whether read-only HTTP may proceed. Reads remain available in starting, ready, stopping, and degraded.
func (*Admission) BeginShutdown ¶ added in v0.11.0
BeginShutdown is ready|starting|degraded → stopping. Idempotent when already stopping.
func (*Admission) BeginShutdownThen ¶ added in v0.11.0
BeginShutdownThen is BeginShutdown plus a then callback still holding a.mu after the stopping transition (or when already stopping).
func (*Admission) IsReady ¶ added in v0.11.0
IsReady is a projection helper for status surfaces. Prefer AllowMutations / AllowClaim for gates so state and decision cannot diverge.
func (*Admission) MarkDegraded ¶ added in v0.11.0
MarkDegraded is sticky until process restart (degraded → ready is illegal). Recovery is restart looperd; Runtime.MarkDegraded also cancels work producers.
func (*Admission) MarkReady ¶ added in v0.11.0
MarkReady is starting → ready after CompleteStartup recovery finishes.
func (*Admission) Reason ¶ added in v0.11.0
Reason returns the last transition reason (empty when unset).
func (*Admission) State ¶ added in v0.11.0
func (a *Admission) State() AdmissionState
State returns the current admission state.
func (*Admission) Transition ¶ added in v0.11.0
func (a *Admission) Transition(to AdmissionState, reason string) error
Transition applies a legal state change. Illegal moves return ErrAdmissionIllegalMove without changing state.
func (*Admission) TransitionThen ¶ added in v0.11.0
func (a *Admission) TransitionThen(to AdmissionState, reason string, then func()) error
TransitionThen applies a legal state change and runs then while still holding a.mu. Runtime.MarkDegraded / BeginShutdown use this so cancelWorkProducers runs in the same critical section as the closed transition — there is no window where admission is already closed but producer cancel has not run yet (worktree cleanup could otherwise start git worktree remove after close). then must not call back into Admission methods that take a.mu (would deadlock).
func (*Admission) WithAllowWork ¶ added in v0.11.0
WithAllowWork runs fn only when admission currently allows work, holding the same mutex as AllowMutations/AllowClaim for the full duration of fn. Use this for check-then-act sections (e.g. webhook accept + enqueue) so MarkDegraded and BeginShutdown cannot interleave between the gate and the mutation. fn must not call back into Admission methods that take a.mu (would deadlock).
type AdmissionState ¶ added in v0.11.0
type AdmissionState string
AdmissionState is the single authoritative live-daemon admission state (ADR-0015 R1 / issue #575). HTTP mutation readiness and scheduler work (full tick: discovery/HITL/claims/stale-reconcile) are projections of this state — not a second ready flag.
Trade-off (AGENTS.md new-concept gate):
Failure prevented: mid-rollout dual ready flags (ownershipAcquired vs HTTP/ scheduler gates) that disagree, admitting mutations or enqueueing work while recovery is incomplete or shutdown has begun; recovery inventing cleanliness from reusable PIDs without a single closed admission Authority.
Costs / new edge cases: sticky degraded until process restart; startup window where reads work but all mutations and work-producing ticks no-op; shutdown must BeginShutdown before storage close; every new work-producing path must call AllowMutations/AllowClaim (audited under #580); more manual_intervention quarantine instead of aggressive auto-clean.
Why simpler alternatives are insufficient: a boolean ready flag next to ownershipAcquired re-creates dual Authority; gating only ClaimNext* leaves discovery/HITL/reconcile free to mutate queue storage while admission is closed; trusting SQLite or PID probes as live Authority lags and is not atomic with admission decisions.
Legal transitions (monotonic / legal only):
starting → ready | stopping | degraded ready → stopping | degraded degraded → stopping (sticky until process restart; no ready) stopping → (none) (terminal for this process lifetime)
any → degraded is sticky until process restart. There is no ClearDegraded: Runtime.MarkDegraded cancels producer contexts (scheduler, cleanup, webhook execute), so reopening admission without restart would leave a ready-looking daemon with permanently dead work producers.
const ( AdmissionStarting AdmissionState = "starting" AdmissionReady AdmissionState = "ready" AdmissionStopping AdmissionState = "stopping" AdmissionDegraded AdmissionState = "degraded" )
type ConfigPatch ¶ added in v0.11.0
type ConfigPatch struct {
Revision string
Set map[string]json.RawMessage
Unset []string
}
type ConfigPatchError ¶ added in v0.11.0
func (*ConfigPatchError) Error ¶ added in v0.11.0
func (e *ConfigPatchError) Error() string
func (*ConfigPatchError) Unwrap ¶ added in v0.11.0
func (e *ConfigPatchError) Unwrap() error
type ConfigReloadError ¶ added in v0.11.0
ConfigReloadError reports a rejected candidate without replacing the last-known-good runtime snapshot.
func (*ConfigReloadError) Error ¶ added in v0.11.0
func (e *ConfigReloadError) Error() string
func (*ConfigReloadError) Unwrap ¶ added in v0.11.0
func (e *ConfigReloadError) Unwrap() error
type ConfigReloadStatus ¶ added in v0.11.0
type ConfigReloadStatus struct {
ConfigPath string
Format string
FilePresent bool
Revision string
LastAttemptAt *time.Time
LastAppliedAt *time.Time
LastError string
RejectedPaths []string
FieldSources map[string]config.ValueSource
}
ConfigReloadStatus is transient diagnostic state. The config file overlaid by the daemon's startup environment and CLI flags remains the authority for global policy; this status only explains whether that authority was applied.
type ContainmentClass ¶ added in v0.11.0
type ContainmentClass string
ContainmentClass is the startup-recovery classification of durable execution evidence after a daemon restart (ADR-0015 R8 / #581).
PID/PGID inspection is drift evidence only. It never authorizes live stop, terminal marking, requeue, or overlapping work, and never alone establishes confirmed-dead after restart.
const ( // ContainmentConfirmedDead means Authority exists to treat the execution as // non-runnable for recovery purposes. // // After restart, only: // - durable terminal finalization already committed before crash, or // - a current-daemon owned processcontainment.Handle that has completed // confirmed drain // may authorize this class. // // Must not authorize confirmed-dead: PID/PGID missing or not running, // probe-then-signal on raw PID/PGID, or leader exit alone without // descendant/containment proof. ContainmentConfirmedDead ContainmentClass = "confirmed_dead" // ContainmentObservedLive means a process probe matched the durable row. // This is evidence only — not adopted live ownership. Recovery must not // signal, terminalize, requeue, or start overlapping work from this class. ContainmentObservedLive ContainmentClass = "observed_live" // ContainmentUncertain covers every other observation (PID absent, command // mismatch, probe error, leader-exit-only without containment proof, etc.). // Uncertain work stays quarantined without raw PID/PGID action. ContainmentUncertain ContainmentClass = "uncertain" )
type ContainmentClassification ¶ added in v0.11.0
type ContainmentClassification struct {
Class ContainmentClass
// Reason is a stable machine-oriented explanation (event payloads / tests).
Reason string
// PID is the durable PID when present (evidence only).
PID int
}
ContainmentClassification is one classified durable observation.
type OpenSQLiteCoordinatorFunc ¶
type OpenSQLiteCoordinatorFunc func(context.Context, string, storage.SQLiteCoordinatorOptions) (*storage.SQLiteCoordinator, error)
type OperationLease ¶ added in v0.11.0
type OperationLease interface {
// Context is cancelled when stop/shutdown races the in-flight claim or run.
// Cancellation alone must not be treated as a bind permit failure — use
// BindClaim's explicit error.
Context() context.Context
// BindClaim binds a successful durable claim to this lease. Returns an
// explicit OperationPermit only when the lease is still owned and live.
// On ErrOperationLeaseCancelled the processor must never start; the claim
// remains owned until durable finalize then Release.
BindClaim(item storage.QueueItemRecord) (OperationPermit, error)
// Release drops the lease. Call immediately on claim miss/error. After a
// successful claim, call only once complete/cancel/requeue is durably
// committed. Never call after a finalize persistence failure.
Release()
// Owns reports whether this lease currently owns queueItemID (bound, not released).
Owns(queueItemID string) bool
}
OperationLease is the Supervisor ownership token for one durable queue claim from before ClaimNext* until durable complete / cancel / requeue (ADR-0015 R6).
type OperationMeta ¶ added in v0.11.0
type OperationMeta struct {
// ClaimedBy is the durable claimed_by value (e.g. "scheduler").
ClaimedBy string
}
OperationMeta identifies one queue claim operation admitted before durable ClaimNext*. Loop/item identity is filled at BindClaim after a successful claim.
type OperationPermit ¶ added in v0.11.0
type OperationPermit struct {
// contains filtered or unexported fields
}
OperationPermit is the explicit token proving BindClaim succeeded. The queue processor / agent spawn path must not start without a non-zero permit.
func (OperationPermit) QueueItemID ¶ added in v0.11.0
func (p OperationPermit) QueueItemID() string
QueueItemID returns the durable queue item bound to this permit.
func (OperationPermit) Valid ¶ added in v0.11.0
func (p OperationPermit) Valid() bool
Valid reports whether this permit authorizes starting the queue processor.
type Options ¶
type Options struct {
Config config.Config
// InitialConfig and ReloadConfig are supplied by bootstrap so hot reloads
// replay the daemon's exact startup precedence (file, environment, and CLI).
// Tests and embedders that omit ReloadConfig simply run without a watcher.
InitialConfig config.LoadedFileConfig
ReloadConfig func() (config.LoadedFileConfig, error)
LoadConfigAt func(string) (config.LoadedFileConfig, error)
ConfigReloadInterval time.Duration
// ConfigPath is the daemon-loaded config file path (from --config /
// LOOPER_CONFIG resolution). Runtime config management patches this source;
// trusted review-submit children receive a separate sanitized run snapshot.
ConfigPath string
Logger bootstrap.Logger
Now func() time.Time
ShutdownTimeout time.Duration
WorktreeCleanupInitialDelay time.Duration
OpenSQLiteCoordinator OpenSQLiteCoordinatorFunc
SyncConfiguredProjects SyncConfiguredProjectsFunc
RunSchedulerTick RunSchedulerTickFunc
ReadProcessCommand ReadProcessCommandFunc
SignalProcess SignalProcessFunc
DeferRecovery bool
}
type ReadProcessCommandFunc ¶
type RecoveryOrphanAgentCleanup ¶
type RecoveryOrphanAgentCleanup struct {
Attempted bool `json:"attempted"`
CleanedCount int64 `json:"cleanedCount"`
QuarantinedCount int64 `json:"quarantinedCount"`
// Classification counts for active execution evidence (ADR-0015 R8 / #581).
// ConfirmedDead requires durable terminal finalization or current-daemon drain;
// PID absence never increments ConfirmedDead.
ConfirmedDeadCount int64 `json:"confirmedDeadCount"`
ObservedLiveCount int64 `json:"observedLiveCount"`
UncertainCount int64 `json:"uncertainCount"`
Warning string `json:"warning,omitempty"`
}
type RecoverySummary ¶
type RecoverySummary struct {
StartedAt string `json:"startedAt,omitempty"`
CompletedAt string `json:"completedAt,omitempty"`
OrphanAgentCleanup RecoveryOrphanAgentCleanup `json:"orphanAgentCleanup"`
ExpiredLocksReleased int64 `json:"expiredLocksReleased"`
InterruptedRunsMarked int64 `json:"interruptedRunsMarked"`
LoopsRequeued int64 `json:"loopsRequeued"`
EventsWritten int64 `json:"eventsWritten"`
}
type Runtime ¶
type Runtime struct {
// contains filtered or unexported fields
}
func (*Runtime) AdmissionState ¶ added in v0.11.0
func (r *Runtime) AdmissionState() AdmissionState
AdmissionState returns the authoritative live admission state.
func (*Runtime) AllowClaim ¶ added in v0.11.0
AllowClaim is the scheduler work-producing projection of admission (full tick + durable claims).
func (*Runtime) AllowMutations ¶ added in v0.11.0
AllowMutations is the HTTP mutation readiness projection of admission.
func (*Runtime) BeginShutdown ¶ added in v0.11.0
BeginShutdown transitions admission to stopping without closing storage. Daemon stop drains HTTP ingress after this so mutations/claims stop first. Also cancels the scheduler context so an in-flight full tick observes cancellation during the HTTP drain window before Runtime.Stop closes the loop; work-producing lanes still recheck AllowClaim as the Authority. Cancels deferred reviewer recovery so a post-ready recovery goroutine cannot still requeue loops/queue items after admission is already stopping; the wait for recovery exit remains in Runtime.Stop via stopDeferredReviewerRecovery. Cancels webhook-forward discovery so process exit can abort in-flight CreateOrGetActiveByDedupe promptly (sticky MarkDegraded does not cancel webhook execute — accepted/202 deliveries must still complete).
Shutdown order (ADR-0015 / #577): close admission → cancel producers → confirmed-drain handles (agents + tracked non-agent shell/trusted-review). Producer cancel must run before ActiveExecutionRegistry.BeginShutdown waits on tracked non-agent handles: validation shell.Run only enters Kill after its owner ctx is canceled. Waiting first would burn the full kill budget then force-kill instead of cancel/drain promptly. SQLite close happens only in Stop after drain succeeds; drain failure is recorded for retain-storage. Non-agent Kill/Drain failures that finish after this returns are re-collected in Stop via NonAgentDrainErr.
func (*Runtime) CompleteStartup ¶ added in v0.7.1
func (*Runtime) Config ¶
Config returns the current runtime configuration with Projects materialized from the authoritative Project Catalog.
func (*Runtime) ConfigReloadStatus ¶ added in v0.11.0
func (r *Runtime) ConfigReloadStatus() ConfigReloadStatus
func (*Runtime) ConfigSnapshot ¶ added in v0.11.0
func (r *Runtime) ConfigSnapshot() (config.Config, ConfigReloadStatus)
ConfigSnapshot returns effective values and reload metadata from one configReloadMu generation for API responses.
func (*Runtime) ExecutionMatchesProcess ¶
func (*Runtime) MarkDegraded ¶ added in v0.11.0
MarkDegraded sticks admission until process restart and cancels work-producing contexts (scheduler, recovery, cleanup) so new discovery/claims/cleanup that already passed AllowClaim cannot complete after the transition. Unlike BeginShutdown, this does not drain active agent handles and does not CancelExecute webhook workers: Forward may already have returned accepted/202 for in-memory queue entries, and sticky degrade leaves the daemon up with no GitHub retry. New webhook accepts are still refused via AllowExecute / AllowExecuteWhile. There is no clear-and-resume path: canceled producer contexts are not recreated; operators must restart looperd.
func (*Runtime) NetworkStatus ¶ added in v0.9.0
func (r *Runtime) NetworkStatus() networkclient.Status
func (*Runtime) PatchConfig ¶ added in v0.11.0
func (r *Runtime) PatchConfig(ctx context.Context, patch ConfigPatch) error
PatchConfig applies a targeted mutation to the file layer. It rereads the source under the mutation lock, validates a same-directory temporary file through the exact startup loader, performs a final identity/mode/byte check, then atomically renames it into place. See the final-check comment below for the narrow portable-filesystem race that remains.
func (*Runtime) ReconcileStaleRunningRuns ¶ added in v0.9.1
func (r *Runtime) ReconcileStaleRunningRuns(ctx context.Context) (StaleRunReconcileSummary, error)
func (*Runtime) ReconcileWebhookForwarders ¶ added in v0.8.0
func (r *Runtime) ReconcileWebhookForwarders()
func (*Runtime) RecordWebhookDelivery ¶ added in v0.8.0
func (*Runtime) RecoverySummary ¶
func (r *Runtime) RecoverySummary() RecoverySummary
func (*Runtime) RefreshWebhookForwarders ¶ added in v0.8.0
func (*Runtime) ReloadConfig ¶ added in v0.11.0
ReloadConfig reparses the configured source using the exact loader captured at bootstrap. A candidate is published atomically only when every changed field is hot-safe; invalid and restart-bound candidates leave running work and the last-known-good snapshot untouched.
func (*Runtime) ShutdownDrainError ¶ added in v0.11.0
ShutdownDrainError returns the drain failure recorded during BeginShutdown, if any.
func (*Runtime) StorageRetained ¶ added in v0.11.0
StorageRetained reports whether Stop skipped SQLite close after a drain failure (ADR-0015 / #577). Operators must not treat stop as graceful success.
func (*Runtime) TriggerSchedulerClaim ¶ added in v0.8.0
func (r *Runtime) TriggerSchedulerClaim()
func (*Runtime) TriggerSchedulerTick ¶
func (r *Runtime) TriggerSchedulerTick()
func (*Runtime) WaitForDeferredReviewerRecovery ¶ added in v0.11.0
WaitForDeferredReviewerRecovery blocks until the post-ready deferred reviewer recovery goroutine exits, or until ctx is canceled. It returns immediately when deferred recovery was never started (for example when no GitHub gateway is configured). Test fixtures call this after CompleteStartup so later inserts of terminal reviewer metadata cannot race normalizeTerminalReviewerLoopForRecovery.
func (*Runtime) WaitForShutdown ¶
func (r *Runtime) WaitForShutdown()
func (*Runtime) WebhookForwarder ¶ added in v0.8.0
func (r *Runtime) WebhookForwarder() WebhookForwarder
func (*Runtime) WebhookStatus ¶ added in v0.8.0
func (r *Runtime) WebhookStatus() WebhookStatus
func (*Runtime) WithAllowClaim ¶ added in v0.11.0
WithAllowClaim runs fn only while claim admission is open, holding the admission mutex for the full duration of fn so MarkDegraded/BeginShutdown cannot interleave with the critical section (webhook accept + enqueue).
func (*Runtime) WorktreeCleanupStatus ¶ added in v0.9.0
func (r *Runtime) WorktreeCleanupStatus() WorktreeCleanupStatus
type Services ¶
type Services struct {
Coordinator *storage.SQLiteCoordinator
Repositories *storage.Repositories
Projects *projects.Service
Loops *loops.Service
Runs *runs.Service
ActiveExecutions *ActiveExecutionRegistry
}
type StaleRunReconcileSummary ¶ added in v0.9.1
type StaleRunReconcileSummary struct {
Mode string `json:"mode"`
StartedAt string `json:"startedAt,omitempty"`
CompletedAt string `json:"completedAt,omitempty"`
CandidateRuns int64 `json:"candidateRuns"`
InterruptedRuns int64 `json:"interruptedRuns"`
LoopsRequeued int64 `json:"loopsRequeued"`
QueueItemsRequeued int64 `json:"queueItemsRequeued"`
QueueItemsCancelled int64 `json:"queueItemsCancelled"`
CleanedExecutions int64 `json:"cleanedExecutions"`
// QuarantinedExecutions counts executions parked via quarantineRecoveryEvidence
// (still-running evidence + manual_intervention). Never report these as cleaned.
QuarantinedExecutions int64 `json:"quarantinedExecutions"`
SkippedUncertainRuns int64 `json:"skippedUncertainRuns"`
EventsWritten int64 `json:"eventsWritten"`
RunIDs []string `json:"runIds,omitempty"`
LoopIDs []string `json:"loopIds,omitempty"`
ExecutionIDs []string `json:"executionIds,omitempty"`
}
type WebhookCounters ¶ added in v0.8.0
type WebhookForwarder ¶ added in v0.8.0
type WebhookForwarder interface {
Forward(context.Context, webhookforward.DeliveryRequest) (webhookforward.ForwardResult, error)
Stats() webhookforward.Stats
// CancelExecute aborts in-flight webhook discovery without waiting for drain.
// BeginShutdown and MarkDegraded call this so admission-closed races cannot
// still enqueue after a one-time AllowExecute pass.
CancelExecute()
Close()
}
type WebhookForwarderState ¶ added in v0.8.0
type WebhookForwarderState struct {
Repo string `json:"repo"`
Running bool `json:"running"`
PID *int `json:"pid,omitempty"`
Adopted bool `json:"adopted"`
Latched bool `json:"latched"`
LatchReason *string `json:"latchReason,omitempty"`
Fingerprint string `json:"fingerprint,omitempty"`
SpawnedAt *string `json:"spawnedAt,omitempty"`
Command []string `json:"command"`
RestartCount int `json:"restartCount"`
LastStartedAt *string `json:"lastStartedAt,omitempty"`
LastExitAt *string `json:"lastExitAt,omitempty"`
LastError string `json:"lastError,omitempty"`
StdoutTail []string `json:"stdoutTail,omitempty"`
StderrTail []string `json:"stderrTail,omitempty"`
}
type WebhookForwarderStatus ¶ added in v0.8.0
type WebhookForwarderStatus struct {
Repo string `json:"repo"`
Events []string `json:"events"`
Command []string `json:"command"`
Running bool `json:"running"`
RespawnCount int `json:"respawnCount"`
LastStartAt *string `json:"lastStartAt,omitempty"`
LastExitAt *string `json:"lastExitAt,omitempty"`
LastError *string `json:"lastError,omitempty"`
Tail []string `json:"tail"`
}
type WebhookQueueStatus ¶ added in v0.8.0
type WebhookRecentOutcome ¶ added in v0.8.0
type WebhookRuntimeStatus ¶ added in v0.8.0
type WebhookStatus ¶ added in v0.8.0
type WebhookStatus struct {
Enabled bool `json:"enabled"`
Mode config.WebhookMode `json:"mode"`
ConfiguredTunnelProjectIDs []string `json:"configuredTunnelProjectIds,omitempty"`
FallbackPollIntervalSeconds int `json:"fallbackPollIntervalSeconds"`
ListenerPath string `json:"listenerPath"`
EndpointURL string `json:"endpointUrl"`
TunnelListenerURL string `json:"tunnelListenerUrl,omitempty"`
TunnelPublicBaseURL string `json:"tunnelPublicBaseUrl,omitempty"`
Degraded bool `json:"degraded"`
DegradedReasons []string `json:"degradedReasons"`
Queue WebhookQueueStatus `json:"queue"`
Counters WebhookCounters `json:"counters"`
RecentOutcomes []WebhookRecentOutcome `json:"recentOutcomes"`
Forwarders []WebhookForwarderState `json:"forwarders"`
TunnelHooks []WebhookTunnelState `json:"tunnelHooks"`
}
type WebhookTunnelState ¶ added in v0.8.1
type WebhookTunnelState struct {
Repo string `json:"repo"`
HookID *int64 `json:"hookId,omitempty"`
ManagedURL string `json:"managedUrl,omitempty"`
LastPingAt *string `json:"lastPingAt,omitempty"`
ConsecutiveDisables int64 `json:"consecutiveDisables"`
Latched bool `json:"latched"`
Orphaned bool `json:"orphaned"`
LastError string `json:"lastError,omitempty"`
}
type WorktreeCleanupStatus ¶ added in v0.9.0
type WorktreeCleanupStatus struct {
Enabled bool `json:"enabled"`
DryRun bool `json:"dryRun"`
LastStartedAt *string `json:"lastStartedAt,omitempty"`
LastCompletedAt *string `json:"lastCompletedAt,omitempty"`
LastStatus string `json:"lastStatus"`
Scanned int `json:"scanned"`
Candidates int `json:"candidates"`
Cleaned int `json:"cleaned"`
Skipped int `json:"skipped"`
Failed int `json:"failed"`
LastError string `json:"lastError,omitempty"`
}