Suppose a button is accepted when during 50ms the average is above or below 50%. That 50ms is the response time and it is a fixed time that determines how responsive the device is.
To get that 50ms, a hardware timer of 100Hz could be used with a filter over 5 samples.
That 100Hz has a fixed influence on the system.
There are very dumb and very complex mathematical calculations to do debouncing with samples at a fixed rate. Those calculations do indeed need a fixed sample rate.
When a keypad matrix is used, an interrupt is often not possible. The timer will just read the matrix and extract the pushed buttons.
A design like that has no weird consequences for longer or shorter delays. That is a good design for an embedded system. That is how embedded devices were designed for decades.
If the button would be connected to an interrupt, the interrupt could not be triggered (no button pressed) or the interrupt could be triggered at an extremely high rate (dirty and bouncing contacts). Maybe even a few kHz burst. It can no longer be predicted what the impact of the interrupt is for the device. Therefor it is a very bad design. That means that if the device would get older and the buttons get worse, the device could stop working.
I'm not joking, that would really be a terrible bad design.
A software timer can be too soft. When the code uses delays, the software timer might be delayed and the pressing the button is not always the same anymore.
In the Arduino, it is often possible to avoid the use of timers and interrupts. If no delays are used, the millis() function is often enough for a software timer with good responsive buttons.
Long story short : a timer interrupt to read buttons has a fixed impact on the software, and the fixed sample rate makes it possible to use debounce calculations. For the Arduino, a software timer with millis() is often enough.
I am not sure if you actually discussed the OP question.
Ever since I started coding for Arduino I have objected to the "looping forever" approach, especially when the task is to "react on input".
The often used argument that "the processor is fast " so polling for external events will eventually succeed is just plain wrong.
Some "gurus" will actually say not to use interrupts on Arduino. Ever.
(I do not wish to get trapped in that pointless argument ever again.)
My question / point - when interrupt is used to DETECT external event , such as "button pushed" , why not let the ISR do the debouncing?
I prefer to let the ISR FINISH the task initiated by the interrupt WHEN there is NOTHING else to do anyway. ( Another often touted and wrong argument - the ISR MUST be as short as possible - going back to "forever loop" concept. )