bundle

package
v0.2.0-rc.1 Latest Latest
Warning

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

Go to latest
Published: Nov 11, 2026 License: MIT Imports: 33 Imported by: 0

Documentation

Overview

Description images: the rendered-image and markdown-upload walk of a pull request description, image identity and sniffing, the attachment listing of a bundle, and the archive that carries the images to a run.

Package bundle defines the evidence bundle: the input a review generation run reads, and the diff index that anchors its hunks.

Bundle is a dedicated type, not a host's stored rows or API types directly: its fields are the only way data leaves the host for the model, so a new column elsewhere cannot widen what a generation run reads by accident.

Code checkout. A generation run reads the repository's code, not only the diff, so its risk and behavior judgments can account for callers, invariants and existing tests the diff does not show; this file exports the head tree and compared merge-base paths into one budgeted archive and unpacks it for the run.

GitHub evidence mapping every host applies the same way, whether it reads stored rows or asks GitHub directly: identifiers, states, bot flags and review thread placement.

Index

Constants

View Source
const (
	AttachmentStored      = "stored"
	AttachmentUnsupported = "unsupported"
	AttachmentTooLarge    = "too_large"
	AttachmentOverLimit   = "over_limit"
	AttachmentExternal    = "external"
	AttachmentFailed      = "failed"
)

Capture states of a description image.

View Source
const (
	OmittedSizeReason      = "omitted_size"
	OmittedSubmoduleReason = "omitted_submodule"
	OmittedBinaryReason    = "binary"
	OmittedBudgetReason    = "omitted_budget"
)

Checkout omission reasons. OmittedBinaryReason is the reason diff.go gives a binary hunk, so omitting a file git also diffs as binary leaves its hunk as it was.

View Source
const (
	RoleCode      = "code"
	RoleTest      = "test"
	RoleGenerated = "generated"
	RoleMigration = "migration"
	RoleDocs      = "docs"
	RoleConfig    = "config"
	RoleVendored  = "vendored"
)
View Source
const (
	ReferenceIssueKey             = "issue_key"
	ReferenceSpec                 = "spec"
	ReferenceCherryPick           = "cherry_pick"
	ReferenceStackedOn            = "stacked_on"
	ReferenceSupersedes           = "supersedes"
	ReferenceIncludes             = "includes"
	ReferenceFollowUp             = "follow_up"
	ReferenceAuthorshipDisclosure = "authorship_disclosure"
	ReferenceImage                = "image"
	ReferenceVideo                = "video"
)

Reference kinds.

View Source
const CitedPromptHeadBytes = 1024

CitedPromptHeadBytes is how much of a cited prompt's text the first shortening keeps.

View Source
const EvidenceBudgetExceededReason = "evidence byte budget exceeded"

EvidenceBudgetExceededReason prefixes the error Fit returns when the bundle cannot be made to fit its byte limits.

View Source
const PromptScanChars = 1 << 20

PromptScanChars is the most characters of a prompt's text, and of its reply, a session source reads. It is generous enough that the cut never fires in practice: byte trimming (Fit) is what bounds prompt text, in the documented trim order. It keeps one oversized prompt from being read whole.

View Source
const ProvisionalReviewConfigPath = "REVIEW.md"

ProvisionalReviewConfigPath is where this loader looks for REVIEW.md until the shaping location is settled.

View Source
const SummaryCommentMarker = "<!-- baum:pr-summary -->"

SummaryCommentMarker opens the pull-request summary comment a baum host posts. That comment is the host's own output, not evidence about the pull request, so it is left out of the conversation; anyone else's comment starting with the marker is an ordinary one.

Variables

View Source
var (
	// ErrOutputTooLarge reports git output over the configured limit. A
	// patch fetcher returns it to make that file textless.
	ErrOutputTooLarge = errors.New("git output exceeds configured limit")
	// ErrPatchUnreadable reports a file git could not diff. A patch fetcher
	// returns it to make that file textless.
	ErrPatchUnreadable = errors.New("git could not diff the file")
)
View Source
var ErrInvalidArchive = errors.New("invalid archive")

ErrInvalidArchive reports a checkout or attachments archive that does not have the shape this package writes: an unexpected entry, a path outside the tree, a missing file or a corrupt stream.

View Source
var ErrNotFound = errors.New("not found")

ErrNotFound reports that a source has no such commit, path or repository. A blob or export source returns it, or an error wrapping it, so the REVIEW.md loader and the checkout export can treat the absence as an ordinary outcome.

Functions

func ApplyCaps

func ApplyCaps(bundle *Bundle, caps Caps)

ApplyCaps enforces the count ceilings, after sorting, so the same rows in any order produce the same selection: sessions by confidence then earliest start; comments to the newest N plus every review verdict. It does not cap prompts or command events: the source that collects sessions already selected them (MaxPromptsPerSession, MaxCommandEventsPerSession). Nor does it cap patch lines or alt text: Fit does, after redaction.

func ApplyCheckoutOmissions

func ApplyCheckoutOmissions(b *Bundle, omissions []CheckoutOmission)

ApplyCheckoutOmissions marks every diff hunk of an omitted file, at either of its paths, textless and appends one generator.truncated note per omission reason with the number of files it omitted. A hunk whose old and new paths were both omitted takes the reason of the later path.

func AttachCommitChanges

func AttachCommitChanges(ctx context.Context, comparer CommitComparer, pr *PullRequest) error

AttachCommitChanges reads the line change of every commit made after the pull request was opened, for the review exchange's changes after opening. A commit the comparer cannot compare keeps no counts, which leaves that figure unknown rather than failing the build.

func AttachThreads

func AttachThreads(b *Bundle, threads []ReviewThreadInput)

AttachThreads sets the bundle's threads, ordered by ID, places each review comment of the conversation in its thread, and records review threads as available. A thread's URL is its first comment's, and its line is set only for a current right-side line, the only new-side position a hunk holds.

func AttachmentID

func AttachmentID(sourceURL string) string

AttachmentID derives an image's ID from its markdown source URL.

func BudgetExceededReason

func BudgetExceededReason(name string) string

