A monetary/fixed-point parser was duplicated in TypeScript (host) and Rust (a zkVM guest), both converting a JSON number's decimal string to signed cents and both originally rejecting scientific notation outright. Production input `net_invested: 8.526512829121202e-14` (float residue from a fully-cancelled value) was stringified as scientific notation by both runtimes and rejected, hard-failing the pipeline. Verified empirically that `8.526512829121202e-14`, `1e-7`, and `1e30` produce identical strings via JS `.toString()` and serde_json `Number::to_string()` (serde_json uses ryu; switchover to exponent form is below 1e-6 and at/above 1e21 in both). Fix: expand scientific notation to plain decimal (`8.5e-14`→`0.0000…085`→0 cents; `1e30`→31-digit integer→overflows i64→rejected) then run the shared digit parser. A negative near-zero (`-8.5e-14`) then exposed a second divergence: JS returned `-0` while Rust `i64` returned `0`; only a strict `Object.is`-based assertion (Vitest `toBe(0)`) caught it. Fixed by normalizing `-0`→`0` (guard `magnitude !== 0` before negating).
Applies whenever a numeric/monetary parser is reimplemented in two languages that must agree bit-for-bit (e.g. one side runs in a zk circuit / on-chain reproduction). Confirmed with Node.js and Rust serde_json v1 (default features, no arbitrary_precision, ryu-backed float Display). The string-equality of the two stringifiers is the load-bearing fact; the `-0` trap applies to any JS-vs-integer comparison. The 2^53 vs i64 integer-overflow threshold also differs between `Number.isSafeInteger` and i64, but is unreachable through scientific-notation expansion since those values are ≥1e21 and rejected by both.