Skip to content

Cosmos: Add Binary Encoding Support for Thinclient Mode - #5284

Open
Arooshi Avasthy (aavasthy) wants to merge 8 commits into
Azure:mainfrom
aavasthy:users/aavasthy/thinclientbinaryencoding
Open

Arooshi Avasthy (aavasthy) wants to merge 8 commits into
Azure:mainfrom
aavasthy:users/aavasthy/thinclientbinaryencoding

Conversation

@aavasthy

@aavasthy Arooshi Avasthy (aavasthy) commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Binary encoding is turned on with the x-ms-cosmos-supported-serialization-formats header. This works on the standard
gateway, but not on the Gateway 2.0 / thin-client path. There, requests are repackaged into RNTBD tokens, and this header had no matching token — so it was dropped and the service always replied in plain text.

This change adds that missing token (SupportedSerializationFormats, 0x00C4) and forwards the header to it on the Gateway 2.0 path, the same way SupportedQueryFeatures already works. Binary encoding stays on by default.

Copilot AI balanced review requested due to automatic review settings September 10, 2026 21:52
@aavasthy
Arooshi Avasthy (aavasthy) requested a review from a team as a code owner September 10, 2026 21:52
@github-actions github-actions Bot added the Cosmos The azure_cosmos crate label Sep 10, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved moderate findings require wire-level response verification, emulator forwarding coverage, and related documentation updates.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR enables Cosmos binary-response negotiation over Gateway 2.0/thin-client requests using RNTBD token 0x00C4.

Changes:

  • Adds serialization-format token encoding and forwarding.
  • Updates emulator handling and transport/E2E tests.
  • Updates Gateway 2.0 and binary-encoding documentation.
File summaries
File Summary Review findings
sdk/cosmos/azure_data_cosmos/tests/gateway_v2_tests/gateway_v2_e2e.rs Adds Gateway 2.0 binary-encoding scenarios. Moderate (3 votes): Assert the raw 0x80 binary preamble; deserialization alone passes with text responses. Moderate (1 vote): Verify TransportKind::GatewayV2, not merely activity IDs. Nit (1 vote): Clarify that the accept-list does not guarantee a binary response. Moderate (1 vote): Validate the outbound token or raw backend response before page processing.
sdk/cosmos/azure_data_cosmos_driver/src/in_memory_emulator/gateway_v2.rs Handles the new token in the emulator. Moderate (1 vote): Preserve the binary-format flag through decode_request or add a Gateway 2.0 raw-response test.
sdk/cosmos/azure_data_cosmos_driver/src/driver/transport/rntbd/tokens.rs Defines token 0x00C4 and its mapping. No final findings.
sdk/cosmos/azure_data_cosmos_driver/src/driver/transport/rntbd/request.rs Tests token serialization round trips. No final findings.
sdk/cosmos/azure_data_cosmos_driver/src/driver/transport/gateway_v2_dispatch.rs Forwards and parses the serialization-format header. No final findings.
sdk/cosmos/azure_data_cosmos_driver/docs/GATEWAY_V2_SPEC.md Documents the Gateway 2.0 negotiation contract. Nit (2 votes): Add corresponding entries to both affected crate changelogs.
sdk/cosmos/azure_data_cosmos_driver/docs/BINARY_ENCODING_SPEC.md Updates binary-encoding feature status. Nit (1 vote): Remove “+ negotiation” from the deferred-status text. Nit (1 vote): Add release-note entries to both affected crate changelogs.
sdk/cosmos/azure_data_cosmos_driver/docs/BINARY_ENCODING_HLD.md Updates remaining work and parity status. No final findings.
Review details

Suppressed comments (7)

sdk/cosmos/azure_data_cosmos/tests/gateway_v2_tests/gateway_v2_e2e.rs:779

  • The assertion compares deserialized RichBinaryDoc values; it never compares the response bytes, and into_model accepts text as well as binary. This wording overstates what the test proves—either call it a decoded-value equality check or inspect the raw body before deserializing if byte-for-byte fidelity is required.
/// Writes a **rich, deeply-nested** document (see [`RichBinaryDoc`]) over
/// Gateway 2.0 with binary encoding enabled, then reads it back and asserts it
/// is byte-for-byte equal.

sdk/cosmos/azure_data_cosmos/tests/gateway_v2_tests/gateway_v2_e2e.rs:751

  • An activity ID is present on both Gateway V1 and Gateway 2.0 responses, so this loop does not verify that the query pages used the transport under test. A regression that routes the query through the standard gateway would still pass; use the same assert_transport_kind(..., TransportKind::GatewayV2) check used by the existing Gateway 2.0 query tests.
        assert!(
            !page.diagnostics().activity_id().as_str().is_empty(),
            "every binary-negotiated Gateway 2.0 query page must surface an activity-id",
        );

sdk/cosmos/azure_data_cosmos/tests/gateway_v2_tests/gateway_v2_e2e.rs:702

  • JsonText,CosmosBinary is an accept-list, and the driver contract explicitly allows the service to answer a query in text. Therefore this comment's claim that the accept-list 'so the feed returns binary' is not guaranteed; describe binary as a possible negotiated response, or make the test assert the raw response only when a wire capture confirms it.
/// Queries advertise a `JsonText,CosmosBinary` accept-list, so the feed returns
/// binary. Exercises the query leg: the same `0x00C4` token rides the request
/// and the binary feed decodes item-by-item back to the typed model.

sdk/cosmos/azure_data_cosmos/tests/gateway_v2_tests/gateway_v2_e2e.rs:752

  • The page/item assertions can all succeed with a text response if the new token is missing, and the query pipeline may re-encode its synthesized page afterward. This therefore does not prove that the service negotiated binary over the thin-client hop; validate the outbound 0x00C4 token and/or the raw backend response before page processing.
        assert!(
            !page.diagnostics().activity_id().as_str().is_empty(),
            "every binary-negotiated Gateway 2.0 query page must surface an activity-id",
        );
        for item in page.items() {

sdk/cosmos/azure_data_cosmos_driver/docs/BINARY_ENCODING_SPEC.md:71

  • The delivery-status follow-up later in this document still says query request-body encoding + negotiation is deferred. This update makes only query request-body encoding remain deferred, so please remove + negotiation there; otherwise the document contradicts the new status shown here.
| `query_items`                               |  — (text spec) |    decode     | ✅ done (response negotiated, standard gateway + Gateway 2.0) |

sdk/cosmos/azure_data_cosmos_driver/docs/BINARY_ENCODING_SPEC.md:88

  • This is a customer-visible transport behavior change, but the current Unreleased entries in azure_data_cosmos_driver/CHANGELOG.md:17 and azure_data_cosmos/CHANGELOG.md:18 still say Gateway 2.0 does not carry the negotiation header, and no replacement entries are added. Add release-note bullets for the affected driver and SDK crates before documenting the feature as complete.
Response negotiation is honored on **both** the standard gateway and the
Gateway 2.0 / thin-client path. On Gateway 2.0 the request is re-encoded as an
RNTBD metadata token list; the `x-ms-cosmos-supported-serialization-formats`
header is forwarded as the RNTBD `SupportedSerializationFormats` token
(`0x00C4`, Byte flags: `JsonText = 0x01`, `CosmosBinary = 0x02`,
`HybridRow = 0x04`), so the negotiation survives thin-client wrapping and the
service returns binary just as it does on the standard gateway.

sdk/cosmos/azure_data_cosmos_driver/src/in_memory_emulator/gateway_v2.rs:386

  • The hosted Gateway V2 emulator accepts this token and then discards it, so decode_request reconstructs an HTTP request without x-ms-cosmos-supported-serialization-formats and always produces text responses for this path. The existing binary-response tests cover direct gateway requests, not this thin-client wrapper, leaving the new Gateway V2 negotiation untested locally; preserve the CosmosBinary bit through the wrapper or add an explicit Gateway V2 raw-response test.
            RntbdRequestToken::SupportedSerializationFormats => {
                // Emulator doesn't model binary negotiation: validate the wire
                // type, ignore the value, always reply text.
                expect_byte(kind, token.value)?;
  • Files reviewed: 8/8 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.


let read_resp = container.read_item(&pk_value, &item_id, None).await?;
assert_transport_kind(&read_resp.diagnostics(), TransportKind::GatewayV2);
let read_item: GwV2TestItem = read_resp.into_model()?;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a dedicated test,  gateway_v2_binary_encoding_wire_format_differential , that reads the raw response body and asserts the  0x80  binary preamble (and contrasts it with a text body from a binary-disabled client on the same item).

@@ -345,6 +345,8 @@ Per Q3 resolution, the Gateway 2.0 proxy requires the header names `x-ms-thincli

**Tenant identification (RNTBD token, not HTTP header)**: the proxy identifies the target Cosmos account from the existing RNTBD `GlobalDatabaseAccountName` token (`0x00CE`, `String`, optional) carried inside the RNTBD metadata stream on **every** Gateway 2.0 request. No Gateway-2.0-specific HTTP headers are introduced for account or regional-account identification — the RNTBD token is the canonical carrier and matches the proxy wire contract. The value is the global database account name (e.g., `myacct` from `myacct.documents.azure.com`), parsed once from the account endpoint URL at client construction.

**Binary-response negotiation (RNTBD token, not HTTP header)**: the client advertises which serialization formats it accepts in responses via the `x-ms-cosmos-supported-serialization-formats` HTTP header (a string accept-list, e.g. `JsonText,CosmosBinary`). On the thin-client path this header is forwarded into the RNTBD metadata stream as the `SupportedSerializationFormats` token (`0x00C4`, `Byte`), where the value is the flags byte the backend parses that accept-list into: `JsonText = 0x01`, `CosmosBinary = 0x02`, `HybridRow = 0x04`, bitwise-OR-combinable (so `JsonText,CosmosBinary` → `0x03`). The token is omitted entirely when the header is absent or resolves to no known format (byte `0`), so behavior is unchanged when binary encoding is off. This is what lets point item ops (`create` / `read` / `replace` / `upsert`) and `query_items` receive `0x80`-prefixed binary responses on a Gateway 2.0 account, at parity with the standard gateway. The ID and byte values are pinned against the server catalog `RntbdRequestTokenIdentifiers_SupportedSerializationFormats` / `RntbdSupportedSerializationFormats`.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

# Conflicts:
#	sdk/cosmos/docs/specs/0014-binary-encoding-high-level-design.md
After merging main, the live thin-client binary query test raced the
proxy's query-routing propagation window (404/1003 OwnerResourceNotFound)
because it still used pre-refactor direct create_item/query_items calls.

Route seed writes through create_seed_item (retries the transient 401
MAC-signature window) and wrap the query drain in
retry_query_owner_not_found, matching main's refactored test infra.
Binary-specific decode assertions are preserved. All 3 live binary
e2e tests pass against the thin-client account.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@aavasthy

Copy link
Copy Markdown
Contributor Author

/azp run rust - cosmos - weekly

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@kundadebdatta Debdatta Kunda (kundadebdatta) moved this from Triage to Needs Attention in CosmosDB Rust SDK and Driver Sep 10, 2026
@kundadebdatta Debdatta Kunda (kundadebdatta) changed the title Enabling binary encoding with thinclient mode. Cosmos: Add Binary Encoding Support for Thinclient Mode Sep 10, 2026
@kundadebdatta

Copy link
Copy Markdown
Member

Binary encoding stays off by default, and nothing changes on the wire when it's off.

Above need to be corrected in the PR description. Binary encoding is enabled by default.

@aavasthy

Copy link
Copy Markdown
Contributor Author

/azp run rust - cosmos - weekly

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@tvaron3 Tomas Varon (tvaron3) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just some none blocking comments

metadata.query_version = Some(expect_small_string(kind, token.value)?)
}
RntbdRequestToken::SupportedSerializationFormats => {
// Emulator doesn't model binary negotiation: validate the wire

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

non blocking but I think it's worth adding especially because this will be the default behavior and will help further testing in other sdks

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the emulator now captures the  SupportedSerializationFormats  token and re-emits the negotiation header, so the shared dispatch returns a binary response (as it will be the default). Added a unit test covering it.

let seen_ids = retry_query_owner_not_found(|| async {
let query = Query::from("SELECT * FROM c");
let mut pages = container
.query_items::<GwV2TestItem>(query, FeedScope::partition(pk_value.clone()), None)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test coverage for cross partition queries would also be useful

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added  gateway_v2_binary_encoding_cross_partition_query_round_trip  — a binary-enabled  full_container()  query that seeds items across multiple physical partitions and asserts every item returns once and decodes.

@aavasthy
Arooshi Avasthy (aavasthy) force-pushed the users/aavasthy/thinclientbinaryencoding branch from 789f9fa to 5d78a95 Compare September 15, 2026 22:21
@aavasthy

Copy link
Copy Markdown
Contributor Author

/azp run rust - cosmos - weekly

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

binary-encoding Cosmos The azure_cosmos crate

Projects

Status: Needs Attention

Development

Successfully merging this pull request may close these issues.

4 participants