Build ErsatzTV Image / CI image pin matches docker/ci (pull_request) Successful in 9s
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 11s
Build ErsatzTV Image / decisions lifecycle (pull_request) Successful in 25s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 1m23s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Successful in 1m20s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 7m50s
Build ErsatzTV Image / Functional E2E (curl contracts) (pull_request) Successful in 14m38s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 17m59s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
Second review returned MERGEABLE with one Medium and three Lows. Addressed all four: - Medium: the save-time normalization had zero test coverage, so a later refactor dropping Math.Max would leave the suite green (the FFmpegState floor keeps the pipeline correct, hiding the regression until someone reads a stored 0 back). Added Create/Update_Should_Floor_QsvExtraHardwareFrames over 0, -8, 63, 64 and 128, plus Create_Should_Leave_Null_QsvExtraHardwareFrames_Null for the null-passthrough branch, following the existing QsvPreferNativeDecoder tests' seed/handle/re-read shape. Negative-controlled: reverting both handlers fails exactly 5. - Low: the SPA `min` was cosmetic. Input does forward it to the DOM, but there is no <form> — save is an onClick gated only on validate(), which had no branch for this field, so a typed 10 submitted fine and was silently changed to 64 with a 200 and no message. validate() now rejects it client-side. - Low: the warning fires at the top of SetAccelState, before we know whether the pipeline uploads at all, so a fully-hardware path could be told "using 64 instead" when nothing consumed either value. Reworded to "will use ... wherever frames are uploaded". - Low: recorded in the decision entry that the save-time normalization is unconditional on hardwareAcceleration (a non-QSV profile's stored value moves too), and that a client PUTting 0 reads back 64 — a transform the OpenAPI description does not advertise. Verified in production, not just asserted. Set prod's profile to 64 (operator-approved) and drove the exposed pipeline myself via the troubleshooting playback API on an mpeg4 .avi, which forces software decode + hwupload: hwupload=extra_hw_frames=64,vpp_qsv=w=1875:h=1080 exit 0, speed 12.0x, 0 ENOMEM Then the negative control on prod's own hardware, same command, only the pool differing: extra_hw_frames=64 -> exit 0, 8 segments, 0 ENOMEM extra_hw_frames=0 -> exit 244, 0 segments, 3 ENOMEM which reproduces the six overnight production failures and confirms the fix. Full suite green: 4095 .NET, 891 web. Refs #350, #516, #519.