The pure Lua version of mw.ustring.gsub handles replacement strings containing invalid '%' sequences differently than the PHP version.
There are two issues:
Issue 1: If a replacement string has '%' followed by an unrecognized character, the pure Lua implementation removes the '%', but PHP keeps it as-is:
mw.ustring.gsub("test", "test", "x%yz")
PHP: x%yz
Lua: xyz
Issue 2: A '%' at the end of a replacement string causes Lua to insert a null byte:
mmw.ustring.gsub("test", "test", "bar%")
PHP: bar%
Lua: bar\000
Both implementations should handle '%' characters the same way.
https://gerrit.wikimedia.org/r/c/mediawiki/extensions/Scribunto/+/1232409 (not for submission) demonstrates the bug: if you update the expected value to match the actual value cited in the test failure, the test will fail again, this time due to a mismatch with the PHP implementation.
You can run the test by installing the Scribunto extension and running composer phpunit -- extensions/Scribunto/tests/phpunit from the MediaWiki installation root.
Here is where the Lua implementation of gsub is located: includes/Engines/LuaCommon/lualib/ustring/ustring.lua, lines 945-1055