bench

package
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Sep 13, 2026 License: Apache-2.0 Imports: 29 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// CacheVersionInstanceID is the stable selector used by the benchmark CLI.
	CacheVersionInstanceID = "python-cache-version-v1"
	// CacheVersionRule is the treatment lesson's stable identity.
	CacheVersionRule = "bump-cached-response-version"
)
View Source
const (
	// ExportRegistryInstanceID is the stable selector used by the benchmark CLI.
	ExportRegistryInstanceID = "go-export-registry-v1"
	// ExportRegistryRule is the treatment lesson's stable identity.
	ExportRegistryRule = "register-async-export-format"
)
View Source
const (
	// OTelHistogramInstanceID selects the pinned OpenTelemetry Go task with
	// the lesson delivered at the explicit-histogram trigger.
	OTelHistogramInstanceID = "opentelemetry-go-histogram-reset-v1"
	// OTelHistogramRule is the treatment lesson's stable identity.
	OTelHistogramRule = "keep-histogram-reset-paths-in-sync"
	// OTelHistogramScopingFamily binds the trigger and repair variants into a
	// matched public-repository delivery experiment.
	OTelHistogramScopingFamily = "opentelemetry-go-histogram-reset-scoping-v1"
)
View Source
const (
	// HookDeliveryAlways repeats matching context on every edit.
	HookDeliveryAlways = reviews.HookDeliveryAlways
	// HookDeliveryOncePerContext suppresses a delivered lesson until compaction.
	HookDeliveryOncePerContext = reviews.HookDeliveryOncePerContext
)
View Source
const (
	// SchemaSyncInstanceID is the stable selector used by the benchmark CLI.
	SchemaSyncInstanceID = "python-ts-schema-sync-v1"
	// SchemaSyncRule is the treatment lesson's stable identity.
	SchemaSyncRule = "sync-generated-api-client"
	// SchemaSyncScopingFamily binds the trigger-scoped and repair-scoped
	// variants into one matched factorial experiment.
	SchemaSyncScopingFamily = "python-ts-schema-sync-scoping-v1"
)
View Source
const (
	ActivationExpectNone   = "none"
	ActivationPrepareNaive = "naive"
)

Activation prompt vocabulary. A prompt expects one shipped skill or none; a prompt may ask for the naive patch first, so a review prompt sees a real diff instead of a clean tree.

View Source
const ActivationResultSchemaVersion = 1

ActivationResultSchemaVersion is the contract of activation rows. They never share a file with workflow rows.

View Source
const CacheVersionCochangeInstanceID = "python-cache-version-cochange-v1"

CacheVersionCochangeInstanceID selects the cache-version task on a history whose commits carry the presenter and the cache namespace together.

View Source
const ExportRegistryCochangeInstanceID = "go-export-registry-cochange-v1"

ExportRegistryCochangeInstanceID selects the export-registry task on a history whose commits carry the preview API and the worker registry together.

View Source
const OTelHistogramRepairInstanceID = "opentelemetry-go-histogram-reset-repair-v1"

OTelHistogramRepairInstanceID selects the repair-scoped control for the pinned OpenTelemetry Go histogram-reset task.

View Source
const ResultSchemaVersion = 7

ResultSchemaVersion is the immutable contract emitted by the current harness and accepted by strict reporting. Version 7 adds the hook-exposure expectation and a shared protocol fingerprint for scoped factorial experiments. Strict reporting continues to accept frozen v5/v6 evidence without rewriting it.

View Source
const SchemaSyncCochangeInstanceID = "python-ts-schema-sync-cochange-v1"

SchemaSyncCochangeInstanceID selects the schema-sync task on a history whose commits carry the trigger and companion files together.

View Source
const SchemaSyncRepairInstanceID = "python-ts-schema-sync-repair-v1"

SchemaSyncRepairInstanceID selects the delivery-scoping CONTROL: the schema-sync fixture with its pin scoped to the repair site.

View Source
const WorkflowResultSchemaVersion = 1

WorkflowResultSchemaVersion is the contract emitted by the workflow runner and accepted by strict reporting. Rows carry the init facts, the tool trace, the verdicts, and the cost of one trial; the JSON shape is documented in bench/workflow-result-v1.schema.json.

Variables

This section is empty.

Functions

func ClaudeArgv added in v0.6.0

func ClaudeArgv(model, effort string, budget float64, tools []string) []string

ClaudeArgv builds the headless Claude Code command for the skills workflow experiment. It is the lessons adapter (cmd/lessons-bench) with three differences: no --disable-slash-commands, because that flag also hides project skills; --tools takes the caller's list, because the arms differ in the tools they expose; and neither --strict-mcp-config nor --mcp-config, because the runner appends both per trial with the binary installed inside the trial. The task prompt is appended by the runner as the last argument.

func CommandVersion added in v0.6.0

func CommandVersion(name string, args ...string) string

CommandVersion asks a binary for its version and returns the first output line, or "unknown" when the binary has no such flag or does not answer.

func ExactModelID added in v0.6.0

func ExactModelID(model string) bool

ExactModelID reports whether model is an exact Claude model ID rather than an alias. A benchmark row must name the model it ran on; an alias resolves to different models over time and would pool rows that never shared one.

func FileSHA256

func FileSHA256(path string) (string, error)

FileSHA256 returns the digest used to bind result rows to the exact Seamark executable that served their hooks.

func Fingerprint

func Fingerprint(cfg RunConfig) (string, error)

Fingerprint binds cost estimates and result pooling to one task, agent configuration, runtime, and Seamark binary. The command itself is hashed, never persisted, because custom adapters may carry sensitive arguments.

func GenerateSchemaSyncFixture

func GenerateSchemaSyncFixture(dir string) error

GenerateSchemaSyncFixture creates a small mixed-language monorepo whose git history contains one earlier backend-only schema change and its follow-up generated-client fix. The current checkout is healthy and carries no Seamark treatment files.

func InstanceIDs

func InstanceIDs() []string

InstanceIDs returns the stable CLI selectors in catalogue order.

func LocalRuntimeID added in v0.6.0

func LocalRuntimeID(agentVersion string, checks []Command) string

LocalRuntimeID describes the host the agent and the fixture's checks run on: the sandbox generation, the platform, the agent version, and the version of every toolchain the checks call. It is part of the fingerprint, so rows from different toolchains are never pooled.

func Preflight

func Preflight(ctx context.Context, cfg RunConfig) error

Preflight validates every invariant that can be checked without spending an agent call: deterministic generation, a clean and healthy base tree, a naive task-only solution the invariant judge must reject, a canonical passing solution, and uncontaminated arm wiring.

func PrepareInstance added in v0.5.0

func PrepareInstance(ctx context.Context, instance Instance) (string, error)

PrepareInstance downloads and verifies the immutable source and offline dependencies required by a public-repository benchmark. Preparation is deliberately separate from Run: agent trials remain network-isolated and a paid run cannot unexpectedly turn into a repository download.

func PriorCostFor

func PriorCostFor(path, fingerprint string) (rows int, meanInput int64, meanCost float64, ok bool)

PriorCostFor only pools rows from the same immutable run fingerprint. An estimate made from another model, task, or runtime is worse than no estimate because it creates false confidence before a paid run.

func PriorWorkflowCostFor added in v0.6.0

func PriorWorkflowCostFor(path, fingerprint string) (rows int, meanInput int64, meanCost float64, ok bool)

PriorWorkflowCostFor pools only valid paired rows with the same workflow fingerprint, for the cost estimate the banner prints before a paid run.

func ProtocolFingerprint added in v0.5.0

func ProtocolFingerprint(cfg RunConfig) (string, error)

ProtocolFingerprint binds two intentional instance variants to identical task, fixture, judge, harness, agent, and runtime conditions. The canonical instance contributes the full fingerprint; only the variant's scoped lesson and exposure expectation are excluded. Reports require equality before evaluating a difference-in-differences claim.

