Two holes the review round found in the previous fix, both of the same shape: a
guard that names its own fields instead of deriving them.
The deco validators short-circuited the entire Validators.IdsMustExist call when
the DecoMode does not consume the ids, which took the 512-item raw-count cap with
it -- an arbitrarily large array under Inherit/Disable parsed and materialized
with nothing bounding it. Only the EXISTENCE half is the apply path's business,
so the mode predicate is now a required argument of the shared validator and gates
that half alone; the cap runs under every mode.
The channel recovery path rechecked GraphicsElementIdsMustExist alone, so a
watermark deleted between validation and SaveChangesAsync still surfaced as the
unhandled 500 the fix exists to remove -- WatermarkId, FFmpegProfileId,
FallbackFillerId and MirrorSourceChannelId are all written by the same save and
lose the same race. Both handlers now re-ask the whole of Validate on
DbUpdateException, so a validator added later is covered without editing the
recovery path.
The API-site outside-folder discriminator test seeded an Image row, so the Kind
conjunct rejected it whatever the path comparison did: a composite revert to
Path.GetFileName(path) == filename && kind == Text passed every API test. It now
carries the seeded Kind, mirroring the seeder-site twin, so only the path half can
reject it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015QqCpYFsKgnAnx6jVwrKiV