When do you need a null terminated string in a read-only scenario?

It's actually pretty easy to know. If you are calling a function that just takes a c-string (char*/const char*), then you need a null terminated string as that is the only way to know where then end of the string is.

If you instead have a function that takes a char*/const char* plus the size, or just two pointers marking the beginning and end of the data, then you don't need a null terminated string since you have/can get the string size without iterating to a null terminator.

When do you need a null terminated string?

You need a null terminated string whenever the API that you use says that you need it. This requirement is ubiquitous in C interfaces and not explicitly stated in some documentation. If a function argument is a char* (possibly to const), and there is no length argument, you should assume the requirement unless documentation says otherwise.

Let's take the function execve (from POSIX standard) as an example:

int execve(const char *pathname, char *const argv[], char *const envp[]);

If you pass a non-null terminated argument as pathname, then the behaviour of your program will be undefined.