Look to your parent code:
int main()
{
    int id = fork();
    
    if (id == 0) {
- you don't test for negative id(indicating some error fromfork()) but, as this error is rare, it's not a problem here)
- you have tested if idis zero (just above), so think twice, are you killing process with process id0???  Shouldn't this kill be in some other part of the code?
- execl()only returns if it indeed fails.  You should only print some error about why- execl()failed and- exit()with a return code indicating that.
        execl("program2", "program2", NULL);
        fprintf(stderr, "EXECL: %s\n", strerror(errno));
        exit(EXIT_FAILURE);
        /* kill(id, SIGUSR1); <-- this code will never execute */
    }
    return 0;
}
Exec functions are never expected to return, as the program that executes them is overwritten by the program you are attempting to execute.  So, if you call execl(2), don't put anything but error code below it.  It's not like calling a subroutine, that returns to the calling program.  It never returns (well, as said, only if the function fails).
If you want to send a signal to your child, the kill() call should be after the if sentence (where, indeed, is the parent code to execute)  You should check first for -1, as this means that fork() failed.
So a better sample code would be: (I have put, not as you did, a complete example, ready to be built and executed at your site, please read How to create a minimal, reproducible example and follow the guidelines there to post testable code. (you lack header files and many things for this code to be testable out of the box)
program1.c
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/time.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include "log.h"  /* see log.h file, below */
char *p1;
int   pid;
int main(int argc, char **argv)
{
    int res;
    p1       = argv[0];
    char *p2 = argc > 1 ? argv[1] : p1;
    pid      = getpid();
    LOG(p1, pid, "STARTING\n");
    LOG(p1, pid, "IGNORING SIGUSR1(%d)\n", SIGUSR1);
    signal(SIGUSR1, SIG_IGN);
    int  id  = fork();
    if (id < 0) { /* error */
        ERR(p1, pid, "FORK: %s\n", strerror(errno));
    }
    if (id == 0) { /* child process */
        pid  = getpid(); /* a new pid as we are children */
        if (argc <= 1) {
            ERR(p1, pid, "nothing to execute\n");
        }
        /* shift the parameters to get the next command name
         * and parameter list */
        argv++;
        argc--;
        LOG(p1, pid, "about to EXECV(");
        char *sep  = "";
        for (int i = 0; i < argc; i++) {
            LOG_TAIL("%s\"%s\"", sep, argv[i]);
            sep    = ", ";
        }
        LOG_TAIL(").\n");
        /* we use execv(2) instead of execl(2) because
         * we are using the parameters as derived from
         * our own parameters, so we change (we did
         * above) the local parameters to main to get
         * the parameter list to execv(). */
        execv(p2, argv);
        ERR(p1, pid, "EXEC: %s\n", strerror(errno));
    }
    /* id > 0 */
    LOG(p1, pid, "FORKed a new child (pid=%d)\n", id);
    {   /* randomize, as all children start at the same time
         * calling srandom() with a time based value will not
         * be a good chance, so I selected to read the seed
         * value from /dev/random */
        static const char rand_dev[] = "/dev/random";
        int fd = open(rand_dev, O_RDONLY);
        int val;
        if (fd >= 0) {
            read(fd, &val, sizeof val);
            srandom(val);
            close(fd);
        } else {
            ERR(p1, pid, "%s: %s\n", rand_dev, strerror(errno));
        }
    }
    int secs = random() % 10 + 1; /* 1..10 s. delay */
    LOG(p1, pid, "Waiting for %ds to next step\n", secs);
    sleep(secs); /* wait between 1 and 10s. */
    LOG(p1, pid, "Sending SIGUSR1(%d) to %s[pid=%d]\n",
            SIGUSR1, p2, id);
    res = kill(id, SIGUSR1);
    if (res < 0) {
        LOG(p1, pid, "KILL(%d, SIGUSR1): %s\n", id, strerror(errno));
    }
    LOG(p1, pid, "Waiting for %s[pid=%d] to finalize\n", p2, id);
    int status;
    res = wait(&status); /* wait for child to end */
    if (res < 0) {
        /* error in wait(2) */
        ERR(p1, pid, "WAIT: %s\n",
                strerror(errno));
    } else if (WIFEXITED(status)) {
        /* child called exit(2) */
        LOG(p1, pid, "WAIT: %s[pid=%d] terminated with exit code %d.\n",
                p2, id, WEXITSTATUS(status));
    } else if (WIFSIGNALED(status)) {
        /* child was aborted by a signal */
        LOG(p1, pid, "WAIT: %s[pid=%d] terminated by signal %d%s.\n",
                p2, id, WTERMSIG(status),
                WCOREDUMP(status)
                    ? ", and dumped a core file"
                    : "");
    }
    LOG(p1, pid, "finalizing\n");
    exit(EXIT_SUCCESS);
} /* main */
program2.c
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "log.h"
char *pn;
int pid;
void signal_handler1(int sig) {
    LOG(pn, pid, "RECEIVED signal %d\n", sig);
}
int main(int argc, char* argv[]) {
    pn = argv[0];
    pid = getpid();
    LOG(pn, pid, "STARTING\n");
    LOG(pn, pid, "Installing signal handler for SIGUSR1(%d)\n",
            SIGUSR1);
    signal(SIGUSR1, signal_handler1);
    LOG(pn, pid, "Program params: ");
    char *sep = "";
    for (int i = 1; i < argc; i++) {
        LOG_TAIL("%s[%s]", sep, argv[i]);
        sep = ", ";
    }
    LOG_TAIL("\n");
    if (argc > 1) { /* at least one parameter, so pause */
        LOG(pn, pid, "Waiting to receive a signal\n");
        int res = pause();
        if (res < 0) {
            LOG(pn, pid, "PAUSE: %s\n", strerror(errno));
        }
    }
    /* and print final message */
    LOG(pn, pid, "Hello world, program terminating\n");
    return 0;
}
Both programs need:
log.h
#ifndef _LOG_H
#define _LOG_H
#define F(_prog, _pid, _fmt) "%s:%s:%d:pid=\033[1;%dm%d\033[m:%s: "\
    _fmt, _prog, __FILE__, __LINE__, (_pid % 7 + 31), (_pid), __func__
#define LOG_TAIL(_fmt, ...) \
        printf(_fmt, ##__VA_ARGS__)
#define LOG(_prog, _pid, _fmt, ...)     \
        printf(F(_prog, _pid, " "_fmt), \
                ##__VA_ARGS__)
#define ERR(_prog, _pid, _fmt, ...) do {      \
        printf(F(_prog, _pid, "ERROR: "_fmt), \
                ##__VA_ARGS__);               \
        exit(EXIT_FAILURE);                   \
    } while (0)
#endif /* _LOG_H */
and  you can build with:
Makefile
targets = p1 p2
toclean = $(targets)
p1_objs = program1.o
p2_objs = program2.o
toclean += $(p1_objs) $(p2_objs)
all: $(targets)
clean:
    rm -f $(toclean)
p1: $(p1_objs)
    $(CC) $(CFLAGS) $(LDFLAGS) $($@_objs) -o $@
p2: $(p2_objs)
    $(CC) $(CFLAGS) $(LDFLAGS) $($@_objs) -o $@
program1.o program2.o: log.h
for a run as:
$ p1 p1 p2 
p1:program1.c:24:pid=11089:main:  STARTING
p1:program1.c:25:pid=11089:main:  IGNORING SIGUSR1(10)
p1:program1.c:62:pid=11089:main:  FORKed a new child (pid=11090)
p1:program1.c:83:pid=11089:main:  Waiting for 1s to next step
p1:program1.c:45:pid=11090:main:  about to EXECV("p1", "p2").
p1:program1.c:24:pid=11090:main:  STARTING
p1:program1.c:25:pid=11090:main:  IGNORING SIGUSR1(10)
p1:program1.c:62:pid=11090:main:  FORKed a new child (pid=11091)
p1:program1.c:83:pid=11090:main:  Waiting for 6s to next step
p1:program1.c:45:pid=11091:main:  about to EXECV("p2").
p2:program2.c:23:pid=11091:main:  STARTING
p2:program2.c:25:pid=11091:main:  Installing signal handler for SIGUSR1(10)
p2:program2.c:29:pid=11091:main:  Program params: 
p2:program2.c:46:pid=11091:main:  Hello world, program terminating
p1:program1.c:86:pid=11089:main:  Sending SIGUSR1(10) to p1[pid=11090]
p1:program1.c:92:pid=11089:main:  Waiting for p1[pid=11090] to finalize
p1:program1.c:86:pid=11090:main:  Sending SIGUSR1(10) to p2[pid=11091]
p1:program1.c:92:pid=11090:main:  Waiting for p2[pid=11091] to finalize
p1:program1.c:101:pid=11090:main:  WAIT: p2[pid=11091] terminated with exit code 0.
p1:program1.c:111:pid=11090:main:  finalizing
p1:program1.c:101:pid=11089:main:  WAIT: p1[pid=11090] terminated with exit code 0.
p1:program1.c:111:pid=11089:main:  finalizing
$ _