evaluate

package
v0.3.0 Latest Latest
Warning

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

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

README

Evaluate

Score every csf build on held-out, rotated past tickets before it goes live.

The loop's struggle rate is observational: harder work in a week hides an improvement, and a gate accepted on its backtest says nothing about outcome. This package fixes the tasks instead. A suite of past tickets, each with the commit its pull request started from and the merged change as its reference, is replayed on a build, and the build's score is the struggle rate of those replays at a fixed budget, with its interval. The suite is hidden from the miners and the loop's corpus readers, it rotates weekly, and the tickets that evolve the harness are never in it.

Citing a result

A pull request that claims an improvement cites a recorded score with one line, exactly as csf eval show prints it:

eval-suite: build=<sha12> suite=v<N> score=<per 1k> [<low>, <high>] delta=<signed per 1k> vs=<sha12>
  • build is the 12-character commit the scored binary was built from (csf.BinaryVersion).
  • suite is the suite version; scores compare only within one version.
  • score is struggle episodes per 1,000 tool calls over the suite's replays, each cut at the suite's budget, with the 95% Garwood interval. Lower is better.
  • delta is score minus the score of build vs on the same suite version; negative is an improvement.

The session gate refuses gh pr ready when the pull request's verdict, before or now line claims an improvement and the body carries no citation that matches a recorded score. csf eval cite -body FILE runs the same check by hand.

Verbs

Verb Does
csf eval suite Select or rotate the suite and record it
csf eval score Replay the suite on the host's build, sharded, and record the score
csf eval show Print a build's score and its citation line
csf eval cite Check a pull request body's improvement claims
csf eval record Record replays a burst shard wrote

csf upgrade refuses a build with no score on the current suite, or one that regressed beyond the bound.

Documentation

Overview

