DEV Community

Vayun Godara
Vayun Godara

Posted on

How I check that my Rust port still does what the Go original does

cliproxy-rs is my Rust port of CLIProxyAPI, a Go proxy that puts Claude, Codex, Gemini and OpenAI-compatible APIs behind one local endpoint. The promise is that a Go user can point the Rust binary at their existing config.yaml and credential files and get the same routes and the same answers.

Trying requests by hand only tells you the requests you tried work. I wanted a coverage number I could trace back to evidence, item by item.

The checklist comes from the Go tree

A list I wrote by hand would only contain the things I remembered, so the checklist is extracted from the Go source at a pinned commit. Each item is one contract: a Go test file, a config key, a public or management route, a plugin RPC method, a CLI flag. At Go v8.0.35 that's 1,951 items. The biggest groups:

Kind Items
Go test-suite files 989
Config leaves 436
Management routes 186
Public routes 77
Plugin RPC methods 62
CLI flags 34

Every item gets one of three statuses:

  • covered: implemented, and a Rust test or a fixture recorded from Go exercises it
  • partial: implemented in part, or implemented with no test that pins Go's behaviour
  • missing: not there

A Python script (audit.py) fills in most of it. Fixtures recorded from Go carry the Go test name and line, so it can match each Go test against the names cited in Rust tests and fixtures. A second script starts the server and records which method and path pairs actually route. When the scan gets something wrong I override it in a TSV, one row per item, with the evidence and a note.

The first audit was too generous

When I redid the audit for v0.2.6, the generated numbers were 854 covered, 722 partial, 111 missing. The README said 835 / 707 / 145, so it was already stale.

I went through all 833 items that weren't covered and 164 changed status. Most moved up (73 partial to covered, 36 missing to covered, 42 missing to partial). 13 went from covered down to partial, and those were the useful ones.

The scanner had counted a route as covered when a fixture hit the same path, even with a different HTTP method, so a GET test was vouching for a POST handler. Now the evidence has to match the method and the complete route.

Two more rules came out of that pass. A subsystem that works doesn't make a whole Go test suite covered: Go has 23 Claude alias-restoration cases, I replay 20, so that item is partial. And a Go test name in a Rust comment is a search hint. It doesn't prove the assertions were ported.

Moving the target

Go keeps shipping. I'd been comparing against v8.0.10, and moving to v8.0.35 meant going through 288 upstream commits and adding 264 checklist items. I kept all 1,687 existing IDs and appended the new ones at the end of each section, so branches I had in flight still point at the right item. Tests Go deleted are marked historical instead of disappearing.

The last audit (20 Oct, against v8.0.35) reads 1,053 covered, 872 partial and 26 missing.

Partial is the biggest bucket. It holds everything implemented in part or implemented without a test that pins Go's behaviour, and the audit won't round any of it up to covered.

If you're porting something

Generate the checklist from the original's source. Make "covered" need evidence a script can find, and make every manual override say why. My first honest pass moved 13 items backwards.

The checklist, the scripts and the per-item notes are in the repo under docs/parity-audit: https://github.com/vayungodara/cliproxy-rs

Top comments (1)

Collapse
 
florian131313 profile image
G •

The match keys off the Go test name cited in the Rust test. If that test asserts a different status or body than the Go original, does the item still land in covered?