Pick the reference implementation. Rust first, because the
type system catches the easiest mistakes (signed/unsigned, missing
match arms) at compile time. Once 13 unit tests pass in Rust,
freeze the golden hashes from the release build.
Port to Go. Mirror the structure 1:1. The only language-shaped
differences are: an explicit sort.Slice everywhere a Rust
BTreeMap iteration is implicit, and fmt.Sprintf("t%d", n) in
place of Rust's format!("t{}", n).
Port to C++. Same structure again. Use std::map instead of
std::unordered_map so iteration is sorted-by-key for free. Use
std::ostringstream for the tag, never std::to_string with
locale-aware formatting.
Write the cross-language script last. Build all three CLI
binaries, run both scenarios, assert pairwise equality and
equality to the goldens.
First Go run produced a different hash for scenario A. Cause:
ranging directly over c.secondary instead of collecting keys and
calling sort.Strings. The fix is in src/go/sql15.go;
see DumpSnapshot.
First C++ run also diverged. Cause: std::unordered_map
instead of std::map. Same fix shape — switch container, or sort
keys before iteration. We chose std::map for symmetry with Rust's
BTreeMap.
A test asserted SHA256("abc") and failed. Typo in the expected
hex string (extra 3, missing trailing d). The canonical value
is ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad.
Worth pinning a known SHA-256 vector in every cross-language lab.