release: 3.1.0 — spec sync 3.19.0 → 3.20.0 (events.fee_changes, is_block_trade, WS event_fee_update)#386
Conversation
… WS event_fee_update Syncs OpenAPI + AsyncAPI snapshots to v3.20.0 (#385). Upstream re-published 3.20.0 with extra additive changes after the drift issue was filed, so the OpenAPI checksum in #385 is stale; the AsyncAPI checksum still matches. New surface - events.fee_changes() / fee_changes_all() (sync + async) for the new paginated GET /events/fee_changes; EventFeeChange model. Both override fields are present-but-None when an override is cleared. - is_block_trade query param on markets.list_trades / list_all_trades (+ legacy list_trades_all) and historical.trades / trades_all. - Trade.is_block_trade — new spec-required, non-nullable bool response field. - WebSocket event_fee_update message on the existing market_lifecycle_v2 channel (EventFeeUpdateMessage / EventFeeUpdatePayload). subscribe_market_lifecycle now yields MarketLifecycleMessage | EventFeeUpdateMessage; channel count stays 11. Spec relaxations that need no facade change (audited) - CreateOrderV2Request.client_order_id relaxed to optional upstream; SDK keeps it required by design for V2 idempotency (docstring clarified). - EventData.product_metadata relaxed to optional; retired the now-obsolete server_omits_despite_required exclusion (spec and SDK now agree). - New ApiKeyScope / FeeType enums; SDK keeps str for forward-compat. Housekeeping - Version 3.0.1 → 3.1.0; CHANGELOG, README + docs banners (99 operations, OpenAPI v3.20.0); regenerated kalshi/_generated/models.py (gitignored). - Tests: unit (events fee_changes sync+async, is_block_trade serialization, Trade field parse/missing, WS dispatch set+cleared), contract drift + WS drift, and live integration coverage for the new methods. Closes #385 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Code Review — PR #386: release 3.1.0 (spec sync v3.19.0 → v3.20.0)OverviewClean, well-scoped spec sync. Four changes from upstream (new Code Quality & Conventions ✅All new code follows project conventions:
Potential Issues1. Behavioral breaking change on The return type change from # Code written against 3.0.x — will raise AttributeError at runtime now
# if an event_fee_update message arrives on the channel:
async for msg in client.ws.subscribe_market_lifecycle():
print(msg.msg.market_ticker) # EventFeeUpdatePayload has no market_tickerThis is correctly documented in the CHANGELOG and PR body, and the 3.1.0 minor bump is defensible since 2.
3. Minor: The field is added as an SDK extension (not in the AsyncAPI schema), which is fine. But the docstring says "NO required seq" without explaining why the field is present at all. A one-liner like Test Coverage ✅Thorough:
One small observation: Security ✅No security concerns. No new auth paths, no user input passed unsanitized. SummaryThe spec sync itself is solid and the implementation is clean. The two actionable items before merging:
Item 1 is a correctness/ergonomics issue; item 2 is optional polish. Everything else looks good to merge. |
- EventFeeUpdateMessage.seq: inline comment explaining it's accepted-if-present for forward-compat/parity (server doesn't emit it). (review item 3) - docs/websockets.md: promote the event_fee_update callout to a migration warning with a discriminate-on-.type example (naive .msg.market_ticker access raises AttributeError). (review item 1) - CHANGELOG: add the same behavioral note for changelog-only readers. Not changed: EventFeeUpdateMessage/Payload stay in kalshi.ws.models (review item 2). No WS message/payload models are exported top-level — REST models (EventFeeChange) are top-level by convention, WS models live under kalshi.ws.models. Promoting only these two would be inconsistent. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Thanks for the review — addressed in acaffba. Item 1 (migration note) — done. Promoted the Item 3 ( Item 2 (top-level export) — verified, no change (the premise doesn't hold). No WS message/payload models are exported from the top-level The integration-pagination observation is fair — the live |
|
Code Review: PR 386 - release 3.1.0 spec sync. Two substantive items: (1) missing is_block_trade serialization test for historical.trades - the markets test covers it but _historical_trades_params is a separate path; (2) Trade.is_block_trade as required with no default is a breaking change for hand-rolled Trade fixtures, worth a Breaking note in CHANGELOG even at minor version. Minor: populate_by_name inconsistency between EventFeeUpdatePayload (WS, has it) and EventFeeChange (REST, missing it) - no-op since neither has aliases but inconsistent with WS model convention. What is good: dispatch routing is correct (MESSAGE_MODELS keyed by type, not channel), False param preservation via _bool_param tested, product_metadata exclusion cleanup is clean, contract map entries present for both new models, WS migration warning is actionable, seq forward-compat choice is well-reasoned, 3011 tests passing. |
Summary
OpenAPI + AsyncAPI spec sync v3.19.0 → v3.20.0,
Closes #385.The audited change set is broader than the issue's headline: upstream re-published
3.20.0with three extra additive changes after the drift issue was filed, so the OpenAPI checksum in #385 is stale (a37111…→ liveb72a2a…). The AsyncAPI checksum still matches (2f72d0…). All changes below were found via a structural diff of the live specs against the committed snapshots, not just the issue body.New public surface
GET /events/fee_changes(paginated)events.fee_changes()/events.fee_changes_all()(sync + async) +EventFeeChangemodelis_block_tradequery param on/markets/trades+/historical/tradesmarkets.list_trades/list_all_trades/list_trades_allandhistorical.trades/trades_allTrade.is_block_traderesponse fieldis_block_trade: bool(strict — missing key raises)event_fee_updatemessage on the existingmarket_lifecycle_v2channelEventFeeUpdateMessage/EventFeeUpdatePayload;subscribe_market_lifecycle()now yieldsMarketLifecycleMessage | EventFeeUpdateMessageEventFeeChange/EventFeeUpdatePayloadcarryfee_type_overrideandfee_multiplier_override, both present-but-Nonewhen an override is cleared. Channel count stays 11 —event_fee_updateis a second message type on an existing channel, not a new channel.Spec relaxations that need no facade change (audited, intentional)
CreateOrderV2Request.client_order_idrelaxed to optional upstream — SDK keeps it required by design for V2 idempotency (docstring clarified). Body-drift compares wire names only, so no test impact.EventData.product_metadatarelaxed to optional — retired the now-obsoleteserver_omits_despite_requiredexclusion (spec and SDK now agree; the field staysdict | Nonebecause the demo server still omits it, guarded bytest_parses_when_server_omits_product_metadata).ApiKeyScope/FeeTypeenums — SDK keepsscopes/fee_typeasstrfor forward-compat.Housekeeping
pyproject.toml,kalshi/__init__.py).docs/index.mdbanners → 99 operations, OpenAPI v3.20.0.kalshi/_generated/models.py(gitignored, local reference only).CLAUDE.mdAPI-reference line.Test plan
ruff check .clean ·mypy kalshi/strict clean (78 files)fee_changes(sync+async happy/filter/limit-bound/paginate),is_block_tradeserialization (true/false/omitted),Trade.is_block_tradeparse + missing-raises, WSevent_fee_updatedispatch (override set + cleared).EventFeeUpdatePayloadexercised by additive/required/coverage/field-type checks).GET /events/fee_changesvalidated live against the demo API.historicalintegration tests (demo server returning HTTP 500 on/historical/*) and 4from_envtests (local.envleak; verified green with.envabsent, i.e. the CI environment).🤖 Generated with Claude Code