Parity
The parity matrix classifies the 120 reference rows of HAProxy 3.4.6 LTS, nginx 1.27.1, ingress-nginx and Envoy API v3: 61 from HAProxy, 20 from nginx, 19 from ingress-nginx and 20 from Envoy. None is left unclassified, and no classification rests on "it compiles, therefore it works".
v0.9.1 result: 11 E1 · 88 E2 · 21 E3 · 0 unclassified. That is not full parity and the page does not claim it.
What each class means
| Class | Meaning | Evidence required |
|---|---|---|
| E1 | Same observable semantics as the reference | A differential corpus case that runs against the reference and EQProxy and passes |
| E2 | Equivalent with a known and documented difference | A test of the behavior and the difference named in the row |
| E3 | Out of scope by decision | A public ADR and an alternative |
An E1 is only accepted if the differential corpus runs it: it is not inferred from a unit test or from the code looking equivalent. A row whose shared semantics are covered but whose directive set is not keeps the E1 for what is covered and names what is missing in the difference column.
Count by reference
| Reference | Rows | E1 | E2 | E3 |
|---|---|---|---|---|
| HAProxy 3.4.6 | 61 | 3 | 49 | 9 |
| nginx | 20 | 3 | 15 | 2 |
| ingress-nginx | 19 | 3 | 11 | 5 |
| Envoy API v3 | 20 | 2 | 13 | 5 |
| Total | 120 | 11 | 88 | 21 |
The eleven E1 rows are: host, path, header and method routing, URL and header rewriting and redirects in HAProxy (C3, C4, C5); virtual hosts, location and headers with X-Forwarded-For in nginx (B-N2, B-N3, B-N4); host and path, PROXY and X-Forwarded-*, and redirects and rewrites in ingress-nginx (B-I2, B-I4, B-I6); advanced routing and header manipulation in Envoy (B-E3, B-E17).
What is out of scope
What EQProxy does not do, by decision written in an ADR:
- Gateways that are not HTTP: FastCGI, uwsgi, scgi (ADR-0032), AJP (ADR-0038), Lua filters (ADR-0041).
- UDP: there are no UDP listeners, balancing or checks; the only UDP is QUIC for HTTP/3 (ADR-0037).
- WAF and ModSecurity/CRS (ADR-0040); the rate limit is not anti-DDoS.
- Configuration snippets (ADR-0042) and TPROXY /
original_dst(ADR-0039). - Store shared between instances: stick-tables,
peers, global rate limit (ADR-0046/0047). - xDS and native discovery: no xDS client (ADR-0027), no Consul or Eureka or API server watch (ADR-0044).
- Algorithms that do not exist:
static-rr,random,RING_HASH/MAGLEV,lb_subset_config. - Binary upgrade and multi-instance deployment: staggered restart behind a load balancer.
Known gaps and narrower semantics
In addition to the above, v0.9.1 has limits that are worth reading before testing anything:
| Point | Status |
|---|---|
| HTTP/3 | Experimental: browsers and curl over h3 unverified, and the threat model's QUIC adversarial tests have not been run |
| Users | None outside the author; production phase 9 is still pending |
map | Only equals matching |
error_pages with format = "raw" | Keeps the status, the Content-Type and the body; the generated Date replaces the file's |
Date of an origin that does not send it | Relayed as is: the proxy only stamps the responses it generates itself |
Interim 100 Continue response | Without header fields |
| Cache | Without stale-while-revalidate or stale-if-error |
| macOS binaries | Not static; only the Linux ones are |
How the evidence is generated
Two Rust harnesses, both #[ignore] because they need Docker.
Differential corpus (23/23). Starts HAProxy 3.4.6, nginx, the ingress-nginx dataplane and static Envoy in containers, and compares each case against EQProxy: status, Location (path and query), declared bodies and declared headers, after the documented normalization. It does not compare times, connection reuse, TLS parameters or bytes of error pages.
cargo test -p eqproxy-cli --test differential -- --ignored --nocapture
Migration matrix (65/65). Four hand-written source configurations and their translation to eqproxy.toml route case by case the same: 13 declared cases × 5 implementations. The originals run in containers and the eqproxy binary natively, all in front of the same five echo backends.
cargo test -p eqproxy-cli --test migration -- --ignored --nocapture
A green corpus is the absence of a counterexample, not a proof of equivalence. The migration matrix is 13 declared cases, not a proof for arbitrary configurations: the method and its limits are published alongside the evidence.