Documentation
¶
Index ¶
- Constants
- Variables
- func AppendACP(path string, event ACPEvent) error
- func AppendClaim(path string, event ACPEvent) error
- func AppendDispatch(path string, event ACPEvent) error
- func CheckpointPath(root, slug string) string
- func HasLiveLease(leases []Lease, now time.Time) bool
- func HasMission(events []ACPEvent, missionID string) bool
- func MissionID(sessionID string, step int, taskID string) string
- func NextAttempt(events []ACPEvent, taskID string) int
- func SaveCheckpoint(root, path string, cp Checkpoint) error
- func SaveSessionCAS(root, path string, expectedRevision int64, next Session) error
- type ACPEvent
- type Action
- type Authority
- type Checkpoint
- type Decision
- type DecisionLimits
- type Dispatcher
- type GateSeverity
- type Lease
- type Reclaim
- type ResumePlan
- type Session
- type SessionState
- type Snapshot
Constants ¶
const ( ACPKindDispatch = "dispatch" ACPKindClaim = "claim" ACPKindReport = "report" )
ACP event kinds. claim/report carry the worker-rigor fields (spec 10 R3); dispatch is the brain's own record.
Variables ¶
var ErrDuplicateMission = errors.New("duplicate mission id")
ErrDuplicateMission is returned when a dispatch with a mission id already in the ledger is appended again. It is the invariant that makes crash-recovery re-issue idempotent: the same deterministic mission id can appear at most once.
var ErrSessionRevisionConflict = errors.New("session revision conflict")
Functions ¶
func AppendACP ¶
AppendACP appends one event to the ledger. It is O(1): Seq is a read-time projection (ReadACP numbers events by position), so a write never re-reads the whole file — open, append, fsync. ponytail: the semantic appends (AppendClaim's attempt count, AppendDispatch's duplicate-mission guard) still scan the ledger, but that read is their actual job and the per-spec ledger is bounded by task count × attempts. Maintain an on-disk index only if a ledger ever grows past a few thousand events.
func AppendClaim ¶
AppendClaim appends a claim event, filling the attempt number from the current ledger when the caller left it zero. The read-then-append happens under the caller's spec lock so the derived attempt is race-free.
func AppendDispatch ¶
AppendDispatch appends a dispatch event, refusing a duplicate mission id (spec 07 R3). The read-then-append runs under the caller's spec lock so the duplicate check is race-free.
func CheckpointPath ¶
CheckpointPath is the per-spec write-ahead checkpoint file.
func HasLiveLease ¶
HasLiveLease reports whether any lease is still within its TTL at now. A live lease means another controller is actively holding work and blocks a second start/resume; only expired/orphaned leases are recoverable by resume (R5).
func HasMission ¶
HasMission reports whether the ledger already carries an event with missionID.
func MissionID ¶
MissionID is the deterministic identifier for a dispatch: session id + step + task. Determinism is the point — a dispatch re-issued after a crash on resume reuses the same mission id, so the ledger's duplicate guard makes re-issue idempotent (spec 07 R3).
func NextAttempt ¶
NextAttempt is the attempt number for a new claim on taskID: the count of prior claim events for that task plus one. It is a countable fact derived from the ledger under the spec lock, never a stored counter that can skew (spec 10 R3). It feeds spec 06's escalation counting.
func SaveCheckpoint ¶
func SaveCheckpoint(root, path string, cp Checkpoint) error
SaveCheckpoint writes the checkpoint durably (atomic write + fsync via core.AtomicWrite) under the spec lock. It must return before the caller makes the corresponding dispatch visible in the ledger (write-ahead ordering).
Types ¶
type ACPEvent ¶
type ACPEvent struct {
Seq int `json:"seq"`
Time time.Time `json:"time"`
Kind string `json:"kind"`
TaskID string `json:"task_id,omitempty"`
Payload string `json:"payload,omitempty"`
// MissionID is the deterministic dispatch identifier (session/step/task, spec
// 07 R3). Optional so bare dispatch events and pre-spec-07 ledgers stay valid.
// It is the key the resume path and the duplicate guard match on.
MissionID string `json:"mission_id,omitempty"`
// Worker-rigor fields (spec 10 R3), all optional so a bare dispatch event and
// pre-telemetry ledgers stay valid. Attempt is monotonic per task (see
// NextAttempt); GitHead pins the claim/report to a commit; ChangedFiles is the
// worker-reported diff surface; VerifyRef points at the verify evidence
// backing a report; Telemetry is verbatim worker cost.
Attempt int `json:"attempt,omitempty"`
GitHead string `json:"git_head,omitempty"`
ChangedFiles []string `json:"changed_files,omitempty"`
VerifyRef string `json:"verify_ref,omitempty"`
Telemetry *core.Annotations `json:"telemetry,omitempty"`
}
func MissionEvent ¶
MissionEvent returns the first event carrying missionID, or false.
type Authority ¶
type Authority struct {
Enabled bool
}
func (Authority) CanClearGate ¶
func (authority Authority) CanClearGate(severity GateSeverity) bool
func (Authority) CanDispatch ¶
type Checkpoint ¶
type Checkpoint struct {
SessionID string `json:"session_id"`
Step int `json:"step"`
Wave int `json:"wave"`
Decision string `json:"decision"`
MissionID string `json:"mission_id,omitempty"`
TaskID string `json:"task_id,omitempty"`
Lease *Lease `json:"lease,omitempty"`
Time time.Time `json:"time"`
}
Checkpoint is the write-ahead record the controller makes durable BEFORE a dispatch becomes visible in the ledger (spec 07 R1). If the process dies after the checkpoint but before the ACP dispatch, resume finds the checkpoint's mission id absent from the ledger and re-issues exactly that dispatch; if it dies after the ledger append, resume finds the mission id present and does not re-issue — this is what makes crash recovery converge with zero double-dispatch.
func LoadCheckpoint ¶
func LoadCheckpoint(path string) (Checkpoint, bool, error)
LoadCheckpoint reads the checkpoint. The bool is false when none exists yet.
type Decision ¶
func Decide ¶
func Decide(snapshot Snapshot, limits DecisionLimits) Decision
func DispatchFrontier ¶
func DispatchFrontier(snapshot Snapshot, limits DecisionLimits, dispatcher Dispatcher) (Decision, error)
func EvaluateBrakes ¶
func EvaluateBrakes(snapshot Snapshot, limits DecisionLimits) Decision
type DecisionLimits ¶
func DecisionLimitsForAuthority ¶
func DecisionLimitsForAuthority(authority Authority, limits DecisionLimits) DecisionLimits
type Dispatcher ¶
type Dispatcher interface {
Dispatch(task core.FrontierTask) error
}
type GateSeverity ¶
type GateSeverity string
const ( GateLow GateSeverity = "low" GateMedium GateSeverity = "medium" GateHigh GateSeverity = "high" GateCritical GateSeverity = "critical" )
type ResumePlan ¶
type ResumePlan struct {
Reissue bool
Mission Checkpoint
Conflict string
}
ResumePlan is the reconciliation of the write-ahead checkpoint against the ACP ledger (spec 07 R3/R4). Exactly one of the outcomes holds:
- Conflict != "": the checkpoint and ledger disagree irreconcilably; resume must refuse (exit 1) rather than guess.
- Reissue == true: the checkpoint's mission never reached the ledger (crash between checkpoint and dispatch); resume re-issues exactly that dispatch.
- both zero: the checkpoint's mission is already in the ledger (or there is no outstanding mission); resume only reconstructs session state.
func PlanResume ¶
func PlanResume(cp Checkpoint, cpExists bool, events []ACPEvent) ResumePlan
PlanResume computes the resume plan from the checkpoint and the ledger. It is pure: the caller supplies the loaded checkpoint (with existence flag) and the ledger events.
type Session ¶
type Session struct {
// ID is a stable identifier minted at `brain start`, used to derive
// deterministic mission ids (session/step/task) that survive a resume.
ID string `json:"id,omitempty"`
Revision int64 `json:"revision"`
State SessionState `json:"state,omitempty"`
// Step is the controller tick counter, incremented per dispatch. It feeds the
// mission id so a re-issued dispatch after resume reuses the same id.
Step int `json:"step,omitempty"`
Leases []Lease `json:"leases,omitempty"`
}
func LoadSession ¶
func (Session) IsTerminal ¶
IsTerminal reports whether the session refuses further step/run/resume.
func (Session) Status ¶
func (s Session) Status() SessionState
Status returns the effective lifecycle state, treating the empty zero value as running (pre-spec-07 compatibility).
type SessionState ¶
type SessionState string
SessionState is the controller lifecycle (spec 07 R2). The persisted state machine is running → {cancelled | complete}; both terminal states refuse further step/run. An empty state decodes as running so pre-spec-07 sessions stay valid. "crashed" is never persisted — it is derived by `brain status` from a checkpoint that outran the ledger (see DeriveStatus).
const ( SessionRunning SessionState = "running" SessionCancelled SessionState = "cancelled" SessionComplete SessionState = "complete" SessionCrashed SessionState = "crashed" )
func DeriveStatus ¶
func DeriveStatus(session Session, cp Checkpoint, cpExists bool, events []ACPEvent) SessionState
DeriveStatus is the effective status reported by `brain status`. A terminal session reports its persisted state. A running session whose checkpoint names a mission missing from the ledger is reported as crashed: the process died mid-dispatch and a resume is needed to converge (spec 07 R6).