The assignment rule does not run on every lead. Whether it runs depends on how the lead was created, and that is the cause behind many "my rule works in the UI but not for these leads" reports.
1. The rule was not asked to run
Leads created through the API, an import or an integration run the assignment rule only if the request asks for it. A data import wizard has a checkbox for it. An API call needs the assignment rule header. Data Loader has an assignment rule setting. If none is set, the lead goes to its default owner, which is often the integration user.
2. The integration sets an owner itself
If the integration writes an owner on the record, that value is used and the rule has nothing to decide.
3. A flow or trigger sets the owner afterwards
Code and flows that run on creation can overwrite whatever the rule chose.
4. The fields the rule tests are empty
An integration that does not populate country, state or source gives the rule nothing to match, and the lead falls to the catch-all.
Check it yourself
SELECT COUNT() FROM Lead WHERE IsConverted = false AND CreatedBy.Name = 'Integration User'
SELECT COUNT() FROM Lead WHERE IsConverted = false AND Owner.Name = 'Integration User'
Use the name of your integration user. If the second number is high, leads are being created and then never reassigned. Compare it with the leads that arrived through the form, which usually run the rule.
Have it checked every night instead.
Routing Forensics connects as a read-only user and checks this, and the rest of your routing, against your real leads. Register interest and you will be first to get a free health report: what is leaking, where, and what it is worth.
The free scan cannot see this one: it reads assignment rules, flows and queues only. Connected, it is checked every night.