Thanks Corran, that information gave me enough to _almost_ figure it out.
In this case I am working with a top-level plot (traits view containing only a single plot Item, in its own window), sorry I didn't think to specify that earlier. Somehow I had missed the do_layout() method in the documentation. I found the "correct" way to set outer_position and outer_bounds properties in the Component class, using set_outer_position() and set_outer_bounds() methods. While do_layout() does propagate the new padding and bounds to the axis objects, for some reason it does not update the actual axis-line drawing coordinates _origin_point and _end_axis_point. To get the axes to draw correctly, I had to manually call (after do_layout) the private _calculate_geometry() and _compute_tick_positions() methods of each axis. Could this be something of a "bug?"
Now the only thing left is that the bounds of the "background" (which make the plot area appear white and the padding area appear grey), and the x_axis line origin (but only for changes in one direction or the other depending on the order in which I call the two axes' _calculate_geometry() methods), don't update to match the axes lines until the next detection of user interaction -- when I click the mouse button, press CTRL, or even simply move the mouse pointer out of the plot window. Even more strange: if I put a (VS Code) breakpoint anywhere inside my handler function and just hit F5 to continue from that point (without moving the mouse at all from where its button_up event initiated the zoom that led to the event I'm handling), the plot background (and x_axis origin when it's incorrect) gets updated correctly. The commented-out lines in the code snippet below are all things I have tried, in different orders and combinations, plus I tried changing the order of lines before, and of the lines after, the do_layout call. I'm hoping the problem is something you'll notice right away.
Jean-Paul
[inside my handler function triggered by changes to y_axis._tick_label_bounding_boxes]
y_ax = event.object
plt = y_ax.component
x_ax = plt.x_axis
outer_width = plt.outer_width
[compute new_padding_left]
plt.padding_left = new_padding_left # this increases plt.outer_width
plt.set_outer_position(0, 0) # automatically updates plt.position
plt.width = outer_width - plt.hpadding # automatically updates plt.outer_width
plt.do_layout()
x_ax._calculate_geometry() # in this order, _origin_point update delayed when padding_left decreases
y_ax._calculate_geometry() # reversed order, _origin_point update delayed when padding_left increases
x_ax._compute_tick_positions(plt)
y_ax._compute_tick_positions(plt)
# plt.do_layout()
# plt.invalidate_and_redraw()
# plt.request_redraw()
# event.handled = True # also tried setting to False