Fine. But the scenario adds an item to the cart and then completes checkout, and checkout is a different module. If I add @checkout as well, is it in two modules, or does the file's directory win regardless of what I tag it?
The directory wins, always. Module membership is derived from where the feature file sits, not from tags — a file belongs to exactly one module, and if module directories are nested the deepest match is the one that owns it. Tags never move a file between modules.
So features/cart/checkout-flow.feature is in cart, full stop. Adding @checkout does not make it a checkout scenario; it adds a tag you can filter on.
That is not useless — it is often exactly what you want for a flow that crosses a boundary. But be clear about what you are buying: -t @checkout will find it, and module coverage will still count it under cart.
Module assignment comes from the directory, not the tags
If the crossing bothers you, the usual answer is that the scenario belongs to whichever module owns the outcome it asserts. Checkout completing is a checkout outcome; the cart steps are setup, and setup is better done through the API anyway.
One thing that surprises people the first time: a tag that belongs to any module's tags list counts as declared everywhere. So @checkout on a file under features/cart/ will not warn as an unknown tag — it is a real tag, just not this module's. You only get the module/tags warning about the one that is missing.
Which means a file in the wrong directory can look almost clean. If a scenario carries @checkout and nothing else module-shaped, and lint is telling you it lacks @cart, that is worth reading as "this file may be in the wrong folder" rather than "add another tag".
And --fix-tags will resolve that warning for you by adding @cart, which is fine when the file is where it should be and unhelpful when it is not. Read the warnings before you fix them in bulk; this one is sometimes telling you something about your directory layout rather than about your tags.