Documentation
¶
Overview ¶
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. `abcd build <itd-N>` starts a run; `abcd implement step` performs the next stage of the current lane and exits; `abcd implement receipt <path>` hands back what an agent stage waited on; `abcd implement status` renders the state. Nothing here holds a run in memory between invocations: every call reads the state file first, does at most one stage, writes the state file last and returns (decisions 1 and 2), so a killed process loses only the stage it was in, which the next call repeats.
The state lives in the checkout's local tier:
.abcd/.work.local/run/<run-id>/state.json the run: its key, lanes, clock and record .abcd/.work.local/run/.lock the advisory lock every mutation takes
The tier is never created here: only a repository abcd manages has it, which is what keeps a run managed-only without a check of its own to drift from (internal/core/mode draws the same line). The run directories beneath it are created one level at a time and proved real (fsutil.EnsureRealDirAll), and the state is written through the package's one atomic writer inside an os.Root, so a symlinked component is refused rather than followed.
The lane's stages are a sequence (Sequence), and each stage's body is a Handler the piece of the spec that delivers it registers in DefaultStages: the worktree (piece 6, lane.go), the brief (piece 5, brief.go), the implement stage and its receipt's verifier (piece 7, receipt.go), the validators (piece 8) and the landing (piece 9). A stage whose body this build does not carry is refused by name, with the piece that delivers it, and the run is left unchanged. A lane's files live in its own directory of the run:
.abcd/.work.local/run/<run-id>/<lane-id>/brief.md the brief the loop renders .abcd/.work.local/run/<run-id>/<lane-id>/receipt.json the implementer's receipt
and its worktree in the machine-scoped store, ~/.abcd.noindex/worktrees/<root-sha>/<run-id>-<lane-id>. The process driver (piece 3, drive.go) is the same loop: Drive performs the next stage and, when it hands the lane to a role routed to a command-line runner (itd-2609201916056194), starts that agent through the runner and hands its receipt back through Receipt.
Core never writes to stdout; the CLI front door formats what these functions return.
Index ¶
- Constants
- Variables
- func DrainSummaryLine(r DrainRoute) string
- func LatestRun(repoRoot string) (string, error)
- func LoadRunners(r layered.Roots) (*runner.Config, error)
- func Resolve(repoRoot, runID string) (string, error)
- func StateRelPath(runID string) string
- func StatusLanes(repoRoot string) ([]statusblock.Started, error)
- func StatusPeers(repoRoot string) (statusblock.HeldBy, error)
- func ValidLaneID(id string) bool
- func ValidRunID(id string) bool
- type AliveLane
- type AuditRun
- type Await
- type CandidateSet
- type CheckResult
- type CheckRow
- type Context
- type DoDRun
- type DrainLane
- type DrainOptions
- type DrainResult
- type DrainRoute
- type DrainState
- type Driver
- type Entry
- type Excluded
- type HandBack
- type Handler
- type Hold
- type Landing
- type Lane
- type LaneAwait
- type LaneHandBack
- type LaneReceipt
- type LaneWorktree
- type NextOptions
- type NextResult
- type Options
- type Outcome
- type Pace
- type PaceValue
- type PendingStep
- type ReceiptRecord
- type RecordLane
- type RecordVerdict
- type Refusal
- type Resolution
- type RunPick
- type RunRecord
- type Runners
- type Stage
- type StageDef
- type Stages
- type StartResult
- type State
- type StepResult
- func Discard(repoRoot, runID, laneID string, o Options) (StepResult, error)
- func Drive(ctx context.Context, repoRoot, runID string, steps Stages, o Options, ...) (StepResult, error)
- func Receipt(repoRoot, runID, receiptPath string, steps Stages, o Options) (StepResult, error)
- func Release(repoRoot, runID, laneID string, o Options) (StepResult, error)
- type Sync
- type Transcript
- type TranscriptCapturer
- type ValidationRound
- type ValidatorRun
- type Verifier
- type Waiting
Constants ¶
const ( BriefFileName = "brief.md" ReceiptFileName = "receipt.json" ReportFileName = "report.md" DoDFileName = "dod.log" )
The files of a lane's directory, .abcd/.work.local/run/<run-id>/<lane-id>/. The loop writes the brief; the implementer writes the other three.
const ( CheckKey = "key" CheckReady = "ready" CheckOpenQuestions = intent.StartCheckOpenQuestions CheckClaimSections = intent.StartCheckClaimSections CheckHold = intent.StartCheckHold CheckBlocked = intent.StartCheckBlocked CheckSteps = intent.StartCheckSteps CheckPeers = "peers" // CheckEligible is an issue key's row: the drained repository's own rule // takes the issue (itd-82 scope 2; decision 10 on the parent). CheckEligible = "eligible" )
Check names, in the fixed order Check reports them.
const ( // DrainStoppedCap: the drain opened --max lanes. DrainStoppedCap = "cap" // DrainStoppedEmpty: no eligible issue is left that this drain has not // taken. DrainStoppedEmpty = "empty" )
Why a drain ended.
const ( DrainLaneInProgress = "in-progress" // DrainLanePullRequest: the landing opened the lane's pull request and // armed it or left it open; the merge is a person's gate. DrainLanePullRequest = "pull-request" DrainLaneHandedBack = "handed-back" // DrainLaneDone: the run is complete. DrainLaneDone = "done" )
The outcomes of a lane the drain opened, as the drain reads its run.
const ( // RoutePromoted: a user moment, promoted to an intent draft with // `capture promote`; the issue gains the draft in related_intents and // nothing else is written. RoutePromoted = "promoted" // RouteDecisionRecord: a rule about trust or safety, flagged as needing a // decision record with the question stated; nothing is minted. RouteDecisionRecord = "decision-record" // RouteRule: above the rule's severity, outside its categories, or held // by another of its rules; flagged naming the rule. RouteRule = "rule" // RouteHome: anything else, flagged with the home the decision belongs in. RouteHome = "home" )
The routes a hand-back takes, by kind (scope 5).
const ( StageRunner = "runner" StageFallback = "fallback" )
StageRunner is the record's stage for a role a runner ran, and StageFallback for one a runner did not.
const ( // Remote is the remote a lane lands through: the one the default branch // is read from. Remote = "origin" // LandDirName is the lane's directory the landing writes into. LandDirName = "land" // PRBodyFileName is the pull request's body as the loop composed it, and // PRStrippedFileName the body re-read from the forge and stripped. PRBodyFileName = "pr-body.md" PRStrippedFileName = "pr-body.stripped.md" // PreflightReceiptsRelDir is where the preflight mints its receipts, one // file named by the full commit id, in any worktree of the repository. PreflightReceiptsRelDir = TierRelDir + "/preflight-receipts" // RulesetsRelDir is the committed mirror of the default branch's rulesets. RulesetsRelDir = ".abcd/work/rulesets" )
The landing's fixed names.
const ( BundledWorkMinutes = 120 BundledPauseMinutes = 300 BundledSubAgents = 2 )
The bundled pace: 120 minutes of work, 300 of pause, two lanes (decision 5, the product thinker's numbers for this repository's runs on 2026-09-20). A repository that measured otherwise writes its own under `pace` in its .abcd/config.json.
const ( HandBackUserVisible = "user-visible" HandBackTrustRule = "trust-rule" HandBackDesignFinding = "design-finding" HandBackSecondPackage = "second-package" )
The kinds a lane hands an issue back as (itd-82: a reviewer's design finding, a second package, a user-visible change the remedy did not name, and a rule about trust or safety).
const ( StageTranscript = "transcript" StageRecord = "record" )
StageTranscript is the run record's stage for a captured transcript, and StageRecord the refusal stage of the record's own verb.
const ( HoldBeforePush = "push" HoldBeforeArm = "arm" )
The landing steps a hold stops before.
const ( RoleRuthless = "ruthless-reviewer" RoleSecurity = "security-reviewer" RoleAuditor = "intent-auditor" )
The validators, by the agent definition each is started as.
const ( ValidateDirName = "validate" FixDirName = "fix" ReturnFileName = "return.md" VerdictFileName = "verdict.json" AuditRequestFileName = "request.md" )
The files of a validation round.
const BranchPrefix = "build/"
BranchPrefix is the namespace every lane branch is cut under.
const BundledFixRounds = 3
BundledFixRounds is the fix rounds a lane may take before it is handed back when nothing sets it (ruling DR1 of 2026-09-29: "tied to the pace settings, a per-run value set alongside --pace, default 3"; itd-50 decision 2).
const CheckRun = "run"
CheckRun is the exclusion of a planned intent this checkout already has a run in progress for: the pick starts a run, never resumes one.
const ConventionsFile = "AGENTS.md"
ConventionsFile is the file a brief's conventions are read from.
const DecisionsLogRel = ".abcd/work/DECISIONS.md"
DecisionsLogRel is the append-only decision log the brief quotes entries of.
const DrainSchemaVersion = 1
DrainSchemaVersion is the drain state's shape.
const DrainStateRel = RunRelDir + "/drain.json"
DrainStateRel is the drain's state file, beside the runs. Its name is not a run id, so the run listing never reads it as one.
const ReceiptSchemaVersion = 1
ReceiptSchemaVersion is the receipt's shape.
const RoleImplementer = "implementer"
RoleImplementer is the agent the implement stage hands a lane to.
const RunIDFamily = "run"
RunIDFamily is the run id's prefix; the id is minted through the record-id seam (adr-45), so two checkouts starting runs in one second draw distinct ids.
const RunRelDir = TierRelDir + "/run"
RunRelDir is the directory every run of this checkout lives under.
const SchemaVersion = 9
SchemaVersion is the state file's shape. A file carrying a version this build does not know is refused rather than read as this one: a field a later build added and this one would drop on its next write is a run silently losing state.
Version 2 added the run's pace (itd-2609201925079472). Version 1 is its strict subset, so a version-1 file is read as a run started before the loop paced a run: it carries no pace, runs unpaced, and is written back at version 2 by its next mutation. A version-1 file carrying a pace is not one version 1 wrote, and is refused.
Version 3 added the pick `abcd build next` made (itd-2609211116005482): the run's `pick` and a lane's `pick_sha`. Versions 1 and 2 are its strict subsets, read as runs no pick started and written back at version 3; one of them carrying a pick is not one its version wrote, and is refused.
Version 4 renamed the lane's stage (BU1, iss-2609291313276243): a lane's and a record line's `step` became `stage`, so the word "step" names only the spec's steps. Versions 1 to 3 wrote `step`, and are migrated on read: the read carries each `step` over to `stage` and writes nothing, and the run's next mutation writes the file back at version 4, as it does for the versions before. One of them that already says `stage` is not one its version wrote, and is refused.
Version 5 added the validate stage's record (spc-2609202134338445 piece 8): a lane's `validation`, its rounds and the verdicts the loop recorded. Version 4 is its strict subset, read as a run no validator has judged yet and written back at version 5; a version-4 file carrying a validation is not one version 4 wrote, and is refused.
Version 6 added the fix-round cap (ruling DR1, 2026-09-29): the pace's `fix_rounds`, and a lane's `hand_back` when it takes its cap of fix rounds without passing. Version 5 is its strict subset, read as a run started before the pace carried the cap, which runs on the bundled one, and written back at version 6; a version-5 file carrying either is not one version 5 wrote, and is refused.
Version 7 added the landing and the run record's transcripts (spc-2609202134338445 pieces 9 and 10): a lane's `landing`, the captures its receipts declared fixed (`resolves`) and the receipts it verified (`receipts`, each with the model its runner reported), and the run's `transcripts`. Version 6 is its strict subset, read as a run nothing has landed yet and written back at version 7; a version-6 file carrying any of them is not one version 6 wrote, and is refused.
Version 8 added the runner's record (itd-2609201916056194, spc-2609202134338445 piece 3): the run's `fallbacks`, one receipt per role a runner did not run, and the `route` a verified receipt or a validator's return names when a runner, not the host, ran its agent. Version 7 is its strict subset, read as a run the host ran every agent of and written back at the current version; a version-7 file carrying either is not one version 7 wrote, and is refused.
Version 9 made a run work in parallel up to its ceiling (ruling DR6, spc-2609202134341288): a lane's `awaits`, a list replacing the one `awaiting`, the run's `waiting`, a lane's `syncs` and `hold`, a pending step's `needs`, and the lane stages `held` and `discarded`. A file of version 8 or lower reads as a run whose lanes each await zero or one agent (its `awaiting` becomes a one-entry `awaits`) and is written back at version 9; a landing's `check_wait_since` (ruling DR6d-2) is version 9's too, added before any release wrote the version; one of them carrying anything only version 9 writes is refused, and so is a version-9 file carrying `awaiting`, which version 9 never writes.
const StageClaim = "claim"
StageClaim is the refusal stage of a start whose shared-run claim is refused for a reason of the caller's own (a session that has not joined, a bound).
const StageDrain = "drain"
StageDrain is the refusal stage of the drain run.
const StagePace = "pace"
StagePace is the refusal stage of a pace or ceiling the loop cannot run on.
const StagePick = "pick"
StagePick is the refusal stage of a pick that takes nothing.
const StateFileName = "state.json"
StateFileName is the name of a run's state file inside its directory.
const SyncDirName = "sync"
SyncDirName is the lane's directory a sync's brief and receipt live in.
const TierRelDir = ".abcd/.work.local"
TierRelDir is the local-ephemeral tier the run state lives in. It is never created here.
const VerdictUnachievable = "unachievable"
VerdictUnachievable is the verdict a lane is handed back with: the run's fix rounds could not bring it to a passing round (itd-50's UNACHIEVABLE).
Variables ¶
var Sequence = []Stage{StageWorktree, StageBrief, StageImplement, StageValidate, StageLand}
Sequence is the lane's stages in the order the loop performs them: make the lane's worktree, render its brief, hand it to an implementer and take the receipt, run the validators, land it. A lane past its last stage is StageDone.
var WorktreeStoreRel = abcdhome.Rel("worktrees")
WorktreeStoreRel is the machine-scoped worktree store, relative to the caller's home.
Functions ¶
func DrainSummaryLine ¶ added in v0.12.0
func DrainSummaryLine(r DrainRoute) string
DrainSummaryLine is a route in one line, for the text surfaces.
func LatestRun ¶ added in v0.12.0
LatestRun names the run a record read addresses when none is named: the one run in progress when there is one, else the most recently started run in this checkout. Several runs in progress are refused, naming them.
func LoadRunners ¶ added in v0.12.0
LoadRunners reads the runner configuration (runner.Load) at the roots a lane starts from, and refuses in the loop's refusal shape on any fault, a model route its provider's allowlist does not admit included, before a run is created or a runner launched (itd-2609201916056194 criterion 5). The configuration's diagnostics are the caller's to print.
func Resolve ¶
Resolve names the run a call addresses. An explicit id is checked for shape and presence; no id addresses the one run in this checkout that is not complete, and is refused naming them when there are several, or none.
func StateRelPath ¶
StateRelPath is a run's state file, relative to the checkout root.
func StatusLanes ¶ added in v0.12.0
func StatusLanes(repoRoot string) ([]statusblock.Started, error)
StatusLanes is the state file read the status block's Now takes (itd-2609212103568351): one entry per run in progress, naming its intent and every lane of it alive (ruling DR6) — each lane's next stage and the roles it waits on, a held lane included — or, while no lane is alive and a spec step still waits, the run with its stage "pending". A complete run is not in a lane. An absent tier or run directory holds none. It is a statusblock.LaneReader.
func StatusPeers ¶ added in v0.12.0
func StatusPeers(repoRoot string) (statusblock.HeldBy, error)
StatusPeers is the peers read the status block's head takes (ruling CC1 of 2026-09-29): build next's own peers check, read once for the block and judged per intent, so the board's "next up" passes over exactly the intents another checkout holds that the pick passes over. It judges on behalf of no session, so every live claim is a peer's. A peer the listing cannot read fails closed on each record, as it does for the pick. It is a statusblock.PeerReader.
func ValidLaneID ¶
ValidLaneID reports whether id is a lane id the loop opens.
func ValidRunID ¶
ValidRunID reports whether id is a run id this package mints.
Types ¶
type AliveLane ¶ added in v0.13.0
type AliveLane struct {
Lane string `json:"lane"`
SpecStep int `json:"spec_step"`
Stage Stage `json:"stage"`
Awaits []Await `json:"awaits"`
Hold *Hold `json:"hold,omitempty"`
// Waiting is the lane's wait for its full check, with the time it began
// (ruling DR6d-2); empty when it waits for none.
Waiting string `json:"waiting,omitempty"`
}
AliveLane is one lane of a run with anything left, as a result reports it.
type AuditRun ¶ added in v0.12.0
type AuditRun struct {
ReceiptID string `json:"receipt_id"`
Request string `json:"request"`
// BaseSHA..HeadSHA is the whole delivery: from the base of the run's first
// lane to this lane's head.
BaseSHA string `json:"base_sha"`
HeadSHA string `json:"head_sha"`
// Worst, NotMet and Inconclusive are read from the verdict.
Worst string `json:"worst,omitempty"`
NotMet []string `json:"not_met,omitempty"`
Inconclusive []string `json:"inconclusive,omitempty"`
}
AuditRun is the fidelity audit the lane that closes the spec takes, once, over the whole delivery (ruling AI): the receipt the close parks for the same record, the request, the range it reads, and what the loop read from the verdict. The verdict itself is the return the run names; the close consumes it (piece 9).
type Await ¶
type Await struct {
// Role is the agent the host starts: an implementer, or a validator that
// did not implement.
Role string `json:"role"`
// Brief is the file the agent is handed.
Brief string `json:"brief"`
// Receipt is where the agent writes its receipt; `implement receipt` is
// called with this path.
Receipt string `json:"receipt"`
Since time.Time `json:"since"`
}
Await is what a lane waits on: the agent a host must start, the brief it is handed and the receipt it writes.
type CandidateSet ¶ added in v0.12.0
type CandidateSet struct {
// Candidates pass every check, in the pick order.
Candidates []intent.PickCandidate `json:"candidates"`
// Excluded fail one, in record order.
Excluded []Excluded `json:"excluded"`
}
CandidateSet is the pick's view of the planned intents.
type CheckResult ¶
type CheckResult struct {
Key string `json:"key"`
Intent string `json:"intent,omitempty"`
Spec string `json:"spec,omitempty"`
OK bool `json:"ok"`
Checks []CheckRow `json:"checks"`
// contains filtered or unexported fields
}
CheckResult is every pre-start check for one key.
func Check ¶
func Check(repoRoot, key string) (CheckResult, error)
Check runs the pre-start checks for key against the checkout at repoRoot. It returns an error only for a fault in reading this checkout (the store will not load, git will not answer); a record that may not start is a result with OK false.
The rows, in order:
- key: an intent id, or an issue id (decision 10's key). An issue key takes two rows after it and no others: eligible (the drained repository's own rule takes the issue, as `abcd drain` reads it) and peers (no peer holds it out of open/, and no session claims it).
- ready: the implement-readiness gate (intent.Ready) — planned, criteria, the spec linked and written. Its advisory rows stay advisory here.
- open_questions: no open question under `## Open Questions` (intent.StartChecksIn: every list item, less the settled markers).
- claim_sections: no unanswered claim section — the mechanism prompt answered or the section absent, the scope conditions recorded.
- hold: no `held:` on the record (iss-2609200830076665).
- blocked: nothing the record names in `blocked_by` is unshipped (itd-2609211116005482: an intent with an unshipped blocker is not one a run may take); a superseded blocker is followed along `superseded_by` to its replacement, transitively (ruling BZ2 of 2026-09-29).
- steps: the spec's `## Steps` reads, and leaves a step to build.
- peers: no peer holds the record — no sibling worktree or local branch holds it in another bucket, and no session holds a live claim on it.
type CheckRow ¶
type CheckRow struct {
Name string `json:"name"`
OK bool `json:"ok"`
Detail string `json:"detail"`
Remedy string `json:"remedy,omitempty"`
// contains filtered or unexported fields
}
CheckRow is one pre-start check's verdict.
type Context ¶
type Context struct {
RepoRoot string
// RunDir is the run's directory, relative to RepoRoot.
RunDir string
State State
Now time.Time
// Await is the await a verifier is handed the receipt of; nil for a body.
Await *Await
}
Context is what a stage's body is handed: where the checkout and the run live, the run as it stood before the stage, and the clock.
type DoDRun ¶
type DoDRun struct {
Command string `json:"command"`
ExitCode *int `json:"exit_code"`
// Output is the run's whole output, a path inside the lane's directory.
Output string `json:"output"`
}
DoDRun is one run of the definition of done.
type DrainLane ¶ added in v0.12.0
type DrainLane struct {
Issue string `json:"issue"`
RunID string `json:"run_id"`
OpenedAt time.Time `json:"opened_at"`
Outcome string `json:"outcome"`
PR int `json:"pr,omitempty"`
}
DrainLane is one issue the drain handed to a lane.
type DrainOptions ¶ added in v0.12.0
type DrainOptions struct {
// Max is --max as typed; 0 when not given, which is all.
Max int
}
DrainOptions are the drain's own flags.
type DrainResult ¶ added in v0.12.0
type DrainResult struct {
State string `json:"state"`
// Started is true when this invocation began a new drain.
Started bool `json:"started"`
Rule string `json:"rule"`
Loosened []string `json:"loosened"`
Order string `json:"order"`
Max int `json:"max"`
Pace *Pace `json:"pace"`
// Lanes are every lane the drain opened, with its outcome as last read.
Lanes []DrainLane `json:"lanes"`
// Lane is the lane in progress after this call, if any.
Lane *DrainLane `json:"lane"`
// Start is the run this call started, when it opened a lane.
Start *StartResult `json:"start"`
// Routed are the hand-backs this call routed; HandBacks every one the
// drain has routed; Flags the rule's hand-backs over the ledger as this
// call read it, each naming its rule, written nowhere.
Routed []DrainRoute `json:"routed"`
HandBacks []DrainRoute `json:"hand_backs"`
Flags []DrainRoute `json:"flags"`
// Passed are eligible issues this call did not take, each with why.
Passed []Excluded `json:"passed"`
Dispositions []capture.DrainVerdict `json:"dispositions"`
NextEligibleAt *time.Time `json:"next_eligible_at"`
Stopped string `json:"stopped,omitempty"`
Complete bool `json:"complete"`
Next string `json:"next"`
}
DrainResult is one drain invocation's summary.
func Drain ¶ added in v0.12.0
func Drain(repoRoot string, o Options, d DrainOptions) (DrainResult, error)
Drain performs one move of the drain run: it begins a drain when none is in progress, honours the window clock, routes the last lane's outcome, and opens the next eligible issue's lane, or says why it opens none. A drain without the repository's rule is refused before anything is written.
type DrainRoute ¶ added in v0.12.0
type DrainRoute struct {
Issue string `json:"issue"`
// From is "lane" for a lane's hand-back, "field" for the rule's.
From string `json:"from"`
Kind string `json:"kind"`
Route string `json:"route"`
// Draft is the intent draft a promotion made; Question the question a
// decision-record flag states; Rule the rule a field hand-back names; Home
// the home a flag names.
Draft string `json:"draft,omitempty"`
Question string `json:"question,omitempty"`
Rule string `json:"rule,omitempty"`
Home string `json:"home,omitempty"`
Reason string `json:"reason"`
// Wrote is the record change the route made, in words; "nothing" for a
// flag.
Wrote string `json:"wrote"`
At *time.Time `json:"at,omitempty"`
}
DrainRoute is one hand-back and where it went.
type DrainState ¶ added in v0.12.0
type DrainState struct {
SchemaVersion int `json:"schema_version"`
StartedAt time.Time `json:"started_at"`
UpdatedAt time.Time `json:"updated_at"`
// Rule is the decision record the rule was read from when the drain began.
Rule string `json:"rule"`
// Max is the cap on lanes the drain opens; 0 is all (the default).
Max int `json:"max"`
// Pace is the pace the drain started on; its window and pause bound the
// drain as they bound a run.
Pace *Pace `json:"pace"`
WindowStartedAt *time.Time `json:"window_started_at,omitempty"`
NextEligibleAt *time.Time `json:"next_eligible_at,omitempty"`
Lanes []DrainLane `json:"lanes"`
HandBacks []DrainRoute `json:"hand_backs"`
// Stopped says why the drain ended, and EndedAt when; empty while it runs.
Stopped string `json:"stopped,omitempty"`
EndedAt *time.Time `json:"ended_at,omitempty"`
}
DrainState is one drain, between invocations.
type Driver ¶
type Driver string
Driver names what drives the loop. The host session is decision 5's default; the process driver is piece 3's, opt-in by configuration.
const DriverHost Driver = "host"
DriverHost is a host session calling `implement step` and `implement receipt` itself.
type Entry ¶
type Entry struct {
At time.Time `json:"at"`
Lane string `json:"lane,omitempty"`
// Stage is the stage the entry records: a lane stage, "start", "open" (a
// later lane opened for its spec step) or "receipt".
Stage string `json:"stage"`
Note string `json:"note,omitempty"`
}
Entry is one line of the run record.
type Excluded ¶ added in v0.12.0
type Excluded struct {
ID string `json:"id"`
Check string `json:"check"`
Reason string `json:"reason"`
}
Excluded is a planned intent the pick did not consider, with the first check that excluded it.
type HandBack ¶ added in v0.12.0
type HandBack struct {
At time.Time `json:"at"`
// Kind, Reason and Home are set when the lane's own receipt handed the work
// back (itd-82 scope 5): the kind of decision it found, what it found, and
// where the decision belongs. Discarded is the lane's head the loop
// discarded with its worktree and branch. The fields below are then empty.
Kind string `json:"kind,omitempty"`
Reason string `json:"reason,omitempty"`
Home string `json:"home,omitempty"`
Discarded string `json:"discarded,omitempty"`
// Verdict is VerdictUnachievable.
Verdict string `json:"verdict,omitempty"`
// Round is the round that did not pass once the cap was reached, and
// FixRounds the cap the run held the lane to.
Round int `json:"round,omitempty"`
FixRounds int `json:"fix_rounds,omitempty"`
// Verdicts is the last round's verdicts as the loop recorded them, and
// Findings the returns of the validators that did not pass, relative to
// the checkout root.
Verdicts string `json:"verdicts,omitempty"`
Findings []string `json:"findings,omitempty"`
// NotMet and Undecided name the criteria the last audit judged not met and
// could not decide, when the lane took the audit.
NotMet []string `json:"not_met,omitempty"`
Undecided []string `json:"undecided,omitempty"`
}
HandBack is a lane stopped and handed back to the person, with what the last round found (ruling DR1 on itd-50's criterion 2).
type Handler ¶
Handler performs one stage for a lane, writing what it made into lane. It must be idempotent: a process killed after the body's effect and before the state write runs the body again on the next call, so a body finds what it made last time rather than making it twice. An error leaves the state as it was; a *Refusal error is passed to the caller as the refusal.
type Hold ¶ added in v0.13.0
type Hold struct {
Since time.Time `json:"since"`
Cause string `json:"cause"`
Head string `json:"head"`
Before string `json:"before"`
Released bool `json:"released,omitempty"`
}
Hold is a lane held after a sibling's hand-back (ruling DR6c): when, the handed-back lane that caused it, the head its passing round judged, and the landing step it stopped before (HoldBeforePush or HoldBeforeArm). Released is set once the person released it to land as it is.
type Landing ¶ added in v0.12.0
type Landing struct {
// Closes is whether this lane's landing closes the spec (and ships the
// intent): the lane that took the fidelity audit.
Closes bool `json:"closes"`
// Records is the loop's records commit on the lane's branch, and
// RecordsDone is set once it is made, or once there was nothing to record.
Records string `json:"records,omitempty"`
RecordsDone bool `json:"records_done"`
// PreflightReceipt is the preflight receipt that named the pushed head,
// home-redacted, and Pushed the head the loop pushed.
PreflightReceipt string `json:"preflight_receipt,omitempty"`
Pushed string `json:"pushed,omitempty"`
// Body is the pull request's body as the loop composed it, relative to the
// checkout root; PRURL is the pull request, and BodyChecked is set once the
// body the forge holds was re-read and found clean.
Body string `json:"body,omitempty"`
PRURL string `json:"pr_url,omitempty"`
BodyChecked bool `json:"body_checked"`
// Merge is the merge rule the ruleset gave, and Armed whether auto-merge
// was armed by it. Nothing is pushed to the lane once Merge is set.
Merge string `json:"merge,omitempty"`
Armed bool `json:"armed"`
// Merged is the default branch's tip, as the remote held it, that carried
// the pushed head when the landing cleaned the lane up.
Merged string `json:"merged,omitempty"`
// CheckWaitSince is when the landing began waiting for its full check: the
// preflight receipt naming the head it pushes (ruling DR6d-2). It is set
// by the first call that finds no receipt, kept until the push, and
// cleared by it.
CheckWaitSince *time.Time `json:"check_wait_since,omitempty"`
}
Landing is the land stage's progress on one lane.
type Lane ¶
type Lane struct {
// ID is the lane's name inside the run: lane-1, lane-2, ….
ID string `json:"id"`
// Key is the record the lane delivers: itd-N, or iss-N (decision 10).
Key string `json:"key"`
// SpecStep is the number of the spec step the lane lands, and StepTitle its
// title. An unstepped spec is one implicit step, number 1.
SpecStep int `json:"spec_step"`
StepTitle string `json:"step_title"`
// Stage is the next stage the loop performs for this lane; StageDone when the
// lane has nothing left.
Stage Stage `json:"stage"`
// Awaits are the agents the lane waits on: one while its implementer
// works, one per validator while its round is out. Each is a slot of the
// run's ceiling until its receipt is verified (criterion 8, ruling DR6).
Awaits []Await `json:"awaits,omitempty"`
// Syncs are the merges of the default branch into the lane after a sibling
// landed; Hold is set while the lane is held after a sibling's hand-back.
Syncs []Sync `json:"syncs,omitempty"`
Hold *Hold `json:"hold,omitempty"`
// The lane's footprint, filled by the stages that make it.
Branch string `json:"branch,omitempty"`
BaseSHA string `json:"base_sha,omitempty"`
HeadSHA string `json:"head_sha,omitempty"`
Worktree string `json:"worktree,omitempty"`
Brief string `json:"brief,omitempty"`
Receipt string `json:"receipt,omitempty"`
PR int `json:"pr,omitempty"`
// PickSHA is the record-only commit at the branch base carrying the run's
// pick entry, on the lane a picked run commits it on; the receipt verifier
// counts the implementer's commits from after it.
PickSHA string `json:"pick_sha,omitempty"`
// Validation is the validate stage's record (piece 8): one round per head
// the validators judged, the last the current one. Only the loop writes a
// verdict into it, parsed from the validator's own return (itd-58).
Validation []ValidationRound `json:"validation,omitempty"`
// HandBack is set when the lane was stopped and handed back to the person:
// its Stage is then StageHandedBack.
HandBack *HandBack `json:"hand_back,omitempty"`
// Receipts are the implementers' receipts the loop verified for the lane,
// the implement stage's and each fix round's, with the model each runner
// reported (criterion 10).
Receipts []ReceiptRecord `json:"receipts,omitempty"`
// Resolves are the captures the lane's receipts declared fixed, each with
// the lane's commit that fixed it; the landing resolves each (piece 9).
Resolves []Resolution `json:"resolves,omitempty"`
// Landing is the landing stage's progress (piece 9): each of its steps is
// recorded as it completes, so a killed landing resumes at the step that
// did not.
Landing *Landing `json:"landing,omitempty"`
}
Lane is one lane: one spec step, one branch, one pull request.
type LaneHandBack ¶ added in v0.12.0
type LaneHandBack struct {
Kind string `json:"kind"`
Reason string `json:"reason"`
Home string `json:"home,omitempty"`
}
LaneHandBack is a lane's own hand-back: the kind of decision it found, the reason in a sentence, and, for the kinds routed to a home, where the decision belongs.
type LaneReceipt ¶
type LaneReceipt struct {
SchemaVersion int `json:"schema_version"`
RunID string `json:"run_id"`
Lane string `json:"lane"`
Branch string `json:"branch"`
// Commits are the full object names of the commits the implementer made on
// the lane's branch.
Commits []string `json:"commits"`
// DefinitionOfDone is the repository's definition of done as the
// implementer ran it.
DefinitionOfDone *DoDRun `json:"definition_of_done"`
// Report is the implementer's report, a path inside the lane's directory.
Report string `json:"report"`
// Model is the model the implementer's harness reported, as reported: the
// binary cannot verify it.
Model string `json:"model,omitempty"`
// Resolves are the captures the lane fixed, each with the commit of the
// lane that fixed it and the judgements a resolution records; the landing
// resolves each with `capture resolve` (spec piece 9).
Resolves []Resolution `json:"resolves,omitempty"`
// HandBack stops the lane: the implementer found a decision inside the
// work and hands it back rather than deciding it (itd-82 scope 5, the
// `handback:` of decision 10 on the parent). The loop reads it before the
// validators, discards the lane's work and ends the lane with it.
HandBack *LaneHandBack `json:"handback,omitempty"`
}
LaneReceipt is the file an implementer writes when its lane is built.
type LaneWorktree ¶
type LaneWorktree struct {
// Home is the caller's home, the base the store is proved real from.
Home string
// RootSHA keys the store on the repository.
RootSHA string
// StoreRel is the lane's store directory, relative to Home.
StoreRel string
// Path is the worktree, Home/StoreRel/<name>.
Path string
// Branch is the lane's branch, build/<name>.
Branch string
}
LaneWorktree is where a lane's worktree lives and what it is called.
type NextOptions ¶ added in v0.12.0
type NextOptions struct {
// Max is --max as typed; 0 when not given.
Max int
// UntilEmpty is --until-empty.
UntilEmpty bool
}
NextOptions are the run count the caller asked for.
type NextResult ¶ added in v0.12.0
type NextResult struct {
CandidateSet
Pick intent.Pick `json:"pick"`
Entry string `json:"entry"`
Start StartResult `json:"start"`
}
NextResult is what Next returns: the candidate set, the pick, the entry it writes, and the run it started.
func Next ¶ added in v0.12.0
func Next(repoRoot string, o Options, n NextOptions) (NextResult, error)
Next picks the readiest planned intent and starts its run. A run count past one is refused (criterion 5 is not built here); an empty candidate set is refused naming every excluded intent and its check, and writes nothing. The pick's entry is checked against the grounds writer's own gate before the run starts, so a pick never starts a run whose reason it cannot write.
type Options ¶
type Options struct {
// Now is the clock; nil means time.Now.
Now func() time.Time
// Minter mints the run id; the zero value is production.
Minter recordid.Minter
// Session is the joined session of the shared run state
// (~/.abcd.noindex/runs/<root-sha>/) a new run is started for. When set, Start
// claims the intent for it there, so a build of the same intent from any
// other checkout of the repository sees the run before its lane has moved
// or claimed anything (iss-2609252050506863). Empty, the run holds no
// claim and is invisible to another checkout until its lane shows.
Session string
// Pace, SubAgents and FixRounds are the --pace, --sub-agents and
// --fix-rounds flags as typed; nil when the flag was not given. They set a
// new run's pace over every configured layer.
Pace, SubAgents, FixRounds *string
// Roots are where the pace's configuration layers are read; nil reads
// them at layered.RootsFor(repoRoot).
Roots *layered.Roots
}
Options are the seams tests set; the zero value is production.
type Outcome ¶
type Outcome struct {
Await *Await
// HandBack stops the lane: it is handed back to the person with what the
// stage found, and the loop starts nothing further for it (itd-50,
// criterion 2). Set only with no Await.
HandBack *HandBack
// Stay records a step of a stage that takes several invocations (the
// landing): the lane's changes are written and the record gets the note,
// and the lane stays at the stage for the next invocation's step. Set only
// with no Await and no HandBack.
Stay bool
// Goto sends the lane back to an earlier stage (the landing's sync sends
// it to a fresh round); set only with no Await, HandBack or Stay.
Goto Stage
// Note is the run record's line for the stage.
Note string
}
Outcome is what a stage's body returns. A body that hands its work to an agent returns Await: the lane then waits on the receipt it names and the stage completes only when Receipt verifies it.
type Pace ¶ added in v0.12.0
type Pace struct {
WorkMinutes PaceValue `json:"work_minutes"`
PauseMinutes PaceValue `json:"pause_minutes"`
SubAgents PaceValue `json:"sub_agents"`
FixRounds PaceValue `json:"fix_rounds,omitzero"`
}
Pace is a run's pace: the working window, the pause after it, the ceiling on this run's lanes and validators alive at once, and the fix rounds a lane may take before it is handed back. FixRounds is zero in a run a state file before version 6 holds: it started before the pace carried the cap, and FixRoundCap reads the bundled value for it.
type PaceValue ¶ added in v0.12.0
type PaceValue struct {
Value int `json:"value"`
Layer string `json:"layer"`
Origin string `json:"origin"`
}
PaceValue is one of the pace's numbers with the layer that supplied it: "flag", "repo", "machine" or "bundled", and the origin — the flag as typed, the file, or "bundled".
type PendingStep ¶
type PendingStep struct {
Number int `json:"number"`
Title string `json:"title"`
// Needs are the spec steps it waits for, as its `- needs:` line or the
// default (every earlier step, ruling DR6b) resolved them; nil in a file
// before version 9, which reads as the default.
Needs []int `json:"needs"`
}
PendingStep is a spec step the run will open a lane for.
type ReceiptRecord ¶ added in v0.12.0
type ReceiptRecord struct {
Role string `json:"role"`
Receipt string `json:"receipt"`
// Model is the model the runner reported, as reported; empty when it
// reported none. The binary cannot verify it.
Model string `json:"model,omitempty"`
// Route is the route that ran the agent when a runner ran it: the runner
// asked for, the one that ran and the model it reported. Absent when the
// host ran it, so a host-run receipt reads as it always has.
Route *runner.RouteRecord `json:"route,omitempty"`
}
ReceiptRecord is one implementer's receipt the loop verified.
type RecordLane ¶ added in v0.12.0
type RecordLane struct {
ID string `json:"id"`
Key string `json:"key"`
SpecStep int `json:"spec_step"`
StepTitle string `json:"step_title"`
Stage Stage `json:"stage"`
Branch string `json:"branch,omitempty"`
BaseSHA string `json:"base_sha,omitempty"`
HeadSHA string `json:"head_sha,omitempty"`
// Receipts are the implementers' receipts the loop verified, each with the
// model its runner reported.
Receipts []ReceiptRecord `json:"receipts"`
// Verdicts are every verdict the loop recorded, round by round.
Verdicts []RecordVerdict `json:"verdicts"`
// Resolves are the captures the lane fixed.
Resolves []string `json:"resolves"`
// PR is the lane's pull request, and Landing what its landing did.
PR int `json:"pr,omitempty"`
Landing *Landing `json:"landing,omitempty"`
HandBack *HandBack `json:"hand_back,omitempty"`
}
RecordLane is one lane of the run record.
type RecordVerdict ¶ added in v0.12.0
type RecordVerdict struct {
Round int `json:"round"`
HeadSHA string `json:"head_sha"`
Role string `json:"role"`
Verdict string `json:"verdict"`
Pass bool `json:"pass"`
// Return is the validator's return the verdict was parsed from.
Return string `json:"return"`
// Route is the runner route that ran the validator; absent when the host
// ran it.
Route *runner.RouteRecord `json:"route,omitempty"`
}
RecordVerdict is one verdict the loop recorded from a validator's return.
type Refusal ¶
type Refusal struct {
// Stage is where the loop refused: "check" before a run starts, "state" for
// a run that cannot be read, "pause" for the window clock, or the lane stage
// ("worktree", "implement", …) and "receipt" inside a run.
Stage string `json:"stage"`
// Check names the pre-start check that failed, when Stage is "check".
Check string `json:"check,omitempty"`
// Lane names the lane, inside a run.
Lane string `json:"lane,omitempty"`
Reason string `json:"reason"`
Remedy string `json:"remedy"`
// Contention marks a refusal that is somebody else's hold rather than the
// caller's fault — a peer holding the record, a run locked by another
// invocation, a pause: back off and take other work. The CLI maps it to
// exit 3, as `abcd implement` does.
Contention bool `json:"contention,omitempty"`
// Checks is every pre-start check's row, when Stage is "check", so a caller
// sees the whole picture rather than the first failure.
Checks []CheckRow `json:"checks,omitempty"`
// Excluded is every planned intent a pick excluded and the check that
// excluded it, when a pick found no candidate.
Excluded []Excluded `json:"excluded,omitempty"`
// contains filtered or unexported fields
}
Refusal is the one shape every refusal of the loop takes (criterion 13): the stage it happened at, the reason and the remedy, in text and in --json. A refusal writes nothing: the state file is as it was before the call, except for the time a landing began waiting for its full check (ruling DR6d-2), which the call that finds the wait writes once, whatever the call answers.
type Resolution ¶ added in v0.12.0
type Resolution struct {
Issue string `json:"issue"`
Commit string `json:"commit"`
Note string `json:"note"`
Impact string `json:"impact"`
Grounds string `json:"grounds"`
}
Resolution is one capture a lane fixed: the issue, the lane's commit that fixed it, and what `abcd capture resolve` records — the note, the product impact and the grounds. The loop checks the shape and that the commit is one the receipt names; the capture store judges the rest when the landing resolves it.
type RunPick ¶ added in v0.12.0
type RunPick struct {
// Lane is the lane whose branch carries the pick's entry as its first
// commit: the run's first lane.
Lane string `json:"lane"`
// Entry is the grounds entry's text, written after the `pursued:` token.
Entry string `json:"entry"`
// Pick is the choice: the candidates in the pick order with their scores,
// the rule, the runner-up.
Pick intent.Pick `json:"pick"`
// Excluded are the planned intents the checks excluded.
Excluded []Excluded `json:"excluded"`
}
RunPick is the pick a run was started from, as the state carries it.
type RunRecord ¶ added in v0.12.0
type RunRecord struct {
RunID string `json:"run_id"`
Key string `json:"key"`
Intent string `json:"intent"`
Spec string `json:"spec"`
Driver Driver `json:"driver"`
Complete bool `json:"complete"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
// Pace is the pace the run ran on, nil for a run started before the loop
// paced a run.
Pace *Pace `json:"pace"`
Lanes []RecordLane `json:"lanes"`
Pending []PendingStep `json:"pending"`
Transcripts []Transcript `json:"transcripts"`
// Fallbacks are the run's fallback receipts, and FallbackCounts their
// count per runner asked for and per role (itd-2609201916056194
// criterion 4).
Fallbacks []runner.FallbackReceipt `json:"fallbacks"`
FallbackCounts runner.Counts `json:"fallback_counts"`
Record []Entry `json:"record"`
}
RunRecord is a run's record as it is read at the end.
func CaptureTranscripts ¶ added in v0.12.0
func CaptureTranscripts(repoRoot, runID string, paths []string, capture TranscriptCapturer, o Options) (RunRecord, error)
CaptureTranscripts captures each path into the history store through capture, one capture per path, and records each in the run's state. It is refused on a run that is not complete: the record's transcripts are the run's, captured at its end. A capture that fails stops the call: the ones before it are recorded, and the refusal names the path that failed, so the call can be made again with the rest. A path captured before is captured again (the store's capture is idempotent) and recorded once.
func ReadRecord ¶ added in v0.12.0
ReadRecord reads a run's record.
type Runners ¶ added in v0.12.0
type Runners struct {
// Config is the runner configuration read when the call began
// (runner.Load); nil drives nothing and leaves every role on the host.
Config *runner.Config
// Transcripts is where each runner's transcript lands: abcd's own store
// (runner.HistoryStore) in production.
Transcripts runner.TranscriptStore
// Timeout bounds one runner's run; runner.DefaultTimeout when zero.
Timeout time.Duration
}
Runners is what the process driver starts a routed role through.
type Stage ¶ added in v0.12.0
type Stage string
Stage is one stage of a lane: the loop performs a lane's stages in order, and the lane as a whole lands one step of the spec (a spec's steps keep that word; BU1, iss-2609291313276243).
const ( StageWorktree Stage = "worktree" StageBrief Stage = "brief" StageImplement Stage = "implement" StageValidate Stage = "validate" StageLand Stage = "land" StageDone Stage = "done" // StageHandedBack is a lane that took its run's cap of fix rounds and still // did not pass (itd-50, criterion 2): the loop starts nothing further for // it, and its intent is the person's to replan. StageHandedBack Stage = "handed-back" // StageHeld is a lane whose round passed after a sibling was handed back // (ruling DR6c): it holds no slot, starts nothing and is never armed until // the person releases it (`implement step --release`) or discards it. StageHeld Stage = "held" // StageDiscarded is a held lane the person discarded: its pull request // closed, its worktree and branch removed, its step left unlanded. StageDiscarded Stage = "discarded" )
The lane's stages, in the order Sequence performs them. StageDone is the state of a lane with nothing left to do, and StageHandedBack of a lane stopped and handed back to the person; neither is a stage with a body.
type StageDef ¶ added in v0.12.0
StageDef is one stage of the lane sequence: its name, the spec piece that delivers its body, and the body — nil when this build does not carry it.
A stage that hands the lane to several agents in turn (the validators, and the fresh implementer their findings go to) sets Repeats: a verified receipt then returns the lane to the stage's body rather than completing the stage, and the body decides, on the next step, whom it hands the lane to next or that the stage is complete.
type Stages ¶ added in v0.12.0
type Stages []StageDef
Stages is the lane sequence with its bodies.
func DefaultStages ¶ added in v0.12.0
func DefaultStages() Stages
DefaultStages is the lane sequence this build carries, each stage with the spec piece that delivers its body: the worktree (lane.go), the brief (brief.go), the implement stage with its receipt's verifier (receipt.go) and the validators with theirs (validate.go), and the landing (land.go).
type StartResult ¶
type StartResult struct {
RunID string `json:"run_id"`
// State is the state file, relative to the checkout root.
State string `json:"state"`
// Resumed is true when a live run for the key already existed: the call
// created nothing and names that run.
Resumed bool `json:"resumed"`
Lane Lane `json:"lane"`
Pending []PendingStep `json:"pending"`
// Checks are the pre-start checks' rows when the call created the run; a
// resumed start runs none, and carries none.
Checks []CheckRow `json:"checks"`
// Claim is the shared-run claim a new run took for Options.Session; nil when
// no session was named or the start resumed a run, and then null in the
// JSON, never absent, so the payload says the run holds no claim.
Claim *implement.ClaimResult `json:"claim"`
// Pace is the run's pace, each number with the layer that supplied it.
// Null for a run started before the loop paced a run.
Pace *Pace `json:"pace"`
// HandBack is set when the run's lane stands handed back to the person.
HandBack *HandBack `json:"hand_back,omitempty"`
Next string `json:"next"`
}
StartResult is what Start returns.
func Start ¶
func Start(repoRoot, key string, o Options) (StartResult, error)
Start resumes the live run for key, or runs the checks and, when every one passes, creates the run: the state file with one lane at the sequence's first stage, the spec's other unlanded steps pending, and the record's first line. A refused check writes nothing.
A live run for the same key in this checkout is looked up first, under the lock, and resumed — named, not duplicated, and not re-judged. The checks judged the record when the run was created; since then the run's own lanes change the tree they read (a lane's worktree moves the intent to shipped/, a lane claims it), so judging again would refuse the run as its own peer. So starting again after a kill loses nothing and repeats nothing, and the checks run only when a run is created. Only the key's shape is checked before the lookup, so a path is never built from a key that is not an intent id.
With o.Session named, a new run also claims its intent in the shared run state for that session, with the run id as the lane and the longest lease a claim takes: the peers check then counts that session's own live claim on the intent as its own, and a build from another checkout counts it as a peer's. A session that has not joined is refused before anything is created; a claim refused under the lock (a racing holder, a second session's bound) leaves no run behind; and a run whose state cannot be written releases the claim it took.
type State ¶
type State struct {
SchemaVersion int `json:"schema_version"`
// RunID names the run and its directory.
RunID string `json:"run_id"`
// Key is the record the run was started for: an intent id, or an issue id
// (decision 10), for which Intent and Spec are empty.
Key string `json:"key"`
// Intent and Spec are the intent the run delivers and the open spec it
// builds against, as the readiness gate judged them.
Intent string `json:"intent"`
Spec string `json:"spec"`
// Driver is what drives the loop (DriverHost unless configured).
Driver Driver `json:"driver"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
// WindowStartedAt and NextEligibleAt are the window clock the pacing intent
// (itd-2609201925079472) writes and reads. The loop honours NextEligibleAt:
// before it, a stage is refused as a pause and nothing moves (decision 2).
WindowStartedAt *time.Time `json:"window_started_at,omitempty"`
NextEligibleAt *time.Time `json:"next_eligible_at,omitempty"`
// Pace is the pace the run started on, each number with the layer that
// supplied it (itd-2609201925079472). Nil in a run a version-1 state file
// holds: it started before the loop paced a run, and runs unpaced.
Pace *Pace `json:"pace,omitempty"`
// Pick is the pick `abcd build next` made to start the run: the
// candidates, their scores and the grounds entry its first lane commits.
// Nil for a run `abcd build <itd-N>` started.
Pick *RunPick `json:"pick,omitempty"`
// Lanes are the lanes opened so far, in the order they opened; several may
// be open at once, up to the ceiling (ruling DR6). A lane lands one step of
// the spec's `## Steps` (the whole spec when it lists none).
Lanes []Lane `json:"lanes"`
// Waiting is the work the ceiling holds back: each item's lane, role and
// the time the ceiling first held it. An item leaves it when it takes a
// slot, with a record entry naming the minutes it waited.
Waiting []Waiting `json:"waiting,omitempty"`
// Pending are the spec's unlanded steps no lane has been opened for yet.
Pending []PendingStep `json:"pending"`
// Record is the run record, accumulated as stages complete.
Record []Entry `json:"record"`
// Transcripts are the transcripts the run's record captured into the
// history store once the run was complete, one capture per path (piece 10).
Transcripts []Transcript `json:"transcripts,omitempty"`
// Fallbacks are the run's fallback receipts, one per role a runner it was
// routed to did not run (itd-2609201916056194 criterion 3): the role, the
// runner asked for, the reason and the route that ran instead. The run's
// summary counts them per runner and per role (runner.Tally).
Fallbacks []runner.FallbackReceipt `json:"fallbacks,omitempty"`
}
State is one run: everything the loop needs between two invocations.
func ReadState ¶
ReadState is the state file's one reader. It refuses a run id of the wrong shape before building a path from it, reads through the checkout's os.Root (so a symlinked component cannot walk the read out of the checkout), decodes strictly — an unknown field is a file some other writer produced — and holds the file to the version and the id it is stored under.
func Runs ¶
Runs lists this checkout's runs, oldest first. An absent tier or run directory holds none. A state file that cannot be read fails the listing, naming it: a run the loop cannot read is not one it may skip past.
func (State) Complete ¶
Complete reports whether the run has nothing left: every lane is done and no spec step is waiting for one.
func (State) FixRoundCap ¶ added in v0.12.0
FixRoundCap is the fix rounds a lane of the run may take before it is handed back: the run's own, or the bundled value for a run that started before the pace carried one (an unpaced run, or a state file before version 6).
func (State) Issue ¶ added in v0.12.0
Issue is the issue an issue-keyed run fixes (decision 10), or "" for a run that builds an intent.
func (State) SlotsInUse ¶ added in v0.13.0
SlotsInUse is the agents the run has out: its outstanding awaits.
type StepResult ¶
type StepResult struct {
RunID string `json:"run_id"`
Lane string `json:"lane,omitempty"`
// PerformedStage is the stage this call completed; empty when it completed none
// (the lane awaits a receipt, or the run is complete).
PerformedStage Stage `json:"performed_stage,omitempty"`
// Stage is the lane's next stage after the call.
Stage Stage `json:"stage,omitempty"`
// Awaiting is what the lane waits on, when it waits on an agent.
Awaiting *Await `json:"awaiting,omitempty"`
Complete bool `json:"complete"`
// NextEligibleAt is set when this call closed the run's window: nothing
// was performed, and no stage is taken before this time.
NextEligibleAt *time.Time `json:"next_eligible_at,omitempty"`
// HandBack is set when the lane was handed back to the person: this call
// stopped it, or it stood stopped when the run was started again.
HandBack *HandBack `json:"hand_back,omitempty"`
// Slots is the agents the run has out after the call, and Ceiling the most
// it may have (the run's pace.sub_agents); CeilingReached is set when this
// call found every slot taken and handed nothing out.
Slots int `json:"slots"`
Ceiling int `json:"ceiling"`
CeilingReached bool `json:"ceiling_reached,omitempty"`
// Alive is every lane of the run with anything left, with its stage and
// each agent it awaits, the held lanes included.
Alive []AliveLane `json:"alive,omitempty"`
// Blocked are the landings that waited on the forge's merge this call
// while another lane moved: each holds only its own lane. Any other refused
// stage is the call's answer, and no lane moves.
Blocked []Refusal `json:"blocked,omitempty"`
// Route is the route that ran the agent when the process driver started
// it through a runner (Drive); absent when the host is to run it.
Route *runner.RouteRecord `json:"route,omitempty"`
// Fallback is the fallback receipt this call recorded when the runner a
// role is routed to did not run it and the host is handed the role.
Fallback *runner.FallbackReceipt `json:"fallback,omitempty"`
Next string `json:"next"`
// contains filtered or unexported fields
}
StepResult is what advance and Receipt return.
func Discard ¶ added in v0.13.0
func Discard(repoRoot, runID, laneID string, o Options) (StepResult, error)
Discard does not land a held lane, on the person's word (`implement step --discard <lane>`): its worktree is removed from the machine store and its branch deleted, then its pull request is closed if it opened one, and its stage is `discarded`; its step stays unlanded in the spec, so a replanned remainder carries it. The local removals come first, so a refused one leaves the pull request open and the lane held, and a retry finds nothing half done: a worktree or branch already gone is passed over. It changes nothing when the lane is not held or any lane is still at work.
func Drive ¶ added in v0.12.0
func Drive(ctx context.Context, repoRoot, runID string, steps Stages, o Options, rs Runners) (StepResult, error)
Drive performs the next stage as advance does and, when the stage hands the lane to an agent whose role is routed to a runner, starts that agent through the runner and hands its receipt back through Receipt. A step that re-tells an await an earlier call began starts nothing. A role on the host, or a runner that did not run it, returns the await for the host to act on, as advance returns it; the latter also names the fallback it recorded.
func Receipt ¶
func Receipt(repoRoot, runID, receiptPath string, steps Stages, o Options) (StepResult, error)
Receipt hands back the receipt an agent stage waited on. The path is looked up among every outstanding await of the run, not only one lane's, and the lane that await belongs to is advanced (ruling DR6): a verified receipt frees its slot, which the next `implement step` fills. It is refused when no await names the path, when this build carries no verifier for the stage, and when the verifier refuses it; in every refusal the run stays where it was and the agent's slot stays taken.
func Release ¶ added in v0.13.0
func Release(repoRoot, runID, laneID string, o Options) (StepResult, error)
Release lands a held lane as it is, on the person's word (`implement step --release <lane>`): its stage returns to `land` and its landing resumes at the step it stopped before, synced first when a sibling landed since its base. It changes nothing when the lane is not held or any lane is still at work.
type Sync ¶ added in v0.13.0
type Sync struct {
At time.Time `json:"at"`
Siblings []string `json:"siblings"`
Merged string `json:"merged"`
Conflicted bool `json:"conflicted"`
Paths []string `json:"paths,omitempty"`
Brief string `json:"brief,omitempty"`
Receipt string `json:"receipt,omitempty"`
// Head is the head the sync produced: the merge commit, or the verified
// head of the implementer who resolved the conflict; empty until then.
Head string `json:"head,omitempty"`
// Round is the fresh round that judges Head, once it has opened.
Round int `json:"round,omitempty"`
}
Sync is one merge of the default branch into a lane after a sibling lane of the run landed (spc-2609202134341288, "Two lanes that touch the same files"): the siblings whose landing caused it, the default branch's sha merged in, whether it conflicted, and the head it produced. A conflicting sync goes to a fresh implementer with the brief and receipt named here.
type Transcript ¶ added in v0.12.0
type Transcript struct {
At time.Time `json:"at"`
// Path is the transcript as it was handed to the capture, home-redacted.
Path string `json:"path"`
// Session is the session the history store recorded it under, and Stored
// where it lives there, home-redacted.
Session string `json:"session"`
Stored string `json:"stored"`
// Wrote is false when the store already held it (an idempotent capture).
Wrote bool `json:"wrote"`
// ScanGap is the capture's scan gap, home-redacted: the repository armed a
// scanner augmenter (gitleaks) that did not run, so the transcript was
// stored masked by the native scanner alone. Empty when there is none.
ScanGap string `json:"scan_gap,omitempty"`
}
Transcript is one transcript the run record captured into the history store.
type TranscriptCapturer ¶ added in v0.12.0
type TranscriptCapturer func(path string) (Transcript, error)
TranscriptCapturer captures one transcript by path into the history store, as `abcd history capture <path>` does, and reports what it stored.
type ValidationRound ¶ added in v0.12.0
type ValidationRound struct {
Round int `json:"round"`
// HeadSHA is the lane's head the round's validators judge.
HeadSHA string `json:"head_sha"`
Validators []ValidatorRun `json:"validators"`
// Fix is the verified receipt of the fresh implementer the round's
// findings were handed to; once set, the next step opens the next round.
Fix string `json:"fix,omitempty"`
}
ValidationRound is one round of the validate stage: the validators it hands the lane's head to, one at a time, and the fresh implementer it hands their findings to when one of them did not pass.
type ValidatorRun ¶ added in v0.12.0
type ValidatorRun struct {
Role string `json:"role"`
Brief string `json:"brief"`
Return string `json:"return"`
// Verdict is the verdict the loop parsed from the return; empty until the
// return is handed back. Pass is whether it lets the lane advance.
Verdict string `json:"verdict,omitempty"`
Pass bool `json:"pass"`
// Audit is the fidelity audit's request and reading, on the
// intent-auditor's run.
Audit *AuditRun `json:"audit,omitempty"`
// Route is the route that ran the validator when a runner ran it; absent
// when the host ran it. It is the one field a runner-run review's record
// differs in from a host-run one's (itd-2609201916056194 criterion 7).
Route *runner.RouteRecord `json:"route,omitempty"`
}
ValidatorRun is one validator of a round: the fresh agent handed the lane, its brief, the return it writes, and the verdict the loop parsed from that return.