Clearing custom normals not working as expected in add-on

I have a button in an add-on that is supposed to loop through your selected objects and clear custom split normals data, among other common mesh cleanup tasks. This code works perfectly fine in a standard Python script:

import bpy

selection = bpy.context.selected_objects
  
for ob in selection:
    if ob.type == 'MESH':
        bpy.context.view_layer.objects.active = ob
        bpy.ops.mesh.customdata_custom_splitnormals_clear()

But the same code does not work in the context of the add-on.

class ClearCustomNormalsOperator(bpy.types.Operator):
    bl_idname = "mesh_cleanup.test"
    bl_label = "Clear Custom Normals"
    
    def execute(self, context):
        selection = context.selected_objects
        
        for ob in selection:
            if ob.type == 'MESH':
                context.view_layer.objects.active = ob
                bpy.ops.mesh.customdata_custom_splitnormals_clear()
                
        return {'FINISHED'}

Pressing this button in the add-on only clears split normals data for the last active object it loops through (whatever the last object you selected basically). Is there something obvious I’m missing here, or are mesh operators treated differently within the context of add-ons?