prediction: typed list-response envelopes for candlesticks + bulk endpoints (closes #404)#419
Conversation
…points (closes #404) Completes #404 (the perps half shipped in #418). The prediction-API list endpoints extracted their REQUIRED array with `data.get(key, [])`, silently masking spec drift on a missing key and TypeError-ing on a null array. Each now validates a typed envelope whose array field is `NullableList`: - markets.candlesticks -> GetMarketCandlesticksResponse{ticker, candlesticks} - markets.bulk_candlesticks -> BatchGetMarketCandlesticksResponse{markets} - markets.bulk_orderbooks -> GetMarketOrderbooksResponse{orderbooks} `NullableList` is the right model for the released API: a MISSING key hard-fails (ValidationError — surfaces drift, the #404 goal), while a NULL array coerces to [] (Kalshi's documented empty-as-null convention; the prior extraction would TypeError on null). The candlesticks envelope also validates the previously-discarded required `ticker`. All 3 envelopes registered in CONTRACT_MAP (drift-checked). Tests: missing key raises + null -> [] for all three (sync + async); candlesticks rejects a missing ticker. CHANGELOG "Changed" note added. mypy strict + ruff + full suite (3660) green. Note: the perps envelopes (#418) used a non-nullable list (hard-fail on null) per the issue's strict criteria; aligning them to NullableList — restoring the pre-#418 `or []` null tolerance — is a reasonable small follow-up.
Code Review — PR #419: Typed list-response envelopes (prediction)OverviewThis PR replaces silent Issues1. Missing async regression tests (actionable)
None of these appear in These three tests should be mirrored in 2. Null-handling inconsistency with perps (design concern)The PR description notes this directly, but it's worth flagging for the review record: perps endpoints (shipped in #418) use non-nullable list (null → hard fail), while these prediction endpoints use Minor Notes
What's Working Well
SummarySolid PR with one actionable gap: mirror the three new regression tests in 🤖 Generated with Claude Code |
…t) (#420) Follow-up to #418/#419. The perps list-response envelopes (markets/funding) used a non-nullable list — hard-failing on a null array per #404's strict wording — while the prediction envelopes (#419) use NullableList (null -> []). This restores the pre-#418 `or []` null tolerance and makes null-handling identical across both surfaces. `GetMarginMarketsResponse.markets`, `GetMarginMarketCandlesticksResponse.candlesticks`, `GetMarginHistoricalFundingRatesResponse.funding_rates`, and `GetMarginFundingHistoryResponse.funding_history` now use NullableList: a MISSING key still hard-fails (surfacing drift), a NULL array coerces to []. 3.2.0 is unreleased, so this refines the envelopes before release. Removed the now-unused `import builtins` from both model files. Tests updated: null -> [] instead of raising. mypy strict + ruff + 1140 perps/contract tests green.
Completes #404 — the prediction-API parity (the perps half shipped in #418). Closes #404.
The prediction list endpoints extracted their REQUIRED array with
data.get(key, []), which silently returned[]on a missing key (masking spec drift) and TypeError'd on a null array. Each now validates a typed envelope:markets.candlesticksGetMarketCandlesticksResponse{ticker, candlesticks}markets.bulk_candlesticksBatchGetMarketCandlesticksResponse{markets}markets.bulk_orderbooksGetMarketOrderbooksResponse{orderbooks}Why
NullableList(and not a bare list)This is released code, so the model is chosen for safety: the array field is
NullableList(required key,BeforeValidatorcoerces null→[]). That gives:ValidationError— surfaces drift (the resources: validate typed list-response envelopes for REQUIRED-array endpoints (perps + prediction) #404 goal), where the old code silently returned[];[]— Kalshi's documented "empty-as-null" convention (MarketCandlesticksalready notes this), and a strict improvement over the old code which TypeError'd on a null array;ticker.Verification
CONTRACT_MAPand pass the drift harness.[]on a null array; candlesticks rejects a missingticker. Existing candlesticks mocks updated to include the spec-requiredticker.mypy --strict+ruffclean; full suite 3660 passed.Follow-up note
The perps envelopes in #418 used a non-nullable list (hard-fail on null) per #404's strict "absent or null → raise" wording. Aligning them to
NullableList— restoring the pre-#418or []null tolerance and matching this PR — is a reasonable small follow-up if you want perps/prediction null-handling identical.🤖 Generated with Claude Code