Reflective dispatch by string literal — getattr(obj, "handler") — resolves the
attribute name to a callable def and emits it under indirect_call (context
"getattr", INFERRED) at both function and module scope, so `graphify affected
handler` now covers getattr call sites.
The name is a STRING, not an identifier: it names an attribute and is never
shadowed by a param/local, so it resolves without the identifier shadow guard —
the inverse of the #1565/#1566 identifier paths. A dynamic name (a variable,
f-string, concatenation, or any expression) is not statically resolvable and emits
nothing; obj.getattr(...) (a method, not the builtin) and the 1-arg form are ignored.
Refactors the shared resolve-and-emit core out of _emit_indirect_ref into
_emit_indirect_by_name so the getattr path reuses it (callable-target-only,
cross-file deferral, dedup) without duplicating the guard; the identifier wrapper
is behavior-preserving. Full suite green.