As noted, the bogus event is fired because TerraTabPaneSkin sets the selected index in response to the initial tab insert event, and then TabPane fires an additional event based on incorrect information.
This represents an interesting design challenge. It is similar to the challenge of keeping a ListView's model and selection state in sync. In Swing, this is handled by the UI delegate (i.e. the skin). When the model fires events, the skin is responsible for updating the component's selection state.
We intentionally chose not to do it this way since it seemed like the component should be responsible for maintaining its own state internally. However, after some further thought I'm wondering if the Swing approach might be better. We had initially viewed the skin as the "view" and the component as the "controller" - however, in retrospect, I think the component is actually the "view-model", and the skin is the "view-controller". The component is part view because it is the object that actually receives user input and paint calls (though it delegates them to the skin). It is part model since it generally hosts the model (either as an intrinsic property like "buttonData" or as an attached model like "listData"). The skin is part view because it actually handles the paint calls, and part controller since it handles user input and other events and updates the component's (i.e. model's) state in response to them.
When viewed as a controller, it seems valid for the skin to be responsible for keeping the component's various models in sync. Since there will never be a practical case where a component does not have a skin installed, this seems OK to me. It means that, in this case, TabPane wouldn't fire an indirect selection change event when a tab is inserted - it would be up to the skin to respond to that event appropriately (which it already does). The skin should also do something similar when a tab is removed.
What do you think? FYI, this would be a big change, as it affects the design of many components. However, I think it could probably be restricted to TabPane, Accordion, and CardPane for now and propagated to ListView, TableView, etc. later.