Why can’t I use “%s” format value in the WordPress function checked?

Because the order of operations means you’re passing that variable into your checked function before the printf function is even being run, which is what’s parsing the enumerated variables.

Here’s a possible solution haven’t tested it though:

printf(
    '<input type="checkbox" id="%2$s" name="%1$s[%2$s]" %3$s)'.
    '<label for="%2$s">%4$s</label>' .
    '<hr />',
    $args['option_name'],
    $args['name'],
    checked("on", $args['value'], false ),
    $args['description']    
);