Performance engineering as a governed system: typed k6 workloads, controlled targets, SLO-based gates, reviewed regression baselines, Grafana/InfluxDB observability, OpenTelemetry, and six distinct workload models for the RealWorld API.
| Evidence | Direct link |
|---|---|
| Live reports | Published performance evidence |
| Current release | v0.4.0 |
| Primary CI | Main load workflow |
| Shared product target | Bounded isolated load profile · Workflow |
| Safety and quality | Quality · Security |
| Repository activity | Default-branch commits · Pull requests |
| Architecture and decisions | Architecture · ADR index |
| Failure evidence | Threshold failure example · Interpretation guide |
| Controlled latency study | Controlled latency experiment protocol and artifact workflow · Controlled latency CI runs |
| Reviewed baseline report | Human-openable load report |
| Engineering question | Implemented answer |
|---|---|
| How is unsafe load prevented? | Public targets are read-only; sustained and write-heavy workloads require a controlled target and explicit override. |
| How are regressions distinguished from noise? | Not reliably yet: the PR comparison is advisory (baseline/gate-mode.json) because the committed baseline's source inputs are unavailable and same-commit spread on shared runners exceeded its 20% tolerance. Recalibration is planned under docs/experiments/. |
| How is performance made diagnosable? | Tagged metrics, JSON and Markdown summaries, Grafana/InfluxDB dashboards, and OpenTelemetry export. |
| How does the suite model different risks? | Smoke, load, stress, spike, soak, and breakpoint workloads with separate intent and thresholds. |
| How does CI remain credible? | Quality, security, main-load, reports, scheduled-soak, and release gates publish durable evidence. |
Release v0.4.0 establishes the governed performance reference: controlled
load targets, advanced workload gates, regression tooling, report publication,
observability capture, security scanning, and documented operational limits.
See release notes and the changelog.
flowchart LR
T["k6 test entry points"] --> S["Reusable scenarios"]
S --> A["Typed API services"]
A --> H["Tagged HTTP client"]
H --> R["RealWorld API"]
T --> O["JSON and Markdown summaries"]
T --> I["InfluxDB v2"]
T --> C["OpenTelemetry Collector"]
I --> G["Grafana dashboard"]
O --> P["CI gates and GitHub Pages"]
Tests never call k6/http directly. Endpoint services own paths, payload envelopes, authentication,
and stable metric names. Write-heavy tests reject non-local targets unless explicitly overridden.
| Type | Purpose | Default target | Command |
|---|---|---|---|
| Smoke | Fast API and SLO validation | Hosted API, read-only | TARGET_ENV=staging npm run smoke |
| Load | Expected traffic and user journeys | Controlled local API | npm run load |
| Stress | Progressive degradation | Controlled local API | npm run stress |
| Spike | Sudden traffic and recovery | Controlled local API | npm run spike |
| Soak | Long-duration stability | Controlled local API | npm run soak |
| Breakpoint | Capacity boundary | Controlled local API | npm run breakpoint |
Use npm run breakpoint:search to run a binary-search capacity probe. Its JSON output reports
lastHealthyVus, firstUnhealthyVus, and toleranceVus.
To inspect retained summaries without starting a load test, run the offline diagnostics panel:
npm run capacity:analyze -- --plan tests/fixtures/capacity-evidence/plan.json --out /tmp/capacity-evidenceThe included plan is authored fixture data. It demonstrates bounded target-pressure and missing-data handling; it is not a measured capacity claim. See breakpoint evidence and limits.
These objectives are controlled-target guardrails for a local RealWorld backend
running on a GitHub-hosted Ubuntu runner. They are not production service SLOs
and should not be compared to internet-facing latency targets. The reviewed
baseline represents a 20-arrival-iterations/s journey profile with 100 max VUs; each
iteration can make multiple HTTP requests. Historical targetRps fields contain
iteration rates, not fixed request throughput. See
the human-openable load report for the
source workflow, target commit, framework commit, and measured percentiles.
Use TARGET_ITERATIONS_PER_SECOND to configure the existing journey. TARGET_RPS
now fails with a migration message rather than silently changing units. For a
separate one-request-per-arrival experiment, run npm run load:500rps against your
owned local target; its report separates warm-up from achieved measurement load.
See workload units and verification. Neither a configured
rate nor a passing counting fixture proves application capacity.
| Endpoint group | p95 | p99 | Error rate |
|---|---|---|---|
| Authentication | < 800 ms | < 1500 ms | < 1% |
| Article reads | < 10 ms | < 20 ms | < 1% |
| Article writes | < 1000 ms | < 2000 ms | < 2% |
| Comment reads | < 5 ms | < 10 ms | < 2% |
| Profiles | < 5 ms | < 10 ms | < 1% |
| Tags | < 5 ms | < 10 ms | < 1% |
See performance SLOs for enforcement details.
The hosted read-only smoke test uses wider network-facing guardrails defined separately in
config/thresholds/smoke.ts.
Prerequisites: Node.js 24.21.0 (see .nvmrc), npm 10.9.4, k6 2.0+, Docker Desktop, and Docker Compose.
npx --yes npm@10.9.4 ci
npm run typecheck
npm run lint
npm run test:unit
npm run buildRun the read-only validation profile:
TARGET_ENV=staging TEST_PROFILE=validation SUMMARY_NAME=smoke npm run smoke$env:TARGET_ENV = 'staging'
$env:TEST_PROFILE = 'validation'
$env:SUMMARY_NAME = 'smoke'
npm run smokeStart observability and run a local observed load:
npm run docker:up
npm run docker:health
npm run load:observed
npm run observability:captureGrafana is available at http://localhost:3001 with local credentials admin / admin.
Grafana evidence is produced by local observed runs because GitHub-hosted CI does not persist a
remote InfluxDB. CI publishes JSON, Markdown, and Pages artifacts instead.
Authenticated scenarios create a disposable setup user against an authorized writable target:
export TARGET_ENV=local
export BASE_URL=http://localhost:3000/api
export TEST_PROFILE=validation
npm run load:journey$env:TARGET_ENV = 'local'
$env:BASE_URL = 'http://localhost:3000/api'
$env:TEST_PROFILE = 'validation'
npm run load:journeySet AUTH_USER_COUNT to size the setup user pool. VUs select credentials deterministically from
that pool, avoiding a single-account bottleneck. Full non-local workloads also require explicit
K6_STAGES; built-in full profiles are limited to the controlled local target.
- PR smoke posts an aggregate Markdown summary to same-repository pull requests.
- Main load, regression, and advanced workload workflows provision a pinned RealWorld backend.
- Load regression checks compare aggregate, endpoint, and business-metric p95/p99 values with the
committed baseline, but the comparator refuses a baseline without accepted provenance, and the
comparison is advisory (
baseline/gate-mode.json): it prints an ADVISORY line and a warning instead of failing. Full advanced runs compare with their latest compatible retained run. - Release publication waits for full stress, spike, soak, and breakpoint evidence.
- GitHub-hosted segmented validation proves partition wiring; the manual distributed workflow is reserved for authorized self-hosted runners and a shared controlled target.
- Security CI runs npm audit, creates a CycloneDX SBOM, and scans the lockfile with OSV.
- Published performance reports
This is the most CI-heavy repository in the portfolio; see the CI workflow map for what each workflow is for and why it exists as a separate gate.
- Architecture
- Contributor onboarding
- Adapting to another API
- Engineering notes
- Results interpretation
- Performance SLOs
- CI workflow map
- Cross-commit regression demonstration
- Visual performance evidence
- Baseline provenance and review decision
- Latest run link and retained historical verification
- Real-service experiment guide
- Architecture decisions
- Capability status
- v0.4.0 release notes
- v0.3.0 release notes
- v0.2.0 release notes
Public endpoints are restricted to short read-only checks. Authenticated writes and sustained load
default to a local target and require ALLOW_NON_LOCAL_LOAD=true elsewhere. Tokens, generated
runtime reports, and unreviewed baseline captures are excluded from version control. The local
observability stack ships with development credentials and anonymous Grafana viewer access; keep
those ports local or rotate credentials before exposing the stack.