bot: pauze tussen pagina-sends (PAGE_SEND_DELAY_MS) tegen staged-ghost-race

This commit is contained in:
Eddy de Vink 2026-10-05 17:24:37 +02:00
commit b1b6137d8a
4 changed files with 59 additions and 8 deletions

View file

@ -21,6 +21,10 @@ DIENSTEN_DIR=../Whatsapp_Dienst/diensten
# Rate limiting # Rate limiting
MAX_REQUESTS_PER_DAY=5 MAX_REQUESTS_PER_DAY=5
# Pauze tussen pagina-sends (ms). Staged-ghost-race-mitigatie: maakt elke pagina
# een effectief losse send (enkele sends falen nooit). 0 = geen pauze.
PAGE_SEND_DELAY_MS=15000
# Admin notifications # Admin notifications
ADMIN_NUMBER=31612345678@c.us ADMIN_NUMBER=31612345678@c.us

View file

@ -185,11 +185,25 @@ getransmitteerd was) — ze zijn géén bezorgbewijs en gaven verkeerde signalen
chromium-tab en verliest de 2e (bestaat in store + ack2 maar wordt nooit verzonden). chromium-tab en verliest de 2e (bestaat in store + ack2 maar wordt nooit verzonden).
De bridge serialiseert nu álle media-sends over alle sessies/clients door één keten De bridge serialiseert nu álle media-sends over alle sessies/clients door één keten
(`serializeMediaSend` in `wwebjs-api-build-p25/src/utils.js`) en wacht (`serializeMediaSend` in `wwebjs-api-build-p25/src/utils.js`) en wacht
**`MEDIA_SEND_DELAY_MS`** (bridge-`.env`: `/home/aiaiaiaiagent/wwebjs-api/.env`, nu `500`) **`MEDIA_SEND_DELAY_MS`** (bridge-`.env`: `/home/aiaiaiaiagent/wwebjs-api/.env`, nu `500`
ná elke media-send. De bot zelf pauzeert **niet**. Config/code/waarom volledig sinds 2026-09-28 teruggezet van 1000; delay lost de race niet op, zie RCA)
gedocumenteerd in vault [[Whatsapp rest-api]] ("Bridge-wide media-send throttle") en ná elke media-send.
[[Dienst media bezorgtest]] (RCA 2026-09-26). Tijdelijke mitigatie — permanente fix - **Bot-side pagina-pacing (`PAGE_SEND_DELAY_MS`, bot-`.env`, nu `15000`)**: sinds
(fork: send óf echt transmetteren óf zichtbaar falen) staat nog open. 2026-10-05 wacht de bot ná elke pagina (behalve de laatste) voordat de volgende
gestuurd wordt. Reden: ook verse single-sends van een "verloren" blz komen aan, maar
de paarsgewijze flow (blz 2 direct na blz 1, brug-delay 500 ms) verliest blz 2 steeds
opnieuw (casus 4027: 3 botruns + herhaalde opvraag na re-render). De pauze maakt elke
pagina een effectief losse send — enige sends falen empirisch niet. `0` zet uit.
De brug-delay zelf NIET verhogen (delay loss effect, RCA 26-09).
- **Bridge-`.env`-wijzigingen**: `env_file` wordt bij container-create gelezen → een
`MEDIA_SEND_DELAY_MS`-wijziging werkt pas na een **recreate**
(`cd ~/wwebjs-api && sudo -A docker compose up -d`); een kale `docker restart` (ook de
wekelijkse timer) herlaadt de `.env` **niet**. Recreate = sessie-herverbinding, alleen
met expliciete toestemming (hard verbod op container-restart staat in de vault).
Config/code/waarom volledig gedocumenteerd in vault [[Whatsapp rest-api]]
("Bridge-wide media-send throttle") en [[Dienst media bezorgtest]] (RCA 2026-09-26).
Tijdelijke mitigatie — permanente fix (fork: send óf echt transmetteren óf zichtbaar
falen) staat nog open.
**Ack-semantiek (wwebjs 1.34.7):** ack 1 = verstuurd naar server (één grijs vinkje), ack 2 = bezorgd op apparaat (twee vinkjes), ack 3 = geopend/gelezen. Let op: eerdere notities die "één grijs vinkje (ack 2)" noemden, zaten er dus naast. **Let op 2 (2026-09-26):** óók deze acks zijn geen leveringsbewijs — zie RCA hieronder. **Ack-semantiek (wwebjs 1.34.7):** ack 1 = verstuurd naar server (één grijs vinkje), ack 2 = bezorgd op apparaat (twee vinkjes), ack 3 = geopend/gelezen. Let op: eerdere notities die "één grijs vinkje (ack 2)" noemden, zaten er dus naast. **Let op 2 (2026-09-26):** óók deze acks zijn geen leveringsbewijs — zie RCA hieronder.
@ -230,11 +244,23 @@ multi-page sends vanzelf en is de race weg.
direct-opvolgende media-send overlapt in de ene tab en de 2e verliest. direct-opvolgende media-send overlapt in de ene tab en de 2e verliest.
Bestand bytes zijn nooit het probleem; **re-render (poppler) is een dwaalspoor en geen Bestand bytes zijn nooit het probleem; **re-render (poppler) is een dwaalspoor en geen
fix** — het maskeerde de race alleen (nieuwe poging = nieuwe race-rol). Mitigatie = fix** — het maskeerde de race alleen (nieuwe poging = nieuwe race-rol). Mitigatie =
bridge-breed throttle (`MEDIA_SEND_DELAY_MS`, 500) — zie hierboven. Bij vermoeden: bridge-breed throttle (`MEDIA_SEND_DELAY_MS`, 500 — delay loss effect, RCA 26-09; teruggezet
van 1000 op 2026-09-28) — zie hierboven. Bij vermoeden:
opnieuw versturen, apparaat als waarheid. opnieuw versturen, apparaat als waarheid.
**1b. Transparante (alpha) PNG — WEL een bestandsklasse (2026-09-28, casus 4039).**
Dienst 4039 (2 blz): blz 79 kwam **nooit** aan — ongeacht volgorde (078 eerst/laatst),
timing (500/1000 ms), UI-reset ertussen of vice versa; verschijnt in beide stores met
server-locators maar rendert niet op het apparaat. Verse `pdftoppm`-render (ondoorzichtig
sRGB, 147 KB i.p.v. 186 KB RGBA) kwam **wel** aan; na vervanging van `4039-079.png`
kwamen beide blz van 4039 aan. Vermoedelijke oorzaak: de opgeslagen PNG's zijn RGBA met
~90% volledig transparante pixels; WhatsApp's re-encode-pipeline (PNG→JPEG) is berucht
onbetrouwbaar met transparante PNGS (o.a. wwebjs-issues #2695 (silent fail PNG send,
multi-device), #3603 (transparante PNG blurred), #201772 (image-send hang); loss of alpha op transparante PNG's in officiële clients ([StackOverflow 37554514](https://stackoverflow.com/questions/37554514/transparent-png-images-in-whatsapp))).
554 van de 555 opgeslagen PNG's zijn RGBA met (deels transparante) achtergrond → zelfde risico op andere diensten (mogelijk de echte oorzaak van de klasse-1 "staged ghosts": de bestand-inhoud i.p.v. timing). De bot stuurt sinds `07b511e` mimetype op basis van extensie; ondoorzichtig renderen bij de bron lost het op; documents via `sendMediaAsDocument` omzeilt de image-pipeline maar is afgewezen als productie-richting.
**2. Ontvanger offline/weigert (ack-1-hang)** — bericht staat gequeued, apparaat pakt het **2. Ontvanger offline/weigert (ack-1-hang)** — bericht staat gequeued, apparaat pakt het
niet op. Check eerst óf het apparaat online is, wacht af; persoonsgebonden. niet op. Check eerst óf het apparaat online is wacht af; persoonsgebonden.
> **Detectie/verificatie:** de bridgestore en live acks zijn **geen** bezorgbewijs (bridge > **Detectie/verificatie:** de bridgestore en live acks zijn **geen** bezorgbewijs (bridge
> fabriceert ze). Enige betrouwbare bronnen: het apparaat en `getInfo` > fabriceert ze). Enige betrouwbare bronnen: het apparaat en `getInfo`

View file

@ -154,7 +154,8 @@ nooit leveringsbewijs.
> **🛡️ Media-pacing zit bridge-breed (2026-09-26), niet in de bot.** Staged-ghost-race: > **🛡️ Media-pacing zit bridge-breed (2026-09-26), niet in de bot.** Staged-ghost-race:
> de wwebjs-media-pipeline is één tab; een direct-opvolgende media-send (van elke client) > de wwebjs-media-pipeline is één tab; een direct-opvolgende media-send (van elke client)
> overlapt en de 2e verliest (in store + ack2 maar nooit verzonden). De bridge serialiseert > overlapt en de 2e verliest (in store + ack2 maar nooit verzonden). De bridge serialiseert
> nu alle media-sends over alle sessies en wacht `MEDIA_SEND_DELAY_MS` (bridge `.env`, 500) > nu alle media-sends over alle sessies en wacht `MEDIA_SEND_DELAY_MS` (bridge `.env`, 500;
> wederzijds bevestigd dat delay de race niet oplost; teruggezet van 1000 op 2026-09-28)
> ertussen. De bot pauzeert niet. Details/config/locatie: zie AGENTS.md en vault "Whatsapp > ertussen. De bot pauzeert niet. Details/config/locatie: zie AGENTS.md en vault "Whatsapp
> rest-api.md". Tijdelijke mitigatie; permanente fix (fork) staat open. > rest-api.md". Tijdelijke mitigatie; permanente fix (fork) staat open.

View file

@ -3,6 +3,21 @@ const { sendTextMessage, sendImageMessage, notifyAdmin, sendChatSeen } = require
const { checkLimit, increment, MAX_REQUESTS_PER_DAY } = require('./rateLimiter') const { checkLimit, increment, MAX_REQUESTS_PER_DAY } = require('./rateLimiter')
const { increment: incrementDaily } = require('./dailyStats') const { increment: incrementDaily } = require('./dailyStats')
// Pauze tussen opeenvolgende pagina-sends. De staged-ghost-race (RCA 2026-09-26)
// treedt op als de 2e pagina start terwijl de 1e nog écht transmetteert — de bot
// wacht per pagina alleen op het optimistische brug-signaal (staging), en de
// bridge-delay (MEDIA_SEND_DELAY_MS) wacht óók op staging (delay loss effect).
// Een bot-side wacht maakt van elke pagina een effectief losse send: die komen
// empirisch wél aan (enkele sends falen nooit).
const PAGE_SEND_DELAY_MS = (() => {
const parsed = parseInt(process.env.PAGE_SEND_DELAY_MS, 10)
return Number.isFinite(parsed) && parsed >= 0 ? parsed : 15000
})()
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
const ALLOWED_GROUP = process.env.ALLOWED_GROUP const ALLOWED_GROUP = process.env.ALLOWED_GROUP
const ALLOWED_GROUP_NAMES = (process.env.ALLOWED_GROUP_NAME || '') const ALLOWED_GROUP_NAMES = (process.env.ALLOWED_GROUP_NAME || '')
.split(',') .split(',')
@ -78,6 +93,11 @@ async function handleWebhook(payload) {
console.error(errorMsg) console.error(errorMsg)
await notifyAdmin(errorMsg) await notifyAdmin(errorMsg)
} }
// Wacht vóór de volgende pagina zodat de echte transmissie van deze pagina
// klaar is (staged-ghost-race RCA) — 0 zet de pauze uit.
if (i < pngPaths.length - 1 && PAGE_SEND_DELAY_MS > 0) {
await sleep(PAGE_SEND_DELAY_MS)
}
} }
} }