Binding approval to a digest of an immutable revision is the right shape, and the point about not re-reading a mutable draft between the hash check and execution is the subtle part. One suggestion is to make the claim itself atomic, for example an UPDATE ... WHERE revision_id = approved AND status = 'approved' that flips the row to 'publishing' and checks the affected row count, so two workers cannot both execute the same approval. For canonicalization, json.dumps with sort_keys is fine inside one codebase, but if another service ever recomputes the digest, a spec like RFC 8785 (JCS) removes float and Unicode normalization ambiguity. Another question is whether the digest should also cover the schema version and the reviewer-visible rendering (for instance, the preview that was shown), since an approval is only meaningful relative to what the person actually saw. How would you handle media that is transformed by the platform after upload, where the fingerprint at execution can no longer match?