Ansible 2.10 split the monolithic package into ansible-core plus separately versioned collections. Modules that used to be built in now live in collections, and the canonical way to reference one is its fully qualified name, such as ansible.builtin.copy or community.general.timezone.
Short names still work for modules in ansible.builtin and for anything resolvable through the collections search path, but the resolution is ambiguous when two installed collections provide the same short name, and the winner depends on the collections keyword and on installation order. A playbook that worked on one control node fails on another with couldn't resolve module/action.
Installing the ansible package rather than ansible-core brings a curated set of collections; ansible-core alone brings only ansible.builtin, which is why a module like community.general.ufw is missing on a minimal install and must be added with ansible-galaxy collection install. Pin collection versions in requirements.yml and install from it in CI, because collections version independently of ansible-core and a Galaxy install with no version constraint resolves to whatever is newest.