Files
openclaw/extensions/imessage/src/test-support
Peter Steinberger b2ea69c9f5 fix(imessage): prevent missed messages after gateway crashes (#110409)
* fix(imessage): adopt durable ingress drain with cursor advanced after append

The chat.db watcher advanced its ROWID cursor after yielding rows to an
in-memory pipeline; a crash between read and dispatch skipped those messages
forever. Raw rows now journal durably (event_id = message GUID, lane per
chat) at the monitor chokepoint, and the cursor advances only after the
durable append — mirroring Telegram's offset-after-spool contract. Dispatch
runs through the core drain with deferred claims, merged fan-out adoption,
and gated settlement; legacy catchup enters the same raw path. The
transitional GUID replay guard is deleted per the layering contract with
4h/10k tombstone parity; the permanent age fence and recovery caps are
untouched. Twin verdict: tapbacks are distinct rows with their own
ROWID/GUID; fresh-GUID stale backlog remains age-fence territory (upstream
imsg source cited in PR).

Autoreview blocked by codex sandbox network in the build stage; full manual
review performed. Part of the #109657 fleet adoption program (wave 2).

* fix(imessage): exempt operator-requested catchup rows from the live age fence

Landing review caught real message loss: legacy catchup accepts rows up to
its configured maxAge (120min default), but the unified durable path ran them
through the 15-minute live Push-flush fence — suppressing AND tombstoning
any catchup row older than 15 minutes, permanently losing history the
operator explicitly asked to replay. Catchup rows now carry provenance
through the journal payload and skip the live fence; the catchup query's own
maxAge window is their age gate. Regression test proves provenance survives
the durable round trip.

* test(imessage): resolve ingress rebase mocks

* docs(imessage): document the fence-suppression vs catchup overlap tradeoff

* fix(imessage): satisfy durable ingress lint gates
2026-07-18 05:51:29 +01:00
..