I got to the bottom of this. drupal_execute() calls drupal_process_form() whose first line is:
$form_state['values'] = array();Since uc_product_add_to_cart_form_submit() invokes all implementations of hook_add_to_cart_data() and passes $form_state to uc_cart_add_item() as $data, all variables get wiped.
drupal_execute() passes $form_state['values'] to $form['#post'] so it's still possible to refer to the values. However this means drupal_execute() is inherently unusable for uc_cart.module unless you hack the core or have your own version of drupal_execute() and drupal_process_form()
