fix(ws-models): OrderbookDeltaPayload.ts AwareDatetime + envelope type Literal narrowing#365
Conversation
…iteral `OrderbookDeltaPayload.ts` was missed by the v2.5 #270 WS AwareDatetime sweep that closed the v2.4 #234 REST gap. Widen it to `AwareDatetime | None` so naive RFC3339 strings on the highest-volume WS channel raise `ValidationError` rather than silently passing as `str`, matching `user_orders` and `communications`. Narrow every WS message envelope's `type` field from bare `str` to its channel-specific `Literal[...]` across `OrderbookSnapshotMessage`, `OrderbookDeltaMessage`, `TickerMessage`, `FillMessage`, `UserOrdersMessage`, `MarketLifecycleMessage`, and `CommunicationsMessage`. The default-value form keeps no-arg construction ergonomics but constructing an envelope with a mismatched `type` string now raises `ValidationError`. This also unlocks `pydantic.Discriminator("type")` for the dispatcher's union without a follow-up wire-format change. Five `tests/ws/test_models.py` fixtures sent `"type": "user_orders"` (plural, channel name) where the wire `type` value per the dispatcher table is `"user_order"` (singular). Those fixtures are corrected to match the dispatch table that real frames go through. Closes #331, #353
Code Review — PR #365OverviewTwo focused spec-drift fixes:
The changes are minimal, surgical, and correct. The Code QualityStrengths:
One issue — test loop stops on first failure:
@pytest.mark.parametrize("cls,expected_type,ok_payload,bad_payload", [
(OrderbookSnapshotMessage, "orderbook_snapshot", {...}, {...}),
...
])
def test_issue_353_envelope_type_literal_narrowing(cls, expected_type, ok_payload, bad_payload):
...Not a blocker, but parametrized tests give much better failure messages. Potential IssuesAnnotation assertion is weak: annotation = cls.model_fields["type"].annotation
assert annotation is not str, f"{cls.__name__} still bare str"This confirms the field isn't bare from typing import get_args
assert get_args(annotation) == (expected_type,)Minor, but it closes a gap for free. Remaining Five more envelopes still carry
If there isn't already a tracking issue for these, opening one would keep the sweep visible. Behavioral Change RiskThe Security / PerformanceNo concerns. Pure model validation tightening. SummaryApprove with two non-blocking suggestions:
The core fix is correct, the test patterns match established conventions, and the |
Summary
Widen
OrderbookDeltaPayload.tstopydantic.AwareDatetime(closing the gap left by the v2.5 #270 WS datetime sweep) and narrow each WS envelope'stypefield from barestrto its channel-specificLiteral[...]. No wire-format change.Issues closed
OrderbookDeltaPayload.tsnow parses RFC3339 strings into tz-aware datetimes and rejects naive timestamps, matchinguser_orders/communications(Polish bundle: model small items (AwareDatetime in WS, V1 Literal, default=None, timestamp typing, Decimal NaN) #270).typefield is barestrwith a default — should be Literal #353 — WS envelopetypenarrowed toLiteral[<channel>]acrossOrderbookSnapshotMessage,OrderbookDeltaMessage,TickerMessage,FillMessage,UserOrdersMessage,MarketLifecycleMessage, andCommunicationsMessage; constructing an envelope with a mismatchedtypestring now raisesValidationErrorand unlockspydantic.Discriminator("type")for downstream dispatchers.Behavioral changes
OrderbookDeltaPayload.tsis nowAwareDatetime | None. Naive RFC3339 strings on this field now raiseValidationErrorinstead of silently parsing asstr. Aware RFC3339 strings continue to parse, but asdatetimeinstead ofstr.typeis now aLiteral. Five existingtests/ws/test_models.pyfixtures sent"type": "user_orders"(plural, channel name) where the dispatch table — and therefore the wiretypevalue — is"user_order"(singular). Those fixtures are corrected to match the dispatch table.Tests
tests/ws/test_models.py::TestIssue331OrderbookDeltaTsAwareDatetime— RFC3339 string parses to tz-aware datetime; naive string raisesValidationError.tests/ws/test_models.py::TestIssue353EnvelopeTypeLiteralNarrowing— All seven narrowed envelopes accept their own type literal and reject any other channel's literal;model_fields["type"].annotationis no longer barestr.test_delta_with_optional_fieldsassertion to compare against adatetimevalue.Source
Round-3 independent audit closure plan, wave W2.