It used to be the case where if Heartbeat processing is above a certain threshold, the game starts falling into what’s commonly called a spiral of death.
This is a common problem of all fixed-framerate update systems: imagine you’re trying to run a 30 Hz update step that takes 40 ms. After every run of an update step like this you are “behind” real-time by an extra 40-33=7 ms. So after running 5 frames with 1 step/frame you’re now 35 ms behind so you’re forced to run 2 steps/frame, with every frame now processing 66 ms of real time in 80 ms - becoming 14 ms late. In 3 frames you have to add one more update step/frame, etc. - this cycle never ends.
We had some code that artificially stops the spiral by clamping the # of steps we run per frame. However, with variable-framerate update this is no longer necessary - game framerate depends on the time you take in Heartbeat/RenderStepped but there are no magical thresholds that, when being crossed, result in sudden unexpected performance drops (physics being the major exception that still runs at fixed framerate…).
wait() loops are not subject to spiral of death since they do not properly account for time - wait(0.1) does not really result in 10 Hz update, it will wake the thread after at least 100 ms have passed since the call to wait() but it does not account for time spent in the script or for extra time the script waited.