Documentation
¶
Overview ¶
Package lookaround collects facts about one project and derives the feed (what changed in a window) or the state (where each task stands). Only Derive and DeriveFeed decide a stage or a group; docs/board.md is the spec.
Index ¶
- Constants
- Variables
- func AgentFor(id, branch, path string) string
- func Plural(n int, word string) string
- func StateGroup(r Row) string
- func StateRank(r Row) int
- type Board
- type Branch
- type Facts
- type Feed
- type FeedRow
- type Findings
- type Inputs
- type Local
- type LocalInputs
- type Next
- type PR
- type PRRef
- type Person
- type Project
- type Quiet
- type RelatedPR
- type ReviewFacts
- type Row
- type Source
- type Task
- type Tip
- type Where
- type Who
- type Window
- type Workspace
- type Worktree
Constants ¶
const ( ViewFeed = "feed" ViewState = "state" )
The two views a board is.
const ( SourceHost = "host" SourceTracker = "tracker" SourceLocal = "local" )
The three sources, in the order the board lists them.
const ( StageAsksWaiting = "asks-waiting" StageBlocked = "blocked" StageReady = "ready" StageInReview = "in-review" StagePROpen = "pr-open" StageImplementing = "implementing" StagePlanning = "planning" StagePlanned = "planned" StageMergedUnfinished = "merged-unfinished" StageNext = "next" StageDone = "done" )
The stages, in the order the board lists rows.
const ( GroupInProgress = "in progress" GroupNext = "next" GroupDone = "done" )
The groups the state's rows draw under, in listing order.
const ( FromLocal = "local" FromTrace = "trace" FromHost = "host" FromTracker = "tracker" FromGuessed = "guessed" )
Where a stage's or a group's evidence came from: local state, the traces f10 left on the host, the host's certain facts (a merge, a creation), the tracker's list, or the host's facts read as a guess.
const ( GroupStarted = "started" GroupUpdated = "updated" GroupReviewed = "reviewed" GroupFinished = "finished" GroupNewTasks = "new-tasks" )
The feed's groups, in the order it lists them.
const ( RelationPart = "part" // the two overlapped RelationFollowUp = "follow-up" // it merged before the later one opened RelationReplaced = "replaced" // it closed unmerged )
How a task's earlier request relates to the one its feed row leads with.
const Version = 4
Version is the Board JSON's version; a change to a stage rule or a field's meaning bumps it with the spec.
Variables ¶
var Groups = []string{GroupStarted, GroupUpdated, GroupReviewed, GroupFinished, GroupNewTasks}
Groups is every feed group in listing order.
var Stages = []string{ StageAsksWaiting, StageBlocked, StageReady, StageInReview, StagePROpen, StageImplementing, StagePlanning, StagePlanned, StageMergedUnfinished, StageNext, StageDone, }
Stages is every stage in listing order.
var StateGroups = []string{GroupInProgress, GroupNext, GroupDone}
StateGroups is every state group in listing order.
Functions ¶
func AgentFor ¶
AgentFor is the name start gave the task's agent in the worktree: the id and the suffix its branch carries, hashed with the path.
func Plural ¶ added in v0.39.0
Plural is n and word, pluralised past one ("-sh" takes "es"). Every renderer counting a word goes through it.
func StateGroup ¶ added in v0.45.0
StateGroup is the heading a state row draws under: a row held only by its base, with no work of its own, is still next. board.html's group() mirrors it.
Types ¶
type Board ¶
type Board struct {
Version int `json:"version"`
GeneratedAt time.Time `json:"generated_at"`
View string `json:"view"`
Project Project `json:"project"`
Window Window `json:"window"`
Sources []Source `json:"sources"`
Rows []Row `json:"rows"` // the state view's; empty in the feed
Feed *Feed `json:"feed,omitempty"` // the feed view's
}
A Board is one project's feed or rows, with where each fact came from.
func Derive ¶
Derive is the board from facts: one row per task or taskless request, staged by the first matching rule in docs/board.md, each naming its evidence. No clock and no I/O: now and since are the board's.
func DeriveFeed ¶ added in v0.39.0
DeriveFeed is the feed from facts over the window: a row per task or taskless request with activity there, grouped by the first matching rule in docs/board.md, a row per task created there, and the quiet count.
func Unreachable ¶
Unreachable is the board of a project no collector could run for. Every source carries the error, so a reader of several boards sees the project failed rather than empty; a project with no checkout keeps local skipped.
type Branch ¶
type Branch struct {
Task string // the id the branch is linked to, else what its name spells
Riders []string // a bundle's other members
After string // the base task recorded on it
Model string // the agent's model, where start recorded it
Agent string // the agent's profile as typed (opus:high), where start recorded one
// Finish is `f10 drive`'s record of running the branch's finish, while
// that drive holds the task's lease
Finish *ref.DriveFinish
}
A Branch is what the local config records on a branch.
type Facts ¶
type Facts struct {
Project Project
Prefix string // the task id prefix, for reading ids off branches and titles
Tasks []Task
PRs []PR
Local *Local // nil when the local collector was skipped or failed
People []Person
Sources []Source
// the feed's: what the host did in the window, each started task's
// other requests by id, and a local-only checkout's branch tips
Activity *forge.Activity
Earlier map[string][]forge.PR
Tips []Tip
}
Facts is what the collectors found, before any interpretation.
type Feed ¶ added in v0.39.0
A Feed is what changed in the window: one row per task whose requests were touched there, per touched request naming no task, and per task created there, and the open requests nobody touched, counted.
type FeedRow ¶ added in v0.39.0
type FeedRow struct {
Group string `json:"group"`
Key string `json:"key"` // the task id, else `#<number>`, else the branch
Task *Task `json:"task,omitempty"`
PR *PRRef `json:"pr,omitempty"`
From string `json:"from"`
Who Who `json:"who"`
// Owes is who the next move waits on: the author after a review, a
// requested reviewer before one.
Owes string `json:"owes,omitempty"`
Abandoned bool `json:"abandoned,omitempty"` // closed without merging, nothing later
Related []RelatedPR `json:"related,omitempty"` // the task's requests opened before PR
Summary string `json:"summary,omitempty"` // what happened, one sentence
At time.Time `json:"at"` // the latest event in the window
}
A FeedRow is one task whose requests were touched in the window, one request naming no task, or one task created there.
type Findings ¶
type Findings struct {
Round int
Open int // findings with no verdict, or a verdict of ask
At time.Time
}
Findings is a task's latest review round as its findings file holds it.
type Inputs ¶
type Inputs struct {
Project Project
Prefix string
// Since is where reading starts: the state view's done window, or the
// earliest span the feed may show.
Since time.Time
// Feed reads what changed since Since instead of where every task
// stands: the host's activity, the tracker's list, and nothing local
// unless the checkout is local only.
Feed bool
// LocalOnly is a checkout with no origin remote: the host is skipped,
// and the tracker too unless a driver answers it (Tasks set).
LocalOnly bool
Host *forge.Host
HostError string // why there is no host, for the source's error
Tasks func(ctx context.Context) ([]Task, error)
// RemoteOpen reports whether the project's declared remote reviewer
// left a review on the request nobody handled; nil declares none. An
// error is a note on the host source, the request kept without it.
RemoteOpen func(ctx context.Context, number int) (bool, error)
Remote bool
Local *LocalInputs
// People is the user's map of one person's identities across the
// sources; nil groups rows by whatever identity each source gives.
People []Person
// Now is the clock; nil is time.Now. A test fixes it so timings are
// stable.
Now func() time.Time
}
Inputs binds the collectors to one project. A nil Host, Tasks or Local is that source absent; Remote skips the local collector on purpose.
type Local ¶
type Local struct {
Runs []state.Run
Worktrees []Worktree
Branches map[string]Branch // by branch name
Plans map[string]time.Time // task id to the plan file's mtime
Archived map[string]bool // task ids whose plan is archived
Findings map[string]Findings // task id to its latest round
Verdicts map[string]string // task id to its latest verdict
Finished map[string]bool // task ids the ledger holds task_finished for
Workspaces map[string]Workspace // worktree path to the Herdr workspace on it
}
Local is what this machine knows: live runs, worktrees, branches, plans, findings, verdicts, what the ledger closed, and Herdr's view.
type LocalInputs ¶
type LocalInputs struct {
Main string // the main checkout
StateDir string // run state files
TTL time.Duration
LedgerPath string // "" reads no ledger
ProjectID string // the ledger's project id
Agents agentctl.Backend // the agent backend, when reachable: read its workspaces; nil reads none
}
LocalInputs is where this machine keeps what the local collector reads.
type PR ¶
type PR struct {
forge.PR
Block *trace.State `json:"block,omitempty"`
Trailers []trace.Parsed `json:"trailers,omitempty"`
HeadExists *bool `json:"head_exists,omitempty"` // read for merged requests only
RemoteOpen bool `json:"remote_open,omitempty"` // the declared remote reviewer left one unhandled
}
A PR is a request with what the host says around it.
type PRRef ¶
type PRRef struct {
Number int `json:"number"`
Title string `json:"title,omitempty"`
URL string `json:"url,omitempty"`
State string `json:"state"` // open, merged or closed
Draft bool `json:"draft,omitempty"`
Head string `json:"head,omitempty"`
Base string `json:"base,omitempty"`
Mergeable string `json:"mergeable,omitempty"` // clean, conflicts or blocked
Checks string `json:"checks,omitempty"` // green, red or pending
}
A PRRef is the request a row hangs on.
type Person ¶
A Person joins the identities one person has across the sources: the tracker's name for them, their host login, the emails their commits carry. Every field but Name is optional.
type Project ¶
type Project struct {
ID string `json:"id"` // the normalised remote, `github.com/org/repo`
Name string `json:"name"` // the main checkout's basename
Host string `json:"host,omitempty"` // gh or glab
Checkout string `json:"checkout,omitempty"` // the main checkout; empty with no checkout read
Remote bool `json:"remote"` // local collectors skipped
// LocalOnly is a checkout with no origin remote: no host to read, so
// the board is this machine's alone.
LocalOnly bool `json:"local_only,omitempty"`
}
Project names the project the board is about.
type Quiet ¶ added in v0.39.0
type Quiet struct {
Count int `json:"count"`
Oldest time.Time `json:"oldest,omitzero"` // the oldest one's creation time
}
Quiet is the open requests with no row in the window: no commits, reviews or status changes there.
type RelatedPR ¶ added in v0.44.0
type RelatedPR struct {
Number int `json:"number"`
URL string `json:"url,omitempty"`
State string `json:"state"` // open, merged or closed
Relation string `json:"relation"`
}
A RelatedPR is one of a task's earlier requests, beside the row's own.
type ReviewFacts ¶
type ReviewFacts struct {
Step string `json:"step,omitempty"` // the step the state block names
Round int `json:"round,omitempty"`
Open int `json:"open,omitempty"`
Asks int `json:"asks,omitempty"`
Approvals int `json:"approvals,omitempty"`
ChangesRequested int `json:"changes_requested,omitempty"`
RemoteOpen bool `json:"remote_open,omitempty"` // the declared remote reviewer left one unhandled
}
ReviewFacts is what the row's reviews add up to.
type Row ¶
type Row struct {
Key string `json:"key"` // the task id, else `#<number>`
Task *Task `json:"task,omitempty"`
Stage string `json:"stage"`
StageFrom string `json:"stage_from"`
Who Who `json:"who"`
Where Where `json:"where"`
Review *ReviewFacts `json:"review,omitempty"`
BlockedBy []string `json:"blocked_by,omitempty"`
LastActivity time.Time `json:"last_activity,omitzero"`
Next Next `json:"next"`
}
A Row is one task, or one request naming no task.
type Source ¶
type Source struct {
Name string `json:"name"`
OK bool `json:"ok"`
Skipped bool `json:"skipped,omitempty"`
Error string `json:"error,omitempty"`
Notes []string `json:"notes,omitempty"`
TookMS int64 `json:"took_ms"`
}
A Source is one collector's result: ok with its facts in, failed with its error and nothing from it, or skipped on purpose.
type Task ¶
type Task struct {
ID string `json:"id"`
Title string `json:"title,omitempty"`
URL string `json:"url,omitempty"`
Status string `json:"status,omitempty"`
Priority string `json:"priority,omitempty"`
Assignee string `json:"assignee,omitempty"`
After string `json:"after,omitempty"` // the base its body names
// Created is when the tracker created it, where the tracker says.
Created time.Time `json:"created,omitzero"`
}
A Task is a tracker row.
type Tip ¶ added in v0.39.0
A Tip is a local branch's last commit, what a checkout with no host shows in its feed.
type Where ¶
type Where struct {
PR *PRRef `json:"pr,omitempty"`
Branch string `json:"branch,omitempty"`
Worktree string `json:"worktree,omitempty"`
Workspace string `json:"workspace,omitempty"`
// BranchLeft marks a merged row whose branch outlived its worktree
BranchLeft bool `json:"branch_left,omitempty"`
}
Where the work is.
type Who ¶
type Who struct {
Agent string `json:"agent,omitempty"` // the Herdr agent in its worktree
AgentStatus string `json:"agent_status,omitempty"` // idle, working, done
Model string `json:"model,omitempty"`
Author string `json:"author,omitempty"` // the request's author
Assignees []string `json:"assignees,omitempty"`
Reviewers []string `json:"reviewers,omitempty"` // requested and not yet heard from
Committers []string `json:"committers,omitempty"` // the author emails on the row's commits
// Person is the one name the row groups under: the assignee, else the
// author, else the first committer, through the people map where it matches.
Person string `json:"person,omitempty"`
}
Who is working on the row, and who it waits on.
type Window ¶
type Window struct {
Since time.Time `json:"since"`
// End closes the feed's span, exclusive; zero in the state view.
End time.Time `json:"end,omitzero"`
// Chosen is how the feed's span was picked: the window named
// (`today`, `last-week`, a date) or the default's pick.
Chosen string `json:"chosen,omitempty"`
// Fallback is the default falling back to the last working day
// because today has no activity yet.
Fallback bool `json:"fallback,omitempty"`
}
Window is the period the board covers: the feed's span, or the time since which the state view's done rows count.
func ChooseWindow ¶ added in v0.39.0
ChooseWindow is the default's span: today when the facts give today a row, else the last working day marked as the fallback. The facts are read from the last working day's start, so one collection answers both.