Reproduction steps:
- Register two valid module commands:
- probe.foo_bar
- probe.foo.bar
- Both commands are accepted by manifest validation.
_module_provider_verb()normalizes both commands to the same action ID:
- probe.foo_bar → probe_foo_bar
- probe.foo.bar → probe_foo_bar
- Register the first command, then register the second.
- Inspect
ACTIONS["probe_foo_bar"].
Expected:
Two valid, distinct module commands should not resolve to the same workflow action ID. A collision should either be rejected or explicitly namespaced.
Actual:
The second registration silently overwrites the first:
before owner: module:probe-module-aafter owner: module:probe-module-b
before cmd: probe.foo_barafter cmd: probe.foo.bar
Root cause:_module_provider_verb() replaces remaining dots in the command verb with underscores. This makes distinct valid command IDs capable of producing the same canonical action ID.
_register_module_integrations() then assigns:
ACTIONS[aid] = integ
without checking whether that action ID is already owned by another command/module.
This can change which module implementation an existing workflow action resolves to without changing the workflow itself.
Station version (railcall version):
station-v0.65
Module slug + version:
Synthetic reproduction using probe-module-a and probe-module-b