Skip to content

feat(scheduler): ADR-0020 slice 1b schedule-through-gate - #171

Merged
chinkan merged 1 commit into
mainfrom
feat/mid-run-1b-schedule
Oct 7, 2026
Merged

chinkan merged 1 commit into
mainfrom
feat/mid-run-1b-schedule

Conversation

@chinkan

@chinkan chinkan commented Oct 7, 2026

Copy link
Copy Markdown
Owner

Summary

ADR-0020 slice 1b: scheduled turns go through TurnGate with the same session_key(bot_id, user_id) serialization as user turns.

  • TurnGate::begin_scheduled: idle → mark Scheduled and return; busy → ticket in waiting_scheduled and await until finish hands the gate (user always finishes first; leftovers stay pending behind).
  • Job runner (main.rs): begin_scheduled before process_message_outcome, finish after every outcome (success / max-iter / error). ADR-0013 re-fires already share this runner, so they use the same path.
  • finish → Next::User: spawn pending user turns via spawn_telegram_turn_loop (extracted from 1a Submit::Start). Bare agent loop fallback when no owning Telegram bot / unparseable ids.
  • During a scheduled turn, user messages still enqueue (👀 from 1a) and are not drained (drain already no-ops for TurnKind::Scheduled; no steer source when schedule_id.is_some()).
  • /stop clear: still drops only the user queue; waiting scheduled tickets are kept (unit-tested).

Out of scope

Refs: ADR-0020 slice 1b

Test plan / QA matrix

  • Unit: schedule serialisation in turn_gate (begin_scheduled blocks behind user; never two active; no drain during scheduled; waiting scheduled before leftover pending; /stop clear keeps tickets)
  • cargo fmt
  • cargo clippy --locked --all-targets -- -D warnings
  • env -u RUSTFOX_GOOGLE_OAUTH_CLIENT_ID cargo test --locked (947 passed / 0 failed)
  • Manual Telegram:
    1. Start a long user turn (e.g. a multi-tool prompt). While it runs, fire a scheduled task for the same bot+user — the schedule should wait and only reply after the user turn ends.
    2. While a scheduled run is active, send a chat message — expect 👀, no steer into the schedule reply; after the schedule finishes, a user turn should start with that pending message.
    3. /stop during a user turn that has a waiting schedule behind it — queue cleared, scheduled run still proceeds.

Scheduled job runner claims TurnGate via begin_scheduled before
process_message_outcome and finish afterward so scheduled and user
turns never run in parallel on the same session_key. finish→User
reuses the Telegram spawn loop (bare agent fallback when no bot).

Refs: ADR-0020 slice 1b

chinkan commented Oct 7, 2026

Copy link
Copy Markdown
Owner Author

TL ACCEPT — tip c48c3c1 (ADR-0020 slice 1b)

Reviewed against ADR-0020 Q8 / Product GO:

  • begin_scheduled: idle → Scheduled; busy → oneshot ticket, user finishes first
  • No steer into schedule (drain empty while TurnKind::Scheduled)
  • User messages during schedule enqueue (👀 from 1a), then finish → Next::User via spawn_telegram_turn_loop
  • /stop clear drops user queue only; waiting scheduled tickets kept (unit-covered)
  • Waiting scheduled beats leftover pending; job runner wraps begin_scheduled / finish around existing ADR-0013 path

Unit coverage for the above looks solid. Merge when QA GO (CI green + manual three) lands. No tag.

Non-block (later): job runner stays globally serial (pre-1b); a long begin_scheduled wait can delay other users' jobs. Fine for personal single-user; revisit only if multi-bot concurrency matters.

@chinkan
chinkan merged commit 3c08e1d into main Oct 7, 2026
14 checks passed
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