Skip to content

Decision needed: required-but-optional drift policy (22 REST + 12 WS models, ~190 field violations) #172

Description

@TexasCoding

test_required_drift (REST) and test_ws_required_drift (WS) fire warnings — not failures — when the spec marks a field required but the SDK keeps it Optional[T] | None with a None default. ~190 individual field instances across 34 model classes.

Until a policy is set, the warn flood masks new drift.

Why this matters

A field declared as Optional[T] | None with a None default misleads users in two directions:

  • mypy infers Optional[T] for callers, forcing pointless if x is not None narrowing on fields the server always sends.
  • Real null-on-the-wire goes unnoticed during testing because Pydantic accepts the None.

Affected models

Reproduce with pytest tests/test_contracts.py -W error::Warning -k 'required_drift'.

REST (22 models, ~134 fields):

Model Fields
Market 34
Order 17
MultivariateEventCollection 13
Fill 13
Settlement 9
Trade 8
Event 7
Series 7
MarketPosition 7
EventPosition 5
EventMetadata 3
Milestone 3
SportFilterDetails 2
IncentiveProgram, ApiKey, SeriesFeeChange, MarketCandlesticks, ScopeList, GetOrderGroupResponse, CreateOrderGroupResponse, CreateOrderRequest 1 each

WS (12 models, ~80 fields):

Payload Fields
UserOrdersPayload 18
FillPayload 14
TickerPayload 13
TradePayload 8
MarketPositionsPayload 7
QuoteExecutedPayload 7
QuoteCreatedPayload, QuoteAcceptedPayload 6 each
MultivariatePayload 4
RfqCreatedPayload, RfqDeletedPayload 3 each
OrderGroupPayload, MarketLifecyclePayload 1 each

Policy options

A. Tighten — drop None defaults on fields the server reliably sends. Requires confirming each field is actually-always-sent against the demo + prod APIs. Soft-breaking at construction sites (callers building these models in tests must add the field).

B. Allowlist — extend EXCLUSIONS in tests/_contract_support.py for fields the spec lies about. Documents the deviation but leaves the runtime type lax.

C. Hybrid — tighten the high-signal cases (top-level Market, Order, Fill, WS *Payloads), allowlist the long-tail with notes.

Recommendation

C (Hybrid). The top 5 models (Market, Order, Fill, UserOrdersPayload, TickerPayload) account for ~96 of ~190 violations and are the user-facing types where lying optional types hurt callers most. The rest are sub-models the user rarely instantiates — allowlist them with a typed EXCLUSIONS reason.

If C is chosen, this issue branches into:

  • A tightening PR per top-5 model (5 PRs, ~96 field changes, each soft-breaking at construction sites).
  • One sweep PR adding EXCLUSIONS entries for the remaining ~94 field instances with kind="server_omits_despite_required" and per-field demo+prod observation notes.

Acceptance

  • Maintainer decision recorded in the issue thread.
  • pytest tests/test_contracts.py -W error::Warning -k 'required_drift' passes.
  • test_required_drift and test_ws_required_drift promoted from warnings.warn to pytest.fail.
  • Any remaining deviations carry an EXCLUSIONS entry with kind="server_omits_despite_required" (new ExclusionKind) and a reason citing demo+prod observations.

Blocking

Needs maintainer decision (tighten vs. allowlist vs. hybrid) before code work starts. Once decided, the tightening pass is mechanical per-model.

Metadata

Metadata

Assignees

No one assigned

    Labels

    polishCode-quality and DX improvements; non-functionalquestionFurther information is requestedtestingTest coverage

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions