docs(363): sweep the scan-flow drift the re-review caught
Build ErsatzTV Image / CI image pin matches docker/ci (pull_request) Successful in 6s
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 8s
Build ErsatzTV Image / decisions.md append-only (pull_request) Successful in 8s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 7m12s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 8s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Successful in 6s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 18m36s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
Build ErsatzTV Image / Functional E2E (curl contracts) (pull_request) Successful in 14m18s

The fix commit softened the script's scan-409 wording + dropped ?deep=true but
left the docs describing the old behavior. Match them:
- docs/e2e-local.md: POST .../scan (no ?deep; note local scans always ForceScan)
  + "409, deterministic bar a tiny residual TOCTOU gap" (was "guaranteed 409")
- docs/ci-cd.md: same "guaranteed 409" -> "409 (deterministic bar ...)"

Docs-only; harness behavior unchanged (still 38/38 green, deterministic).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-18 15:44:47 +02:00
co-authored by Claude Opus 4.8
parent 4345180a56
commit a1b75c1f2c
2 changed files with 9 additions and 7 deletions
+3 -2
View File
@@ -301,8 +301,9 @@ image's ffmpeg, to exercise two `IEntityLocker` contracts **deterministically**
racing request once the lock is *provably* held, never a sleep-and-hope): (a) the **library-scan
"already scanning" 409** — seed ~60 tiny clips into the built-in Shows library so the scanner
subprocess runs a few seconds, poll `GET /libraries/scan-status` until the library shows active (that
window is a strict subset of the scan lock's held window), then a second `POST .../scan` is a
guaranteed 409; (b) the **external-collections "already scanning" 409** — the per-family lock is taken
window is a strict subset of the scan lock's held window), then a second `POST .../scan` is a 409
(deterministic bar a tiny residual TOCTOU gap the multi-second scan covers); (b) the
**external-collections "already scanning" 409** — the per-family lock is taken
synchronously *before* the 202, so the 202 proves it held, and pointing the seeded source at a
non-routable address keeps the background sync hung so the window stays open. No new CI step or
dependency: ffmpeg ships in the toolchain image, and python3 was already a harness dependency
+6 -5
View File
@@ -161,11 +161,12 @@ What it covers. Most assertions are curl-only (no seeded media / ffmpeg / browse
API can't create straight into the running instance's DB via python3's stdlib `sqlite3` (whose
busy-timeout retry serializes behind the app's writer):
- **library-scan "already scanning"**: seed ~60 tiny ffmpeg clips into the built-in Shows library
(Id=2) so the scanner subprocess runs a few seconds → `POST .../scan?deep=true` `202` → poll
`GET /libraries/scan-status` until library 2 shows active (that window is a strict subset of the
scan lock's held window — `ScannerProxyService.StartScan` fires *after* `LockLibrary`, `EndScan`
*before* `UnlockLibrary`) → a second `POST .../scan` is a guaranteed `409`. Self-skips (advisory)
if ffmpeg is absent.
(Id=2) so the scanner subprocess runs a few seconds → `POST .../scan` `202` (local scans always
ForceScan, so no `deep` needed) → poll `GET /libraries/scan-status` until library 2 shows active
(that window is a strict subset of the scan lock's held window — `ScannerProxyService.StartScan`
fires *after* `LockLibrary`, `EndScan` *before* `UnlockLibrary`) → a second `POST .../scan` is a
`409`, deterministic bar a tiny residual TOCTOU gap the multi-second scan covers. Self-skips
(advisory) if ffmpeg is absent.
- **external-collections "already scanning"**: seed a Jellyfin media-source row pointing at a
non-routable address (so the background sync hangs and the per-family lock stays held). The lock
is taken synchronously *before* the `202`, so the `202` proves it held → `collections-scan-status`