Help us shape the future of Go! Take the 2026 Go Developer Survey

review

package
v1.0.1 Latest Latest
Warning

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

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

Documentation

Index

Constants

View Source
const (
	AnglesDir   = "angles"
	CheckoutDir = "checkout"
	ScratchDir  = "scratch"
	DiffFile    = "diff.patch"
)

Artifact paths shared by pipeline stages and their callers. CheckoutDir is reserved for caller-acquired files; agentcore does not create a checkout.

View Source
const (
	// SideNew is the file as the change leaves it.
	SideNew = "new"
	// SideOld is a line the change removed.
	SideOld = "old"
)

Sides of a diff a finding anchors to.

View Source
const (
	RuleDrop     = "drop"
	RuleDownrank = "downrank"
)
View Source
const (
	// AngleQuickGeneral gives a small change one light pass for whatever is
	// wrong with it.
	AngleQuickGeneral = "quick_general"
	// AngleGeneral reviews the change as a whole, thoroughly, not narrowed
	// to one concern.
	AngleGeneral = "general"
	// AngleDocs checks the comments and the prose that describe the code
	// against the code as the change leaves it.
	AngleDocs = "docs"
	// AngleTests checks the tests and the documentation the change owes.
	AngleTests = "test_coverage"
	// AngleAcceptance checks the change against the acceptance criteria of
	// what it says it does.
	AngleAcceptance = "acceptance_criteria"
	// AngleSideEffects checks what the change breaks elsewhere.
	AngleSideEffects = "side_effects"
)

The angles a review runs from, each one a session of its own reading the review brief, as many of them as the change's size calls for (sizeAngles in angles.go). A project turns one off, or back on, under [angles].

View Source
const (
	SeverityOff    = "off"
	SeverityInfo   = "info"
	SeverityLow    = "low"
	SeverityMedium = "medium"
	SeverityHigh   = "high"
)

Severities a category can be pinned to, most severe last. SeverityOff drops the category's findings instead of ranking them.

View Source
const BriefFile = "brief.json"

BriefFile is the name the brief is written under inside a review's artifact directory, which WriteBrief and ReadBrief are given.

View Source
const DistillerName = "distiller"

DistillerName is the name of the distiller session, in an error message.

View Source
const FindingsFile = "findings.json"

FindingsFile is the name the merged findings are written under inside a review's artifact directory.

View Source
const TriageFile = "triage.json"

TriageFile is the name the triage state is written under inside a review's artifact directory.

Variables

BuiltinAngles lists the angles a review can run, in the order they are fanned out. A review runs the ones its change's size calls for that the project enables (anglesFor in angles.go).

Severities lists the accepted severity values, in the order they are printed.

View Source
var Sizes = []string{"xs", "s", "m", "l", "xl"}

Sizes are the sizes a brief can give a change, smallest first.

Functions

func CompareFindings

func CompareFindings(a, b Finding) int

CompareFindings orders the list: most severe first, then by file and line with the findings about the change as a whole after the anchored ones, then in angle order, then by title.

func Filter

func Filter(findings []Finding, rules []Rule, repo string, compare Comparator) ([]Finding, []Silenced)

Filter is the noise filter over a review's findings: the list triage sees, and what the rules kept out of it or ranked down in it. repo is the opaque scope used to select rules.

The findings come back ordered as the judge orders them, most severe first, so a finding ranked down moves to where its new severity puts it. Findings with no rule to match are returned as they are: an empty rule list changes nothing.

func JSONObject

func JSONObject(text string) (string, bool)

JSONObject is the JSON object in a session's answer: the last fenced block when it fenced one, and otherwise everything from the first brace to the last, which is the whole answer when the session answered as it was asked to.

func NoiseSection

func NoiseSection(rules []Rule, repo, angle string) string

NoiseSection is what an angle session reviewing repo is told about the rules that name its angle: what a person has dismissed from it before, so it does not report the same thing again. It is empty when no rule does, and a rule with no text says nothing to a session: it silences a whole category, which is not something to tell a session it found.

func ResumePrompt

func ResumePrompt(run AngleRun, question string) string

ResumePrompt is what a reopened angle session is asked. It has the brief, the diff and its own findings already: only the question is new.

func SameFinding

func SameFinding(a, b *Finding, compare Comparator) bool

SameFinding reports whether b reports what a reports: the same place, and the same kind of problem or the same words for it (see the package comment above).

func WriteAngleRun

func WriteAngleRun(artifact string, run *AngleRun) error

WriteAngleRun writes one angle's run into a review's artifact directory, as AnglesDir/<angle>.json, creating the directories when they are not there.

func WriteBrief

func WriteBrief[R Reference](dir string, b *Brief[R]) error

WriteBrief writes the brief into a review's artifact directory, creating the directory when it is not there. What else the directory holds, and how a review finds it again, is artifact.go.

func WriteFindings

func WriteFindings(dir string, f *Findings) error

WriteFindings writes the merged findings into a review's artifact directory, creating it when it is not there.

func WriteTriage

func WriteTriage(dir string, t *Triage) error

WriteTriage writes the triage state into a review's artifact directory, creating it when it is not there. A state with no decisions is written with an empty list, not a null.

Types

type Agent

type Agent interface {
	Run(ctx context.Context, req AgentRequest) (*AgentResult, error)
}

Agent runs one review session. It is the seam every session in the pipeline goes through: the distiller here, the angle sessions after it.

type AgentRequest

type AgentRequest struct {
	// Name identifies the session in an error message.
	Name string
	// Prompt is the whole of what the session is told: a review session has
	// no separate system prompt, because codex takes none.
	Prompt string
	// Dir is the directory the session runs in, which is what its
	// read-only tools can reach. It must be a directory the review is
	// willing to have read: the checkout of the repository under review, or
	// an empty one.
	Dir string
	// ResumeID continues an earlier session of this agent (AgentResult.ID)
	// instead of starting one, for the triage action that asks an angle a
	// follow-up question. Claude and codex (through thread/resume) honour
	// it.
	ResumeID string
}

AgentRequest is one review session.

type AgentResult

type AgentResult struct {
	// ID is the agent's own id for the session, which resumes it later.
	ID string
	// Text is the session's last message, which is what it was asked for.
	Text string
	// Turns is how many turns it took, and CostUSD what it cost when the
	// CLI reported one, which CostKnown says: codex reports none, so its
	// cost is unknown rather than zero.
	Turns     int
	CostUSD   float64
	CostKnown bool
	// Provider and Model are the agent that answered, when the
	// implementation says: one that fell back to another agent reports that
	// one, so the run records the session that exists and Resume knows what
	// to reopen it with. Empty keeps what the angles were configured with.
	Provider string
	Model    string
}

AgentResult is what a finished review session produced.

type AngleEvent

type AngleEvent string

AngleEvent is what Angles.Progress is told about an angle's session.

const (
	// AngleStarted is told as the session starts.
	AngleStarted AngleEvent = "started"
	// AngleFinished is told as the session ends with an answer.
	AngleFinished AngleEvent = "finished"
	// AngleFailed is told as the session ends with an error instead.
	AngleFailed AngleEvent = "failed"
)

type AngleRun

type AngleRun struct {
	// Angle is the angle the session reviewed from, a name in
	// BuiltinAngles.
	Angle string `json:"angle"`
	// Provider and Model are the agent the session ran as. A session is
	// reopened by the same agent: another provider does not know its id.
	Provider string `json:"provider"`
	Model    string `json:"model,omitempty"`
	// Dir is where the session ran, retained for caller-owned resumption.
	Dir string `json:"dir"`
	// SessionID is the agent's own id for the session, which Resume gives
	// back to it. It is empty for a session that failed.
	SessionID string `json:"session_id,omitempty"`
	// Answer is what the session said last, as it said it: the findings it
	// was asked for, in the JSON shape the prompt describes. Reading them
	// into findings is the judge's job (judge.go), not this file's.
	Answer string `json:"answer,omitempty"`
	// Turns is how many turns the session took and CostUSD what it cost,
	// when the CLI reported one; CostUnknown says it reported none.
	Turns       int     `json:"turns,omitempty"`
	CostUSD     float64 `json:"cost_usd,omitempty"`
	CostUnknown bool    `json:"cost_unknown,omitempty"`
	// Error is what the session failed with, and "" for one that finished.
	// A session that answered that it could not read its input has failed
	// too, and keeps that answer beside the error. A failed angle is kept
	// with the rest so the review can say which angle nobody looked from.
	Error string `json:"error,omitempty"`
}

AngleRun is one angle's session: what it came to, and what reopens it.

func ReadAngleRuns

func ReadAngleRuns(artifact string) ([]AngleRun, error)

ReadAngleRuns reads the angle runs back out of a review's artifact directory, in BuiltinAngles order: the angles that ran, and none for a review whose angles have not run yet. A file that is not a run is an error naming it.

func (*AngleRun) Failed

func (r *AngleRun) Failed() bool

Failed reports whether the session failed, in which case it found nothing and there is nothing to resume.

type Angles

type Angles[R Reference] struct {
	// Agent runs the sessions; Provider and Model say which agent it is,
	// which is what every run records so it can be reopened by the same
	// one.
	Agent    Agent
	Provider string
	Model    string
	// Sized replaces the built-in angles of each size it names (sizeAngles),
	// a size it leaves out keeps the built-in list.
	Sized map[string][]string
	// Prepare optionally supplies the session directory. The caller owns any
	// acquisition; nil uses Dir or a persistent scratch directory.
	Prepare func(context.Context, string) (string, error)
	// AgentFor optionally selects an agent and recorded model per angle.
	// It is called concurrently; profile construction belongs to the caller.
	AgentFor func(angle string) (Agent, string)
	// ProviderFor optionally selects the provider recorded for an angle. Both
	// callbacks must be safe for concurrent calls; nil retains Provider.
	ProviderFor func(angle string) string
	// Dir is an existing working directory, used when Prepare is nil.
	// agentcore does not write the diff into this caller-owned directory.
	// With no directory, sessions use a persistent scratch directory.
	Dir string
	// Log receives angle-selection diagnostics, and is silent when nil.
	Log io.Writer
	// Rules are the reviewer notes' rules (policy.go), read by whoever runs
	// the review: the ones that name the repository under review and the
	// angle become the part of that angle's prompt saying what has been
	// dismissed from it before. A person who has dismissed nothing has
	// none, and their sessions are told nothing extra.
	Rules []Rule
	// Progress is told how each angle's session is going, for a display to
	// draw while the angles run: AngleStarted the moment before the
	// session starts, and AngleFinished or AngleFailed the moment it ends.
	// It is called from the goroutine of the angle it is about, so calls
	// arrive at once from several angles and it has to be safe to call
	// concurrently. Nil is told nothing, and costs nothing.
	Progress func(angle string, event AngleEvent)
}

Angles runs the angle sessions of a review.

func (*Angles[R]) Run

func (a *Angles[R]) Run(ctx context.Context, artifact string, project *Settings, brief *Brief[R], diff string) ([]AngleRun, error)

Run fans out one session per angle the brief's size calls for (Sized, else sizeAngles) and project enables (anglesFor), all at once, each given the brief and the diff, and waits for every one of them. The runs come back in BuiltinAngles order and are written into artifact, one file per angle, before Run returns. A brief whose size is not one of Sizes is reported on Log and gets the angles of the largest.

Prepare supplies a working directory when set; otherwise sessions use Dir or the artifact's empty ScratchDir. Acquisition stays with the caller.

One angle failing stops none of the others: the runs are complete whether or not err is nil, a failed angle is among them with Error set, and err says so once every angle has ended. An angle whose session answered that it could not read what it was given (unreadableInput) has failed too: an angle that did not see the change has not found it clean. An error before any session ran (no brief, a directory that could not be made) returns no runs.

diff is the pull request's diff, and "" when it was not gathered. It is in every angle's prompt, so a session reads it without a tool, and it is also written once to DiffFile inside dir (writeDiff), where the session's read-only tools can search it. It is not written when dir is Dir, the checkout the machine already had: a review does not write into a working tree it did not make. Progress, when set, is told as each session starts and ends.

func (*Angles[R]) SelectedAngles

func (a *Angles[R]) SelectedAngles(settings *Settings, size string) []string

SelectedAngles returns the enabled angles for size in catalog order.

type Artifact

type Artifact[R Reference] struct {
	// Dir is the directory.
	Dir string
	// Brief is the brief, which every artifact has: a directory without one
	// is not a review.
	Brief *Brief[R]
	// Runs are the angle runs, in BuiltinAngles order, and none for a
	// review whose angles have not run. They are the angles Brief.Size
	// called for that the project enabled (anglesFor), each one run whether
	// it finished or failed: an angle with no run is one the size did not
	// call for, or one the project turned off.
	Runs []AngleRun
	// Findings is the judge's list, and nil for a review not judged yet.
	Findings *Findings
	// Triage is what triage decided, and nil for a review not triaged yet.
	Triage *Triage
}

Artifact is one review's directory read into memory: the parts of it that are there, and nil for the ones the review has not reached.

func ReadArtifact

func ReadArtifact[R Reference](dir string) (*Artifact[R], error)

ReadArtifact reads a review's directory back: the brief, which must be there, and the angle runs, findings and triage state that are. A file that is there and does not read is an error naming it.

func (*Artifact[R]) Write

func (a *Artifact[R]) Write() error

Write writes every part of the artifact that is there into its directory, creating it when it is not. A nil brief is an error: the directory would not read back as a review. Runs that are nil are not written, so a review's earlier runs stay.

type Brief

type Brief[R Reference] struct {
	// Ref identifies the change under review; Title and Author are supplied
	// by the caller. All three come from the bundle.
	Ref    R      `json:"ref"`
	Title  string `json:"title,omitempty"`
	Author string `json:"author,omitempty"`

	// Summary is what the change does, in the distiller's words.
	Summary string `json:"summary"`
	// Size is how large the change is, one of Sizes, as the distiller
	// judged it from the change's scope (the files and lines it touches,
	// the generated files in Excluded not among them) and its risk (which
	// parts of the project those are).
	Size string `json:"size"`
	// AcceptanceCriteria are what the change says it does: the criteria of
	// the issues it closes, the promises of its own description.
	AcceptanceCriteria []Point `json:"acceptance_criteria,omitempty"`
	// StyleRules are the rules the project's own style sources put on a
	// change like this one, the ones that apply and not the whole of what
	// the files say.
	StyleRules []Point `json:"style_rules,omitempty"`
	// TouchedAreas are the parts of the project the change touched.
	TouchedAreas []TouchedArea `json:"touched_areas,omitempty"`

	// Sources are the context sources the bundle was gathered from, and
	// NotGathered what those sources could not read (Bundle.Skipped), so a
	// session reading the brief knows what nobody looked at.
	Sources     []string `json:"sources,omitempty"`
	NotGathered []string `json:"not_gathered,omitempty"`
	// Excluded are the generated files the caller took out of the diff
	// before the distiller read it (Bundle.Excluded): what the change did
	// there is not in the size, and a finding anchored there is dropped. A
	// brief written before there were any reads back with none.
	Excluded []ExcludedFile `json:"excluded,omitempty"`
	// SessionID is the distiller session's own id, which is what a later
	// session would be resumed from, and CostUSD what that session cost
	// when the CLI reported a cost (AgentResult.CostUSD): what the factory
	// counts against its budgets, since the distiller is no session of its
	// own runner. CostUnknown says the CLI reported none.
	SessionID   string  `json:"session_id,omitempty"`
	CostUSD     float64 `json:"cost_usd,omitempty"`
	CostUnknown bool    `json:"cost_unknown,omitempty"`
}

Brief is what the distiller made of the context bundle: the starting context of every session after it.

It is angle-agnostic. An angle session reads the same brief whether it reviews the change as a whole or checks its documentation, tests, acceptance criteria or side effects, so nothing here is written for one of them: the criteria are what the change says it does, the style rules are what this project asks of any change, and the touched areas are what it changed. What each angle makes of that is the angle's own business.

