Drift
When a server payload has an explicit null for marketA/marketB, TypeScript's r.marketA || {} fallback still produces a fully-shaped (if empty) UnifiedMarket object via convertMarket({}). Python's _parse_market returns its input unchanged when it's neither a UnifiedMarket nor a dict, so r.get("marketA", {}) — which only substitutes the default when the key is absent, not when it's null — lets an explicit null flow straight through as None.
TypeScript SDK
sdks/typescript/pmxt/router.ts:615-616:
marketA: convertMarket(r.marketA || {}),
marketB: convertMarket(r.marketB || {}),
Python SDK
sdks/python/pmxt/router.py:642-643:
market_a=_parse_market(r.get("marketA", {})),
market_b=_parse_market(r.get("marketB", {})),
_parse_market (sdks/python/pmxt/router.py:28-34) returns its input unchanged when it's neither a UnifiedMarket nor a dict.
Expected
Both SDKs should produce the same type for market_a/market_b given the same wire payload — either both fall back to an empty market object, or both preserve None.
Impact
ArbitrageOpportunity.market_a/market_b is None in Python vs. a market-shaped object in TypeScript for the same payload. Any code doing opportunity.market_a.title crashes with AttributeError in Python but not in TypeScript. This is distinct from existing issue #1535, which is scoped to numeric/venue field defaulting on this same method, not the market-object type itself.
Found by automated SDK cross-language drift audit
Drift
When a server payload has an explicit
nullformarketA/marketB, TypeScript'sr.marketA || {}fallback still produces a fully-shaped (if empty)UnifiedMarketobject viaconvertMarket({}). Python's_parse_marketreturns its input unchanged when it's neither aUnifiedMarketnor adict, sor.get("marketA", {})— which only substitutes the default when the key is absent, not when it'snull— lets an explicitnullflow straight through asNone.TypeScript SDK
sdks/typescript/pmxt/router.ts:615-616:Python SDK
sdks/python/pmxt/router.py:642-643:_parse_market(sdks/python/pmxt/router.py:28-34) returns its input unchanged when it's neither aUnifiedMarketnor adict.Expected
Both SDKs should produce the same type for
market_a/market_bgiven the same wire payload — either both fall back to an empty market object, or both preserveNone.Impact
ArbitrageOpportunity.market_a/market_bisNonein Python vs. a market-shaped object in TypeScript for the same payload. Any code doingopportunity.market_a.titlecrashes withAttributeErrorin Python but not in TypeScript. This is distinct from existing issue #1535, which is scoped to numeric/venue field defaulting on this same method, not the market-object type itself.Found by automated SDK cross-language drift audit