Ctrl K
ComunidadGuías…

tests/fixtures/README.md

Rama dev · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Recorded API fixtures

Response shapes recorded from real servers (plex-safety rule 11). Identifying values
(names, ids, tokens, hostnames) are sanitized; structure and field names are verbatim.

> **XML fixtures must NOT use a bare `.xml` extension — use `.xml.txt`.** Unraid Community
> Applications scans every `*.xml` file in the repo looking for app templates, and flags any that
> isn't one as `not_unraid_application`, which shows as a failed check on our CA submission. The
> content is still plain XML; only the filename differs.

| File                              | Source                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     | Recorded   |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------- |
| `pms_managed_hubs.xml.txt`        | PMS 1.43.3.10896 `GET /hubs/sections/1/manage` (XML), the endpoint `LibrarySection.managedHubs()` reads — captured off a real PMS's Movies library, 70 hubs reduced to 8, titles neutralised (the real ones name individual people, via each row's per-account title marker). Settles what `is_collection_hub` matches: a COLLECTION's hub is `custom.collection.<sectionID>.<ratingKey>` here (a single ratingKey — the DOUBLED form in `pms_hubs_shared_account.json` is `/hubs`, a different endpoint), and built-in hubs use their own families (`movie.recentlyadded`, `recent.library.playlists`). Built-ins DO carry all three `promotedTo*` flags, so the guard's fail-open path is belt-and-braces rather than load-bearing; `deletable` is present on collections and absent on built-ins. **Note what is NOT here: not one collection on this server had `promotedToRecommended=0`.** Every hub with all three flags off is a built-in the owner switched off. So either Plex promotes a new collection to Recommended by default, or an off-shelf collection is absent from this listing entirely — unresolved, and it bears on whether issue #106's anchor case is reachable in practice | 2026-08-30 |
| `pms_managed_hub_renamed_collection.json` | PMS 1.43.4.10903 — one Shortlist row's collection read three ways moments after an in-place rename, off a real PMS's Movies library: `GET /hubs/sections/1/manage`, `GET /library/metadata/<ratingKey>` and `GET /hubs/sections/1`. ratingKey neutralised, per-account title markers stripped. Settles why `place_rows` identifies a hub by the ratingKey in its identifier and not by title: **the manage listing keeps the title the collection had when it was promoted**, while the collection and the hub viewers are served both carry the new one. Matched by title, a renamed row reads as somebody else's collection. On one real server 15 of 93 promoted rows in one library were in that state after one night | 2026-09-16 |
| `pms_hubs_home.json`              | PMS 1.43.3 `GET /hubs` (JSON) — reconstructed from the live Phase 0 probe observations (collection hub `key`/`context` shapes); re-record with a direct capture when convenient                                                                                                                                                                                                                                                                                                                                                                                                            | 2026-07-12 |
| `plextv_users.xml.txt`            | plex.tv `GET /api/users` — field-verified live in Phase 0 (share filters as `<User>` attributes)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           | 2026-07-12 |
| `plextv_resources.json`           | plex.tv `GET /api/v2/resources?includeHttps=1` — the shape behind `auth.owned_machine_ids()`, which decides who may sign in to an unclaimed instance and which server they may link. Captured owned entry is real; the `owned:false` and player entries are synthesised (this account has no inbound shares) and labelled as such in `_why`                                                                                                                                                                                                                                                | 2026-07-29 |
| `pms_watched_incremental.xml.txt` | PMS 1.43.3 `GET /library/sections/{key}/all` — the watched read, plus a measured table of which query params this server honours. The headline: `unwatched=0` and `sort=lastViewedAt:desc` work, while **every cutoff-filter form (`lastViewedAt>=`, `>>=`, and a `year>>=` control) is silently ignored** and returns the full set with a 200. That is why the incremental watch-history read narrows by ordering + an early stop rather than by a filter                                                                                                                                 | 2026-07-30 |
| `plextv_combined_filters.json`    | plex.tv `PUT /api/users/{id}` + `GET /api/users` — proof that share-filter strings are stored and returned VERBATIM: `\|`/`&` between conditions and `,`/`%2C` between values all round-trip byte-identical, with no normalization. So the shape Shortlist reads is whichever writer last touched that account (Plex Web, plexapi, or us), which is the whole of issue #77. Written to a canary account with its original value snapshotted and restored                                                                                                                                   | 2026-08-10 |
| `pms_collections_listing.json`    | PMS 1.43.3 `GET /library/sections/{key}/all?type=18` vs `GET /library/collections/{rk}` — the collections LISTING carries **no** `<Label>` children (103 collections, zero labels); they exist only on the per-collection detail read, which plexapi fetches silently behind `collection.labels`. Every label-based read in Shortlist depends on that, and a successful-but-empty read is indistinguishable from an unlabelled row — which is why the sweep both re-reads per collection and refuses to act when NO row reads as labelled, and why the fake now serves the same two shapes | 2026-08-10 |
| `pms_collection_field_edits.json` | PMS 1.43.4 `PUT /library/sections/{key}/all?type=18&id=…&summary.value=…&titleSort.value=…` (plexapi `Collection.edit`) on a throwaway collection in a real PMS's TV library, created and deleted by the probe. Settles how issue #120 must write a row's summary and sort title: a LOCKED sort title survives a title edit and a membership write (so Shortlist re-applies it after a rename), an UNLOCKED custom one is overwritten by the next title edit (so it is locked), a blank unlocked one is rebuilt by Plex from the full title with its leading emoji kept, the summary round-trips byte-exact, labels are untouched, and a field edit costs ~0.01–0.09s where a label write there took 21.9s | 2026-09-13 |
| `pms_hubs_shared_account.json`    | PMS 1.43.3 `GET /hubs` fetched with a SHARED account's own server token, on a server carrying 46 per-person rows. Settles two things that were assumed. A promoted row appears as its OWN hub — identity lives in `key` (`/library/collections/<id>/children`), and there are **no** `Metadata` entries of type `collection` to look for. And a real PMS **does** apply a share `label!=` filter to `/hubs`: this account's Home carried its own four rows, the shared row, and other tools' collections, and not one of the other 45 people's rows. That is the filter-enforcement canary's whole premise, previously untested. Reduced from 33 hubs to 11 and from 6 Metadata items per hub to 2 (with `size`/`hubKey` reduced to match); titles neutralised, including two "Because you watched X" rows that named a real person's viewing — see the file's `_sanitized` | 2026-08-18 |
| `overseerr_media_page.json`       | Seerr 3.4.1 (`seerr-team/seerr`) `GET /api/v1/media`, recorded 2026-09-02 off a live 26,941-row instance — one row per (mediaType, status) actually present, plus the single row that was genuinely downloading. Settles three things the specs get wrong. **`mediaType` is real** (present on all 5,000 sampled rows, absent from the published `MediaInfo` schema) and load-bearing, since TMDB's movie and tv id spaces overlap. **The status enum is not what any spec says**: the server's own code has `BLOCKLISTED=6, DELETED=7`, while Overseerr's spec AND Seerr's own shipped `seerr-api.yml` both say `6=DELETED` and document nothing above 6 — yet 821 of 5,000 rows were status 7. And **PROCESSING does not mean downloading**: 76 rows were PROCESSING and exactly ONE was moving, which is why `downloadStatus` decides that word. Sanitized: serviceUrl hosts, Plex machine ids, downloadStatus titles, long season arrays trimmed | 2026-09-02 |
| `overseerr_users_page.json`       | Seerr 3.4.1 `GET /api/v1/user` — key set, null pattern and pageInfo recorded 2026-09-02 from a 62-account instance; the identities are FABRICATED (the real ones are 62 real people). What it settles: **`username` was null on all 62**, so every account names itself with `displayName` + `plexUsername` — and `displayName` is the field the published `User` schema omits. That is why the client falls through `displayName` → `username` → `plexUsername` → `email` rather than trusting the documented field | 2026-09-02 |
| `tmdb_discover_paged.json`        | TMDB API v3 `GET /discover/movie` (pages 1 and 34 of 34) and `GET /discover/tv`, with the Halloween season's keywords OR'd by `\|`, recorded 2026-09-15 for seasonal rows (discussion #124); 2 results per page, overviews cut. Settles how a season's title list is read. Pages carry `total_pages`/`total_results`. **Paging by `popularity.desc` silently loses titles** (Christmas: 3,133 unique ids over 3,370 results, because popularity moves between page reads) while `primary_release_date.asc` (`first_air_date.asc` for TV) returns all 3,370. **A page above 500 answers HTTP 400**, so a list is read to `min(total_pages, 500)` | 2026-09-15 |
| `tmdb_search_keyword.json`       | TMDB API v3 `GET /search/keyword?query=thanksgiving` page 1, recorded 2026-10-02 for the season editor's tag search (issue #137), verbatim: 4 results, each only `{id, name}`, with `page`/`total_pages`/`total_results` and no film count. Settles why `TmdbClient.search_keywords` reads page 1 of `/discover/movie` per tag for its count: the keyword search carries none. Holds no credential | 2026-10-02 |
| `overseerr_requests_page.json`    | Seerr 3.4.1 `GET /api/v1/request?filter=all&sort=added`, recorded 2026-09-28 off a live instance (7 requests, 6 people); identities FABRICATED with ids remapped consistently across the three `*_request_tags.json` / `overseerr_*` files of the same date. Settles what a "Your requests" row (issue #127) reads: **`requestedBy.plexId` is on every request** and equals `users.plex_account_id`, so a request maps to a person with no name matching; `status` 5 (COMPLETED) is set by Seerr itself when the media lands, and for a TV request only when every requested season is available, each `seasons[].status` flipping first; `media.mediaAddedAt` is when Plex first saw the title; `media` carries no title | 2026-09-28 |
| `overseerr_arr_settings.json`     | Seerr 3.4.1 `GET /api/v1/settings/radarr` + `/sonarr`, recorded 2026-09-28. Settles that **`tagRequests` is a readable key** (absent from the published schema) — the switch that makes Seerr stamp `<seerrUserId>-<username>` on each Radarr/Sonarr item it sends, which is what lets a deleted request still be traced to a person | 2026-09-28 |
| `radarr_request_tags.json`        | Radarr v3 `GET /api/v3/tag` + `GET /api/v3/movie`, recorded 2026-09-28 (10,168 movies, 48 tags, 5 Seerr requester tags on 7 movies; items cut to the keys a requests row reads, titles neutralised). Settles the requester tag FORMAT (`<seerr user id>-<username>`, matched on the number only) and that **a tag survives the Seerr request being deleted**: 3 of the 7 tagged films had no request left in Seerr and every one still carried its tag | 2026-09-28 |
| `sonarr_request_tags.json`        | Sonarr v3 `GET /api/v3/tag` + `GET /api/v3/series`, same recording as above (4,966 series, 63 tags, 3 requester tags on 4 series). Same format and same survival: 3 of 4 tagged shows had their request deleted | 2026-09-28 |
| `pms_collection_children.xml.txt` | PMS 1.43.4.10903 `GET /library/collections/{rk}/children?includeGuids=1` (what plexapi's `Collection.items()` issues), off a regular 50-film collection in a real PMS's Movies library, cut to 4 films; file paths neutralised, and the owner's own viewing (`viewCount`, `lastViewedAt`, `userRating`, `lastRatedAt`) removed. Settles what a custom season (issue #137) reads from an owner's collection: **every member carries its `tmdb://` guid inline**, so one read maps a collection to TMDB ids with no per-film re-read (every member of 46 to 1,187-film collections, smart and regular, on the same server). The container carries only `size`, no `totalSize` | 2026-10-02 |
| `pms_section_title_search.xml.txt` | PMS 1.43.4.10903 `GET /library/sections/{key}/all?includeGuids=1&title=free` with `X-Plex-Container-Size: 5` (plexapi's `LibrarySection.search(title=…, maxresults=5)`), off a 10k-film Movies library; file paths neutralised, the owner's own viewing (`viewCount`, `lastViewedAt`, `userRating`, `lastRatedAt`) removed, and one Shortlist row's title (a person's watch plus their account marker) replaced. Settles the season editor's film search: **`title=` is a substring match** (5 of `totalSize` 21), every result carries its `tmdb://` guid, and a result lists Shortlist's own rows among its `<Collection>` tags | 2026-10-02 |
| `pms_active_sessions.xml.txt` | PMS `GET /status/sessions`, a sanitised capture of a real response (commit 037f54e6) cut to 3 sessions (two paused, one playing); user ids, titles and player names are placeholders. Records a real difference between this endpoint and the history log: **`/status/sessions` carries `grandparentRatingKey`, the history log does not**, so the history path has to take the show key out of a `grandparentKey` path. Backs the pick-credit read of a play in progress (`test_play_history.py`) | 2026-08-23 |
| `pms_play_history.xml.txt` | PMS `GET /status/sessions/history/all` — the durable play log, which the library read cannot give (it ignores `viewedAt>` filtering). 5 rows of a 101,604-row log; account ids neutralised, titles replaced in the 2026-10-09 scrub. Settles the row shape the watch-event reader parses: `historyKey`, `viewedAt`, `accountID`, `deviceID`, and **no duration, no `viewOffset`, no TMDB guid**. A duplicate `viewedAt` pair on one film is kept on purpose (two history rows for one play) | 2026-08-23 |
| `pms_history_after_scrobble_empty.xml.txt` | PMS `GET /status/sessions/history/all` as the test account, read after 31 `/:/scrobble` writes: an empty container (`size="0" totalSize="0"`). Settles that **a scrobble writes nothing to the play-history log**, so a watching-account transfer cannot inject fake plays into `watch_events`. Probed 2026-08-25 on PMS 1.43.3.10896 (`watching-account-transfer-design.md` §2); `scripts/recheck_pms_assumptions.py` re-measures it after a Plex upgrade | 2026-08-25 |
| `pms_in_progress_movies.xml.txt` | PMS `GET /library/sections/{key}/all` filtered to part-watched films (`viewOffset>`), the read the watching-account transfer makes to replicate Continue Watching. 3 of 81 films, owner account; full per-film child set kept (`Media`/`Part`, `Image`, `Guid`, `Genre`, `Role`). Settles that `viewOffset` rides on the row beside `viewCount`/`lastViewedAt`, and that a part-watched film can also be a finished one. Part of the 2026-08-25 probe set | 2026-08-25 |
| `pms_in_progress_episodes.xml.txt` | Same read against the TV library with episodes (`type=4`, `viewOffset>`): 3 of 267 part-watched episodes. Settles that an episode row carries `grandparentRatingKey`/`parentRatingKey` and `viewOffset`, so a partial watch is placed on the exact episode and never on the show key (the One Piece bug in commit 4352559f). Part of the 2026-08-25 probe set | 2026-08-25 |
| `pms_watched_episodes.xml.txt` | PMS `GET /library/sections/{key}/all?type=4&unwatched=0` — the per-EPISODE watched read that is the source of truth for the watching-account transfer (the show-level `unwatched=0` read knows how MANY episodes were watched, never WHICH). 3 of 9,582 rows. Part of the 2026-08-25 probe set; the 2026-09-01 roll-up fixture below is the larger recording of the same endpoint | 2026-08-25 |
| `pms_watched_episodes_rollup.xml.txt` | PMS 1.43.3 `GET /library/sections/{key}/all?type=4&unwatched=0`, the episode-level read that is ground truth for what someone watched (issue #108). Titles and ids sanitised; attribute names and presence verbatim. Settles that `?type=2&unwatched=0` filters on the SHOW row's own watch-state, not on `viewedLeafCount`: on one server it returned 533 shows, while `?type=2` held 491 with watched episodes — **20 of them never came back**, every one with correct leaf counts and no `lastViewedAt`. Replaced by `?type=2&viewedLeafCount!=0` (identical 491, one read); this walk survives as `_newest_episode_stamps`, and its `totalSize` of 9,563 is why that function folds per page instead of retaining rows (~14 MB per user per library per sync) | 2026-09-01 |
| `pms_watched_shows.xml.txt` | PMS 1.43.3 `GET /library/sections/{key}/all?type=2&unwatched=0` on a show library; 10 `<Directory>` rows. **Only the viewed/total pairs were measured** (2/23, 4/142, 47/47, 14/67, 42/122, 2/176, 4/138, 100/100, 12/17, 4/38); the `lastViewedAt` values are INVENTED (three copied from the movie fixture, the rest round numbers) — the file says so itself. Settles that `unwatched=0` on a show means "started", not "finished" (2 of 176 comes back), which is why a 0% row treats started as watched. Row 5006 is a hand-marked series with no show-level `lastViewedAt`. No longer the read Shortlist makes; kept as the evidence for the change to `viewedLeafCount!=0` | 2026-08-05 |
| `pms_watched_shows_either.xml.txt` | PMS 1.43.5 `GET /library/sections/{key}/all?type=2&includeGuids=1&push=1&viewedLeafCount!=0&or=1&unwatched=0&pop=1`, owner token; 3 of 547 rows, titles/keys/guids sanitised and timestamps shifted by one constant, counts verbatim. The show read Shortlist makes since #173. Settles that `push`/`or`/`pop` ORs the two filters: 547 = exactly the union of `viewedLeafCount!=0` (485) and `unwatched=0` (528), the same for each of ten shared tokens, with `sort=lastViewedAt:desc` still honoured; the ungrouped `or=1` returned 5,953 rows. One row of each shape: played, marked watched (#108), watched episodes deleted (#173) | 2026-10-30 |
| `pms_show_counters_after_deleting_episodes.json` | Measurement log, not a single response: a throwaway PMS 1.43.5.11029 (Personal Media TV library, deleted afterwards), plus read-only counts from a production server. Settles #173: deleting watched episodes keeps the show's `viewCount`/`lastViewedAt` and drops `viewedLeafCount` to 0, so the show leaves `viewedLeafCount!=0` and stays in `unwatched=0` and On Deck; **Mark as unwatched** on the series clears the show's counters; unmarking each episode leaves them behind. On the production server 62 owner shows were in that state, 54 with every present episode added after the show was last viewed | 2026-10-30 |
| `pms_all_leaves.xml.txt` | PMS 1.43.4 `GET /library/metadata/{showRatingKey}/allLeaves` — every episode of one show with the reading account's own watch state, cut from 8 episodes to 4 (`size`/`totalSize` set to 4 to match; nested `Media`/`Part`/`Image`/`Role` trimmed). Settles the stale-"finished"-date bug in #108: marking a series watched bumps `viewedLeafCount` and leaves the show's `lastViewedAt` alone, so only the episodes hold the real date. Also settles that **`?unwatched=0` is silently ignored on this endpoint** (`viewCount` is applied client-side), that `totalSize` is absent unless `X-Plex-Container-Size` is sent, and the trap that an abandoned episode (`lastViewedAt`, no `viewCount`) can be newer than the one actually watched | 2026-09-05 |
| `pms_watched_user_rating.xml.txt` | PMS 1.43.3 `GET /library/sections/{key}/all?type=1&unwatched=0&includeGuids=1`, recorded once per token across 50 accounts (owner + 49 shared) for issue #69. Titles, ids, summaries and account names sanitised. Settles that `userRating` rides on the watched read we already make and is scoped to the TOKEN; and the trap that 90.7% of the OWNER's values were fractional (7.9, 8.8) — written by an external rating sync (Kometa), which Plex's own half-star controls cannot produce — while 0 of 36 viewer ratings were. That is why `WatchedItem.is_human_rating` and an account-level guard exist | 2026-08-06 |
| `pms_metadata_batch_partial.json` | PMS 1.43.3.10793 `GET /library/metadata/<live>,<deleted>`, JSON, keys replaced by placeholders. Settles that **a partial batch answers 200 with the FOUND subset and 404s only when no requested key exists**, so `plex_pms.fetch_items` treats a `NotFound` as "every key is gone". Replaced a guessed premise (commit 5cc55710). The same shape is what an allow-list account sees when reading as itself | 2026-08-18 |
| `pms_collection_title_tags.json` | Measurement log, not a single response: PMS 1.43.3.10793 behaviour behind issue #119's refused renames, taken with throwaway collections (deleted in a `finally`) and read-only from Plex's own database. Settles that a collection's title is a server-wide `tags` row (`tag_type` 2, `NOCASE`); a delete leaves the row behind; a rename onto a name another tag row holds answers **409**, while a create REUSES the row (so same-named "twins" in two libraries share it); and the orphan-reclaim sequence (helper create, rename helper, rename row, delete helper). On the live server 4 of 5 refused renames hit an orphan; 41 orphaned Shortlist tags in total. Holds the 409 body verbatim | 2026-09-14 |
| `pms_collections_tab_filter_visibility.json` | Measurement summary, not a raw response: PMS 1.43.3, read-only, as one shared account's own server token on a server with 48 shared accounts and 186 Shortlist collections (all `collectionMode` 0). Settles that "Hide collection" does NOT keep a row out of the Collections tab or collection search, while the share-filter `label!=` exclude does (0 of 180 other people's rows visible, 2 of 2 unexcluded shared rows visible). That is why `_exclude_first_rows` merges a person's exclude as soon as their first row is written | 2026-09-13 |
| `pms_share_filter_boolean_semantics.json` | Measurement log: what a real PMS (1.43.4.10903) does with a share filter joined by `\|` versus `&`, as opposed to `plextv_combined_filters.json`, which only shows plex.tv STORES both. Each `filterMovies` value was written to one shared account (`PUT /api/users/{id}`), waited 90 s, then `GET /hubs` and the library count read with that account's token; original restored afterwards. Settles (#116) that `\|` is OR and `&` is AND, so `contentRating!=X\|label!=ours` hides nothing of ours and switches off the owner's own rating exclude (9,988 movies visible, not 9,970); that a trailing `&` clause is ANDed with the whole filter before it; that PMS applies a change within ~25 s; and that a literal `&` inside a label makes `GET /hubs` answer HTTP 500 | 2026-09-13 |
| `pms_label_filter.json` | Measurement log, PMS 1.43.5.11029 `GET /library/sections/{key}/all` with an ITEM-label filter, owner token, counts only. Settles how issue #151 finds Agregarr's `trailer-placeholder` stand-ins: `label=<name>` and `label!=<name>` are honoured by tag name, case-insensitively, and partition a library exactly (10,053 + 11 = 10,064), so a reader can verify its own answer; `includeLabels=1` inlines nothing. Also that a show's `leafCount` counts its Season 0 episodes (28 of 28), which is why one S00E00 trailer play reads as a finished show, and the shape of a show's `/children` (seasons carry `index`, the "All episodes" entry does not) that tells a trailer-only show from one with real episodes. No placeholder item is recorded: the server had none | 2026-10-11 |
| `pms_share_filter_allow_lists.json` | Measurement log (issue #115): what a real PMS (1.43.3.10793) does with an account's ALLOW list (`label=`, `contentRating=`), measured by writing one managed Home account's filters and reading as that account. Settles the grouping `(A\|B)&C` (`\|` binds tighter), that `&` between two allow conditions is a strict AND, and that `GET /library/metadata/{k1,k2,…}` as the account returns only the keys its filter admits. **Corrected 2026-09-18:** admitting the row's own label does NOT fill the row (11 of 9,991 movies matched, none in the row) — a filter matches ITEMS by label and a row's members carry no `shortlist_` label — so the account sees an empty row; `RowPolicy.visible` is what fills it | 2026-09-13 |
| `plextv_home_users.xml.txt` | plex.tv `GET /api/home/users`, recorded from a real Plex Home with names and ids fabricated (ids deliberately match `plextv_users.xml.txt` so the join in `list_users()` cannot silently match nothing). The only endpoint that reports `restrictionProfile`; `/api/users` says `restricted="1"` for every managed account and nothing more (issue #20). Settles that a profiled account (`little_kid`) answers HTTP 422 to a label-restriction write, so a managed user with NO profile is the one that needs its excludes. An unprofiled account's `restrictionProfile` is ABSENT in this file; a 2026-10-10 read of the live endpoint returned it present and EMPTY (`restrictionProfile=""`). Both read as "none" (`test_an_empty_profile_attribute_means_no_preset`) | 2026-07-29 |
| `plextv_restricted_user.json` | `PlexTvClient.list_users()` output (already parsed — `restricted`, `home`, `protected`, `user_type`, `filters{}`), captured live from a large production server. Values URL-encoded exactly as plex.tv returned them. Settles that a restricted account CAN hold share filters — here a `contentRating=` parental-control list, not `label!=` — so the 2026-07-25 note that a restricted account "sees zero collections" was recorded against a profiled account (issue #20) and merging excludes in is mechanically ordinary. Scrubbed 2026-10-09 | 2026-07-28 |
| `github_releases.json` | GitHub `GET /repos/stevezau/shortlist/releases?per_page=100`, unauthenticated — the list the What's new dialog reads. 12 releases reduced to 5 and each to the 7 fields read; values verbatim. Settles that the list is ordered by PUBLISH date, not version (v1.2.1 after v1.3.0, so the dialog sorts itself), that `body` is the owner-editable release markdown, and that drafts are hidden from an unauthenticated caller | 2026-09-14 |
| `exa_search_structured.json` | Exa `POST /search` response (`requestId`, `resolvedSearchType`, `searchTime`, `costDollars`, `output`, 3 `results` with `text`/`author`/`publishedDate`/`image`), recorded from the live API during the web-search backend probe (commit 77dcd278). Settles the structured-output shape `search.py` parses. Holds no credential | 2026-09-02 |
| `searxng_search.json` | SearXNG `GET /search?format=json` for the seed "what to watch next if you liked Severance", 6 results; top-level `query`, `answers`, `corrections`, `infoboxes`, `suggestions`, `unresponsive_engines`. The shape `SearxngClient` reads when web search runs on the owner's own instance (commit 9af71774). No provenance note in the file | 2026-08-11 |
| `sonarr_series_lookup.json` | Sonarr 4.0.19 `GET /api/v3/series/lookup?term=…` on a real instance, **re-recorded VERBATIM** (the first version had `images` stripped while claiming to be real — a fixture whose value is being the real shape must not be edited). Settles that **every season arrives `monitored: true`** on a lookup, so the body says "all seasons" while `addOptions.monitor` asks for one and Sonarr resolves it in favour of the body; the same commit measured each monitor mode on the live server and offers only the ones that behave | 2026-08-26 |
| `curator_anthropic_complete.json` | Anthropic Messages API `POST /v1/messages` reply, for the curator's plain completion. **Hand-written, not a recording:** placeholder ids, round token counts, no provenance note in the file or commit. Shape follows the public API; the SDK object is replayed through `test_curator.py` | 2026-07-31 |
| `curator_anthropic_recommend_web.json` | Anthropic Messages reply for the web-search recommend call: two text blocks, the second a JSON array of `{title, year, media}`. Hand-written, as above | 2026-07-31 |
| `curator_google_generate_content_complete.json` | Google Gemini `generateContent` reply for a plain completion (`candidates[].content.parts[]`, `usage_metadata`). Hand-written, as above | 2026-07-31 |
| `curator_google_generate_content_web.json` | Gemini `generateContent` reply for the grounded web call: a preamble part then a JSON array part. Hand-written, as above | 2026-07-31 |
| `curator_openai_chat_completion.json` | OpenAI `POST /v1/chat/completions` reply (`gpt-4o-mini`, `usage.prompt_tokens`/`completion_tokens`). Hand-written, as above | 2026-07-31 |
| `curator_openai_compatible_models.json` | An OpenAI-compatible `GET /v1/models` list as a local server such as Ollama returns it (`id`, `created`, `object`, `owned_by`), three entries with sequential `created` values. Hand-written, as above | 2026-07-31 |
| `curator_openai_responses_web_search.json` | OpenAI `POST /v1/responses` reply with the `web_search` tool: an `output` message holding two `output_text` blocks (preamble, then a JSON array). Hand-written, as above | 2026-07-31 |