Skip to content

Models drifted from wire: MiddleSide rejects live /opportunities/middles payloads; EVOpportunity.confidence_score never populates #18

Description

@Mlaz-code

Found by the docs-reality audit 2026-07-14 (report: DOCS_REALITY_AUDIT_2026-07-14.md at the docs.sharpapi.io repo root on dev; unit: top-concepts-sdks-examples; wire shapes independently re-verified against deployed sharp-api-go 84c92a4).

Two model↔wire mismatches in src/sharpapi/models.py:

1. MiddleSide (models.py:385) — raises ValidationError on every live middles response.

class MiddleSide(BaseModel):
    book: str
    selection: str
    line: float
    odds: OddsValue          # required nested object

The live API sends middle sides flatsportsbook (not book) and odds_american / odds_decimal / odds_probability / fair_probability (no nested odds object). Required fields book and odds are absent from real payloads, so client.middles() cannot parse a successful response at all → pydantic ValidationError.

2. EVOpportunity.confidence_score (models.py:277) — silently always None.

Wire field is confidence (int 0–100); there is no alias, so confidence_score: float | None = None never populates. Consumers filtering on opp.confidence_score get None for every row (silent, unlike #1).

Wire sample (live /api/v1/opportunities/ev?limit=1, trimmed):

{"confidence": 60, "sportsbook": "draftkings", "odds_american": -185, "odds_decimal": 1.541, "odds_probability": 0.6491, "fair_probability": 0.7407, "quality_tier": "B", }

Suggested fix: rename to confidence (or add a populate-by-alias), flatten MiddleSide to the wire contract, and add a recorded-fixture round-trip test against captured live payloads so model drift fails CI. Note the wire also now carries quality_tier ("A"/"B"/"C") on EV rows (shipped 2026-07-14) — worth adding to EVOpportunity in the same pass. The docs SDK pages mirror these model shapes and are being corrected in the docs audit's Wave 1; the SDK is the source the docs should follow, so this fix should land first. PyPI is immutable — needs a version bump + release.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions