test(server): validate upstream 0.9.1 client interop #82

Merged
Lochnair merged 4 commits from test/upstream-client-interop into main 2026-08-13 11:19:43 +00:00
Lochnair commented 2026-08-13 09:47:42 +00:00 (Migrated from github.com)

Summary

Ran the released upstream IRTT 0.9.1 client as a black box against the real
Tokio irtt_server::Server over explicit loopback listeners, and recorded the
result in docs/validation/UPSTREAM_CLIENT_INTEROP.md.

12 of 13 matrix rows pass; 1 is skipped for a client-side CLI reason. No
implementation incompatibility was found, so no code fix is included — the
only committed file is the validation document.

At a glance: IPv4 ordinary PASS, HMAC PASS (plus a wrong-key negative
control PASS), IPv6 loopback PASS, packet-length restriction PASS
(both strict and --loose), interval restriction / rate limiter PASS,
maximum-duration restriction PASS, no-test PASS, midpoint timestamps
PASS (monotonic-only, wall-only, both clocks). Continuous request
SKIPPED — upstream's CLI refuses -d 0, so continuous mode was not
exercisable through it (no capture was taken, so what the client emitted before
exiting was not observed).

Two findings worth reading in the doc:

  • The single-field midpoint reply that irtt-rs deliberately emits (rather
    than upstream 0.9.1's dual-field form) is accepted by the released client,
    which derives RTT and IPDV from it correctly. This was the likeliest
    reply-shape incompatibility and it did not materialise.
  • The server-initiated maximum-duration Close was not reached in the tested
    low-delay loopback run: the upstream client honoured the negotiated Duration
    and stopped well before the +2 s boundary, so no echo arrived to carry Close.
    This is not a universal claim about every conforming-client/network-path
    combination — the deadline is evaluated on arrival, so sufficiently delayed
    in-flight traffic could still reach that boundary. Not a defect either: the
    two-second grace is the measured margin recorded in the airlocked evidence, so
    no change was made, and the Close path stays covered deterministically by the
    in-repo tests in crates/irtt-server/src/tests/lifecycle.rs.

Validation boundary

  • Upstream source, tests and repository history were not inspected.
  • Only the executable's reported version, its irtt help client output, its exit
    status and its normal stdout/stderr were observed.
  • No upstream source was downloaded: an existing 0.9.1 installation was used, so
    there was no module cache to avoid reading in the first place.
  • The airlocked protocol evidence (docs/protocol/**, docs/clean-room/**) was
    not changed.
  • The server was exposed through a throwaway harness kept outside the repository
    that only builds a ServerConfig, binds, prints the address and runs. It is
    not committed, and no CLI server applet was added.

Tested

  • IPv4 ordinary session
  • HMAC session, plus a bounded wrong-key negative control
  • IPv6 loopback session
  • Server packet-length restriction, strict and --loose
  • Server interval restriction and the per-session rate limiter
  • Maximum-duration restriction and negotiation
  • No-test open
  • Midpoint timestamps with monotonic-only, wall-only and both clocks

The tested client arguments/scenarios, the upstream executable's SHA-256 and
reported version, and the host/toolchain details are recorded in the validation
document.

Remaining scope

Not established by this validation: DSCP response marking; the full ServerFill
policy (echo payloads remain zero-filled); wildcard/multi-homed source-address
handling (pktinfo); exhaustive or pathological parameter combinations; any
operating system other than the macOS/arm64 host recorded in the document; and
behavior across a real network path. No claim of universal compatibility is made.

Verification

  • cargo fmt --all -- --check
  • cargo check --workspace --all-targets --all-features --locked
  • cargo test --workspace --all-targets --all-features --locked
  • cargo clippy --workspace --all-targets --all-features --locked -- -D warnings
  • RUSTDOCFLAGS="-D warnings" cargo doc -p irtt-proto -p irtt-client -p irtt-server --all-features --no-deps
  • Complete black-box matrix rerun from scratch against the final branch state,
    with every harness process confirmed alive after its client exited and shut
    down cleanly afterwards.

No permanent test in this repository depends on the upstream executable, the Go
toolchain or network access.

## Summary Ran the released upstream IRTT **0.9.1 client** as a black box against the real Tokio `irtt_server::Server` over explicit loopback listeners, and recorded the result in `docs/validation/UPSTREAM_CLIENT_INTEROP.md`. **12 of 13 matrix rows pass; 1 is skipped for a client-side CLI reason.** No implementation incompatibility was found, so **no code fix is included** — the only committed file is the validation document. At a glance: IPv4 ordinary **PASS**, HMAC **PASS** (plus a wrong-key negative control **PASS**), IPv6 loopback **PASS**, packet-length restriction **PASS** (both strict and `--loose`), interval restriction / rate limiter **PASS**, maximum-duration restriction **PASS**, no-test **PASS**, midpoint timestamps **PASS** (monotonic-only, wall-only, both clocks). Continuous request **SKIPPED** — upstream's CLI refuses `-d 0`, so continuous mode was not exercisable through it (no capture was taken, so what the client emitted before exiting was not observed). Two findings worth reading in the doc: - The **single-field midpoint reply** that `irtt-rs` deliberately emits (rather than upstream 0.9.1's dual-field form) is accepted by the released client, which derives RTT and IPDV from it correctly. This was the likeliest reply-shape incompatibility and it did not materialise. - The **server-initiated maximum-duration Close was not reached** in the tested low-delay loopback run: the upstream client honoured the negotiated Duration and stopped well before the `+2 s` boundary, so no echo arrived to carry Close. This is not a universal claim about every conforming-client/network-path combination — the deadline is evaluated on arrival, so sufficiently delayed in-flight traffic could still reach that boundary. Not a defect either: the two-second grace is the measured margin recorded in the airlocked evidence, so no change was made, and the Close path stays covered deterministically by the in-repo tests in `crates/irtt-server/src/tests/lifecycle.rs`. ## Validation boundary - Upstream source, tests and repository history were **not** inspected. - Only the executable's reported version, its `irtt help client` output, its exit status and its normal stdout/stderr were observed. - No upstream source was downloaded: an existing 0.9.1 installation was used, so there was no module cache to avoid reading in the first place. - The airlocked protocol evidence (`docs/protocol/**`, `docs/clean-room/**`) was **not** changed. - The server was exposed through a throwaway harness kept outside the repository that only builds a `ServerConfig`, binds, prints the address and runs. It is not committed, and no CLI server applet was added. ## Tested - IPv4 ordinary session - HMAC session, plus a bounded wrong-key negative control - IPv6 loopback session - Server packet-length restriction, strict and `--loose` - Server interval restriction and the per-session rate limiter - Maximum-duration restriction and negotiation - No-test open - Midpoint timestamps with monotonic-only, wall-only and both clocks The tested client arguments/scenarios, the upstream executable's SHA-256 and reported version, and the host/toolchain details are recorded in the validation document. ## Remaining scope Not established by this validation: DSCP response marking; the full `ServerFill` policy (echo payloads remain zero-filled); wildcard/multi-homed source-address handling (`pktinfo`); exhaustive or pathological parameter combinations; any operating system other than the macOS/arm64 host recorded in the document; and behavior across a real network path. No claim of universal compatibility is made. ## Verification - `cargo fmt --all -- --check` - `cargo check --workspace --all-targets --all-features --locked` - `cargo test --workspace --all-targets --all-features --locked` - `cargo clippy --workspace --all-targets --all-features --locked -- -D warnings` - `RUSTDOCFLAGS="-D warnings" cargo doc -p irtt-proto -p irtt-client -p irtt-server --all-features --no-deps` - Complete black-box matrix rerun from scratch against the final branch state, with every harness process confirmed alive after its client exited and shut down cleanly afterwards. No permanent test in this repository depends on the upstream executable, the Go toolchain or network access.
chatgpt-codex-connector[bot] (Migrated from github.com) reviewed 2026-08-13 09:51:20 +00:00
chatgpt-codex-connector[bot] (Migrated from github.com) left a comment

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a50edff624

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

### 💡 Codex Review Here are some automated review suggestions for this pull request. **Reviewed commit:** `a50edff624` <details> <summary>ℹ️ About Codex in GitHub</summary> <br/> [Your team has set up Codex to review pull requests in this repo](https://chatgpt.com/codex/cloud/settings/general). Reviews are triggered when you - Open a pull request for review - Mark a draft as ready - Comment "@codex review". If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". </details>
@@ -0,0 +1,137 @@
# Upstream IRTT 0.9.1 Client Interoperability
chatgpt-codex-connector[bot] (Migrated from github.com) commented 2026-08-13 09:51:21 +00:00

P2 Badge Include the commands needed to reproduce the matrix

The document claims the validation is reproducible from commands above, but it contains only partial client argument lists: there are no complete irtt client invocations or targets, and the external server harness needed to select configurations, report its ephemeral port, handle shutdown, and run Server::run is deliberately omitted. Anyone attempting to rerun or audit this validation therefore cannot reproduce the recorded matrix from the committed artifact; include the harness and complete commands (or remove the reproducibility claim).

Useful? React with 👍 / 👎.

**<sub><sub>![P2 Badge](https://img.shields.io/badge/P2-yellow?style=flat)</sub></sub> Include the commands needed to reproduce the matrix** The document claims the validation is reproducible from commands above, but it contains only partial client argument lists: there are no complete `irtt client` invocations or targets, and the external server harness needed to select configurations, report its ephemeral port, handle shutdown, and run `Server::run` is deliberately omitted. Anyone attempting to rerun or audit this validation therefore cannot reproduce the recorded matrix from the committed artifact; include the harness and complete commands (or remove the reproducibility claim). Useful? React with 👍 / 👎.
chatgpt-codex-connector[bot] (Migrated from github.com) commented 2026-08-13 09:51:21 +00:00

P2 Badge Qualify the maximum-duration Close conclusion

Stopping transmission before the server deadline does not guarantee that no echo arrives after it: on a real or sufficiently queued network path, a request sent within the negotiated Duration can remain in flight for over two seconds and reach the server after first served echo + maximum + 2 s, at which point it can carry Close while the client is draining replies. The loopback run establishes only that this path was unreachable under negligible delay, so qualify this conclusion rather than stating it for every conforming client.

Useful? React with 👍 / 👎.

**<sub><sub>![P2 Badge](https://img.shields.io/badge/P2-yellow?style=flat)</sub></sub> Qualify the maximum-duration Close conclusion** Stopping transmission before the server deadline does not guarantee that no echo arrives after it: on a real or sufficiently queued network path, a request sent within the negotiated Duration can remain in flight for over two seconds and reach the server after `first served echo + maximum + 2 s`, at which point it can carry Close while the client is draining replies. The loopback run establishes only that this path was unreachable under negligible delay, so qualify this conclusion rather than stating it for every conforming client. Useful? React with 👍 / 👎.
Lochnair (Migrated from github.com) reviewed 2026-08-13 10:16:49 +00:00
@@ -0,0 +1,137 @@
# Upstream IRTT 0.9.1 Client Interoperability
Lochnair (Migrated from github.com) commented 2026-08-13 10:16:49 +00:00

Good catch — fixed in 02bdb495a1 by removing the unsupported reproducibility/exact-command claim rather than by adding the missing material.

The closing sentence now says this document is a record of the manual validation that was performed, not a reproduction harness: the server policy and client arguments are summarized in the matrix, but the throwaway harness was discarded afterwards and is not committed, so the run is not reproducible from this artifact alone. The disposable harness is deliberately not being promoted into repository infrastructure.

The PR body was corrected the same way ("Exact commands ..." → "The tested client arguments/scenarios ... are recorded in the validation document").

Good catch — fixed in 02bdb495a1455e7c5d0bb9070835e7ca50ec88b2 by removing the unsupported reproducibility/exact-command claim rather than by adding the missing material. The closing sentence now says this document is a record of the manual validation that was performed, not a reproduction harness: the server policy and client arguments are summarized in the matrix, but the throwaway harness was discarded afterwards and is not committed, so the run is not reproducible from this artifact alone. The disposable harness is deliberately not being promoted into repository infrastructure. The PR body was corrected the same way ("Exact commands ..." → "The tested client arguments/scenarios ... are recorded in the validation document").
Lochnair (Migrated from github.com) reviewed 2026-08-13 10:17:02 +00:00
@@ -0,0 +1,137 @@
# Upstream IRTT 0.9.1 Client Interoperability
Lochnair (Migrated from github.com) commented 2026-08-13 10:17:02 +00:00

Correct, and the original reasoning was wrong in exactly the way you describe — it argued from transmission time when the deadline is evaluated on arrival. Fixed in 02bdb495a1.

The finding is now scoped to the tested low-delay loopback path: negotiation reduced Duration to 500 ms, the client stopped transmitting after ~400 ms, no echo arrived near the +2 s deadline, so the scenario did not exercise the Close. The document now states explicitly that this does not follow for every conforming client — an echo sent legitimately before the negotiated Duration elapsed could still be queued or delayed for more than two seconds and arrive after first served echo + configured maximum + 2 s, carrying Close while the client drains replies. The conclusion is reframed as the Close providing a termination path for traffic continuing or arriving beyond the grace, including delayed in-flight traffic, and the matrix row now reads "Close reply not reached on loopback".

Unchanged: this is not an implementation defect, the +2 s grace matches the airlocked measured behavior, no code fix is justified, and the lifecycle tests still cover the Close path. The PR body carries the same qualification.

Correct, and the original reasoning was wrong in exactly the way you describe — it argued from transmission time when the deadline is evaluated on arrival. Fixed in 02bdb495a1455e7c5d0bb9070835e7ca50ec88b2. The finding is now scoped to the tested low-delay loopback path: negotiation reduced Duration to 500 ms, the client stopped transmitting after ~400 ms, no echo arrived near the +2 s deadline, so the scenario did not exercise the Close. The document now states explicitly that this does not follow for every conforming client — an echo sent legitimately before the negotiated Duration elapsed could still be queued or delayed for more than two seconds and arrive after `first served echo + configured maximum + 2 s`, carrying Close while the client drains replies. The conclusion is reframed as the Close providing a termination path for traffic continuing or arriving beyond the grace, including delayed in-flight traffic, and the matrix row now reads "Close reply not reached on loopback". Unchanged: this is not an implementation defect, the +2 s grace matches the airlocked measured behavior, no code fix is justified, and the lifecycle tests still cover the Close path. The PR body carries the same qualification.
chatgpt-codex-connector[bot] (Migrated from github.com) reviewed 2026-08-13 10:18:08 +00:00
chatgpt-codex-connector[bot] (Migrated from github.com) left a comment

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 02bdb495a1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

### 💡 Codex Review Here are some automated review suggestions for this pull request. **Reviewed commit:** `02bdb495a1` <details> <summary>ℹ️ About Codex in GitHub</summary> <br/> [Your team has set up Codex to review pull requests in this repo](https://chatgpt.com/codex/cloud/settings/general). Reviews are triggered when you - Open a pull request for review - Mark a draft as ready - Comment "@codex review". If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". </details>
@@ -0,0 +1,137 @@
# Upstream IRTT 0.9.1 Client Interoperability
chatgpt-codex-connector[bot] (Migrated from github.com) commented 2026-08-13 10:18:08 +00:00

P2 Badge Match the strict/loose claim to the recorded matrix

The interval-restriction and maximum-duration rows are recorded only with --loose, yet this paragraph says restriction scenarios were run both ways. As written, this clean-room validation artifact credits strict-mode coverage that the matrix does not document; either qualify the statement as applying only to packet-length restriction or add the missing strict runs and outcomes.

AGENTS.md reference: AGENTS.md:L12-L14

Useful? React with 👍 / 👎.

**<sub><sub>![P2 Badge](https://img.shields.io/badge/P2-yellow?style=flat)</sub></sub> Match the strict/loose claim to the recorded matrix** The interval-restriction and maximum-duration rows are recorded only with `--loose`, yet this paragraph says restriction scenarios were run both ways. As written, this clean-room validation artifact credits strict-mode coverage that the matrix does not document; either qualify the statement as applying only to packet-length restriction or add the missing strict runs and outcomes. AGENTS.md reference: [AGENTS.md:L12-L14](https://github.com/Lochnair/irtt-rs/blob/02bdb495a1455e7c5d0bb9070835e7ca50ec88b2/AGENTS.md#L12-L14) Useful? React with 👍 / 👎.
Lochnair (Migrated from github.com) reviewed 2026-08-13 10:35:45 +00:00
@@ -0,0 +1,137 @@
# Upstream IRTT 0.9.1 Client Interoperability
Lochnair (Migrated from github.com) commented 2026-08-13 10:35:45 +00:00

Qualified to packet-length restriction only in 750e28200a — the interval and maximum-duration rows are now stated as --loose only, rather than adding strict runs (that would mean recreating the discarded harness and rerunning the upstream matrix, which is out of scope for this artifact).

🤖 Addressed by Claude Code

Qualified to packet-length restriction only in 750e28200a07ceacd01126fcfe91ac029a4b30b3 — the interval and maximum-duration rows are now stated as `--loose` only, rather than adding strict runs (that would mean recreating the discarded harness and rerunning the upstream matrix, which is out of scope for this artifact). _🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
chatgpt-codex-connector[bot] (Migrated from github.com) reviewed 2026-08-13 10:38:03 +00:00
chatgpt-codex-connector[bot] (Migrated from github.com) left a comment

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 750e28200a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

### 💡 Codex Review Here are some automated review suggestions for this pull request. **Reviewed commit:** `750e28200a` <details> <summary>ℹ️ About Codex in GitHub</summary> <br/> [Your team has set up Codex to review pull requests in this repo](https://chatgpt.com/codex/cloud/settings/general). Reviews are triggered when you - Open a pull request for review - Mark a draft as ready - Comment "@codex review". If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". </details>
@@ -0,0 +1,137 @@
# Upstream IRTT 0.9.1 Client Interoperability
chatgpt-codex-connector[bot] (Migrated from github.com) commented 2026-08-13 10:38:03 +00:00

P2 Badge Qualify the claim that continuous mode never reached the wire

The recorded observations establish that the client printed DurationNonPositive, but the stated methodology includes neither a packet capture nor server-side datagram instrumentation, and explicitly says no upstream behavior was inferred beyond program output. Consequently, this skipped run does not establish that the client emitted no datagram before reporting the error; qualify the wire-level conclusion or support it with a black-box packet observation.

AGENTS.md reference: AGENTS.md:L12-L14

Useful? React with 👍 / 👎.

**<sub><sub>![P2 Badge](https://img.shields.io/badge/P2-yellow?style=flat)</sub></sub> Qualify the claim that continuous mode never reached the wire** The recorded observations establish that the client printed `DurationNonPositive`, but the stated methodology includes neither a packet capture nor server-side datagram instrumentation, and explicitly says no upstream behavior was inferred beyond program output. Consequently, this skipped run does not establish that the client emitted no datagram before reporting the error; qualify the wire-level conclusion or support it with a black-box packet observation. AGENTS.md reference: [AGENTS.md:L12-L14](https://github.com/Lochnair/irtt-rs/blob/750e28200a07ceacd01126fcfe91ac029a4b30b3/AGENTS.md#L12-L14) Useful? React with 👍 / 👎.
Lochnair (Migrated from github.com) reviewed 2026-08-13 10:40:30 +00:00
@@ -0,0 +1,137 @@
# Upstream IRTT 0.9.1 Client Interoperability
Lochnair (Migrated from github.com) commented 2026-08-13 10:40:29 +00:00

Dropped the wire-level claim in 9d7566955d — the row now records only what was observed (argument refused, non-zero exit, none of the connection line printed in every other scenario), states explicitly that no packet capture was taken so the emission was not observed, and keeps the supportable conclusion that continuous mode was not exercisable through this CLI; the PR body carries the same qualification.

🤖 Addressed by Claude Code

Dropped the wire-level claim in 9d7566955d63fe3105adc2fa346982ac53db1d4e — the row now records only what was observed (argument refused, non-zero exit, none of the connection line printed in every other scenario), states explicitly that no packet capture was taken so the emission was not observed, and keeps the supportable conclusion that continuous mode was not exercisable through this CLI; the PR body carries the same qualification. _🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
Sign in to join this conversation.