Possible solution

The reason we're running into problems with internal module functions being exposed to the caller is because the tests scripts are being executed from inside the module (from Invoke-Pester).  When you pass a script block into a module function as an argument, you don't have that problem; the script block is bound to the caller's session state, not the module's.  Even if you invoke it with the call operator from inside the module, it still behaves as though it exists outside the module's scope.

By using Reflection, we can simulate this, even though Invoke-Pester is still doing all the work, by setting the script block's InternalSessionState property.  Invoke-Pester now has a -UseModuleScope switch, which is only required when running Pester's own internal tests (which rely on the test code being able to see implementation details, in most cases).  You need to run a second test without the switch enabled, on a different test directory, in order to test the scope functionality:

Invoke-Pester -Path .\Functions -UseModuleScope
Invoke-Pester -Path .\ScopeTests