compare

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Aug 14, 2026 License: Apache-2.0 Imports: 3 Imported by: 0

Documentation

Overview

Package compare diffs a candidate eval report against a baseline. It operates only over the safe report fields (identities, statuses, finite measurements) and never touches raw conversation content, finding messages, or target-error causes, so its output carries no untrusted content.

A case is one (scenario, evaluator-name) identity. Because a report retains every per-(scenario, trial) sample, a case gathers all of an evaluator's assessments across trials on both sides, so repeated-trial variance stays visible: the individual trial results are retained, not just an aggregate mean.

Two matched cases are COMPATIBLE only when their evaluator revisions agree. Score distributions are compared only for compatible cases; an incompatible case (the evaluator changed revision between runs) is surfaced as such and never silently averaged across the revision boundary. Comparison classifies each case as added, removed, incompatible, errored, unverified, failed, changed, or unchanged — it does not reduce a run to a single mean.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CaseClass

type CaseClass string

CaseClass is the classification of one compared case. It is a closed set.

const (
	// CaseAdded: the case exists in the candidate but not the baseline.
	CaseAdded CaseClass = "added"
	// CaseRemoved: the case exists in the baseline but not the candidate.
	CaseRemoved CaseClass = "removed"
	// CaseIncompatible: the case exists in both but the evaluator revision
	// changed, so the two are not comparable and distributions are not compared.
	CaseIncompatible CaseClass = "incompatible"
	// CaseErrored: the candidate case has an error-status assessment — the
	// evaluator failed to reach a verdict. Surfaced distinctly from a regression.
	CaseErrored CaseClass = "errored"
	// CaseUnverified: the candidate case has an unverified assessment (and no
	// error). Unknown is never a pass.
	CaseUnverified CaseClass = "unverified"
	// CaseFailed: the candidate case has a failing verdict (and no error or
	// unverified). A standing quality failure.
	CaseFailed CaseClass = "failed"
	// CaseChanged: the case passes in the candidate but its outcome or score
	// distribution differs from the baseline.
	CaseChanged CaseClass = "changed"
	// CaseUnchanged: the case passes in both with an equivalent distribution.
	CaseUnchanged CaseClass = "unchanged"
)

type CaseComparison

type CaseComparison struct {
	Key               CaseKey
	Class             CaseClass
	Compatible        bool
	BaselineRevision  eval.Revision
	CandidateRevision eval.Revision
	Baseline          []TrialResult
	Candidate         []TrialResult
	Distributions     []MeasurementDelta
}

CaseComparison is the diff of one case. Baseline and Candidate hold the retained per-trial results; Distributions is non-empty only for a compatible case that carries measurements.

type CaseKey

type CaseKey struct {
	ScenarioID string
	Evaluator  eval.Name
}

CaseKey identifies a compared case: a scenario and an evaluator name. The evaluator revision is a compatibility attribute, not part of the key, so a revision bump is reported as an incompatible case rather than as an unrelated add/remove pair.

type Comparison

type Comparison struct {
	Cases []CaseComparison
}

Comparison is the full baseline-vs-candidate diff: one entry per case, in a canonical order.

func Compare

func Compare(baseline, candidate eval.Report) (Comparison, error)

Compare diffs candidate against baseline. It first validates both inputs at the report boundary (Report.Validate), returning an *InvalidReportError that names the offending side, so an input bypassing reportjson.Decode cannot merge distinct assessments into one case. It then fails closed on a non-finite measurement value (a report should never contain one; comparison rejects it rather than propagate a poisoned aggregate) and otherwise returns a per-case diff that retains individual trial results and compares distributions only for compatible cases.

type ComparisonSide

type ComparisonSide string

ComparisonSide names which of Compare's two input reports a failure concerns. It is a closed set of package constants, always safe to render — it carries no report content.

const (
	// SideBaseline is the baseline report passed to Compare.
	SideBaseline ComparisonSide = "baseline"
	// SideCandidate is the candidate report passed to Compare.
	SideCandidate ComparisonSide = "candidate"
)

type Distribution

type Distribution struct {
	Count int
	Mean  float64
	Min   float64
	Max   float64
}

Distribution summarises a measurement across a case's trials.

type EvaluatorRevisionDriftError

type EvaluatorRevisionDriftError struct{}

EvaluatorRevisionDriftError reports that a SINGLE report carried the same evaluator name under two different revisions across its samples. Within one report a name must identify exactly one revision; comparison keys a case by evaluator name, so a name mapped to two revisions cannot be gathered into one case without silently absorbing one revision as a trial of the other. Comparison rejects it fail-closed rather than corrupt the case. This is distinct from a legitimate cross-report revision change (baseline E@v1 vs candidate E@v2, each internally consistent), which surfaces as an incompatible case, not this error. No name or revision is embedded — both are report-supplied.

func (*EvaluatorRevisionDriftError) Error

type InvalidReportError

type InvalidReportError struct {
	// Side is the input report that failed validation.
	Side ComparisonSide
	// Cause is the report's own typed validation error.
	Cause error
}

InvalidReportError reports that one of Compare's input reports failed its own Report.Validate boundary check. Compare validates BOTH inputs before indexing so a hand-built or non-decoded report cannot bypass the report-level invariants (unique sample identities, unique evaluator names, consistent revisions) and silently merge distinct assessments into one case. Side names which input failed (baseline or candidate); the wrapped Cause is the report's own typed validation error, available via Unwrap so a caller can classify the underlying reason with errors.As. No report content is embedded: Side is a closed constant and the cause is itself content-free.

func (*InvalidReportError) Error

func (e *InvalidReportError) Error() string

func (*InvalidReportError) Unwrap

func (e *InvalidReportError) Unwrap() error

type MeasurementDelta

type MeasurementDelta struct {
	Name          eval.Name
	Unit          eval.Unit
	BaselineUnit  eval.Unit
	CandidateUnit eval.Unit
	UnitMismatch  bool
	Baseline      Distribution
	Candidate     Distribution
}

MeasurementDelta pairs a measurement's baseline and candidate distributions. It is populated only for compatible cases.

A measurement name may appear on both sides carrying DIFFERENT units (for example latency in seconds on the baseline and a bare count on the candidate). Numbers measured in different units are not comparable, so the two units are tracked separately and never collapsed: BaselineUnit and CandidateUnit expose each side's unit, and UnitMismatch flags the incompatibility. Unit is the agreed unit when both sides match (and the baseline's when they do not), retained for the common compatible case.

type NonFiniteMeasurementError

type NonFiniteMeasurementError struct{}

NonFiniteMeasurementError reports that a report carried a measurement whose value was NaN or ±Inf. A well-formed report never contains one (the runner validates measurements at its boundary); comparison rejects it fail-closed rather than propagate a poisoned mean or min/max. No value is embedded — it is not finite and not safe to render as a number.

func (*NonFiniteMeasurementError) Error

func (e *NonFiniteMeasurementError) Error() string

type TrialResult

type TrialResult struct {
	TrialIndex   int
	Status       eval.AssessmentStatus
	Measurements []eval.Measurement
}

TrialResult is one evaluator assessment on one trial, retained so per-trial variance is visible. Measurements are the safe (name/value/unit) triples.

Jump to

Keyboard shortcuts

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