Azure / Azure/azure-sdk-for-rust
[Cosmos] Binary Encoding Negotiation on the Gateway 2.0 / Thin-Client Path
- Dominant language
- Rust
- Stars
- 884
- Forks
- 365
- Avg merge
- 2d 19h
- Merged PRs (30d)
- 109
Description
## Summary
Cosmos binary JSON encoding is negotiated with the `x-ms-cosmos-supported-serialization-formats` HTTP header. That header is honored on the **standard gateway** path only. On the **Gateway 2.0 / thin-client** path the driver re-encodes the request as an RNTBD metadata token list, and there is no `SupportedSerializationFormats` token in the catalog — so the negotiation is silently dropped and the service responds with **text**.
This is pending item **#1** in [`BINARY_ENCODING_HLD.md` — Pending work][hld-pending], and divergence **#3** in the Rust vs .NET parity table of the same document.
## Why it matters (customer-visible, not benign)
Binary encoding exists in large part to fix the integral-`Double` → integer divergence (#5028).
When negotiation is dropped:
- The service returns text; `serde_json` parses an integral value as `f64`. A wide integer that round-trips correctly on the standard gateway can then fail typed deserialization on a thin-client account — **same code, same document, different account configuration**.
- The RU and bandwidth saving is forfeited with **no signal**. There is no way to distinguish "binary negotiated" from "binary received" other than counting bytes on the wire.
- The failure is silent and account-shape-dependent, which makes it hard to diagnose in the field.
The gap applies to every operation that negotiates a binary response on Gateway 2.0: point item ops (`create` / `read` / `replace` / `upsert`) and `query`.
> Note: the request-side encode is **not** affected — `apply_request_binary_encoding` transcodes the
> body before RNTBD framing, and the frame carries those bytes verbatim. This issue is specifically
> about **response negotiation**.
## Current behavior
- `CosmosDriver::apply_response_negotiation` ([`driver/cosmos_driver.rs`][driver]) sets `request_headers.supported_serialization_formats` to `"CosmosBinary"` for point ops, or `"JsonText,CosmosBinary"` for query.
- On Gateway 2.0, [`gateway_v2_dispatch.rs`][dispatch] builds the RNTBD metadata token list from a fixed set of HTTP headers. `SUPPORTED_SERIALIZATION_FORMATS` is not among them, and the outer HTTP request is a POST whose body is the RNTBD frame — so the header never reaches the backend.
- Result: the backend applies its default (text) and the response carries no `0x80` preamble, so `is_binary` correctly routes it to the text path. Everything "works", just without binary.
## Proposed fix
Mirror the existing `SupportedQueryFeatures` (`0x00FF`) forwarding pattern:
1. **Add the request token** to [`transport/rntbd/tokens.rs`][tokens]:
- New `RntbdRequestToken::SupportedSerializationFormats` variant carrying its wire ID and token
type, wired into both `TryFrom` and `value()`.
- A `Token::supported_serialization_formats(..)` constructor.
2. **Forward the header** in [`transport/gateway_v2_dispatch.rs`][dispatch]: read
`request_header_names::SUPPORTED_SERIALIZATION_FORMATS`, skip empty values, and push the token.
Keep it adjacent to the existing `SupportedQueryFeatures` / `QueryVersion` forwarding block.
3. **Confirm the value encoding** the proxy expects — string accept-list
(`"JsonText,CosmosBinary"`) versus an enum byte. This must be pinned against the proxy's contract,
not inferred: an earlier String-typed `ReadConsistencyStrategy` prototype caused the proxy to
hang, so a wrong token type is not a benign failure.
4. **Emulator support**: teach `in_memory_emulator/gateway_v2.rs` to read and honor the new token, so
the existing binary-encoding tests can run against the hosted Gateway 2.0 path without a live
account.
5. **Docs**: remove the "Gateway 2.0 limitation (follow-up)" callout from
[`BINARY_ENCODING_SPEC.md` §2][spec], drop pending item #1 and parity divergence #3 from
[`BINARY_ENCODING_HLD.md`][hld], and add the token row to the RNTBD token catalog in
[`GATEWAY_V2_SPEC.md`][gw2-spec].
## Open questions
- **Token ID and type.** Must be confirmed against the reference implementations (.NET `RntbdConstants.RntbdRequestTokenIdentifiers.SupportedSerializationFormats`, Java
`RntbdConstants.RntbdRequestHeader.SupportedSerializationFormats`) before any value is committed to `tokens.rs`. Do not guess.
- **Is the token in `thinClientProxyExcludedSet`?** If the proxy explicitly excludes it, the fix is a proxy-side change and this issue becomes a service dependency rather than an SDK one.
- **Older proxy versions.** Does an unknown or unsupported token cause a hard failure, or is it skipped? If it can fail, emission may need to be gated on a capability signal.
- **Query accept-list semantics on Gateway 2.0.** Does the proxy honor `"JsonText,CosmosBinary"` per page the way the standard gateway does?
## Acceptance criteria
- [ ] With binary encoding enabled against a Gateway 2.0 account, point item ops (`create` / `read` / `replace` / `upsert`) receive `0x80`-prefixed binary responses.
- [ ] With binary encoding enabled against a Gateway 2.0 account, `query_items` receives binary feed pages: single-partition, passthrough cross-partition, streaming `ORDER BY`, and `OFFSET` / `LIMIT`.
- [ ] Unit test: the RNTBD metadata token list built for a binary-negotiated operation contains the `SupportedSerializationFormats` token with the expected value, and omits it when binary encoding is disabled.
- [ ] Unit test: a round-trip through `RntbdRequestFrame::read` / `write` preserves the token.
- [ ] Emulator-backed integration test covering the Gateway 2.0 plus binary encoding combination.
- [ ] The existing wide-integer / `u64` fidelity assertions pass on the Gateway 2.0 path — see
[`BINARY_ENCODING_U64_MAX_ANALYSIS.md`][u64] for the known-impossible cases to keep excluded.
- [ ] [`binary_encoding_roundtrip_fuzz`][fuzzer] runs green with the Gateway 2.0 transport
configuration added to its config matrix.
- [ ] Behavior is unchanged when binary encoding is off — no new token on the wire.
- [ ] Docs updated: spec, HLD pending list, HLD parity table, and the Gateway 2.0 token catalog.
Contributor guide
Assessment
This issue has not been assessed yet.