BudgetExceededReason names which checkout budget a failure exceeded: exceeding it fails the run naming the budget.

func CapReviewConfigContent

func CapReviewConfigContent(config *ReviewConfig) bool

CapReviewConfigContent bounds config.Content to its leading bytes in place, reporting whether it cut anything.

func ChangePaths

func ChangePaths(change FileChange) []string

ChangePaths returns the pathspecs that let a single-file diff detect the change as a rename: the old path and, when it differs, the new path.

func ChangesReviewConfig

func ChangesReviewConfig(hunks []Hunk) bool

ChangesReviewConfig reports whether the diff adds, edits, renames or removes REVIEW.md: a rename away from the location carries it as OldPath.

func CheckRunID

func CheckRunID(databaseID int64) string

CheckRunID is a check run's identifier: its GitHub database ID.

func CommandOutcome

func CommandOutcome(status string) string

CommandOutcome maps a tool result's status to a command event's closed outcome vocabulary (succeeded, failed, interrupted, unknown). An empty status, a tool use with no recorded result, is "unknown".

func CommandText

func CommandText(input []byte) string

CommandText reads the shell command line from a tool use's raw input JSON, trying the "command" and "cmd" keys different vendors use (sessions/codexsession/tool_results.go tries the same pair). A command value may be a string or a string array (argv-style vendors); both are normalised to one shell-syntax string. The text is for ParseCommandParaphrase only and must never enter a bundle.

func ExplicitAutomationProvider

func ExplicitAutomationProvider(body string) (provider string, ok bool)

ExplicitAutomationProvider reports the disclosed automation provider named in a comment or review body. ok is true for any disclosure, including a generic "generated by <tool>" phrase naming no recognised provider, in which case provider is empty.

func Fit

func Fit(bundle *Bundle, caps Caps) error

Fit trims the encoded bundle in the documented order until its content is within MaxBytes, then checks the diff index against its own MaxDiffIndexBytes. The diff index is every hunk's entry without its patch text; patch text is content. So trimming can empty every patch but never drops a hunk, and the hunk count alone never exceeds the content limit. The documented order is assistant replies, older prompts, command paraphrases, comment bodies oldest first (keeping review verdicts), generated and vendored patch text, superseded session decisions, ordinary patch text, the text of cited prompts, then whole sessions from lowest confidence. A session's current decisions go only with the session: they are a short, reviewed account of what its prompts decided, so they outlast every cut of raw prompt text. The prompts at the turns they cite are kept with them: the older-prompts stage spares them, and before any session is dropped their text is shortened, longest first, to a leading CitedPromptHeadBytes and then, if still needed, emptied, keeping each prompt's entry and index so a surviving decision's prompt anchors still resolve. REVIEW.md content is cut first, ahead of every documented stage, because it is supplementary guidance rather than PR evidence, and because a fixed content cap would otherwise make a MaxBytes configured below it permanently unsatisfiable. The attachments part counts as content but no stage cuts it: the files it lists reach the agent whole (the description-image rules).

Fit runs after Redact. It first cuts each hunk's patch to MaxHunkPatchLines and each attachment's alt text and heading to MaxImageAltBytes, so those cuts always follow redaction: a patch reaches Redact with the margin diff parsing keeps past the line cap, and a secret the cap runs through is masked whole.

func FlagBotContribution

func FlagBotContribution(item *ConversationItem)

FlagBotContribution sets Bot and BotTool from the recognised disclosures: bot reports and agent reviews are flagged with their tool. A REVIEW.md marker registry, which would set BotReport, is not built.

func FlagBotReport

func FlagBotReport(item *ConversationItem, markers []string)

FlagBotReport sets BotReport on a bot's item whose body carries one of markers, the bot-report markers a REVIEW.md marker registry names. The registry is not built yet, so hosts pass none and BotReport stays false.

func GitHubContentURL

func GitHubContentURL(u *url.URL) bool

GitHubContentURL also admits the asset storage GitHub redirects uploads to.

func HunkDiffURL

func HunkDiffURL(path string, line int) string

HunkDiffURL is a hunk's DiffURL: GitHub's diff fragment shape, diff-<sha256(path)>R<line>, for the path and first new line it records. A document's github_url is this value, so a host can derive it from the hunk's path and new_range rather than store it.

func IsBotActor

func IsBotActor(actorType string) bool

IsBotActor reports whether a GitHub actor type (GraphQL's __typename, or REST's user type) is a Bot.

func KeepKnownCommandTargets

func KeepKnownCommandTargets(sessions []Session, knownPath func(string) bool)

KeepKnownCommandTargets clears every command target of sessions that knownPath does not accept and that is not one of the session's own touched paths or a directory above one, for a host that paraphrases commands before the paths it knows are all read.

func KnownPaths

func KnownPaths(paths ...string) func(string) bool

KnownPaths returns a knownPath predicate for ParseCommandParaphrase that accepts each of paths and every directory above it, but not the repository root. Paths are cleaned and a leading "./" is ignored.

func MarkdownUploads

func MarkdownUploads(body string) map[string]string

MarkdownUploads maps each upload's asset UUID to its markdown source URL, without a query or fragment: a pasted signed link keeps no token.

func MaxAttachmentsArchiveBytes

func MaxAttachmentsArchiveBytes(maxImages int, maxImageBytes int64) int64

MaxAttachmentsArchiveBytes bounds an attachments archive: every image at its limit, a tar header and padding for each, and the end marker.

func ProviderFromLogin

func ProviderFromLogin(login string) string

ProviderFromLogin reports the automation provider a bot login's name discloses, or "" when none is recognised.

func PullRequestState

func PullRequestState(state string, merged bool) string

PullRequestState is GitHub's state lower-cased, or "merged" once the pull request is merged.

func Redact

func Redact(ctx context.Context, bundle *Bundle, redactor *Redactor) error

Redact masks secrets and e-mail addresses in every bundle string field, after reference extraction (which runs against the unredacted bundle) and before the byte-fit pass and the hunk line cap it starts with. Each field is redacted as one text, so a secret spanning lines is found, and keeps its length and lines. The hunks of one file are redacted together, as the file's patch, so the engine follows a key that runs on from one hunk into the next (goredact v0.4.0 and later mask it in both); each hunk keeps its diff markers and its header's line ranges. Runs of base64 lines and base64 hunk headings are masked as key material too, a deliberate over-mask (redactPatches, base64Masks). A patch still holds the margin diff parsing keeps past the line cap, and the lines an earlier hunk of the file drops are read too, so a secret the cap runs through is masked as in the whole patch. MaskedSpanCount is the number of spans masked, e-mail addresses and base64 runs the engine left included. It counts the spans in the text Redact reads, each file's patch up to its last hunk's margin, so a secret spanning hunks counts once, and one only in lines the cap then drops counts too.

Mentions are not rewritten: nothing in the bundle is posted to a code host as it is, and a field may hold code (a patch, a suggestion block, a prompt), where an "@" is an annotation, decorator or package scope. Text published to a code host has its mentions defanged where it is published.

Every free-text or URL field is covered, including References[].Value — ReferenceAuthorshipDisclosure copies up to 80 trailing characters of raw text and an image/video reference copies the matched URL, so a secret masked in Body/Title could otherwise still surface here — and branch names, check names/URLs, requested-reviewer logins, comment paths and a session decision's title, summary, rationale, rejected alternative, evidence and files, none of which are structurally constrained enough to skip. SHA, ID and closed-enum fields (Kind, State, Role, Change, Outcome, a decision's Who, Category and Trigger, ...) are not redacted: they are not free text, and running secret detection on a hex SHA risks a false-positive match corrupting the hash a hunk/commit anchor resolves against. DiffURL is a generated hash fragment, reference Source is a fixed tag with a numeric comment ID, and AuthorAssociation is a GitHub enum; these also contain no user-authored text. ReviewConfig.Content (REVIEW.md) is likewise not redacted: unlike a PR body or comment, it has no audience but the review agent itself — it never displays to a human viewer — and the model can already read the same unredacted file directly off the checkout via its Read tool, so masking the bundled copy would only create an inconsistency between the two, not add any protection.

func RedactFilePatch

func RedactFilePatch(ctx context.Context, redactor *Redactor, path, patch string) (masked string, ok bool, err error)

RedactFilePatch masks one file's patch, its text from the first hunk header on, as Redact masks the hunks diff parsing takes from the same patch: parseFileHunks reads it, with no line cap, and redactPatches masks the hunks as one file's text. A patch read after the bundle was built, such as the viewer's excerpt of a hunk whose text a document left out, therefore shows no secret the stored hunk would have hidden. The result is the masked hunk texts, each ending in a newline and without a CR before it, as stored hunks hold them. ok is false for a patch diff parsing reads as textless: binary, without a hunk, or with a line over its limit.

func RoleForPath

func RoleForPath(filePath string) string

RoleForPath derives a hunk's role from its repository-relative path. Rules are checked in order; the first match wins.

func SetDigest

func SetDigest(bundle *Bundle) error

SetDigest stamps bundle.Digest with the SHA-256 of the encoded bundle, so identical content in any order produces an identical digest.

func SniffImage

func SniffImage(content []byte) (contentType string, width, height int, ok bool)

SniffImage accepts PNG, JPEG, GIF and WebP by content and reads their size.

func SortChecks

func SortChecks(checks []Check)

SortChecks orders checks by ID, so the same checks always encode the same.

func SortConversation

func SortConversation(items []ConversationItem)

SortConversation orders items by creation time, undated items last, then by ID.

func StatusCheckID

func StatusCheckID(nodeID string, databaseID int64) string

StatusCheckID is a commit status's identifier: its GraphQL node ID, or its database ID when the host has no node ID.

func TargetPath

func TargetPath(target string) string

TargetPath is the repository path a command target names: the target without a trailing Go package pattern "/...".

func UnpackAttachments

func UnpackAttachments(ctx context.Context, archive, dir string, attachments []Attachment, maxImageBytes int64) error

UnpackAttachments writes exactly the images the bundle lists to attachments/<id>.<ext> in the run directory, read-only. An archive holding anything else, missing a listed image or not matching its hash fails with ErrInvalidArchive. An empty archive path means the run has no images.

The caller must bound the archive's size before calling (see MaxAttachmentsArchiveBytes). A maxImageBytes of zero puts no per-entry limit before the hash check.

func UnpackCheckout

func UnpackCheckout(ctx context.Context, archive, dir string, caps CheckoutConfig) error

UnpackCheckout writes a gzip-compressed checkout archive into dir as the read-only head/ and merge-base/ trees, enforcing caps again so a run never reads more than the builder was allowed to write. An archive that does not have the shape WriteArchive produces fails with ErrInvalidArchive; one over a budget fails with BudgetExceededReason naming it, and so does a zero cap.

The caller must bound the archive's size before calling (see MaxArchiveBytes): the gzip stream is drained after the tar trailer without a limit, and directory entries do not count toward MaxTotalFiles.

func UnpackHeadCheckout

func UnpackHeadCheckout(ctx context.Context, archive, dir string, caps CheckoutConfig) error

UnpackHeadCheckout is UnpackCheckout for an archive written without a merge base: it holds head/ alone.

func ValidAttachmentID

func ValidAttachmentID(id string) bool

ValidAttachmentID reports whether id has the shape AttachmentID produces.

Types

type Attachment

type Attachment struct {
	Origins     []ImageOrigin `json:"origins,omitempty"`
	ID          string        `json:"id"`
	Path        string        `json:"path"`
	SourceURL   string        `json:"source_url,omitempty"`
	SourceURLs  []string      `json:"source_urls,omitempty"`
	ContentType string        `json:"content_type"`
	// Alt and Heading, the nearest markdown heading above the image, are
	// redacted and capped.
	Alt      string `json:"alt,omitempty"`
	Heading  string `json:"heading,omitempty"`
	Position int    `json:"position"`
	Width    int    `json:"width"`
	Height   int    `json:"height"`
	SHA256   string `json:"sha256"`
}

Attachment is one captured image. Its file is in the run directory at Path.

func DescriptionAttachments

