Skip to content

docs(opportunities): reality-audit — flat envelopes + live-verified field contracts for ev/arbitrage/middles/low-hold#276

Merged
Mlaz-code merged 6 commits into
mainfrom
docs/audit-piece-opportunities
Jul 2, 2026
Merged

docs(opportunities): reality-audit — flat envelopes + live-verified field contracts for ev/arbitrage/middles/low-hold#276
Mlaz-code merged 6 commits into
mainfrom
docs/audit-piece-opportunities

Conversation

@Mlaz-code

Copy link
Copy Markdown
Collaborator

What this carries

The opportunities piece of the 2026-06-26 docs reality-audit (origin/docs/audit-2026-06-26-fixes), cherry-picked onto main and then re-verified against the live API on 2026-07-02:

Audit commit Page
406dc54 opportunities-ev — flat envelope + correct field contract
72b1147 opportunities-arbitrage — flat envelope; fix leg fields; drop CSV no-op
caa1d8d opportunities-middles + opportunities-middles-summary — flat envelope + flat sides; rewrite fictional summary
906bd7d opportunities-low-hold — flat envelope + flat sides; remove phantom deep_links

Plus one new commit (010113c) fixing drift found during today's live re-verification. The WIP commit 83fb982 touches none of this family's pages, so no WIP hunks apply here.

Live verification (2026-07-02, direct backend)

Endpoint Result
GET /opportunities/ev (Pro+) Verified + drift-fixed. Envelope/pagination (incl. next_cursor) match. Live rows carry fields the page missed — display_selection, market_id, partner_fair_probability, cross_ref_count/cross_ref_dispersion, single_sharp_period, est_correction_s, is_alternate_line, conditional team_side/market_segment — now documented. Example replaced with a verbatim live 2-row response. Filters spot-checked live (min_ev, devig_book=circa, sort modes); tier gate (ev = pro+) and 401/429 shapes verified against tiers.go/ratelimit.go.
GET /opportunities/arbitrage (Hobby+) Verified + drift-fixed. Row + leg field sets match the live response exactly. 10% profit cap confirmed live (max 9.82 across 200 rows); min_profit filter works; engine default floor 0.5 confirmed (min live profit 0.53 with no param). Added the working state param (default pa, appends ?state= to leg deep_links — verified live) and completed the warnings vocab (HIGH_PROFIT_SUSPICIOUS, LIVE_STALE_ODDS observed live/in engine). Example replaced with a verbatim live response.
GET /opportunities/middles (Pro+) Verified + drift-fixed. Warning thresholds had drifted: HIGH_PROBABILITY fires above 35% (doc said 15%) and STALE_ODDS above 300s (doc said 30s) — both confirmed empirically (82 live rows in (0.15,0.35] carry no flag; 133 rows aged 30–300s carry no flag) and against pkg/middlesengine/compute.go. Documented live-present alt_side1/alt_side2/is_team_total/team_name/worst_case_pnl. Re today's mlb calibration merge (0.65→0.58): no doc example hardcoded a stale probability claim; the middle_probability description now names the per-sport calibration explicitly. Example replaced with a verbatim live response that genuinely trips all three warnings.
GET /opportunities/middles/summary Verified. {data:{total, by_sport, by_league}, updated_at} with {count, avg_quality_score, avg_expected_value} buckets matches live exactly; example replaced with a verbatim live ?sport=baseball response. Stale "~250ms cache" note corrected (reads the same in-process engine result).
GET /opportunities/middles/:id Verified. Fresh id returns {data, updated_at}; unknown id → 404 not_found (note: ids churn fast — an expired id also 404s).
GET /opportunities/low_hold (Pro+) Verified + drift-fixed. Row + side field sets match live exactly. state param removed (no deep links on this endpoint → verified no-op), examples de-stated; documented the live 308 Permanent Redirect from /low-hold and /lowhold to the canonical /low_hold. Default hold-ascending sort and max_hold filter confirmed live. Example replaced with a verbatim live response.
All four 401 missing_api_key shape verified live; 403 tier_restricted + tier mapping (ev/middles/low_hold = pro+, arbitrage = hobby+) verified against tiers.go; 429 limits (hobby 120/min, pro 300/min) verified against ratelimit.go.

Cross-cutting drift fixed

The "New (May 2026)" nested reference blocks (home/away/sport_ref/league_ref/market_ref/sportsbook_ref) are not emitted on any opportunities endpoint today — 0/200 live EV rows, 0 arb legs, 0 middle sides; the EV/arb/middles engine structs carry no ref fields, so addNestedRefs is a no-op on these paths. They ARE live on /odds for atlas-mapped books. All three pages now mark these blocks Reserved — not currently emitted on this endpoint instead of claiming every row carries them.

Validation

  • All 5 changed files compile with the repo's own @mdx-js/mdx 3.1.1 (compile(), docs#271 verifier pattern).
  • Code fences balanced; frontmatter intact.
  • Scope: only the en pages of the opportunities family. openapi.json / openapi-version.json / sitemap.xml / account-keys.mdx untouched (owned by the final spec piece). Commit 9a9af03 is NOT part of this piece.

Follow-up

  • i18n backfill needed for de/es/pt-BR: all five en pages changed; the localized counterparts still carry the pre-audit content.
  • Do not merge yet — part of the staged docs reality-audit landing.

Type: docs

sharp-resolver[bot] and others added 6 commits July 2, 2026 14:09
Fixes audit C7/H18/H19/H20 + MED/LOW (verified vs live :3003):
- envelope {success, ..., meta:{source,summary,filters}} -> flat
  {data, pagination, updated_at}; pagination gains count/total/next_cursor;
  remove the fictional Meta Summary section + JS meta.count/meta.summary reads
- field renames: game_id->event_id, market->market_type, game->event_name,
  confidence_score->confidence (JSON rows, schema, prose, intro callout)
- devig_method value is UPPERCASE (POWER), not "power"
- 401 unauthorized -> missing_api_key/invalid_api_key; 403 feature_required ->
  tier_restricted (+tier/required_tier); 429 retry_after = Unix-ms
- drop non-existent deprecated aliases ev_percent / devig_book; note circa is
  also used as a sharp anchor; document emitted fields odds_probability,
  sportsbooks[], deep_link
- group event_name uses "Away @ Home"

`market` query param kept (real filter alias). EN only; locales tracked separately.

Type: docs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…V no-op

Fixes audit C8/H21/H22 + MED/LOW (verified vs live :3003):
- envelope {success, ..., meta:{source,summary,filters,books_analyzed}} -> flat
  {data, pagination, updated_at}; pagination gains count/total; JS stops reading meta
- leg implied_probability -> odds_probability; remove leg timestamp (not emitted);
  document emitted leg fields odds_id, deep_link, line
- top-level: document emitted estimated_net_profit_percent, league_label, market_label
- remove format=csv param + CSV Format section (S4 #4, approved no-op)
- 401 unauthorized -> missing_api_key/invalid_api_key; 403 +tier/required_tier;
  429 retry_after = Unix-ms; nested-ref logo host -> cdn.sharpapi.io; X-Request-Id

EN only; de/es/pt-BR backfill tracked separately.

Type: docs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ional summary

Fixes audit C9/H23/H24/H25 + MED/LOW (verified vs live :3003):
middles (list):
- envelope {success, ..., meta:{count,total,source,pagination,summary,filters}} ->
  flat {data, pagination, updated_at}
- side1/side2 nested odds:{american,decimal,probability,fair_probability} -> FLAT
  odds_american/odds_decimal/odds_probability/fair_probability; remove side deep_link
  (not emitted); document side selection_id/market_id/external_event_id
- min_size param is a no-op -> documented min_profit (filters roi_percentage) (S4 #5);
  size-based advice now points at sort=middle_size
- detail endpoint returns {data, updated_at} and 404 for unknown/malformed id
- document market_label/league_label; 401/403 codes; logo host; X-Request-Id

middles-summary (C9):
- response body was wholly fictional -> real {data:{total, by_sport, by_league}},
  each bucket {count, avg_quality_score, avg_expected_value}; rewrite examples +
  field table; drop success/meta; cache note 10s -> ~250ms; 401/403 codes

EN only; de/es/pt-BR backfill tracked separately.

Type: docs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…tom deep_links

Fixes audit H26 + MED/LOW (verified vs live :3003):
- envelope {success, ..., meta:{source,summary,filters}} -> flat
  {data, pagination, updated_at}; pagination gains count
- side1/2/3 nested odds:{american,decimal,implied_probability,fair_probability}
  -> FLAT odds_american/odds_decimal/odds_probability/fair_probability
- remove per-side deep_links {book:url} (never emitted) + the deep-links callout
  and Best-Practice claim; document side selection_id/market_id/external_event_id
- document row market_label/league_label
- 401 unauthorized -> missing_api_key/invalid_api_key; 403 +tier/required_tier;
  429 retry_after = Unix-ms; X-Request-Id format

EN only; de/es/pt-BR backfill tracked separately.

Type: docs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… corrected thresholds, reserved ref blocks

Re-verified all four opportunity endpoints (+ middles summary/detail)
against the live API on top of the 2026-06-26 audit commits:

- All five Success(200) examples replaced with verbatim live responses
  (captured 2026-07-02), so every field name/shape shown is real.
- middles: HIGH_PROBABILITY threshold is >35% (not 15%) and STALE_ODDS
  is >300s (not 30s) — both confirmed empirically against live rows
  (82 rows in (0.15,0.35] carry no flag; 133 rows aged 30-300s carry
  no flag). Documented alt_side1/alt_side2, is_team_total, team_name,
  worst_case_pnl; middle_probability now notes the per-sport
  calibration (refreshed 2026-07-02, mlb totals 0.65->0.58).
- ev: documented always-present fields the page missed
  (display_selection, market_id, partner_fair_probability,
  cross_ref_count/dispersion, single_sharp_period, est_correction_s,
  is_alternate_line) + conditional team_side/market_segment/
  is_suspended; fixed X-Request-Id example format; noted the ~0.1%
  engine EV floor.
- arbitrage: documented the working `state` query param (default pa,
  appends ?state= to leg deep_links — verified live) and completed the
  warnings vocab (HIGH_PROFIT_SUSPICIOUS, LIVE_STALE_ODDS).
- low_hold: dropped the `state` param row + examples (no deep links on
  this endpoint -> no-op, verified); documented the 308 redirect from
  /low-hold and /lowhold to the canonical /low_hold path.
- all: the "New (May 2026)" nested ref blocks (home/away/*_ref) are
  NOT emitted on any opportunities endpoint today (0/200 live EV rows,
  0 arb legs, 0 middle sides; engines carry no ref fields) — re-marked
  Reserved/not-currently-emitted; they are live only on /odds for
  atlas-mapped books.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- middles: worst_case_pnl is the RAW worst-case PnL (positive on
  guaranteed-profit middles); worst_case_loss is the same value clamped
  to <= 0 — they diverge on every guaranteed-profit middle (live:
  worst_case_loss=0, worst_case_pnl=5.77, GUARANTEED_PROFIT). Source:
  pkg/middlesengine/compute.go WorstCaseLoss=min(0,x) vs WorstCasePnl=x.
- arbitrage: LOW_IMPLIED_TOTAL marked Reserved / not currently emitted —
  the in-process arbengine never stamps it (0 of 12 qualifying 2-leg
  <96% rows in fresh live sample; stamping exists only in legacy
  transforms.go path).
- arbitrage: leg deep_link typed string|null (was string|undefined) —
  key is always present, explicit null when absent (59/59 live legs
  carry the key: 54 valued, 5 null, 0 omitted).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Mlaz-code Mlaz-code merged commit aeaf6dc into main Jul 2, 2026
@Mlaz-code Mlaz-code deleted the docs/audit-piece-opportunities branch July 2, 2026 18:56
@Mlaz-code

Copy link
Copy Markdown
Collaborator Author

Merge gate (auto-classified): gate=docs — auto-classified by the gate-log enforcer (14min after merge, no Merge gate: audit comment found). Reviewer agent: please correct if wrong by replying with Merge gate: gate=<correct-word> — <evidence>. The audit log keys on the first such token; your correction overrides this auto-classified guess.

Posted by scripts/gate-log-enforcer.py because instruction-level rules about the gate= template aren't binding (0/N adoption); structural enforcement fills the log either way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant