9.4 KiB
tele-tui Refactor Plan
For agentic workers: REQUIRED SUB-SKILL: Use
superpowers:subagent-driven-development(recommended) orsuperpowers:executing-plansto 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.rsimplements the scoped traits forTdClient.current_chat_messages()returnsCow<'_, [MessageInfo]>; mutation goes throughupdate_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.rsintosrc/input/handlers/chat/media.rs. - The repository no longer uses the local
build.rsthat tried to linktdlib-rsduring build-script execution.
Verification already used for this baseline:
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.mdCargo.tomlsrc/tdlib/trait.rssrc/tdlib/mod.rssrc/tdlib/client_impl.rssrc/utils/formatting.rssrc/input/handlers/chat.rssrc/input/handlers/chat/media.rstests/helpers/fake_tdclient.rstests/helpers/fake_tdclient_impl.rs- touched tests and benches
Steps:
- Review
git diff --statandgit diff --check. - Run the full verification commands from the baseline section.
- 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.rstests/helpers/fake_tdclient_impl.rstests/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:
- Move state aliases and shared storage fields into
state.rs. - Move fixture construction helpers such as
with_chat,with_messages, and account setup helpers intobuilders.rs. - Move behavior helpers such as send/edit/delete/reaction operations into
operations.rs. - Move read/assertion helpers such as sent-message inspection and viewed-message inspection into
inspect.rs. - Keep the public test API stable unless a call site becomes simpler and safer.
- Remove direct test access to internal
Arc<Mutex<...>>fields where helper methods are clearer. - Run
cargo test --all-features.
Acceptance criteria:
FakeTdClientremains easy to construct in integration tests.- No test loses behavior coverage.
tests/helpers/fake_tdclient.rsbecomes 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.rssrc/tdlib/chat_helpers.rssrc/tdlib/update_handlers.rssrc/tdlib/message_converter.rssrc/tdlib/client_impl.rs
Search command:
rg -n "current_chat_messages_mut|chats_mut|folders_mut|pending_user_ids_mut|user_cache_mut" src/tdlib
Steps:
- Add focused methods on
TdClientfor common mutations: update chat, update message by id, queue pending user, update user cache, update folders. - Replace raw
*_mut()usage in helper/update modules with those methods. - Keep raw mutable access private to
TdClientimplementation where it is still needed. - Add or update tests around message updates, user-cache updates, and chat-list updates.
- 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.rssrc/input/handlers/chat.rssrc/app/mod.rssrc/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:
- Split modal handlers by modal type and keep
modal.rsas the dispatcher/module entry point. - Split message UI rendering into header, pinned-message, and list rendering modules.
- Keep public function names stable until each split is covered by tests.
- Avoid mixing behavior changes with file movement.
- Run focused modal/navigation/message tests after each split.
- Run
cargo test --all-featuresafter 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.rssrc/input/handlers/chat.rssrc/ui/components/message_bubble.rssrc/utils/tdlib.rssrc/audio/player.rs
Search command:
rg -n "unwrap\\(|expect\\(|panic!\\(" src
Steps:
- Replace
photo_info().unwrap()andvoice_info().unwrap()withlet Some(...) else { ... }. - Replace
selected_chat_id.unwrap()with an early return or status message. - Review playback/message unwraps in
message_bubble.rsand convert absent data into graceful UI fallback. - Audit mutex unwraps separately; leave only cases where poisoning should be fatal and documented by context.
- Add tests for missing media metadata and absent selected chat.
- 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.rssrc/tdlib/reactions.rssrc/tdlib/messages/operations.rs
Steps:
- Review every TODO in
src/. - Convert active TODOs into tests or tracked plan items.
- Remove stale TODOs whose behavior is already implemented.
- For pinned-message compatibility in
messages/operations.rs, decide whether the fallback is still needed and document the decision in code or tests. - 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.ymlDEVELOPMENT.mdAGENT.md
Steps:
- Add CI steps for
cargo check --all-targets --all-features. - Add CI steps for
cargo clippy --all-targets --all-features -- -D warnings. - Add CI steps for
cargo test --all-features. - Document the same commands in
DEVELOPMENT.mdorAGENT.md. - 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:
cargo check --all-targets --all-featurespasses.cargo clippy --all-targets --all-features -- -D warningspasses.cargo test --all-featurespasses.git diff --checkpasses.- No unexpected
*.snap.newfiles remain. rg -n "current_chat_messages_mut|chats_mut|folders_mut|pending_user_ids_mut|user_cache_mut" src/tdlibshows only intentionally contained internal access.rg -n "unwrap\\(|expect\\(|panic!\\(" srchas no risky production UI or TDLib data-path panics left.
Recommended Commit Order
- Baseline commit for already completed facade/timezone/media/test cleanup.
FakeTdClientsplit.- TDLib internal mutation API cleanup.
- Modal and message UI file splits.
- Production unwrap cleanup.
- TODO cleanup.
- CI quality gate.