func DescriptionAttachments(body string, images []DescriptionImage) []Attachment

DescriptionAttachments lists the stored images for the bundle, each under the nearest heading above it in the untrimmed body.

type BlobFetcher

type BlobFetcher interface {
	Blob(ctx context.Context, commitOID, path string) ([]byte, error)
}

BlobFetcher is the trusted blob accessor the loader reads one file through. It returns ErrNotFound, or an error wrapping it, for a commit or path that does not exist.

type Bundle

type Bundle struct {
	Repository   string             `json:"repository"`
	PullRequest  PullRequest        `json:"pull_request"`
	Diff         []Hunk             `json:"diff"`
	Checks       []Check            `json:"checks"`
	Conversation []ConversationItem `json:"conversation"`
	// Threads are the pull request's review threads with their resolution,
	// from the stored GitHub activity snapshot; empty when none was synced.
	Threads    []Thread    `json:"threads"`
	Sessions   []Session   `json:"sessions"`
	References []Reference `json:"references"`
	// Attachments are captured images, with description images first and native
	// session images carrying their recorded origins.
	// The byte fit counts them and never trims them.
	Attachments  []Attachment     `json:"attachments,omitempty"`
	ReviewConfig *ReviewConfig    `json:"review_config,omitempty"`
	Previous     *PreviousVersion `json:"previous,omitempty"`
	// Sources records which parts had data available, so an empty slot
	// downstream reads as absent input rather than model omission.
	Sources Sources `json:"sources"`
	// Truncated is one plain-language generator.truncated note per cut.
	Truncated []string `json:"truncated,omitempty"`

	// MaskedSpanCount is not part of the encoded bundle a model reads: it is
	// recorded with the stored version.
	MaskedSpanCount int `json:"-"`
	// FileComparisons preserve each stack member's path changes before hunk-ID
	// deduplication, for derived links into the member's comparison base.
	FileComparisons []FileComparison `json:"-"`
	// Digest is the bundle digest, computed from the encoded, redacted,
	// trimmed bundle, and stored with the version.
	Digest string `json:"-"`
}

Bundle is the generation run's input: everything the model may cite, each with the identifier its anchor type resolves against.

func (*Bundle) DecisionIDs

func (b *Bundle) DecisionIDs() map[string][]string

DecisionIDs returns, by root session ID, the DecisionID of each decision of each session that carries decisions, in the session's order; nil when no decision has one.

func (*Bundle) SetDecisionIDs

func (b *Bundle) SetDecisionIDs(ids map[string][]string)

SetDecisionIDs sets each session's decisions' DecisionID from ids, as DecisionIDs returned them for the same bundle. A session whose decisions do not number as many as its IDs gets none.

type Caps

type Caps struct {
	MaxSessions                int
	MaxPromptsPerSession       int
	MaxCommandEventsPerSession int
	MaxComments                int
	MaxHunkPatchLines          int
	// MaxBytes bounds the encoded bundle apart from the diff index's hunk
	// entries; patch text counts here. MaxDiffIndexBytes bounds those entries.
	MaxBytes          int
	MaxDiffIndexBytes int
	// MaxDiffFiles and MaxDiffPatchBytes bound what assembly reads for the
	// diff index.
	MaxDiffFiles      int
	MaxDiffPatchBytes int64
	// MaxImageAltBytes bounds each description image's alt text and heading.
	MaxImageAltBytes int
}

Caps are the configured count and byte ceilings applied to a bundle. ApplyCaps and Fit read the comment, session, patch, image and byte limits. MaxPromptsPerSession and MaxCommandEventsPerSession are applied by the source that collects sessions, and DiffLimits gives the limits diff assembly reads.

func (Caps) DiffLimits

func (c Caps) DiffLimits() DiffLimits

DiffLimits returns the limits BuildDiffIndexWithin reads.

type Check

type Check struct {
	// HeadSHA identifies checks retained from a different revision during refresh.
	HeadSHA string `json:"head_sha,omitempty"`
	ID      string `json:"id"`
	Name    string `json:"name"`
	// Kind is "check_run" or "status".
	Kind       string `json:"kind"`
	Conclusion string `json:"conclusion,omitempty"`
	Status     string `json:"status,omitempty"`
	// Required is true or false from readable branch protection, and
	// explicitly nil when the host cannot read it. Hosts that do not sync
	// branch protection or rulesets always leave it nil.
	Required    *bool      `json:"required"`
	URL         string     `json:"url,omitempty"`
	StartedAt   *time.Time `json:"started_at,omitempty"`
	CompletedAt *time.Time `json:"completed_at,omitempty"`
}

Check is one check run or commit status for the head.

type CheckoutBuilder

type CheckoutBuilder struct {
	// Config bounds the checkout; the builder reads it on every export.
	Config CheckoutConfig
}

CheckoutBuilder exports one run's isolated, budgeted code checkout.

func NewCheckoutBuilder

func NewCheckoutBuilder(config CheckoutConfig) *CheckoutBuilder

func (*CheckoutBuilder) WriteArchive

func (b *CheckoutBuilder) WriteArchive(ctx context.Context, pinned PinnedExport, head, mergeBase string, hunks []Hunk, output io.Writer) (omissions []CheckoutOmission, err error)

WriteArchive streams both trees from one pinned snapshot without checking them out; an empty mergeBase, which takes no hunks, writes the head tree alone. The compared paths go first, at the head and then at the merge base, and the rest of the head tree fills what the budget leaves: a file that does not fit is omitted with OmittedBudgetReason instead of failing the export, so the archive always stays within MaxTotalBytes and MaxTotalFiles. Binary files are omitted with OmittedBinaryReason.

A compared path the diff holds as text is never treated as binary: the archive applies working-tree-encoding, so a UTF-16 text file arrives with NUL bytes although git diffs its canonical content as text.

type CheckoutConfig

type CheckoutConfig struct {
	ScratchRoot   string `json:"-"`
	MaxFileBytes  int64  `json:"max_file_bytes"`
	MaxTotalBytes int64  `json:"max_total_bytes"`
	MaxTotalFiles int    `json:"max_total_files"`
}

