I was able to reproduce the issue with UserDefaults, that means the bug is related to the widget's refresh mechanism.

I suspect it was related to widget's refresh budget, here is the documentation from Apple:
A widget’s budget applies to a 24-hour period. WidgetKit tunes the 24-hour window to the user’s daily usage pattern, which means the daily budget doesn’t necessarily reset at exactly midnight. For a widget the user frequently views, a daily budget typically includes from 40 to 70 refreshes. This rate roughly translates to widget reloads every 15 to 60 minutes, but it’s common for these intervals to vary due to the many factors involved.
Note
The system takes a few days to learn the user’s behavior. During this learning period, your widget may receive more reloads than normal.
Cases in which WidgetKit doesn’t count reloads against your widget’s budget include when:
- The widget’s containing app is in the foreground.
- The widget’s containing app has an active audio or navigation session.
The widget performs an app intent, such as when the user taps a button or toggles a switch.
- The widget performs an animation.
- The system locale changes.
- Dynamic Type or Accessibility settings change.
- For cases such as system appearance changes or system locale changes, don’t request a timeline reload from your app. The system updates your widgets automatically. In StandBy, the system refreshes your widget’s display at a system-defined rate that doesn’t count against the its budget.
- WidgetKit does not impose this limit when debugging your widget in Xcode. To verify that your widget behaves correctly, test your app and widget’s behavior outside of Xcode’s debugger.
Among which, we can see apple made an exception to this:
The widget performs an app intent, such as when the user taps a button or toggles a switch.
That means we can easily update our own widget without worrying about the budget. However, if we want to refresh other widgets using WidgetCenter.shared.reloadAllTimelines(), the widget refresh will be subject to budget.
If you observe the console log, you will see clear evidence:
Task [2318] [com.cleverlearn.Trask::com.cleverlearn.Trask.TraskWidgets:TodoListWidget:-2125748069729905058] Ignoring low-priority task with configuration: [externalRequest([source:<BSProcessHandle: 0x69c7897a0; TraskWidgets:23827; valid: YES>], reason: WidgetCenterServer)-immediate-budgeted-1]; Current: task [[2226-externalRequest([source:<BSProcessHandle: 0x69b8957a0; TraskWidgets:23522; valid: NO>], reason: WidgetCenterServer)-immediate]], Queued: task identifier: 2231; lifetime: 1637891ms; configuration: [externalRequest([source:<BSProcessHandle: 0x69b406850; TraskWidgets:23522; valid: NO>], reason: WidgetCenterServer)-immediate-budgeted-1]
The console log reason: WidgetCenterServer)-immediate-budgeted-1 confirms that:
When you call reloadAllTimelines() or reloadTimelines(ofKind:) from within an intent, those other widgets are still subject to the budget, which is why TodoListWidget doesn't update.
PS: I tested and waited enough long time, and the target widget finally catch up with the correct timeline, you can even choose to change device locale to let it refresh immediately.
PS: Tapping on Widget A and another instance of Widget A will not subject to the refresh budget, you already mentioned that.
If someone want to seek a hacky solution, this is the simple project to begin with.