In HTTP/2 the server pushes to the client a request for the resource with a PUSH_PROMISE frame.
While going from server to client, this is not a response, but a request, the request the client would make to fetch that resource.
When the client receives the PUSH_PROMISE, it can look at the URI, and figure out the cache status of this resource. Browsers typically use different caches for normally received resources and pushed resources.
If the cache is still valid, the client may cancel the pushed stream by sending a RST_STREAM frame to the server for that stream.
Meanwhile, the server starts what it takes to push the resource. This will generate a HEADERS response frame that will contain the typical response headers such as etag.
When the client receives the HEADERS response frame, it has one more chance to cancel the stream, although - of course - DATA frames may be inflight, possibly all of them.
Saving bandwidth may be interesting, but it's typically not a problem to waste a little bandwidth; what matters more from the user experience point of view is the latency, and the push mechanism reduces that by a considerable amount.
I don't think the push mechanism compromises any client cache optimization; had this been the case, browser vendors would have fought against this feature, while instead most of them (if not all) implement it with very good results in user experience and diminished latency.
Sure the mechanism could be improved, for example by having clients and servers agree on some header that will give more information about the resource being pushed, but so far works fairly well.
[Disclaimer: I'm a Jetty committer]
Having been the first to implement SPDY and HTTP/2 Push for the Java ecosystem (almost 3 years ago), the Jetty Project is certainly interested in more discussions and ideas around HTTP/2 Push.