Hi Christian,
It's intentional that you can't see the event in this case. Eventually, we expect that the third server will be able to form a direct connection to the first server here, so the second server is cut out of the loop.
There are three design patterns you can use to get what you want here, depending on who you trust:
1) If the second server trusts the first server, it can ask the first server to create a new capability representing the same underlying object (presumably implemented as a wrapper), and then notify the second server when that capability is dropped. Then, pass the new wrapper capability off to the third server.
interface Foo {
getNotifyOnDropWrapper @0 (observer :Capability) -> (wrapped :Foo);
# Returns a new capability pointing to this same object, but which also
# holds on to `observer`, such that when the new capability is dropped,
# `observer` is dropped too. This allows the caller to be notified when
# the new capability is dropped.
}
2) If the second server trusts the third server, it can pass the third server a second capability that has no methods, and say "please drop this capability at the same time as you drop the main one". Then listen for the second capability to be dropped. Caveat: In the future where the third server forms a direct connection to the first server to handle the main capability, then these two capabilities end up on two different connections, and it's possible that one of the connections will become broken (thus automatically dropping the capability) before the other one does.
3) If the second server only trusts itself, then it must arrange to force messages to be proxied through it. The second server can construct its own wrapper around the capability, which just forwards all calls to the original capability, but whose destructor notifies the second server that the capability has been dropped. Then it sends only the wrapper to the third server. Note that the most efficient way to implement this (in C++, at least) is by using membranes; see capnp/membrane.h. "Membranes" are a fancy form of wrappers that can also transitively wrap any capabilities received *through* the original capability. Possibly more importantly for you, though, is that membranes implement proxying of calls in a more efficient way than you'd normally achieve by writing a wrapper in the obvious way.
I recommend #1 if it fits.
-Kenton