Context
Request IDs are correctly limited to JavaScript's exactly representable integer maximum (9007199254740991), but several other protocol integers permit the full unsigned 64-bit range.
Problem
schema/ipc/v1/common.schema.json and protocol-specific schemas allow values up to 18446744073709551615 for fields including deadlines, retry delays, expiries, and authorization durations. Rust models these as u64.
Common JSON/OpenRPC clients—especially JavaScript/TypeScript clients using number and ordinary JSON.parse—cannot round-trip integers above 2^53 - 1 exactly. A deadline or expiry may silently change value before validation, signature/correlation logic, or comparison. The protocol already acknowledges this portability constraint for request IDs, so applying a different numeric model to timestamps/durations is surprising.
Suggested resolution
Before freezing v1, choose one wire-wide rule:
- Recommended: constrain every JSON integer to the exactly representable range
0..=9007199254740991 (or 1..= where positive), including deadline_unix_ms, retry_after_ms, expires_at_unix_ms, requested_authorization_duration_ms, and protocol-specific TTL/expiry fields; or
- encode potentially larger integer fields as canonical decimal strings.
The first option is simpler and still represents epoch milliseconds for hundreds of thousands of years.
Update schemas, Rust validation, C parsing, docs, and fixtures together. Do not rely on a language binding to discover after parsing that precision was already lost.
Deterministic coverage
Add cross-language cases for:
- fractional values;
- negative values where unsigned/positive is required;
2^53 - 1 accepted;
2^53 rejected;
u64::MAX rejected;
- boundary values passing identically through the C and Rust clients.
Context
Request IDs are correctly limited to JavaScript's exactly representable integer maximum (
9007199254740991), but several other protocol integers permit the full unsigned 64-bit range.Problem
schema/ipc/v1/common.schema.jsonand protocol-specific schemas allow values up to18446744073709551615for fields including deadlines, retry delays, expiries, and authorization durations. Rust models these asu64.Common JSON/OpenRPC clients—especially JavaScript/TypeScript clients using
numberand ordinaryJSON.parse—cannot round-trip integers above2^53 - 1exactly. A deadline or expiry may silently change value before validation, signature/correlation logic, or comparison. The protocol already acknowledges this portability constraint for request IDs, so applying a different numeric model to timestamps/durations is surprising.Suggested resolution
Before freezing v1, choose one wire-wide rule:
0..=9007199254740991(or1..=where positive), includingdeadline_unix_ms,retry_after_ms,expires_at_unix_ms,requested_authorization_duration_ms, and protocol-specific TTL/expiry fields; orThe first option is simpler and still represents epoch milliseconds for hundreds of thousands of years.
Update schemas, Rust validation, C parsing, docs, and fixtures together. Do not rely on a language binding to discover after parsing that precision was already lost.
Deterministic coverage
Add cross-language cases for:
2^53 - 1accepted;2^53rejected;u64::MAXrejected;