CheckoutConfig bounds one run's checkout. MaxTotalBytes/MaxTotalFiles count only non-omitted content: a file omitted for exceeding MaxFileBytes, as binary or as submodule content, does not count toward either. WriteArchive omits files that would exceed them instead of failing; UnpackCheckout rejects an archive that exceeds them. ScratchRoot is local to each process and never crosses to a review agent.

A zero MaxTotalBytes or MaxTotalFiles means unlimited in WriteArchive but nothing allowed in UnpackCheckout; MaxFileBytes is always enforced, so zero omits or rejects every file.

func (CheckoutConfig) MaxArchiveBytes

func (c CheckoutConfig) MaxArchiveBytes() int64

MaxArchiveBytes bounds a checkout archive within the configured caps: its content plus tar headers and gzip overhead.

type CheckoutOmission

type CheckoutOmission struct {
	Path   string
	Reason string
}

CheckoutOmission is one file the checkout left out of the tree.

type CommandEntry

type CommandEntry struct {
	Program  string `json:"program"`
	Category string `json:"category"`
	Target   string `json:"target,omitempty"`
}

CommandEntry is one simple command within a (possibly compound or piped) execute tool use.

func ParseCommandParaphrase

func ParseCommandParaphrase(command string, knownPath func(string) bool) []CommandEntry

ParseCommandParaphrase extracts one entry per simple command from a possibly compound or piped command line. Raw command lines never survive past this function's return: it returns only program base name, category and an optional target. The target is the first argument that is path-shaped and, normalised, a path knownPath accepts: positive evidence it is a path of the repository, such as a changed file, a touched path or a file in the checkout. With a nil knownPath no entry has a target.

type CommandEvent

type CommandEvent struct {
	ID   string     `json:"id"`
	Time *time.Time `json:"time,omitempty"`
	// Outcome is "succeeded", "failed", "interrupted" or "unknown".
	Outcome  string         `json:"outcome"`
	Commands []CommandEntry `json:"commands"`
}

CommandEvent is one execute tool use. ID is the tool-use identifier the session_event anchor cites.

type Commit

type Commit struct {
	SHA         string     `json:"sha"`
	Subject     string     `json:"subject"`
	CommittedAt *time.Time `json:"committed_at,omitempty"`
	Additions   *int       `json:"additions,omitempty"`
	Deletions   *int       `json:"deletions,omitempty"`

	// Parents are the commit's parent SHAs, which the host reads to choose
	// the comparison for Additions and Deletions; not part of the encoded
	// bundle.
	Parents []string `json:"-"`
}

Commit is one synced commit of the pull request. Additions and Deletions are its change against its first parent, read only for commits made after the pull request was opened, and nil when the mirror cannot compare it; a merge commit carries zero, since what it brings in is not this pull request's change.

type CommitComparer

type CommitComparer interface {
	Compare(ctx context.Context, baseOID, headOID, mode string) (Comparison, error)
}

CommitComparer reads one commit's change against its parent.

type ComparedFile

type ComparedFile struct {
	Path    string `json:"path"`
	OldPath string `json:"old_path,omitempty"`
	Change  string `json:"change"`
}

ComparedFile records a file's names and presence across a comparison.

type Comparison

type Comparison struct {
	BaseOID      string       `json:"base_oid"`
	HeadOID      string       `json:"head_oid"`
	MergeBaseOID string       `json:"merge_base_oid,omitempty"`
	Files        []FileChange `json:"files"`
}

Comparison is the list of files that differ between two commits.

type ConversationItem

type ConversationItem struct {
	ID string `json:"id"`
	// Kind is "comment", "review" or "review_comment".
	Kind              string `json:"kind"`
	AuthorLogin       string `json:"author_login"`
	AuthorAssociation string `json:"author_association,omitempty"`
	// Bot is true when GitHub reports the author as a Bot actor.
	Bot bool `json:"bot"`
	// BotTool is the disclosed or recognised automation provider, set only
	// when Bot is true or a disclosure was found in the body; the helpers run
	// per contribution.
	BotTool string `json:"bot_tool,omitempty"`
	// BotReport is true for a bot-report marker from REVIEW.md's marker
	// registry, which is not built, so it is always false for now. The
	// host's own summary comment is not in the conversation at all.
	BotReport bool       `json:"bot_report,omitempty"`
	Body      string     `json:"body"`
	CreatedAt *time.Time `json:"created_at,omitempty"`
	// State is the review verdict for a review item.
	State string `json:"state,omitempty"`
	// Path is set for a review comment.
	Path string `json:"path,omitempty"`
	// Commit is the head a review assessed.
	Commit string `json:"commit,omitempty"`
	// Review is the review a review comment was submitted with.
	Review string `json:"review,omitempty"`
	// Thread and Resolved place a review comment in its review thread when
	// the activity snapshot holds it; ThreadRoot marks the thread's first
	// comment.
	Thread     string `json:"thread,omitempty"`
	ThreadRoot bool   `json:"thread_root,omitempty"`
	Resolved   *bool  `json:"resolved,omitempty"`
}

ConversationItem is one issue comment, review or review comment.

type DescriptionImage

type DescriptionImage struct {
	Origins    []ImageOrigin `json:"origins,omitempty"`
	ID         string
	SourceURL  string
	SourceURLs []string
	// Alt is redacted.
	Alt string
	// Position is the image's 1-based place among the description's images.
	Position    int
	State       string
	ContentType string
	Size        int64
	Width       int
	Height      int
	SHA256      string
	// ObjectKey is where the host stored the copy.
	ObjectKey string
}

DescriptionImage is one captured image. Native session copies have Origins and no SourceURL. Only a Stored image has its copy's fields set.

func WriteAttachments

func WriteAttachments(ctx context.Context, images []DescriptionImage, archive io.Writer, open func(context.Context, DescriptionImage) (io.ReadCloser, error), skipped func(DescriptionImage, error)) ([]DescriptionImage, error)

WriteAttachments archives the stored copies as a plain tar of attachments/<id>.<ext> entries and returns the images it holds. open reads one stored copy. A copy that cannot be read or no longer matches its hash is left out of the archive, and so of the bundle: capture never fails assembly. skipped, when not nil, is told of each image left out and why.

type DiffLimits

type DiffLimits struct {
	// MaxFiles bounds the changed files, checked before any patch is read.
	MaxFiles int
	// MaxPatchBytes bounds the patch bytes read across every file.
	MaxPatchBytes int64
	// MaxHunkLines is the per-hunk line cap Fit applies, with its note,
	// after redaction. Parsing keeps each hunk's leading MaxHunkLines
	// lines and up to redactionMargin bytes past them: the cap and its note
	// behave as on the full text, and redaction reads a secret the cap runs
	// through whole. A file whose hunk other than its last is cut keeps its
	// whole patch until Redact, which reads each file's hunks as one text;
	// MaxPatchBytes bounds what is kept.
	MaxHunkLines int
}

DiffLimits bound the diff index assembly reads. A zero field is unlimited.

type FileChange

type FileChange struct {
	OldPath   string `json:"old_path,omitempty"`
	NewPath   string `json:"new_path,omitempty"`
	Status    string `json:"status"`
	OldMode   string `json:"old_mode,omitempty"`
	NewMode   string `json:"new_mode,omitempty"`
	OldOID    string `json:"old_oid,omitempty"`
	NewOID    string `json:"new_oid,omitempty"`
	PatchHash string `json:"patch_hash,omitempty"`
	Additions *int64 `json:"additions,omitempty"`
	Deletions *int64 `json:"deletions,omitempty"`
}

FileChange is one file of a Comparison.

type FileComparison

type FileComparison struct {
	BaseRevision string         `json:"base_revision"`
	Changes      []ComparedFile `json:"changes"`
}

FileComparison is one stack member's file changes, in member order.

type Hunk

type Hunk struct {
	// ID hashes the file path and normalised hunk content, so it survives a
	// context shift and a rebase.
	ID      string `json:"id"`
	Path    string `json:"path"`
	OldPath string `json:"old_path,omitempty"`
	// Change is "added", "modified", "removed" or "renamed".
	Change string `json:"change"`
	// Role is one of code, test, generated, migration, docs, config,
	// vendored.
	Role      string `json:"role"`
	StartLine int    `json:"start_line,omitempty"`
	LineCount int    `json:"line_count,omitempty"`
	Additions int    `json:"additions"`
	Deletions int    `json:"deletions"`
	DiffURL   string `json:"diff_url"`
	// Patch is empty for a textless hunk: binary, unreadable, or omitted by
	// the checkout budget; the host sets TextlessReason for its omissions.
	Patch          string `json:"patch,omitempty"`
	Textless       bool   `json:"textless,omitempty"`
	TextlessReason string `json:"textless_reason,omitempty"`
	// contains filtered or unexported fields
}

Hunk is one entry of the diff index.

func BuildDiffIndex

func BuildDiffIndex(comparison Comparison, fetch PatchFetcher, roleFor func(path string) string) ([]Hunk, error)

BuildDiffIndex splits every compared file into hunks, in Comparison.Files order, assigning content-addressed IDs and roles.

Hunk IDs hash the file path and a normalised form of the hunk's changed lines (the "+"/"-" lines only, not the "@@" line numbers and not unchanged context): this is what makes an ID survive a context shift (the same change, with different surrounding context after a nearby edit) and a rebase (the same change against a different base). Two hunks in the same file whose changed lines are byte-identical (e.g. two blank-line-only hunks) hash equally; ordinal suffixes disambiguate them in file order.

func BuildDiffIndexWithin

func BuildDiffIndexWithin(comparison Comparison, fetch PatchFetcher, roleFor func(path string) string, limits DiffLimits) ([]Hunk, []string, error)

BuildDiffIndexWithin is buildDiffIndex within limits. Exceeding a file or byte limit fails with the checkout budget reason naming it.

type ImageOrigin added in v0.2.0

type ImageOrigin struct {
	Session      string     `json:"session"`
	ChildSession string     `json:"child_session,omitempty"`
	ChildInput   string     `json:"child_input,omitempty"`
	Turn         int        `json:"turn"`
	Input        string     `json:"input,omitempty"`
	Tool         string     `json:"tool,omitempty"`
	ToolName     string     `json:"tool_name,omitempty"`
	Kind         string     `json:"kind"`
	Position     int        `json:"position"`
	Timestamp    *time.Time `json:"timestamp,omitempty"`
}

ImageOrigin identifies a retained image's native session input or tool result. Session is the root card; ChildSession identifies nested agent work.

type PatchFetcher

type PatchFetcher func(paths ...string) ([]byte, error)

PatchFetcher returns the unified diff patch text for one file of a comparison, or nil for a binary or unreadable change. An ErrOutputTooLarge or ErrPatchUnreadable error makes that file textless. paths holds the old and new path of a rename so git can pair them; otherwise the one path.

type PinnedExport

type PinnedExport interface {
	ExportCommit(ctx context.Context, commitOID string) (io.ReadCloser, error)
	ExportCommitPath(ctx context.Context, commitOID, path string) (io.ReadCloser, error)
}

PinnedExport is one pinned snapshot's worth of exports: every call through it, for as long as the checkout that holds it runs, reads the same physical copy of the repository, so a rebuild cannot mix trees. A missing commit or path returns ErrNotFound or an error wrapping it.

type PreviousSection

type PreviousSection struct {
	ID                string          `json:"id"`
	Title             string          `json:"title"`
	Kind              string          `json:"kind"`
	HunkContentHashes []string        `json:"hunk_content_hashes"`
	Content           json.RawMessage `json:"content,omitempty"`
}

type PreviousVersion

type PreviousVersion struct {
	Version  int               `json:"version"`
	Sections []PreviousSection `json:"sections"`
	// HunkRanges is each hunk's right side in the previous version, by hunk
	// ID: its first line and line count. The host uses it to move the
	// sections' hunk anchors to where the same hunk sits now. It is never
	// part of the bundle.
	HunkRanges map[string][2]int `json:"-"`
	// Attachments are the IDs of the images the previous version was offered
	// (its index.attachments). When the bundle offers an image missing here,
	// no section's details are reused: only the details stage places images.
	// It is never part of the bundle.
	Attachments []string `json:"-"`
}

PreviousVersion is the current version's sections, for regeneration to partition against.

type Prompt

type Prompt struct {
	At           *time.Time `json:"at,omitempty"`
	Index        int        `json:"index"`
	ID           string     `json:"id"`
	Text         string     `json:"text"`
	Reply        string     `json:"reply,omitempty"`
	TouchedPaths []string   `json:"touched_paths,omitempty"`
}

Prompt is one human prompt. Index is the prompt's position among the session's human prompts; ID is its stored identifier, the prompt anchor.

type PullRequest

type PullRequest struct {
	Number            int    `json:"number"`
	State             string `json:"state"`
	Draft             bool   `json:"draft"`
	Title             string `json:"title"`
	Body              string `json:"body"`
	AuthorLogin       string `json:"author_login"`
	AuthorAssociation string `json:"author_association"`
	AuthorBot         bool   `json:"author_bot"`
	BaseRef           string `json:"base_ref"`
	BaseSHA           string `json:"base_sha"`
	// HeadRef is the pull request's own branch name — where a contributor
	// actually puts ticket keys and other references, unlike BaseRef (almost
	// always the default branch).
	HeadRef            string   `json:"head_ref"`
	HeadSHA            string   `json:"head_sha"`
	MergeBaseSHA       string   `json:"merge_base_sha"`
	MergedSHA          string   `json:"merged_sha,omitempty"`
	RequestedReviewers []string `json:"requested_reviewers"`
	// OpenedAt is when GitHub reports the pull request was opened.
	OpenedAt *time.Time `json:"opened_at,omitempty"`
	Commits  []Commit   `json:"commits"`
}

type Redactor

type Redactor struct {
	// contains filtered or unexported fields
}

Redactor masks bundle text with the redact package's engine, the one redaction configuration baum uses for input, output and logs. It is safe for concurrent use.

func NewRedactor

func NewRedactor() (*Redactor, error)

NewRedactor returns a redactor with the process-wide engine (redact.Shared), compiling the redaction rules on first use.

func (*Redactor) Find

func (r *Redactor) Find(ctx context.Context, s string) ([]redact.Span, error)

Find returns the spans RedactString masks in s, one per finding, so two secrets written side by side are told apart.

func (*Redactor) RedactLines

func (r *Redactor) RedactLines(ctx context.Context, lines []string) ([]string, int, error)

RedactLines redacts lines that read as one text, such as a code excerpt's lines, as their newline-joined text, so a secret written across several of them is found as a whole. It returns as many lines as it was given, each masked in place, and the spans masked in the joined text. A line may hold a newline itself: each is cut back out at its own offsets. Should the mask ever change the text's length, every line is masked whole instead.

func (*Redactor) RedactString

func (r *Redactor) RedactString(ctx context.Context, s string) (string, int, error)

RedactString masks every secret and e-mail address in s and returns the result with the number of spans masked, which the bundle reports as its masked-span count. Secrets are found over the whole text, so a key that spans lines is caught, and the result keeps the length and the lines of s: a patch keeps its line numbers. Mentions are left as written; a code host is protected from them where text is published, not here.

type Reference

type Reference struct {
	// Kind is one of: issue_key, spec, spec_assertion, cherry_pick,
	// stacked_on, supersedes, includes, follow_up, image, video,
	// authorship_disclosure.
	Kind  string `json:"kind"`
	Value string `json:"value"`
	// Source names where the reference was found: "body", "commit_subject",
	// "branch", or "comment:<id>".
	Source string `json:"source"`
}

Reference is one extracted reference, extracted before redaction and trimming so a reference inside cut text still survives.

func CollectReferences

func CollectReferences(b Bundle) []Reference

CollectReferences extracts the references of a bundle's pull request description, head branch, commit subjects and conversation, de-duplicated and ordered. It reads untrimmed text, so call it before caps and trimming.

func ExtractReferences

func ExtractReferences(text, source string) []Reference

ExtractReferences finds every recognised reference in text, tagging each with source.

type RenderedImage

type RenderedImage struct {
	ID, SourceURL, Alt string
	// FetchURL is the signed rendered source; it is never stored or logged.
	FetchURL string
	// State is preset for an image that is not downloaded.
	State string
}

RenderedImage is one image found in a rendered description.

func RenderedImages

func RenderedImages(bodyHTML string, uploads map[string]string) []RenderedImage

RenderedImages walks the img elements of body_html. GitHub renders none from HTML comments or code fences, so those are left out. A repeated image is listed once.

type ReviewConfig

type ReviewConfig struct {
	Present bool   `json:"present"`
	Digest  string `json:"digest,omitempty"`
	Content string `json:"content,omitempty"`
	// ChangedInPullRequest is true when the diff index touches REVIEW.md.
	// The head version in the checkout is then a proposal, not the policy
	// this review applies.
	ChangedInPullRequest bool `json:"changed_in_pull_request,omitempty"`
}

ReviewConfig is REVIEW.md at the pull request's base commit, the target branch's policy. Present is false when the file is absent there, in which case defaults apply and only ChangedInPullRequest can be set. Content is REVIEW.md's own text, verbatim and unredacted (it has no audience but the review agent, which can read the same file unredacted off the checkout anyway), given to generation up front rather than requiring it to browse for the file itself; it is empty when the file is absent, not valid UTF-8, or was capped by the host's size limit. Location, syntax and override acceptance are still shaping: the text is visible as context but is not parsed, no roles or markers are extracted, and overrides are not accepted.

func LoadReviewConfig

func LoadReviewConfig(ctx context.Context, fetcher BlobFetcher, commitSHA string) (*ReviewConfig, error)

LoadReviewConfig loads REVIEW.md at commitSHA, which the builder passes as the pull request's base commit, or reports it absent. Content carries the file's own committed text, verbatim and unredacted (see Redact), so generation sees it up front instead of needing to browse for it. Binary or non-UTF-8 content is reported present, with a digest, but no content — the same "cannot fabricate text" rule an unreadable diff hunk follows.

