structural typing is a good step - but afaik there's no way to distinguish between different types that have the same structure but different context - a "truth.right" will be different from a "direction.right", but it's up to the dev to keep that straight.
duck typing is what ruby does without sorbet or rbs, it portrays nothing about how the code bits interact at the boundary. if a "dog" is passed in but a "cat" is expected, things will work just fine until runtime when the cat is asked to bark. (saying as someone who is a big fan of ruby overall)