Half of it is the distiller's reading of the bundle (Summary, Size, AcceptanceCriteria, StyleRules, TouchedAreas) and half is what the caller already knew (Ref, Title, Author, Sources, NotGathered, Excluded, SessionID): the session is not asked for a fact the gather has, so it cannot get one wrong.

func ParseBrief

func ParseBrief[R Reference](text string) (*Brief[R], error)

ParseBrief reads the brief out of what the session answered.

func ReadBrief

func ReadBrief[R Reference](dir string) (*Brief[R], error)

ReadBrief reads the brief back out of a review's artifact directory.

func (*Brief[R]) Text

func (b *Brief[R]) Text() string

Text renders the brief as markdown for an angle session. The angle prompt adds the diff location separately; Text does not include the diff.

func (*Brief[R]) Validate

func (b *Brief[R]) Validate() error

Validate checks that the distiller produced a brief at all. A session that answered with an empty object parses and is worth nothing, so the summary is required: it is the one part every reader of the brief uses. So is the size, one of Sizes: it is what decides how much of a review the change gets.

type Bundle

type Bundle[R Reference] struct {
	Ref     R        `json:"ref"`
	Title   string   `json:"title,omitempty"`
	Author  string   `json:"author,omitempty"`
	Items   []Item   `json:"items"`
	Skipped []string `json:"skipped,omitempty"`
	// Excluded are the generated files the caller took out of the diff,
	// which is the diff the items hold and the sessions read.
	Excluded []ExcludedFile `json:"excluded,omitempty"`
}

Bundle is caller-supplied context, in acquisition order, without truncation.

func (*Bundle[R]) Of

func (b *Bundle[R]) Of(source string) []Item

Of returns the items one source contributed, in bundle order.

func (*Bundle[R]) Sources

func (b *Bundle[R]) Sources() []string

Sources lists the sources that contributed an item, in first-seen order without repeats, including when items from a source are interleaved.

func (*Bundle[R]) Text

func (b *Bundle[R]) Text() string

Text renders the bundle as the markdown a session reads: one section per item, its content in a fence long enough to hold it, and what was skipped at the end.

type Comparator

type Comparator func(title, body, otherTitle, otherBody string) bool

Comparator reports whether two title/body pairs describe the same problem. It is also used for reviewer-note text matching. Nil disables text matching; anchored findings with overlapping lines and the same category still merge.

type Decision

type Decision struct {
	// Finding is the id of the finding (Finding.ID).
	Finding string `json:"finding"`
	// Action is the action taken on it.
	Action string `json:"action"`
	// Reason is why, for an action that records one.
	Reason string `json:"reason,omitempty"`
	// Comment is the text the finding is posted as, when triage edited it.
	Comment string `json:"comment,omitempty"`
	// Question and Answer are what an ask asked the angle and what the
	// angle answered, and Added the ids of the findings the answer turned
	// up that the review did not have.
	Question string   `json:"question,omitempty"`
	Answer   string   `json:"answer,omitempty"`
	Added    []string `json:"added,omitempty"`
}

Decision is what triage decided about one finding: the action taken on it, and what went with the action. The actions are the triage queue's (triage.go: ActionSelect, ActionDismiss, ActionDefer, ActionAsk), and what each records here is its own: a dismissal its reason, a selection the comment text when it was edited, an ask its question, the answer and the findings the answer added.

type Distiller

type Distiller[R Reference] struct {
	// Agent runs the session.
	Agent Agent
	// Dir is the checkout of the repository under review, which the
	// session's read-only tools can reach. It is "" on a machine that has
	// none, and the session then runs in an empty
	// directory of its own: a review must not read whichever repository the
	// command happened to be run in.
	Dir string
}

Distiller runs the first session of a review: it reads the context bundle and writes the brief every session after it starts from.

It is the session that turns a gather into a review. The bundle is raw and as large as the supplied context; the brief is short, angle-agnostic and the same for every angle, so a change in what the angles are told starts here rather than in five prompts.

func (*Distiller[R]) Distill

func (d *Distiller[R]) Distill(ctx context.Context, b *Bundle[R]) (*Brief[R], error)

