tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[CreateOrderGroupResponse] PASSED [ 87%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[MarginPosition] PASSED [ 87%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[GetMarginPositionsResponse] PASSED [ 87%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[MarginFill] PASSED [ 87%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[MarginTrade] PASSED [ 88%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[MarginSubaccountBalance] PASSED [ 88%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[GetMarginBalanceResponse] PASSED [ 88%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[MarginRiskPosition] PASSED [ 88%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[GetMarginRiskResponse] PASSED [ 88%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[NotionalRiskLimitResponse] PASSED [ 88%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[GetMarginFeeTiersResponse] PASSED [ 88%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[AccountApiLimits] PASSED [ 89%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[MarginFundingRate] PASSED [ 89%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[MarginFundingHistoryEntry] PASSED [ 89%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[MarginFundingRateEstimate] PASSED [ 89%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[GetMarginHistoricalFundingRatesResponse] PASSED [ 89%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[GetMarginFundingHistoryResponse] PASSED [ 89%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[IntraExchangeInstanceTransferResponse] PASSED [ 89%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[CreateSubaccountResponse] PASSED [ 90%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[CreateMarginFCMSubtraderRequest] PASSED [ 90%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[CreateMarginFCMSubtraderResponse] PASSED [ 90%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[FCMSubtraderRiskControls] PASSED [ 90%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[GetFCMSubtraderRiskControlsResponse] PASSED [ 90%]
tests/test_contracts.py::TestPerpsSpecDrift::test_response_drift[UpdateFCMSubtraderRiskControlsRequest] PASSED [ 90%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[margin_reports] PASSED [ 90%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[active_obligations] PASSED [ 91%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[obligation_history] PASSED [ 91%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[obligation_history_all] PASSED [ 91%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[settlement_details] PASSED [ 91%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[settlement_details_all] PASSED [ 91%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[maintenance_margin_details] PASSED [ 91%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[maintenance_margin_details_all] PASSED [ 91%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[funding_payments] PASSED [ 92%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[funding_payments_all] PASSED [ 92%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[settlement_estimate_by_asset_class] PASSED [ 92%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[settlement_balance] PASSED [ 92%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[guaranty_fund_balance] PASSED [ 92%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[settlement_balance_history] PASSED [ 92%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[settlement_balance_history_all] PASSED [ 92%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[settlement_balance_withdrawal] PASSED [ 93%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[list_subtrader_groups] PASSED [ 93%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_sync_params_match_spec[delete_subtrader_group] PASSED [ 93%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[margin_reports] PASSED [ 93%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[active_obligations] PASSED [ 93%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[obligation_history] PASSED [ 93%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[obligation_history_all] PASSED [ 93%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[settlement_details] PASSED [ 94%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[settlement_details_all] PASSED [ 94%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[maintenance_margin_details] PASSED [ 94%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[maintenance_margin_details_all] PASSED [ 94%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[funding_payments] PASSED [ 94%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[funding_payments_all] PASSED [ 94%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[settlement_estimate_by_asset_class] PASSED [ 94%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[settlement_balance] PASSED [ 95%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[guaranty_fund_balance] PASSED [ 95%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[settlement_balance_history] PASSED [ 95%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[settlement_balance_history_all] PASSED [ 95%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[settlement_balance_withdrawal] PASSED [ 95%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[list_subtrader_groups] PASSED [ 95%]
tests/test_contracts.py::TestPerpsScmRequestParamDrift::test_async_params_match_spec[delete_subtrader_group] PASSED [ 95%]
tests/test_contracts.py::TestPerpsScmRequestBodyDrift::test_body_properties_match_spec[withdraw_settlement_balance] PASSED [ 96%]
tests/test_contracts.py::TestPerpsScmRequestBodyDrift::test_body_properties_match_spec[create_subtrader_group] PASSED [ 96%]
tests/test_contracts.py::TestPerpsScmRequestBodyDrift::test_body_properties_match_spec[update_subtrader_group] PASSED [ 96%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[MarginReport] PASSED [ 96%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[GetMarginReportsResponse] PASSED [ 96%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[ObligationReceiveInfo] PASSED [ 96%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[SettlementDetail] PASSED [ 96%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[MaintenanceMarginDetail] PASSED [ 97%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[FundingPaymentDetail] PASSED [ 97%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[ObligationEntry] PASSED [ 97%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[GetActiveMarginObligationsResponse] PASSED [ 97%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[GetObligationSettlementDetailsResponse] PASSED [ 97%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[GetObligationMaintenanceMarginDetailsResponse] PASSED [ 97%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[GetObligationFundingPaymentsResponse] PASSED [ 97%]
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[AssetClassSettlementEstimate] PASSED [ 98%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[GetSettlementEstimateByAssetClassResponse] PASSED [ 98%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[GetSettlementBalanceResponse] PASSED [ 98%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[GetGuarantyFundBalanceResponse] PASSED [ 98%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[WithdrawSettlementBalanceResponse] PASSED [ 98%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[GetSettlementBalanceWithdrawalResponse] PASSED [ 99%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[SettlementBalanceHistoryEntry] PASSED [ 99%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[MarginSubtraderGroup] PASSED [ 99%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[GetMarginSubtraderGroupsResponse] PASSED [ 99%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[CreateMarginSubtraderGroupRequest] PASSED [ 99%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[CreateMarginSubtraderGroupResponse] PASSED [ 99%]
tests/test_contracts.py::TestPerpsScmSpecDrift::test_response_drift[UpdateMarginSubtraderGroupRequest] PASSED [100%]
=================================== FAILURES ===================================
___________________ test_every_spec_endpoint_is_mapped[core] ___________________
spec_loader = <function _load_spec at 0x7f4f07b931a0>
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 /live_data/weather/{city}
E - GET /portfolio/target_balance_allocation
E - POST /portfolio/target_balance_allocation
tests/test_contracts.py:1299: Failed
__________________ test_every_spec_endpoint_is_mapped[perps] ___________________
spec_loader = <function _load_perps_spec at 0x7f4f077760c0>
endpoint_map = [MethodEndpointEntry(sdk_method='kalshi.perps.resources.exchange.PerpsExchangeResource.status', http_method='GET', pat...urce.orderbook', http_method='GET', path_template='/margin/markets/{ticker}/orderbook', request_body_schema=None), ...]
label = 'perps'
@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: perps: spec operations not in the endpoint map (add a MethodEndpointEntry, or record in _UNIMPLEMENTED_ENDPOINTS with a reason):
E - DELETE /margin/cross/positions/{ticker}/exit_trigger
E - DELETE /margin/cross/positions/{ticker}/exit_trigger/{trigger_id}
E - DELETE /margin/isolated/positions/{ticker}/exit_trigger
E - GET /margin/cross/positions/{ticker}/exit_trigger
E - GET /margin/isolated/positions/{ticker}/exit_trigger
E - PUT /margin/cross/positions/{ticker}/exit_trigger
E - PUT /margin/cross/positions/{ticker}/exit_trigger/{trigger_id}
E - PUT /margin/isolated/positions/{ticker}/exit_trigger
tests/test_contracts.py:1299: Failed
=============================== warnings summary ===============================
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)
-- 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 /live_data/weather/{city}
- GET /portfolio/target_balance_allocation
- POST /portfolio/target_balance_allocation
FAILED tests/test_contracts.py::test_every_spec_endpoint_is_mapped[perps] - Failed: perps: spec operations not in the endpoint map (add a MethodEndpointEntry, or record in _UNIMPLEMENTED_ENDPOINTS with a reason):
- DELETE /margin/cross/positions/{ticker}/exit_trigger
- DELETE /margin/cross/positions/{ticker}/exit_trigger/{trigger_id}
- DELETE /margin/isolated/positions/{ticker}/exit_trigger
- GET /margin/cross/positions/{ticker}/exit_trigger
- GET /margin/isolated/positions/{ticker}/exit_trigger
- PUT /margin/cross/positions/{ticker}/exit_trigger
- PUT /margin/cross/positions/{ticker}/exit_trigger/{trigger_id}
- PUT /margin/isolated/positions/{ticker}/exit_trigger
============= 2 failed, 695 passed, 1 warning in 270.42s (0:04:30) =============
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)