Reviewed and cleanup usage of "fail" word in comments and method names
diff --git a/common/kotlinx-coroutines-core-common/src/Exceptions.common.kt b/common/kotlinx-coroutines-core-common/src/Exceptions.common.kt
index 7658fb2..7762a36 100644
--- a/common/kotlinx-coroutines-core-common/src/Exceptions.common.kt
+++ b/common/kotlinx-coroutines-core-common/src/Exceptions.common.kt
@@ -13,7 +13,9 @@
  * @suppress **Deprecated**: Replace with [CancellationException].
  */
 @InternalCoroutinesApi
-@Deprecated(message = "Replace with CancellationException", replaceWith = ReplaceWith("CancellationException"))
+@Deprecated( // todo: remove deprecated, make it internal
+    message = "Replace with CancellationException",
+    replaceWith = ReplaceWith("CancellationException"))
 public expect class JobCancellationException(
     message: String,
     cause: Throwable?,
diff --git a/common/kotlinx-coroutines-core-common/src/Job.kt b/common/kotlinx-coroutines-core-common/src/Job.kt
index 3713c07..36a9c8a 100644
--- a/common/kotlinx-coroutines-core-common/src/Job.kt
+++ b/common/kotlinx-coroutines-core-common/src/Job.kt
@@ -15,8 +15,12 @@
 
 /**
  * A background job. Conceptually, a job is a cancellable thing with a life-cycle that
- * culminates in its completion. Jobs can be arranged into parent-child hierarchies where cancellation
- * of parent lead to an immediate cancellation of all its [children] and vice versa.
+ * culminates in its completion.
+ *
+ * Jobs can be arranged into parent-child hierarchies where cancellation
+ * of parent lead to an immediate cancellation of all its [children]. Failure or cancellation of a child
+ * with an exception other than [CancellationException] immediately cancels its parent. This way, parent
+ * can [cancel] its own children (including all their children recursively) without cancelling itself.
  *
  * The most basic instances of [Job] are created with [launch][CoroutineScope.launch] coroutine builder or with a
  * `Job()` factory function.
@@ -38,7 +42,7 @@
  * that provide an optional `start` parameter create a coroutine in _new_ state when this parameter is set to
  * [CoroutineStart.LAZY]. Such a job can be made _active_ by invoking [start] or [join].
  *
- * A job is _active_ while the coroutine is working. Failure of the job makes it _cancelling_.
+ * A job is _active_ while the coroutine is working. Failure of the job with exception makes it _cancelling_.
  * A job can be cancelled it at any time with [cancel] function that forces it to transition to
  * _cancelling_ state immediately. The job becomes _cancelled_  when it finishes executing it work.
  *
@@ -47,7 +51,7 @@
  * +-----+ start  +--------+ complete   +-------------+  finish  +-----------+
  * | New | -----> | Active | ---------> | Completing  | -------> | Completed |
  * +-----+        +--------+            +-------------+          +-----------+
- *                  |        cancel        |
+ *                  |  cancel / fail       |
  *                  |     +----------------+
  *                  |     |
  *                  V     V
@@ -65,6 +69,12 @@
  * Note, that _completing_ state is purely internal to the job. For an outside observer a _completing_ job is still
  * active, while internally it is waiting for its children.
  *
+ * Normal cancellation of a job is distinguished from its failure by the type of its cancellation exception cause.
+ * If the cause of cancellation is [CancellationException], then the job is considered to be _cancelled normally_.
+ * This usually happens when [cancel] is invoked without additional parameters. If the cause of cancellation is
+ * a different exception, then the job is considered to have _failed_. This usually happens when the code of the job
+ * encounters some problem and throws an exception.
+ *
  * All functions on this interface and on all interfaces derived from it are **thread-safe** and can
  * be safely invoked from concurrent coroutines without external synchronization.
  */
@@ -94,25 +104,31 @@
     // ------------ state query ------------
 
     /**
-     * Returns `true` when this job is active -- it was already started and has not completed or failed yet.
+     * Returns `true` when this job is active -- it was already started and has not completed nor was cancelled yet.
      * The job that is waiting for its [children] to complete is still considered to be active if it
-     * has not failed and was not cancelled.
+     * was not cancelled nor failed.
+     *
+     * See [Job] documentation for more details on job states.
      */
     public val isActive: Boolean
 
     /**
-     * Returns `true` when this job has completed for any reason. A job that has failed or cancelled
+     * Returns `true` when this job has completed for any reason. A job that was cancelled or failed
      * and has finished its execution is also considered complete. Job becomes complete only after
      * all its [children] complete.
+     *
+     * See [Job] documentation for more details on job states.
      */
     public val isCompleted: Boolean
 
     /**
      * Returns `true` if this job was cancelled for any reason, either by explicit invocation of [cancel] or
-     * because it had failed or its children or parent was cancelled.
+     * because it had failed or its child or parent was cancelled.
      * In the general case, it does not imply that the
      * job has already [completed][isCompleted], because it may still be finishing whatever it was doing and
      * waiting for its [children] to complete.
+     *
+     * See [Job] documentation for more details on cancellation and failures.
      */
     public val isCancelled: Boolean
 
@@ -203,7 +219,7 @@
      *
      * A parent-child relation has the following effect:
      * * Cancellation of parent with [cancel] or its exceptional completion (failure)
-     *   immediately fails all its children.
+     *   immediately cancels all its children.
      * * Parent cannot complete until all its children are complete. Parent waits for all its children to
      *   complete in _completing_ or _cancelling_ states.
      *
@@ -300,10 +316,10 @@
     public fun invokeOnCompletion(handler: CompletionHandler): DisposableHandle
 
     /**
-     * Registers handler that is **synchronously** invoked once on failure or completion of this job.
-     * When job is already failing or complete, then the handler is immediately invoked
+     * Registers handler that is **synchronously** invoked once on cancellation or completion of this job.
+     * When job was already cancelled and is completed its execution, then the handler is immediately invoked
      * with a job's cancellation cause or `null` unless [invokeImmediately] is set to false.
-     * Otherwise, handler will be invoked once when this job is failing or is complete.
+     * Otherwise, handler will be invoked once when this job is cancelled or is complete.
      *
      * The meaning of `cause` that is passed to the handler:
      * * Cause is `null` when job has completed normally.
@@ -311,9 +327,9 @@
      *   **It should not be treated as an error**. In particular, it should not be reported to error logs.
      * * Otherwise, the job had _failed_.
      *
-     * Invocation of this handler on a transition to a _failing_ state
+     * Invocation of this handler on a transition to a _cancelling_ state
      * is controlled by [onCancelling] boolean parameter.
-     * The handler is invoked when the job is failing when [onCancelling] parameter is set to `true`.
+     * The handler is invoked when the job becomes _cancelling_ if [onCancelling] parameter is set to `true`.
      *
      * The resulting [DisposableHandle] can be used to [dispose][DisposableHandle.dispose] the
      * registration of this handler and release its memory if its invocation is no longer needed.
@@ -328,7 +344,7 @@
      * This function should not be used in general application code.
      * Implementations of `CompletionHandler` must be fast and _lock-free_.
      *
-     * @param onCancelling when `true`, then the [handler] is invoked as soon as this job transitions to _failing_ state;
+     * @param onCancelling when `true`, then the [handler] is invoked as soon as this job transitions to _cancelling_ state;
      *        when `false` then the [handler] is invoked only when it transitions to _completed_ state.
      * @param invokeImmediately when `true` and this job is already in the desired state (depending on [onCancelling]),
      *        then the [handler] is immediately and synchronously invoked and no-op [DisposableHandle] is returned;
@@ -391,15 +407,15 @@
 // -------------------- Parent-child communication --------------------
 
 /**
- * A reference that parent receives from its child so that it can report its failure.
+ * A reference that parent receives from its child so that it can report its cancellation.
  *
  * @suppress **This is unstable API and it is subject to change.**
  */
 internal interface ChildJob : Job {
     /**
-     * Parent is reporting failure to the child by invoking this method.
-     * Child finds the failure cause using [getCancellationException] of the [parentJob].
-     * This method does nothing is the child is already failing.
+     * Parent is cancelling its child by invoking this method.
+     * Child finds the cancellation cause using [getCancellationException] of the [parentJob].
+     * This method does nothing is the child is already being cancelled.
      *
      * @suppress **This is unstable API and it is subject to change.**
      */
@@ -407,16 +423,16 @@
 }
 
 /**
- * A handle that child keep onto its parent so that it is able to report its failure.
+ * A handle that child keep onto its parent so that it is able to report its cancellation.
  *
  * @suppress **This is unstable API and it is subject to change.**
  */
 internal interface ChildHandle : DisposableHandle {
     /**
-     * Child is reporting failure to the parent by invoking this method.
+     * Child is cancelling its parent by invoking this method.
      * This method is invoked by the child twice. The first time child report its root cause as soon as possible,
-     * so that all its siblings and the parent can start finishing their work asap on failure. The second time
-     * child invokes this method when it had aggregated and determined its final termination cause.
+     * so that all its siblings and the parent can start cancelling their work asap. The second time
+     * child invokes this method when it had aggregated and determined its final cancellation cause.
      *
      * @suppress **This is unstable API and it is subject to change.**
      */
diff --git a/common/kotlinx-coroutines-core-common/src/JobSupport.kt b/common/kotlinx-coroutines-core-common/src/JobSupport.kt
index 604e0b6..a8551b7 100644
--- a/common/kotlinx-coroutines-core-common/src/JobSupport.kt
+++ b/common/kotlinx-coroutines-core-common/src/JobSupport.kt
@@ -204,14 +204,13 @@
         }
         // Create the final state object
         val finalState = when {
-            // if we have not failed -> use proposed update value
+            // was not cancelled (no exception) -> use proposed update value
             finalException == null -> proposedUpdate
-            // small optimization when we can used proposeUpdate object as is on failure
+            // small optimization when we can used proposeUpdate object as is on cancellation
             finalException === proposedException -> proposedUpdate
             // cancelled job final state
             else -> CompletedExceptionally(finalException)
         }
-
         // Now handle exception if parent can't handle it
         if (finalException != null && !cancelParent(finalException)) {
             handleJobException(finalException)
@@ -238,9 +237,9 @@
          * But it has negative consequences: same exception can be added as suppressed more than once.
          * Consider concurrent parent-child relationship:
          * 1) Child throws E1 and parent throws E2.
-         * 2) Parent goes to "Failing(E1)" and cancels child with E1
+         * 2) Parent goes to "Cancelling(E1)" and cancels child with E1
          * 3) Child goes to "Cancelling(E1)", but throws an exception E2
-         * 4) When child throws, it notifies parent that it is failing, adding its exception to parent's list of exceptions/
+         * 4) When child throws, it notifies parent that it is cancelled, adding its exception to parent's list of exceptions
          * 5) Child builds final exception: E1 with suppressed E2, reports it to parent.
          * 6) Parent aggregates three exceptions: original E1, reported E2 and "final" E1.
          *    It filters the third exception, but adds the second one to the first one, thus adding suppressed duplicate.
@@ -336,8 +335,8 @@
         // first cancel our own children
         onCancellation(cause)
         notifyHandlers<JobCancellingNode<*>>(list, cause)
-        // then report to the parent that we are failing
-        cancelParent(cause) // tentative failure report -- does not matter if there is no parent
+        // then cancel parent
+        cancelParent(cause) // tentative cancellation -- does not matter if there is no parent
     }
 
     private fun NodeList.notifyCompletion(cause: Throwable?) =
@@ -396,10 +395,10 @@
     public final override fun getCancellationException(): CancellationException {
         val state = this.state
         return when (state) {
-            is Finishing -> state.rootCause?.toCancellationException("Job is failing")
+            is Finishing -> state.rootCause?.toCancellationException("Job is cancelling")
                 ?: error("Job is still new or active: $this")
             is Incomplete -> error("Job is still new or active: $this")
-            is CompletedExceptionally -> state.cause.toCancellationException("Job has failed")
+            is CompletedExceptionally -> state.cause.toCancellationException("Job was cancelled")
             else -> JobCancellationException("Job has completed normally", null, this)
         }
     }
@@ -411,7 +410,7 @@
      * Returns the cause that signals the completion of this job -- it returns the original
      * [cancel] cause, [CancellationException] or **`null` if this job had completed normally**.
      * This function throws [IllegalStateException] when invoked for an job that has not [completed][isCompleted] nor
-     * failing yet.
+     * is being cancelled yet.
      *
      * @suppress **This is unstable API and it is subject to change.**
      */
@@ -463,15 +462,15 @@
                         var handle: DisposableHandle = NonDisposableHandle
                         if (onCancelling && state is Finishing) {
                             synchronized(state) {
-                                // check if we are installing failing handler on job that is failing
-                                rootCause = state.rootCause // != null if we are failing
-                                // We add node to the list in two cases --- either the job is not failing
+                                // check if we are installing cancellation handler on job that is being cancelled
+                                rootCause = state.rootCause // != null if cancelling job
+                                // We add node to the list in two cases --- either the job is not being cancelled
                                 // or we are adding a child to a coroutine that is not completing yet
-                                if (rootCause == null || handler.isHandlerOf<ChildHandleImpl>() && !state.isCompleting) {
+                                if (rootCause == null || handler.isHandlerOf<ChildHandleNode>() && !state.isCompleting) {
                                     // Note: add node the list while holding lock on state (make sure it cannot change)
                                     val node = nodeCache ?: makeNode(handler, onCancelling).also { nodeCache = it }
                                     if (!addLastAtomic(state, list, node)) return@loopOnState // retry
-                                    // just return node if we don't have to invoke handler (not failing yet)
+                                    // just return node if we don't have to invoke handler (not cancelling yet)
                                     if (rootCause == null) return node
                                     // otherwise handler is invoked immediately out of the synchronized section & handle returned
                                     handle = node
@@ -479,7 +478,7 @@
                             }
                         }
                         if (rootCause != null) {
-                            // Note: attachChild uses invokeImmediately, so it gets invoked when adding to failing job
+                            // Note: attachChild uses invokeImmediately, so it gets invoked when adding to cancelled job
                             if (invokeImmediately) handler.invokeIt(rootCause)
                             return handle
                         } else {
@@ -608,7 +607,7 @@
     public override fun cancel(cause: Throwable?): Boolean =
         cancelImpl(cause) && handlesException
 
-    // parent is reporting failure to a child child
+    // parent is cancelling child
     public final override fun parentCancelled(parentJob: Job) {
         cancelImpl(parentJob)
     }
@@ -624,7 +623,7 @@
             // make sure it is completing, if cancelMakeCompleting returns true it means it had make it
             // completing and had recorded exception
             if (cancelMakeCompleting(cause)) return true
-            // otherwise just record failure via makeCancelling below
+            // otherwise just record exception via makeCancelling below
         }
         return makeCancelling(cause)
     }
@@ -653,7 +652,7 @@
         else -> (cause as Job).getCancellationException()
     }
 
