Documentation
¶
Overview ¶
Package fleetgoal is the goal executor's mind (design 055): it observes a fleet, judges whether the fleet and each of its agents are on track to their goals, and plans the few messages that keep them moving in order.
PURE, LIKE internal/fleet AND internal/board: no NATS, no clock, no I/O. The actor around it (internal/actors/fleet_goal_executor.go) reads the ledger and the board, hands both in with `now`, and sends what Plan returns. Every verdict below is therefore reproducible in a test to the millisecond, which is the point: a coordinator whose judgement cannot be replayed cannot be trusted to interrupt anyone.
IT READS WHAT THE HUMAN READS. The assessment is built on board.BuildFlow, board.BuildFlowDeps and board.TeamRows — the model behind the team view (t) and the dependency tree — so anything the executor says about a bottleneck or a waiting count can be checked against the screen.
Index ¶
Constants ¶
const ( KindReport = "goal-report" KindAlert = "goal-alert" )
Board post kinds the executor writes.
const ( CondDeadlock = "deadlock" CondStressed = "stressed" CondStrayed = "strayed" CondStalled = "stalled" CondBlocker = "blocker" CondBlocked = "blocked" CondUnblocked = "unblocked" CondIdle = "idle" CondProgressing = "progressing" CondMet = "met" )
Conditions — per member, several may hold; the primary is the first in ConditionOrder that does.
const ( StateStarting = "starting" // nobody has declared anything yet StateOnTrack = "on-track" StateAtRisk = "at-risk" StateOffTrack = "off-track" StateStuck = "stuck" StateMet = "met" StateNoGoal = "no-goal" )
Fleet states.
const ( KindSequence = "SEQUENCE" // a deadlock: one breaker goes first, the rest hold KindHurry = "HURRY" // a blocker with waiters: finish this first, give an ETA KindWait = "WAIT" // a waiter: whom you wait on, until when; do not ask them KindShield = "SHIELD" // a stressed agent: messages held, one thing to do KindRealign = "REALIGN" // a strayed agent: back to the goal KindPull = "PULL" // an idle agent's parent: give it goal work, or pair it KindRisk = "RISK" // the head: the fleet's state got worse KindConfirm = "CONFIRM" // the head: every member goal is met; is the fleet's? )
Directive kinds.
const Identity = "fleet"
Identity is the board identity the executor posts and sends as. The fleet actor's: the executor is its child, and the flow view draws both as the one `fleet` node. The envelope says which of the two is speaking.
Variables ¶
var ( // StressThreshold is the score at which an agent is stressed (§5.1). StressThreshold = 3 // RecentWindow is how far back "recent prompts" reach. RecentWindow = 15 * time.Minute // WanderWindow bounds the "wandering" signal: task texts declared within it. WanderWindow = 30 * time.Minute // OverrunGrace is the least slack past an agent's own ETA before it is // called an overrun. OverrunGrace = 10 * time.Minute )
Thresholds. Variables, not constants, only so a test can name them; the actor never changes them.
var ( // MaxPerHour bounds the executor's messages to one agent. MaxPerHour = 4 // MaxPerHourStressed bounds them for a stressed agent. MaxPerHourStressed = 1 // LadderTop is the highest escalation level: 1 the agent, 2 + its parent, // 3 + the head and a board alert for the human. LadderTop = 3 )
Budget and ladder. Variables only so a test can name them.
var ConditionOrder = []string{CondDeadlock, CondStressed, CondStrayed, CondStalled, CondBlocker, CondBlocked, CondUnblocked, CondIdle, CondProgressing, CondMet}
ConditionOrder is the priority of conditions: the most actionable first.
Functions ¶
Types ¶
type Action ¶
type Action struct {
Kind string
To string // pane id
Label string // display name of To
// About is the agent the directive concerns (== To unless it is a copy
// to a parent or the head).
About string
Text string
// Ask: the recipient's next `fleet status` answers it (HURRY, REALIGN,
// SEQUENCE to the breaker). Otherwise informational: `board ack` closes it.
Ask bool
Level int
Key string
}
Action is one directive to send.
type Assessment ¶
type Assessment struct {
Fleet string
BoardID string
State string
Why []string
// Pct is the mean declared pct over members with one; -1 when none.
Pct int
// Finish is the critical-path finish of the fleet; 0 when unknown.
// Unknown counts the open paths with no estimate.
Finish int64
Unknown int
DueAt int64
Bottleneck string // pane id ("" none)
BottleneckWaiting int
// Members in chain order — the team view's order.
Members []MemberAssessment
// Cycles are deadlocks, each in blocked_by order (pane ids).
Cycles [][]string
// Deps is the dependency tree exactly as the views render it.
Deps []string
// BoardOK is false when pressure could not be read.
BoardOK bool
}
Assessment is one cycle's verdict on the whole fleet.
func Assess ¶
func Assess(in Input, mem *Memory) Assessment
Assess judges the fleet. mem must have been fed this cycle by Observe.
func (*Assessment) Member ¶
func (a *Assessment) Member(id string) *MemberAssessment
Member finds a member's assessment by pane id.
type Input ¶
type Input struct {
Fleet fleet.Fleet
// Threads is the fleet board's recent window; nil with BoardOK false when
// the recorder did not answer — pressure is then UNKNOWN, never zero.
Threads []board.Thread
BoardOK bool
Now int64
Config fleet.GoalExec // resolved
}
Input is one cycle's observation.
type MemberAssessment ¶
type MemberAssessment struct {
PaneID string
Label string
Role string
Parent string // pane id; may be outside the fleet
Primary string
Conditions []string
Work, Task, Activity, Health string
Pct *int
EtaAt int64
Goal *fleet.Goal
// Waiting is how many distinct agents wait on this one, directly or not —
// the dependency tree's count.
Waiting int
// Waiters are the agents blocked directly on this one (pane ids).
Waiters []string
// BlockedBy are its blockers (pane ids, "human", "ext:…").
BlockedBy []string
// Pressure, from the board. -1 when the board could not be read.
OpenPrompts int
RecentPrompts int
StressScore int
StressWhy []string
StrayWhy []string
// Finish is when it is expected to be done (critical path); 0 = unknown.
Finish int64
}
MemberAssessment is one agent's verdict.
func (*MemberAssessment) Has ¶
func (m *MemberAssessment) Has(c string) bool
Has reports whether m has condition c.
type Memory ¶
type Memory struct {
Samples map[string][]Sample
Ladder map[string]*Rung
Sent map[string][]int64 // pane -> send times within the last hour
Cycles int
LastState string
LastReport string // the last report's fingerprint
LastReportAt int64
IntervalSec int // the adaptive cadence's current interval
}
Memory is the executor's own state across cycles. In-process: warm-up (Plan's first cycle sends nothing) is the guard against a restarted daemon re-sending everything it said before.
type Plan ¶
type Plan struct {
Actions []Action
// Alerts are board `goal-alert` posts (level-3 escalations, waits on the
// human) — for the human, who reads the board.
Alerts []string
// Report is a `goal-report` status post, or "" when nothing changed.
Report string
// NextSec is when to look again.
NextSec int
// Held counts directives the budget deferred to a later cycle.
Held int
}
Plan is one cycle's output.