WP_Query ordered by meta_value_num doesn’t fetch posts without this meta field

The reason you’re only getting those users that have that meta_key is because you’re include 'meta_key' => '...' in $args. That limits results to those that have that key, regardless of any clauses you may have in a meta_query. This applies to WP_Query, WP_User_Query and WP_Comment_Query.

Starting in WP 4.2, you can “name” the clauses in a meta_query and then use those “names” in the orderby clause, see Query improvements in WP 4.2: ‘orderby’ and ‘meta_query’. Unfortunately, the code reference and codex entries for WP_Query and WP_User_Query haven’t been updated to reflect this, altho WP_Meta_Query does cover it.

So, you can ALMOST get what you’re after with the following:

$args = array (
    'role'  => 'my_staff_role',
    'fields' => 'all',
    'meta_query' => array (
        'relation' => 'OR',
        'exists' => array (
            'key' => 'staff_profile_position',
            'compare' => 'EXISTS',
//          'type' => 'NUMERIC',
            ),
        'not_exists' => array (
            'key'     => 'staff_profile_position',
            'compare'   => 'NOT EXISTS',
            ),
        ),
    'orderby' => 'exists not_exists',
    ) ;

Note: To mimic 'orderby' => 'meta_value_num' (as you have in your question) you would have to include 'type' => 'NUMERIC' in the meta_query clauses. However, that causes all of users without to sort to the top, instead of the bottom (which is why I have it commented out above).

Thus, if you can live with having those users with your meta_key to be ordered by that key treated as a string, rather than a number, then the above will do.

If you can’t, then you’ll have to do 2 separate queries (one for those users with the meta_key, ordered numerically by that key, and one for those users without the meta_key) and merge the results of those 2 queries.