AtlatestRenderedmarkdown
Readme
Off-device repro evidence — courier second spam cause (2026-07-01)
All runs used a LOCAL mock (mock_telegram.py) via COURIERTELEGRAMAPI_URL. NOTHING reached real Telegram. Mock models Telegram's getUpdates offset semantics (offset N confirms/drops updates < N) and records every request.
Binaries:
- FIXED: build/dev/bin/courier (branch fix/courier-log-persist-repro)
- CONTROL: master + api-url-only change (isolates the offset-persistence fix)
Deliverable 1 — --log now APPENDS across restarts (was: truncate)
2026-07-01T13:50:34Z [INFO] Courier starting mode=leader relay=none telegram=not configured 2026-07-01T13:50:34Z [INFO] MCP server ready name=courier --- courier restart --- 2026-07-01T13:50:36Z [INFO] Courier starting mode=leader relay=none telegram=not configured 2026-07-01T13:50:36Z [INFO] MCP server ready name=courier --- courier restart --- 2026-07-01T13:50:38Z [INFO] Courier starting mode=leader relay=none telegram=not configured 2026-07-01T13:50:38Z [INFO] MCP server ready name=courier
3x 'Courier starting' + 2x restart markers => full history preserved.
SECOND CAUSE — BEFORE (pre-fix control): backlog delivered + re-delivered
Cold start with a 2-update backlog. Each delivered message = one inbound the leader would ACK = one outbound Telegram send => storm.
control RUN 1 (cold start) stdout events:
{"type":"hello","pid":3748}
{"type":"heartbeat"}
{"type":"message","text":"BACKLOG-1","sender":"daviwil","sender_id":"42","chat_id":"1001"}
{"type":"message","text":"BACKLOG-2","sender":"daviwil","sender_id":"42","chat_id":"1001"}
{"type":"heartbeat"}
{"type":"heartbeat"}
{"type":"heartbeat"}
{"type":"heartbeat"}
control RUN 1 stderr (no offset persistence, no drain):
2026-07-01T13:49:48Z [INFO] Telegram poller child started pid=3748
control RUN 2 (restart, backlog still pending) -> RE-DELIVERS:
{"type":"message","text":"BACKLOG-1","sender":"daviwil","sender_id":"42","chat_id":"1001"}
{"type":"message","text":"BACKLOG-2","sender":"daviwil","sender_id":"42","chat_id":"1001"}SECOND CAUSE — AFTER (fixed): drain on cold start, deliver-once, no re-delivery
RUN 1 (cold start, 2-update backlog) stdout events:
{"type":"hello","pid":30027}
{"type":"heartbeat"}
{"type":"heartbeat"}
{"type":"heartbeat"}
{"type":"heartbeat"}
{"type":"heartbeat"}
{"type":"heartbeat"}
{"type":"heartbeat"}
RUN 1 stderr:
2026-07-01T13:44:45Z [INFO] Cold start: drained Telegram backlog (not delivered) count=2 offset=3
RUN 2 (restart; 1 NEW update injected) -> delivers NEW once:
{"type":"message","text":"NEW-live-msg","sender":"daviwil","sender_id":"42","chat_id":"1001"}
2026-07-01T13:44:51Z [INFO] Restored Telegram getUpdates offset offset=3
RUN 3 (restart, no new updates) -> NO re-delivery:
message events: 0
2026-07-01T13:44:57Z [INFO] Restored Telegram getUpdates offset offset=4