refactor(telegram): split MessageView into pure reconcile + executor #49

Merged
weiwen merged 1 commit from refactor/message-view-reconcile-seam into main 2026-07-06 21:34:23 +08:00
Owner

What

Splits MessageView out of telegram/mod.rs into a new telegram/view.rs, separating the edit-vs-send-vs-skip decision from the teloxide IO.

  • reconcile(current, pages, markup) -> Vec<ViewOp> — the prefix-stable rolling seal, now a pure free function over &[String].
  • plan_plain(current, text) — the error-notice path, folded into the same ViewOp vocabulary.
  • execute(&mut self, …) — the sole teloxide-touching method; replays ops, records sent message IDs, and debug_asserts the ids.len() == rendered.len() invariant.
  • Thin apply/apply_with_buttons/set_plain wrappers preserve the caller-facing interface, so deliver_streaming/render_final are unchanged.

Why

The reconciliation logic — the most intricate code in the delivery path — was previously reachable only through a live Telegram API and had no tests. Moving the decision behind a pure function gives it the same table-testable surface paginate already enjoys.

Tests

9 new table tests assert on ViewOp equality: the prefix-stable seal, changed-tail-only edits, markup-on-unchanged-last-page, markup-only-on-last-op, both plan_plain paths, and one documenting the preserved shrink-orphan quirk (a shrinking response leaves trailing messages untouched — behavior is preserved exactly, not fixed here). execute is intentionally left untested: its edit-vs-send branch is now 1:1 with the op variant.

  • cargo test: 113 passed, 0 failed
  • cargo clippy --all-targets: clean

Behavior preserved exactly. One-line CONTEXT.md architecture note added; no new glossary term.

## What Splits `MessageView` out of `telegram/mod.rs` into a new `telegram/view.rs`, separating the edit-vs-send-vs-skip **decision** from the teloxide **IO**. - `reconcile(current, pages, markup) -> Vec<ViewOp>` — the prefix-stable rolling seal, now a pure free function over `&[String]`. - `plan_plain(current, text)` — the error-notice path, folded into the same `ViewOp` vocabulary. - `execute(&mut self, …)` — the sole teloxide-touching method; replays ops, records sent message IDs, and `debug_assert`s the `ids.len() == rendered.len()` invariant. - Thin `apply`/`apply_with_buttons`/`set_plain` wrappers preserve the caller-facing interface, so `deliver_streaming`/`render_final` are unchanged. ## Why The reconciliation logic — the most intricate code in the delivery path — was previously reachable only through a live Telegram API and had **no tests**. Moving the decision behind a pure function gives it the same table-testable surface `paginate` already enjoys. ## Tests 9 new table tests assert on `ViewOp` equality: the prefix-stable seal, changed-tail-only edits, markup-on-unchanged-last-page, markup-only-on-last-op, both `plan_plain` paths, and one **documenting** the preserved shrink-orphan quirk (a shrinking response leaves trailing messages untouched — behavior is preserved exactly, not fixed here). `execute` is intentionally left untested: its edit-vs-send branch is now 1:1 with the op variant. - `cargo test`: 113 passed, 0 failed - `cargo clippy --all-targets`: clean Behavior preserved exactly. One-line `CONTEXT.md` architecture note added; no new glossary term.
refactor(telegram): split MessageView into pure reconcile + executor
All checks were successful
CI / check (pull_request) Successful in 1m32s
PR Triage — label changes-requested reviews / triage-review (pull_request) Successful in 1s
110e551841
Move MessageView into a new telegram/view.rs and split its
edit-vs-send-vs-skip decision out of the teloxide IO. The rolling seal
(prefix-stable page reconciliation) is now a pure `reconcile(current,
pages, markup) -> Vec<ViewOp>` plus `plan_plain`; `execute` is the only
method that touches the Bot, replaying ops and recording sent IDs.

This makes the reconciliation logic — previously reachable only through a
live Telegram API — table-testable against ViewOp equality. Behavior is
preserved exactly, including leaving trailing messages orphaned when a
response shrinks (documented by a test).
weiwen merged commit bcae930d78 into main 2026-07-06 21:34:23 +08:00
weiwen deleted branch refactor/message-view-reconcile-seam 2026-07-06 21:34:23 +08:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
weiwen/evie!49
No description provided.