I have done some playing around, and created a simple window for evaluating and playing with how events work in Kivy.
Here is my example. As you mentioned ZenCode, as soon as I add on_touch_down() methods to my widgets, event bubbling doesn't take place. In this default example only the top level widget, a FloatLayout, gets touch_down events no matter where I touch:

...so as has been pointed out, touch event bubbling is prevented when you override on_touch_down(). This makes sense because the Widget class' on_touch_down() method is defined in the
kivy.uix.widget.py file, and it dispatches events to the Widget's children. Override that method: no dispatch is called.
Notice that I have placed "# TESTPOINT XYZ" comments ahead of the on_touch_down() methods so I can reference them here:
If I have a top-level Widget (MyFloatLayout) with no on_touch_down() method, touches pass to its children, as seen:
(see TESTPOINT FLOAT)
MyLabel: touched! Oddball
MyScrollView: touched! [2, 2]
MyScrollView: touched! [1, 2]
MyScrollView: touched! [2, 1]
MyScrollView: touched! [1, 1]
If I uncomment the same method, but leave commented the <code>super(MyFloatLayout, self).__init__(*args, **kwargs)</code>, I see only:
MyFloatLayout: touched! root
If I uncomment the <code>super(MyFloatLayout, self).__init__(*args, **kwargs)</code>, I see:
MyLabel: touched! Oddball
MyScrollView: touched! [2, 2]
MyScrollView: touched! [1, 2]
MyScrollView: touched! [2, 1]
MyScrollView: touched! [1, 1]
MyFloatLayout: touched! root
So the super() merely allows the event to bubble through, and then the remaining code (the print statements- eg, "...touch! root") in the on_touch_down() of my custom widgets are executed.
Now let's take a look at the children of root's MyScrollView children, as I uncomment the super() call in the on_touch_down() method at TESTPOINT SCROLL. In my app, the last widget added is the odd_label. Then the ScrollViews are added; the last one is myscrollview named [2, 2]. Each ScrollView has a StackLayout added to it, and prior to that a series of Labels are added.
The order of adding widgets is, in reverse from LAST to FIRST, is:
odd_label, 4 * [ myscrollview, mystacklayout, a_label (10 of them) ], MyFloatLayout. So the last is the parent of everyone.
A touch event thus looks like this. Notice that mystacklayout overrides the on_touch_down() method but does not have a call to super(), so its children do not see the events:
MyLabel: touched! Oddball
MyScrollView: touched! [2, 2]
MyScrollView: touched! [1, 2]
MyScrollView: touched! [2, 1]
MyScrollView: touched! [1, 1]
MyFloatLayout: touched! root
MyStackLayout: touched! [2, 2]
The event distribution goes like this:
The event took place in the parent, MyFloatLayout, so it is dispatched to its children. odd_label gets it first, since it was the last widget added to MyFloatLayout. Now its peers will get them: all four of the myscrollview's, in reverse order of their adding. So far so good.
Next, the parent MyFloatLayout gets it. This is where it gets interesting: after the children of root see the event, the children of its children will get it- but only if I click within one of those widgets that contains the children. Here I have clicked in the upper right (position 2,2) of the four boxes of labels. So the event is dispatched to that mystacklayout instance. There is no super() to mystacklayout's on_touch_down method so the event stops bubbling.
Inteed, if I uncomment the super() to mystacklayout's on_touch_down method, and if I click into the 2,2 MyScrollView, I see:
MyLabel: touched! Oddball
MyScrollView: touched! [2, 2]
MyScrollView: touched! [1, 2]
MyScrollView: touched! [2, 1]
MyScrollView: touched! [1, 1]
MyFloatLayout: touched! root
MyLabel: touched! [2, 2]_lbl: 9
MyLabel: touched! [2, 2]_lbl: 8
MyLabel: touched! [2, 2]_lbl: 7
MyLabel: touched! [2, 2]_lbl: 6
MyLabel: touched! [2, 2]_lbl: 5
MyLabel: touched! [2, 2]_lbl: 4
MyLabel: touched! [2, 2]_lbl: 3
MyLabel: touched! [2, 2]_lbl: 2
MyLabel: touched! [2, 2]_lbl: 1
MyLabel: touched! [2, 2]_lbl: 0
MyStackLayout: touched! [2, 2]
Similarly for the other myscrollview's: The only label's that get the event are those that are children of the MyStackLayout which is a child of the MyScrollView in which the touch takes place. It appears that what happens is this; it's really quite simple:
A. If a touch happens on a widget, then that widget and all if its immediate children will see the touch event.
B. Since the event is dispatched through a Python method, then if you override that method without calling super() you will lose the dispatch mechanism to that widget's list of children.
C. If a widget's event method returns True, Kivy will not dispatch the event any longer. Note that if you return true and override a method such as on_touch_down() and use super() in it, its children will still receive the event but other peers added to the parent widget before it will not get the event.
D. Once the event has been dispatched to the widget and all of its children, it is checked to see if it collides with any of the children. If so, go back to step A where "widget" is now that child.
All widgets at a level in the widget heirarchy receive the event in order of the latest widget added. This order is consistent so that peers receive the event in the order of when they were added, from the last peer added to the first. Children receive the event in the same order, from the last child added to the first.
However, only children of the topmost touched child (if any) will see the event. Notice how the MyStackLayout and the MyLabels get the event, but only because I clicked in the MyScrollView parent of the MyStackLayout in position [2, 2].
If I click in the background OR on the oddball label- that is, not on any of the myscrollviews:
MyLabel: touched! Oddball
MyScrollView: touched! [2, 2]
MyScrollView: touched! [1, 2]
MyScrollView: touched! [2, 1]
MyScrollView: touched! [1, 1]
MyFloatLayout: touched! root
Again, all peers get the event, but it doesn't carry into all the children of the myscrollview's. The rule stands: the touch must happen on a widget (Step A, above). It and all its immediate children will see the touch event.
Children will only receive the event if their parent has super() in the event method that overrides the widget's event method, or if their parent doesn't override the widget's event method at all.