Package evaluate scores csf builds on a held-out, rotated suite of past tickets before they go live (EVAL-SUITE, #416). A suite ticket is replayed from the commit its pull request started from, on the build being scored, and read at a fixed budget of tool calls by the loop's own struggle definition (ouroboros.StrugglesWithin); the merged change is the reference its files are compared with. The suite is hidden from the miners and the loop's corpus readers, rotates weekly, and never holds a ticket the loop evolves the harness on.

Index

Constants

View Source
const (
	NodeHost  = "host"
	NodeBurst = "burst"
)

The node kinds a replay runs on: this host, or a cloud burst job.

View Source
const (
	MetricScore       = "csf_eval_struggle_rate_per_1k_tool_calls"
	MetricWallSeconds = "csf_eval_score_wall_seconds"
	MetricCostUSD     = "csf_eval_score_cost_usd"
	MetricShards      = "csf_eval_shards"
)

The suite's series, read from the records at each scrape; the CSF dashboard's Evaluation suite row draws them.

View Source
const (
	// RotationPeriod is how long one suite version stands: the struggle
	// rate's own reporting period, a week, so every weekly reading of the
	// headline is on one fixed suite.
	RotationPeriod = 7 * 24 * time.Hour
)

Variables

View Source
var (
	// ErrUncited reports a pull request body that claims an improvement and
	// carries no citation matching a recorded score.
	ErrUncited = errors.New("evaluate: an improvement is claimed without a suite citation that matches a recorded score")
	// ErrNoRate reports a score with no tool call, which has nothing to cite.
	ErrNoRate = errors.New("evaluate: the score has no tool call to rate")
)
View Source
var (
	// ErrInvalidOption reports a nil option or one the replayer cannot use.
	ErrInvalidOption = errors.New("evaluate: invalid option")
	// ErrNoOriginal reports a suite ticket whose original run left no recipe.
	ErrNoOriginal = errors.New("evaluate: the ticket's original run has no recipe to replay")
)
View Source
var (
	// ErrUnscored reports a build with no complete score on the suite.
	ErrUnscored = errors.New("evaluate: the build has no complete score on the current suite")
	// ErrRegressed reports a build whose score is worse than the live
	// build's beyond the bound.
	ErrRegressed = errors.New("evaluate: the build regressed beyond the bound")
)
View Source
var (
	// ErrDatabaseRequired reports a store built without the database.
	ErrDatabaseRequired = errors.New("evaluate: the csfpg database is required")
	// ErrNoSuite reports a read of the suite before any was selected.
	ErrNoSuite = errors.New("evaluate: no suite has been selected; run csf eval suite")
)
View Source
var (
	// ErrEmptyPool reports a selection with no eligible ticket.
	ErrEmptyPool = errors.New("evaluate: no eligible ticket for the suite")
	// ErrNotDisjoint reports a suite holding a ticket the loop evolves the
	// harness on.
	ErrNotDisjoint = errors.New("evaluate: the suite and the evolution tickets overlap")
)
View Source
var ReplayTools = []string{
	"Read", "Write", "Edit", "Glob", "Grep", "TodoWrite",
	"Bash(git:*)",
	"Bash(gh issue view:*)", "Bash(gh issue list:*)", "Bash(gh pr view:*)", "Bash(gh pr list:*)", "Bash(gh pr diff:*)", "Bash(gh run list:*)", "Bash(gh run view:*)",

	"Bash(tools/bazel.sh:*)", "Bash(bash tools/check-house-lint.sh:*)", "Bash(bash tools/ontology-score.sh:*)",
	"Bash(bash tools/check-merge.sh:*)", "Bash(bash tools/check-generated.sh:*)", "Bash(python3 tools/check_operator_identifiers.py:*)",
	"Bash(docker run:*)", "Bash(docker build:*)",
	"Bash(ls:*)", "Bash(cat:*)", "Bash(head:*)", "Bash(tail:*)", "Bash(wc:*)", "Bash(grep:*)", "Bash(rg:*)", "Bash(find:*)",
	"Bash(sed:*)", "Bash(awk:*)", "Bash(sort:*)", "Bash(uniq:*)", "Bash(diff:*)", "Bash(jq:*)", "Bash(stat:*)", "Bash(tree:*)",
	"Bash(echo:*)", "Bash(printf:*)", "Bash(pwd)", "Bash(mkdir:*)", "Bash(cp:*)", "Bash(mv:*)", "Bash(touch:*)", "Bash(gofmt:*)",
}

ReplayTools are the tool rules a replay may use: the files, all of git (the replay repository's origin is its own local copy, so even a push stays there), read-only gh, the pinned build, the repository's own scripts and the read-only shell tools. Nothing that reaches past the replay is allowed (gh writes, csf send, merge or submit, the csf MCP tools, an arbitrary bash -c), because a replay re-runs a real brief that may say to do exactly that. A refused call is a struggle signal on every build alike, so scores stay comparable.

Functions

func CheckClaims

func CheckClaims(ctx context.Context, body string, recompute Recompute) error

CheckClaims is the proof check (#416 Build 5): a body that claims an improvement must carry at least one citation whose line equals the one the records give. A body that claims nothing passes.

func Citation

func Citation(score Score, versus Score) (string, error)

Citation is the line a pull request cites score with, measured against the score of build vs on the same suite version.

func Claims

func Claims(body string) []string

Claims lists the summary lines of body that claim an improvement.

func Disjoint

func Disjoint(suite Suite, evolution []int64) error

Disjoint checks that no suite ticket is one the loop evolves the harness on (#416 Build 7).

func HiddenAssignments

func HiddenAssignments(corpus iofs.IFiles, hidden map[int64]bool) (map[string]bool, error)

HiddenAssignments lists the run directories under corpus that worked a hidden ticket: the original runs of suite tickets and every replay of them. The corpus readers skip these, so a miner run never receives a suite ticket's event log.

func Read

func Read(events []byte, budget int) (toolCalls int64, episodes int64)

Read is what one replay's event log contributes at budget: its tool calls and struggle episodes by the loop's definition.

func Recall

func Recall(reference []string, touched []string) float64

Recall is the share of the reference's files the replay's change touched; a reference with no files is fully recalled by nothing, so 0.

func TicketOf

func TicketOf(corpus iofs.IFiles, assignment string) (int64, error)

TicketOf reads the ticket a run worked from its recipe, 0 when the run names none.

func TicketOfTitle

func TicketOfTitle(title string) int64

TicketOfTitle reads the ticket a pull request title names, 0 for none.

Types

type Cited

type Cited struct {
	Build   string
	Version int
	Versus  string
	Line    string
}

Cited is one citation found in a body: what it names, and the line.

func Citations

func Citations(body string) []Cited

Citations reads every citation line in body.

type Collector

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

Collector measures every recorded score at each scrape.

func NewSuiteCollector

func NewSuiteCollector(scores func(ctx context.Context) ([]Score, error)) *Collector

NewSuiteCollector measures the scores scores returns.

func (*Collector) Collect

func (collector *Collector) Collect(metrics chan<- prometheus.Metric)

Collect reads the scores and sends every series; a record that cannot be read sends none.

func (*Collector) Describe

func (collector *Collector) Describe(descriptions chan<- *prometheus.Desc)

Describe sends every series' description.

type Comparison

type Comparison struct {
	Delta  float64 `json:"delta_per_1k"`
	Bound  float64 `json:"bound_per_1k"`
	Paired int     `json:"paired_tickets"`
}

Comparison is a candidate build against the live one on the same suite version: the difference of the pooled scores and the bound it is judged by, from the suite's own run-to-run variance (the spread of the per-ticket differences of the two builds' replays).

func Admit

func Admit(suite Suite, candidate []Replay, live []Replay, candidateBuild string, liveBuild string) (*Comparison, error)

Admit is the score-before-live check: the candidate must have a complete score on the suite, and when the live build has one too, the candidate must not be worse beyond the bound. It returns the comparison it judged by, nil when the live build had no complete score to compare with.

func Compare

func Compare(candidate []Replay, live []Replay) Comparison

Compare judges candidate against live: delta is candidate minus live (negative is better) and bound is z95 times the standard error of the mean per-ticket difference. With fewer than two paired tickets there is no variance to bound by, and the bound is infinite.

type Derivation

type Derivation struct {
	Pool       int     `json:"pool"`
	Evolution  int     `json:"evolution_excluded"`
	Budget     int     `json:"budget_tool_calls"`
	BudgetFrom string  `json:"budget_from"`
	Rate       float64 `json:"pool_rate_per_1k"`
	Dispersion float64 `json:"dispersion"`
	Effect     float64 `json:"effect_log"`
	Needed     int     `json:"replays_needed"`
	Size       int     `json:"size"`
	SizeFrom   string  `json:"size_from"`
	Resolves   float64 `json:"resolves_factor"`
}

Derivation records how a suite's size and budget follow from the pool: every number a reader needs to redo the arithmetic.

type Host

Host is the harness host a replay runs on, as the four operations the replayer calls: the generated client's methods, or the in-process service's.

type Job

type Job struct {
	Ticket Ticket          `json:"ticket"`
	Recipe json.RawMessage `json:"recipe"`
}

Job is one suite ticket ready to replay: the ticket and the replay recipe, encoded as protojson so a job crosses to a burst node as data.

func Jobs

func Jobs(suite Suite, corpus iofs.IFiles, build string, repository string) ([]Job, error)

Jobs builds the replay of every suite ticket from its original run's recipe: the same agent and task, on the suite's model, from the commit its pull request started from, in repository (a clone whose pushes never reach the real one), on a branch named for the build.

func Relocate

func Relocate(jobs []Job, repository string) ([]Job, error)

Relocate points every job's replay at repository: the clone a node other than the one that built the jobs replays from.

type MergedPull

type MergedPull struct {
	Number      int64
	Title       string
	MergeCommit string
	BaseCommit  string
	Files       []string
}

MergedPull is one merged pull request as the pool reads it: its title, merge commit, the commit it started from (the merge commit's first parent) and the files it changed.

type Recompute

type Recompute func(ctx context.Context, build string, version int, versus string) (string, error)

Recompute is the citation line the records give for a build on a suite version measured against build vs, as Citation writes it.

type Replay

type Replay struct {
	Build         string    `json:"build"`
	SuiteVersion  int       `json:"suite_version"`
	Ticket        int64     `json:"ticket"`
	Node          string    `json:"node"`
	Assignment    string    `json:"assignment"`
	ToolCalls     int64     `json:"tool_calls"`
	Episodes      int64     `json:"episodes"`
	Recall        float64   `json:"recall"`
	CostUSDMicros int64     `json:"cost_usd_micros"`
	Seconds       int64     `json:"seconds"`
	RecordedAt    time.Time `json:"recorded_at"`
}

Replay is one suite ticket replayed on one build, read at the suite's budget: its tool calls and struggle episodes, the share of the reference's files it touched, what it cost and how long it ran.

type Replayer

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

Replayer runs replays on one harness host: it submits each job, reads the replay's event log as it grows, cancels the session once the suite's budget of tool calls is spent, and records what the replay read.

func NewReplayer

func NewReplayer(options ...ReplayerOption) (*Replayer, error)

NewReplayer validates the whole option set before building the replayer.

func (*Replayer) Run

func (replayer *Replayer) Run(ctx context.Context, build string, suite Suite, node string, jobs []Job, record func(ctx context.Context, replay Replay) error) error

Run replays jobs on the host for build and suite at the suite's budget and hands each finished replay to record, tagged with node.

type ReplayerOption

type ReplayerOption func(replayer *Replayer) error

ReplayerOption configures a Replayer.

func WithClock

func WithClock(source clock.IClock, poll time.Duration) ReplayerOption

WithClock grants the clock the replayer paces its reads by. Required.

func WithHost

func WithHost(host Host) ReplayerOption

WithHost grants the harness host the replays run on. Required.

func WithLauncher

func WithLauncher(launcher proc.ILauncher) ReplayerOption

WithLauncher grants the process capability git reads a replay's change through. Required.

func WithLogger

func WithLogger(logger *slog.Logger) ReplayerOption

WithLogger grants the logger progress goes to.

func WithParallel

func WithParallel(parallel int) ReplayerOption

WithParallel bounds the replays running at once on the host; the host's own admission bounds them further.

func WithState

func WithState(directory string, files iofs.IFiles) ReplayerOption

WithState grants the host's state directory, where each replay's run directory and event log appear. Required.

type Run

type Run struct {
	Build        string
	SuiteVersion int
	StartedAt    time.Time
	FinishedAt   time.Time
}

Run is one scoring run of a build on a suite version: its wall clock.

type Score

type Score struct {
	Build        string         `json:"build"`
	SuiteVersion int            `json:"suite_version"`
	Replays      int            `json:"replays"`
	Expected     int            `json:"expected"`
	Complete     bool           `json:"complete"`
	ToolCalls    int64          `json:"tool_calls"`
	Episodes     int64          `json:"episodes"`
	PerK         *float64       `json:"per_1k"`
	Low          *float64       `json:"low"`
	High         *float64       `json:"high"`
	Recall       float64        `json:"recall"`
	CostUSD      float64        `json:"cost_usd"`
	WallSeconds  float64        `json:"wall_seconds"`
	Nodes        map[string]int `json:"nodes"`
}

Score is a build's result on one suite version: struggle episodes per 1,000 tool calls over its replays with the 95% Garwood interval (the headline), the mean recall of the reference, what scoring cost and how long it took, and the replays per node kind.

func ScoreOf

func ScoreOf(build string, suite Suite, replays []Replay, wall time.Duration) Score

ScoreOf folds a build's replays on suite into its score; wall is the scoring run's wall clock, zero when none was recorded.

type Suite

type Suite struct {
	Version    int       `json:"version"`
	SelectedAt time.Time `json:"selected_at"`
	// Model is the model every replay of this version runs on, so two
	// builds' scores differ by the build alone.
	Model string `json:"model"`
	// Tools are the tool rules every replay of this version may use; empty
	// in a record made before they were recorded, which means ReplayTools.
	Tools        []string   `json:"tools,omitempty"`
	RotatesAt    time.Time  `json:"rotates_at"`
	Tickets      []Ticket   `json:"tickets"`
	EvolutionSet []int64    `json:"evolution_tickets"`
	Derivation   Derivation `json:"derivation"`
}

Suite is one version of the held-out suite.

func Select

func Select(pool []Ticket, evolution []int64, version int, model string, now time.Time) (Suite, error)

Select draws suite version from the pool: the tickets the loop evolves the harness on are removed, the budget and size are derived from the rest, and the held-out tickets are the size first by a hash of the version and the ticket, so a version always draws the same tickets and the next draws afresh.

func (*Suite) Due

func (suite *Suite) Due(now time.Time) bool

Due reports whether the suite's rotation time has come at now; no suite at all is due.

func (Suite) Holds

func (suite Suite) Holds(ticket int64) bool

Holds reports whether ticket is in the suite.

type SuiteStore

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

SuiteStore keeps the suites, replays and scoring runs in CSF's PostgreSQL schema (the csf_eval_* tables), the one place results from every node are aggregated. It borrows the capability and never closes it.

func NewSuiteStore

func NewSuiteStore(database csfpg.IDB) (*SuiteStore, error)

NewSuiteStore returns the store over a pool the binary opened through ipc/db/csfpg, or over pgmem's IDB in a spec.

func (*SuiteStore) HiddenTickets

func (store *SuiteStore) HiddenTickets(ctx context.Context) (map[int64]bool, error)

HiddenTickets is every ticket any suite version has held: once held out, a ticket stays hidden from the miners and the loop's corpus readers.

func (*SuiteStore) LatestSuite

func (store *SuiteStore) LatestSuite(ctx context.Context) (Suite, error)

LatestSuite reads the current suite version.

func (*SuiteStore) Recompute

func (store *SuiteStore) Recompute(ctx context.Context, build string, version int, versus string) (string, error)

Recompute gives the citation line the records hold for build on a suite version against build vs: the Recompute the proof check runs.

func (*SuiteStore) RecordReplay

func (store *SuiteStore) RecordReplay(ctx context.Context, replay Replay) error

RecordReplay records one replay, replacing an earlier reading of the same build, version and ticket.

func (*SuiteStore) RecordRun

func (store *SuiteStore) RecordRun(ctx context.Context, run Run) error

RecordRun records a scoring run's wall clock.

func (*SuiteStore) RecordSuite

func (store *SuiteStore) RecordSuite(ctx context.Context, suite Suite) error

RecordSuite records a new suite version.

func (*SuiteStore) Replays

func (store *SuiteStore) Replays(ctx context.Context, build string, version int) ([]Replay, error)

Replays reads a build's replays on a suite version, by ticket.

func (*SuiteStore) Runs

func (store *SuiteStore) Runs(ctx context.Context) ([]Run, error)

Runs reads every scoring run, oldest first.

func (*SuiteStore) ScoreOn

func (store *SuiteStore) ScoreOn(ctx context.Context, build string, suite Suite) (Score, error)

ScoreOn is a build's score on suite from the records, with its scoring run's wall clock when one was recorded.

func (*SuiteStore) Scores

func (store *SuiteStore) Scores(ctx context.Context) ([]Score, error)

Scores is every recorded scoring run's score.

func (*SuiteStore) Suites

func (store *SuiteStore) Suites(ctx context.Context) ([]Suite, error)

Suites reads every suite version, oldest first.

type Ticket

type Ticket struct {
	Number      int64    `json:"ticket"`
	PullRequest int64    `json:"pull_request"`
	BaseCommit  string   `json:"base_commit"`
	MergeCommit string   `json:"merge_commit"`
	Files       []string `json:"files"`
	Assignment  string   `json:"assignment"`
	// ToolCalls and Episodes are the original run's whole reading, used to
	// derive the budget and the size; they are not a score.
	ToolCalls int64 `json:"tool_calls"`
	Episodes  int64 `json:"episodes"`
}

Ticket is one past ticket in the pool or the suite: the pull request that closed it, the commit that pull request started from, its merge commit, the files the merged change touched (the reference) and the original run whose recipe a replay reuses, with how that run read at the suite budget.

func Pool

func Pool(corpus iofs.IFiles, pulls []MergedPull) ([]Ticket, error)

Pool is every past ticket a suite may hold: a merged pull request that names its ticket, and a run under corpus that worked the ticket and left its recipe, the one with the most tool calls being the original. A ticket closed by several pull requests is held once, by its last.

Jump to

Keyboard shortcuts

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