rload 0.2.2

A Rust HTTP/1.1 load generator with Nginx access-log and JSONL replay
Documentation
# Rload release plan

## Current status

- `rload` 0.1.2 and 0.2.0 are published to crates.io; the main branch is now
  tracking post-0.2.0 and 0.2.1 development work.
- The package includes the standard license files and third-party notice.
- The package metadata points to the public repository, homepage, and docs.rs.
- `./scripts/release-check.sh` is the required local gate.
- The 0.2.0 development branch adds CI gates for macOS, Linux, and Windows.

## Post-0.1.1 priorities

1. Add CI on macOS, Linux, and Windows for formatting, Clippy, tests, package
   verification, and a smoke HTTP run. Windows must also verify path handling,
   socket error recovery, and the release binary invocation from PowerShell.
2. Publish a signed changelog and migration notes from the old internal
   `r-wrk` name to `rload`.
3. Fixed global replay rate control is implemented on the 0.2.0 development
   branch with validation and configured/measured-rate reporting. It remains
   independent from request selection order and burst profiles.
4. Access-log timestamp pacing is implemented on the 0.2.0 development branch:
   it preserves inter-record gaps, supports a playback multiplier, accepts
   second or fractional-second timestamps, rejects missing/decreasing values,
   and explicitly treats the unknowable loop-boundary gap as zero. It is
   independent from request selection and mutually exclusive with fixed rate.
5. Keep Lua/LuaJIT out of the first release line unless a separate compatibility
   design and licensing review is approved.
6. Tolerant access-log replay is implemented on the 0.2.0 development branch:
   unsupported methods are skipped, counted by method and total, and printed in
   the final summary. Machine-readable result output remains to be designed.
7. Burst/stage traffic models are implemented on the 0.2.0 development branch.
   Timed rate stages support baseline, spike, and recovery profiles, hold the
   final rate after the profile ends, and remain independent from sequential,
   shuffle, or random request selection.
8. Versioned machine-readable output is implemented with
   `--output-format json`. Schema version 1 covers aggregate, latency, HTTP,
   method, URI, socket-error, replay filtering/skipping, and pacing fields while
   preserving the existing text output as the default.

## Future candidate features

- Automatic target inference from access-log fields that explicitly provide
  scheme, host, and port. This is intentionally not scheduled for 0.2.0;
  standard origin-form logs do not contain enough information to infer a target
  safely.
- Optional GUI configuration interface built on top of the rload engine. The
  GUI should configure and validate workloads, launch or attach to an rload
  execution, and present live/final statistics without moving load-generation
  logic into the UI. The CLI and engine must remain usable without GUI
  dependencies.
- Scripted request/response hooks for request preparation and response result
  processing. The intended pipeline is `request -> pre-script filter -> core ->
  response -> post-script filter`. This remains a future candidate until a
  runtime, sandbox, failure model, and isolation design can guarantee a
  zero-cost disabled path and no performance regression for unscripted loads.
  It is not planned for v0.2.2 or v0.3.0.

## v0.2.1 planned work

Implementation and the local three-way validation gate were completed on
2026-07-13. The raw benchmark results are archived under
`benchmarks/results/threeway-20260713T102319Z`, with the sign-off report in
`benchmarks/VALIDATION_2026-07-13_0.2.1.md`.

- Add `RunSummary::read_bytes` permanently alongside the existing
  `response_body_bytes` field. `read_bytes` will count bytes successfully read
  from the response socket and handed to the HTTP parser, including response
  headers, body bytes, and chunk framing, so it can be compared directly with
  wrk's `read` metric. `response_body_bytes` will continue to represent only
  decoded response payload bytes for application-level traffic analysis.
- Report both counters in text output and JSON schema v1 without removing or
  renaming `response_body_bytes`; add regression coverage for content-length,
  chunked, connection-close, and partial-read/error cases.
- Define and document the rule that bytes successfully read before a later
  socket error remain counted, matching wrk's incremental read accounting.
- Extend the three-way benchmark report to compare `read_bytes` with wrk's
  `read` value while retaining `response_body_bytes` for payload comparisons.
- Make JSONL request replay tolerant of exported application-log records:
  ignore unknown top-level fields while retaining validation for known fields.
- Default an omitted JSONL `method` to `GET`; define whether explicit `null`
  has the same meaning and cover the decision with tests and documentation.
- Extract the top-level JSONL `args` field as a raw query string and append it
  to `uri`, using `?` or `&` as appropriate. Define the canonical input rule
  that `args` must not include its own separator, and test existing-query,
  empty-query, and malformed-query edge cases.
- Add a representative two-line fixture based on real exported logs and use it
  in parser regression tests, including unknown fields, missing fields, and
  repeated records.
- Add opt-in human-readable CLI formatting with `--output-beauty`. Keep the
  existing default text parser anchors compatible for benchmark scripts and keep
  `--output-format json` unchanged. Add golden and CLI tests for the beauty
  format without changing the benchmark execution path.

## v0.2.2 planned work

The next replay-focused release will make finite replay cycles explicit and
bring timestamp pacing to JSONL request files.

1. Add `--replay-rounds <N>` for finite replay inputs. A round is one complete
   traversal of the filtered sequence; require a positive integer, define its
   interaction with duration/request limits and all pacing/order modes, and
   report configured/completed rounds without changing defaults.
2. Permit `--replay-timestamps` with `--request-file` and require the JSONL
   schema to define the timestamp format. Use `timestamp_micros` as the
   canonical field, with `time` and `_time` aliases. The schema format uses
   strftime/chrono-style placeholders and defaults to the Nginx format
   `%d/%b/%Y:%H:%M:%S %z`; fractional seconds are supported. Normalize all
   parsed values to the existing microsecond representation. No separate
   timestamp-format CLI option will be added.
3. Define alias precedence and validation: canonical `timestamp_micros` wins;
   conflicting aliases are rejected, malformed or missing timestamps in
   timestamp mode are rejected, and timestamps must be non-decreasing.
4. Share existing timestamp semantics: `--replay-speed` applies, sequential
   order is required, timestamp pacing is mutually exclusive with fixed-rate
   and stage pacing, and no synthetic delay is added between cycles.
5. Preserve tolerant JSONL behavior (unknown fields ignored, missing method
   defaults to GET, existing `args` joining rules) and update README,
   README.zh-cn, CLI help, schema notes, and changelog.
6. Add parser, pacing, CLI, compatibility, and benchmark regressions covering
   both replay sources and deterministic finite-cycle counts. Run Linux,
   macOS, and Windows CI plus the three-way benchmark gate before release.
7. Add an optional schema file for nested JSONL field mappings. Every schema
   mapping is optional: absent mappings use the conventional top-level names,
   while an absent mapping falls back to the current extraction logic for that
   field. Schema configuration changes extraction paths only; it does not
   change existing record-value defaults or validation. Timestamp remains
   optional for ordinary replay but is required when timestamp pacing is
   enabled. The schema owns timestamp format configuration; do not add a
   separate timestamp-format CLI option.
8. Enforce load-time materialization: compile schema paths and parse all field
   values, including timestamps, while loading JSONL, then store the existing
   `ReplayRequest` objects. No dynamic JSON traversal, schema lookup, or
   timestamp string parsing is permitted in the request/response hot path.

## Deferred follow-up work

- Re-run the wrk accuracy matrix on a dedicated or separate-server host. This is
  intentionally deferred and is not a blocker for the current 0.1.1 release
  preparation.
- Investigate and resolve the zero-delay P99 sensitivity before claiming
  unconditional parity across environments.
- Define the skipped-record output schema and verify that skipped access-log
   entries do not affect sent-request latency, throughput, or URI statistics.
- Fixed-rate, timestamp, and stage pacing are mutually exclusive and covered by
  multiplier, precision, transition, and duration-boundary tests.

## Benchmark policy

Every benchmark sign-off must cover three dimensions: functional completeness
regression, performance regression, and statistical accuracy. Each dimension
must compare the same three implementations under equivalent parameters:
`wrk`, the latest published rload release, and the current development build.
Use at least five alternating paired runs for statistical accuracy decisions;
record throughput, latency percentiles, errors, and peak RSS, and retain the
raw result directories with the report.

## Release checklist

- [x] Confirm crates.io metadata and README links resolve.
- [x] Run `./scripts/release-check.sh` on the release commit.
- [x] Run the local wrk accuracy and access-log replay matrices and archive
      results.
- [ ] Run the deferred independent-server accuracy matrix (post-release task).
- [x] Review `LICENSE-MIT`, `LICENSE-APACHE`, and `THIRD_PARTY_NOTICES.md`.
- [x] Update the version to 0.2.0 and run the final package gate.
- [ ] Tag the release and publish the changelog.

## Automated release workflow

Push a tag in the form `vMAJOR.MINOR.PATCH` (for example `v0.2.0`) to run
`.github/workflows/release.yml`. The workflow validates that the tag matches
`Cargo.toml`, runs the release gate, publishes the crate, creates a GitHub
Release, updates `wenhaozhao/homebrew-rload`, and commits the new version to
the GitHub Pages homepage.

Required Actions secrets:

- `CARGO_REGISTRY_TOKEN`: crates.io API token with publish permission.
- `HOMEBREW_TAP_TOKEN`: fine-grained token with Contents read/write access to
  `wenhaozhao/homebrew-rload`.

The workflow can also be started manually with a release tag input.