Documentation
¶
Overview ¶
Package implement is the run machinery an autonomous implementation run calls: the run's shared state in the machine-scoped store, the sessions that join it, the claim that makes a record the unit of exclusion between them, the bounds that keep a second session from becoming a hazard, and the run log the comparison of division modes is derived from (itd-2609221656373558, spc-2609221657588816).
Everything lives under one directory per repository:
~/.abcd.noindex/runs/<root-sha>/<YYYY-MM-DD>.jsonl the run log, one event per line ~/.abcd.noindex/runs/<root-sha>/claims/<record>.json one claim per record ~/.abcd.noindex/runs/<root-sha>/sessions/<id>.json one record per joined session
The key is the repository's root-commit SHA, the same key and the same full form the transcript, history and voyage stores use (internal/core/history's location.go says why: a checkout moves, is renamed and is cloned twice, while its root commit changes under none of that). Two sessions in two worktrees of one repository therefore share one directory and no repository file.
The package is the seed the implement loop builds on (itd-2609201916151817: `implement step` and `implement receipt`) and the pacing verb reads (itd-2609201925079472): a Run is the handle a later state file hangs off, and the log is the measurement both inherit. Core never writes to stdout; the CLI front door formats what these functions return.
Index ¶
- Constants
- Variables
- func LoadSites() []string
- func LoggableEvents() []string
- func ParseLog(name string, data []byte) ([]Event, []Unparsed)
- func ReadingCorpus(repoRoot string) ([]string, error)
- func RequiredFields(event string) []string
- func TouchesReadingCorpus(corpus, paths []string) string
- type Claim
- type ClaimRequest
- type ClaimResult
- type ClaimState
- type CoverageGap
- type Event
- type Evidence
- type FieldGap
- type HeldError
- type JoinResult
- type LeaveResult
- type LoadAverages
- type LoadLimits
- type LoadOtherStrays
- type LoadOwnStray
- type LoadRemedy
- type LoadRequest
- type LoadResult
- type LoadRunLog
- type Mode
- type ModeTally
- type Report
- type Role
- type Run
- func (r *Run) AgentsAlive(s Session) (int, error)
- func (r *Run) Check(session string, stage Stage, paths []string) (Verdict, error)
- func (r *Run) Claim(req ClaimRequest) (ClaimResult, error)
- func (r *Run) Claims() ([]ClaimState, error)
- func (r *Run) Compare() (Report, error)
- func (r *Run) CurrentMode() (WindowState, bool, error)
- func (r *Run) Join(id string, role Role, model, reason string, ceiling int) (JoinResult, error)
- func (r *Run) Joined(id string) (Session, error)
- func (r *Run) Leave(id, reason string) (LeaveResult, error)
- func (r *Run) Log(session, event string, fields map[string]string) (Event, error)
- func (r *Run) ReadLog() ([]Event, []Unparsed, error)
- func (r *Run) Release(session, record string) (Claim, error)
- func (r *Run) Sessions() ([]Session, error)
- func (r *Run) SetMode(session string, m Mode, window int) (WindowState, error)
- type Session
- type SessionContext
- type SessionTally
- type Stage
- type Unparsed
- type UnreadableClaimError
- type Verdict
- type WindowState
Constants ¶
const ( MinLease = time.Minute MaxLease = 24 * time.Hour )
Lease bounds. A lease shorter than a minute lapses under its own gate run; a lease longer than a day outlives any window the run keeps.
const ( SitePreflight = "preflight" SiteEvalHarness = "eval-harness" )
The sites the check runs at.
const ( // LoadOK: nothing to warn about. LoadOK = "ok" // LoadWarning: at least one trigger fired. LoadWarning = "warning" // LoadSkipped: a CI runner, where the check does not run. LoadSkipped = "skipped" // LoadUnchecked: the machine could not be read (an unsupported platform, or // a read that failed) and nothing fired on what could be read. LoadUnchecked = "unchecked" )
The four statuses.
const ( LimitsDefault = "default" LimitsFile = "file" LimitsDefaultAfterMalformed = "default-after-malformed" )
Where the limits came from.
const ( CoresOnline = "online" CoresRuntime = "runtime" )
The core-count sources.
const ( PrivateNameMask = "[private name]" WithheldNameMask = "[name withheld: private-names layer unreadable]" )
PrivateNameMask replaces an own stray's name the private banned-names layer matches; WithheldNameMask replaces every name when that layer cannot be read.
const ( EventSessionOpen = "session_open" EventSessionClose = "session_close" EventWindowMode = "window_mode" EventClaim = "claim" EventClaimDenied = "claim_denied" EventClaimLapsed = "claim_lapsed" EventClaimReleased = "claim_released" EventBackoff = "backoff" EventLaneOpen = "lane_open" EventLaneClose = "lane_close" EventAgentStart = "agent_start" EventAgentEnd = "agent_end" EventCeilingWait = "ceiling_wait" EventGateRun = "gate_run" EventReview = "review" EventFallback = "fallback" EventStop = "stop" EventRefusal = "refusal" EventPR = "pr" EventCapture = "capture" // EventContext is an orchestrator's context measurement: used_pct (the share // of its context window in use), role and note. The run measures it because // it is also an experiment in keeping a session alive for days. EventContext = "context" // EventCeilingOverrun is a session going over its agent ceiling: alive (the // agents alive), ceiling, lane and minutes (how long it was over). The verb // refuses an agent_start past the ceiling, so an overrun is what the host // did anyway — a fork, an agent started outside the log — and says so. EventCeilingOverrun = "ceiling_overrun" // The evidence events: what an autonomous run records so a later run can be // built to need no person. An intervention is a person acting on the run // (kind, by, what, why, autonomy_gap — what abcd or the host would need so // no person is needed — and optionally at and detected_after_min); a stop is // a stall (cause, and optionally last_productive, noticed_after_min and // recovery); a decision is a judgement call a person would normally make // (what, alternative, why, and optionally at). EventIntervention = "intervention" EventDecision = "decision" // EventLoad is the load check's warning (itd-2609231434459890), written by // `implement load` alone and only when it warns inside a live run. The run's // hand-kept load samples share the name and carry no `triggers`, which is how // a reader tells the two apart. EventLoad = "load" )
Event names. The first group is written only by this package's verbs, so the log cannot claim a join, a window or a claim that the run state does not hold.
const CoverageGapAfter = 6 * time.Hour
CoverageGapAfter is how long before the run's last line a measured event's last line may fall before the report names its coverage as stopping.
const DefaultLease = 2 * time.Hour
DefaultLease is how long a claim holds when the caller names no lease: long enough for a lane's build-and-gate cycle, short enough that a session that died mid-lane frees its record within the same working window.
const JoinGrace = time.Minute
JoinGrace is how long before a window_mode a session_open may be logged and still count in that window.
const MaxCeiling = 64
MaxCeiling bounds a stated agent ceiling.
The ceiling is a session's own limit on the agents it runs at once — for the second session, on top of the first session's (itd-2609221656373558, criterion 5). The session states it on joining, and the record and the session_open line carry it. abcd runs no agent, so what it holds the ceiling against is what the session declares: the agents its own agent_start and agent_end lines leave alive (Run.AgentsAlive). An agent_start past the ceiling is refused and the refusal logged, and every check reports the count beside the ceiling. An agent the session never logs — a fork, one the host started outside the log — is invisible, so the count is a discipline the session keeps with the verb's help, not a census of processes (iss-2609240646542516).
const UnreadableClaimGrace = time.Minute
UnreadableClaimGrace is how long a claim file nobody can parse holds its record, counted from the file's modification time. Every claim is written under the run's lock in one create, so an unparseable file is a writer killed between the create and the write; the grace is only long enough that a reader racing that writer backs off rather than taking the record.
const UnsetMode = "unset"
UnsetMode labels the events logged before any window opened.
Variables ¶
var CoverageEvents = []string{EventLaneOpen, EventLaneClose, EventAgentStart, EventAgentEnd, EventGateRun}
CoverageEvents are the hand-kept events the report's figures rest on and a run writes throughout, so their stopping partway is a gap, not a lull.
var ErrContention = errors.New("contention")
ErrContention is the class of every "someone else holds it" outcome: a record another session has claimed, or the run state locked by another session's mutation. It is not a fault: the caller backs off and tries other work. The CLI maps it to exit 3.
var ErrRefused = errors.New("refused")
ErrRefused is the class of every refusal: an input the verb does not recognise, a session that has not joined, or a bound the caller's role does not permit. Nothing is written for the refused act (the refusal itself may be logged). The CLI maps it to exit 2.
var InterventionKinds = []string{
"session_open", "account", "ruling", "restart", "close_session", "file_restore", "permission", "other",
}
InterventionKinds is the closed vocabulary of an intervention's kind.
var LimitsFileDisplay = abcdhome.Display(machineload.LimitsFileName)
LimitsFileDisplay is the settings file as every report names it.
Functions ¶
func LoggableEvents ¶
func LoggableEvents() []string
LoggableEvents returns the events `implement log` accepts, for help text and shell completion.
func ReadingCorpus ¶
ReadingCorpus is what "a lane that touches the reading corpus" means, derived from the checkout's committed preset file rather than restated here: the union of every position's object.paths, plus the preset file itself, whose recalibration serialises such lanes (iss-2609211105023379). A lane that edits one of those paths moves what a cold reading is handed, and so the measured windows the first session recalibrates. An entry names a file or a directory; a directory covers everything beneath it.
It is read through reading.LoadPresets, the loader the reading verb itself uses, so the two can never disagree about what the corpus is, and it refuses what that loader refuses: an untracked, symlinked or unparseable preset file. A corpus that cannot be derived is an error, never an empty list — the caller fails closed on it.
func RequiredFields ¶ added in v0.12.0
RequiredFields returns the fields `implement log` requires on event, each as its accepted names ("minutes|wall_minutes|wall_min"), for help text and the report's missing-field count.
func TouchesReadingCorpus ¶
TouchesReadingCorpus returns the first path that falls in corpus — equal to an entry, or beneath one — or "" when none does.
Types ¶
type Claim ¶
type Claim struct {
Record string `json:"record"`
Session string `json:"session"`
Lane string `json:"lane"`
ClaimedAt time.Time `json:"claimed_at"`
ExpiresAt time.Time `json:"expires_at"`
}
Claim is one claim file's content.
type ClaimRequest ¶
type ClaimRequest struct {
Session string
Record string
Lane string
// Lease is the claim's lifetime; zero means DefaultLease.
Lease time.Duration
// Paths are the repository-relative files the lane expects to touch, when the
// caller knows them. For the second session a path in the reading corpus —
// or any path, when the corpus cannot be derived — refuses the claim (see
// ReadingCorpus).
Paths []string
}
ClaimRequest is what a session asks for.
type ClaimResult ¶
type ClaimResult struct {
Claim Claim `json:"claim"`
// Renewed is true when the session already held the record and the lease was
// extended instead of a second claim being taken.
Renewed bool `json:"renewed"`
// Lapsed is the expired claim this one replaced, when there was one.
Lapsed *Claim `json:"lapsed,omitempty"`
}
ClaimResult is what a granted claim reports.
type ClaimState ¶
type ClaimState struct {
Claim
Live bool `json:"live"`
// Unreadable marks a claim file nobody can parse: it carries only its
// record, and its lease is the grace after the file was written.
Unreadable bool `json:"unreadable,omitempty"`
}
ClaimState is a claim as read at a moment: whether its lease still holds.
type CoverageGap ¶ added in v0.12.0
type CoverageGap struct {
Event string `json:"event"`
Lines int `json:"lines"`
Last time.Time `json:"last"`
// RunLast is the run's last line, load samples aside.
RunLast time.Time `json:"run_last"`
HoursBefore float64 `json:"hours_before"`
}
CoverageGap is a measured event whose lines stop partway through the run.
type Event ¶
type Event struct {
TS time.Time `json:"ts"`
Session string `json:"session"`
Event string `json:"event"`
Fields map[string]json.RawMessage `json:"-"`
}
Event is one line of the run log as it was read: the three fixed fields parsed, and every field (the fixed three included) kept as raw JSON so a reader can take what it understands and leave the rest.
type Evidence ¶ added in v0.12.0
type Evidence struct {
Interventions int `json:"interventions"`
InterventionsByKind map[string]int `json:"interventions_by_kind"`
// DetectedAfterMinutes sums the interventions' detected_after_min: how long
// the needs went unnoticed.
DetectedAfterMinutes float64 `json:"detected_after_minutes"`
Stops int `json:"stops"`
// StopNoticedAfterMinutes sums the stops' noticed_after_min.
StopNoticedAfterMinutes float64 `json:"stop_noticed_after_minutes"`
Decisions int `json:"decisions"`
}
Evidence is the run's evidence events counted over the whole run: what a run that needs no person would have to do without.
type FieldGap ¶ added in v0.12.0
type FieldGap struct {
Event string `json:"event"`
Field string `json:"field"`
Lines int `json:"lines"`
Of int `json:"of"`
}
FieldGap is a field `implement log` requires of an event, and how many of the log's lines of that event lack it.
type HeldError ¶
type HeldError struct {
Holder Claim
}
HeldError is the contention a refused claim returns: the record and the session that holds it.
type JoinResult ¶
type JoinResult struct {
Session Session `json:"session"`
// Rejoined is true when the session's record already existed with the same
// role: a resumed session opens again rather than being refused.
Rejoined bool `json:"rejoined"`
}
JoinResult is what Join reports.
type LeaveResult ¶
LeaveResult is what Leave reports.
type LoadAverages ¶
type LoadAverages struct {
One float64 `json:"one"`
Five float64 `json:"five"`
Fifteen float64 `json:"fifteen"`
}
LoadAverages are the three load averages.
type LoadLimits ¶
type LoadLimits struct {
StrayMinutes int `json:"stray_minutes"`
ExtremeLoad float64 `json:"extreme_load"`
Source string `json:"source"`
StrayFromFile bool `json:"stray_from_file"`
ExtremeFromFile bool `json:"extreme_from_file"`
// Malformed says why the settings file is unusable, when it is: a line
// number and a fault class, never a value.
Malformed string `json:"malformed,omitempty"`
}
LoadLimits are the limits in force and where they came from.
type LoadOtherStrays ¶
LoadOtherStrays is every other account's strays: a count and a CPU total in cores, rounded to one decimal, and nothing else.
type LoadOwnStray ¶
type LoadOwnStray struct {
Name string `json:"name"`
PID int `json:"pid"`
PGID int `json:"pgid"`
AgeS int64 `json:"age_s"`
CPUPct int `json:"cpu_pct"`
}
LoadOwnStray is one of the caller's own strays as it is printed and logged.
type LoadRemedy ¶
type LoadRemedy struct {
// Form is "group" (pgrep -g, then kill -- -PGID) or "process" (ps -p, then
// kill PID).
Form string `json:"form"`
PGID int `json:"pgid,omitempty"`
PIDs []int `json:"pids,omitempty"`
PID int `json:"pid,omitempty"`
// Why says why a process form is not the group form.
Why string `json:"why,omitempty"`
}
LoadRemedy is one printed way to stop some of the caller's own strays.
type LoadRequest ¶
type LoadRequest struct {
// Site is where the check runs: SitePreflight or SiteEvalHarness.
Site string
// Getenv reads the environment; nil is os.Getenv.
Getenv func(string) string
// Read reads the machine; nil is machineload.Read.
Read func() (machineload.Snapshot, error)
// Home is the caller's home, where ~/.abcd.noindex/load-limits lives; "" resolves it.
Home string
// RepoRoot is the checkout the check runs in, whose private banned-names
// layer scrubs the own strays' names; "" is outside any checkout.
RepoRoot string
// RootSHA keys the run state; "" derives it from RepoRoot.
RootSHA string
// Self is the invocation; the zero value is this process.
Self machineload.Self
// Now is the clock for the run-log line; nil is time.Now.
Now func() time.Time
// GOOS names the platform in the cannot-check reason; "" is runtime.GOOS.
GOOS string
}
LoadRequest is one check. Every field but Site has a working zero value; the others exist so a test never depends on the real machine, environment or home.
type LoadResult ¶
type LoadResult struct {
Status string `json:"status"`
Site string `json:"site"`
Load *LoadAverages `json:"load"`
Cores int `json:"cores"`
CoresSource string `json:"cores_source,omitempty"`
Limits *LoadLimits `json:"limits"`
Triggers []string `json:"triggers"`
OwnStrays []LoadOwnStray `json:"own_strays"`
OwnStraysMore int `json:"own_strays_more"`
OtherStrays LoadOtherStrays `json:"other_strays"`
Remedy []LoadRemedy `json:"remedy"`
NamesWithheld bool `json:"names_withheld,omitempty"`
WithinPreflight bool `json:"within_preflight"`
RunLog LoadRunLog `json:"run_log"`
// Reason says why the check was skipped or could not read everything.
Reason string `json:"reason,omitempty"`
}
LoadResult is the check's whole report.
func CheckLoad ¶
func CheckLoad(req LoadRequest) LoadResult
CheckLoad runs the load check once. It never returns an error: a machine it cannot read is a status with a reason, and a run log it cannot write is reported on the result beside a warning that stands.
func LoadResultFromEvent ¶
func LoadResultFromEvent(ev Event) (LoadResult, error)
LoadResultFromEvent reads a logged `load` event back into the warning it records, so a reader renders exactly what was printed. The run-log outcome is not part of the event.
No production code reads it yet; its readers are tests in two packages, this one and the CLI surface's (TestLoggedEventRendersToThePrintedWarning, which needs the surface's unexported renderer). It stays here, exported, because Go has no test-only export across packages and the decoding needs the unexported loadEvent, so moving it into a test file would duplicate the event's shape.
type LoadRunLog ¶
type LoadRunLog struct {
Logged bool `json:"logged"`
Session string `json:"session,omitempty"`
Error string `json:"error,omitempty"`
}
LoadRunLog is what happened to the run-log event.
type Mode ¶
type Mode string
Mode is a window's division of work between the sessions. `single` is a window with one session; the three the intent measures are `claim` (a session claims a record before opening its lane), `batch` (the run file assigns whole batches per session) and `split-roles` (the first builds; the second reviews, audits and lands).
const ( ModeSingle Mode = "single" ModeClaim Mode = "claim" ModeBatch Mode = "batch" ModeSplitRoles Mode = "split-roles" )
The four modes.
type ModeTally ¶
type ModeTally struct {
Mode string `json:"mode"`
Windows int `json:"windows"`
WallMinutes float64 `json:"wall_minutes"`
LanesOpened int `json:"lanes_opened"`
LanesLanded int `json:"lanes_landed"`
SecondLanesLanded int `json:"second_session_lanes_landed"`
Collisions int `json:"collisions"`
Lapses int `json:"claims_lapsed"`
Backoffs int `json:"backoffs"`
BackoffMinutes float64 `json:"backoff_minutes"`
AgentMinutes float64 `json:"agent_minutes"`
CeilingWaitMinutes float64 `json:"ceiling_wait_minutes"`
// CeilingOverruns are the ceiling_overrun lines, and CeilingOverrunMinutes
// the minutes over they carry.
CeilingOverruns int `json:"ceiling_overruns"`
CeilingOverrunMinutes float64 `json:"ceiling_overrun_minutes"`
Refusals int `json:"refusals"`
LandedPerHour float64 `json:"lanes_landed_per_hour"`
Sessions []SessionTally `json:"sessions"`
}
ModeTally is one division mode's figures over every window that ran it.
type Report ¶
type Report struct {
Events int `json:"events"`
Unparsed []Unparsed `json:"unparsed"`
Modes []ModeTally `json:"modes"`
// Context is each session's context measurement, by session id.
Context []SessionContext `json:"context"`
// Evidence counts the run's interventions, stops and decisions.
Evidence Evidence `json:"evidence"`
// MissingFields names, per event and required field, the lines lacking it.
MissingFields []FieldGap `json:"missing_fields"`
// Coverage names each measured event whose lines stop partway.
Coverage []CoverageGap `json:"coverage"`
// Leader is the mode with the most lanes landed per wall-clock hour, "" when
// no mode landed a lane or two modes tie. It is a figure, not a verdict: the
// run's report names which mode it would keep, and says why.
Leader string `json:"leader"`
LeaderBasis string `json:"leader_basis"`
}
Report is the derived comparison.
type Role ¶
type Role string
Role is a session's standing in the run. The first session is the run: it may cut a release and take any lane, and it never waits on the second. The second is optional and bounded (the intent's decision 3): at most one lane, never the release, never a lane that touches the reading corpus, and it backs off on contention.
The role lives in the session's record in the run state, written when the session joins. It is deliberately not read from the environment: a variable a shell, a task runner or a repository's configuration can set is not a statement the session made, and the bounds key on it. What the record gives is consistency, not authentication — two sessions of one account can each write anything under that account's home — so the bounds are a discipline two cooperating sessions keep, checked at every verb, not a wall against a hostile one.
type Run ¶
type Run struct {
// Dir is the run directory, ~/.abcd.noindex/runs/<root-sha>.
Dir string
// RootSHA is the repository's root-commit SHA the directory is keyed on.
RootSHA string
// RepoRoot is the checkout the run was opened from. The reading corpus the
// second session's bounds check against is read from its preset file.
RepoRoot string
// Now is the clock. Tests set it; nil means time.Now.
Now func() time.Time
// contains filtered or unexported fields
}
Run is one repository's run state. The zero value is not usable; construct it with Open (which creates the directories a mutation needs) or Peek (which creates nothing, for the read-only renders).
func Open ¶
Open returns the run for rootSHA, creating its directories when absent. Every level from ~/.abcd.noindex down is created one at a time and proved a real directory, never through a symlink (fsutil.EnsureRealDirAll), so a planted redirect is refused before anything is written beneath it.
func OpenJoined ¶
OpenJoined returns the run for rootSHA on behalf of a session that must already have joined it: every writer but join. A run directory that does not exist holds no session, so the caller is refused before anything is created — no directory, no lock, no log line. An existing run is opened as Open opens it, and the verb itself refuses a session it does not hold.
func Peek ¶
Peek returns the run for rootSHA without creating anything. A run directory that does not exist reads as an empty run: no sessions, no claims, no log.
func (*Run) AgentsAlive ¶ added in v0.12.0
AgentsAlive counts the agents a session has declared alive: the agents named by its agent_start lines since it joined, each with no agent_end of the same agent after it. It counts what the session wrote and nothing else — abcd runs no agent, and a line the session never wrote (a fork, an agent the host started outside the log) is invisible here — so it is the declared count the ceiling is held against, not a census of processes. Lines naming no agent cannot be matched and are not counted.
func (*Run) Check ¶
Check says whether a session may take a stage, and logs the refusal when it may not. The first session may take every stage. The second is refused:
- the release stage, always — only the first session cuts a release;
- a lane in a split-roles window, where the second only reviews, audits and lands;
- a lane whose paths reach the reading corpus.
Review, audit and land are open to both. A refusal is an ErrRefused-classed error and a `refusal` line in the log; an allowed stage writes nothing.
func (*Run) Claim ¶
func (r *Run) Claim(req ClaimRequest) (ClaimResult, error)
Claim takes req.Record for req.Session. In order, under the run's lock:
- the session must have joined; its role decides the bounds;
- a second session is refused when it already holds a live claim on another record (one lane at a time), when the window's mode is split-roles (the second builds nothing), or when req.Paths reach the reading corpus;
- the claim file is created exclusively. If it exists and this session holds it, the lease is renewed. If another session's lease has passed, the lapse is logged, the stale file removed, and the create retried. If another session's lease holds, the denial is logged naming the holder — and for the second session a backoff is logged beside it — and a *HeldError (ErrContention) is returned.
A granted claim is logged as `claim`. When that line cannot be written the claim is removed again, so the claims directory never holds a claim the log does not.
func (*Run) Claims ¶
func (r *Run) Claims() ([]ClaimState, error)
Claims lists every claim file, live or lapsed, by record.
func (*Run) CurrentMode ¶
func (r *Run) CurrentMode() (WindowState, bool, error)
CurrentMode returns the mode the log last recorded, whoever wrote the line (a hand-written window_mode counts the same as one SetMode wrote). ok is false when no window has been opened; an unrecognised mode word is returned as it was written, and the bounds treat it as no split.
func (*Run) Join ¶
Join records a session in the run and logs its session_open. Nothing signals any other session: joining is a file the joiner writes and a log line, and the first session learns of a second only if it reads the run state. The record is taken by an exclusive create; a session that joins again with the role it holds is a resume, and one that asks for a different role is refused. ceiling is the session's own agent ceiling (see MaxCeiling), zero for none; a resume keeps the ceiling it joined with and refuses a different one.
func (*Run) Joined ¶ added in v0.12.0
Joined returns a joined session's record, or refuses one the run does not hold, writing nothing: for a caller that acts for a session in the run state and must know it has joined before it creates anything of its own.
func (*Run) Leave ¶
func (r *Run) Leave(id, reason string) (LeaveResult, error)
Leave closes a session: it releases every claim the session holds, logs session_close with the reason, and removes the session's record. A session that stops without leaving is covered by its claims' leases instead.
func (*Run) Log ¶
Log appends one event on a joined session's word: the run's hand-kept events (lane_open, agent_end, backoff, …) through the same single-write append the verbs use. The event must be one of LoggableEvents — the verb-owned events are refused, because a hand-written claim the claims directory does not hold is a log that lies — and fields are key=value pairs under the limits above. A value that parses as an integer, a decimal or a boolean is written as a JSON number or boolean when it round-trips to the same text; anything else as a string.
func (*Run) ReadLog ¶
ReadLog reads every day's log in the run directory, in date order. A missing directory is an empty log. Lines that are not a JSON object carrying ts, session and event are returned as Unparsed rather than failing the read: the log is hand-written in part, and a comparison that stopped at the first odd line would report nothing.
func (*Run) Release ¶
Release gives up a session's claim on a record and logs claim_released. Only the holder releases: a session cannot free another's claim, which lapses on its own lease instead.
type Session ¶
type Session struct {
Session string `json:"session"`
Role Role `json:"role"`
JoinedAt time.Time `json:"joined_at"`
Model string `json:"model,omitempty"`
// Ceiling is the session's own agent ceiling as it stated it on joining,
// zero when it stated none.
Ceiling int `json:"ceiling,omitempty"`
}
Session is a joined session's record.
type SessionContext ¶
type SessionContext struct {
Session string `json:"session"`
Role string `json:"role"`
Events int `json:"events"`
LastUsedPct float64 `json:"last_used_pct"`
LastAt time.Time `json:"last_at"`
}
SessionContext is one session's context measurement across the whole run: how many context lines it logged and the last used_pct among them. It is per session rather than per mode because an orchestrator's context is carried across windows, not reset by them.
type SessionTally ¶
type SessionTally struct {
Session string `json:"session"`
Role string `json:"role"`
LanesOpened int `json:"lanes_opened"`
LanesLanded int `json:"lanes_landed"`
AgentMinutes float64 `json:"agent_minutes"`
BackoffMinutes float64 `json:"backoff_minutes"`
CeilingWaitMinutes float64 `json:"ceiling_wait_minutes"`
CeilingOverruns int `json:"ceiling_overruns"`
Collisions int `json:"collisions"`
}
SessionTally is one session's share of a mode.
type Stage ¶ added in v0.12.0
type Stage string
Stage is a point in a run where the second session's bounds are checked before the session acts, called a stage like the loop's lane stages (rulings BU1 and CM1: a spec's piece is a step, and nothing else is). A lane is opened by a claim (Claim applies the lane bounds itself); Check is for the stages that are not claims, and for a lane whose files are only known once it has been built.
const ( StageLane Stage = "lane" StageRelease Stage = "release" StageReview Stage = "review" StageAudit Stage = "audit" StageLand Stage = "land" )
The stages.
func ParseStage ¶ added in v0.12.0
ParseStage accepts exactly one of Stages.
type Unparsed ¶
type Unparsed struct {
File string `json:"file"`
Line int `json:"line"`
Reason string `json:"reason"`
}
Unparsed is one log line the reader could not use, with why.
type UnreadableClaimError ¶
UnreadableClaimError is a claim file nobody can parse — a session killed between the exclusive create and the write leaves an empty one. It names the file's full path and when it lapses, never a guess at who holds it.
func (*UnreadableClaimError) Error ¶
func (e *UnreadableClaimError) Error() string
type Verdict ¶
type Verdict struct {
Session string `json:"session"`
Role Role `json:"role"`
Stage Stage `json:"stage"`
Mode Mode `json:"mode,omitempty"`
Allowed bool `json:"allowed"`
// Ceiling is the session's own agent ceiling as it joined with it, zero when
// it stated none: reported with every verdict, beside AgentsAlive, so the
// session about to act sees the limit it keeps (see MaxCeiling).
Ceiling int `json:"ceiling,omitempty"`
// AgentsAlive is the count of the session's agents its own log lines declare
// alive (see Run.AgentsAlive): what an agent_start is held against when the
// session stated a ceiling.
AgentsAlive int `json:"agents_alive"`
}
Verdict is Check's answer.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package loop is the implement loop's engine (itd-2609201916151817, spc-2609202134338445): the state file a run lives in, the checks that decide whether a run may start, and the step interface a driving host calls.
|
Package loop is the implement loop's engine (itd-2609201916151817, spc-2609202134338445): the state file a run lives in, the checks that decide whether a run may start, and the step interface a driving host calls. |