factorycorpus

package
v0.1.0 Latest Latest
Warning

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

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

Documentation

Overview

Package factorycorpus is the home of the RFC-201 §5 generation factory's COMMITTED output: machine-generated, oracle-blessed yamsql scenarios that live in the repository as permanent suite content.

The distinction from every other generative harness here is that nothing in this package generates anything. rowdiff, the fuzz targets and the chaos suite all re-derive their cases on every run; if their generator breaks, the coverage silently evaporates. A file under testdata/ is a frozen expectation: it keeps testing the engine even if the generator, the oracle infrastructure and the Java server are all broken or gone, it bisects with git, and it converts oracle agreement — a moment-in-time fact — into a regression pin, a permanent one.

The committed format is GENUINE `.yamsql` (RFC-201 §5.7, owner ruling 2026-08-01): one file per feature family (FamilyOf), each holding that family's scenarios as (schema_template, setup, test_block) document triples in the Java yaml-tests dialect — the same convention the vendored corpus uses (cte.yamsql holds the CTE tests). Provenance lives in comments, the one extension yamsql tolerates freely, so Java's own yaml-tests runner can execute a committed file verbatim; that is what makes cross-engine blessing literal rather than aspirational.

The package therefore holds six things and no more:

  • the FAMILY mapping (family.go): feature vector → family key → file name, the grouping convention the loader cross-checks per scenario;
  • the WRITER (writer.go), which emits a family file in a canonical form that survives a Load/MarshalFamily round trip byte for byte, so a re-bless produces a reviewable diff instead of reformatting noise;
  • the HEADER (header.go), the §5.1 provenance contract every committed scenario carries — generator version, seed, blessing oracle, feature vector, plan shape, date — parseable without executing anything;
  • the LOADER (load.go), which owns provenance and the provenance↔document cross-checks over its OWN flat testdata/ directory, and delegates the yamsql structure to javayamsql.Parse — the strict parser gating the vendored Java corpus — so the factory corpus cannot drift from the shared format without the build going red. Execution (run.go) delegates to javacorpus.RunParsed for the same reason: one runner, not a fork;
  • the CENSUS and RATCHET (census.go), the governance instrument of RFC-201 §8: scenario count, test count, per-feature-vector counts and the per-dedup-key blessing, computed from the files and gated so they can only go up; and
  • the RETIREMENT LEDGER (retirement.go and retirements/), the sole explicit exception for a planner change that makes an old physical plan point cease to exist. It binds the reason, date, RFC, exact base Git commit, logical census, and full filename-plus-content tree before and after. CI proves that commit is on the trusted target history and materializes it to authenticate the old hashes; it authenticates the new hashes at the ledger's unique first-add commit and, while newly proposed, against raw proposed HEAD too. The checkout must exactly match those raw corpus and ledger blobs, so Git filters cannot rewrite evidence. The new ledger's BEFORE must equal the trusted target corpus, and every trusted scenario remains byte-identical unless that ledger authorizes the full transition; pure additions need no exception. Later corpus growth therefore does not weaken or invalidate older ledgers, and neither a synthetic/invented old side, nested corpus file, balanced delete+add, nor unrelated edit can hitchhike on a reviewed decrease.

The producer lives in the sibling `factory` package and in `cmd/factory-run`; the split is what lets the corpus run with no dependency on the generator that wrote it.

Index

Constants

View Source
const (
	DispositionRetired  = "retired"
	DispositionReplaced = "replaced"
	DispositionAdded    = "added"
)
View Source
const CensusBaselinePath = "census_baseline.json"

CensusBaselinePath is the committed baseline, relative to this package.

View Source
const FileExt = ".yamsql"

FileExt is the extension of a committed corpus family file. The corpus is genuine yamsql grouped one file per feature family (RFC-201 §5.7).

View Source
const FormatVersion = 2

FormatVersion is the provenance contract's own version. It changes when the set of REQUIRED provenance keys or the file layout changes, so an old committed file fails to load loudly instead of being read with a key silently missing. Version 2 is the yamsql convergence: one `.yamsql` file per feature family, each scenario a (schema_template, setup, test_block) document triple in the Java yaml-tests dialect, provenance in comments.

View Source
const ScenarioTimeout = 2 * time.Minute

ScenarioTimeout bounds one scenario. A committed scenario runs four queries over at most a couple of dozen rows; anything approaching this bound is a hang, not slow work, and failing at the bound keeps a hung scenario from consuming the whole target's budget and reporting as a timeout with no name attached.

View Source
const SummaryLimit = 10

SummaryLimit is how many failing scenarios a summary names in full. A corpus break is usually systemic — one engine change reddens hundreds of scenarios at once — so naming every one of them would reproduce the very unbounded output the summary exists to avoid. The first few names plus an exact count is what a triager actually acts on.

View Source
const TestdataDir = "testdata"

TestdataDir is the corpus directory relative to this package.

Variables

This section is empty.

Functions

func BlessingRank

func BlessingRank(b Blessing) int

BlessingRank orders authorities from weakest to strongest, and is what makes "promotion" a decidable question rather than a matter of opinion.

The per-scenario ratchet compares a scenario against ITSELF across batches on this scale, keyed by dedup key: rising is promotion and silent, falling is a downgrade and red. An aggregate COUNT per label cannot express that — promoting a scenario decrements the count of the label it left, so a count floor on `metamorphic` fires on exactly the improvement it should welcome.

func CensusSHA256

func CensusSHA256(c Census) (string, error)

CensusSHA256 fingerprints the canonical census bytes used by the committed baseline. A ledger therefore authorizes exactly one measured transition, not any future shrink that happens to reuse its path.

func CheckFamilyPlacement

func CheckFamilyPlacement(path string, featureVector string) error

CheckFamilyPlacement verifies that a scenario's feature vector places it in the family file it was found in.

func CheckRatchet

func CheckRatchet(baseline, current Census) []string

CheckRatchet compares a measured census against the committed baseline and returns one message per SHRINK, empty when the corpus only grew.

The rule is componentwise, not aggregate: totals rising while a dimension empties out is exactly the failure mode a single count cannot see, and it is the realistic one — a regenerated batch that drops a query family still grows the total. A feature vector present in the baseline and absent now is a shrink to zero and is named as such; a NEW feature vector is growth and is silent.

Blessing is ratcheted the same way and for the same reason: re-running a batch without the Java server would otherwise re-bless cross-engine files as metamorphic, keeping every count intact while quietly deleting the second engine from the corpus's authority.

func CheckResult

func CheckResult(s *Scenario, res javacorpus.FileResult) error

CheckResult folds a scenario's ledger entry into pass/fail: every committed test must have RUN and ASSERTED. A skip class that suppressed an assertion, or a query count below the committed stanza count, is a failure — zero failures out of zero executed tests is the loudest possible instrument failure wearing the quietest possible output.

func CorpusTreeSHA256

func CorpusTreeSHA256(corpusDir string) (string, error)

CorpusTreeSHA256 fingerprints every flat YAML file in corpusDir, including its basename and exact bytes. CensusSHA256 deliberately measures logical coverage; the tree fingerprint independently prevents an unlisted setup, query, row, or expectation edit from hitchhiking on a retirement.

func DedupKeyOf

func DedupKeyOf(featureVector string, planShape string) string

DedupKeyOf is the corpus's primary key: a digest over the feature vector and the plan shape. Neither half is sufficient alone — the feature vector says what the query ASKED (two different plans for the same shape are two different tests) and the plan shape says what the planner DID (explaindiff's ShapeOf is type-only, so a scan filtered on `a` and one filtered on `b` collapse to the same shape). A candidate is committed only if this key is new.

func Describe

func Describe(s *Scenario, res javacorpus.FileResult) string

Describe renders a scenario's result for a test log: where it lives, its provenance, and what happened.

func FailureSummary

func FailureSummary(failures []ScenarioFailure, total, limit int) string

FailureSummary renders a bounded report of a corpus run's failures: how many of how many, then up to limit named scenarios with their reproduce command.

The result is bounded by limit regardless of how many scenarios failed or how large their diffs are, and it is deterministic: failures are ranked by class and then by name, so the same break names the same scenarios on every run and across runners. Changed answers come first — see the ordering note below for why a name-only order hides them. A limit <= 0 means SummaryLimit.

func FamilyFileName

func FamilyFileName(family string) string

FamilyFileName renders a family key as its committed file name.

The mapping must be INJECTIVE over the family keys the generator can produce, or two families would silently merge into one file; the loader re-derives every scenario's family and cross-checks it against the file it sits in, which is what makes a collision loud rather than latent.

func FamilyOf

func FamilyOf(featureVector string) string

FamilyOf maps a feature vector onto its feature FAMILY — the logical group whose scenarios share one committed `.yamsql` file, mirroring the upstream corpus's convention of one file per feature area (cte.yamsql holds the CTE tests, in-operator-queries.yamsql the IN tests).

The family key is `shape|predicate-class|subquery-class`:

  • the query shape (`single`, `join2.inner`, `join3.comma`, …),
  • the WHERE tree's top connective with the SORTED SET of its child leaf classes (`and(cmp+colcol)`), or the bare leaf class (`cmp`, `in`) when the predicate is a single leaf,
  • the correlated sub-construct (`exists`, `scalarsub`, both, or none).

These are the same axes the per-PR stratifier spreads its budget over (StratumKey), with the connective refined by its child classes. The refinement is what keeps the files readable: the plain top-connective key collapses a quarter of the corpus into one `and` bucket (238 scenarios / ~950 test stanzas in one file, measured on the 2026-08-01 corpus), while the refined key's largest family holds 123 scenarios. The FULL feature vector is deliberately not the key — it carries the index set, projection width and ordering, so it is nearly unique per scenario and would recreate the one-file-per-scenario layout this grouping replaces.

func IsPortableCorpusFilename

func IsPortableCorpusFilename(name string) bool

IsPortableCorpusFilename reports whether name is one lowercase-ASCII flat YAML basename on both POSIX and Windows. The restricted alphabet prevents forbidden characters, Unicode normalization ambiguity, and case-folding collisions; Windows device names remain forbidden separately.

func MarshalFamily

func MarshalFamily(entries []*Scenario) ([]byte, error)

MarshalFamily renders one family's scenarios as the bytes of its committed `.yamsql` file.

The emitted file is genuine yamsql — parseable by the javayamsql parser and within the subset Java's own yaml-tests runner accepts, which is what makes cross-engine blessing literal: Java can execute the exact committed file. Provenance lives in the comment header (the one extension yamsql tolerates freely); each scenario is a (schema_template, setup, test_block) document triple whose `connect:` index names its own schema registration, so the whole file executes as one Java run and any single scenario executes alone after the loader rebases its connect index.

The contract is BYTE-EXACT ROUND TRIPPING:

MarshalFamily(Load(MarshalFamily(entries))) == MarshalFamily(entries)

Without it a re-bless (§5.3) produces a diff full of reformatting noise and the reader cannot see which expectation actually moved — which is the only thing a re-bless review is for. Scenario order inside the file is therefore derived, not positional: entries are sorted by (seed, query index, projection), so a nightly append lands in a deterministic place and re-emitting the whole family reproduces the file byte for byte.

func RenderCensus

func RenderCensus(c Census) ([]byte, error)

RenderCensus serializes a baseline with sorted keys and a trailing newline, so a batch that adds nothing produces no diff.

func RunScenario

func RunScenario(ctx context.Context, clusterFile string, s *Scenario) javacorpus.FileResult

RunScenario executes one committed scenario against the cluster and returns the javayamsql runner's ledger entry.

Execution is NOT re-implemented: the scenario's document triple goes through javacorpus.RunParsed, so a committed factory scenario is executed by exactly the machinery that executes the vendored Java corpus — same schema_template lifecycle, same option layering, same result matching. That is what makes the shared format worth having. Only the LOADING is this package's own, because provenance is a factory concept the vendored corpus does not carry.

The IDPrefix is derived from the scenario name, which is unique by construction (seed, query index, projection), so parallel execution cannot collide on a database path or a template name.

func ShapeDigest

func ShapeDigest(shape []string) string

ShapeDigest folds a plan shape rendering (explaindiff.ShapeOf output) into the fixed-width form the header carries. The full rendering is many lines and would dominate the header; the digest is stable because the rendering is (it holds Go type names and tree positions, nothing versioned).

func SubtestFramingBytes

func SubtestFramingBytes(fullName string) int

SubtestFramingBytes is what the Go test runner spends on framing lines alone for a parallel subtest of the given full name — RUN, PAUSE, CONT and the result line. It is the floor of the corpus target's output: it is paid on a fully passing run, before a single byte of failure detail.

=== RUN   <name>\n            10 + len + 1
=== PAUSE <name>\n            10 + len + 1
=== CONT  <name>\n            10 + len + 1
    --- PASS: <name> (0.00s)  4 + 10 + len + 9

func ValidateRetirementLedgerAfter

func ValidateRetirementLedgerAfter(ledger RetirementLedger, after Census, corpusDir string) error

ValidateRetirementLedgerAfter checks the committed half of a transaction. It is used by CI after the old files no longer exist in the checkout.

func ValidateRetirementLedgerBefore

func ValidateRetirementLedgerBefore(
	ledger RetirementLedger,
	before Census,
	corpusDir string,
) error

ValidateRetirementLedgerBefore checks the historical half of a retirement against corpus files materialized from ledger.BaseCommit. The CI history command supplies this directory from raw `git ls-tree`/`git cat-file` blobs, then validates the AFTER side at the unique commit that first added the ledger (and against raw proposed HEAD while that ledger is new to the trusted branch). Both endpoints are therefore anchored to repository history without checkout or archive attributes rewriting evidence, and without making an old ledger compare against a later, legitimately grown corpus.

func ValidateRetirementTransition

func ValidateRetirementTransition(ledger RetirementLedger, before, after Census, corpusDir string) error

ValidateRetirementTransition authorizes one non-additive corpus transition only when both census endpoints and every resulting file match the reviewed ledger. The census can remain flat for a content replacement.

Types

type Blessing

type Blessing string

Blessing names the oracle authority that froze a scenario's expectations. RFC-201 §5.3: a committed expectation is frozen, and WHICH oracle froze it determines how much it is worth — so it is recorded in the file rather than inferred from the run that produced it.

const (
	// BlessingCrossEngine means the Java engine returned the same rows: the
	// strongest authority available, because the expectation is then
	// independent of every Go-side belief.
	BlessingCrossEngine Blessing = "cross-engine"
	// BlessingMetamorphic means no second engine saw the query and the
	// expectation rests on the metamorphic oracles alone (§5.5) — the TLP
	// partition plus second-plan agreement. Honest, weaker, and UPGRADEABLE:
	// re-running the batch against a reachable Java server promotes the
	// scenario without regenerating it.
	BlessingMetamorphic Blessing = "metamorphic"
	// BlessingMetamorphicTLPOnly means the TLP partition agreed and the
	// second-plan oracle was STRUCTURALLY INAPPLICABLE to the shape — not
	// skipped by accident, but unable to apply for a reason a committed pin
	// establishes.
	//
	// It exists so that "every applicable oracle agreed" can be said honestly
	// without saying "both oracles agreed". Correlated EXISTS is the first
	// instance: the perturbed plan comes out byte-identical because the outer
	// leg is a filtered scan either way, so there is no second plan to compare
	// and never will be under that perturbation. Blessing such a scenario plain
	// `metamorphic` would claim evidence that does not exist; refusing to bless
	// it at all cost the corpus an entire query family (zero of the first 900
	// scenarios carried an EXISTS, while the generator emits them at ~1/4).
	//
	// It is DELIBERATELY a distinct census dimension. Authority is measured, and
	// a label that quietly absorbed a weaker case would make the measurement lie.
	BlessingMetamorphicTLPOnly Blessing = "metamorphic-tlp-only"
)

type Census

type Census struct {
	// Scenarios is the number of committed scenarios (test_block triples)
	// across all family files.
	Scenarios int `json:"scenarios"`
	// Tests is the number of committed test stanzas across all files.
	Tests int `json:"tests"`
	// ByFeature counts SCENARIOS per feature vector. This is the dimension
	// audit: a shrink here names exactly which query shape stopped being
	// covered, which a total count cannot.
	ByFeature map[string]int `json:"by_feature"`
	// ByBlessing counts scenarios per blessing authority. It is REPORTED, so a
	// batch's authority mix is visible at a glance, but it is deliberately NOT
	// ratcheted: see ByKeyBlessing.
	ByBlessing map[string]int `json:"by_blessing"`
	// ByKeyBlessing maps each scenario's dedup key to its blessing, and it is
	// what the authority ratchet actually gates on.
	//
	// A count floor per label points the WRONG WAY. Promoting a file from
	// metamorphic to cross-engine — the exact improvement the corpus wants, and
	// the one the metamorphic label's own doc promises — decrements
	// `metamorphic`, so a floor on that count fires on the improvement while
	// staying silent on the downgrade that replaces a cross-engine file with a
	// brand-new metamorphic one at a different key. Keying by dedup key
	// compares a scenario against ITSELF across batches, which is the only
	// comparison that can tell promotion from regression.
	ByKeyBlessing map[string]string `json:"by_key_blessing"`
}

Census is the measured state of the committed corpus: RFC-201 §8's governance instrument. Raw test count is deliberately NOT the headline — a corpus of 100k tests on one axis and zero on another is the failure this design exists to kill — so the per-feature-vector map is a first-class field and the ratchet gates it dimension by dimension.

func ComputeCensus

func ComputeCensus(scenarios []*Scenario) Census

ComputeCensus measures the corpus from the FILES, never from a manifest the factory also wrote. A census derived from the producer's own bookkeeping agrees with the producer by construction and would stay green through a batch that wrote nothing to disk.

func LoadCensus

func LoadCensus(path string) (Census, error)

LoadCensus reads a committed census baseline.

type FamilyFile

type FamilyFile struct {
	Path string
	// Family is the file-level family key; every scenario's feature vector
	// maps onto it.
	Family    string
	Scenarios []*Scenario
}

FamilyFile is one committed `.yamsql` family file.

func Load

func Load(path string) (*FamilyFile, error)

Load reads one committed family file.

Parsing is NOT re-implemented: the yamsql structure goes through javayamsql.Parse, the same strict parser that gates the vendored Java corpus, so the factory corpus inherits every block/config/tag check that parser grew. What this loader adds is the provenance contract and the cross-checks binding provenance to documents — a header describing a different scenario than the one under it is worse than no header, because the census would report it with total confidence.

func LoadBytes

func LoadBytes(path string, data []byte) (*FamilyFile, error)

LoadBytes is Load over bytes already in hand. path is used only for the family/file-name cross-check and for error context; nothing is read from disk.

It exists so a re-emitted family can be parsed back WITHOUT being written first: cmd/factory-rebless verifies that marshalling preserved every frozen row before it commits any bytes to the tree, and a check that has to write the file in order to verify it is not a check, it is a rollback.

type Header struct {
	// Name is the scenario name; it must equal the scenario's test_block name,
	// so a provenance block cannot drift onto someone else's documents without
	// the mismatch being visible.
	Name string
	// Generator identifies the case generator and its version, e.g.
	// "rowdiff-gen/1". Together with Seed it is the whole reproduction recipe.
	Generator string
	// Seed is the generator seed. Same seed, same generator version, same
	// case — pinned by TestFactoryDeterminism.
	Seed uint64
	// QueryIndex is the index of the query within the seed's case, and
	// Projection the index of the projection variant. Seed alone does not
	// identify a candidate: one case yields several queries and each query
	// several projections.
	QueryIndex int
	Projection int
	// Date is the batch date, YYYY-MM-DD. It is an INPUT to generation, never
	// read from the clock: §5.4 forbids wall-clock in the generation path, so
	// regenerating a committed scenario byte-identically means passing back the
	// date it already carries.
	Date string
	// Blessing is the authority that froze the expectations.
	Blessing Blessing
	// Oracles lists the oracles that actually RAN and agreed, in a stable
	// order. An oracle that was skipped (its precondition unmet) must not
	// appear — the whole point of the list is that it cannot claim coverage
	// the run did not exercise.
	Oracles []string
	// FeatureVector is the serialized spec-struct feature vector: the
	// structural description of the query, literals erased. It is one half of
	// the dedup key, the axis the census reports per-dimension counts on, and
	// what places the scenario in its family file (FamilyOf).
	FeatureVector string
	// PlanShape is a hex digest of explaindiff.ShapeOf over the physical plan.
	// It is the other half of the dedup key: the feature vector says what was
	// ASKED, the plan shape says what the planner DID, and two candidates
	// agreeing on both add nothing to each other.
	PlanShape string
	// DedupKey is the digest of (FeatureVector, PlanShape) — the corpus's
	// primary key, and the key the blessing ratchet compares a scenario
	// against itself on. Stored rather than recomputed so the loader can
	// detect a collision without a planner.
	DedupKey string
}

Header is the RFC-201 §5.1 provenance block of ONE committed scenario: the `#` comment lines immediately above the scenario's document triple inside its family file. It is deliberately a flat key/value comment block rather than YAML content — the yamsql parser must see exactly the Java yaml-tests schema and nothing else (a provenance key inside a document would be an unknown directive), while the census must be able to read provenance from thousands of scenarios without executing them. Comments are the one extension the format tolerates freely, so a file this package writes is parseable by Java's own yaml-tests runner verbatim.

func ParseHeader

func ParseHeader(lines []string) (Header, error)

ParseHeader reads one scenario's provenance block from its comment lines. Every key in the contract is REQUIRED: a missing one is an error, never a zero value. A header whose fields default silently is a header that stops describing the scenario the moment the contract grows, and the census would keep reporting a confident number computed from absent data.

func (Header) Render

func (h Header) Render() string

Render returns the scenario's provenance comment block, newline-terminated, ready to sit immediately above the scenario's `---` document separator.

type IncompleteError

type IncompleteError struct {
	// Reason names the wall-clock budget that ended the scenario.
	Reason string
	// Detail is the scenario's full description, as every other corpus failure
	// carries it.
	Detail string
}

IncompleteError is a scenario that never produced an answer because it ran out of wall-clock, as opposed to one whose answer changed.

It is a TYPE rather than a formatted string because the distinction has a second consumer: FailureSummary has to rank a genuine disagreement above a timing artifact, and a summary that re-derives the class by matching on its own prose would break the moment the sentence is reworded.

func (*IncompleteError) Error

func (e *IncompleteError) Error() string

type RetirementChange

type RetirementChange struct {
	Name        string `json:"name"`
	Disposition string `json:"disposition"`
	OldSHA256   string `json:"old_sha256,omitempty"`
	NewSHA256   string `json:"new_sha256,omitempty"`
}

RetirementChange identifies one exact corpus file before and after the transaction. OldSHA256 is absent only for an addition; NewSHA256 is absent only for a retirement.

type RetirementLedger

type RetirementLedger struct {
	FormatVersion      int                `json:"format_version"`
	RFC                string             `json:"rfc"`
	Date               string             `json:"date"`
	Reason             string             `json:"reason"`
	BaseCommit         string             `json:"base_commit"`
	BeforeCensusSHA256 string             `json:"before_census_sha256"`
	AfterCensusSHA256  string             `json:"after_census_sha256"`
	BeforeTreeSHA256   string             `json:"before_tree_sha256"`
	AfterTreeSHA256    string             `json:"after_tree_sha256"`
	Changes            []RetirementChange `json:"changes"`
}

RetirementLedger is the explicit exception to the corpus growth ratchet. A behavior-changing planner patch can make an old physical plan point cease to exist; silently lowering the census would hide that loss, while retaining a stale reproduction recipe would lie. The ledger binds one reviewed reason to the exact before/after census and every file transition.

func LoadRetirementLedger

func LoadRetirementLedger(path string) (RetirementLedger, error)

LoadRetirementLedger reads and validates the ledger's static structure.

type Scenario

type Scenario struct {
	// Path is the family file the scenario was loaded from.
	Path string
	// Header is the scenario's provenance block.
	Header Header
	// Doc is the logical scenario reconstructed from the yamsql blocks: the
	// internal carrier the writer marshals and the determinism gate compares
	// against regenerated candidates. Row cells are Go values (int64, float64,
	// float32, string, bool, nil) decoded from the typed yamsql cells.
	Doc *yamsql.Scenario
	// Blocks is the scenario's parsed (schema_template, setup, test_block)
	// triple with its `connect:` indices REBASED to 1, so the scenario executes
	// alone through the javayamsql runner exactly as it would inside the whole
	// family file.
	Blocks []*javayamsql.Block
}

Scenario is one committed factory scenario: its provenance header, the reconstructed logical scenario (schema, setup, tests with frozen rows), and the parsed yamsql document triple it executes as.

func LoadDir

func LoadDir(dir string) ([]*Scenario, error)

LoadDir reads every committed family file in dir and returns the flattened, dedup-checked scenario list, sorted by (file, position).

An empty directory is an ERROR, not an empty result: every caller here is a gate, and a gate over zero files is green forever.

func (*Scenario) SubFile

func (s *Scenario) SubFile() *javayamsql.File

SubFile returns the scenario as a standalone parsed yamsql file, the unit the runner executes. The path names the family file and the scenario so a failure locates both.

type ScenarioFailure

type ScenarioFailure struct {
	// Name is the scenario's header name, e.g. "fc_0000000112_q0_p0".
	Name string
	// Path is the family file it was loaded from.
	Path string
	// Seed and Date are the generator inputs — together the reproduce recipe.
	Seed uint64
	Date string
	// Err is why it failed. Only its first line survives into the summary.
	Err error
}

ScenarioFailure is one failing scenario, reduced to what identifies it and what reproduces it. It deliberately does NOT carry the full result diff: the diff is already in the log at the point of failure, and a summary that repeats it is a summary that can itself blow the budget.

Jump to

Keyboard shortcuts

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