type ReviewThreadComment

type ReviewThreadComment struct {
	ID  string
	URL string
}

ReviewThreadComment is a review comment's conversation ID (its GitHub database ID) and URL.

type ReviewThreadInput

type ReviewThreadInput struct {
	ID       string
	Path     string
	Side     string
	Line     *int
	Resolved bool
	Outdated bool
	Comments []ReviewThreadComment
}

ReviewThreadInput is one review thread as GitHub reports it. Side is the diff side of Line ("LEFT" or "RIGHT"); Comments are the thread's comments in thread order.

type Session

type Session struct {
	ValidationEvents []SessionEvent `json:"validation_events,omitempty"`
	RootSessionID    string         `json:"id"`
	Vendor           string         `json:"vendor"`
	Restricted       bool           `json:"restricted"`
	Models           []string       `json:"models,omitempty"`
	Title            string         `json:"title,omitempty"`
	Branch           string         `json:"branch,omitempty"`
	StartedAt        *time.Time     `json:"started_at,omitempty"`
	EndedAt          *time.Time     `json:"ended_at,omitempty"`
	Outcome          string         `json:"outcome,omitempty"`

	Prompts       []Prompt       `json:"prompts,omitempty"`
	CommandEvents []CommandEvent `json:"command_events,omitempty"`
	// Decisions are the decisions a host extracted from the session's
	// transcript, in the host's order. Nil means none were extracted (off,
	// failed or skipped); a non-nil empty list means the session was
	// extracted and made none. A restricted session never carries them.
	Decisions *[]SessionDecision `json:"decisions,omitempty"`
	// Nil means extraction did not run; an empty list means it found no checks.
	Validations           *[]SessionValidation `json:"validations,omitempty"`
	NotVerified           []ValidationGap      `json:"not_verified,omitempty"`
	SetAside              []ValidationSetAside `json:"set_aside,omitempty"`
	ValidationUnavailable string               `json:"validation_unavailable,omitempty"`

	// Confidence, HasStartedAt and StartedAtValue are the sort keys used when
	// capping and ordering sessions; not part of the encoded bundle.
	Confidence     float64   `json:"-"`
	HasStartedAt   bool      `json:"-"`
	StartedAtValue time.Time `json:"-"`
	// AuthoritativeLink is the host's: whether the session is linked to the
	// pull request by more than a heuristic. Not part of the encoded bundle.
	AuthoritativeLink bool `json:"-"`
}

Session is one linked session. Restricted is true for a session of which the pull request's repository is not a connected member: only RootSessionID and Vendor are populated, everywhere in the bundle.

type SessionDecision

type SessionDecision struct {
	Title               string   `json:"title,omitempty"`
	Summary             string   `json:"summary"`
	Who                 string   `json:"who"`
	Category            string   `json:"category"`
	Trigger             string   `json:"trigger,omitempty"`
	Rationale           string   `json:"rationale,omitempty"`
	RejectedAlternative string   `json:"rejected_alternative,omitempty"`
	Superseded          bool     `json:"superseded,omitempty"`
	Turns               []int    `json:"turns"`
	DecidedTurn         int      `json:"decided_turn,omitempty"`
	Evidence            string   `json:"evidence,omitempty"`
	EvidenceTurn        int      `json:"evidence_turn,omitempty"`
	Files               []string `json:"files,omitempty"`
	DecisionID          string   `json:"-"`
}

SessionDecision is one decision extracted from a session: a choice between plausible alternatives that shaped the repository. Who is "human", "agent" or "agent_proposed_human_approved"; Superseded marks a choice a later decision of the session reversed or replaced. Turns are prompt indexes of the session, the turns where it was proposed, made or implemented; Files are repository-relative paths edited in those turns. Trigger is what prompted it (request, review, failure, finding or initiative), Rationale why as the session states it, DecidedTurn the turn the choice was made, and Evidence a verbatim quote from EvidenceTurn showing it; each is empty when not extracted. DecisionID is the host's stable ID of the decision, empty when it has none; it is not part of the encoded bundle, so the model never reads it, and a host that needs it after decoding a bundle sets it again (SetDecisionIDs).

type SessionEvent

type SessionEvent struct {
	ID      string     `json:"id"`
	Time    *time.Time `json:"time,omitempty"`
	Verb    string     `json:"verb"`
	Summary string     `json:"summary"`
}

SessionEvent is a cited non-command tool event retained for anchor resolution.

type SessionValidation

type SessionValidation struct {
	ID            string                `json:"id"`
	Method        string                `json:"method"`
	Checked       string                `json:"checked"`
	Outcome       string                `json:"outcome"`
	EvidenceClass string                `json:"evidence_class"`
	Caveats       string                `json:"caveats,omitempty"`
	CommitLabel   ValidationCommitLabel `json:"commit_label"`
	EventIDs      []string              `json:"event_ids"`
}

SessionValidation is a cited check, with deterministic coverage of the reviewed head.

type Sources

type Sources map[string]bool

Sources records which bundle parts had data available.

type Thread

type Thread struct {
	ID       string `json:"id"`
	Path     string `json:"path"`
	Line     *int   `json:"line"`
	Resolved bool   `json:"resolved"`
	Outdated bool   `json:"outdated"`
	URL      string `json:"url,omitempty"`
}

Thread is one review thread. Line is the current new-side line, null once outdated.

type ValidationCommitLabel

type ValidationCommitLabel struct {
	State  string `json:"state"`
	SHA    string `json:"sha,omitempty"`
	Reason string `json:"reason"`
}

type ValidationGap

type ValidationGap struct {
	What     string   `json:"what"`
	EventIDs []string `json:"event_ids,omitempty"`
	Turns    []int    `json:"turns,omitempty"`
}

type ValidationSetAside

type ValidationSetAside struct {
	What         string   `json:"what"`
	StatedReason string   `json:"stated_reason"`
	EventIDs     []string `json:"event_ids,omitempty"`
	Turns        []int    `json:"turns,omitempty"`
}

Jump to

Keyboard shortcuts

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