detect_shadowed_dcode_safe() -> ShadowedDcode | NoneBest-effort detect_shadowed_dcode that never raises.
The shadow check only ever runs to decorate an already-successful upgrade,
so a defect in detection — or an unexpected error escaping the narrow
OSError guards inside detect_shadowed_dcode — must not turn a working
upgrade into a user-facing failure. Any unexpected exception is logged and
treated as "no shadow detected", matching the fail-open bias the detector
already applies internally.