TL;DR: Because Angular still uses zone.js in order to trigger change detection.
Zone.js behind the scenes is wrapping a bunch of browser APIs in order to detect when an event happens on the page (there are specific types of events it looks for, see the Angular docs about zones for more details). It doesn't notify Angular what event exactly happened, but it will say that it is possible that some value somewhere was changed. Angular then kicks off change detection that loops through the whole component tree, checking all the components for changes. If ChangeDetectionStrategy.OnPush
is enabled, then it can be more efficient, checking only the components in the tree that may have changed.
This is why you see your function execute to update the signal correctly. The missing link is that zone.js would detect that and notify Angular that something was updated in order to kick off the change detection. If you were to add a call to manually trigger change detection, then it should get your example working again.
Signals are only the first step on the path to being able to remove zone.js completely from a compatible app. There is a (now complete) RFC on Angular's GitHub repository discussing Signal-Based Components, which would be a further step towards being able to accomplish a zoneless Angular app. It will just take some time for all of the infrastructure of Angular to be changed, since zone.js is such a fundamental part of how Angular currently works.
Here is a slightly-old article that discusses more of zone.js and its role in the Angular change detection process (it is still pretty relevant).