tests/test_contracts.py::TestPerpsRequestParamDrift::test_sync_params_match_spec[candlesticks] PASSED [ 79%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_sync_params_match_spec[list1] PASSED [ 79%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_sync_params_match_spec[list_all] PASSED [ 79%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_sync_params_match_spec[get1] PASSED [ 80%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_sync_params_match_spec[cancel] PASSED [ 80%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_sync_params_match_spec[list2] PASSED [ 80%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_sync_params_match_spec[get2] PASSED [ 80%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_sync_params_match_spec[delete] PASSED [ 80%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_sync_params_match_spec[positions] PASSED [ 80%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_sync_params_match_spec[fills] PASSED [ 80%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_sync_params_match_spec[fills_all] PASSED [ 81%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_sync_params_match_spec[trades] PASSED [ 81%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_sync_params_match_spec[trades_all] PASSED [ 81%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_sync_params_match_spec[balance] PASSED [ 81%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_sync_params_match_spec[risk] PASSED [ 81%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_sync_params_match_spec[notional_risk_limit] PASSED [ 81%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_sync_params_match_spec[fee_tiers] PASSED [ 82%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_sync_params_match_spec[api_limits] PASSED [ 82%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_sync_params_match_spec[rate_estimate] PASSED [ 82%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_sync_params_match_spec[historical_rates] PASSED [ 82%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_sync_params_match_spec[history] PASSED [ 82%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[status] PASSED [ 82%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[enabled] PASSED [ 82%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[risk_parameters] PASSED [ 83%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[list0] PASSED [ 83%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[get0] PASSED [ 83%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[orderbook] PASSED [ 83%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[candlesticks] PASSED [ 83%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[list1] PASSED [ 83%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[list_all] PASSED [ 83%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[get1] PASSED [ 84%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[cancel] PASSED [ 84%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[list2] PASSED [ 84%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[get2] PASSED [ 84%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[delete] PASSED [ 84%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[positions] PASSED [ 84%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[fills] PASSED [ 85%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[fills_all] PASSED [ 85%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[trades] PASSED [ 85%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[trades_all] PASSED [ 85%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[balance] PASSED [ 85%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[risk] PASSED [ 85%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[notional_risk_limit] PASSED [ 85%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[fee_tiers] PASSED [ 86%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[api_limits] PASSED [ 86%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[rate_estimate] PASSED [ 86%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[historical_rates] PASSED [ 86%]
tests/test_contracts.py::TestPerpsRequestParamDrift::test_async_params_match_spec[history] PASSED [ 86%]
tests/test_contracts.py::TestPerpsRequestBodyDrift::test_body_properties_match_spec[create0] PASSED [ 86%]
tests/test_contracts.py::TestPerpsRequestBodyDrift::test_body_properties_match_spec[decrease] PASSED [ 87%]
tests/test_contracts.py::TestPerpsRequestBodyDrift::test_body_properties_match_spec[amend] PASSED [ 87%]
tests/test_contracts.py::TestPerpsRequestBodyDrift::test_body_properties_match_spec[create1] PASSED [ 87%]
tests/test_contracts.py::TestPerpsRequestBodyDrift::test_body_properties_match_spec[update_limit] PASSED [ 87%]
tests/test_contracts.py::TestPerpsRequestBodyDrift::test_body_properties_match_spec[transfer_instance] PASSED [ 87%]
tests/test_contracts.py::TestPerpsRequestBodyDrift::test_body_properties_match_spec[transfer_subaccount] PASSED [ 87%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[ExchangeStatus] PASSED [ 87%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[MarginEnabledResponse] PASSED [ 88%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[GetMarginRiskParametersResponse] PASSED [ 88%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[MarginMarket] PASSED [ 88%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[MarginMarketSchedule] PASSED [ 88%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[MarginMarketCandlestick] PASSED [ 88%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[BidAskDistributionHistorical] PASSED [ 88%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[PriceDistributionHistorical] PASSED [ 88%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[GetMarginMarketsResponse] PASSED [ 89%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[GetMarginMarketCandlesticksResponse] PASSED [ 89%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[CreateMarginOrderResponse] PASSED [ 89%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[MarginOrder] PASSED [ 89%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[GetMarginOrderResponse] PASSED [ 89%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[GetMarginOrdersResponse] PASSED [ 89%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[CancelMarginOrderResponse] PASSED [ 90%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[DecreaseMarginOrderResponse] PASSED [ 90%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[AmendMarginOrderResponse] PASSED [ 90%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[OrderGroup] PASSED [ 90%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[GetOrderGroupResponse] PASSED [ 90%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[CreateOrderGroupResponse] PASSED [ 90%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[MarginPosition] PASSED [ 90%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[GetMarginPositionsResponse] PASSED [ 91%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[MarginFill] PASSED [ 91%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[MarginTrade] PASSED [ 91%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[MarginSubaccountBalance] PASSED [ 91%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[GetMarginBalanceResponse] PASSED [ 91%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[MarginRiskPosition] PASSED [ 91%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[GetMarginRiskResponse] PASSED [ 91%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[NotionalRiskLimitResponse] PASSED [ 92%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[GetMarginFeeTiersResponse] PASSED [ 92%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[AccountApiLimits] PASSED [ 92%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[MarginFundingRate] PASSED [ 92%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[MarginFundingHistoryEntry] PASSED [ 92%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[MarginFundingRateEstimate] PASSED [ 92%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[GetMarginHistoricalFundingRatesResponse] PASSED [ 93%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[GetMarginFundingHistoryResponse] PASSED [ 93%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[IntraExchangeInstanceTransferResponse] PASSED [ 93%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[CreateSubaccountResponse] PASSED [ 93%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[margin_reports] PASSED [ 93%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[active_obligation] PASSED [ 93%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[active_obligations] PASSED [ 93%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[obligation_history] PASSED [ 94%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[obligation_history_all] PASSED [ 94%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[settlement_estimate] PASSED [ 94%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[settlement_estimate_by_asset_class] PASSED [ 94%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[settlement_balance] PASSED [ 94%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[guaranty_fund_balance] PASSED [ 94%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[settlement_balance_history] PASSED [ 95%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[settlement_balance_history_all] PASSED [ 95%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[settlement_balance_withdrawal] PASSED [ 95%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[margin_reports] PASSED [ 95%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[active_obligation] PASSED [ 95%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[active_obligations] PASSED [ 95%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[obligation_history] PASSED [ 95%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[obligation_history_all] PASSED [ 96%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[settlement_estimate] PASSED [ 96%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[settlement_estimate_by_asset_class] PASSED [ 96%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[settlement_balance] PASSED [ 96%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[guaranty_fund_balance] PASSED [ 96%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[settlement_balance_history] PASSED [ 96%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[settlement_balance_history_all] PASSED [ 96%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[settlement_balance_withdrawal] PASSED [ 97%]
tests/test_contracts.py::TestPerpsScmRequestBodyDrift::test_body_properties_match_spec[withdraw_settlement_balance] PASSED [ 97%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[MarginReport] PASSED [ 97%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[GetMarginReportsResponse] PASSED [ 97%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[ObligationReceiveInfo] PASSED [ 97%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[SettlementDetail] PASSED [ 97%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[MaintenanceMarginDetail] PASSED [ 98%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[ObligationEntry] PASSED [ 98%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[GetActiveMarginObligationResponse] PASSED [ 98%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[GetActiveMarginObligationsResponse] PASSED [ 98%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[MarketSettlementEstimate] PASSED [ 98%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[SettlementEstimate] PASSED [ 98%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[GetSettlementEstimateResponse] PASSED [ 98%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[AssetClassSettlementEstimate] PASSED [ 99%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[GetSettlementEstimateByAssetClassResponse] PASSED [ 99%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[GetSettlementBalanceResponse] PASSED [ 99%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[GetGuarantyFundBalanceResponse] PASSED [ 99%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[WithdrawSettlementBalanceResponse] PASSED [ 99%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[GetSettlementBalanceWithdrawalResponse] PASSED [ 99%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[SettlementBalanceHistoryEntry] PASSED [100%]
=================================== FAILURES ===================================
___________________ test_every_spec_endpoint_is_mapped[core] ___________________
spec_loader = <function _load_spec at 0x7f7c46cc2de0>
endpoint_map = [MethodEndpointEntry(sdk_method='kalshi.resources.markets.MarketsResource.list', http_method='GET', path_template='/ma...rkets.MarketsResource.list_trades', http_method='GET', path_template='/markets/trades', request_body_schema=None), ...]
label = 'core'
@pytest.mark.parametrize(
("spec_loader", "endpoint_map", "label"),
[
(_load_spec, METHOD_ENDPOINT_MAP, "core"),
(_load_perps_spec, PERPS_METHOD_ENDPOINT_MAP, "perps"),
(_load_perps_scm_spec, PERPS_SCM_METHOD_ENDPOINT_MAP, "perps_scm"),
],
ids=["core", "perps", "perps_scm"],
)
def test_every_spec_endpoint_is_mapped(
spec_loader: Any,
endpoint_map: list[MethodEndpointEntry],
label: str,
) -> None:
"""Fail if a spec operation is neither mapped nor explicitly unimplemented.
Closes the false-negative gap where a newly-ADDED upstream endpoint shipped
untested because nothing asserted spec paths ⊆ ``METHOD_ENDPOINT_MAP``. The
reverse direction (a map entry whose path the spec dropped) is caught by the
param-drift tests, which fail loud when the path is absent from the spec.
"""
spec_ops = _spec_operations(spec_loader())
mapped = {(e.http_method.upper(), e.path_template) for e in endpoint_map}
unmapped = spec_ops - mapped - set(_UNIMPLEMENTED_ENDPOINTS)
if unmapped:
> pytest.fail(
f"{label}: spec operations not in the endpoint map (add a "
f"MethodEndpointEntry, or record in _UNIMPLEMENTED_ENDPOINTS with a reason):\n"
+ "\n".join(f" - {m} {p}" for m, p in sorted(unmapped))
)
E Failed: core: spec operations not in the endpoint map (add a MethodEndpointEntry, or record in _UNIMPLEMENTED_ENDPOINTS with a reason):
E - GET /historical/positions
tests/test_contracts.py:1299: Failed
=============================== warnings summary ===============================
tests/test_contracts.py::TestSpecDrift::test_additive_drift[HistoricalCutoff]
/home/runner/work/kalshi-python-sdk/kalshi-python-sdk/tests/test_contracts.py:837: AdditiveOptionalDriftWarning: Additive-optional drift in kalshi.models.historical.HistoricalCutoff: Spec field 'market_positions_last_updated_ts' has no SDK mapping
_warn_additive_optional(entry.sdk_model, additive_optional)
tests/test_contracts.py::TestAdditiveDriftClassification::test_optional_drift_survives_the_nightly_strict_gate
/home/runner/work/kalshi-python-sdk/kalshi-python-sdk/tests/test_contracts.py:988: AdditiveOptionalDriftWarning: Additive-optional drift in tests.synthetic.Fake: Spec field 'opt_new' has no SDK mapping
_warn_additive_optional("tests.synthetic.Fake", msgs)
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[GetSettlementEstimateResponse]
/home/runner/work/kalshi-python-sdk/kalshi-python-sdk/tests/test_contracts.py:2088: AdditiveOptionalDriftWarning: Additive-optional drift in kalshi.perps.klear.models.margin.GetSettlementEstimateResponse: Spec field 'omitted_subtrader_count' has no SDK mapping
_warn_additive_optional(entry.sdk_model, additive_optional)
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[AssetClassSettlementEstimate]
/home/runner/work/kalshi-python-sdk/kalshi-python-sdk/tests/test_contracts.py:2088: AdditiveOptionalDriftWarning: Additive-optional drift in kalshi.perps.klear.models.margin.AssetClassSettlementEstimate: Spec field 'omitted_subtrader_count' has no SDK mapping
_warn_additive_optional(entry.sdk_model, additive_optional)
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_contracts.py::test_every_spec_endpoint_is_mapped[core] - Failed: core: spec operations not in the endpoint map (add a MethodEndpointEntry, or record in _UNIMPLEMENTED_ENDPOINTS with a reason):
- GET /historical/positions
============ 1 failed, 661 passed, 4 warnings in 243.66s (0:04:03) =============
Nightly strict contract tests failed
The scheduled
Spec Drift Detectionrun found the SDK contract suite no longer matches upstream OpenAPI/AsyncAPI.To resolve: locally run
uv run python scripts/sync_spec.py+uv run python scripts/generate.py, reconcile models/maps, and open a PR withCloses #<this issue>. This tracker auto-closes on the next green scheduled run.To silence while a reconcile is in flight, add the
spec-drift-acklabel — nightly runs then stop commenting until the failing set changes.Failing test output (last 200 lines)