Add clearer rules for implementations.

This helps implementations know how to handle corner cases, and helps
users know what behavior they can rely on.

R=rnystrom@google.com

Review URL: https://codereview.chromium.org//1604903006 .
diff --git a/pkgs/stream_channel/lib/stream_channel.dart b/pkgs/stream_channel/lib/stream_channel.dart
index a8c9a09..fd7b093 100644
--- a/pkgs/stream_channel/lib/stream_channel.dart
+++ b/pkgs/stream_channel/lib/stream_channel.dart
@@ -9,18 +9,55 @@
 
 /// An abstract class representing a two-way communication channel.
 ///
-/// Subclasses are strongly encouraged to mix in or extend [StreamChannelMixin]
-/// to get default implementations of the various instance methods. Adding new
-/// methods to this interface will not be considered a breaking change if
-/// implementations are also added to [StreamChannelMixin].
+/// Users should consider the [stream] emitting a "done" event to be the
+/// canonical indicator that the channel has closed. If they wish to close the
+/// channel, they should close the [sink]—canceling the stream subscription is
+/// not sufficient. Protocol errors may be emitted through the stream or through
+/// [Sink.done], depending on their underlying cause. Note that the sink may
+/// silently drop events if the channel closes before [Sink.close] is called.
+///
+/// Implementations are strongly encouraged to mix in or extend
+/// [StreamChannelMixin] to get default implementations of the various instance
+/// methods. Adding new methods to this interface will not be considered a
+/// breaking change if implementations are also added to [StreamChannelMixin].
+///
+/// Implementations must provide the following guarantees:
+///
+/// * The stream is single-subscription, and must follow all the guarantees of
+///   single-subscription streams.
+///
+/// * Closing the sink causes the stream to close before it emits any more
+///   events.
+///
+/// * After the stream closes, the sink is automatically closed. If this
+///   happens, sink methods should silently drop their arguments until
+///   [Sink.close] is called.
+///
+/// * If the stream closes before it has a listener, the sink should silently
+///   drop events if possible.
+///
+/// * Canceling the stream's subscription has no effect on the sink. The channel
+///   must still be able to respond to the other endpoint closing the channel
+///   even after the subscription has been canceled.
+///
+/// * The sink *either* forwards errors to the other endpoint *or* closes as
+///   soon as an error is added and forwards that error to the [Sink.done]
+///   future.
+///
+/// These guarantees allow users to interact uniformly with all implementations,
+/// and ensure that either endpoint closing the stream produces consistent
+/// behavior.
 abstract class StreamChannel<T> {
-  /// The stream that emits values from the other endpoint.
+  /// The single-subscription stream that emits values from the other endpoint.
   Stream<T> get stream;
 
   /// The sink for sending values to the other endpoint.
   StreamSink<T> get sink;
 
   /// Creates a new [StreamChannel] that communicates over [stream] and [sink].
+  ///
+  /// Note that this stream/sink pair must provide the guarantees listed in the
+  /// [StreamChannel] documentation.
   factory StreamChannel(Stream<T> stream, StreamSink<T> sink) =>
       new _StreamChannel<T>(stream, sink);