Gap
Core defines PaginatedMarketsResult.total and PaginatedEventsResult.total as required number fields. Both SDKs model them as optional, which means consumers who write result.total without a null-check have different runtime semantics depending on whether they use core directly or go through an SDK.
Core
core/src/BaseExchange.ts lines 411–429:
export interface PaginatedMarketsResult {
data: UnifiedMarket[];
total: number; // ← required
nextCursor?: string;
}
export interface PaginatedEventsResult {
data: UnifiedEvent[];
total: number; // ← required
nextCursor?: string;
}
total carries no ? and is not | undefined — the core contract is that every paginated response includes the count.
TypeScript SDK
sdks/typescript/pmxt/models.ts lines 240–263:
export interface PaginatedMarketsResult {
data: UnifiedMarket[];
total?: number; // ← optional (wrong)
nextCursor?: string;
}
export interface PaginatedEventsResult {
data: UnifiedEvent[];
total?: number; // ← optional (wrong)
nextCursor?: string;
}
Python SDK
sdks/python/pmxt/models.py lines 411–436:
@dataclass
class PaginatedMarketsResult:
data: List[UnifiedMarket]
total: Optional[int] = None # ← optional (wrong)
next_cursor: Optional[str] = None
@dataclass
class PaginatedEventsResult:
data: List[UnifiedEvent]
total: Optional[int] = None # ← optional (wrong)
next_cursor: Optional[str] = None
Evidence
core/src/BaseExchange.ts:416: total: number — no ?, no | undefined
core/src/BaseExchange.ts:427: total: number — same
sdks/typescript/pmxt/models.ts:245: total?: number
sdks/typescript/pmxt/models.ts:259: total?: number
sdks/python/pmxt/models.py:418: total: Optional[int] = None
sdks/python/pmxt/models.py:432: total: Optional[int] = None
Impact
- SDK consumers using
result.total to render pagination controls (e.g. "page 2 of 47") must guard against undefined/None even though core always sends the count. This produces unnecessary defensive code.
- TypeScript:
result.total has type number | undefined; arithmetic like Math.ceil(result.total / pageSize) silently produces NaN when total is omitted despite core guaranteeing it.
- Python:
result.total typed as Optional[int]; code like range(0, result.total, page_size) requires an explicit not-None check that the core contract makes unnecessary.
- Divergence from core weakens the SDK as a drop-in replacement for direct core usage.
Found by automated Core-to-SDK surface coverage audit
Gap
Core defines
PaginatedMarketsResult.totalandPaginatedEventsResult.totalas requirednumberfields. Both SDKs model them as optional, which means consumers who writeresult.totalwithout a null-check have different runtime semantics depending on whether they use core directly or go through an SDK.Core
core/src/BaseExchange.tslines 411–429:totalcarries no?and is not| undefined— the core contract is that every paginated response includes the count.TypeScript SDK
sdks/typescript/pmxt/models.tslines 240–263:Python SDK
sdks/python/pmxt/models.pylines 411–436:Evidence
core/src/BaseExchange.ts:416:total: number— no?, no| undefinedcore/src/BaseExchange.ts:427:total: number— samesdks/typescript/pmxt/models.ts:245:total?: numbersdks/typescript/pmxt/models.ts:259:total?: numbersdks/python/pmxt/models.py:418:total: Optional[int] = Nonesdks/python/pmxt/models.py:432:total: Optional[int] = NoneImpact
result.totalto render pagination controls (e.g. "page 2 of 47") must guard againstundefined/Noneeven though core always sends the count. This produces unnecessary defensive code.result.totalhas typenumber | undefined; arithmetic likeMath.ceil(result.total / pageSize)silently producesNaNwhentotalis omitted despite core guaranteeing it.result.totaltyped asOptional[int]; code likerange(0, result.total, page_size)requires an explicit not-None check that the core contract makes unnecessary.Found by automated Core-to-SDK surface coverage audit