From 02f146c1ff0e29cadf072fc60f443d4913174189 Mon Sep 17 00:00:00 2001 From: Dave Nagoda Date: Tue, 30 Jun 2026 15:07:14 -0700 Subject: [PATCH] Preserve JSON input object order Function-runner parses JSON inputs into serde_json::Value and reserializes them before passing bytes to the WASM. With serde_json's default map implementation, this sorts object keys lexicographically, which can change JS behavior that depends on Object.keys() ordering for fallback logic.\n\nEnable serde_json's preserve_order feature so JSON input object key order is retained, and add a regression test covering nested metafield-like message objects. This keeps function-rerunner parity closer to production inputs for Checkout Blocks discount functions.\n\nVerified with:\n- cargo test json_input_preserves_object_key_order_in_raw_bytes\n- cargo build --release\n- cargo test\n- Rerunning the 17 discount localized-message mismatch rows with the fixed release runner produced full semantic matches. Assisted-By: devx/c659e918-9568-4750-b122-e3890447348a --- Cargo.lock | 1 + Cargo.toml | 2 +- src/container.rs | 15 +++++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index ee10bd6f..238c0d10 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2588,6 +2588,7 @@ version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ + "indexmap", "itoa", "memchr", "serde", diff --git a/Cargo.toml b/Cargo.toml index fb59981d..6b0ffc5f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ wasmtime-wasi = "=39.0.1" deterministic-wasi-ctx = "=3.0.4" anyhow = "1.0" clap = { version = "4.5", features = ["derive"] } -serde_json = "1.0" +serde_json = { version = "1.0", features = ["preserve_order"] } colored = "3.1" serde = "1.0" rust-embed = "8.11.0" diff --git a/src/container.rs b/src/container.rs index c3c1fd1b..435bf729 100644 --- a/src/container.rs +++ b/src/container.rs @@ -136,3 +136,18 @@ impl BytesContainer { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn json_input_preserves_object_key_order_in_raw_bytes() { + let raw = br#"{"msg":{"sq-XK":"5.00 EUR Zbritje","en":"5.00 EUR Discount"}}"#.to_vec(); + + let input = BytesContainer::new(BytesContainerType::Input, Codec::Json, raw.clone()) + .expect("valid JSON input"); + + assert_eq!(String::from_utf8(input.raw).unwrap(), String::from_utf8(raw).unwrap()); + } +}