Document JobSupport state-transition & notification time-line
diff --git a/common/kotlinx-coroutines-core-common/src/JobSupport.kt b/common/kotlinx-coroutines-core-common/src/JobSupport.kt
index 6cf4b39..39ee958 100644
--- a/common/kotlinx-coroutines-core-common/src/JobSupport.kt
+++ b/common/kotlinx-coroutines-core-common/src/JobSupport.kt
@@ -80,6 +80,45 @@
        state without going to COMPLETING state)
 
        Note, that the actual `_state` variable can also be a reference to atomic operation descriptor `OpDescriptor`
+
+       ---------- TIMELINE of state changes and notification in Job lifecycle ----------
+
+       | The longest possible chain of events in shown, shorter versions cut-through intermediate states,
+       |  while still performing all the notifications in this order.
+
+       + Job object is created
+       ## NEW: state == EMPTY_ACTIVE | is InactiveNodeList
+       + initParentJob / initParentJobInternal (invokes attachChild on its parent, initializes parentHandle)
+       ~ waits for start
+       >> start / join / await invoked
+       ## ACTIVE: state == EMPTY_ACTIVE | is JobNode | is NodeList
+       + onStartInternal / onStart (lazy coroutine is started)
+       ~ active coroutine is working
+       >> childFailed / fail invoked
+       ## FAILING: state is Finishing, state.rootCause != null
+       ------ failing listeners are not admitted anymore, invokeOnCompletion(onFailing=true) returns NonDisposableHandle
+       ------ new children get immediately cancelled, but are still admitted to the list
+       + onFailing
+       + notifyFailing (invoke all failing listeners -- cancel all children, suspended functions resume with exception)
+       + failParent (rootCause of failure is communicated to the parent, parent starts failing, too)
+       ~ waits for completion of coroutine body
+       >> makeCompleting / makeCompletingOnce invoked
+       ## COMPLETING: state is Finishing, state.isCompleting == true
+       ------ new children are not admitted anymore, attachChild returns NonDisposableHandle
+       ~ waits for children
+       >> last child completes
+       - computes the final exception
+       ## SEALED: state is Finishing, state.isSealed == true
+       ------ cancel/childFailed returns false (cannot handle exceptions anymore)
+       + failParent (final exception is communicated to the parent, parent incorporates it)
+       + handleJobException ("launch" StandaloneCoroutine invokes CoroutineExceptionHandler)
+       ## COMPLETE: state !is Incomplete (CompletedExceptionally | Cancelled)
+       ------ completion listeners are not admitted anymore, invokeOnCompletion returns NonDisposableHandle
+       + parentHandle.dispose
+       + notifyCompletion (invoke all completion listeners)
+       + onCompletionInternal / onCompleted / onCompletedExceptionally
+
+       ---------------------------------------------------------------------------------
      */
 
     // Note: use shared objects while we have no listeners