func RejectOutputCollision added in v0.6.0

func RejectOutputCollision(outPath string, protected []string) error

RejectOutputCollision refuses an output path that names or aliases one of the protected inputs, so a report can never overwrite the evidence it was built from. "-" means stdout and is always accepted.

func ResolveSeamarkBinary added in v0.6.0

func ResolveSeamarkBinary(configured string) (string, error)

ResolveSeamarkBinary returns the absolute path of the seamark binary a benchmark drives: the configured one, or bin/seamark from `make build`. The file must exist, because every row hashes it.

func SameAgentArgv added in v0.6.0

func SameAgentArgv(argv []string) map[WorkflowArm][]string

SameAgentArgv gives both arms the same agent command, for custom adapters and stub agents that do not read --tools.

func ValidateActivationRow added in v0.6.0

func ValidateActivationRow(row ActivationRow) error

ValidateActivationRow enforces the semantic contract of an activation row.

func ValidateResultRow

func ValidateResultRow(row Row) error

ValidateResultRow enforces the semantic contract documented by the versioned schemas in bench/. It is intentionally stricter than ReadRows, whose best-effort behavior remains useful for historical cost estimation.

func ValidateWorkflowRow added in v0.6.0

func ValidateWorkflowRow(row WorkflowRow) error

ValidateWorkflowRow enforces the semantic contract of a workflow row. It is stricter than ReadWorkflowRows, whose best-effort reading remains useful for cost estimation.

func WorkflowFingerprint added in v0.6.0

func WorkflowFingerprint(cfg WorkflowConfig) (string, error)

WorkflowFingerprint binds cost estimates and result pooling to one instance, arm assignment, agent configuration, runtime, Seamark binary, and skills tree. The agent commands are hashed, never persisted, because custom adapters may carry sensitive arguments.

func WorkflowInstanceIDs added in v0.6.0

func WorkflowInstanceIDs() []string

WorkflowInstanceIDs returns the CLI selectors in catalogue order.

func WorkflowPreflight added in v0.6.0

func WorkflowPreflight(ctx context.Context, cfg WorkflowConfig) error

WorkflowPreflight validates every invariant that can be checked without spending an agent call. It runs the lessons preflight on the shared instance (determinism, judges, patches, checks, a treatment-free tree), then adds three gates of its own: the fixture history carries the trigger-companion co-change, the seamark binary answers an MCP initialize request as "seamark", and both arms wire exactly what they measure. Every failure names its gate.

func WorkflowTools added in v0.6.0

func WorkflowTools(arm WorkflowArm) []string

WorkflowTools lists the tools an arm exposes to the agent, in --tools order. The list is the expected init tool set as well: a row whose init record shows any other set is invalid.

func WriteAtomic added in v0.6.0

func WriteAtomic(path string, content []byte) error

WriteAtomic writes content through a temporary file and a rename, so a reader never sees a half-written report.

func WriteReport added in v0.6.0

func WriteReport(outPath string, content []byte) error

WriteReport writes a rendered report to outPath, or to stdout when outPath is "-"; both report CLIs share the rule.

Types

type ActivationCriteria added in v0.6.0

type ActivationCriteria struct {
	MinimumRecall          map[string]float64 `yaml:"minimum_recall"`
	MaximumFalseActivation float64            `yaml:"maximum_false_activation"`
}

ActivationCriteria are the frozen pass criteria of the activation evaluation: a minimum recall per skill on its should-activate prompts and a maximum false-activation rate on the should-not prompts.

type ActivationInputs added in v0.6.0

type ActivationInputs struct {
	Paths   []string
	Prompts ActivationPromptSet
}

ActivationInputs names the activation result files and the prompt manifest they were measured against. The zero value means no activation section.

type ActivationPrompt added in v0.6.0

type ActivationPrompt struct {
	ID     string `yaml:"id"`
	Prompt string `yaml:"prompt"`
	// Expect names the skill that should activate, or "none" for a prompt
	// no skill should answer.
	Expect string `yaml:"expect"`
	// Prepare changes the fixture before the session: "naive" applies the
	// instance's naive patch; empty leaves the tree untouched.
	Prepare string `yaml:"prepare,omitempty"`
	// Note says why the prompt is in the set.
	Note string `yaml:"note,omitempty"`
}

ActivationPrompt is one entry of the checked-in prompt set.

type ActivationPromptSet added in v0.6.0

type ActivationPromptSet struct {
	SchemaVersion int                `yaml:"schema_version"`
	Instance      string             `yaml:"instance"`
	Prompts       []ActivationPrompt `yaml:"prompts"`
}

ActivationPromptSet is the checked-in prompt file. Instance names the workflow instance the prompts are written for: they name its files, so a run on another fixture would measure a mismatch, not activation.

func LoadActivationPrompts added in v0.6.0

func LoadActivationPrompts(path string) (ActivationPromptSet, error)

LoadActivationPrompts parses and validates a prompt file. Unknown keys and a second YAML document are errors, so a typo cannot silently drop a case.

func (ActivationPromptSet) SHA256 added in v0.6.0

func (s ActivationPromptSet) SHA256() (string, error)

SHA256 identifies the exact prompt set a row was measured against.

func (ActivationPromptSet) Validate added in v0.6.0

func (s ActivationPromptSet) Validate() error

Validate rejects a prompt set that could not measure what the report claims: ids must be unique and usable in file names, every expectation must name a shipped skill or none, every shipped skill needs at least one should-activate prompt, and there must be at least one should-not prompt.

type ActivationRate added in v0.6.0

type ActivationRate struct {
	Numerator   int
	Denominator int
}

ActivationRate is a numerator over a denominator, kept as counts so the report can print "2/3" and the reader can see how small the sample is.

func (ActivationRate) Value added in v0.6.0

func (r ActivationRate) Value() (float64, bool)

Value returns the rate, or false when nothing was measured.

type ActivationReport added in v0.6.0

type ActivationReport struct {
	Inputs         []ReportInput
	Fingerprint    string
	PromptSetSHA   string
	RequestedModel string
	Model          string
	MaxTurns       int
	Rows           []ActivationRow
	// Missing lists the manifest prompts without a valid session, in
	// manifest order.
	Missing []string
	Stats   ActivationStats
	Status  string
	Reasons []string
}

ActivationReport renders one activation experiment against the frozen criteria. One experiment means one fingerprint, prompt set, requested model, and turn cap; rows from another identity are refused, never pooled. Every prompt of the manifest needs a valid session before the criteria are assessed: a run that stopped early must read as insufficient, not as a pass on the prompts it happened to reach.

type ActivationRow added in v0.6.0

type ActivationRow struct {
	SchemaVersion int    `json:"schema_version"`
	TS            string `json:"ts"`
	RunID         string `json:"run_id"`
	Instance      string `json:"instance"`
	Fixture       string `json:"fixture"`
	Fingerprint   string `json:"fingerprint"`
	// PromptSetSHA identifies the whole prompt file; PromptID and
	// PromptSHA identify the one prompt this row measured.
	PromptSetSHA string `json:"prompt_set_sha256"`
	PromptID     string `json:"prompt_id"`
	PromptSHA    string `json:"prompt_sha256"`
	Expected     string `json:"expected"`
	Prepare      string `json:"prepare,omitempty"`
	// Activated lists the skills the agent loaded; Hit says the session met
	// its expectation: the expected skill loaded, or nothing loaded for a
	// should-not prompt. Other skills loading beside the expected one keep
	// Hit true and show up in the report's cross-activation count.
	Activated []string `json:"activated,omitempty"`
	Hit       bool     `json:"hit"`
	MaxTurns  int      `json:"max_turns,omitempty"`

	Valid                 bool   `json:"valid"`
	InvalidReason         string `json:"invalid_reason,omitempty"`
	InfrastructureFailure bool   `json:"infrastructure_failure,omitempty"`

	InitSeen   bool             `json:"init_seen,omitempty"`
	ResultSeen bool             `json:"result_seen,omitempty"`
	Tools      []string         `json:"tools,omitempty"`
	MCPServers []MCPServerState `json:"mcp_servers,omitempty"`
	Skills     []string         `json:"skills,omitempty"`
	Plugins    []string         `json:"plugins,omitempty"`
	// DeniedTools lists the tools the agent asked for and was refused. A
	// refused Skill call is a recall miss the harness caused, not the
	// model, so the row is invalid rather than a miss.
	DeniedTools []string `json:"denied_tools,omitempty"`

	SeamarkCalls     int            `json:"seamark_calls"`
	SeamarkToolCalls map[string]int `json:"seamark_tool_calls,omitempty"`
	Edits            int            `json:"edits"`

	AgentUsage

	SeamarkVersion string  `json:"seamark_version,omitempty"`
	SeamarkSHA     string  `json:"seamark_sha256,omitempty"`
	AgentVersion   string  `json:"agent_version,omitempty"`
	Effort         string  `json:"effort,omitempty"`
	MaxBudgetUSD   float64 `json:"max_budget_usd,omitempty"`
	RuntimeID      string  `json:"runtime_id,omitempty"`

	Transcript    string `json:"transcript,omitempty"`
	TranscriptSHA string `json:"transcript_sha256,omitempty"`
	StderrLog     string `json:"stderr,omitempty"`
	StderrSHA     string `json:"stderr_sha256,omitempty"`
}

ActivationRow is one prompt session of the activation evaluation.

func ReadActivationRows added in v0.6.0

func ReadActivationRows(path string) ([]ActivationRow, string, error)

ReadActivationRows reads an activation results file strictly: every line must be a valid row, because the report renders every one of them.

type ActivationStats added in v0.6.0

type ActivationStats struct {
	Recall          map[string]ActivationRate
	FalseActivation ActivationRate
	// CrossActivations counts valid should-activate sessions that loaded a
	// skill other than the expected one; two skills on one prompt is a
	// description defect the criteria do not otherwise see.
	CrossActivations int
	Valid            int
	Invalid          int
}

ActivationStats are the inputs of the activation criteria: recall per expected skill over its should-activate prompts, and the false-activation rate over the should-not prompts. Only valid rows count.

func ActivationStatsFor added in v0.6.0

func ActivationStatsFor(rows []ActivationRow) ActivationStats

ActivationStatsFor tallies rows into the criteria's inputs.

func (ActivationStats) Lines added in v0.6.0

func (s ActivationStats) Lines() []string

Lines renders the stats as raw counts, one line per criterion input.

type ActivationSummary added in v0.6.0

type ActivationSummary struct {
	Rows          []ActivationRow
	StoppedReason string
}

ActivationSummary is one activation run's outcome.

func RunActivation added in v0.6.0

func RunActivation(ctx context.Context, cfg WorkflowConfig, prompts ActivationPromptSet) (ActivationSummary, error)

RunActivation replays the prompt set, one fresh skills-arm session per prompt, and records which skills activated. Sessions are capped by cfg.MaxTurns; reaching the cap is a measured outcome. Provider failures stop the run before the next paid session, and cancellation returns the partial summary with a nil error.

func (ActivationSummary) Lines added in v0.6.0

func (s ActivationSummary) Lines() []string

Lines renders the run as the activation stats plus the stop reason.

type AgentUsage added in v0.6.0

type AgentUsage struct {
	RequestedModel      string                `json:"requested_model,omitempty"`
	Model               string                `json:"model,omitempty"`
	ModelUsage          map[string]ModelUsage `json:"model_usage,omitempty"`
	InputTokens         int64                 `json:"input_tokens,omitempty"`
	CacheReadTokens     int64                 `json:"cache_read_input_tokens,omitempty"`
	CacheCreationTokens int64                 `json:"cache_creation_input_tokens,omitempty"`
	ContextTokens       int64                 `json:"context_tokens,omitempty"`
	OutputTokens        int64                 `json:"output_tokens,omitempty"`
	Turns               int                   `json:"turns,omitempty"`
	PermissionDenials   int                   `json:"permission_denials,omitempty"`
	CostUSD             float64               `json:"cost_usd,omitempty"`
	DurationMS          int64                 `json:"duration_ms,omitempty"`
	AgentExit           int                   `json:"agent_exit"`
	TimedOut            bool                  `json:"timed_out,omitempty"`
	AgentError          bool                  `json:"agent_error,omitempty"`
}

AgentUsage is the provider-reported identity and usage of one session. The fields mirror the lessons Row because the same parser fills them.

type Arm

type Arm string

Arm is one experimental condition. The fixture itself carries no seamark artifacts; each arm installs exactly what it measures.

const (
	// ArmHookOff is the true baseline: no lesson anywhere, no hook.
	ArmHookOff Arm = "hook-off"
	// ArmFileOnly commits the real lesson to lessons.yaml but wires no
	// hook: delivery depends on the agent discovering the file. This
	// is the mechanism arm — a committed lessons.yaml is itself a
	// delivery channel, and the hook's claim is beating it.
	ArmFileOnly Arm = "file-only"
	// ArmPlacebo wires the hook with a same-size lesson that carries
	// no information about the mistake: the cost/attention control.
	ArmPlacebo Arm = "placebo"
	// ArmHookOn is the full treatment: real lesson, hook wired.
	ArmHookOn Arm = "hook-on"
)

type ArmReport

type ArmReport struct {
	Attempted        int
	Valid            int
	TaskDone         int
	InvariantPass    int
	ContextTokens    int64
	CostUSD          float64
	HookMatches      int
	HookInjections   int
	HookRepeated     int
	HookSuppressed   int
	HookContextBytes int
}

ArmReport aggregates valid and invalid attempts for one arm.

type BenchmarkReport

type BenchmarkReport struct {
	ResultSchemaVersion int
	ClaimSchemaVersion  int
	EvidenceFrom        string
	EvidenceTo          string
	Inputs              []ReportInput
	Cohorts             []CohortReport
	Assessments         []ClaimAssessment
}

BenchmarkReport is a deterministic summary of explicit raw inputs.

func BuildBenchmarkReport

func BuildBenchmarkReport(paths []string, registry ClaimRegistry) (BenchmarkReport, error)

BuildBenchmarkReport strictly reads the requested JSONL files. Malformed or semantically invalid rows fail the report instead of disappearing.

func (BenchmarkReport) Markdown

func (r BenchmarkReport) Markdown() string

Markdown renders a deterministic, reviewable report. Percentages are point estimates; the paired discordance counts remain visible so tiny samples do not look conclusive.

type CheckResult

type CheckResult struct {
	Command  string `json:"command"`
	Pass     bool   `json:"pass"`
	TimedOut bool   `json:"timed_out,omitempty"`
	Output   string `json:"output,omitempty"`
}

CheckResult is the persisted result of one validation command.

type Claim

type Claim struct {
	ID            string `yaml:"id"`
	Claim         string `yaml:"claim"`
	PrimaryMetric string `yaml:"primary_metric"`
	Comparison    string `yaml:"comparison"`
	// TreatmentInstance and ControlInstance name the two variants a
	// difference_in_differences claim compares. Both must appear in
	// Instances; empty for hook-on_vs_hook-off claims.
	TreatmentInstance            string   `yaml:"treatment_instance,omitempty"`
	ControlInstance              string   `yaml:"control_instance,omitempty"`
	Direction                    string   `yaml:"direction"`
	RequiredModel                string   `yaml:"required_model"`
	RequiredEffort               string   `yaml:"required_effort"`
	RequireCleanSeamark          bool     `yaml:"require_clean_seamark"`
	MinimumEffect                float64  `yaml:"minimum_effect"`
	MinimumInstanceEffect        float64  `yaml:"minimum_instance_effect"`
	MaximumHarmfulInterference   float64  `yaml:"maximum_harmful_interference"`
	MinimumInstances             int      `yaml:"minimum_instances"`
	MinimumValidPairsPerInstance int      `yaml:"minimum_valid_pairs_per_instance"`
	Instances                    []string `yaml:"instances"`
}

Claim defines one falsifiable product claim and its evidence floor.

type ClaimAssessment

type ClaimAssessment struct {
	ID                  string
	Definition          Claim
	Status              string
	Reason              string
	QualifyingInstances int
	MeanEffect          float64
	WorstInstanceEffect float64
	HarmfulInterference float64
	// AnchorNote carries the component effects behind a factorial claim. It is
	// report-only; the frozen verdict uses their difference.
	AnchorNote string
}

ClaimAssessment says whether the supplied evidence has reached the frozen floor. A positive effect with too few independent instances stays insufficient rather than being promoted to a pass.

type ClaimRegistry

type ClaimRegistry struct {
	SchemaVersion int     `yaml:"schema_version"`
	Claims        []Claim `yaml:"claims"`
}

ClaimRegistry is the versioned set of thresholds frozen before expanding a benchmark corpus.

func LoadClaimRegistry

func LoadClaimRegistry(path string) (ClaimRegistry, error)

LoadClaimRegistry parses and validates the committed claim thresholds.

func (ClaimRegistry) Validate

func (r ClaimRegistry) Validate() error

Validate rejects claim files that could silently weaken or ambiguously define the evidence threshold.

type CohortReport

type CohortReport struct {
	Instance            string
	Fingerprint         string
	Task                string
	TaskSHA             string
	Pin                 string
	Fixture             string
	RequestedModel      string
	Model               string
	SeamarkVersion      string
	SeamarkSHA          string
	AgentVersion        string
	Effort              string
	HookDelivery        HookDeliveryMode
	HookExposure        HookExposureExpectation
	ComparisonFamily    string
	ProtocolFingerprint string
	RuntimeID           string
	MaxBudgetUSD        float64
	Rows                int
	ValidPairs          int
	FavorablePairs      int
	UnfavorablePairs    int
	TiedPairs           int
	HarmfulPairs        int
	HookOn              ArmReport
	HookOff             ArmReport
}

CohortReport is one immutable experiment fingerprint. Different harness, fixture, model, or runtime identities are never pooled.

func (CohortReport) Effect

func (c CohortReport) Effect() (float64, bool)

Effect returns the hook-on minus hook-off invariant-pass rate, conditional on completing the visible task in each arm.

func (CohortReport) EffectInterval95

func (c CohortReport) EffectInterval95() (low, high float64, ok bool)

EffectInterval95 returns a conservative Newcombe-style 95% Wilson score interval for the difference between the two conditional proportions. Paired direction counts are reported separately because they preserve information this interval does not model.

type Command

type Command struct {
	Name    string
	Args    []string
	Timeout time.Duration
}

Command is a deterministic repository-local validation command. Hidden task/invariant judges stay in Go; these commands answer whether the tree the agent left behind still builds and passes its public checks.

func (Command) String

func (c Command) String() string

type HookDeliveryMode

type HookDeliveryMode = reviews.HookDeliveryMode

HookDeliveryMode is the lessons hook policy measured by a benchmark cohort.

type HookExposureExpectation added in v0.5.0

type HookExposureExpectation string

HookExposureExpectation says whether a hooked arm must prove that its configured pin matched the agent's edit trajectory. Most benchmark treatments require an injection. A scope-control instance may make exposure optional because the absence of a match is the behavior under test; preflight still proves that the hook and lesson were installed correctly.

const (
	// HookExposureRequired invalidates a hooked row that proves no matching injection.
	HookExposureRequired HookExposureExpectation = "required"
	// HookExposureOptional permits zero exposure for a scoped control.
	HookExposureOptional HookExposureExpectation = "optional"
	// HookExposureNone is reserved for arms with no hook treatment.
	HookExposureNone HookExposureExpectation = "none"
)

type Instance

type Instance struct {
	ID          string
	Rule        string
	Task        string
	LessonYAML  string
	PlaceboYAML string

	Generate  func(string) error
	Judge     func(string) (Verdict, error)
	ApplyGold func(string) error
	// ApplyNaive installs a task-complete solution that deliberately omits the
	// owner invariant. Preflight uses it to prove that the two judges actually
	// discriminate the failure mode the experiment claims to measure.
	ApplyNaive func(string) error
	// JudgeVersion must change whenever verdict semantics change. It binds
	// persisted rows to the exact interpretation used by this instance.
	JudgeVersion string
	Checks       []Command
	// HookExposure controls validation of hooked arms. Empty means required,
	// preserving the original benchmark contract. Optional is reserved for a
	// scope-control whose valid outcome may be zero matching edits.
	HookExposure HookExposureExpectation
	// ComparisonFamily groups intentionally different instances that form one
	// factorial experiment. Empty means the instance is not cross-compared.
	ComparisonFamily string
	// ProtocolInstance names the canonical instance whose full fingerprint
	// defines the shared protocol for ComparisonFamily. Every family variant
	// points to the same canonical instance.
	ProtocolInstance string

	// ExploreFiles are repository-relative paths whose appearance in an
	// assistant message is useful diagnostic evidence. They do not affect the
	// verdict.
	ExploreFiles []string

	// Prepare materializes any external, pinned source required by Generate.
	// Synthetic instances leave it nil. Public-repository instances use an
	// explicit preparation step so paid runs and their agents never depend on
	// network access.
	Prepare func(context.Context) (string, error)
	// contains filtered or unexported fields
}

Instance is one immutable benchmark problem. The runner deliberately knows nothing about the fixture's language or mistake class: generation, judging, and verification all live here so additional instances do not fork the experimental harness.

func CacheVersionInstance

func CacheVersionInstance() Instance

CacheVersionInstance models an owner-only compatibility rule: changing a cached response shape requires a namespace bump even though the presenter and its public tests pass without one.

func ExportRegistryInstance

func ExportRegistryInstance() Instance

ExportRegistryInstance models a split synchronous/asynchronous ownership rule: the visible preview API and its tests do not exercise the worker's separately maintained formatter registry.

func InstanceByID

func InstanceByID(id string) (Instance, error)

InstanceByID resolves one CLI-facing benchmark instance. An empty selector retains the schema-sync instance as the backwards-compatible default.

func Instances

func Instances() []Instance

Instances returns the stable benchmark catalogue. Values are constructed on demand so callers can safely customize them without mutating shared state. Catalogue membership is intentionally outside the execution fingerprint: adding an unrelated fixture must not invalidate an existing cohort.

func OTelHistogramInstance added in v0.5.0

func OTelHistogramInstance() Instance

OTelHistogramInstance is a pinned public-repository task derived from open-telemetry/opentelemetry-go#8399 and its merged fix #8403. The reported reproduction exercises explicit histograms. The owner invariant is parallel reset behavior in both exponential-histogram collection paths.

func OTelHistogramRepairInstance added in v0.5.0

func OTelHistogramRepairInstance() Instance

OTelHistogramRepairInstance differs from OTelHistogramInstance only by placing the lesson at the exponential-histogram repair path. An agent that edits only the explicit implementation therefore receives no reminder.

func SchemaSyncInstance

func SchemaSyncInstance() Instance

SchemaSyncInstance models a recurring owner-only contract: backend API changes require an explicit generated-client refresh that ordinary backend tests do not enforce. The repository is synthetic and deterministic, but the workflow is the same one used by mixed Python/TypeScript monorepos.

func SchemaSyncRepairInstance added in v0.5.0

func SchemaSyncRepairInstance() Instance

SchemaSyncRepairInstance is SchemaSyncInstance with ONE difference: the pin's region moves from the trigger (server) to the repair site (web/src/api). The fixture, task, judges, patches, and the pin's note are shared by construction — the region swap is a textual replacement on the same yaml. The report subtracts each variant's hook-off baseline before attributing the remaining outcome delta to delivery scoping. This is the control variant of the lessons-delivery-scoping claim.

func (Instance) TaskSHA

func (i Instance) TaskSHA() string

TaskSHA identifies the exact problem statement without copying it into every result row.

func (Instance) Validate

func (i Instance) Validate() error

Validate rejects incomplete instances before they can spend an agent call.

type MCPServerState added in v0.6.0

type MCPServerState struct {
	Name   string `json:"name"`
	Status string `json:"status,omitempty"`
}

MCPServerState is one MCP server as the agent's init record reports it.

type ModelUsage

type ModelUsage struct {
	InputTokens         int64   `json:"input_tokens,omitempty"`
	CacheReadTokens     int64   `json:"cache_read_input_tokens,omitempty"`
	CacheCreationTokens int64   `json:"cache_creation_input_tokens,omitempty"`
	OutputTokens        int64   `json:"output_tokens,omitempty"`
	CostUSD             float64 `json:"cost_usd,omitempty"`
}

ModelUsage preserves provider-reported usage for every model involved in a session. Helper-model calls must never be mistaken for the primary model.

type ReportInput

type ReportInput struct {
	Path   string
	SHA256 string
	Rows   int
}

ReportInput identifies one raw input exactly.

type Row

type Row struct {
	SchemaVersion int    `json:"schema_version"`
	TS            string `json:"ts"`
	RunID         string `json:"run_id"`
	Instance      string `json:"instance"`
	TaskSHA       string `json:"task_sha256"`
	Pin           string `json:"pin"`
	Arm           Arm    `json:"arm"`
	Trial         int    `json:"trial"`
	TaskDone      bool   `json:"task_pass"`
	Avoided       bool   `json:"invariant_pass"`
	Notes         string `json:"notes,omitempty"`

	// Valid says the agent session and treatment were actually delivered.
	// PairValid additionally says every requested arm in this trial number was
	// valid. Only rows satisfying both enter effect tallies.
	Valid                 bool   `json:"valid"`
	PairValid             bool   `json:"pair_valid"`
	InvalidReason         string `json:"invalid_reason,omitempty"`
	InfrastructureFailure bool   `json:"infrastructure_failure,omitempty"`
	// Fixture is the generated repo's full HEAD commit. Generation
	// is deterministic, so this identifies the exact fixture content a
	// row was measured against — rows from different fixture versions
	// must never be pooled as one series.
	Fixture string `json:"fixture,omitempty"`
	// HookFirings is how many firing records the trial repo's own
	// audit log holds after the run (hook-on arm only). Zero means the
	// injection never reached the agent and the arms were effectively
	// identical — the row proves its treatment happened instead of
	// assuming it.
	HookFirings int `json:"hook_firings,omitempty"`
	// HookAuditRows records every audit row, including unrelated or malformed
	// firings. HookFirings counts only rows proving that the selected lesson
	// reached an in-region edit through the expected hook surface.
	HookAuditRows int `json:"hook_audit_rows,omitempty"`
	// Schema v6 delivery intensity. Matches counts matching edit-hook
	// invocations; each match either injected context or was fully suppressed.
	HookMatches      int `json:"hook_matches"`
	HookInjections   int `json:"hook_injections"`
	HookRepeated     int `json:"hook_repeated_injections"`
	HookSuppressed   int `json:"hook_suppressed"`
	HookContextBytes int `json:"hook_context_bytes"`
	// Transcript is where this trial's raw agent output was saved;
	// StderrLog and Patch keep the rest of the audit record, so a
	// verdict stays checkable after the trial dir is deleted.
	Transcript    string `json:"transcript,omitempty"`
	TranscriptSHA string `json:"transcript_sha256,omitempty"`
	StderrLog     string `json:"stderr,omitempty"`
	StderrSHA     string `json:"stderr_sha256,omitempty"`
	Patch         string `json:"patch,omitempty"`
	PatchSHA      string `json:"patch_sha256,omitempty"`
	// Checks are public repository-local validation commands. Hidden task and
	// invariant judges are represented by TaskDone and Avoided above.
	ChecksPass bool          `json:"checks_pass"`
	Checks     []CheckResult `json:"checks,omitempty"`
	// LessonFileRead: the agent named .seamark/lessons.yaml in its own
	// messages. In arms without a lesson file this must be false; in a
	// control arm it would mean contamination.
	LessonFileRead bool `json:"lesson_file_read,omitempty"`
	// Explored lists instance-selected files the agent named in its own
	// messages and tool calls, in first-mention order. It is diagnostic
	// evidence only and never affects a verdict.
	Explored            []string                `json:"explored,omitempty"`
	RequestedModel      string                  `json:"requested_model,omitempty"`
	Model               string                  `json:"model,omitempty"`
	ModelUsage          map[string]ModelUsage   `json:"model_usage,omitempty"`
	InputTokens         int64                   `json:"input_tokens,omitempty"`
	CacheReadTokens     int64                   `json:"cache_read_input_tokens,omitempty"`
	CacheCreationTokens int64                   `json:"cache_creation_input_tokens,omitempty"`
	ContextTokens       int64                   `json:"context_tokens,omitempty"`
	OutputTokens        int64                   `json:"output_tokens,omitempty"`
	Turns               int                     `json:"turns,omitempty"`
	PermissionDenials   int                     `json:"permission_denials,omitempty"`
	CostUSD             float64                 `json:"cost_usd,omitempty"`
	DurationMS          int64                   `json:"duration_ms,omitempty"`
	AgentExit           int                     `json:"agent_exit"`
	TimedOut            bool                    `json:"timed_out,omitempty"`
	AgentError          bool                    `json:"agent_error,omitempty"`
	InitSeen            bool                    `json:"init_seen,omitempty"`
	ResultSeen          bool                    `json:"result_seen,omitempty"`
	Tools               []string                `json:"tools,omitempty"`
	Plugins             []string                `json:"plugins,omitempty"`
	MCPServers          []string                `json:"mcp_servers,omitempty"`
	SeamarkVersion      string                  `json:"seamark_version,omitempty"`
	SeamarkSHA          string                  `json:"seamark_sha256,omitempty"`
	AgentVersion        string                  `json:"agent_version,omitempty"`
	Effort              string                  `json:"effort,omitempty"`
	HookDelivery        HookDeliveryMode        `json:"hook_delivery,omitempty"`
	HookExposure        HookExposureExpectation `json:"hook_exposure,omitempty"`
	MaxBudgetUSD        float64                 `json:"max_budget_usd,omitempty"`
	RuntimeID           string                  `json:"runtime_id,omitempty"`
	Fingerprint         string                  `json:"fingerprint,omitempty"`
	ProtocolFingerprint string                  `json:"protocol_fingerprint,omitempty"`
	ComparisonFamily    string                  `json:"comparison_family,omitempty"`
}

Row is one trial's result as appended to the JSONL file. Rows are self-contained: pin, arm, verdict, and cost travel together so the file stays meaningful across runs and versions.

func ReadRows

func ReadRows(path string) ([]Row, error)

ReadRows reads a results JSONL file back, skipping unparseable lines. A missing file is an empty history, not an error.

type RunConfig

type RunConfig struct {
	Trials     int           // trials per arm
	Arms       []Arm         // arms to run; nil means both
	Instance   Instance      // zero value selects SchemaSyncInstance
	AgentArgv  []string      // agent command; the task prompt is appended as the last argument
	SeamarkBin string        // absolute path to the seamark binary (hook command + index)
	Timeout    time.Duration // per-trial agent timeout; 0 means 10 minutes
	Out        string        // results JSONL path, appended one row per trial
	WorkDir    string        // parent for trial dirs; "" means a fresh temp dir
	Keep       bool          // keep trial dirs after judging, for inspection
	// TranscriptDir saves each trial's raw agent stdout (the full
	// stream-json transcript when the agent emits one) for reading WHY
	// a verdict came out the way it did. Empty disables saving.
	TranscriptDir string
	// PrepareIndex runs `seamark index` in hook-on trials so the hook
	// has a store to read. Hermetic tests turn it off.
	PrepareIndex bool
	Version      string // seamark version stamped into rows
	SeamarkSHA   string // exact binary digest stamped into rows
	AgentVersion string // agent CLI version stamped into rows
	Model        string // exact requested primary model; empty for custom agents
	Effort       string // requested effort level
	MaxBudgetUSD float64
	RuntimeID    string // sandbox/toolchain identity
	Fingerprint  string // immutable instance + runtime configuration hash
	// ProtocolFingerprint omits the intentionally varied instance scope while
	// binding every shared part of a cross-instance experiment.
	ProtocolFingerprint string
	// RunID groups rows and makes transcript names unique across concurrent
	// invocations. Empty asks Run to generate a cryptographically random ID.
	RunID string
	// HookDelivery selects the edit-hook repeat policy. Empty means always.
	HookDelivery HookDeliveryMode

	// RequireStructuredResult and RequireCleanInit are true for the
	// default Claude adapter. Stub/custom adapters may leave them false.
	RequireStructuredResult bool
	RequireCleanInit        bool
	Log                     func(string, ...any) // progress lines; nil silences
}

RunConfig configures one benchmark run.

type Summary

type Summary struct {
	Rows          []Row
	ByArm         map[Arm]Tally
	RunID         string
	Instance      string
	Rule          string
	HookExposure  HookExposureExpectation
	StoppedReason string
}

Summary is the whole run's outcome, per arm.

func Run

func Run(ctx context.Context, cfg RunConfig) (Summary, error)

Run executes the experiment: Trials fresh fixture repos per arm, alternating arms so slow model drift within the run spreads evenly, each judged mechanically. A pair is finalized and appended before the next pair starts; graceful cancellation also flushes a completed arm from a partially executed pair.

Cancelling ctx stops the run cleanly between (or during) trials and returns the partial summary with a nil error, so an interrupted run still reports what it measured.

func (Summary) Lines

func (s Summary) Lines() []string

Lines renders the summary the way the RFC reports results: raw counts per arm, no statistics theater, plus the measured token cost of the injection when both arms reported usage.

type Tally

type Tally struct {
	Attempted    int
	Ran          int
	Invalid      int
	Completed    int // trials where the task was done at all
	Avoided      int // completed trials where the owner invariant passed
	Firings      int // hook firing records across the arm's trials
	Matches      int
	Injections   int
	Repeated     int
	Suppressed   int
	ContextBytes int
	MeanInput    int64
}

Tally is one arm's aggregate.

type Verdict

type Verdict struct {
	// TaskDone means the agent completed the visible task.
	TaskDone bool
	// Avoided means a task-complete solution also preserved the owner invariant.
	Avoided bool
	// Notes concisely explains the deterministic judgment.
	Notes string
}

Verdict is one trial's deterministic judgment, read from the code the agent left behind rather than inferred from its transcript.

func JudgeSchemaSync

func JudgeSchemaSync(dir string) (Verdict, error)

JudgeSchemaSync first verifies the requested backend behavior, then derives the expected TypeScript client independently of the agent-editable generator.

type WorkflowArm added in v0.6.0

type WorkflowArm string

WorkflowArm is one condition of the skills workflow experiment. Both arms connect the seamark MCP server and approve its five tools; they differ in exactly one thing: whether the three agent skills are installed and the Skill tool is exposed.

const (
	// ArmMCPOnly connects the MCP server and approves its tools. No skill
	// is installed and the Skill tool is not exposed.
	ArmMCPOnly WorkflowArm = "mcp-only"
	// ArmMCPSkills adds the three managed skills under .claude/skills, the
	// Skill tool, and the Skill allow rules.
	ArmMCPSkills WorkflowArm = "mcp-skills"
)

type WorkflowArmReport added in v0.6.0

type WorkflowArmReport struct {
	Attempted     int
	Valid         int
	TaskDone      int
	InvariantPass int
	WorkflowProcessCounts
	ContextTokens int64
	CostUSD       float64
}

WorkflowArmReport aggregates one arm's valid paired rows of a cohort.

type WorkflowAssessment added in v0.6.0

type WorkflowAssessment struct {
	ID                  string
	Definition          WorkflowClaim
	Status              string
	Reason              string
	Reasons             []string
	QualifyingInstances int
	MeanEffect          float64
	WorstInstanceEffect float64
	HarmfulInterference float64
}

WorkflowAssessment says whether the evidence reached a frozen claim's floor. Reasons names every failed condition, so a failing claim is explained, not just declared.

type WorkflowClaim added in v0.6.0

type WorkflowClaim struct {
	ID                           string   `yaml:"id"`
	Claim                        string   `yaml:"claim"`
	PrimaryMetric                string   `yaml:"primary_metric"`
	Comparison                   string   `yaml:"comparison"`
	Direction                    string   `yaml:"direction"`
	RequiredModel                string   `yaml:"required_model"`
	RequiredEffort               string   `yaml:"required_effort"`
	RequireCleanSeamark          bool     `yaml:"require_clean_seamark"`
	MinimumEffect                float64  `yaml:"minimum_effect"`
	MinimumInstanceEffect        float64  `yaml:"minimum_instance_effect"`
	MaximumHarmfulInterference   float64  `yaml:"maximum_harmful_interference"`
	MinimumInstances             int      `yaml:"minimum_instances"`
	MinimumValidPairsPerInstance int      `yaml:"minimum_valid_pairs_per_instance"`
	Instances                    []string `yaml:"instances"`
	ProcessMetrics               []string `yaml:"process_metrics"`
}

WorkflowClaim defines one falsifiable claim about the skills and its evidence floor. The threshold fields mean what they mean in the lessons registry; the assessment reuses the lessons rule by construction.

type WorkflowClaimRegistry added in v0.6.0

type WorkflowClaimRegistry struct {
	SchemaVersion int                `yaml:"schema_version"`
	Claims        []WorkflowClaim    `yaml:"claims"`
	Activation    ActivationCriteria `yaml:"activation"`
}

WorkflowClaimRegistry freezes the workflow claim thresholds and the activation criteria before the cohort runs. It lives in its own file, bench/workflow-claims.yaml, so the lessons registry stays untouched.

func LoadWorkflowClaimRegistry added in v0.6.0

func LoadWorkflowClaimRegistry(path string) (WorkflowClaimRegistry, error)

LoadWorkflowClaimRegistry parses and validates the committed workflow thresholds. Unknown keys and a second document are errors.

func (WorkflowClaimRegistry) Validate added in v0.6.0

func (r WorkflowClaimRegistry) Validate() error

Validate rejects a registry that could silently weaken or ambiguously define the evidence threshold, including one without activation criteria.

type WorkflowCohort added in v0.6.0

type WorkflowCohort struct {
	Instance         string
	Fingerprint      string
	Task             string
	TaskSHA          string
	Trigger          string
	Companion        string
	Fixture          string
	RequestedModel   string
	Model            string
	SeamarkVersion   string
	SeamarkSHA       string
	AgentVersion     string
	Effort           string
	RuntimeID        string
	MaxBudgetUSD     float64
	ValidPairs       int
	FavorablePairs   int
	UnfavorablePairs int
	TiedPairs        int
	HarmfulPairs     int
	Skills           WorkflowArmReport
	Only             WorkflowArmReport
	// TranscriptDirs lists where the cohort's transcripts live, so a reader
	// can find the evidence behind a row.
	TranscriptDirs []string
}

WorkflowCohort is one immutable experiment fingerprint of the workflow benchmark: rows with different harness, fixture, model, or runtime identities are never pooled.

func (WorkflowCohort) Effect added in v0.6.0

func (c WorkflowCohort) Effect() (float64, bool)

Effect returns the MCP + skills minus MCP-only invariant-pass rate, conditional on completing the visible task in each arm.

func (WorkflowCohort) EffectInterval95 added in v0.6.0

func (c WorkflowCohort) EffectInterval95() (low, high float64, ok bool)

EffectInterval95 returns the lessons report's Wilson-based interval for the conditional effect.

type WorkflowConfig added in v0.6.0

type WorkflowConfig struct {
	Trials   int
	Arms     []WorkflowArm    // arms to run; nil means both
	Instance WorkflowInstance // required; there is no default instance
	// AgentArgv is the agent command per arm. The arms differ in the tools
	// they expose, so each arm has its own command line. The runner appends
	// the trial's MCP configuration and then the task prompt.
	AgentArgv     map[WorkflowArm][]string
	SeamarkBin    string        // absolute path to the seamark binary (MCP server + index)
	Timeout       time.Duration // per-trial agent timeout; 0 means 10 minutes
	Out           string        // results JSONL path, appended one row per trial
	WorkDir       string        // parent for trial dirs; "" means a fresh temp dir
	Keep          bool          // keep trial dirs after judging, for inspection
	TranscriptDir string        // saves each trial's raw agent output; empty disables
	// PrepareIndex copies the seamark binary into the trial and indexes the
	// fixture, so the MCP server answers from a ready index. Hermetic tests
	// turn it off and keep an inert fake path.
	PrepareIndex bool
	Version      string // seamark version stamped into rows
	SeamarkSHA   string // exact binary digest stamped into rows
	AgentVersion string // agent CLI version stamped into rows
	Model        string // exact requested primary model; empty for custom agents
	Effort       string // requested effort level
	MaxBudgetUSD float64
	RuntimeID    string // sandbox/toolchain identity
	Fingerprint  string // immutable instance + runtime configuration hash
	// RunID groups rows and makes transcript names unique across concurrent
	// invocations. Empty asks RunWorkflow to generate a random ID.
	RunID string
	// MaxTurns caps activation sessions (RunActivation) with --max-turns.
	// Zero leaves the agent's default. Workflow trials never use it.
	MaxTurns int
	// RequireStructuredResult and RequireExpectedInit are true for the
	// managed Claude adapter. The second is the counterpart of the lessons
	// harness's clean-init rule: here the init record must show exactly the
	// seamark MCP server, the arm's tool set, and, in the skills arm, exactly
	// the three shipped skills.
	RequireStructuredResult bool
	RequireExpectedInit     bool
	Log                     func(string, ...any) // progress lines; nil silences
}

WorkflowConfig configures one workflow run. It carries the operator fields of RunConfig without the lessons hook fields, because no arm installs a lesson or a hook.

type WorkflowInstance added in v0.6.0

type WorkflowInstance struct {
	Instance

	// Trigger is the repository-relative file the visible task changes
	// first. The preflight asks `seamark why <trigger>` to name Companion.
	Trigger string
	// Companion is the repository-relative file the owner invariant
	// requires and the naive solution forgets.
	Companion string
}

WorkflowInstance is a benchmark problem for the skills workflow experiment. It wraps a lessons Instance and names the two files the experiment is about: the trigger file the task changes first, and the companion file the owner invariant lives in. The fixture history must carry the pair as a co-change, so `change_set` on the trigger can name the companion before the agent edits.

func CacheVersionCochangeInstance added in v0.6.0

func CacheVersionCochangeInstance() WorkflowInstance

CacheVersionCochangeInstance is CacheVersionInstance with one difference: its history. The base fixture bumps the cache namespace only in a separate fix commit, so the pair never reaches two shared commits. This variant introduces the cached API in one commit, repeats the backend-only mistake, fixes it by introducing the version namespace with a commit message that says why, then moves the presenter and the cache module together three more times: a plan-tier field with its bump, the revert of that field, and the region field with its bump. The tests for two of those changes are committed on their own, so the cache module is the strongest partner of the presenter among the files the task does not plan. The final tree equals the base fixture's final tree.

func ExportRegistryCochangeInstance added in v0.6.0

func ExportRegistryCochangeInstance() WorkflowInstance

ExportRegistryCochangeInstance is ExportRegistryInstance with one difference: its history. The base fixture registers each new format only in a separate fix commit, so the pair never reaches two shared commits. This variant adds the preview API and the registry in one commit, repeats the preview-only mistake for CSV, fixes it, then moves the preview switch and the registry together three more times: TSV added, TSV dropped, JSON added. The tests for two of those changes are committed on their own, so the registry is the strongest partner of the preview switch among the files the task does not plan. The final tree equals the base fixture's final tree.

func SchemaSyncCochangeInstance added in v0.6.0

func SchemaSyncCochangeInstance() WorkflowInstance

SchemaSyncCochangeInstance is SchemaSyncInstance with one difference: its history. The base fixture never commits server/schema.py together with web/src/api/generated.ts, so co-change mining (two shared commits at least) finds no pair and `change_set` cannot name the companion. This variant grows the API in four commits that update the schema and the generated client together, commits the tests for two of them separately, keeps the backend-only mistake and its fix commit, and ends at exactly the base tree. The generated client is then the strongest partner of the schema among the files the task does not plan: the first cohort showed that a companion listed below the test files, at the mining floor, is read as noise.

func WorkflowInstanceByID added in v0.6.0

func WorkflowInstanceByID(id string) (WorkflowInstance, error)

WorkflowInstanceByID resolves one workflow instance. There is no default: every paid workflow run names its instance explicitly.

func WorkflowInstances added in v0.6.0

func WorkflowInstances() []WorkflowInstance

WorkflowInstances returns the stable catalogue of the skills workflow experiment: co-change variants of the three synthetic lessons fixtures. The pinned OpenTelemetry task is absent on purpose. Its prepared checkout is a single-commit clone with no history, so no co-change pair can exist in it and the preflight's co-change gate refuses it. Catalogue membership is outside every fingerprint, so adding an entry never invalidates an existing cohort.

func (WorkflowInstance) Validate added in v0.6.0

func (w WorkflowInstance) Validate() error

Validate rejects a workflow instance before it can spend an agent call.

type WorkflowProcessCounts added in v0.6.0

type WorkflowProcessCounts struct {
	ChangeSetFirst int // change_set ran before the first edit
	CompanionNamed int // change_set named the companion
	NamedByCheck   int // check named the companion the diff left out
	Opened         int // the agent opened the companion after it was named
	WhyFollowed    int // why followed the named companion
	CheckLast      int // check ran after the last edit
	SeamarkCalls   int
	Activations    map[string]int
}

WorkflowProcessCounts are the per-arm counts the run summary and the report both accumulate over valid paired rows: the process rates the experiment records beside the claim, the Seamark call volume, and the skill activations. One type keeps the two tallies from drifting apart.

type WorkflowReport added in v0.6.0

type WorkflowReport struct {
	ResultSchemaVersion int
	ClaimSchemaVersion  int
	EvidenceFrom        string
	EvidenceTo          string
	Inputs              []ReportInput
	Cohorts             []WorkflowCohort
	Assessments         []WorkflowAssessment
	Activation          *ActivationReport
}

WorkflowReport is a deterministic summary of explicit raw inputs.

func BuildWorkflowReport added in v0.6.0

func BuildWorkflowReport(paths []string, activation ActivationInputs, registry WorkflowClaimRegistry) (WorkflowReport, error)

BuildWorkflowReport strictly reads the workflow result files and, when given, the activation result files against their prompt manifest. Malformed or semantically invalid rows fail the report instead of disappearing.

func (WorkflowReport) Markdown added in v0.6.0

func (r WorkflowReport) Markdown() string

Markdown renders a deterministic, reviewable report. Percentages are point estimates; the paired discordance counts stay visible so tiny samples do not look conclusive.

type WorkflowRow added in v0.6.0

