feat!: spec sync 3.22.0 → 3.23.0 (v6.0.0) — drop multivariate lookup-history, additive drift fixes#466
Conversation
…history, additive drift fixes Reconciles the SDK with OpenAPI/AsyncAPI 3.23.0, resolving all 18 nightly strict contract-drift failures from #463. Breaking: Kalshi removed the GET /multivariate_event_collections/{ticker}/lookup endpoint (GetMultivariateEventCollectionLookupHistory) and the LookupPoint schema, so lookup_history() (sync + async) and LookupPoint are removed. Additive (backward-compatible): - ApiKey / CreateApiKeyRequest / GenerateApiKeyRequest: +subaccount - SubaccountTransfer: +exchange_index, +transfer_type, and position-only +market_ticker/+side/+count/+price_cents - ApplySubaccountTransferRequest: +exchange_index - MarginOrder: +order_reason; MarginPosition/MarginRiskPosition: +is_portfolio - MarketLifecyclePayload (WS): +price_ranges - Removed the stale Market.response_price_units drift exclusion Defensive (fields 3.23.0 removed/relaxed but the SDK still required — a latent parse-break the spec→SDK drift suite cannot catch): - Market.fractional_trading_enabled, MarketPosition.resting_orders_count, MarginPosition.margin_used → optional New 3.23.0 capabilities are tracked as follow-ups: #464 (position-transfer endpoint) and #465 (create-subaccount request body). Closes #463 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Code ReviewThis PR syncs the SDK to spec 3.23.0, cleanly removes the deleted `lookup_history` endpoint and `LookupPoint` model, and makes defensive optionalizations for three fields the spec removed or relaxed (`Market.fractional_trading_enabled`, `MarketPosition.resting_orders_count`, `MarginPosition.margin_used`). The removal of the `Market.response_price_units` exclusion is safe — the field is fully gone from the spec and the stale-exclusion test would have caught leaving it in. Overall a clean and well-reasoned drift sync. One confirmed bug: Bug: missing bounds validation on
|
Completes the 3.23.0 spec surface for the subaccounts resource — the two new capabilities #463 deferred as follow-ups. - transfer_position() (sync + async) → POST /portfolio/subaccounts/positions/transfer: moves an open position (contracts) between subaccounts, returns ApplySubaccountPositionTransferResponse (position_transfer_id). New models ApplySubaccountPositionTransferRequest / ...Response. - create(exchange_index=...) → the optional CreateSubaccountRequest body added to POST /portfolio/subaccounts. New CreateSubaccountRequest model. Registered both in CONTRACT_MAP / METHOD_ENDPOINT_MAP / BODY_MODEL_MAP so the drift suite validates them against the spec; added unit + integration coverage; exported the 3 new models; updated docs + CHANGELOG. Also corrected the subaccounts doc's cash-transfer example (transfer() returns None). Closes #464 Closes #465 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Code Review — v6.0.0 / spec 3.22.0 → 3.23.0Overall this is a clean spec-sync. The defensive optionalizations, contract-map registrations, and drift-test plumbing are all done correctly. A few issues worth addressing before merge. Bugs1. Duplicate The diff adds 2. Both have no default, meaning any response from a pre-3.23.0 server that omits them will raise a exchange_index: int | None = None
transfer_type: Literal["cash", "position"] | None = NoneMissing Validation3. No bounds on The spec declares Test Coverage Gaps4. No unit test for
5. No tests for new Three models got a new optional field with no new test cases. At minimum: a round-trip serialization test with 6. No negative test for
7. No unit test for The WS model addition has no test coverage. A simple parse test with 8. Whether Minor9. What's Good
|
Review response (PR #466 bot review): - api_keys: bound CreateApiKeyRequest/GenerateApiKeyRequest.subaccount to the spec's 0-63 range (ge=0, le=63); thread a `subaccount` kwarg through create()/generate() (sync + async) so it's settable without the request model. - tests: subaccount round-trip + out-of-range rejection (api keys, request + resource), async transfer_position happy-path, WS price_ranges parse/absent, and required-absence tests for SubaccountTransfer + MarginPosition. Kept the newly spec-required response fields (SubaccountTransfer.exchange_index / transfer_type, Margin*.is_portfolio) REQUIRED — this matches the repo's test_required_drift spec-required => SDK-required enforcement and the ROADMAP's stated "tighten toward required for reliably-sent fields" direction. The PR's optional-izations were only for fields the spec REMOVED/RELAXED (a different case). Docs (v6.0.0 readiness): - OpenAPI version bump v3.22.0 -> v3.23.0 (README, docs/index, CLAUDE). - api-keys.md (subaccount kwarg), subaccounts.md/multivariate.md (done earlier), reference.md (new request models), perps.md (is_portfolio / order_reason). - ROADMAP.md: v6.0.0 shipped entry + backfilled the v4.x/v5.x gap. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Thanks for the review. Addressed in 1. Duplicate 2. 3. Bounds on 4. Async 5. 6. 7. 8. 9. Separately, folded in #464 ( |
Code Review — PR #466 (spec sync 3.22.0 → 3.23.0, v6.0.0)This PR is a clean, well-structured spec sync. The removal of Two plausible correctness risks are worth resolving before merge, plus a minor test-thoroughness gap. Finding 1 —
|
Summary
Syncs the SDK to upstream OpenAPI/AsyncAPI 3.22.0 → 3.23.0 (v6.0.0). The headline change is breaking: Kalshi removed the multivariate lookup-history endpoint, so the SDK removes the matching method and model. Everything else is additive/defensive and backward-compatible. This PR resolves all 18 nightly strict contract-drift failures (#463) and implements the two new 3.23.0 subaccount capabilities (#464, #465), so the SDK adheres to 3.23.0 completely.
Changes
Breaking
multivariate_collections.lookup_history()(sync + async) and theLookupPointmodel — upstream deletedGET /multivariate_event_collections/{ticker}/lookup(GetMultivariateEventCollectionLookupHistory) and theLookupPointschema in 3.23.0.lookup_tickers()(PUT) is unaffected.New endpoints (3.23.0)
subaccounts.transfer_position(...)(sync + async) →POST /portfolio/subaccounts/positions/transfer— moves an open position between subaccounts; returnsApplySubaccountPositionTransferResponse. New modelsApplySubaccountPositionTransferRequest/...Response.subaccounts.create(exchange_index=...)—POST /portfolio/subaccountsgained an optionalCreateSubaccountRequestbody. NewCreateSubaccountRequestmodel.CONTRACT_MAP/METHOD_ENDPOINT_MAP/BODY_MODEL_MAPso the drift suite validates them against the spec; unit + integration coverage added; 3 new models exported fromkalshi/kalshi.models.Additive fields (backward-compatible)
ApiKey/CreateApiKeyRequest/GenerateApiKeyRequest:+subaccountSubaccountTransfer:+exchange_index,+transfer_type(cash/position), position-only+market_ticker/+side/+count/+price_centsApplySubaccountTransferRequest:+exchange_indexMarginOrder:+order_reason;MarginPosition/MarginRiskPosition:+is_portfolioMarketLifecyclePayload(WS):+price_rangesMarket.response_price_unitsdrift exclusionDefensive
ValidationErrorthe spec→SDK drift suite can't catch). Made optional:Market.fractional_trading_enabled,MarketPosition.resting_orders_count,MarginPosition.margin_used.Housekeeping
5.0.1 → 6.0.0; CHANGELOG,docs/migration.md,docs/resources/multivariate.md+docs/resources/subaccounts.mdupdated (incl. fixing a stale cash-transfer()example that printedresp.transfer_idthough it returnsNone). Regeneratedspecs/*+kalshi/_generated/models.py.Test plan
uv run pytest tests/ --ignore=tests/integration -q— 4123 passed, 3 skippeduv run ruff check .— cleanuv run mypy kalshi/— clean (157 files)tests/test_contracts.py) — green; new endpoints drift-validated against 3.23.0transfer_positionregistered (discovered == registered)tests/integration/) — not run (needs live demo creds; position-transfer smoke test skips gracefully when demo has no position)Notes for reviewers
specs/openapi.yamlre-serialization (upstream reformatted the file); the semantic spec deltas are small.Issue links
Closes #463
Closes #464
Closes #465