There's not enough detail to analyze the likely issue, but I can point out what won't work in your situation:
Your ValidateLocalInstallation custom action is immediate, which means it runs before the system is even changed at all by anything in the MSI file. No files have been written and no services have been installed or started. So the issue is not, as you state, anything to do with running after StartServices. Installations are two phase - immediate means write the execution/rollback script, call immediate custom actions, don't do anything to the system. Deferred is when the install actually does something - it calls deferred custom actions and does the work. Yes, if you look in a verbose log you might see things in a confusing order, but that's because there are two StartServices entries, one immediate (just a script/rollback entry) and one that really starts installed services, so my guess is that you are misinterpreting the log.
It's marked as impersonate=no, and that's not going to help. Immediate custom actions run with the installing user's credentials so impersonate=no is irrelevant. You're running with the installing user's credentials.
Immediate custom actions that run with the installing user's credentials are not elevated (unless you launched the entire MSI setup from an elevated context) so it's possible that failures in your code may be security related, depending on what your code does.
There's no way to tell if your custom action is actually working. It might do all kinds of things, catch errors, and then return a success result so that the installation continues anyway. Without seeing your code there's no way to tell if it's working, but if you're using return=check you need to be sure to return an error result if anything goes wrong so that the install will fail and roll back, that is the point of return=check. Clearly, it seems to me that if the files don't get created then you should fail the install.
It's not clear to me why you can't install the files to that folder - the LocalAppDataFolder property is probably the one you'd need. I suspect that you need to be installing those files and then adding content with a deferred custom action before StartServices. I'd also pass the LocalAppDataFolder property value to your custom action to be sure you know the corrrect location because if you find out that you need deferred and impersonate=no, then your CA will run with the local system account, and attempts to get the "curent user's" local app data folder will be the system account's, not the installing user's.