type WorkflowRow struct {
	SchemaVersion int         `json:"schema_version"`
	TS            string      `json:"ts"`
	RunID         string      `json:"run_id"`
	Instance      string      `json:"instance"`
	TaskSHA       string      `json:"task_sha256"`
	Trigger       string      `json:"trigger"`
	Companion     string      `json:"companion"`
	Arm           WorkflowArm `json:"arm"`
	Trial         int         `json:"trial"`
	// Fixture is the generated repo's full HEAD commit, so rows from
	// different fixture versions are never pooled as one series.
	Fixture     string `json:"fixture"`
	Fingerprint string `json:"fingerprint"`

	// Valid says the agent session and the arm's wiring were delivered.
	// PairValid additionally says every arm in this trial number was valid.
	// Only rows satisfying both enter effect tallies.
	Valid                 bool   `json:"valid"`
	PairValid             bool   `json:"pair_valid"`
	InvalidReason         string `json:"invalid_reason,omitempty"`
	InfrastructureFailure bool   `json:"infrastructure_failure,omitempty"`

	// The init record proves what the agent had: the arm's tool set, the
	// seamark MCP server, the skills, and no plugins.
	InitSeen   bool             `json:"init_seen,omitempty"`
	ResultSeen bool             `json:"result_seen,omitempty"`
	Tools      []string         `json:"tools,omitempty"`
	MCPServers []MCPServerState `json:"mcp_servers,omitempty"`
	Skills     []string         `json:"skills,omitempty"`
	Plugins    []string         `json:"plugins,omitempty"`
	// DeniedTools lists the tools the agent asked for and was refused, from
	// the result record. A refused seamark tool or Skill tool means the arm's
	// approvals were not in effect, so the row is invalid.
	DeniedTools []string `json:"denied_tools,omitempty"`

	WorkflowTrace

	TaskDone bool   `json:"task_pass"`
	Avoided  bool   `json:"invariant_pass"`
	Notes    string `json:"notes,omitempty"`
	// Checks are public repository-local validation commands. The hidden
	// task and invariant judges are TaskDone and Avoided above.
	ChecksPass bool          `json:"checks_pass"`
	Checks     []CheckResult `json:"checks,omitempty"`

	AgentUsage

	SeamarkVersion string  `json:"seamark_version,omitempty"`
	SeamarkSHA     string  `json:"seamark_sha256,omitempty"`
	AgentVersion   string  `json:"agent_version,omitempty"`
	Effort         string  `json:"effort,omitempty"`
	MaxBudgetUSD   float64 `json:"max_budget_usd,omitempty"`
	RuntimeID      string  `json:"runtime_id,omitempty"`

	// Transcript, stderr, and patch keep the audit record with digests, so a
	// verdict stays checkable after the trial dir is deleted.
	Transcript    string `json:"transcript,omitempty"`
	TranscriptSHA string `json:"transcript_sha256,omitempty"`
	StderrLog     string `json:"stderr,omitempty"`
	StderrSHA     string `json:"stderr_sha256,omitempty"`
	Patch         string `json:"patch,omitempty"`
	PatchSHA      string `json:"patch_sha256,omitempty"`
}

WorkflowRow is one workflow trial as appended to the JSONL file. Rows are self-contained: identity, validity, the init facts, the tool trace, the verdicts, and the cost travel together.

func ReadWorkflowRows added in v0.6.0

func ReadWorkflowRows(path string) ([]WorkflowRow, error)

ReadWorkflowRows reads a workflow results file back, skipping unparseable lines. A missing file is an empty history, not an error.

func ReadWorkflowRowsStrict added in v0.6.0

func ReadWorkflowRowsStrict(path string) ([]WorkflowRow, string, error)

ReadWorkflowRowsStrict reads one workflow results file the way the report does: every non-empty line must be exactly one valid row. It returns the rows and the file's SHA-256.

type WorkflowSummary added in v0.6.0

type WorkflowSummary struct {
	Rows          []WorkflowRow
	ByArm         map[WorkflowArm]WorkflowTally
	Instance      string
	StoppedReason string
}

WorkflowSummary is the whole run's outcome, per arm.

func RunWorkflow added in v0.6.0

func RunWorkflow(ctx context.Context, cfg WorkflowConfig) (WorkflowSummary, error)

RunWorkflow executes the experiment: Trials fresh fixture repos per arm, alternating arms so slow model drift within the run spreads evenly, each judged mechanically. A pair is finalized and appended before the next pair starts; graceful cancellation also flushes a completed arm from a partially executed pair. The pairing, cancellation, and infrastructure-stop rules are the lessons harness's rules, applied to the workflow rows.

func (WorkflowSummary) Lines added in v0.6.0

func (s WorkflowSummary) Lines() []string

Lines renders the summary as raw counts per arm: outcomes, the process rates the experiment is about, activations, and cost.

type WorkflowTally added in v0.6.0

type WorkflowTally struct {
	Ran       int
	Invalid   int
	Completed int // trials where the task was done at all
	Avoided   int // completed trials where the owner invariant passed
	WorkflowProcessCounts
	MeanInput int64
	CostUSD   float64
}

WorkflowTally is one arm's aggregate over valid paired rows.

type WorkflowTrace added in v0.6.0

type WorkflowTrace struct {
	// ChangeSetBeforeFirstEdit is true when a change_set call preceded the
	// first Edit or Write, or when the agent never edited at all.
	ChangeSetBeforeFirstEdit bool `json:"change_set_before_first_edit"`
	// ChangeSetFiles lists the files of the first change_set call.
	ChangeSetFiles []string `json:"change_set_files,omitempty"`
	// CompanionNamedByChangeSet is true when a change_set result named the
	// companion file that the agent had not put in the call itself.
	CompanionNamedByChangeSet bool `json:"companion_named_by_change_set"`
	// CompanionNamedByCheck is true when a check result listed the companion
	// under "history suggests also reviewing": the diff left it out and
	// history named it. The unindexed-files note also quotes paths, so only
	// that section counts.
	CompanionNamedByCheck bool `json:"companion_named_by_check"`
	// WhyFollowedCompanion is true when a why call whose query is the
	// companion path followed the change_set or check that named it. A
	// query by symbol or by bare file name does not count; the rule is the
	// same in both arms.
	WhyFollowedCompanion bool `json:"why_followed_companion"`
	// CompanionOpenedAfterNamed is true when a Read, Edit, Write, or
	// MultiEdit on the companion followed the call that named it. The first
	// cohort showed this is the step that decides the outcome: a named
	// companion the agent never opened was never acted on.
	CompanionOpenedAfterNamed bool `json:"companion_opened_after_named"`
	// CheckAfterLastEdit is true when a check call followed the last edit.
	CheckAfterLastEdit bool `json:"check_after_last_edit"`
	// CheckVerdict is the verdict line of the last check result, for
	// example "allow (mode: warn)"; empty when the call failed.
	CheckVerdict string `json:"check_verdict,omitempty"`
	// Activations lists the skills the agent loaded, in first-use order.
	Activations []string `json:"activations,omitempty"`
	// SeamarkCalls counts every seamark MCP tool call; SeamarkToolCalls
	// splits the count by tool name.
	SeamarkCalls     int            `json:"seamark_calls"`
	SeamarkToolCalls map[string]int `json:"seamark_tool_calls,omitempty"`
	// Edits counts Edit, Write, and MultiEdit calls. Edits made through
	// Bash are invisible here; the patch stays the record of what changed.
	Edits int `json:"edits"`
	// FirstEditSeq is the position of the first edit among all tool calls,
	// counted from 1; zero when there was no edit.
	FirstEditSeq int `json:"first_edit_seq,omitempty"`
}

WorkflowTrace is what the transcript proves about the agent's process: whether it asked Seamark before editing, whether Seamark named the companion file, whether the agent followed that lead, whether it checked the finished diff, and which skills activated. Every field is read from the agent's own tool calls and their results, never from its prose.

Jump to

Keyboard shortcuts

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