Skip to content

Add guided sport and competitor config flow - #365

Draft
Chreece wants to merge 14 commits into
vasqued2:masterfrom
Chreece:guided-config-flow
Draft

Chreece wants to merge 14 commits into
vasqued2:masterfrom
Chreece:guided-config-flow

Conversation

@Chreece

@Chreece Chreece commented Aug 28, 2026

Copy link
Copy Markdown

Dependency

Depends on #364.

This PR is stacked directly on the current narrow #364 soccer/all fix
(9610957b33d18dd22e865925e6c3ab9e92f06112).

PR #364 does not introduce a new all-sports universal runtime. It remains
limited to the reproduced ESPN soccer/all gaps.

Summary

Add a guided sport → competitor → competition setup flow while keeping
Advanced / Custom API available.

The guided flow:

  1. chooses a sport;
  2. searches for a team or athlete;
  3. lets the user select the canonical ESPN competitor;
  4. offers verified competition choices plus All competitions;
  5. creates the Team Tracker entry.

Scope

This PR contains only guided setup/UI work:

  • custom_components/teamtracker/config_flow.py
  • custom_components/teamtracker/strings.json
  • translation catalogs
  • tests/test_config_flow.py
  • tests/test_config_flow_soccer_all_discovery.py
  • tests/test_guided_translations.py

It does not add or change runtime providers/parsers. TheSportsDB remains
separate in PR #369.

All competitions

The All competitions choice maps to Team Tracker's existing
league_path: all behavior.

This PR does not claim to expand ESPN/Team Tracker all runtime support to
every sport. Coverage remains dependent on the existing provider behavior and
what ESPN exposes for the selected sport.

For soccer, the missing aggregate-feed/setup cases are handled by the narrow
changes in PR #364.

Search behavior

Teams

  • discover current ESPN league paths for the chosen sport;
  • search league team collections;
  • deduplicate only by canonical numeric ESPN team ID;
  • preserve distinct IDs even when names are similar;
  • use conservative local fuzzy/transliteration matching.

Individual sports

Guided search supports Golf, MMA, Racing and Tennis.

  • ESPN search is used as a canonical identity source;
  • results are independently sport-checked;
  • numeric athlete IDs are extracted from ESPN identity data;
  • collection presence is not treated as proof of competition membership.

Competition choices

Specific competition choices are derived from real ESPN schedule/event
evidence for the selected competitor.

The All competitions option uses the existing runtime path described above;
it is not backed by a new universal provider in #364.

Translations

The guided UI includes the existing translation set shipped on this branch,
including Greek Όλες οι διοργανώσεις.

Status

This PR remains Draft while #364 is reviewed.

The branch has been rebuilt so its direct parent is the restored narrow #364
head and its own delta contains only config-flow, translations, and their
tests.

@Chreece
Chreece force-pushed the guided-config-flow branch 2 times, most recently from 92f6d26 to 0455622 Compare August 30, 2026 16:41
@Chreece

Chreece commented Sep 4, 2026

Copy link
Copy Markdown
Author

Rebased this guided setup flow on the reduced #364 implementation.

The flow still provides sport → competitor search → competition / All competitions, but no longer depends on the discarded universal ESPN runtime. Soccer discovery now reuses #364's live league discovery, numeric ESPN IDs stay internal, and athlete entries keep the human-name runtime format already supported upstream.

No parser, coordinator, sensor, provider-factory, or event-state changes are included. The updated config-flow regressions and full suite pass.

Of course it needs broader user testing...

irishpadres and others added 3 commits September 4, 2026 10:36
…rrent one

_async_get_team_schedule() derives derived_league_name (the last-resort
label used when a fallback-sourced match has neither altGameNote nor a
usable season slug) by looping over team.nextEvent and then
/schedule, unconditionally overwriting one shared variable on every
iteration with no date-relevance check. ESPN returns /schedule
newest-first, so "whichever event is processed last" is reliably the
oldest entry in the list - not the team's actual current competition.

Real example: AC Milan's /schedule right now has two 2026-27 Serie A
results at the top (8/28, 8/23) followed by four older 2026 Club
Friendly results (8/15 -> 7/25). derived_league_name silently computes
to "Club Friendly" for a team in the middle of Serie A play. Inter
Miami hits the same bug. This is worse than an empty label - it's a
confidently wrong one with no signal it's wrong.

Fix: collect every candidate event (from both sources) with a parsed
date, and pick whichever is closest to today - the nearest upcoming
one, or the most recent one if nothing is upcoming yet - instead of
"whatever's last in an API-ordered array".

Added two regression tests: one with a synthetic reconstruction of the
AC Milan schedule shape, one replaying the real captured API responses
verbatim (tests/tt/captures/espn-soccer-all-{team,schedule}-103-ac-
milan-20260904.json). Both confirmed to fail on unpatched code with
the exact "Club Friendly" result and pass with this fix.

Claude-Session: https://claude.ai/code/session_01JhjTRygQ6wJEtNaXkbMnCQ
Per review feedback on this PR: an event closer to today with no
usable season label (no displayName, no convertible slug) was still
being added to the candidate list, and since the nearest candidate
always wins, it could beat a farther-but-labeled event and produce an
empty derived_league_name where the previous code at least had
something.

Skip candidates with no usable name entirely instead of letting them
win on proximity. Also guard `event.get("season") or {}` against an
explicit `season: null`, which crashed the previous version of this
loop (pre-existing on the current vasqued2#364 head too, not introduced here,
per review).

Added three regression tests covering the differential cases from
review: unlabeled-nearer-past, unlabeled-nearer-future, and multiple
unlabeled-nearer candidates - all must still resolve to the farther
labeled event rather than "".

Claude-Session: https://claude.ai/code/session_01JhjTRygQ6wJEtNaXkbMnCQ
…nearest-event

Fix derived_league_name picking the oldest schedule event, not the current one
Restore only the provider and score regression tests from a679a3c. Both team.nextEvent and schedule fallback scores use ESPN displayValue, falling back to value, without mutating cached responses.

Do not restore the separate POST/PRE handoff or fallback-merging changes. Normal parsers, event selection, provider priority, guided setup and TheSportsDB remain unchanged.

Validation before publication: both original score regression tests fail against the audited deployed provider and pass against this provider; 24 additional dependency-isolated scalar/date/cache cases pass. These are synthetic-fixture static-provider checks, not a full Home Assistant suite or live API replay.
Carry PR vasqued2#364's score normalization and regression tests forward without changing the guided-flow delta or rewriting existing branch history.
Chreece added a commit to Chreece/ha-teamtracker that referenced this pull request Sep 13, 2026
Inherit PR vasqued2#364's ESPN score-only normalization via PR vasqued2#365. TheSportsDB-specific files and the branch's own provider isolation remain unchanged. Preserve existing history; do not restore the separate POST/PRE or fallback-merging changes.
@Chreece
Chreece force-pushed the guided-config-flow branch 4 times, most recently from 718aa6f to 9e6d120 Compare September 14, 2026 03:46
Carry PR vasqued2#364's verified match-day cache refresh, fallback score normalization, and API_LIMIT handoff regressions into vasqued2#365 without changing the guided-flow delta.
Chreece added a commit to Chreece/ha-teamtracker that referenced this pull request Sep 14, 2026
Inherit PR vasqued2#364's verified match-day cache refresh, fallback score normalization, and API_LIMIT POST/PRE handoff through vasqued2#365. TheSportsDB-specific delta remains unchanged.
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.

2 participants