Skip to content

Investigate Unicode normalization in command routing #147

Description

@iriswolf

Problem

A user reports that a Cyrillic command containing ё is matched for some Telegram users and not for others. The report is not reproducible yet.

The current dispatcher compares command tokens with StringComparison.Ordinal or StringComparison.OrdinalIgnoreCase; it does not apply Unicode normalization first. That can distinguish a composed ё (U+0451) from a canonically equivalent decomposed sequence (е + U+0308). It must not be assumed that affected users actually send this sequence: they may instead be entering the distinct letter е.

Why This Needs Investigation Before Design

ё versus decomposed е + diaeresis is a Unicode representation issue. е versus ё is a product-level aliasing decision. A global replacement or normalization of incoming message text would be unsafe: it could alter raw handler input, template route values, and regex captures.

Investigation Plan

  1. Capture the exact Message.Text code points from one matching and one non-matching update. Record the Telegram update type and the route declaration, but do not publish user text or personal data.
  2. Add a deterministic regression test for the observed representation through the generated registration path and direct handler registration path.
  3. Confirm whether the mismatch is:
    • composed versus decomposed canonical Unicode;
    • plain е versus ё spelling;
    • a routing-boundary issue unrelated to Unicode normalization.
  4. Verify the behavior for Command, CommandTemplate, and CommandRegex separately. Regex capture values must be treated as a distinct contract.
  5. Only after the observed case is classified, write and review the implementation design.

Design Constraints After Reproduction

  • Preserve the raw ctx.Message.Text exposed to handlers.
  • Do not globally replace е with ё or the reverse.
  • If canonical normalization is justified, scope it to the smallest safe command-matching boundary and use NormalizationForm.FormC consistently for both route literals and compared command input.
  • Do not silently normalize regex captures or arbitrary text routes without an explicit, tested contract.
  • Keep user-facing spelling aliases explicit, for example separate [Command("работенка")] and [Command("работёнка")] routes when a bot chooses to support both.

Code Pointers

  • src/TeleFlow.Framework/Internal/Handlers/TelegramHandlerSelector.cs:321-339 chooses the command route matching path.
  • src/TeleFlow.Framework/Internal/Handlers/TelegramHandlerSelector.cs:404-474 extracts the prefixed or prefix-less command body.
  • src/TeleFlow.Framework/Internal/Handlers/TelegramHandlerSelector.cs:500-524 compares exact command tokens with ordinal comparers.
  • src/TeleFlow.Framework/Internal/Handlers/TelegramHandlerSelector.cs:543-575 passes command templates and regex routes to the pattern matcher.
  • tests/TeleFlow.ArchitectureTests/TelegramHandlerDispatcherTests.cs:823-870 covers command-template dispatch and prefix-less regressions; extend it with the verified Unicode case.

Acceptance Criteria

  • A deterministic test demonstrates the actual reported representation mismatch, or the report is classified as a bot-level aliasing/configuration issue.
  • The issue records the verified Unicode sequences and the affected route kinds without retaining user message content.
  • A reviewed design is added only after reproduction and explicitly states the behavior for exact commands, templates, regex, raw handler text, and aliases.
  • No implementation is merged under this issue before those conditions are met.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:frameworkHandler framework, dispatcher, filters, callbacks, and contextsbugSomething isn't workingpriority:p1High priority workstatus:readyReady for implementation or review

    Type

    No type

    Projects

    • Status
      Done

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions