docs: function executeProcessOneTasks(batch, message, cancellable, context) {
    const states = batch.states;
    const messageState = states.get(message);
  
    let completed = false;
    let cancelled = false;
    if (cancellable) Promises.installCancel(cancellable, () => {
      if (!completed) cancelled = true;
      return completed;
    });
  
    // First get all of the message's process one tasks
    // const tasksByName = batch.getProcessOneTasks(message);
    const tasks = taskUtils.getTasks(messageState.ones);
  
    const t = tasks.length;
    const ts = toCountString(t, 'process one task');
  
    // Collect all of the message's process one tasks that are NOT yet fully finalised
    const incompleteTasks = tasks.filter(task => !task.isFullyFinalised());
  
    const i = incompleteTasks.length;
  
    if (i <= 0) {
      const is = toCountString(i, 'incomplete task');
      if (context.debugEnabled) context.debug(`Skipping execution of ${ts} on message (${messageState.id}), since ${is}`);
    } else {
      if (context.traceEnabled) context.trace(`About to execute ${i} incomplete of ${ts} on message (${messageState.id})`);
    }
  
    // Start executing each of the incomplete tasks on the message and collect their done promises
    const promises = incompleteTasks.map(task => {
      const p = task.execute(message, batch, context);
      return whenDone(task, p, cancellable, context);
    });
  
    return Promises.every(promises, cancellable, context).then(
      outcomes => {
        // Check if there is a next message that was waiting for the current message to finish processing
        const nextMessage = messageState.nextMessage;
  
        // Start processing the next message (if any), but ONLY if we have completely finalised the current message's process one tasks
        if (nextMessage) {
          const nextMessageState = states.get(nextMessage);
          if (!cancelled) {
            // Check if we have now completely finalised the processing of all of the current message's incomplete process one tasks
            const allTasksFullyFinalised = incompleteTasks.every(task => task.isFullyFinalised());
            if (allTasksFullyFinalised) {
              // Start executing all of the process one tasks on the next message
              context.debug(`About to process NEXT message (${getMessageStateKeySeqNoId(nextMessageState)}) after (${getMessageStateKeySeqNoId(messageState)}) finalised`);
              return executeProcessOneTasks(batch, nextMessage, cancellable, context)
                .then(nextOutcomes => {
                  completed = true;
                  return outcomes.concat(nextOutcomes);
                });
            } else {
              completed = true;
              const stillIncompleteTasks = incompleteTasks.filter(task => !task.isFullyFinalised());
              context.debug(`Cannot process next message (${getMessageStateKeySeqNoId(nextMessageState)}) yet, since (${getMessageStateKeySeqNoId(messageState)}) is still not finalised (incomplete tasks: ${stillIncompleteTasks.map(t => `${t.name} - ${t.state.name}`).join('; ')})`);
              return outcomes;
            }
          } else {
            context.debug(`Skipped processing of next message (${getMessageStateKeySeqNoId(nextMessageState)}), since batch processing has been cancelled`);
            return outcomes;
          }
        } else {
          completed = true;
          return outcomes;
        }
      },
      err => {
        context.error(`Failed to process message (${messageState.id}, ${messageState.key})`, err);
        throw err;
      }
    );
  }