How does one, for an array of user items, merge the entries of consecutive user items where user name and an additional sole property name are equal?

This solution too, is implemented as a reduce task.

The iterating task works with a lookbehind approach, comparing the current user item to the previous one. If both matching criteria (same user name and same property name) are met the process tries to look up an already existing merger object which would be referred to via the collector object. In case a previous merger did not happen a new merger object gets created from the previous user item and assigned to the collector. In any case the merger would be aggregated by the currently processed user item.

function mergeConsecutiveSameSoleUserEntry(collector, userItem, idx, arr) {
  let { merger, result } = collector;
  let isProceedUnmerged = true;

  if (idx >= 1) {
    const { user: userName, ...soleEntry } = userItem;
    const { user: prevUserName, ...prevSoleEntry } = arr[idx - 1] ?? {};

    if (userName === prevUserName) {
      const [soleKey, soleValue] = Object.entries(soleEntry).at(0);
      const [prevSoleKey, prevSoleValue] = Object.entries(prevSoleEntry).at(0);

      if (soleKey === prevSoleKey) {
        if (!merger) {

          merger = collector.merger = {
            user: userName,
            [soleKey]: [prevSoleValue],
          };
          result[result.length - 1] = merger;
        }
        merger[soleKey].push(soleValue);
        
        isProceedUnmerged = false;
      }
    }
  }
  if (isProceedUnmerged) {
    Reflect.deleteProperty(collector, 'merger');

    result.push(userItem);
  }
  return collector;
}

console.log([

  { user: 'user1', comment: 'This is a comment' },
  { user: 'user1', role: 'member' },
  { user: 'user1', role: 'writer' },
  { user: 'user1', role: 'observer' },
  { user: 'user2', comment: 'This is a comment' },
  { user: 'user2', role: 'writer' },
  { user: 'user2', role: 'admin' },
  { user: 'user1', role: 'admin' },
  { user: 'user1', role: 'observer' },
  { user: 'user3', comment: 'This is another comment' },
  { user: 'user3', comment: 'And this is yet another comment' },
  { user: 'user2', comment: 'Yet another comment' },

].reduce(mergeConsecutiveSameSoleUserEntry, { result: [] }).result);
.as-console-wrapper { min-height: 100%!important; top: 0; }