mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-26 03:51:11 +00:00
* refactor(whatsapp): replay durable inbound through the shared drain Accept-before-processing stays; the private startup replay loop and inline complete/release bookkeeping move to the core drain. Drain-owned entries keep their durable id so downstream failures release for replay, dedupe-claim contention stays retryable instead of tombstoning, and undeliverable claims still send configured read receipts. Rows tombstone at dispatch return (pre-migration timing), not at adoption (#108656). * fix(whatsapp): finish durable ingress drain adoption with serialized conversation lanes Core durable ingress intentionally serializes claims by remote JID. Same-conversation bursts now merge as queued followups in the core reply lane after adoption; channel debouncing remains for control and retry paths, with merged fan-out and gated settlement. Built on the durable drain branch base by @obviyus. * fix(whatsapp): fail closed on persistence failure and guard prepared-inbound races Landing autoreview caught two holes: the persistence-failure fallback dispatched live, bypassing drain dedupe and lane serialization now that the replay guard is deleted (duplicate replies / session races); and duplicate pending rows could orphan or clobber preparedInboundByDurableId entries. The append now retries transient failures with short backoff then drops loudly (fail closed — the fallback traded a correctness race for availability against an already-broken store); redeliveries neither clobber the first delivery's in-flight preparation nor keep orphan entries. The old fallback-contract test is repurposed to prove retry-then-durable-delivery. * fix(whatsapp): dispose the durable drain when the close drain times out The close timeout abandoned the graceful drain path before its finally could dispose, so a successor monitor could pump the same account queue against a still-live drain. The timeout wrapper now owns disposal; dispose is idempotent so the graceful path's cleanup is unaffected. * style(whatsapp): keep ingress internals unexported and drop a dead harness helper * refactor(whatsapp): move durable payload serialization to its own module The dead-export gate refused serializer/error exports whose only external consumers were tests. The payload contract (Long-timestamp-preserving serialize/deserialize + the permanent-error class) now lives in durable-payload.ts with durable-receive as its production consumer; the dead WhatsAppRetryableInboundError class is deleted (any non-permanent error is retryable to the drain classifier, so test-support throws a plain Error). * fix(whatsapp): guard prepared-map ownership and bound its growth A duplicate pending delivery's finishPreparation deleted the first delivery's kept entry (ownership guard now requires the deleter to be the installer), and queue pruning could evict pending rows whose prepared-map entries then lingered forever on a blocked lane (map now evicts oldest-first at a bound above the queue's pending cap; dispatch already re-normalizes the journaled payload when its entry is gone). Regression covers the duplicate case. * style(whatsapp): prune split leftovers and satisfy consistent-return lint * style(whatsapp): satisfy type-aware lint across the drain monitor Closed verdict shape for the retry result (queue enqueue's metadata generic leaks any into the union), Promise.resolve-wrapped abandonment aggregators, braced timeout executor, and the drain merged to a single const (lazy closures above only run post-start, so const-after-use is TDZ-safe). --------- Co-authored-by: Ayaan Zaidi <hi@obviy.us>