canonicalize datastream wire payloads to camelCase#130
Merged
Conversation
…jects
The WASM rules engine accepts either casing per field via serde aliases,
but rejects an object carrying both casings of the same field ("duplicate
field"). syncEntitlementDerivedFields wrote snake_case credit_remaining
next to the canonicalized creditRemaining, so one partial credit_balances
update made every subsequent flag check for that company fall back to its
default value.
Write the camelCase field instead, and canonicalize incoming partial
metrics/entitlements via the Fern serializers so merged entities keep a
single shape. Adds wasm-datastream.test.ts, which exercises the full
wire -> canonicalize -> merge -> evaluate path against the real engine.
cbrady
reviewed
Jun 3, 2026
cbrady
approved these changes
Jun 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Run incoming DataStream company/user/flag payloads through the Fern serializers (
parseOrThrow) on ingest instead of casting the raw wire object, so the cache holds a single canonical camelCase shape. Unknown keys usepassthroughso a server running ahead of the pinned SDK keeps its entity (known fields canonicalized, unknown fields retained) rather than being dropped.merge.tsis simplified accordingly: partial updates write camelCase fields directly, dropping the dual camel/snakegetPropreads, and nested objects arriving in partials (metrics, entitlements) are canonicalized on merge.Canonicalization surfaced a casing bug in the entitlement sync:
syncEntitlementDerivedFieldswrote snake_casecredit_remainingnext to the canonicalizedcreditRemaining, and the WASM rules engine rejects an object carrying both casings of one field ("duplicate field") — so a single partial credit-balance update made every subsequent flag check for that company fall back to its default value. The sync now writes the camelCase field.The wire format from the API is snake_case (rulesengine v0.1.16 json tags) and the WASM engine (rulesengine/v0.2.0) accepts either casing per field via serde aliases, so both the old snake cache and the new camelCase cache evaluate correctly — only mixed-casing objects break. New
wasm-datastream.test.tsexercises the full wire → canonicalize → merge → evaluate path against the real engine in CI, including the partial-metrics flag flip and the credit-balance regression.