Final-review follow-ups:
- MediaAttacher::resolveInlineMedia now deletes the media it hosted in this call
when any item fails, so a mixed [good, bad] batch no longer orphans the good
item's Media row + file while the request is correctly rejected with 422. Makes
the create/update media resolution truly all-or-nothing.
- PostMediaRules: keep source/source_meta on both contracts (the API previously
passed them through with no item rules — don't silently drop them) so the media
item shape is uniform; only id/path/url differ by contract.
- Make MediaAttacher::fetchToWorkspace private (no external callers).
- Test the partial-batch rollback (no Media, no post persisted).