purpose of run-parts(8) utility

You can use find instead of run-parts, there is no way to show which one is better. But I think using run-parts is shorter (less typing) and make your script more maintainable. An example is /etc/crontab:

# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user  command
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )

For second question, you can find the answer in debianutils source code. In file run-parts.c, line 198:

/* Execute a file */                                                            
void run_part(char *progname)                                                   
{ 
     ....
     args[0] = progname;                                                         
     execv(progname, args);                                                      
     error("failed to exec %s: %s", progname, strerror(errno));                  
     exit(1);
     ....
}

You can see run-parts using execv system call. So if your file is not an binary execuable or an Interpreter script, execv can not run the file.

Note

  • What is Interpreter script:

From man execve, section Interpreter scripts:

Interpreter scripts
       An  interpreter  script  is  a  text  file  that has execute permission
       enabled and whose first line is of the form:

           #! interpreter [optional-arg]

       The interpreter must be a valid pathname for an executable which is not
       itself  a  script.   If  the filename argument of execve() specifies an
       interpreter script, then interpreter will be invoked with the following
       arguments:

           interpreter [optional-arg] filename arg...

       where arg...  is the series of words pointed to by the argv argument of
       execve().

       For portable use, optional-arg should either be absent, or be specified
       as  a  single word (i.e., it should not contain white space); see NOTES
       below.
  • You can see debianutils source code here.

The files that run-parts runs are fairly well documented. In addition to them being executable, the following man page snippet explains the requirements:

If  neither  the --lsbsysinit option nor the --regex option is given then the
names must consist entirely of ASCII upper- and lower-case letters, ASCII digits,
ASCII underscores, and ASCII minus-hyphens.

If the --lsbsysinit option is given, then the names must not end in .dpkg-old  or
.dpkg-dist or .dpkg-new or .dpkg-tmp, and must belong to one or more  of  the 
following  namespaces:  the  LANANA-assigned  namespace  (^[a-z0-9]+$); the LSB
hierarchical and reserved namespaces (^_?([a-z0-9_.]+-)+[a-z0-9]+$); and the
Debian cron script namespace (^[a-zA-Z0-9_-]+$)

Using the --lsbsysinit option is particularly useful for running scripts in /etc since many of the scripts will be listed as conffiles in their respective packages. A common case where files with the dpkg-* extension are created is when changes have been made to the installed version and dpkg tries to install a new version. dpkg will usually store the version the user didn't choose in the same directory. Using run-parts is a good, standard way to ensure that none of these extensions or any others which are not meant to be run aren't. It reduces the chances of bugs appearing because a developer forgot to include one of these in their script.

Even without the --lsbsysinit, it is still a useful command to reduce the amount of code that needs to be written and improve reliability when used throughout the system. Though not quite so much as it is easier to replace with a find ... -executable -exec {} ; or the like.