So native messaging is fundamentally about opening a named pipe to a child process managed by the browser. I found that the pipe would silently break or time out. In the former scenario, the app was running but could no longer exchange native messages with the browser or extensions - chrome was just ignoring the pipe traffic. In practice I was able to use native messaging to spawn the executable but to actually talk with it I needed to use a websocket, kind of defeating the point.
I initially assumed I was doing something wrong but after a week or so experimenting with simple test cases I could not get it to work. Maybe it works fine on Linux and Mac but not Windows.