A dynamic block has no save output at all

A block rendered by PHP at request time returns null from save, which means the post contains only the block comment and its attributes.

register_block_type( __DIR__, array(
    'render_callback' => function ( array $attributes ): string {
        $posts = get_posts( array(
            'post_type'      => 'product',
            'posts_per_page' => min( (int) $attributes['count'], 12 ),
        ) );

        return turkerdev_render_products( $posts );
    },
) );

// save: () => null   ← in the JavaScript

Returning null is what exempts the block from validation entirely, which means no deprecation array is ever needed and the markup can change freely — the single biggest maintenance saving available. The cost is that the block runs on every page view rather than once at save, so caching becomes your problem. Anything with a query, a date, or content that changes independently of the post should be dynamic for correctness rather than for convenience.