Stop trusting Plex's Date Added on its own

Jess spotted that dates looked like file dates rather than library-add dates.
He is right, and MediaShelf was not the culprit: it reproduces Plex's addedAt
exactly (verified 500/500 identical to the second). Plex's own field is what
follows the file — replace or re-encode one and Date Added resets while the
item, its ratingKey and its watch history all survive.

Measured on the live library, comparing addedAt against lastViewedAt where both
exist: 55 of 509 movies (10.8%) and 306 of 1,393 TV Show Archive items (22.0%)
were watched BEFORE they were "added" — 19% overall. 2001: A Space Odyssey
reports added 2026-07-31, last watched 2017-08-26.

That is not cosmetic. pre_history is derived from added_at, so an old item whose
file was replaced looks post-coverage and gets promoted into the CONFIDENT
reclaim pool, which is the one pool meant to be trustworthy.

A completed play proves the item already existed, so added_at is now
MIN(provider_added_at, first_watched_at). Plex's raw value is kept in
provider_added_at, added_at_source records which applied, and the item drawer
explains the substitution instead of quietly disagreeing with Plex. Unwatched
items keep Plex's value since nothing contradicts it. first_seen_at is also
recorded now and is authoritative for anything added from here on.

Plex's API has no better field; the true insert time is only in Plex's own
metadata_items.created_at on Loki.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GVbG48GAXfCZatcmX123Ra
This commit is contained in:
Jess Hallsworth 2026-09-10 17:35:48 +00:00
parent d12cbc62ee
commit e819548ff2
No known key found for this signature in database
9 changed files with 234 additions and 15 deletions

View file

@ -270,7 +270,7 @@ From each `Video` element on `/library/sections/{id}/all`:
| `guid` | cross-server content identity | `guid` |
| `type` | `movie` / `episode` / `season` / `show` | `kind` |
| `title`, `year` | display | `title`, `year` |
| `addedAt` | epoch seconds, when Plex first saw the file | `added_at` |
| `addedAt` | epoch seconds**follows the FILE, not the library entry** (§4.12) | `provider_added_at` |
| `updatedAt` | epoch seconds, last metadata change | `updated_at` |
| `duration` | milliseconds | `duration_ms` |
| `viewCount` | plays — **token-account scoped**, see §4.5 | (advisory only) |
@ -362,6 +362,51 @@ the ingest is designed to be slow and steady rather than parallel and aggressive
| Malformed / partial item | Item skipped, logged, counted in `scan.warning_count`; the scan still succeeds |
| Timeout mid-page | Up to 3 retries with exponential backoff, then the scan fails |
### 4.12 Date Added is not the date it was added
Plex's `addedAt` is the field its UI calls Date Added, and it is the obvious
source for "when did this arrive". It is also, on this library, wrong 19% of the
time — because it tracks the **file**, not the library entry. Replace or
re-encode a file and Plex resets Date Added while keeping the item, its ratingKey
and its entire watch history.
Measured on the live server (2026-09-10), comparing `addedAt` against
`lastViewedAt` on items that have both:
| Library | items with both dates | watched BEFORE "added" |
|---|---|---|
| Movies | 509 | 55 (10.8%) |
| TV Show Archive | 1,393 | 306 (22.0%) |
| **overall** | **1,902** | **361 (19.0%)** |
*2001: A Space Odyssey* reports added 2026-07-31 and last watched 2017-08-26.
Plex's API exposes no better field; the true insert time exists only in Plex's
own SQLite `metadata_items.created_at`, which needs filesystem access to Loki.
This is not cosmetic. `pre_history` is derived from `added_at`, so an old item
whose file was replaced looks post-coverage and is promoted into the
**confident** reclaim pool — the one pool that is supposed to be trustworthy. The
new-arrival grace is affected the same way in reverse.
**What MediaShelf does about it.** A completed play is proof the item already
existed, so the first play is a lower bound on the true add date:
```
added_at = MIN(provider_added_at, first_watched_at)
```
`provider_added_at` keeps Plex's raw value, `added_at_source` records which
applied, and the UI explains the substitution on any corrected row rather than
silently showing a different date than Plex does. Items nobody ever watched keep
Plex's value — nothing contradicts it.
Separately, `first_seen_at` records when MediaShelf itself first saw a row. That
is authoritative for everything added from now on, whatever Plex does to its own
field, and needs no correction.
The exact fix, if it is ever worth the access: read `metadata_items.created_at`
from Plex's database on Loki and backfill it.
### 4.8 Tautulli — the watch-history source
Tautulli runs at `http://192.168.1.100:8181` (on Isis) and has been logging every