docs(media): the Plex leg ran, and a script fed over stdin owns that stdin
The 2026-11-01 morning leg cleared every Plex row naming a held path, so the prune page records the outcome plus the residue that is normal: a section pass rewrites feature rows first and can leave rows for clips in a film's other/ or extras/ folder standing after the refreshing flag is back to 0. Beside REAL: 0 that is a dead disc-menu clip, not a false prune, and no reason to touch the cache or the database. Plex gains the two operational laws the run taught: a start job issued after an unmask belongs to the manager, not the shell, and lands minutes later surviving the client that issued it; a refresh fired while PMS is warming answers 000, so retry it rather than restart the service. The trap that made a finished job look hung belongs to the remote job runner: a script fed to bash -s IS the stdin, so any child that reads stdin (podman exec -i) swallows the rest of the script without a word.
This commit is contained in:
1 parent
010b9affc7
commit
13830865f6
3 files changed
+31
-10
No files matched your search
@@ -106,11 +106,12 @@ cross it as inotify events. Scan in the order the rescan law sets — Jellyfin t
|
|||||||
`Idle`, then Plex's Movies section alone, one accepted refresh each; the requests
|
`Idle`, then Plex's Movies section alone, one accepted refresh each; the requests
|
||||||
are owned by [[Jellyfin]] and [[Plex]].
|
are owned by [[Jellyfin]] and [[Plex]].
|
||||||
|
|
||||||
As of 2026-11-01 the Plex leg is deliberately deferred: Plex is stopped and
|
The Plex leg may be deferred on purpose: stop **and mask** Plex (`systemctl --user
|
||||||
**masked** (`systemctl --user stop plex && systemctl --user mask plex`) so its
|
stop plex && systemctl --user mask plex`) so its metadata fetches cannot stack on a
|
||||||
metadata fetches cannot stack on Jellyfin's live scan, and a masked unit stays
|
live Jellyfin scan, and because a masked unit stays stopped through a reboot —
|
||||||
stopped through a reboot — `unmask` before starting it. Its Movies section (key 1)
|
`unmask` before starting it. The 2026-11-01 morning ran it once Jellyfin reached
|
||||||
holds ~187 rows naming held paths until that one refresh is accepted.
|
`Idle`: one accepted `refresh` on the Movies section cleared every row that named a
|
||||||
|
held path.
|
||||||
|
|
||||||
The same evening's detritus pass is a second, separate hold: 423 files (12 MiB) in
|
The same evening's detritus pass is a second, separate hold: 423 files (12 MiB) in
|
||||||
`/mnt/entropy/.AGENTTRASH/20261101-detritus-sweep`, plan `detritus-sweep-plan.tsv`,
|
`/mnt/entropy/.AGENTTRASH/20261101-detritus-sweep`, plan `detritus-sweep-plan.tsv`,
|
||||||
@@ -126,6 +127,12 @@ extension the census does not recognise is a reason to stop, not to sweep.
|
|||||||
verdict is `still at src: 0` with `REAL: 0`, and the rows that simply vanished
|
verdict is `still at src: 0` with `REAL: 0`, and the rows that simply vanished
|
||||||
from the database are the pass succeeding.
|
from the database are the pass succeeding.
|
||||||
|
|
||||||
|
One residue is normal, so do not chase it: a section pass rewrites the feature rows
|
||||||
|
first, and rows for clips in a film's `other/` or `extras/` subfolder can still name
|
||||||
|
a held path after the section's `refreshing` flag is back to `0`. Beside `REAL: 0`
|
||||||
|
that is a dead disc-menu clip — not a false prune, and no reason to touch the cache,
|
||||||
|
the database, or the hold.
|
||||||
|
|
||||||
## Failure signatures
|
## Failure signatures
|
||||||
|
|
||||||
| Symptom | Meaning |
|
| Symptom | Meaning |
|
||||||
|
|||||||
@@ -86,7 +86,12 @@ root runs as the `dank` user, and the deployer adopts the data root with
|
|||||||
4. **Cold container boot is slow.** PMS pre-binds 32400 and empty-replies
|
4. **Cold container boot is slow.** PMS pre-binds 32400 and empty-replies
|
||||||
while the HTTP layer finishes loading; the first boot of a years-old
|
while the HTTP layer finishes loading; the first boot of a years-old
|
||||||
library took ~10 minutes (2026-09 cutover). The deployer gate now allows
|
library took ~10 minutes (2026-09 cutover). The deployer gate now allows
|
||||||
600 s before failing; later boots are much faster (warm page cache).
|
600 s before failing; later boots are much faster (warm page cache). A
|
||||||
|
`systemctl --user start` issued after an `unmask` is a job in the manager,
|
||||||
|
not in the shell that issued it: it lands minutes later and survives that
|
||||||
|
client dying, so a wrapper script that looks hung is usually only waiting —
|
||||||
|
read `is-active` and `podman ps` before declaring a fault, and give every
|
||||||
|
step of such a script its own `timeout`.
|
||||||
5. **`32400` answers TLS only to remote clients.** PMS requires secure
|
5. **`32400` answers TLS only to remote clients.** PMS requires secure
|
||||||
connections, so `curl http://192.168.0.235:32400/identity` from any other
|
connections, so `curl http://192.168.0.235:32400/identity` from any other
|
||||||
machine closes without a single byte (curl exit 52) — that reads as a dead
|
machine closes without a single byte (curl exit 52) — that reads as a dead
|
||||||
@@ -131,10 +136,13 @@ shred -u /tmp/px.tok
|
|||||||
```
|
```
|
||||||
|
|
||||||
Every section answers `204` — or `200` with a Directory body when
|
Every section answers `204` — or `200` with a Directory body when
|
||||||
`Accept: application/json` is sent. Inside the quoted `printf` format a
|
`Accept: application/json` is sent. A refresh fired while PMS is still warming
|
||||||
backslash-newline is LITERAL, not a continuation, so `mk` writes two `printf`s:
|
answers `000` instead (the empty reply of gotcha 4, arriving mid-request): retry
|
||||||
one glued line and one stray backslash is a config file curl rejects, and the
|
until it answers and never restart the service over it. Inside the quoted
|
||||||
failure prints as `option -K: is unknown`, never as a bad config line.
|
`printf` format a backslash-newline is LITERAL, not a continuation, so `mk`
|
||||||
|
writes two `printf`s: one glued line and one stray backslash is a config file
|
||||||
|
curl rejects, and the failure prints as `option -K: is unknown`, never as a bad
|
||||||
|
config line.
|
||||||
|
|
||||||
Proof that a rename landed is not a scan response: `scripts/media-verify.py`
|
Proof that a rename landed is not a scan response: `scripts/media-verify.py`
|
||||||
replays the run's journal against the database — the only read that
|
replays the run's journal against the database — the only read that
|
||||||
|
|||||||
@@ -107,6 +107,12 @@ job.sh watch # refreshing status table
|
|||||||
`ssh 'bash -c "python3 -c \"…\""'` quoting broke repeatedly (unterminated
|
`ssh 'bash -c "python3 -c \"…\""'` quoting broke repeatedly (unterminated
|
||||||
quotes; `grep -c` returning `"0\n0"` because `|| echo 0` appended a line)
|
quotes; `grep -c` returning `"0\n0"` because `|| echo 0` appended a line)
|
||||||
every failure disappeared once the script was a file.
|
every failure disappeared once the script was a file.
|
||||||
|
- **A script fed over stdin owns that stdin.** `ssh host 'bash -s' <<'EOS'` hands
|
||||||
|
the script itself to stdin, so any child that reads stdin — `podman exec -i`,
|
||||||
|
`ssh -t`, a bare `read` — swallows everything after it and the remainder
|
||||||
|
vanishes without a word. It reads exactly like a hang: the commands before the
|
||||||
|
child print, the ones after never existed. Drop `-i`, or give every child
|
||||||
|
`< /dev/null`.
|
||||||
|
|
||||||
## Verify before trusting it (3am law)
|
## Verify before trusting it (3am law)
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user