engine

package
v0.32.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 17, 2026 License: MIT Imports: 32 Imported by: 0

Documentation

Overview

Package engine runs one role once: check, prepare, propose, judge, apply (docs/spec/role-contract.md, "One run").

Index

Constants

View Source
const MergeNormal = "normal"

MergeNormal is the merge policy's level where workline's own routine merge requests need no person's yes (role.MergeLevels).

View Source
const ModelTrailer = "Workline-Model"

ModelTrailer names, in the engine's own commits, each agent and model whose answer they hold, as <agent>:<model> (claude:claude-sonnet-5).

View Source
const OwnTrailer = "Workline-Role"

OwnTrailer marks the commits the engine makes itself, naming the role, so that they do not wake the line again (docs/spec/routing.md).

View Source
const Rewriter = "committer"

Rewriter is the role whose trailer marks a person's commit whose message it rewrote (ADR-0046): never a commit workline made.

Variables

View Source
var ErrLeftToAPerson = errors.New("left to a person")

ErrLeftToAPerson says a role's branch holds a commit a person added: nothing is pushed over it, the branch and its merge request are theirs (ADR-0034, amended).

View Source
var RoutineKinds = []string{kindRecords, kindDerived, kindDocs, kindReader}

RoutineKinds are the kinds, from the narrowest.

Functions

func Annotate added in v0.31.0

func Annotate(from FromMergeRequest, build func(read func(path string) ([]byte, error)) ([]forge.Annotation, int)) []verdict.Finding

Annotate shows the documentalist's findings of a merge request's own run on the head it judged, as the annotations of the check FindingsCheck, which open no conversation (#412). build makes them from the files as that head holds them, its branch fetched when the commit is not here. The run's findings are data its code could have written: only their places and words are shown, nothing is applied. What became of them is a finding, never an error: on a forge that takes no check (GitLab, whose Code Quality report shows them), nothing.

func OwnCommit added in v0.26.1

func OwnCommit(repo, commit, base string) string

OwnCommit names the role of a commit workline made, "" when it is none. Its trailer is not taken on trust — anyone can write one: a merge is workline's only when it merges base, or a commit of base's history, and its tree is exactly what workline's own merge of its two parents gives (OwnMerge); another commit, only when it changes doc pages alone (docPage). Else it is judged as a person's.

func OwnMerge added in v0.26.1

func OwnMerge(repo, commit, base string) bool

OwnMerge says whether a merge commit is one `follow` makes: its second parent base, or in base's history — the base merged in, never another branch —, merged into its first, workline's own lines settled (ADR-0041), and nothing else: its tree exactly the one that merge gives.

func ProposeBranch added in v0.2.2

func ProposeBranch(f forge.Forge, repo, roleName, key, title, body, trailers string, written []string) (int, error)

ProposeBranch commits the files written in the working tree on the role's branch for a task (workline/<role>/<key>), force-pushes it — unless the forge keeps its branches in the clone — opens its merge request or updates the one open, and puts the working tree back on the branch it was on. trailers end the commit's message. A branch a person committed to is never pushed over: ErrLeftToAPerson, the working tree as it was.

func RunsDir added in v0.27.0

func RunsDir(repo string) string

RunsDir is where repo's runs are kept: WORKLINE_RUNS_DIR when set — in CI, somewhere an artifact can carry them to the job that applies —, else its git folder's workline/runs.

func WriteVerdict added in v0.26.1

func WriteVerdict(file string, v HeadVerdict) error

WriteVerdict writes a head's verdict to file, as JSON.

Types

type FollowOptions added in v0.25.0

type FollowOptions struct {
	Repo, Forge, Base string
	// Gardening: the roles' gardening merge requests too (ADR-0034, amended).
	Gardening bool
	// People: each person's merge request into Base, left in conflict with
	// it only on lines workline writes, gets Base merged in, those lines
	// settled (the documentalist's `update-branches: conflicts`, ADR-0041).
	People bool
	// IsDoc says whether a file is one of the docs, whose header workline
	// writes; nil, none is.
	IsDoc func(path string) bool
	// Release says whether a branch is a release tool's: its merge request
	// is a bot's, rebuilt by the tool.
	Release func(branch string) bool
	// Derive says whether the docs' derived blocks, in the tree at dir,
	// read what the documentalist's `derive` commands give there: a merge
	// request regenerating them is `derived` at `normal` only then; nil,
	// never.
	Derive func(dir string, docs map[string]string) bool
	// Merge is the project's merge policy, its level (`merge: {autonomy:
	// cautious}`); "" none: no merge request's auto-merge is touched
	// (ADR-0042, merge.go).
	Merge string
	// Alone are the kinds that wait for a person's yes at `normal` the
	// project lets merge with none (`merge: {alone: [reader]}`,
	// role.MergeAlone).
	Alone []string
	// Verdict is a file holding the line's verdict on a merge request's
	// head (`workline route --verdict`), kept first, for the merge policy;
	// with VerdictOnly, nothing else is done: a job of its own keeps it,
	// which no newer run cancels (GitHub's concurrency).
	Verdict     string
	VerdictOnly bool
}

FollowOptions are what `workline follow` is given.

type FromMergeRequest added in v0.27.0

type FromMergeRequest struct {
	Repo     string // its checkout of the base: the project's settings are read there
	RolesDir string // its engine's roles
	Forge    string // its forge
	ID       int    // the merge request whose run it applies
	Head     string // the commit that run judged, as the forge's event names it
}

FromMergeRequest is what a job applying a merge request's own run takes from itself, never from the run.

type HeadVerdict added in v0.26.1

type HeadVerdict struct {
	Head     string            `json:"head"`
	Status   string            `json:"status"`
	Steps    []StepStatus      `json:"steps,omitempty"`
	Findings []verdict.Finding `json:"findings,omitempty"`
}

HeadVerdict is the line's verdict on a merge request's head, written by the judging job (`workline route --verdict`), kept by the job that writes (`workline follow --verdict`).

type Options

type Options struct {
	Repo      string            // repository the role works on
	RolesDir  string            // folder holding the roles
	Role      string            // role name
	Event     string            // event the role runs on
	AI        string            // agent spec, see agent.Parse; empty = the project's setting
	DefaultAI string            // used when neither AI nor the project says (the user's own default)
	Inputs    map[string]string // name -> value, written to in/input/<name>
	Targets   map[string]string // name -> file an intention writes back to (e.g. the hook's message file)

	Forge  string        // forge spec, see forge.Open; empty = the project's `forge` setting
	Target *forge.Target // the issue or merge request comments and labels go on
	// Branch is the one the targeted merge request comes from, when the job
	// knows it without the forge (a CI job without the forge's token); else
	// the forge is asked. Its branch tells a release tool's (ADR-0017).
	Branch string
	Scope  []string // paths the task is about; a patch outside is refused
	// NoApply stops after judging: the proposals and what apply needs are kept
	// in the run folder, for `workline apply` in another job holding the token.
	NoApply bool
	// OpenMergeRequest puts what the patches wrote on a branch of the role's,
	// and opens a merge request for it, or updates the one open (ADR-0006).
	OpenMergeRequest bool
	// PushToMergeRequest commits what the patches wrote to the branch of the
	// merge request the run targets; from a fork, the diff goes in a comment.
	PushToMergeRequest bool

	// TamperBeforeApply changes the prepared input between propose and apply.
	// It exists only for the conformance test that proves apply notices.
	TamperBeforeApply bool
}

Options describe one run.

type Result

type Result struct {
	Status     string            `json:"status"`
	Summary    string            `json:"summary,omitempty"`
	Findings   []verdict.Finding `json:"findings,omitempty"`
	AgentCalls int               `json:"agent-calls"`
	Calls      []agent.Call      `json:"calls,omitempty"` // each call: what was asked, what answered
	Applied    []string          `json:"applied"`
	Refused    []string          `json:"refused"`
	Handoffs   []any             `json:"handoffs,omitempty"` // next roles asked for; routing runs them
	Notes      []string          `json:"notes,omitempty"`    // what the agent left for a person: a round's notes each
	RunDir     string            `json:"run-dir"`
	ToApply    bool              `json:"to-apply,omitempty"` // judged with NoApply: `workline apply` still has work
	// Pending: the run folders `workline apply` is given, one a round, when
	// a run judged with NoApply went round, each round a merge request of
	// its own (ADR-0013's amendment).
	Pending      []string `json:"pending,omitempty"`
	MergeRequest int      `json:"merge-request,omitempty"` // the merge request the patches went to
	// Issues and Waiting are a role keeping a backlog's links, for the
	// job's summary (ADR-0038): the address of the forge's issues, an
	// issue's number after it making its page; the saved filter of what
	// waits on a person, workline:proposed.
	Issues  string `json:"issues,omitempty"`
	Waiting string `json:"waiting,omitempty"`
	// contains filtered or unexported fields
}

Result is what a run reports.

func Follow added in v0.17.0

func Follow(o FollowOptions) *Result

Follow keeps a role's release merge requests (fixElsewhere's, ADR-0017) on the tip of base, as a release tool keeps its own branch: run when base moves, it rebuilds each open one whose branch base moved under, by redoing the branch's change on base's new tip, and force-pushes it — the merge request stays the same (ADR-0034). A branch already on base's tip is left as it is; one a person committed to is never rebuilt over them; one whose change no longer applies is left for a person.

