bugreport

package
v1.0.7 Latest Latest
Warning

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

Go to latest
Published: Oct 30, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package bugreport files a defect in forge itself with the Reliant engineering team: `forge report-bug`.

Inside Reliant an agent files with reliant's own report_bug tool, whose record the worker's log pipeline ships to our telemetry. A forge running in Claude Code, Codex or Cursor, or at a person's terminal, has no such pipeline, so it posts the report to the control plane's public ingest, controlplane.v1.ForgeReportService/FileBugReport, which writes the same kind of issue record (control-plane docs/design/forge-cli-reports.md).

forge sends NOTHING unless someone files a report. There is no automatic crash or error reporting and no telemetry. What a report carries is listed in docs/report-bug.md; Payload is all of it.

The report id is minted here, so it can be printed whatever the ingest answers, and a repeat of a report filed in the last 30 minutes returns the first report's id without sending anything (State).

Index

Constants

View Source
const (
	// Procedure is the ingest rpc.
	Procedure = "controlplane.v1.ForgeReportService/FileBugReport"

	// EndpointEnv overrides the control plane reports go to (a dev or
	// staging control plane). Unset, reports go to cloud.DefaultEndpoint.
	EndpointEnv = "FORGE_REPORT_ENDPOINT"

	// DedupeWindow is how long a filed report answers a repeat of itself.
	DedupeWindow = 30 * time.Minute

	// MaxTitleBytes bounds redacted UTF-8 title bytes including the marker.
	MaxTitleBytes = 200
	// MaxTextBytes bounds redacted UTF-8 text bytes including the marker.
	MaxTextBytes = 4000
)
View Source
const StateFile = "report-bug.json"

StateFile is the file, in forge's config directory, that holds this machine's install id and the reports filed in the last DedupeWindow.

Variables

This section is empty.

Functions

func CommandLine

func CommandLine(args []string) string

CommandLine is args joined into one line with every value that could hold a secret removed: the value of a secret-named flag becomes redact.Marker, the value of a report text flag becomes "…", and every remaining argument is redact.Text'd (credential shapes, home directories). The program path is reduced to its base name.

func DefaultEndpoint

func DefaultEndpoint() string

DefaultEndpoint is EndpointEnv when set, cloud.DefaultEndpoint otherwise.

func Fingerprint

func Fingerprint(title string) string

Fingerprint names the defect a title describes, for local deduplication: the title redacted, lowercased, its words kept and every word holding a digit dropped (ids, counts and ports vary between two sightings of one defect). reliant's report_bug deduplicates by the same rule.

func Severities

func Severities() []string

Severities are the accepted severities, most severe first.

Types

type ClientContext

type ClientContext struct {
	ForgeVersion        string `json:"forgeVersion,omitempty"`
	OS                  string `json:"os,omitempty"`
	Arch                string `json:"arch,omitempty"`
	CommandLine         string `json:"commandLine,omitempty"`
	ProjectForgeVersion string `json:"projectForgeVersion,omitempty"`
	Harness             string `json:"harness,omitempty"`
	InstallID           string `json:"installId,omitempty"`
	GoVersion           string `json:"goVersion,omitempty"`
}

ClientContext is the wire form of Context.

type Context

type Context struct {
	// ForgeVersion is this binary's version (buildinfo.Version()).
	ForgeVersion string
	// ProjectForgeVersion is forge.yaml's forge_version of the project forge
	// ran in, "" outside one.
	ProjectForgeVersion string
	// Harness is the agent harness forge detected, "" for a person.
	Harness string
	// Args is the command line (os.Args). It is redacted by CommandLine.
	Args []string
}

Context is what forge knows about where it ran. The caller supplies it; nothing here reads the environment beyond the OS and architecture.

type Filed

type Filed struct {
	ID      string    `json:"id"`
	FiledAt time.Time `json:"filed_at"`
}

Filed is one recorded report.

type Filer

type Filer struct {
	// Endpoint is the control plane's base URL.
	Endpoint string
	// Token is a forge login to present, "" for none. It only adds the
	// caller's ids to the record; the ingest ignores one it cannot validate.
	Token string
	// State is where the install id and recent reports are kept.
	State *State
	// Now is the clock; tests pin it.
	Now func() time.Time
	// contains filtered or unexported fields
}

Filer files reports.

func (*Filer) File

func (f *Filer) File(ctx context.Context, r Report, c Context) (Result, error)

File validates r, answers a repeat with the first report's id, and otherwise sends it and records it. A report the ingest refused is not recorded, so filing it again retries.

func (*Filer) Preview

func (f *Filer) Preview(r Report, c Context) (Payload, error)

Preview is the payload File would send for r, under a placeholder id. Nothing is sent or recorded.

type Payload

type Payload struct {
	ReportID string        `json:"reportId"`
	Severity string        `json:"severity"`
	Title    string        `json:"title"`
	Summary  string        `json:"summary,omitempty"`
	Expected string        `json:"expected,omitempty"`
	Actual   string        `json:"actual,omitempty"`
	Evidence string        `json:"evidence,omitempty"`
	Client   ClientContext `json:"client"`
}

Payload is exactly what is sent: FileBugReportRequest in protojson.

func BuildPayload

func BuildPayload(reportID, installID string, r Report, c Context) Payload

BuildPayload redacts and bounds r and c into the payload a report sends, under reportID and installID.

type Report

type Report struct {
	// Severity is critical (data loss, or nothing can proceed), high (it
	// blocks the task), medium (there is a workaround) or low (cosmetic).
	Severity string `json:"severity"`
	// Title is one line naming the defect; ids and numbers go in Evidence.
	Title    string `json:"title"`
	Summary  string `json:"summary,omitempty"`
	Expected string `json:"expected,omitempty"`
	Actual   string `json:"actual,omitempty"`
	// Evidence is how to reproduce it: commands, output, file paths.
	Evidence string `json:"evidence,omitempty"`
}

Report is what the reporter writes. Its JSON form is what `forge report-bug --json` reads.

func (Report) Validate

func (r Report) Validate() error

Validate reports what is wrong with r, or nil.

type Result

type Result struct {
	// ReportID is the report's id: this report's, or the earlier one a
	// duplicate was answered with.
	ReportID string `json:"report_id"`
	// Duplicate: the same report was filed within DedupeWindow, and nothing
	// was sent.
	Duplicate bool `json:"duplicate,omitempty"`
	// FiledAt is when ReportID was filed.
	FiledAt time.Time `json:"filed_at"`
}

Result is a filed report.

type State

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

State is this machine's report state: a random install id, minted on first use, which is the ingest's per-install rate-limit key, and the reports filed recently, which answer a repeat with the first report's id.

A state file that cannot be read or written never stops a report: the report is sent with a fresh install id and is simply not deduplicated.

func NewState

func NewState(dir string) *State

NewState is the state kept in dir.

func (*State) Lookup

func (s *State) Lookup(key string, now time.Time) (installID string, prior Filed, ok bool)

Lookup returns the install id (minting and storing one on first use) and the report filed under key within DedupeWindow of now, if any.

func (*State) Record

func (s *State) Record(key, id string, now time.Time)

Record stores that the report under key was filed as id at now, and drops every report older than DedupeWindow.

Jump to

Keyboard shortcuts

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