# Telegram UX Archive Control adds a separate handler/module to the existing bot. Existing commands and conversations retain their current behavior. ## Authorization and shared state The handler accepts private-chat users through the existing `@username` allowlist for compatibility. A configured numeric Telegram user ID may pin an entry; when pinned, both the ID and current allowlist rule must match. This mitigates username reassignment while permitting a staged migration. Jobs, placements, events, queues, and routes are shared administrative state and store no initiating-user identity. UI session state records only what is needed to resume the conversation/view and expires after 24 hours by default. ## Entry point and navigation The existing “Archive/Unarchive Resources” entry opens one message: ```text What do you want to do? [ Archive ] [ Unarchive ] [ Evict Cache ] [ Job Status ] ``` All subsequent pages edit this message. `Cancel` closes the active selection flow. `Back` returns one level while retaining validated filters/selections. Callback payloads contain opaque session/action IDs, not resource names or paths, and are validated against persisted session revision and expiry. ## Archive and unarchive flow ### 1. Select source resource Control queries relevant online nodes on demand. It groups identical resource and selection replicas into one display choice while showing distinct selections separately. The list is stable-sorted and paged: ```text Which cached resource do you want to archive? (page 1/3) filters: `documentary`, `2025` 1. `10.0 GB` Resource A — cache-1 2. `840 MB` Resource B — cache-2 [ 1 ] [ 2 ] [ Prev ] [ Next ] [ Remove filters ] [ Cancel ] ``` Size is selected-complete logical content, not total torrent size. New messages add literal, case-insensitive filters and narrow the current results; Remove filters resets the chain. If no item remains, the message explains whether no source is online, no selected-complete data exists, or filters eliminated all results. ### 2. Select source replica and target If multiple identical-selection replicas exist, control may choose a healthy source automatically using deterministic availability/route/free-space rules; otherwise it lists the source replicas. One eligible target is selected automatically; multiple targets are paged. Offline targets are not offered. A resource already on a target is still eligible when the requested selection has an unverified delta. The UI says that it will extend an existing placement. ### 3. Confirm or choose one entry Before showing confirmation, control obtains fresh full trees from source and target and calculates the transfer delta. ```text Archive Resource A from cache-1 to archive-2? Requested: 7 files, 10.0 GB Already verified there: 2 files, 3.1 GB Will transfer: 5 files, 6.9 GB [ Confirm ] [ Choose one entry… ] [ Cancel ] ``` Choose one entry opens a paged/filterable tree. Only source-selected-complete files/directories are enabled. Selecting a directory expands it to descendant file indices, returns to a freshly recomputed confirmation, and clearly states the chosen subtree. The protocol supports multiple entries from v1, but the initial UI exposes one. Confirmation uses a persisted, single-use nonce bound to session revision, operation, resource, source, target, selection, fingerprints, and placement generation. Double taps or stale callbacks cannot create a second job. ## Evict Cache flow The first page lists current cache placements. Selecting one triggers fresh queries to the cache and relevant online archive nodes. Each row/confirmation shows coverage: - enabled when the union of verified archives covers every selected cache file; - disabled with missing file count/size and unavailable archive explanation otherwise. There is no override button. Confirmation creates a durable three-step eviction job; it never clears an archive placement or a transfer history row. ## Job Status Status pages show live and retained jobs with operation, resource, endpoints, state, current-step and overall percentages, bytes/s where meaningful, and failure reason. Routine edits are coalesced to one per five seconds by default. Step changes, stall transitions, failures, commit, cleanup-required, and terminal states edit immediately subject to Telegram rate-limit backoff. State symbols: | Symbol | Meaning | | --- | --- | | 🟡 | queued/not started | | 🔵 | active, waiting, or stalled | | 🟠 | committed but cleanup required | | 🟢 | succeeded | | 🔴 | failed or cancelled | Transfer jobs display five numbered steps: Source Stage/HardLink, Syncthing, Target Merge/Copy, QB Verification, and Staging Cleanup. Route setup and preflight are named, unnumbered pre-steps. Eviction displays Verify Archive Coverage, QB Remove Entry, and Safe File Unlink. A stalled job keeps its last overall percentage: ```text 🔵 Archive: Resource A — cache-1 → archive-2 [2/5 Syncthing: 63.42%, overall 32.68%, stalled, last progress 38m ago] Waiting indefinitely; retry occurs when progress/service connectivity returns. ``` Failure messages include stable phase and clear reason, while hiding secrets and host-only paths. ## Clear and remove behavior `Clear Finished` hides only green successful jobs and leaves a 30-day default tombstone. Orange Cleanup Required is not clearable as finished. `Remove One` first replaces buttons with current-page job numbers and Cancel. A successful green row hides immediately. A queued job confirmation deletes only its queue record/reservation. An active, failed-with-residue, or cancelling job requires a second confirmation and begins/continues compensation; its row remains until safe cleanup is known. A committed job can only retry staging cleanup. No history action deletes a cache placement; that is exclusively Evict Cache. ## Restart and rate-limit behavior Sessions, pages, filters, chosen entries, confirmation bindings, and live status views are persisted. On bot restart, active status messages resume updates when the stored chat/message remains editable; otherwise users can reopen Job Status without losing job state. “message is not modified” is treated as success. Telegram retry-after values pause/coalesce edits without affecting orchestration. ## Interactive test entry An opt-in `Archive Control (Test)` entry reuses this same handler with an independent callback namespace and SQLite database. Its scripted backend provides comprehensive, empty, and slow-route scenarios without contacting control/client daemons, qBittorrent, or Syncthing. The production entry, callback namespace, database, jobs, placements, and other bot features are unchanged. The test entry exposes administrator-only `/actest` controls to reset a scenario, move a synthetic job through displayed states, fail the next selected backend call, complete a slow route, inspect recent trace events, or export the complete JSONL trace. The trace contains callback and filter inputs, session state transitions, exact message/keyboard renders, backend results/errors, and job transitions, so a UI report can be reproduced without live storage nodes.