Distill runs the distiller session over the bundle and returns the brief it produced. The session is asked for its reading of the context and for nothing the caller already knows: the reference, the sources gathered and what they could not read are copied out of the bundle afterwards, so no part of the brief is a fact a session could have got wrong.

type ExcludedFile

type ExcludedFile struct {
	Path    string `json:"path"`
	Added   int    `json:"added"`
	Removed int    `json:"removed"`
	Reason  string `json:"reason,omitempty"`
}

ExcludedFile is one file the caller took out of the diff before the review saw it, a generated one, and what the change did to it: the number of lines it added and removed there, and why the file was excluded, in the caller's words. The brief lists them so every session knows what nobody reviewed, and Exclude drops a finding anchored in one.

func (ExcludedFile) String

func (f ExcludedFile) String() string

String renders the file for a list: its path, its line counts and, when there is one, the reason.

type Finding

type Finding struct {
	// ID names the finding in triage. It is the first eight hex digits of
	// the SHA-256 of the file, side, lines and title, so it is the same on
	// every merge of the same findings and never repeats across the
	// findings one session adds after another.
	ID string `json:"id"`
	// Angle is the angle that found it, a name in BuiltinAngles, and
	// SessionID that angle's session (AngleRun.SessionID), which is what
	// the ask action resumes with a question about it.
	Angle     string `json:"angle"`
	SessionID string `json:"session_id,omitempty"`
	// Category is the kind of problem, in the angle's own word or two,
	// lowercased: "naming", "missing test". A project pins a category's
	// severity by this name (Settings.Severity).
	Category string `json:"category"`
	// Severity is one of SeverityInfo, SeverityLow, SeverityMedium and
	// SeverityHigh, after the judge has normalised what the session said
	// and applied the project's pins. Never SeverityOff: a finding in a
	// category pinned off is dropped, not kept.
	Severity string `json:"severity"`
	// File, Lines and Side anchor the finding to the diff: the path in the
	// repository, the lines in it, and which side of the change they are
	// on. A finding about the change as a whole has none of them.
	File  string    `json:"file,omitempty"`
	Lines LineRange `json:"lines,omitzero"`
	Side  string    `json:"side,omitempty"`
	// Title is the finding in one line and Body what is wrong and why it
	// matters, in the two or three sentences prompts/angle.md asks for:
	// what is posted on the lines, where Evidence is not.
	Title string `json:"title"`
	Body  string `json:"body"`
	// Suggestion is the text that would replace the lines, when the angle
	// could write it.
	Suggestion string `json:"suggestion,omitempty"`
	// Evidence is what the angle read that shows the problem. Triage shows
	// it after the body; a posted review and a report leave it out.
	Evidence string `json:"evidence,omitempty"`
	// Sources are where the rule or the requirement the finding is about
	// was read: "#12", "CONTRIBUTING.md".
	Sources []string `json:"sources,omitempty"`
	// AlsoFrom names the other angles that reported the same finding, when
	// the judge merged theirs into this one.
	AlsoFrom []string `json:"also_from,omitempty"`
}

Finding is one problem a review found.

func Exclude

func Exclude(findings []Finding, excluded []ExcludedFile) (kept, dropped []Finding)

Exclude drops the findings anchored in one of the files the caller took out of the diff (Bundle.Excluded): a session that read past the diff and reported a generated file anyway. It returns the findings kept, in their order, and the ones dropped. A finding about the change as a whole is kept: it is anchored nowhere.

func Merge

func Merge(findings []Finding, project *Settings, alike Comparator) []Finding

Merge is the judge's list: findings, from any number of angles and sessions, normalised, pinned and dropped as project says, deduplicated, ordered most severe first and given their ids. It is what Judge runs over the angle sessions' answers and what a later session's findings are merged into the list with: an id is a hash of what places a finding, not its position, so merging the list again with new findings appended keeps the ids of the ones already in it.

func ParseFindings

func ParseFindings(angle, sessionID, text string) ([]Finding, error)

ParseFindings reads the findings out of what an angle session answered: the "findings" list of the JSON object in it, marked as found by angle and sessionID. Every finding comes back as the session said it, trimmed, with its category lowercased and its anchor made consistent (no lines or side without a file, a side that is SideNew or SideOld); the judge does the rest. An answer with no JSON object or a malformed findings field is an error. A missing or null findings field returns no findings and no error.

A finding with neither title nor body is dropped: there is nothing to show a person. One with a body and no title is kept under its first line.

func (*Finding) Anchored

func (f *Finding) Anchored() bool

Anchored reports whether the finding points at a file.

func (*Finding) Comment

func (f *Finding) Comment() string

Comment is the text a finding is posted as when triage does not edit it: its title, then its body. The suggestion is not in it: the output renders that as a suggestion of its own, and the text is what a person edits.

type Findings

type Findings struct {
	// Items are the findings, deduplicated, severity-normalised, most
	// severe first. Empty for a change with nothing wrong.
	Items []Finding `json:"findings"`
	// Skipped names failed sessions and answers ParseFindings could not read,
	// each with why. Missing or null findings lists are successful empty
	// results and are not skipped.
	Skipped []string `json:"skipped,omitempty"`
	// Silenced are the findings the reviewer notes acted on (noise.go): the
	// ones a rule kept out of Items, and the ones it let through one
	// severity lower. It is what a review answers "what did my notes hide"
	// with, and empty for a review nothing was hidden from.
	Silenced []Silenced `json:"silenced,omitempty"`
}

Findings is what the judge made of the angle sessions: the one list a review triages, and the angles it could not read.

func Judge

func Judge(runs []AngleRun, project *Settings, alike Comparator) *Findings

Judge merges what the angle sessions came to into the findings a review triages. Failed runs and answers ParseFindings cannot parse (including malformed findings fields) contribute nothing and are named in Findings.Skipped. Missing or null findings lists contribute no findings without being skipped. Parsed findings are merged with Merge under project's category pins. A nil project pins nothing.

func ReadFindings

func ReadFindings(dir string) (*Findings, error)

ReadFindings reads the merged findings back out of a review's artifact directory.

type Item

type Item struct {
	// Source is the caller-supplied name of the source that produced the item.
	Source string `json:"source"`
	// Name says which piece it is, in whatever way the source names its
	// own: a path, a change reference, a symbol.
	Name string `json:"name"`
	// Content is the text, as it was read.
	Content string `json:"content"`
}

Item is one piece of context a source gathered.

type LineRange

type LineRange struct {
	Start int `json:"start"`
	End   int `json:"end"`
}

LineRange is the lines a finding is about, both ends inclusive, 1-based. It is written as the two-element array the angle prompt asks for, [start, end], and read from that, from a one-element array, from a bare number and from {"start": n, "end": m}: every way a session has written it. The zero value is no lines at all.

func (LineRange) IsZero

func (r LineRange) IsZero() bool

IsZero reports whether the range holds no lines, which is what leaves it out of the JSON.

func (LineRange) MarshalJSON

func (r LineRange) MarshalJSON() ([]byte, error)

MarshalJSON writes the range as [start, end].

func (LineRange) Overlaps

func (r LineRange) Overlaps(o LineRange) bool

Overlaps reports whether the two ranges share a line. Two empty ranges share none.

func (LineRange) String

func (r LineRange) String() string

String is the range as a person writes it: "12" or "12-14".

func (*LineRange) UnmarshalJSON

func (r *LineRange) UnmarshalJSON(data []byte) error

UnmarshalJSON reads every shape a range has been written in. A range that makes no sense (an end before its start, a line 0 or below) reads as no lines rather than as an error: a session that got the lines wrong still found something.

type Point

type Point struct {
	Text string `json:"text"`
	// Source is where the statement was read, in the distiller's words:
	// "#567", "CLAUDE.md", "the pull request body". It is empty when the
	// distiller named none.
	Source string `json:"source,omitempty"`
}

Point is one statement in the brief and where it came from: a criterion and the issue that asked for it, a style rule and the file it is written in.

type Reference

type Reference interface {
	fmt.Stringer
	URL() string
	ReviewScope() string
}

Reference is caller-owned review identity. Its JSON representation is preserved in artifacts; agentcore only uses its display text, link and opaque rule scope. Implementations used with ReadBrief/ReadArtifact must support JSON decoding.

type Rule

type Rule struct {
	// Scope, Angle and Category are what the finding must be to match, each
	// one anyValue or empty for "whatever it is".
	Scope    string
	Angle    string
	Category string
	// Action is RuleDrop or RuleDownrank.
	Action string
	// Text is the dismissal reason the rule was made from, which a finding's
	// title is compared against. A rule with no text matches every finding
	// its repo, angle and category match: that is how a whole category is
	// silenced.
	Text string
	// Count is how many dismissals the rule was made from, refreshed by
	// every consolidation. It says how sure a person was, and nothing reads
	// it back.
	Count int
}

Rule is a dismissal pattern: what a review does with a finding that a person has said no to before.

func (Rule) Line

func (r Rule) Line() string

Line is the rule as it is written in the file.

func (Rule) Matches

func (r Rule) Matches(repo string, f *Finding, compare Comparator) bool

Matches reports whether the rule is about this finding of a review of repo: its repository, angle and category, and its text against the finding's title (see the file comment above).

type Runner

type Runner[R Reference] struct {
	Distiller   *Distiller[R]
	Angles      *Angles[R]
	Settings    *Settings
	Rules       []Rule
	Compare     Comparator
	Log         io.Writer
	Progress    func(string, AngleEvent)
	AnglesReady func([]string)
}

Runner reviews supplied context and diff. The caller owns acquisition, artifact naming, agent profiles, and publication.

func (*Runner[R]) Run

func (r *Runner[R]) Run(ctx context.Context, dir string, bundle *Bundle[R], diff string) (*Artifact[R], error)

Run writes each stage into dir. Failures before the brief remove dir, including anything acquired there; later failures leave partial artifacts. One failed angle is non-fatal when another succeeds.

type Settings

type Settings struct {
	Angles     map[string]bool
	Categories map[string]string
}

Settings controls angle selection and category severity independently of configuration files or acquisition policy. Missing angles are enabled.

func (*Settings) EnabledAngles

func (p *Settings) EnabledAngles() []string

EnabledAngles lists the angles this project enables, in BuiltinAngles order. A review runs the ones among them its change's size calls for (anglesFor in angles.go).

func (*Settings) Severity

func (p *Settings) Severity(category string) string

Severity is the severity this project pins findings in category to, and "" when it pins none. A category pinned to SeverityOff is dropped.

type Silenced

type Silenced struct {
	// ID, Title, Angle and Category are the finding's, as it was when the
	// rule matched.
	ID       string `json:"id"`
	Title    string `json:"title"`
	Angle    string `json:"angle"`
	Category string `json:"category"`
	// Action is what the rule did: RuleDrop, and the finding is not in the
	// list at all, or RuleDownrank, and it is in it one severity lower.
	Action string `json:"action"`
	// Severity is the severity the finding had before the rule acted.
	Severity string `json:"severity"`
	// Rule is the rule that matched, as the notes file writes it.
	Rule string `json:"rule"`
}

Silenced is one finding the reviewer notes acted on: enough of it to say what was hidden and which rule hid it, without keeping the finding itself.

type TouchedArea

type TouchedArea struct {
	// Name is the area in the project's own terms: a package, a command, a
	// document.
	Name string `json:"name"`
	// Paths are the files the change touched in it.
	Paths []string `json:"paths,omitempty"`
	// Summary is what the change did there.
	Summary string `json:"summary,omitempty"`
}

TouchedArea is one part of the project the change touched.

type Triage

type Triage struct {
	// Decisions are the decisions taken, in the order they were taken.
	Decisions []Decision `json:"decisions"`
}

Triage is the triage state of a review: what a person, or in factory mode an agent, decided about its findings. The triage queue (triage.go) writes it with every decision, and reads a judged review that has none as one never triaged.

func ReadTriage

func ReadTriage(dir string) (*Triage, error)

ReadTriage reads the triage state back out of a review's artifact directory.

Jump to

Keyboard shortcuts

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