There's no proper call-stack with function recursion. For example if you call a function that creates and sets a score, that score will still be set when the function is exited.
When a function is called, its commands are essentially just appended to the front of the to-do list.
For this reason, you shouldn't worry about recursion depth. And, as there are ...
How I have handled similar ideas:
Set the recipe's "result" to a particular item that a player is not likely to ever have in their inventory (I usually use bat_spawn_egg).
Create an advancement that a player achieves either by crafting your custom recipe or by acquiring a bat_spawn_egg into their inventory.
Set the reward of the advancement to trigger a ...
Use loot tables. For your example, save this as data_pack_name/data/minecraft/loot_tables/blocks/grass_block.json.
A long search for the cause, a short and simple answer:
Functions that are rewards for an advancement triggered by the consume_item trigger are executed before the item does what it does. For example your function first gives its effects to you, THEN the milk bucket clears all effects and the empty bucket it put into its slot.
Ok, so after a bit of thinking time I got it. Here is the file:
According to the error messages, it seemed that you are using Essentials? If you are not, the following will not ever be correct.
Use minecraft:give instead of give, since Essentials give command does not recognize selectors.