With gardening, run when gardening runs, it tends the roles' other merge requests too, one a task (ADR-0006): each base moved under is rebuilt the same way, or closed, one comment saying why, when nothing of it is left to merge — base holds its change already, base changed the lines it changed, or it only records when docs were read. One a person committed to is left to them, and named only when it no longer merges (ADR-0034, amended).

With People, the project's choice, it merges base into each person's merge request left in conflict with it only on lines workline writes, those settled: a doc's record of when it was checked, a derived block (ADR-0041; settle.go).

With Merge, the project's merge policy, it turns the forge's auto-merge on for each merge request a person accepted, its head's verdict passed, and brings the first in line up to date with base, one at a time (ADR-0042; merge.go). Verdict, a head's verdict the line wrote, is kept first, in hand for this run and, where the forge keeps it, for the next.

func Resume

func Resume(runDir string) *Result

Resume applies what an interrupted run had not applied yet, from what that run recorded. The agent is not called again, and nothing is applied if the prepared input changed since.

func ResumeFrom added in v0.27.0

func ResumeFrom(listed string, from FromMergeRequest) *Result

ResumeFrom applies a run a merge request's own CI run judged, listed as listed: found by its name in this job's runs folder (RunsDir), never at a path the run wrote. Only its proposals are read, and only what the merge request's line may do is applied: by a role of this engine's that runs on a merge request, proposals of its own kinds, to that merge request — its branch, its comments —, never another merge request opened but the release's own fix (ADR-0017). Once the merge request's branch moved on from the head judged, only what its role names to say what that head held is applied (`on-moved-on`: the reviewer's review, #375), nothing else.

func Run

func Run(o Options) *Result

Run executes one run and always returns a result with a status: an error inside the run becomes a blocking finding, never a silent pass. When pre took less than there was to do and said so in in/more, and the round passed and applied something, the role goes round again: the next round sees what this one applied. Calls and applied intentions add up; a later round's finding replaces an earlier one of the same rule and place, and what a round deferred is dropped: the next round reports what is left.

Judged with NoApply for merge requests of its own (gardening in CI), a round applies nothing the next could see; it goes round again when it proposed a merge request for a task no earlier round proposed: the next round is told that task waits, as one open on the forge, and takes up what it deferred — the docs judged in parts after those judged whole (ADR-0013). Each round is a run folder to apply, in Pending.

type StepStatus added in v0.26.1

type StepStatus struct {
	Name   string `json:"name"`
	Status string `json:"status"`
}

StepStatus is a step of the line, and how it ended.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL