surge — intake & requirements (sdlc G0/G1)
Slug: surge · 2026-11-06 · author: luann + Claude Gate note: authored in sdlc artifact format; formal gate reviews can be run later from the sdlc workspace (/sdlc-intake surge). G5 (UI) is N/A — this is a CLI + Go library; the only "UI" is the generated HTML report, which follows the agentic-fx design tokens.
G0 — problem framing
Problem. The load testing in use is bound by an interpreted runtime — several processes needed on one machine just to use its cores — offers load only in the closed model, so a slowing target quietly receives less of it, and has no pass/fail language of its own, so gating lives in scripts beside the test. The orchestration layer inherits all three.
Who hurts. QA engineers writing and running perf tests; pipelines that need a trustable pass/fail; anyone reading a report that silently applied less load than asked.
Why now. Perf tier of the stlc bundle needs a dependable engine; the team standardized tooling on Go (verdict, recall).
Decision. Build surge: a Go load-testing engine, usable as a library (Users and weighted Tasks in Go) and as a CLI (YAML scenarios), designed so an orchestration layer can later drive it as an engine. Full analysis: design.md.
G1 — requirements
Functional
| ID | Requirement | Acceptance criteria |
|---|---|---|
| REQ-001 | YAML scenario mode | surge run f.yaml executes a multi-step flow with per-step method/url/headers/body/json/form; strict parsing rejects unknown keys with line numbers |
| REQ-002 | Go library mode | User types with weight, weighted or sequential Tasks, OnStart/OnStop, Wait(min,max); a main.go + RunMain() is a runnable test with the same flags as the CLI (-vus, -duration, -rate) |
| REQ-003 | Closed workload model | VU count ramps linearly through stages; constant shorthand vus + duration |
| REQ-004 | Open workload model | Arrival-rate stages with max_vus cap; arrivals that find no free VU are counted as dropped_iterations, never silently delayed |
| REQ-005 | Fixed-iteration mode | iterations + vus for smoke runs; optional duration cap |
| REQ-006 | Correlation | extract from JSON path / regex / header into variables usable in later steps via ${var} |
| REQ-007 | Checks | status / body_contains / json path / max_duration; check failures are counted separately from request errors |
| REQ-008 | Data-driven tests | CSV feeders with circular/random/once modes, exposed as ${feeder.column} |
| REQ-009 | Templating | ${var}, ${env.X}, ${feeder.col}, ${uuid()}, ${randint(a,b)}, ${randstr(n)}, ${now()}, ${now_iso()} |
| REQ-010 | Thresholds / CI gating | Expressions p50/p90/p95/p99/avg/min/max[(request)] <op> dur, error_rate/check_rate <op> %, rps/count <op> n; any failure → exit code 1; parse errors fail before the run starts |
| REQ-011 | Reports | Live console line; final summary table; JSON summary; per-second CSV; self-contained HTML report with charts |
| REQ-012 | Ad-hoc mode | surge quick <url> needs zero files (method, headers, body, vus/rate, duration via flags) |
| REQ-013 | Validation | surge validate f.yaml checks config, feeder files, regexes and thresholds without sending traffic |
| REQ-014 | Easy setup | surge init scaffolds a commented starter scenario; the binary is static, go install or a single file copy installs it |
| REQ-015 | Test any system | The scheduler drives a protocol-agnostic VU interface; library ctx.Time(name, fn) records custom-protocol timings (gRPC, WS, TCP, DB) into the same metrics/thresholds/reports |
| REQ-016 | Warmup | warmup duration excluded from final stats, visible on the timeline |
| REQ-017 | Graceful stop | In-flight iterations get grace_stop to finish; Ctrl-C still prints the summary |
Non-functional
| ID | Requirement | Acceptance criteria |
|---|---|---|
| NFR-001 | Throughput | ≥ 50k req/s on an M-series laptop against a local target (small responses), one process |
| NFR-002 | Metric honesty | Histogram error ≤ ~3%; percentiles clamped to observed min/max; coordinated omission surfaced via open model + dropped counter |
| NFR-003 | Footprint | Bounded memory per run (fixed-size histograms; timeline grows 1 point/sec); 2 external deps (yaml, gjson) |
| NFR-004 | Error diagnostics | Failures classified (timeout/refused/reset/dns/HTTP n) with top-error counts in reports |
| NFR-005 | UX of failure | Config errors name the YAML line; threshold typos fail before traffic is sent |
Out of scope (v1.0) → roadmap
distributed master/worker (v2, design §7), native WebSocket/gRPC clients (v1.1), web UI (reports go to files / verdict hub), JS scripting.