docs: private void updateMember(GossipMember remoteMember, boolean direct) {
      GossipMember localMember = members.get(remoteMember.id());
      if (localMember == null) {
        remoteMember.setActive(true);
        remoteMember.setReachable(true);
        members.put(remoteMember.id(), remoteMember);
        post(new GroupMembershipEvent(GroupMembershipEvent.Type.MEMBER_ADDED, remoteMember));
      } else if (!Objects.equals(localMember.version(), remoteMember.version())) {
        members.remove(localMember.id());
        localMember.setReachable(false);
        post(new GroupMembershipEvent(GroupMembershipEvent.Type.REACHABILITY_CHANGED, localMember));
        localMember.setActive(false);
        post(new GroupMembershipEvent(GroupMembershipEvent.Type.MEMBER_REMOVED, localMember));
        members.put(remoteMember.id(), remoteMember);
        remoteMember.setActive(true);
        remoteMember.setReachable(true);
        post(new GroupMembershipEvent(GroupMembershipEvent.Type.MEMBER_ADDED, remoteMember));
      } else if (!Objects.equals(localMember.properties(), remoteMember.properties())) {
        if (!localMember.isReachable()) {
          localMember.setReachable(true);
          post(new GroupMembershipEvent(GroupMembershipEvent.Type.REACHABILITY_CHANGED, localMember));
        }
        localMember.properties().putAll(remoteMember.properties());
        post(new GroupMembershipEvent(GroupMembershipEvent.Type.METADATA_CHANGED, localMember));
      } else if (!localMember.isReachable() && direct) {
        localMember.setReachable(true);
        localMember.setTerm(localMember.getTerm() + 1);
        post(new GroupMembershipEvent(GroupMembershipEvent.Type.REACHABILITY_CHANGED, localMember));
      } else if (!localMember.isReachable() && remoteMember.getTerm() > localMember.getTerm()) {
        localMember.setReachable(true);
        localMember.setTerm(remoteMember.getTerm());
        post(new GroupMembershipEvent(GroupMembershipEvent.Type.REACHABILITY_CHANGED, localMember));
      }
    }