That @observe is looking for two different traits on Foo, bar (which exists) and value) which does not.
If you wish to observe bar.value, and bar can change, your bar observer needs to delegate the value observing to the new bar instance (and clean up any old handlers)
@observe("bar")
def _observe_bar(self, change):
if change.old:
change.old.unobserve(self._on_bar_value, ["value"])
if change.new:
change.new.observe(self._on_bar_value, ["value"])
def _on_bar_value(self, change):
print('asdfasdf')
print(change['old'])
print(change['new'])