feat: spec sync 3.20.0 → 3.21.0 + nightly drift issue automation#449
Conversation
Reconcile the SDK against upstream OpenAPI 3.21.0 (additive drift) and implement the four new 3.21.0 endpoints. Also close the nightly spec-drift CI gap: failures now open a tracking issue instead of failing silently between the weekly spec-sync runs. Drift fixes (additive): - events.list/list_all: `tickers` query param - communications quotes: `min_ts`/`max_ts` query params - perps MarginMarket: settlement/liquidation/reference mark prices (TickerPrice) - perps MarginPosition: required `subaccount` - WS ErrorPayload: `market_tickers` New endpoints (sync + async, tested): - client.communications.block_trade_proposals (list/list_all/create/accept) - account.volume_progress() Infra: - spec-drift.yml: open/dedup a tracking issue on scheduled failure (least-privilege permissions, SHA-pinned actions) - TestWsSpecDrift fixture -> @staticmethod (removes strict-mode 60-error cascade) - add _post_void for 204 endpoints; minimal_kwargs helper supports AwareDatetime Bump 4.0.0 -> 4.1.0; re-vendor specs; update CHANGELOG + doc banners. Verified: ruff, mypy (157 files), full suite (4308 passed, 3 skipped), nightly-strict contract mirror (670 passed). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Code Review — PR #449: spec sync 3.20.0 → 3.21.0 + nightly drift issue automationOverviewThis is a clean, well-structured spec-sync PR. All additions are additive (new endpoints, new fields on existing models), the dual sync/async pattern is followed consistently, and the drift machinery change is a real improvement. A few things worth flagging before merge. Positive notes
Issues to resolve before merge1. In uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
2. The updated spec changes: # before
enum: ['yes', 'no', 'scalar', 'void']
# after
enum: ['yes', 'no', 'scalar']The PR body calls all changes "additive," but this removes a value from a response-side enum. The 3. class TickerPrice(BaseModel):
price: DollarDecimal
ts_ms: int
model_config = {"extra": "allow", "populate_by_name": True}
4. Same observation — Minor observations (non-blocking)
SummaryThe implementation is solid and follows all project conventions. The two items worth resolving before merge are the 🤖 Generated with Claude Code |
- CHANGELOG: note upstream narrowing of Settlement.market_result enum (void removed); SDK uses plain str so no code change - drop dead populate_by_name from TickerPrice + BlockTradeProposal (no aliases, so it was a no-op) - add a missing-required-field test for ProposeBlockTradeRequest Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Code Review — PR #449: spec sync 3.20.0 → 3.21.0 + nightly drift issue automationOverviewThis PR syncs the SDK against OpenAPI v3.21.0 and AsyncAPI, adds four new endpoints ( Strengths
Issues / Concerns1. The underlying 2. Adding a required field to a response model is a compatibility break for any downstream user constructing 3. Block-trade models absent from The three new account-volume models are registered with generated counterparts: ContractEntry(sdk_model="kalshi.models.account.AccountVolumeProgress", ...)But none of the five new communications models appear. If there are no generated OpenAPI counterparts for the block-trade models, omitting them is correct — but a short comment in the map (or a line in the PR description) would make the absence clearly intentional rather than an oversight. 4. Spec YAML trailing space (cosmetic, vendored)
5. Shell MARKER hardening (low risk)
Minor Nits
SummaryThis is a well-executed spec sync. New endpoints follow established patterns exactly, test coverage is solid, and the CI automation is properly secured. The three substantive items (type annotation on 🤖 Generated with Claude Code |
- contract map: register BlockTradeProposal + the two block-trade request bodies in CONTRACT_MAP for response-side drift coverage (closes a gap vs the account-volume models; matches Quote/RFQ + CreateQuoteRequest pattern) - CHANGELOG: note MarginPosition.subaccount is now required (update mocks) - block_trade_proposals.create: type the caller-facing `expiration_ts` overload as `datetime | str` (impl stays Any so the AwareDatetime field still accepts strings under mypy) - spec-drift.yml: `readonly MARKER` for the dedup marker Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Code ReviewOverall this is a high-quality, well-structured spec-sync PR. The implementation is clean, conventions are followed throughout, and test coverage is solid. A few issues worth addressing before merge. Potential Breaking Change — Semver Concern
Adding a required field to a response model is a backward-incompatible change for any downstream code that constructs Given the field is spec-required and Kalshi will always include it in API responses, the real-world blast radius is limited to test code — but it's still a breaking change by contract. Recommend either bumping to 5.0.0 or declaring Missing
|
| Severity | Issue |
|---|---|
| 🔴 Consider | MarginPosition.subaccount required field is a breaking change; evaluate major bump |
| 🟡 Recommend | Add BlockTradeProposalStatusLiteral type alias for consistency |
| 🟡 Recommend | Verify actions/checkout SHA independently before merge |
| 🟢 Minor | _post_void Content-Type defensiveness |
| 🟢 Minor | Async test decorator inconsistency |
The core logic, model design, contract coverage, and CI improvements are all solid. Address the semver question and the status literal before merging.
…ds (#451) (#452) * fix: spec drift — settlement_sources on Event + lifecycle strike fields The live v3.21.0 spec gained fields after #449 synced it, redding the nightly strict contract run (#451): - EventData.settlement_sources (spec-required, nullable) → Event.settlement_sources, typed NullableList[SettlementSource] so a JSON null coerces to []. Mirrors EventMetadata/Series. SettlementSource moved above Event so the forward ref resolves under `from __future__ import annotations`. event_dict() fixture gains the required key. - marketLifecycleV2Payload.{strike_type,cap_strike,custom_strike} → MarketLifecyclePayload (all optional; present only on metadata_updated). specs/openapi.yaml: the freshly-fetched live spec also *transiently* dropped CreateOrder / BatchCreateOrders / AmendOrder (104→101 ops), which would red the body-drift tests for those endpoints. That is an upstream publishing glitch, not a real API change — so the committed openapi was kept at its known-good 104-op state and settlement_sources added surgically to EventData. specs/asyncapi.yaml was synced normally (additive strike fields + WS error-doc refinements; no dropped channels). Verified: ruff clean, mypy clean, strict nightly contract suite (-W error::UserWarning) green, full unit suite 4315 passed / 3 skipped. Closes #451 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test: cover settlement_sources coercion + lifecycle strike fields Addresses the PR #452 review (claude[bot]): add unit coverage for the new fields rather than relying on the contract suite alone. - TestEventSettlementSources: null -> [] coercion, typed SettlementSource list parsing, and required-key enforcement. - TestMarketLifecycleStrikeFields: the asyncapi 'between' example (strike_type + floor_strike + cap_strike + custom_strike) and the default-None path on non-metadata events. - Tighten the Event.settlement_sources comment: only Series mirrors the nullable shape; EventMetadata's field is a plain list (not nullable). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Spec sync from upstream OpenAPI v3.20.0 → v3.21.0 plus implementation of the four new 3.21.0 endpoints, and closes the nightly spec-drift CI gap.
Why
The nightly Spec Drift Detection workflow has been failing since upstream moved to 3.21.0, but no issue was being created — issue-filing lived only in the weekly Weekly Spec Sync (Mondays only). This PR fixes the drift and wires the nightly job to open a tracking issue on failure.
Drift fixes (all additive)
events.list/list_all—tickersfiltercommunicationsquotes —min_ts/max_tsMarginMarket—settlement_mark_price/liquidation_mark_price/reference_price(nestedTickerPrice)MarginPosition— requiredsubaccountErrorPayload—market_tickersNew endpoints (sync & async, fully tested)
client.communications.block_trade_proposals—list/list_all/create/accept(+ 5 models)account.volume_progress()(+ 3 models)Infra
spec-drift.yml: areport-failurejob opens (and dedups on a stable marker) aspec-drifttracking issue on scheduled failure; least-privilegepermissions, SHA-pinned actionsTestWsSpecDriftfixture →@staticmethod(removes the 60-error cascade under-W error::UserWarning)_post_voidtransport helper for 204 endpoints;minimal_kwargstest helper supportsAwareDatetimeRelease
4.0.0 → 4.1.0, re-vendored specs, CHANGELOG## 4.1.0, doc banners → v3.21.0 / 104 operationsVerification
uv run ruff check .✓uv run mypy kalshi/✓ (157 files)pytest tests/test_contracts.py -W error::UserWarning): 670 passed🤖 Generated with Claude Code