Skip to content

fix(posts): per-platform media validation instead of shared list - #11

Merged
Cryptoom merged 1 commit into
mainfrom
claude/tpx-05-a2-validation
Sep 16, 2026
Merged

Cryptoom merged 1 commit into
mainfrom
claude/tpx-05-a2-validation

Conversation

@Cryptoom

Copy link
Copy Markdown
Owner

Summary

ContentTypeCompatibleWithMedia::entriesForUpdate() now resolves each platform entry's own effective media list instead of validating every platform against one shared list. Wires PR #9's (A1) PostPlatform::scopedMediaItems() into validation for the first time.

Resolution order per entry:

  1. Request-resubmitted media, when present (applies uniformly, there is no per-platform media field in the request yet).
  2. That platform's own scopedMediaItems() (pivot-scoped selection; falls back internally to the post's full media when the pivot has no rows for that platform, today's universal case, so no behavior change there).
  3. The post's full stored media, only reached when no PostPlatform row could be resolved for the entry at all (defensive).

errorsFor() consumes each entry's own media key instead of a second shared $media parameter.

Randfall handled deliberately: a content_type that requires media (e.g. facebook_story) whose scoped media resolves to an empty list still correctly fails with the "requires media" error. This is the correct behavior, not a bug to soften, and is covered by a dedicated test.

Call sites updated to match:

  • app/Http/Requests/App/Post/UpdatePostRequest.php: replaced the old field-level Rule::when(..., [new ContentTypeCompatibleWithMedia]) (bound to one shared $data['media']) with an after() validator using entriesForUpdate()/errorsFor(), mirroring what the public API request already did. This also closes the same "schedule/publish without resubmitting content_type" gap the API path already covered, which the field-level rule never handled for the web app.
  • app/Http/Requests/Api/Post/UpdatePostRequest.php: passes requestMedia into entriesForUpdate() instead of pre-resolving a shared media array.
  • app/Mcp/Tools/Post/UpdatePostTool.php: drops the now-removed second errorsFor() argument.
  • assertStoredPostCompatible() (used by PublishPostTool): same, drops the second argument.

Also fixes a lazy-loading bug surfaced while wiring this in: PostPlatform::scopedMediaItems() reads $this->post->mediaItems, which throws under Model::shouldBeStrict() (tests/local) unless the inverse post relation is pre-set. Added a private postPlatformsFor() helper that sets it on every fetched PostPlatform before scopedMediaItems() can be called.

Test plan

  • tests/Unit/Rules/ContentTypeCompatibleWithMediaTest.php: 48 passed, including 6 new tests covering all three fallback stages, the empty-media randfall, two platforms validating independently against different effective media, and assertStoredPostCompatible().
  • tests/Feature/UpdatePostRequestTest.php (web): 26 passed.
  • Api + MCP post/media/publish feature tests (PostApiPlatformMetaTest, PostMediaApiTest, PostApiTest, PostMediaExistsValidationTest, PostToolTest, PostPlatformMetaToolTest, PostPublishToolTest, PublishPostTest): 194 passed.
  • Broader Post/Media/Platform sweep (79 files): 849 passed, 1 pre-existing skip.
  • vendor/bin/pint --dirty --format agent: passed, no changes needed.
  • Two independent code-review rounds (adversarial, separate agent runs): both PASS, no blockers or majors.

🤖 Generated with Claude Code

ContentTypeCompatibleWithMedia::entriesForUpdate() now resolves each
platform entry's own effective media list (request media if resubmitted,
else PostPlatform::scopedMediaItems(), else the post's full stored media)
instead of validating every platform against one shared list. errorsFor()
consumes each entry's own media accordingly.

Wires A1's scopedMediaItems() helper into validation for the first time.
A content_type that requires media whose scoped selection resolves to
none still correctly fails, deliberately not softened.

Web UpdatePostRequest now runs the check via an after() validator (like
the API request already did) instead of a field-level Rule bound to a
single shared $data['media'], closing the same "publish without
resubmitting content_type" gap the API path already covers.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Cryptoom
Cryptoom merged commit 7b73cf5 into main Sep 16, 2026
@Cryptoom
Cryptoom deleted the claude/tpx-05-a2-validation branch September 16, 2026 22:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant