Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 7s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 4m39s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 5m30s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
Codex independent review of #263 surfaced two defects the fork review missed: - High — client load TOCTOU: BlockEditor read root metadata (getBlock) and items+ETag (getBlockItemsWithMeta) concurrently, so a concurrent write landing between them (with the items read resolving last) left a stale root paired with a current ETag → the save silently overwrote the concurrent change with no 412. Fix: read items+ETag FIRST, then the root metadata, so the captured ETag is never newer than the root version and any inconsistency fails safe (save 412s → conflict dialog → reload). - Medium — `ParseIfMatch` accepted non-canonical strong tags ("03", "+3", " 3 ") as version 3. An ETag is opaque; only the exact emitted form is valid. Fix: canonical decimal only (`NumberStyles.None` + no leading zeros) → else 400. Tests: new `ConcurrencyHeadersTests` (canonical parse + padded/signed/whitespace/weak/ unquoted/list/overflow/empty → malformed); `ApiResultsTests` gains the 412 mapping case. Existing BlocksScreen tests still green (load reordering is behavior-preserving for the non-concurrent path). Refs #253 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>