I had defined an action called `init` in one of my controllers. Turns out this causes the action to run as soon as the controller is instantiated, before the app's `launch` event has been fired. Renaming the action made everything run as expected.
I can't find reference to the special behavior of the `init` action in the Sencha Touch doc. It would be good to put this in there!