Skip to content

TV completion can fork imported season identities and infer completion from sparse history #812

Description

@ryan-winkler

Summary

Completing a whole TV show can create a second season identity when an imported season already exists in another compatible library bucket. The duplicate can split the user's episode history and dates across two season rows.

The same completion path can also infer Completed from the highest episode number instead of the number of distinct completed episodes when release events are unavailable. For example, watching only episode 10 of a ten-episode season must not complete the season.

Reported impact

PR #760 reports an imported Breaking Bad library where seasons in the tv bucket held the user's April 2025 dates. Completing the show created new season-bucket rows and a second set of 62 episodes dated on the completion day. The original dates remained attached to the first rows.

Reproduction shape

  1. Import a TV show, its seasons, and episode history so each season Item uses the show's tv bucket.
  2. Keep the original episode dates on those rows.
  3. Mark the whole TV show as completed.
  4. TV._completed() resolves only the canonical completion bucket and creates a parallel Item/Season/episode set instead of reusing the compatible imported season.
  5. In a season with no release-event rows, set local_season_episode_count=10 and record only episode 10. A maximum-position comparison can mark the season completed even though nine episodes have no completed evidence.

Expected behavior

  • Reuse an existing season item only from a bucket that is compatible with the parent TV identity.
  • Never attach a normal TV completion to an anime-bucket season, or an anime completion to an unrelated TV identity.
  • Preserve existing Season, Episode, start-date, end-date, score, note, and history rows.
  • Use an atomic create path when no compatible season item exists.
  • Derive local completion from the count of distinct completed episodes, not the highest episode number.
  • Preserve a deliberate In progress status used for a rewatch.

Acceptance criteria

  • A TV-bucket imported season is reused when the matching TV show is completed.
  • No second season Item, Season, or episode set is created.
  • Existing watch dates remain attached and visible.
  • Normal TV and anime identity buckets cannot cross-attach.
  • Concurrent completion attempts converge without an avoidable create race or duplicate-key error.
  • One sparse late-episode watch does not complete the season.
  • All distinct completed episodes can complete a season when local_season_episode_count is authoritative.
  • A manual In progress rewatch remains In progress.
  • Focused model tests cover each case.
  • uv run --no-sync ruff check src and the affected model tests pass.

Relationships

Notes for contributors

The objective in #760 is valid. The implementation needs an allowed-bucket rule, the existing database-safe create behavior, and count-based completion evidence before it is safe to merge. This issue keeps those requirements in one place for the current contributor and future fixes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions