checkout

package
v0.4.0 Latest Latest
Warning

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

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

Documentation

Overview

Package checkout is the synthetic reference system: a three-stage payment lifecycle (auth, capture, settle) with seeded traffic on an hour-of-week curve, fault-injection knobs for the degradation loci, and an in-memory ledger that serves as ground truth for the engine.

Capture and settle are capacity-limited FIFO stages (per-minute worker capacity, fixed service delay); a queue-consumer-stall fault sets capacity to zero for its window, so a real backlog forms and drains at the stage's capacity afterwards. The api faults reject (5xx) or lose (latency abandonment) arrivals; an upstream blackout suppresses arrivals entirely, with an optional recovered fraction re-arriving after the outage. The ledger is omniscient: it records abandoned transactions and suppressed demand that real telemetry could never see — the asymmetry the engine's evidence labels are about.

The simulation is discrete-event on a virtual clock (minute resolution, single-threaded): identical Config yields a byte-identical ledger on the same toolchain and architecture. Arrival sampling consumes math.Exp, which Go does not promise bit-identical across platforms, so golden expected values must be generated by CI (ubuntu/amd64), never on a laptop. All fixtures produced here are synthetic by construction — never derived from real data.

Index

Constants

View Source
const (
	NoEnterprise = -1.0 // EnterpriseFraction: all-SMB traffic
	InstantStage = -1   // CaptureDelayMin / SettleDelayMin: zero delay
)

Explicit-zero sentinels. The zero value of each tuning knob means "use the default", so a scenario that wants a literal zero spells it with these. Any other negative value is a configuration error and Run panics.

Variables

This section is empty.

Functions

func DefaultCurve

func DefaultCurve() [168]float64

DefaultCurve is a realistic hour-of-week arrival-rate curve (mean arrivals per minute), Monday 00:00 UTC = index 0. Shape: weekday business-hours peak (~6/min), evening shoulder, deep night trough (~0.4/min), weekends at roughly 60% of weekday volume. The absolute numbers only need to be plausible — the engine is judged against the ledger this curve generates, not against the real world.

Types

type Config

type Config struct {
	Seed  uint64
	Start time.Time // aligned down to the minute
	End   time.Time

	// Curve is the hour-of-week arrival-rate curve (mean arrivals per
	// minute for each of the 168 hours, Monday 00:00 = index 0). Nil means
	// DefaultCurve.
	Curve *[168]float64

	// EnterpriseFraction is the probability a customer is enterprise
	// (default 0.1).
	EnterpriseFraction float64

	// Customers is the size of the synthetic customer pool (default 3000).
	Customers int

	// Stage service delays (defaults: capture 2 min, settle 5 min).
	CaptureDelayMin int
	SettleDelayMin  int

	// Stage worker capacities in transactions per minute (default 20 —
	// comfortably above the default curve's 6/min peak, so the baseline
	// has no contention). A consumer-stall fault forces 0 for its window.
	// There is no literal-zero form: a consumer that is down is a
	// queue-consumer-stall fault over the window, never a capacity of 0
	// (which would make the FIFO cursor spin forever).
	CaptureCapacityPerMin int
	SettleCapacityPerMin  int

	// Faults active during the run. Each is validated; see FaultSpec.
	Faults []FaultSpec
}

Config drives one simulation run. The zero values of the tuning knobs are replaced by defaults in Run (see the sentinels above for literal zeros).

type FaultKind

type FaultKind string

FaultKind names the four degradation loci: API-level failures, API-level latency (abandonment), queue consumer stalls, and upstream blackouts (traffic never enters).

const (
	FaultAPI5xx        FaultKind = "api-5xx"
	FaultAPILatency    FaultKind = "api-latency"
	FaultConsumerStall FaultKind = "queue-consumer-stall"
	FaultBlackout      FaultKind = "upstream-blackout"
)

type FaultSpec

type FaultSpec struct {
	Kind FaultKind `yaml:"kind"`
	From time.Time `yaml:"from"`
	To   time.Time `yaml:"to"`

	// Rate: api-5xx failure probability, or api-latency abandonment
	// probability, in (0, 1]. Semantics when faults overlap: each active
	// fault rolls independently per transaction, so two 0.5 faults
	// compound to ~0.75 — overlapping specs model overlapping causes.
	// Abandonment short-circuits the 5xx roll (an abandoned request never
	// reached the api), which makes rng consumption outcome-dependent;
	// deterministic under a seed either way.
	Rate float64 `yaml:"rate,omitempty"`

	// Queue: which stage a queue-consumer-stall halts.
	Queue Queue `yaml:"queue,omitempty"`

	// Blackout recovery: the fraction of suppressed demand that returns
	// after the outage, spread uniformly over the RecoveryWithin window.
	// Zero fraction means the demand is simply gone.
	RecoveredFraction float64       `yaml:"recovered_fraction,omitempty"`
	RecoveryWithin    time.Duration `yaml:"recovery_within,omitempty"`
}

FaultSpec is one active degradation over [From, To) — the declarative form used both in Go and as a row in the scenario YAML. Fields beyond the window apply per kind and are validated by Validate.

func (FaultSpec) Validate

func (f FaultSpec) Validate() error

Validate rejects malformed fault specs loudly — a broken scenario must never produce plausible-looking ground truth.

type GoldenWindow

type GoldenWindow struct {
	From       time.Time
	To         time.Time
	CaptureSLA time.Duration
}

GoldenWindow declares the incident window a scenario's golden expected values are computed over, and the capture SLA used for breach counting. Explicit in the file — deriving it from fault windows would let a scenario edit silently move the goalposts.

type Ledger

type Ledger struct {
	Txns []Txn
}

Ledger is the ground truth: every synthetic transaction ever created, in creation order — including abandoned ones telemetry never saw.

type Queue

type Queue string

Queue names a stalled stage.

const (
	QueueCapture Queue = "capture"
	QueueSettle  Queue = "settle"
)

type Result

type Result struct {
	Ledger     Ledger
	Suppressed []SuppressedMinute
	Config     Config
}

Result of a run: the ground-truth ledger, suppressed-demand record, and the effective config.

func Run

func Run(cfg Config) Result

Run executes the simulation and returns the ground-truth ledger. Identical Config (including Seed) yields a byte-identical ledger on the same toolchain and architecture — see the package doc for why golden values must come from CI. Run panics on invalid tuning knobs: a broken scenario must never produce plausible-looking ground truth.

type Scenario

type Scenario struct {
	Name   string
	Config Config
	Golden GoldenWindow
}

Scenario is a named, file-loadable simulation configuration — the unit the testkit runs and the golden fixtures are written in.

func LoadScenario

func LoadScenario(path string) (Scenario, error)

LoadScenario reads and validates a scenario YAML file. Every validation failure is an error with the field named — a broken scenario must never produce plausible-looking ground truth.

func ParseScenario

func ParseScenario(raw []byte) (Scenario, error)

ParseScenario parses scenario YAML bytes; see LoadScenario.

type Segment

type Segment string

Segment is the customer segment (smb or enterprise).

const (
	SegmentSMB        Segment = "smb"
	SegmentEnterprise Segment = "enterprise"
)

type State

type State string

State is a transaction's lifecycle state in the ledger.

const (
	StateCreated   State = "created"        // arrived, auth not yet attempted
	StateAuthed    State = "authed"         // auth ok, inside the capture stage
	StateCaptured  State = "captured"       // capture ok, inside the settle stage
	StateSettled   State = "settled"        // terminal success
	StateAuthFail  State = "failed_auth"    // terminal: rejected at the api (5xx)
	StateAbandoned State = "abandoned"      // terminal: user gave up on api latency; telemetry never saw it
	StateCapFail   State = "failed_capture" // terminal: capture-worker rejected
)

type SuppressedMinute

type SuppressedMinute struct {
	Minute time.Time
	Count  int
}

SuppressedMinute records upstream-blackout demand that never entered: Count arrivals that would have happened at Minute. Only the ground truth can know this; the engine's counterfactual leg is judged against it.

type Txn

type Txn struct {
	ID          string
	CustomerID  string // pre-hashed form, e.g. "h:c000042"
	Segment     Segment
	AmountMinor int64
	Currency    string

	CreatedAt  time.Time
	AuthedAt   time.Time
	CapturedAt time.Time
	SettledAt  time.Time

	State State

	// Recovered marks demand that re-arrived after an upstream blackout;
	// RecoveredFrom is the originating blackout's From instant, so a
	// recovery stays attributed to the incident that suppressed it —
	// even when the re-arrival was suppressed again by a later blackout
	// on its way back.
	Recovered     bool
	RecoveredFrom time.Time
}

Txn is one synthetic invoice payment — a ledger row. Amounts are int64 minor units; time fields are zero until the stage happens.

Jump to

Keyboard shortcuts

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