I found an answer to one of my questions. The MCU gets lost when I don't define the handler because the ram and flash vectors are getting mixed up.
The examples do in fact set up RTC_FR_IRQHandler because of a bug in the SDK.
When the system is coming up, the timers are initialized in TMR_Init():

StackTimer_Init() overrides and enables the RTC_FR interrupt so that the stack timer handler is used:

The abstraction layer eventually calls InstallIRQHandler where the new handler is installed. Note that the vector table is then moved to RAM:

After initialization, I eventually go into DS(0) in POWER_EnterPowerDown(). On my very first wakeup event, the vector table pointer is restored to _Vectors:

Unfortunately, you can see that in startup_QN908XC.s _Vectors is defined as the flash vector table.

...oops!
I'm guessing what's needed is something like:
Index: fsl_power.c
===================================================================
--- fsl_power.c (revision 20178)
+++ fsl_power.c (working copy)
@@ -352,9 +352,30 @@
#if ((__FPU_PRESENT == 1) && (__FPU_USED == 1)) || (defined(__VFP_FP__) && !defined(__SOFTFP__))
SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); /* set CP10, CP11 Full Access */
#endif
+#if defined(__CC_ARM)
+ extern uint32_t Image$$VECTOR_ROM$$Base[];
+ extern uint32_t Image$$VECTOR_RAM$$Base[];
+ extern uint32_t Image$$RW_m_data$$Base[];
- SCB->VTOR = (uint32_t)&__Vectors;
+#define __VECTOR_TABLE Image$$VECTOR_ROM$$Base
+#define __VECTOR_RAM Image$$VECTOR_RAM$$Base
+#define __RAM_VECTOR_TABLE_SIZE (((uint32_t)Image$$RW_m_data$$Base - (uint32_t)Image$$VECTOR_RAM$$Base))
+#elif defined(__ICCARM__)
+ extern uint32_t __RAM_VECTOR_TABLE_SIZE[];
+ extern uint32_t __VECTOR_TABLE[];
+ extern uint32_t __VECTOR_RAM[];
+#elif defined(__GNUC__)
+ extern uint32_t __VECTOR_TABLE[];
+ extern uint32_t __VECTOR_RAM[];
+ extern uint32_t __RAM_VECTOR_TABLE_SIZE_BYTES[];
+ uint32_t __RAM_VECTOR_TABLE_SIZE = (uint32_t)(__RAM_VECTOR_TABLE_SIZE_BYTES);
+#endif /* defined(__CC_ARM) */
+ //SCB->VTOR = (uint32_t)&__Vectors;
+ /* Point the VTOR to the position of vector table */
+ SCB->VTOR = (uint32_t)__VECTOR_RAM;
+
+
/* All registers in NVIC are lost, restore from backup values */
NVIC->ISER[0U] = backISER[0U];
NVIC->ISER[1U] = backISER[1U];
In any event, this still does not answer why I'm not waking up when the RTC fires. It doesn't really have anything to do with the vector table, right?