docs(tv): split the TV arm into its own page, add the folder-identity laws #122

Merged
dank merged 2 commits from docs/tv-folder-identity-law into main 2026-11-02 14:03:57 -08:00
Owner

docs(tv): the TV arm becomes its own page; add the folder-identity laws

serverAppConfigs-docs/Dankserver/Media Relayout.md crossed the OKF 500-line
ceiling when the 2026-11-02 TVShows laws landed, and the ceiling was right: the
TV arm reads a different authority and refuses for different reasons, exactly
like the music and audiobook arms that already have pages of their own.

What changed

  • New page [[Media TV Relayout]] — the arm moved verbatim (the tvdb
    authority order, the four refusals, the operator id map, the tvdb sheet) plus
    the two laws the 2026-11-02 pass earned:
    • A folder that names two series is not evidence of two series — the files
      answer.
      ffprobe -show_entries format_tag=title names the series per
      file. COW and CHICKEN … Complete Animated TV Series carries
      Cow and Chicken - SxxEyy - <title> on 103 of 104 files and no I Am
      Weasel
      tag at all: the 7-minute duration class is a half-episode segment,
      not a second show, and a file holding both segments needs a remux this
      executor will never do.
    • Right numbering plus a wrong name means rename the folder and nothing
      else
      — tag Sxx matching its Season NN folder, equal per-season
      counts, no duplicate SxxEyy key. Renumbering buys nothing and can mislabel
      an episode silently.
  • [[Media Relayout]] keeps the executor laws and gains a hold folder
    outside --root forces --force on BOTH apply and sweep
    , with the
    reason it is safe: sweep_targets marks only ancestors under --root, so a
    hold folder beyond the root can never be selected — it only blocks everything
    that is. Also: reap answering no ghosts after a rename of folders the
    server never identified is the expected result, because Jellyfin writes a
    sidecar only for a series it recognised.
  • [[Jellyfin]] gains the settle read: GET /ScheduledTasks, the row whose
    Name is exactly Scan Media Library, field State (Idle|Running).
    /Library/ScanStatus is a 404 on 12.4, so a watcher built on it reports
    nothing and a scanning server reads as idle. Settle = a Running sighting
    plus two consecutive Idles.
  • index.md regenerated with scripts/gen-vault-index.py — the seam
    refuses a hand-carved row, which is exactly what it caught here.

Second commit — the merge procedure (8f0b198)

  • A parked folder merges into the row that owns the show. The folder that
    never got an id usually holds episodes the identified folder lacks. The
    owner is the folder whose Series row carries the tvdb id; the
    comparison is episode identity — which (season, episode) the provider row
    gives each file, read straight out of the server, because release folders
    renumber (one park carried S01E01-11 of a show tvdb books as seasons 2 and
    3, every episode running the same eleven minutes). A season the owner has no
    file in whole (mkdir Season NN only) is the merge contract: the .mkv
    files under the new Season NN/ with names riding unchanged, and a .srt
    keeps the owner's stem, because Jellyfin attaches sidecars by stem
    equality. The same episode on both sides is the operator's call, never a plan
    row. Both sides speak different path dialects — the server records the
    container coordinate, the journal speaks the array — so a join that forgets
    the translation returns zero rows and reads as an empty library.
  • Two laws, with their reasons. One tvdb id can carry two Series rows, so
    the id-less folder list proves nothing about a merge: a parked folder whose
    words parse to a registered show gets identified on its own and keeps its own
    folder, and the library then offers the show twice. And library files move
    only while Scan Media Library is Idle — a Running sighting plus two
    consecutive Idle polls, because a gap between sub-tasks reads as finished
    and a rename under a running scan leaves the server holding a path that no
    longer exists.

Gates

./tests/run.sh before each commit (820 assertions green on the PR checkout); python3 scripts/check-okf.py serverAppConfigs-docs reports 125 concept pages, 0 violations. Docs-only
change: the deployer treats it as a no-op and the e2e gate is not in scope.

Build checkout: /home/blank/Projects/serverAppConfig (the session cwd differs,
per the footer).


cwd: /home/blank/.omp/wt/wt-20261030-163847-6d1fc1f · session: 01a18f2e-18b1-7573-bcd5-ac99636f8bcb

# docs(tv): the TV arm becomes its own page; add the folder-identity laws `serverAppConfigs-docs/Dankserver/Media Relayout.md` crossed the OKF 500-line ceiling when the 2026-11-02 TVShows laws landed, and the ceiling was right: the TV arm reads a different authority and refuses for different reasons, exactly like the music and audiobook arms that already have pages of their own. ## What changed - **New page `[[Media TV Relayout]]`** — the arm moved verbatim (the tvdb authority order, the four refusals, the operator id map, the tvdb sheet) plus the two laws the 2026-11-02 pass earned: - **A folder that names two series is not evidence of two series — the files answer.** `ffprobe -show_entries format_tag=title` names the series per file. `COW and CHICKEN … Complete Animated TV Series` carries `Cow and Chicken - SxxEyy - <title>` on 103 of 104 files and no *I Am Weasel* tag at all: the 7-minute duration class is a half-episode segment, not a second show, and a file holding both segments needs a remux this executor will never do. - **Right numbering plus a wrong name means rename the folder and nothing else** — tag `Sxx` matching its `Season NN` folder, equal per-season counts, no duplicate `SxxEyy` key. Renumbering buys nothing and can mislabel an episode silently. - **`[[Media Relayout]]`** keeps the executor laws and gains **a hold folder outside `--root` forces `--force` on BOTH `apply` and `sweep`**, with the reason it is safe: `sweep_targets` marks only ancestors under `--root`, so a hold folder beyond the root can never be selected — it only blocks everything that is. Also: `reap` answering `no ghosts` after a rename of folders the server never identified is the expected result, because Jellyfin writes a sidecar only for a series it recognised. - **`[[Jellyfin]]`** gains the settle read: `GET /ScheduledTasks`, the row whose `Name` is exactly `Scan Media Library`, field `State` (`Idle`|`Running`). `/Library/ScanStatus` is a 404 on 12.4, so a watcher built on it reports nothing and a scanning server reads as idle. Settle = a `Running` sighting plus two consecutive `Idle`s. - **`index.md`** regenerated with `scripts/gen-vault-index.py` — the seam refuses a hand-carved row, which is exactly what it caught here. ## Second commit — the merge procedure (8f0b198) - **A parked folder merges into the row that owns the show.** The folder that never got an id usually holds episodes the identified folder lacks. The **owner** is the folder whose `Series` row carries the tvdb id; the **comparison is episode identity** — which (season, episode) the provider row gives each file, read straight out of the server, because release folders renumber (one park carried `S01E01-11` of a show tvdb books as seasons 2 and 3, every episode running the same eleven minutes). A season the owner has no file in whole (`mkdir Season NN` only) is the merge contract: the `.mkv` files under the new `Season NN/` with names riding unchanged, and a `.srt` keeps the **owner's** stem, because Jellyfin attaches sidecars by stem equality. The same episode on both sides is the operator's call, never a plan row. Both sides speak different path dialects — the server records the container coordinate, the journal speaks the array — so a join that forgets the translation returns zero rows and reads as an empty library. - **Two laws, with their reasons.** One tvdb id can carry two `Series` rows, so the id-less folder list proves nothing about a merge: a parked folder whose words parse to a registered show gets identified on its own and keeps its own folder, and the library then offers the show twice. And library files move only while `Scan Media Library` is Idle — a `Running` sighting plus two consecutive `Idle` polls, because a gap between sub-tasks reads as finished and a rename under a running scan leaves the server holding a path that no longer exists. ## Gates `./tests/run.sh` before each commit (820 assertions green on the PR checkout); `python3 scripts/check-okf.py serverAppConfigs-docs` reports 125 concept pages, 0 violations. Docs-only change: the deployer treats it as a no-op and the e2e gate is not in scope. Build checkout: `/home/blank/Projects/serverAppConfig` (the session cwd differs, per the footer). --- cwd: /home/blank/.omp/wt/wt-20261030-163847-6d1fc1f · session: 01a18f2e-18b1-7573-bcd5-ac99636f8bcb
dank added 1 commit 2026-11-02 09:06:54 -08:00
Media Relayout.md crossed the OKF 500-line ceiling with the 2026-11-02 TV
laws, and the ceiling was right: the TV arm reads a different authority and
refuses for different reasons, like the music and audiobook arms that already
have pages. The arm moves verbatim to Media TV Relayout.md and gains two laws
from the TVShows pass: a folder naming two series is not evidence of two
series (ffprobe's embedded title tag answers per file), and right numbering
with a wrong name means rename the folder only. The executor page keeps the
executor laws and gains the hold-outside---root/--force law; Jellyfin.md gains
the settle read (ScheduledTasks State, since /Library/ScanStatus is a 404 on
12.4). Index regenerated with gen-vault-index.py.

cwd: /home/blank/.omp/wt/wt-20261030-163847-6d1fc1f · session: 01a18f2e-18b1-7573-bcd5-ac99636f8bcb
dank added 1 commit 2026-11-02 13:56:03 -08:00
A parked folder whose name parses to a registered show merges into the row
that owns the show. The proof is the episode rows standing under the owner
folder — never the id-less folder list, because one tvdb id can carry two
`Series` rows and an id-less folder that parses gets identified on its own
and keeps its own folder, offering the show twice.

No library file moves while `Scan Media Library` is Running: wait for a
Running sighting and then two consecutive Idle polls, because a gap between
sub-tasks reads as finished. Both sides speak different path dialects (the
server records the container coordinate, the journal speaks the array), so a
join that forgets the translation reads as an empty library.

Lands on [[Media TV Relayout]] — the page that owns the TV arm — so
`Media Relayout.md` stays under the OKF ceiling.
dank merged commit 541067e6b2 into main 2026-11-02 14:03:57 -08:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dank/serverAppConfigs#122