ECA lets you write a nested token path with dots instead of colons, because TokenDecoratorTrait::normalizeKey() translates . to :. Drupal core never sees such a token: Token::scan() only matches [type:rest], so ECA scans for colon-free tokens itself and resolves them as root-level tokens.
Resolution always worked. Rendering did not. The root-level path only produced a string for scalars, for objects with __toString() and for entities. Every path that resolved to a typed data object - which is most of them - rendered as an empty string, and no replacement was recorded at all.
Before
[foo.bar] => '' [foo:bar] => 'baz'
[pdf.0.fids.0] => '' [pdf:0:fids:0] => '123'
[account.name] => '' [account:name] => 'admin'
[account.name.value] => 'admin'
After
All four render the same as their colon spelling.
Why the old behavior looked arbitrary
[account.name.value] rendered but [account.name] did not, because FieldItemList is a ListInterface and not a ComplexDataInterface, so resolution fell into magic property access and landed on a raw PHP string.
What you need to check
Only models that print a dot-separated token. One that silently produced an empty string now produces a value: conditions comparing such a token against an empty value flip from TRUE to FALSE; templates that tolerated the empty replacement change output. Token: set value is explicitly called out as unaffected, because it already worked - the value was re-wrapped into a DTO, so only direct printing failed.