It appears that the manner in which app1 is coded may be the culprit. If I change from a network stream to a local file as input, the problem disappears, and even the simple
open(FH,"app1 args | app2 args |"); form works as expected (all children and the enclosing shell are killed when I close FH).
Thus I'm off to visit app1's source. Many thanks for the guidance.