feat(telegram): wake-on-complete for idle chats - #228
Merged
Conversation
Background jobs started from a Telegram chat were dead letters when the chat was idle: the raw exit line reached the chat but no agent turn ever ran, so results were never summarized or acted on. With background.wake_on_complete (default true), an exit on an idle chat now starts one system-initiated wake turn via the normal chat pipeline — exits within wake_coalesce_ms coalesce into a single turn, spend is bounded per chat by max_wakes_per_hour, and busy chats keep the legacy raw exit line (their notice drain already reaches the model). Wake turns run with no user binding, so approval prompts remain available to any allowed chat member without hijacking a user. Mirrors the serve-surface wake dispatcher (bg_wake.go) on the Telegram surface. Docs updated in docs/TELEGRAM.md and docs/CONFIG.md.
…op race Adversarial review rounds 1-2 findings, all fixed: - F1 (P1): the per-chat exit-watcher re-pushed raw completion lines for jobs a wake turn already covered. The controller now records routed job ids and the watcher skips them. - F2 (P2): a user message taking the chat slot between the idle probe and the coalesce timer queued a stale wake behind the user's turn. fire() now re-checks idleness, drops the wake, and refunds the spend (the user's turn notice drain delivers the data). - F3 (P2): routed-id recording raced the watcher's 10s tick — the id is now recorded before the busy probe and rolled back if reserve fails. - F4 (P2): concurrent stop() callers could double-close done. The close now happens under the controller mutex. - F5: routed map bounded (reset at 1024 entries; suppression only matters while the watcher is live). Regression tests added for F1/F2 semantics; full Telegram/bg scope green with -race -count=1.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Background jobs started from a Telegram chat were dead letters when the chat was idle: the raw 📋 exit line reached the chat, but no agent turn ever ran — the model never saw the results, so nothing was summarized or acted on.
With
background.wake_on_complete(default true, same setting as the serve surface), an exit on an idle chat now starts one system-initiated wake turn through the normal chat pipeline:wake_coalesce_msshare one); raw push suppressedDesign
background.wake_on_complete+wake_coalesce_ms+max_wakes_per_hour(per chat); forced off withnotify: "off".userID 0— the approver's existing "no user binding" mode, so group approvals work without user hijack.pinChat), bounded wait — a wake never queues behind a long turn.stop()closes under the mutex — safe against drop-vs-shutdown races.Testing
cmd/odek/bg_telegram_wake_test.go(allowed/disabled paths, idle wake, busy fallback, spend cap, coalescing, wake-routed watcher suppression, busy-at-fire drop+refund, nil-bot noop).-race -count=1.go build ./...+go vetclean.Adversarial review
3-judge ritual, 2 rounds, 5 findings (1×P1, 3×P2, 1×info) — all fixed with regression tests; final
-racesweep green.Docs
docs/TELEGRAM.md: new "Wake-on-complete" section + routing tabledocs/CONFIG.md:wake_on_completesemantics extended to the Telegram surface