-    // transitions to Failing state
+    // transitions to Cancelling state
     // cause is Throwable or Job when cancelChild was invoked, cause can be null only on cancel
     private fun makeCancelling(cause: Any?): Boolean {
         var causeExceptionCache: Throwable? = null // lazily init result of createCauseException(cause)
@@ -663,7 +662,7 @@
                     val notifyRootCause = synchronized(state) {
                         if (state.isSealed) return false // too late, already sealed -- cannot add exception nor mark cancelled
                         // add exception, do nothing is parent is cancelling child that is already being cancelled
-                        val wasCancelling = state.isCancelling // will notify if was not failing
+                        val wasCancelling = state.isCancelling // will notify if was not cancelling
                         // Materialize missing exception if it is the first exception (otherwise -- don't)
                         if (cause != null || !wasCancelling) {
                             val causeException = causeExceptionCache ?: createCauseException(cause).also { causeExceptionCache = it }
@@ -676,11 +675,11 @@
                     return true
                 }
                 is Incomplete -> {
-                    // Not yet finishing -- try to make it failing
+                    // Not yet finishing -- try to make it cancelling
                     val causeException = causeExceptionCache ?: createCauseException(cause).also { causeExceptionCache = it }
                     if (state.isActive) {
-                        // active state becomes failing
-                        if (tryMakeFailing(state, causeException)) return true
+                        // active state becomes cancelling
+                        if (tryMakeCancelling(state, causeException)) return true
                     } else {
                         // non active state starts completing
                         when (tryMakeCompleting(state, CompletedExceptionally(causeException), mode = MODE_ATOMIC_DEFAULT)) {
@@ -697,10 +696,10 @@
     }
 
     // Performs promotion of incomplete coroutine state to NodeList for the purpose of
-    // converting coroutine state to Failing, returns null when need to retry
-    private fun getOrPromoteFailingList(state: Incomplete): NodeList? = state.list ?:
+    // converting coroutine state to Cancelling, returns null when need to retry
+    private fun getOrPromoteCancellingList(state: Incomplete): NodeList? = state.list ?:
         when (state) {
-            is Empty -> NodeList() // we can allocate new empty list that'll get integrated into Failing state
+            is Empty -> NodeList() // we can allocate new empty list that'll get integrated into Cancelling state
             is JobNode<*> -> {
                 // SINGLE/SINGLE+ must be promoted to NodeList first, because otherwise we cannot
                 // correctly capture a reference to it
@@ -710,15 +709,15 @@
             else -> error("State should have list: $state")
         }
 
-    // try make new failing state on the condition that we're still in the expected state
-    private fun tryMakeFailing(state: Incomplete, rootCause: Throwable): Boolean {
+    // try make new Cancelling state on the condition that we're still in the expected state
+    private fun tryMakeCancelling(state: Incomplete, rootCause: Throwable): Boolean {
         check(state !is Finishing) // only for non-finishing states
         check(state.isActive) // only for active states
         // get state's list or else promote to list to correctly operate on child lists
-        val list = getOrPromoteFailingList(state) ?: return false
-        // Create failing state (with rootCause!)
-        val failing = Finishing(list, false, rootCause)
-        if (!_state.compareAndSet(state, failing)) return false
+        val list = getOrPromoteCancellingList(state) ?: return false
+        // Create cancelling state (with rootCause!)
+        val cancelling = Finishing(list, false, rootCause)
+        if (!_state.compareAndSet(state, cancelling)) return false
         // Notify listeners
         notifyCancelling(list, rootCause)
         return true
@@ -765,17 +764,17 @@
         if (state !is Incomplete)
             return COMPLETING_ALREADY_COMPLETING
         /*
-         * FAST PATH -- no children to wait for && simple state (no list) && not failing => can complete immediately
-         * Failures always have to go through Finishing state to serialize exception handling.
+         * FAST PATH -- no children to wait for && simple state (no list) && not cancelling => can complete immediately
+         * Cancellation (failures) always have to go through Finishing state to serialize exception handling.
          * Otherwise, there can be a race between (completed state -> handled exception and newly attached child/join)
          * which may miss unhandled exception.
          */
-        if ((state is Empty || state is JobNode<*>) && state !is ChildHandleImpl && proposedUpdate !is CompletedExceptionally) {
+        if ((state is Empty || state is JobNode<*>) && state !is ChildHandleNode && proposedUpdate !is CompletedExceptionally) {
             if (!tryFinalizeSimpleState(state, proposedUpdate, mode)) return COMPLETING_RETRY
             return COMPLETING_COMPLETED
         }
         // get state's list or else promote to list to correctly operate on child lists
-        val list = getOrPromoteFailingList(state) ?: return COMPLETING_RETRY
+        val list = getOrPromoteCancellingList(state) ?: return COMPLETING_RETRY
         // promote to Finishing state if we are not in it yet
         // This promotion has to be atomic w.r.t to state change, so that a coroutine that is not active yet
         // atomically transition to finishing & completing state
@@ -798,10 +797,10 @@
             // add new proposed exception to the finishing state
             val wasCancelling = finishing.isCancelling
             (proposedUpdate as? CompletedExceptionally)?.let { finishing.addExceptionLocked(it.cause) }
-            // If it just becomes failing --> must process failing notifications
+            // If it just becomes cancelling --> must process cancelling notifications
             notifyRootCause = finishing.rootCause.takeIf { !wasCancelling }
         }
-        // process failing notification here -- it cancels all the children _before_ we start to to wait them (sic!!!)
+        // process cancelling notification here -- it cancels all the children _before_ we start to to wait them (sic!!!)
         notifyRootCause?.let { notifyCancelling(list, it) }
         // now wait for children
         val child = firstChild(state)
@@ -818,11 +817,11 @@
         get() = (this as? CompletedExceptionally)?.cause
 
     private fun firstChild(state: Incomplete) =
-        state as? ChildHandleImpl ?: state.list?.nextChild()
+        state as? ChildHandleNode ?: state.list?.nextChild()
 
     // return false when there is no more incomplete children to wait
     // ## IMPORTANT INVARIANT: Only one thread can be concurrently invoking this method.
-    private tailrec fun tryWaitForChild(state: Finishing, child: ChildHandleImpl, proposedUpdate: Any?): Boolean {
+    private tailrec fun tryWaitForChild(state: Finishing, child: ChildHandleNode, proposedUpdate: Any?): Boolean {
         val handle = child.childJob.invokeOnCompletion(
             invokeImmediately = false,
             handler = ChildCompletion(this, state, child, proposedUpdate).asHandler
@@ -833,7 +832,7 @@
     }
 
     // ## IMPORTANT INVARIANT: Only one thread can be concurrently invoking this method.
-    private fun continueCompleting(state: Finishing, lastChild: ChildHandleImpl, proposedUpdate: Any?) {
+    private fun continueCompleting(state: Finishing, lastChild: ChildHandleNode, proposedUpdate: Any?) {
         require(this.state === state) // consistency check -- it cannot change while we are waiting for children
         // figure out if we need to wait for next child
         val waitChild = lastChild.nextChild()
@@ -843,13 +842,13 @@
         if (tryFinalizeFinishingState(state, proposedUpdate, MODE_ATOMIC_DEFAULT)) return
     }
 
-    private fun LockFreeLinkedListNode.nextChild(): ChildHandleImpl? {
+    private fun LockFreeLinkedListNode.nextChild(): ChildHandleNode? {
         var cur = this
         while (cur.isRemoved) cur = cur.prevNode // rollback to prev non-removed (or list head)
         while (true) {
             cur = cur.nextNode
             if (cur.isRemoved) continue
-            if (cur is ChildHandleImpl) return cur
+            if (cur is ChildHandleNode) return cur
             if (cur is NodeList) return null // checked all -- no more children
         }
     }
@@ -857,9 +856,9 @@
     public final override val children: Sequence<Job> get() = buildSequence {
         val state = this@JobSupport.state
         when (state) {
-            is ChildHandleImpl -> yield(state.childJob)
+            is ChildHandleNode -> yield(state.childJob)
             is Incomplete -> state.list?.let { list ->
-                list.forEach<ChildHandleImpl> { yield(it.childJob) }
+                list.forEach<ChildHandleNode> { yield(it.childJob) }
             }
         }
     }
@@ -867,15 +866,15 @@
     @Suppress("OverridingDeprecatedMember")
     public final override fun attachChild(child: ChildJob): ChildHandle {
         /*
-         * Note: This function attaches a special ChildNode object. This node object
+         * Note: This function attaches a special ChildHandleNode node object. This node object
          * is handled in a special way on completion on the coroutine (we wait for all of them) and
          * is handled specially by invokeOnCompletion itself -- it adds this node to the list even
-         * if the job is already failing.  For "failing" state child is attached under state lock.
+         * if the job is already cancelling. For cancelling state child is attached under state lock.
          * It's required to properly wait all children before completion and provide linearizable hierarchy view:
-         * If child is attached when job is failing, such child will receive immediate notification on failure,
-         * but parent *will* wait for that child before completion and will handle its exception.
+         * If child is attached when job is already being cancelled, such child will receive immediate notification on
+         * cancellation, but parent *will* wait for that child before completion and will handle its exception.
          */
-        return invokeOnCompletion(onCancelling = true, handler = ChildHandleImpl(this, child).asHandler) as ChildHandle
+        return invokeOnCompletion(onCancelling = true, handler = ChildHandleNode(this, child).asHandler) as ChildHandle
     }
 
     @Suppress("OverridingDeprecatedMember")
@@ -893,7 +892,7 @@
     }
 
     /**
-     * This function is invoked once when job is failing or is completed.
+     * This function is invoked once when job is being cancelled, fails, or is completed.
      * It's an optimization for [invokeOnCompletion] with `onCancellation` set to `true`.
      *
      * @suppress **This is unstable API and it is subject to change.*
@@ -901,7 +900,10 @@
     protected open fun onCancellation(cause: Throwable?) {}
 
     /**
-     * When this function returns `true` the parent fails on the failure of this job.
+     * When this function returns `true` the parent is cancelled on cancellation of this job.
+     * Note, that [CancellationException] is considered "normal" and parent is not cancelled when child produces it.
+     * This allows parent to cancel its children (normally) without being cancelled itself, unless
+     * child crashes and produce some other exception during its completion.
      *
      * @suppress **This is unstable API and it is subject to change.*
      */
@@ -925,6 +927,9 @@
     protected open fun handleJobException(exception: Throwable) {}
 
     private fun cancelParent(cause: Throwable): Boolean {
+        // CancellationException is considered "normal" and parent is not cancelled when child produces it.
+        // This allow parent to cancel its children (normally) without being cancelled itself, unless
+        // child crashes and produce some other exception during its completion.
         if (cause is CancellationException) return true
         if (!cancelsParent) return false
         return parentHandle?.childCancelled(cause) == true
@@ -964,7 +969,7 @@
         }
     }
 
-    // Completing, Failing, Cancelling states,
+    // Completing & Cancelling states,
     // All updates are guarded by synchronized(this), reads are volatile
     @Suppress("UNCHECKED_CAST")
     private class Finishing(
@@ -1036,7 +1041,7 @@
     private class ChildCompletion(
         private val parent: JobSupport,
         private val state: Finishing,
-        private val child: ChildHandleImpl,
+        private val child: ChildHandleNode,
         private val proposedUpdate: Any?
     ) : JobNode<Job>(child.childJob) {
         override fun invoke(cause: Throwable?) {
@@ -1262,7 +1267,7 @@
 // -------- invokeOnCancellation nodes
 
 /**
- * Marker for node that shall be invoked on in _failing_ state.
+ * Marker for node that shall be invoked on in _cancelling_ state.
  * **Note: may be invoked multiple times.**
  */
 internal abstract class JobCancellingNode<out J : Job>(job: J) : JobNode<J>(job)
@@ -1279,7 +1284,7 @@
     override fun toString() = "InvokeOnCancelling[$classSimpleName@$hexAddress]"
 }
 
-internal class ChildHandleImpl(
+internal class ChildHandleNode(
     parent: JobSupport,
     @JvmField val childJob: ChildJob
 ) : JobCancellingNode<JobSupport>(parent), ChildHandle {
@@ -1288,7 +1293,7 @@
     override fun toString(): String = "ChildHandle[$childJob]"
 }
 
-// Same as ChildHandleImpl, but for cancellable continuation
+// Same as ChildHandleNode, but for cancellable continuation
 internal class ChildContinuation(
     parent: Job,
     @JvmField val child: AbstractContinuation<*>