Validate Custom Post Type fields

Whether a post is a draft or published is defined by the post status, not any of the meta fields, so you’ll have to hook into wp_insert_post_data and force the post_status to draft if anything in your form is invalid:

add_filter( 'wp_insert_post_data', function( $data ) {
    if ( $data['post_type'] != 'zip_code' )
        return $data;

    // Validate your nonces and $_POST fields here
    if ( ! $valid ) {
        $data['post_status'] = 'draft'; // Force draft
    }
});

Also note that wp_insert_post_data runs before save_post, so you’ll have to validate again and save the meta fields in save_post just like you’re already doing.

I would also recommend not using options for admin notice triggers. They’re global for all users, and they’re autoloaded by default every time and everywhere. Use the usermeta table instead by using set_user_setting() and then get_user_setting().

Hope that helps!