Build ErsatzTV Image / CI image pin matches docker/ci (pull_request) Successful in 5s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Successful in 10s
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 11s
Build ErsatzTV Image / decisions.md append-only (pull_request) Successful in 28s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 1m24s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Failing after 3m45s
Build ErsatzTV Image / Functional E2E (curl contracts) (pull_request) Successful in 14m16s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 19m46s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
Extends scripts/e2e-functional.sh with the two IEntityLocker 409 contracts the first cut (ersatztv#299) deferred as "racy", made DETERMINISTIC by firing the racing request only once the lock is provably held (no sleep-and-hope): - library-scan "already scanning" 409: seed ~60 tiny ffmpeg clips into the built-in Shows library so the scanner subprocess runs a few seconds, poll GET /libraries/scan-status until the library is active (that window is a strict subset of the scan lock's held window — StartScan after LockLibrary, EndScan before UnlockLibrary), then a second POST .../scan is a guaranteed 409. Self-skips (advisory) when ffmpeg is absent. - external-collections "already scanning" 409: 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 corroborates; unknown source 404. Seeding uses python3's stdlib sqlite3 (already a harness dep) to insert rows the API can't create (LibraryPath, media-source); WAL mode tolerates the second writer. No new CI step/dependency — ffmpeg ships in the toolchain image. Verified: 4/4 fresh-instance runs green (38/38), lock section deterministic. Still deferred to #363 follow-ups: the playout-build lock 409 + isLocked projection (#215) and the UI-interactive Playwright flows. Docs updated same PR: docs/e2e-local.md, docs/ci-cd.md, the functional-e2e job comment in .gitea/workflows/docker-build.yml. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>