Documentation
¶
Index ¶
- Constants
- Variables
- func CompareFindings(a, b Finding) int
- func Filter(findings []Finding, rules []Rule, repo string, compare Comparator) ([]Finding, []Silenced)
- func JSONObject(text string) (string, bool)
- func NoiseSection(rules []Rule, repo, angle string) string
- func ResumePrompt(run AngleRun, question string) string
- func SameFinding(a, b *Finding, compare Comparator) bool
- func WriteAngleRun(artifact string, run *AngleRun) error
- func WriteBrief[R Reference](dir string, b *Brief[R]) error
- func WriteFindings(dir string, f *Findings) error
- func WriteTriage(dir string, t *Triage) error
- type Agent
- type AgentRequest
- type AgentResult
- type AngleEvent
- type AngleRun
- type Angles
- type Artifact
- type Brief
- type Bundle
- type Comparator
- type Decision
- type Distiller
- type ExcludedFile
- type Finding
- type Findings
- type Item
- type LineRange
- type Point
- type Reference
- type Rule
- type Runner
- type Settings
- type Silenced
- type TouchedArea
- type Triage
Constants ¶
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; core does not create a checkout.
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.
const ( RuleDrop = "drop" RuleDownrank = "downrank" )
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].
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.
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.
const DistillerName = "distiller"
DistillerName is the name of the distiller session, in an error message.
const FindingsFile = "findings.json"
FindingsFile is the name the merged findings are written under inside a review's artifact directory.
const TriageFile = "triage.json"
TriageFile is the name the triage state is written under inside a review's artifact directory.
Variables ¶
var BuiltinAngles = []string{AngleQuickGeneral, AngleGeneral, AngleDocs, AngleTests, AngleAcceptance, AngleSideEffects}
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).
var Severities = []string{SeverityOff, SeverityInfo, SeverityLow, SeverityMedium, SeverityHigh}
Severities lists the accepted severity values, in the order they are printed.
var Sizes = []string{"xs", "s", "m", "l", "xl"}
Sizes are the sizes a brief can give a change, smallest first.
Functions ¶
func CompareFindings ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
WriteFindings writes the merged findings into a review's artifact directory, creating it when it is not there.
func WriteTriage ¶
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 ¶
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.
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. // Core 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.
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 ¶
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.
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 ¶
ParseBrief reads the brief out of what the session answered.
func (*Brief[R]) Text ¶
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 ¶
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.
type Comparator ¶
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 ¶
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 ¶
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.
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 ¶
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 ¶
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 ¶
IsZero reports whether the range holds no lines, which is what leaves it out of the JSON.
func (LineRange) MarshalJSON ¶
MarshalJSON writes the range as [start, end].
func (LineRange) Overlaps ¶
Overlaps reports whether the two ranges share a line. Two empty ranges share none.
func (*LineRange) UnmarshalJSON ¶
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 ¶
Reference is caller-owned review identity. Its JSON representation is preserved in artifacts; core 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.
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 ¶
Settings controls angle selection and category severity independently of configuration files or acquisition policy. Missing angles are enabled.
func (*Settings) EnabledAngles ¶
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).
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 ¶
ReadTriage reads the triage state back out of a review's artifact directory.