# tele-tui Refactor Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use `superpowers:subagent-driven-development` (recommended) or `superpowers:executing-plans` to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Finish the next review/refactor layer after the TDLib facade split, keeping behavior stable while making the code easier to test, review, and change. **Architecture:** The current working tree already introduces scoped TDLib traits, removes the local `build.rs`, switches message formatting to the system local timezone, moves media chat handlers into a submodule, and makes fake TDLib state more explicit. The remaining work should continue in small vertical slices with focused tests after each slice. **Tech Stack:** Rust 2021, Tokio, tdlib-rs, ratatui, crossterm, insta, criterion, Woodpecker CI. --- ## Current Baseline The current uncommitted layer should be treated as the baseline before starting the next refactor tasks. - TDLib facade is split into scoped traits in `src/tdlib/trait.rs`. - `src/tdlib/client_impl.rs` implements the scoped traits for `TdClient`. - `current_chat_messages()` returns `Cow<'_, [MessageInfo]>`; mutation goes through `update_current_chat_messages`. - Runtime date formatting uses the system local timezone; tests can inject deterministic time through `FixedLocalTime`. - Media/image/voice chat handling is moved from `src/input/handlers/chat.rs` into `src/input/handlers/chat/media.rs`. - The repository no longer uses the local `build.rs` that tried to link `tdlib-rs` during build-script execution. Verification already used for this baseline: ```bash cargo check --all-targets --all-features cargo clippy --all-targets --all-features -- -D warnings cargo test --all-features git diff --check ``` ## Task 0: Commit Current Layer Goal: preserve the completed facade/timezone/media/test-cleanup work before deeper refactors. Files to review before commit: - `CONTEXT.md` - `Cargo.toml` - `src/tdlib/trait.rs` - `src/tdlib/mod.rs` - `src/tdlib/client_impl.rs` - `src/utils/formatting.rs` - `src/input/handlers/chat.rs` - `src/input/handlers/chat/media.rs` - `tests/helpers/fake_tdclient.rs` - `tests/helpers/fake_tdclient_impl.rs` - touched tests and benches Steps: - [x] Review `git diff --stat` and `git diff --check`. - [x] Run the full verification commands from the baseline section. - [x] Commit this layer separately from the follow-up refactors. ## Task 1: Split `FakeTdClient` Goal: reduce `tests/helpers/fake_tdclient.rs` from one large mixed helper into smaller modules with clear responsibilities. Target files: - `tests/helpers/fake_tdclient.rs` - `tests/helpers/fake_tdclient_impl.rs` - `tests/helpers/mod.rs` - new `tests/helpers/fake_tdclient/state.rs` - new `tests/helpers/fake_tdclient/builders.rs` - new `tests/helpers/fake_tdclient/operations.rs` - new `tests/helpers/fake_tdclient/inspect.rs` Steps: - [x] Move state aliases and shared storage fields into `state.rs`. - [x] Move fixture construction helpers such as `with_chat`, `with_messages`, and account setup helpers into `builders.rs`. - [x] Move behavior helpers such as send/edit/delete/reaction operations into `operations.rs`. - [x] Move read/assertion helpers such as sent-message inspection and viewed-message inspection into `inspect.rs`. - [x] Keep the public test API stable unless a call site becomes simpler and safer. - [x] Remove direct test access to internal `Arc>` fields where helper methods are clearer. - [x] Run `cargo test --all-features`. Acceptance criteria: - `FakeTdClient` remains easy to construct in integration tests. - No test loses behavior coverage. - `tests/helpers/fake_tdclient.rs` becomes a small module entry point instead of the main implementation body. ## Task 2: Tighten Internal TDLib Mutation API Goal: limit raw mutable access to TDLib client internals and replace cross-module state poking with domain-specific methods. Target files: - `src/tdlib/client.rs` - `src/tdlib/chat_helpers.rs` - `src/tdlib/update_handlers.rs` - `src/tdlib/message_converter.rs` - `src/tdlib/client_impl.rs` Search command: ```bash rg -n "current_chat_messages_mut|chats_mut|folders_mut|pending_user_ids_mut|user_cache_mut" src/tdlib ``` Steps: - [x] Add focused methods on `TdClient` for common mutations: update chat, update message by id, queue pending user, update user cache, update folders. - [x] Replace raw `*_mut()` usage in helper/update modules with those methods. - [x] Keep raw mutable access private to `TdClient` implementation where it is still needed. - [x] Add or update tests around message updates, user-cache updates, and chat-list updates. - [x] Run `cargo test --all-features`. Acceptance criteria: - External and helper modules express intent through domain methods. - Raw state access is either gone or contained in a small internal area. ## Task 3: Split Remaining Large Input and UI Files Goal: make modal, message rendering, and app/input code easier to review independently. Target files: - `src/input/handlers/modal.rs` - `src/input/handlers/chat.rs` - `src/app/mod.rs` - `src/ui/messages.rs` - new `src/input/handlers/modal/account.rs` - new `src/input/handlers/modal/delete.rs` - new `src/input/handlers/modal/profile.rs` - new `src/input/handlers/modal/reactions.rs` - new `src/input/handlers/modal/pinned.rs` - new `src/ui/messages/header.rs` - new `src/ui/messages/list.rs` - new `src/ui/messages/pinned.rs` Steps: - [x] Split modal handlers by modal type and keep `modal.rs` as the dispatcher/module entry point. - [x] Split message UI rendering into header, pinned-message, and list rendering modules. - [x] Keep public function names stable until each split is covered by tests. - [x] Avoid mixing behavior changes with file movement. - [x] Run focused modal/navigation/message tests after each split. - [x] Run `cargo test --all-features` after the full split. Acceptance criteria: - Large files are reduced to dispatch/orchestration roles. - The split does not change key handling or rendering behavior. - Module names match user-facing concepts instead of implementation accidents. ## Task 4: Remove Production `unwrap()` Risk Goal: keep test unwraps where useful, but remove production unwraps where runtime data can be absent. Target files: - `src/input/handlers/chat/media.rs` - `src/input/handlers/chat.rs` - `src/ui/components/message_bubble.rs` - `src/utils/tdlib.rs` - `src/audio/player.rs` Search command: ```bash rg -n "unwrap\\(|expect\\(|panic!\\(" src ``` Steps: - [x] Replace `photo_info().unwrap()` and `voice_info().unwrap()` with `let Some(...) else { ... }`. - [x] Replace `selected_chat_id.unwrap()` with an early return or status message. - [x] Review playback/message unwraps in `message_bubble.rs` and convert absent data into graceful UI fallback. - [x] Audit mutex unwraps separately; leave only cases where poisoning should be fatal and documented by context. - [x] Add tests for missing media metadata and absent selected chat. - [x] Run `cargo clippy --all-targets --all-features -- -D warnings`. Acceptance criteria: - Malformed or partial TDLib data does not panic in normal UI paths. - Error handling stays local and does not add noisy user-facing text. ## Task 5: Resolve TODO and Compatibility Paths Goal: make unfinished behavior explicit: either implement it, test it, or remove stale comments. Target files: - `src/input/key_handler.rs` - `src/tdlib/reactions.rs` - `src/tdlib/messages/operations.rs` Steps: - [x] Review every TODO in `src/`. - [x] Convert active TODOs into tests or tracked plan items. - [x] Remove stale TODOs whose behavior is already implemented. - [x] For pinned-message compatibility in `messages/operations.rs`, decide whether the fallback is still needed and document the decision in code or tests. - [x] Run `cargo test --all-features`. Acceptance criteria: - Remaining TODOs point to real unresolved behavior. - No stale TODO describes behavior that no longer exists. ## Task 6: Add CI Quality Gate Goal: make local quality checks reproducible in CI. Target files: - `.woodpecker/check.yml` - `DEVELOPMENT.md` - `AGENT.md` Steps: - [x] Add CI steps for `cargo check --all-targets --all-features`. - [x] Add CI steps for `cargo clippy --all-targets --all-features -- -D warnings`. - [x] Add CI steps for `cargo test --all-features`. - [x] Document the same commands in `DEVELOPMENT.md` or `AGENT.md`. - [x] Keep CI commands aligned with the commands used by agents and humans locally. Acceptance criteria: - CI catches compile, lint, and test failures before merge. - Local documentation and CI use the same command set. ## Global Acceptance Criteria Before considering the refactor layer complete: - [x] `cargo check --all-targets --all-features` passes. - [x] `cargo clippy --all-targets --all-features -- -D warnings` passes. - [x] `cargo test --all-features` passes. - [x] `git diff --check` passes. - [x] No unexpected `*.snap.new` files remain. - [x] `rg -n "current_chat_messages_mut|chats_mut|folders_mut|pending_user_ids_mut|user_cache_mut" src/tdlib` shows only intentionally contained internal access. - [x] `rg -n "unwrap\\(|expect\\(|panic!\\(" src` has no risky production UI or TDLib data-path panics left. ## Recommended Commit Order 1. Baseline commit for already completed facade/timezone/media/test cleanup. 2. `FakeTdClient` split. 3. TDLib internal mutation API cleanup. 4. Modal and message UI file splits. 5. Production unwrap cleanup. 6. TODO cleanup. 7. CI quality gate.