Баг #3: consumer падал навсегда с TypeError "Cannot read properties of null
(reading 'length')" и переставал читать стрим. Два корня:
1. XtrimSupervisor.trim() брал MINID = lastDeliveredId. Но un-acked pending
записи старше lastDeliveredId (доставлены, не подтверждены) → XTRIM сносил
собственные pending группы. Теперь нижняя граница trim — самый старый
un-acked ID из XPENDING (новый метод RedisStore.xpendingMinId), а сравнение
stream-ID числовое по <ms>-<seq>, не лексикографическое ('1000' < '999').
2. parseStreamEntries падал на null rawFields: при перечитывании PEL
(XREADGROUP ... 0) Redis отдаёт [id, null] для обрезанных ID. Добавлен
гард `if (!rawFields) continue` — обрезанные записи пропускаются.
Триггер: consumer отстаёт от писателя (бутстрап с genesis) → растёт pending →
XtrimSupervisor сносит pending → PEL отдаёт null → краш в бесконечном цикле.
Воспроизведено и проверено на реальном Redis (новый integration-тест
xtrim.integration.test.ts, гоняется в CI): trim сохраняет все un-acked pending,
PEL-перечитка не падает на null. Unit: 211 зелёных.
parser2 1.1.2→1.1.3. ship-reader без изменений.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>