# M4a task 14: the serve loop **Branch:** `m4a` (run `git switch m4a`; `git status --short` must be empty, otherwise stop) **Commit subject:** `gatewayd: serve, the event loop, typing, catch-up and reconnecting` ## Goal The loop that ties tasks 03 to 13 together (spec sections 8 and 9): - **Connecting**, at start and after every loss: `GET /users/me`, open the WebSocket, wait for `hello`, then log `gatewayd: connected to as `. A connection that fails is tried again after 1, 2, 5, 10, then every 30 seconds, with one log line per attempt: `gatewayd: cannot reach : ; trying again in s`, then a newline and `see docs/runbook.md#mattermost-unreachable`. A refused token (401 or 403) is never tried again: `run` returns `Stop::Auth`. - **After a restart** (the first connection only): every turn left in flight gets `interrupted: gatewayd restarted before the answer arrived; ask again` in its thread. A later reconnect must not do this: those turns are still running. - **Catching up**: the direct channel with each allowed user, and each allowed channel, from its mark. A channel without a mark is marked "now" and not caught up: history is not answered. - **Each post**, live or caught up: posts in channels we do not track are not recorded at all. A tracked post is recorded as handled **before** it is acted on, so after a crash it is not answered twice (the in-flight record reports it instead). Then it is routed (task 11): a stranger is logged by user id and post id only, **never with the text**. - **Turns** run on their own threads (task 13), recorded in flight while they run. When one ends, its session's waiting messages start the next. - **Typing**: every `typing_every_ms`, `user_typing` for every thread with a turn running. ## Files - Copy: `crates/gatewayd/tests/serve.rs`, `crates/gatewayd/tests/serve_restart.rs`, `crates/gatewayd/tests/support/fake_mm.rs`, `crates/gatewayd/tests/support/gateway.rs`, and the skeletons `crates/gatewayd/src/serve/mod.rs` and `crates/gatewayd/src/serve/handle.rs` - Modify: `crates/gatewayd/src/lib.rs` (`pub mod serve;`), `docs/implementer-log.md` ## The skeletons `serve/mod.rs`, written: the pointers, `INTERRUPTED`, `Log`, `Stop` (`Auth`, `State`, `Start`, `Asked`) and its `Display`, `Tuning` and its default, the `Gateway` struct, and the two functions that are glue: **`run`** (the connect-or-back-off loop) and **`Gateway::event_loop`** (finish turns, send typing, wait for an event, handle it). Read both first: they call everything you write. To fill: `From for Stop`, `backoff`, `sleep_unless`, `connect`, `Gateway::new`, `Gateway::connected`. `serve/handle.rs`, all to fill: `now_ms`, `post`, `tracked`, `handle_post`, `start`, `finished`, `typing`, `catch_up`. Each `todo!()` has its steps above it, with the exact log lines. `run` takes the token already loaded and a `stop` flag, so the tests need no secrets and can end it; task 15's `main` passes a flag that is never set. ## Steps - [ ] **1. Copy.** `git switch m4a`, then `mkdir -p crates/gatewayd/src/serve && cp docs/plans/M4a/files/crates/gatewayd/src/serve/mod.rs docs/plans/M4a/files/crates/gatewayd/src/serve/handle.rs crates/gatewayd/src/serve/`, `cp docs/plans/M4a/files/crates/gatewayd/tests/serve.rs docs/plans/M4a/files/crates/gatewayd/tests/serve_restart.rs crates/gatewayd/tests/` and `cp docs/plans/M4a/files/crates/gatewayd/tests/support/fake_mm.rs docs/plans/M4a/files/crates/gatewayd/tests/support/gateway.rs crates/gatewayd/tests/support/`. Add `pub mod serve;` to `lib.rs`. - [ ] **2. See it fail.** `cargo test -p gatewayd --no-fail-fast --test serve --test serve_restart`. Expected: it compiles; `serve` 6 fail; `serve_restart` 6 fail and 1 passes (a damaged state file stops `run` before anything you write is called). - [ ] **3. Fill `mod.rs` first** (`from`, `backoff`, `sleep_unless`, `Gateway::new`, `connect`, `connected`), **then `handle.rs`** (`now_ms`, `post`, `tracked`, `finished`, `typing`, `start`, `handle_post`, `catch_up`). `cargo check -p gatewayd` after each function. - [ ] **4. See it pass.** `cargo test -p gatewayd --test serve --test serve_restart`, five times. Expected: 6 and 7 passed each time, in about 2 s. - [ ] **5. Run the gate.** `cargo fmt --all`, then `make gate`. Expected last line: `gate: ok`. - [ ] **6. Log and commit.** `git add crates/gatewayd docs/implementer-log.md Cargo.lock && git commit` ## Done when - Both suites pass five times running; `make gate` prints `gate: ok`. ## Stop and report if - A test passes only sometimes, or a test takes 5 s or more (that is a wait that timed out, not a pass). - `run` or `event_loop` seems to need a change. They are given; report instead.