Skip to content

feat(telegram): wake-on-complete for idle chats - #228

Merged
jkyberneees merged 3 commits into
mainfrom
feat/telegram-wake
Sep 9, 2026
Merged

feat(telegram): wake-on-complete for idle chats#228
jkyberneees merged 3 commits into
mainfrom
feat/telegram-wake

Conversation

@jkyberneees

Copy link
Copy Markdown
Contributor

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:

Chat state Behavior
Idle + wake on Coalesced wake turn (exits within wake_coalesce_ms share one); raw push suppressed
Busy (turn running) Legacy raw 📋 push — the running turn's notice drain already reaches the model
Wake disabled / spend cap hit Legacy raw 📋 push

Design

  • No new config knob — reuses background.wake_on_complete + wake_coalesce_ms + max_wakes_per_hour (per chat); forced off with notify: "off".
  • Wake turns run with userID 0 — the approver's existing "no user binding" mode, so group approvals work without user hijack.
  • Idle detection reuses the chat turn slot (pinChat), bounded wait — a wake never queues behind a long turn.
  • Busy-at-fire drops the wake and refunds the spend (the user's turn drain delivers the data).
  • Routed job ids recorded before the busy probe so the 10s exit-watcher can never double-push; rolled back if reserve fails; map bounded.
  • stop() closes under the mutex — safe against drop-vs-shutdown races.

Testing

  • RED-first: 9 tests in 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).
  • Full Telegram/bg scope green with -race -count=1.
  • go build ./... + go vet clean.

Adversarial review

3-judge ritual, 2 rounds, 5 findings (1×P1, 3×P2, 1×info) — all fixed with regression tests; final -race sweep green.

Docs

  • docs/TELEGRAM.md: new "Wake-on-complete" section + routing table
  • docs/CONFIG.md: wake_on_complete semantics extended to the Telegram surface

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.
@jkyberneees
jkyberneees merged commit e92b144 into main Sep 9, 2026
10 checks passed
@jkyberneees
jkyberneees deleted the feat/telegram-wake branch September 9, 2026 20:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant