Dankserver rebooted with the array's mount and the media containers racing. In a rootless quadlet RequiresMountsFor= is inert — the user manager cannot
order against the system's mnt-entropy.mount — so podman resolved the bind
against the pre-mount directory. Jellyfin and Plex came up blind, Jellyfin read
an empty library and logged Removing item, Type: "Season" by the thousand, and
nothing refused. Copyparty (Volume=/mnt/entropy:/w:ro) had no guard at all.
Change
scripts/wait-for-mount.sh [-t SECONDS] MOUNTPOINT... — waits for each named
mountpoint, then refuses by name. Exit 0 mounted, 1 refused, 2 usage.
jellyfin.container, plex.container, copyparty.container gain ExecStartPre=…/scripts/wait-for-mount.sh <sources>; the two media units drop UnitConfigItem=ConditionPathIsMountPoint=.
Why not the Condition (measured on the host): an unmet condition logs skipped, unmet condition check with NRestarts=0 and no start attempt ever follows,
so a mount that lands one second late leaves the service dead until a human
starts it. That is fail-dead. The gate waits, and Restart=always carries it.
Law recorded in AGENTS.md (Boot Persistence) and in Media Metadata View (guard, law, and the blind-bind failure signature).
Verification
On the host, isolated in a scratch XDG_CONFIG_HOME so no live unit was touched:
the podman 5.7.0 generator acceptsExecStartPre in [Service] (exit 0,
all three units generated, gate line present) — the key is not a batch killer;
the gate waits for a bind mount that appears 2 s into its window and proceeds
(exit 0);
it refuses a plain directory after the window, naming the path (exit 1).
New seam tests/array_mount_gate.bats: 6 pass, 1 skip (creating a mount needs
privileges the dev box withholds — that case is the host run above).
The one pre-existing test touched
tests/media_overlay.bats asserted "both media servers bind the view and refuse
to start without it" by grepping the old key by name. Same intent, new mechanism:
the assertion now rides the gate. Nothing else in that file changed.
## Why
Dankserver rebooted with the array's mount and the media containers racing. In a
**rootless** quadlet `RequiresMountsFor=` is inert — the user manager cannot
order against the system's `mnt-entropy.mount` — so podman resolved the bind
against the *pre-mount* directory. Jellyfin and Plex came up blind, Jellyfin read
an empty library and logged `Removing item, Type: "Season"` by the thousand, and
nothing refused. Copyparty (`Volume=/mnt/entropy:/w:ro`) had no guard at all.
## Change
- `scripts/wait-for-mount.sh [-t SECONDS] MOUNTPOINT...` — waits for each named
mountpoint, then refuses **by name**. Exit 0 mounted, 1 refused, 2 usage.
- `jellyfin.container`, `plex.container`, `copyparty.container` gain
`ExecStartPre=…/scripts/wait-for-mount.sh <sources>`; the two media units drop
`UnitConfigItem=ConditionPathIsMountPoint=`.
- Why not the Condition (measured on the host): an unmet condition logs `skipped,
unmet condition check` with `NRestarts=0` and **no start attempt ever follows**,
so a mount that lands one second late leaves the service dead until a human
starts it. That is fail-*dead*. The gate waits, and `Restart=always` carries it.
- Law recorded in `AGENTS.md` (Boot Persistence) and in
[[Media Metadata View]] (guard, law, and the blind-bind failure signature).
## Verification
On the host, isolated in a scratch `XDG_CONFIG_HOME` so no live unit was touched:
- the podman 5.7.0 generator **accepts** `ExecStartPre` in `[Service]` (exit 0,
all three units generated, gate line present) — the key is not a batch killer;
- the gate waits for a bind mount that appears 2 s into its window and proceeds
(exit 0);
- it refuses a plain directory after the window, naming the path (exit 1).
New seam `tests/array_mount_gate.bats`: 6 pass, 1 skip (creating a mount needs
privileges the dev box withholds — that case is the host run above).
## The one pre-existing test touched
`tests/media_overlay.bats` asserted "both media servers bind the view and refuse
to start without it" by grepping the old key by name. Same intent, new mechanism:
the assertion now rides the gate. Nothing else in that file changed.
---
cwd: /home/blank/.omp/wt/array-gate · session: 2026-10-30T23-38-45-297Z_01a18f2e-18b1-7573-bcd5-ac99636f8bcb
Dankserver rebooted with the array's mount and the media containers racing. A
rootless quadlet cannot order itself against the system's mnt-entropy.mount, so
`RequiresMountsFor=/mnt/entropy` is inert in the user manager: podman resolved
the bind against the pre-mount directory, Jellyfin and Plex came up blind, and
Jellyfin read an empty library and began `Removing item, Type: "Season"` by the
thousand. Copyparty had no guard at all.
`scripts/wait-for-mount.sh` is the gate: it waits for every named mountpoint,
then refuses by name. `ConditionPathIsMountPoint=` is NOT the fix — measured on
the host, an unmet condition logs `skipped, unmet condition check` with
NRestarts=0 and no start attempt ever follows, which is fail-dead, not
fail-closed. Jellyfin and Plex swap the condition for the gate; Copyparty gets
one; the law is recorded in AGENTS.md and the view page.
Verified on the host: the 5.7.0 quadlet generator accepts ExecStartPre in
[Service] (exit 0, all three units generated, gate present), the gate waits for
a mount that appears mid-window and proceeds, and it refuses a plain directory
after its window naming the path.
tests/media_overlay.bats pinned the old mechanism by name; its intent — both
media servers refuse to start without the view — now rides the gate.
dank
merged commit 6d274acc47 into main2026-10-31 18:20:40 -07:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Why
Dankserver rebooted with the array's mount and the media containers racing. In a
rootless quadlet
RequiresMountsFor=is inert — the user manager cannotorder against the system's
mnt-entropy.mount— so podman resolved the bindagainst the pre-mount directory. Jellyfin and Plex came up blind, Jellyfin read
an empty library and logged
Removing item, Type: "Season"by the thousand, andnothing refused. Copyparty (
Volume=/mnt/entropy:/w:ro) had no guard at all.Change
scripts/wait-for-mount.sh [-t SECONDS] MOUNTPOINT...— waits for each namedmountpoint, then refuses by name. Exit 0 mounted, 1 refused, 2 usage.
jellyfin.container,plex.container,copyparty.containergainExecStartPre=…/scripts/wait-for-mount.sh <sources>; the two media units dropUnitConfigItem=ConditionPathIsMountPoint=.skipped, unmet condition checkwithNRestarts=0and no start attempt ever follows,so a mount that lands one second late leaves the service dead until a human
starts it. That is fail-dead. The gate waits, and
Restart=alwayscarries it.AGENTS.md(Boot Persistence) and inMedia Metadata View (guard, law, and the blind-bind failure signature).
Verification
On the host, isolated in a scratch
XDG_CONFIG_HOMEso no live unit was touched:ExecStartPrein[Service](exit 0,all three units generated, gate line present) — the key is not a batch killer;
(exit 0);
New seam
tests/array_mount_gate.bats: 6 pass, 1 skip (creating a mount needsprivileges the dev box withholds — that case is the host run above).
The one pre-existing test touched
tests/media_overlay.batsasserted "both media servers bind the view and refuseto start without it" by grepping the old key by name. Same intent, new mechanism:
the assertion now rides the gate. Nothing else in that file changed.
cwd: /home/blank/.omp/wt/array-gate · session: 2026-10-30T23-38-45-297Z_01a18f2e-18b1-7573-bcd5-ac99636f8bcb