Skip to content

Fix: DM flow swallowing /status (and other commands) - #47

Merged
rezhajulio merged 3 commits into
rezhajulio:mainfrom
TayoBus:fix/dm-swallows-status
Oct 8, 2026
Merged

rezhajulio merged 3 commits into
rezhajulio:mainfrom
TayoBus:fix/dm-swallows-status

Conversation

@TayoBus

@TayoBus TayoBus commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Problem

Sending /status in DM answered with the unrestriction-flow message ("Kamu tidak memiliki pembatasan dari bot ini…") instead of the status report.

Root cause

Both dm and status live in dispatch group 0, and dm registers first in MANIFEST_ORDER. Its check (is_private_chat and has_text) matched the /status DM before the status spec was ever evaluated — first-match-wins meant handle_dm ran and handle_status never did. /status was the only command affected (every other command plugin registers before dm).

Fix

The DM flow's check now excludes bot commands other than /start:

  • free-text DMs → DM flow (unchanged)
  • /start and /start <deep-link payload> → DM flow (unchanged; deep-link recovery depends on it)
  • /status, /trusted, and any other command → falls through to its own handler

This is order-independent, so future command plugins registered after dm won't hit the same trap.

Verification

  • New TestDmCommandCarveOut (5 tests) in tests/test_dispatch.py: /status and /trusted DMs reach their handlers, /start (plain + deep-link) and free text still reach the DM flow.
  • uv run pytest: 1284 passed; ruff check . clean; mypy src/bot/ tests/ clean.

/status (DM-only admin): render the operational summary as a native
rich message — per-group <table bordered striped> (Grup | Penegakan |
Captcha | Probation | Pending | Nonaktif, scoped to the caller's admin
groups) plus a key-value section (Uptime, Database, Refresh admin,
Auto-restrict). Any send_rich_message failure falls back to the
byte-identical Markdown message (verified empirically against the
pre-change output).

/trusted: drop the standalone User ID column — four columns forced
horizontal scrolling. The numeric ID is folded into the User cell as
name (@username)<br><code>id</code>, keeping it visible and copyable.
Markdown fallback untouched.

Dates: the /trusted Date column and the /status job timestamps now
render in WIB (Asia/Jakarta) instead of UTC, in both the rich output
and the Markdown fallback (shared display strings; new constants.WIB
single source of truth).

/check deliberately stays on Markdown: aiogram 3.31 has no
edit-to-rich equivalent, so its callback-query edit path could never
go rich and a rich-then-Markdown flip mid-flow would be worse than
consistent Markdown.
…operty

test_with_username_format asserts '(@' appears only via the username
suffix, but the name strategy allows punctuation, so Hypothesis can
generate name='(@' and fail the property through no fault of the code.
assume('(@' not in name) keeps the property's intent (username suffix
logic) while excluding the degenerate input. Pre-existing flake,
unrelated to the rich-text work.
The dm plugin registers before status in group 0, and its check
(private + text) matched /status DMs first, so handle_dm answered
with the unrestriction message and handle_status never ran
(first-match-wins).

The DM flow now owns free-text DMs and /start deep links only: its
check excludes any bot_command that isn't /start. /status (and any
future command registered after dm) falls through to its handler.
@rezhajulio
rezhajulio merged commit 060ac73 into rezhajulio:main Oct 8, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants