When re-submitting a version to stores where the previous review was APPROVED:
1. markSubmitted now sets those stores to WITHDRAWN (not PENDING), preserving
the old batchId/submittedAt for traceability. This signals to executeSubmitAsync
that the store cancel API must be called before a new submission is attempted.
2. executeSubmitAsync detects the WITHDRAWN state and calls cancelAtStore first,
then falls through to the normal submission path. This revokes the old approval
on the store's side so no stale webhook or poll cycle can fire APPROVED for the
old review after re-submission.
3. updateStoreReview now rejects APPROVED transitions from PENDING or WITHDRAWN
states (stale webhook guard). A valid approval can only arrive after the store
has seen the new submission (i.e. current state must be SUBMITTING or UNDER_REVIEW).
This prevents autoPublishAfterReview from triggering before the new review cycle.
Operation log includes `approvedWithdrawn` list when any store was withdrawn on re-submit.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>