# 140 — Handoff (state of the work on 2026-10-01, written so another agent can continue alone)

Read first: `000-index.md` (board, rules), `docs/plan/skin-milionar/000-index.md` "Current state", `AGENTS.md`.
User talks Czech, wants short factual answers; **targeted tests only, never the full skin baseline**; no commits.

## 1. Phases

| Phase | State | Evidence |
|-------|-------|----------|
| L0 store, meta cache, urls, fixture provider, unit harness | done, user OK | 030 §6 |
| L1 canonical play URL, resolver, service tracker, mirror into Kodi | done, user OK (movie + episode tracked for real) | 040 §7, §7a |
| L2 next-episode logic, autoplay, collection offer, refresher | **done, user OK 2026-10-01 (real source tested)** | 050 §6, §6b |
| L3 My movies / My series native listings | **done, user OK 2026-10-01** (listings.py, fast path, buttons on top, library look) | 060 §6 |
| L4 Home rows | **done, user OK 2026-10-01** (rows.py, slots; widget manager reworked 2026-10-02, awaiting user test) | 070 §5, §6 |
| L5 context menu everywhere | **done, user OK 2026-10-01** (menu.py, ctx.py, touchpoints) | 080 §4, 090 |
| L6 acceptance | **done, user OK 2026-10-01** (feature doc written) | 120 §5 |

Tests: `python3 -m unittest discover -s scripts/library_harness -p 'test_*.py'` -> 92 green (offline, Kodi
stubs in `scripts/library_harness/stubs.py`, one set of fake modules per process). Live helper:
`scripts/library_harness/live.py` (setup / play / stop / state), fixture provider = local ffmpeg videos
(`make_media.py`, `make_fixtures.py`), harness ops `addon_setting` and `call` (service code needs
`kodi_live.py restart`; the service caches imported modules).

## 2. The open problem (L2 failed in the user's real test)

The user played Black Mirror S01E01 (TMDb 42009) from My series and seeked to the very end: **no countdown, the
episode ended, nothing followed.** Causes found:

1. **Duplicated TMDb data** (the user is rightly angry): My series entries hold only a snapshot (id, name,
   overview, poster, year, rating), no seasons / episodes; the old listings (`TMDbClient.display_series_seasons`,
   `display_season_episodes`) call TMDb **live on every open, with no cache**; the new `meta` cache
   (`library.db`, `tv:<id>`, `season:<id>:<n>`) is filled only by the new code. Result: the data is fetched twice
   and the new cache is often empty at play time.
2. **Bug (fixed in code):** L0 seeded `meta` with the partial list entries (`seed_legacy`), so `tv:42009` existed
   without `seasons` -> `autoplay.plan` returned `none`. Removed the seeding, `tmdb._cached(..., complete=...)` now
   refetches entries that lack `seasons` / `episodes` / `genres` / `parts`, 14 partial rows purged from the user's DB,
   fixtures got `genres`.
3. **Late plan (fixed in code, untested live):** the plan was computed at the countdown point (network + all seasons),
   so a seek to the end could not make it. `tracker.Engine` now prefetches the plan at playback start
   (`_prefetch_worker` -> event `autoplay_prefetch`), uses it at once at the countdown point and `_follow_up()` starts
   the next episode (or notifies "vyjde ..." / "Seriál dokoukán") at the natural end even when the dialog never ran;
   it respects `autoplay_enabled_global`.

## 3. Decisions the user made just now (record in 900-decisions.md when implemented)

- **One TMDb data source for series: `meta` in `library.db`.** The two old listings must read and write it
  **now, as a small fix** (not waiting for L3), so opening a series in My series fills the cache autoplay uses and
  nothing is downloaded twice.
- **Unify everything**: also move the old `wcs/metadata/TMDbCache.py` users to `meta` and retire the old
  `tmdb_cache.json`. Users today: `wcs/ui/UI.py:1014`, `wcs/ui/dialogs/DialogWcsMyList.py:18`,
  `wcs/search/title_aliases.py`, `wcs/metadata/CSFDClient.py`, `wcs/metadata/TMDbLogo.py` (logo, aliases, details
  dialogs). Bigger change in finished dialogs -> do it as its own step with a regression check of each touched
  dialog (one capture / one scenario each).

## 4. Next steps in order

**Status 2026-10-01 (later): steps 1-4 below are done except the user's real test; see 050 §6b.** Next: L3 (060, read §0 first). Rules learned: never open the old My list dialog (`DialogWcsMyList`, not part of the new skin) in live tests (memory `feedback-never-open-old-mylist-dialog`); the user does not use a terminal, explain without commands.

1. Add the missing unit tests for the prefetch / `_follow_up` behaviour in `test_autoplay.py`: plan prefetched at
   start (nothing shown before the countdown), seek to the very end still plays the next episode once and counts
   watched once, plan missing at the end is computed then, autoplay off does nothing at the end. In the helper
   `start()` pump the event queue after `handle('started')`. (A previous edit of that file did not apply.)
2. Hook `display_series_seasons` / `display_season_episodes` (TMDbClient.py ~590-920) to
   `wcs.library2.tmdb.show / season` (write what they download into `meta`, read from it when complete).
3. Migrate the `TMDbCache` users above to `meta` (keys per 030 §3 plus a generic key space for logos / aliases /
   details), delete `tmdb_cache.json` handling afterwards; update 030 and 010.
4. Re-test live with the fixture provider (restart Kodi first): scenarios 4 and 5 from 120 §3 and a seek to the end
   (see 050 §6), then ask the user to repeat the real test: **My series -> an episode -> seek to the last minute ->
   countdown -> the next episode starts without the source dialog**; also Cancel and Dismiss.
5. After the user's "L2 OK": L3 (060). L3 must build the season / episode listings from `meta` with the canonical
   play URLs (this also fixes the user's complaints that the resume state differs between context menus: today only
   Kodi's own bookmark for the old `tmdb_episode_search` URL shows "Pokračovat od ...", movie items have no state,
   the skin's Continue row has no addon context menu - all planned in L3 / L4 / L5, 080).

## 5. Facts an agent must know

- Kodi crashes when Back is pressed while a plugin directory script runs (race in Kodi, 060 §0): L3 listings
  must use the `main.py` fast path (no router import) and read `meta` (inline fetch only for never-seen data, 030 §3). Reproducing it with scripted keys failed.
- Autoplay settings in the addon: `autoplay_countdown_seconds` ("Odpočet před koncem epizody (s)", when the dialog
  appears, counted from the end) and `autoplay_trigger_seconds` ("Spustit další před koncem (s)", when the next
  episode starts); the dialog runs `countdown - trigger` s. Both are read by `autoplay.settings()` (clamped 10-120 / >= 3).

- Entry points of tracked playback: `utils.play_movie_from_addon`, `search_and_play_episode`,
  `play_episode_from_addon`, `SeriesSearch.search_and_handle_episode` (route `tmdb_episode_search`, resolves for
  Kodi itself), router action `show_search_dialog`, AI chat Play button. Untracked by design: MyTV, MyCinema, Kodi
  library `.strm`, manual files, generic text search (`action=search`). `tmdb_movie_search` in the router calls a
  function that does not exist (old dead route).
- `PlayMedia(url)` does not put the item in Kodi's playlist (position -1): the next item is started with
  `Player.play(canonical)` from the service loop, once per playback (never `stop()` + `PlayMedia`).
- Kodi mirror: `Files.SetFileDetails` / `GetFileDetails` work for plugin URLs; adoption of Kodi-side changes every
  5 s while a Videos window shows addon URLs (`tracker.adopt_focused`, `mirror.check`).
- The user's data: My movies 3, My series 13 (list in `library.db`, old JSON kept as `*.json.migrated`), history
  was reset by the user on 2026-10-01 (backup in the session scratchpad of that day) and can be reset again with the
  new button (addon settings and skin settings -> Milionář). Autoplay settings were set back to 45 s / 15 s after
  tests; the user's earlier values are unknown.
- Fixture rows must be removed after live tests (see how it was done: delete `>= 900000` rows from
  `library.db`, reset Kodi records with `Files.SetFileDetails`, restore settings `dev_fixture_provider=false`,
  `lib_resume_min_seconds=180`, autoplay 45 / 15).
- Kodi may start windowed after a restart (1677x924); `Action(togglefullscreen)` restores 2560x1440 before any
  native capture.
