refactor(commands): standardize parameter conventions

This commit is contained in:
tiennm99 committed 2026-07-21 14:51:28 +07:00
1 parent a211b7f8b7
commit d2c3129d41
10 files changed
+329 -21

No files matched your search

+2 -5
View File
@@ -29,11 +29,8 @@ deleting commands, update all related surfaces:
- tests for registration, handlers, and command menu behavior - tests for registration, handlers, and command menu behavior
- README/docs when behavior changes are user-visible - README/docs when behavior changes are user-visible
Use lowercase, descriptive parameter names in command metadata and usage text. Follow `docs/command-parameter-conventions.md` for all command parameter
Include units or currencies when meaningful (for example, `<vnd_amount>`), use metadata and usage text. Keep metadata, usage errors, examples, and tests exact.
`[...]` for optional input, append `...` for remaining free text, and use
parentheses to document structured input (for example,
`<ratio(owned:new)>`). Keep metadata, usage errors, examples, and tests exact.
Telegram's native menu and `/help` show command syntax plus the summary without Telegram's native menu and `/help` show command syntax plus the summary without
example invocations. example invocations.
+3 -6
View File
@@ -33,12 +33,9 @@ description:
`/help` combines the full command syntax and summary on one line. Neither `/help` combines the full command syntax and summary on one line. Neither
discovery surface includes example invocations. discovery surface includes example invocations.
For future commands, use lowercase descriptive parameter names. Include units Future commands must follow the
or currencies when they affect meaning (`<vnd_amount>`, `<usd_to_spend>`), use [command parameter conventions](docs/command-parameter-conventions.md). Keep
square brackets for optional input (`[date]`), append `...` when an argument command metadata, handler usage text, tests, and documentation aligned.
accepts remaining text (`[target...]`), and describe structured input in
parentheses (`<ratio(owned:new)>`, `<options(comma-separated)>`). Keep command
metadata, handler usage text, tests, and this documentation aligned.
### Stock dividend commands ### Stock dividend commands
+2 -2
View File
@@ -67,7 +67,7 @@ func TestCommandDiscovery_AllPublicCommandsHaveSafeMetadata(t *testing.T) {
"gold_sell": "<luong>", "gold_sell": "<luong>",
"lol": "[date]", "lol": "[date]",
"loldle": "[champion]", "loldle": "[champion]",
"random": "<options(comma-separated)>", "random": "<option,...>",
"stats": "[users | user <username> | cmd <command_name>]", "stats": "[users | user <username> | cmd <command_name>]",
"stock_price": "<ticker>", "stock_price": "<ticker>",
"stock_topup": "<vnd_amount>", "stock_topup": "<vnd_amount>",
@@ -78,7 +78,7 @@ func TestCommandDiscovery_AllPublicCommandsHaveSafeMetadata(t *testing.T) {
"stock_dividend": "<vnd_per_share> <ratio(owned:new)> <ticker>", "stock_dividend": "<vnd_per_share> <ratio(owned:new)> <ticker>",
"trongtruonghop": "[target...]", "trongtruonghop": "[target...]",
"tth": "[target...]", "tth": "[target...]",
"wheelofnames": "<options(comma-separated)>", "wheelofnames": "<option,...>",
"wordle": "[word]", "wordle": "[word]",
} }
+72
View File
@@ -0,0 +1,72 @@
# Command Parameter Conventions
## Overview
Every Telegram command declares optional `Parameters` metadata. The bot reuses
that string in `/help` and Telegram's native command menu, so it must be short,
consistent, and understandable on a phone.
Treat `Parameters` as display syntax, not as a validation schema. Handlers
remain responsible for parsing and validation.
## Syntax
| Meaning | Format | Example |
|---|---|---|
| Required value | `<name>` | `<ticker>` |
| Required comma-separated values | `<name,...>` | `<option,...>` |
| Optional value | `[name]` | `[date]` |
| Optional remaining text | `[name...]` | `[target...]` |
| Alternatives in an optional group | `[literal | literal <name>]` | `[users | user <username>]` |
Use only constructs required by the command. Do not introduce a formal schema
language or extra punctuation without a user-facing need.
## Naming
- Use lowercase `snake_case`.
- Prefer one descriptive noun: `<ticker>`, `<quantity>`, `<champion>`.
- Include units or currencies when they prevent ambiguity: `<vnd_amount>`,
`<usd_to_spend>`.
- Do not add primitive types such as `<quantity:number>` or `<date:string>`.
- Keep literal subcommands bare: `users`, `user`, `cmd`.
- Put spaces around `|` in alternatives.
- Do not repeat format prose inside a placeholder.
- Show punctuation that users must type exactly when omitting it would be
error-prone. `<ratio(owned:new)>` and `<option,...>` are approved compact
shapes.
## Examples
```text
/stock_buy <quantity> <ticker>
/lol [date]
/trongtruonghop [target...]
/stats [users | user <username> | cmd <command_name>]
/stock_share_dividend <ratio(owned:new)> <ticker>
/random <option,...>
```
## Change Checklist
When adding or changing a command:
1. Make `Parameters` match the handler's accepted argument order.
2. Keep the parameter string single-line and concise enough for Telegram's
command-description limit.
3. Update handler usage and error text to use the same syntax.
4. Update registration, handler, `/help`, and native-menu tests.
5. Update README or feature documentation when behavior is user-visible.
6. Follow the stats migration rules in `AGENTS.md` when a command name changes
or a command is deleted.
## References
- [POSIX.1-2024 utility conventions](https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap12.html)
- [GNU command-line interface standards](https://www.gnu.org/prep/standards/html_node/Command_002dLine-Interfaces.html)
- [Microsoft command-line syntax key](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/command-line-syntax-key)
- [Python argparse documentation](https://docs.python.org/3/library/argparse.html)
- [docopt usage-pattern grammar](https://github.com/docopt/docopt/blob/master/README.rst)
The supporting project-specific analysis is in
[`plans/reports/260721-1418-command-parameter-schema-research.md`](../plans/reports/260721-1418-command-parameter-schema-research.md).
@@ -1,5 +1,10 @@
# Telegram Command Discovery Journal # Telegram Command Discovery Journal
> Historical note: the later command-parameter convention simplifies
> `<options(comma-separated)>` to `<option,...>`, keeping the literal delimiter
> visible without prose inside the placeholder. See
> `docs/command-parameter-conventions.md`.
## Context ## Context
Telegram's native command menu and `/help` exposed only short descriptions, Telegram's native command menu and `/help` exposed only short descriptions,
@@ -0,0 +1,44 @@
# Command Parameter Conventions Journal
## Context
Command parameter labels had grown organically, especially for comma-separated
arguments. Researched common CLI notation to establish a minimal display syntax
for Telegram's native menu, `/help`, and handler usage text.
## What Changed
- Added the evergreen `docs/command-parameter-conventions.md` reference with
concise rules for required, optional, variadic, alternative, and structured
parameters.
- Recorded the user-selected `<option,...>` notation for required
comma-separated values.
- Updated `/random` and `/wheelofnames` metadata, usage text, and contract tests
from `<options(comma-separated)>` to `<option,...>`.
- Linked project guidance and README command-discovery documentation to the
shared convention reference.
## Reflection
The compact notation communicates both one-or-more values and the literal comma
separator without turning display metadata into a schema language. Keeping the
rules in an evergreen document avoids repeating policy in project instructions
and feature docs.
## Decisions
- Parameter strings remain presentation-only; handlers own validation.
- `/random` and `/wheelofnames` parsing and runtime behavior remain unchanged.
- Metadata, usage errors, and tests must use the same exact notation.
## Verification
- Passed: focused command-presentation and misc tests.
- Passed: `go test ./...`
- Passed: `go vet ./...`
- Passed: `go build ./...`
- Passed: `golangci-lint run`
## Next Steps
- Apply the evergreen conventions whenever command parameters change.
@@ -26,14 +26,14 @@ func TestCommandPresentation(t *testing.T) {
menu: "Health check!", menu: "Health check!",
}, },
{ {
name: "variadic parameters keep ellipsis", name: "concise parameter name",
command: Command{ command: Command{
Name: "random", Name: "random",
Parameters: "<options(comma-separated)>", Parameters: "<option,...>",
Description: "Pick one option", Description: "Pick one option",
}, },
invocation: "/random <options(comma-separated)>", invocation: "/random <option,...>",
menu: "<options(comma-separated)>. Pick one option.", menu: "<option,...>. Pick one option.",
}, },
} }
+2 -2
View File
@@ -12,7 +12,7 @@ import (
"github.com/tiennm99/miti99bot/internal/modules/util/chathelper" "github.com/tiennm99/miti99bot/internal/modules/util/chathelper"
) )
const randomUsage = "Usage: /random <options(comma-separated)>" const randomUsage = "Usage: /random <option,...>"
func splitWheelOptions(arg string) []string { func splitWheelOptions(arg string) []string {
parts := strings.Split(arg, ",") parts := strings.Split(arg, ",")
@@ -30,7 +30,7 @@ func randomCommand() modules.Command {
Name: "random", Name: "random",
Visibility: modules.VisibilityPublic, Visibility: modules.VisibilityPublic,
Description: "Pick one random comma-separated option", Description: "Pick one random comma-separated option",
Parameters: "<options(comma-separated)>", Parameters: "<option,...>",
Handler: func(ctx context.Context, b *bot.Bot, update *models.Update) error { Handler: func(ctx context.Context, b *bot.Bot, update *models.Update) error {
if update.Message == nil { if update.Message == nil {
return nil return nil
@@ -24,7 +24,7 @@ func wheelOfNamesCommand() modules.Command {
Name: "wheelofnames", Name: "wheelofnames",
Visibility: modules.VisibilityPublic, Visibility: modules.VisibilityPublic,
Description: "Pick one comma-separated option with wheel GIF when configured", Description: "Pick one comma-separated option with wheel GIF when configured",
Parameters: "<options(comma-separated)>", Parameters: "<option,...>",
Handler: func(ctx context.Context, b *bot.Bot, update *models.Update) error { Handler: func(ctx context.Context, b *bot.Bot, update *models.Update) error {
if update.Message == nil { if update.Message == nil {
return nil return nil
@@ -63,7 +63,7 @@ func wheelOfNamesCommand() modules.Command {
} }
} }
const wheelUsage = "Usage: /wheelofnames <options(comma-separated)>" const wheelUsage = "Usage: /wheelofnames <option,...>"
func wheelResultCaption(result string) string { func wheelResultCaption(result string) string {
result = truncateWheelResultCaption(result) result = truncateWheelResultCaption(result)
@@ -0,0 +1,193 @@
---
type: research-report
conducted_at: 2026-07-21T14:18:00+07:00
scope: Telegram command discovery syntax
status: complete
---
# Research Report: Minimal Command Parameter Schema
## Summary
Keep the project's current lightweight schema. It already matches familiar CLI
synopsis conventions closely enough:
```text
<name> required value
[name] optional value
[name...] optional remaining text
a | b alternatives inside one optional group
```
Do not add types such as `<quantity:number>`. Common CLI usage lines describe
structure, not a type system. Use a descriptive name (`<quantity>`,
`<vnd_amount>`) and put validation details in the summary or usage error.
Only one current notation is needlessly heavy. After project-owner review, the
approved compact replacement is:
```text
<options(comma-separated)> -> <option,...>
```
This keeps the literal comma visible without putting prose inside the
placeholder. Keep `<ratio(owned:new)>` for the same reason: the separator is
essential input syntax and the concise shape prevents a likely user error.
## Contents
- [Scope and method](#scope-and-method)
- [Evidence](#evidence)
- [Recommended schema](#recommended-schema)
- [Current command audit](#current-command-audit)
- [Rejected alternatives](#rejected-alternatives)
- [Next steps](#next-steps)
- [References](#references)
- [Unresolved questions](#unresolved-questions)
## Scope and Method
Evaluated only the syntax displayed after `/command` in Telegram's native menu
and `/help`. Criteria, in order:
1. Understandable without a legend
2. Minimal visual noise on a phone
3. Accurate to the parser
4. Consistent across commands
5. Familiar to terminal users
Sources span POSIX.1-2024, current GNU guidance, Python 3.14 documentation,
Microsoft's command-line syntax key, docopt's usage grammar, and Telegram's
current Bot API. The configured Gemini path was disabled. Web search returned
an authorization error, so primary sources were retrieved directly over HTTPS.
## Evidence
### Strong consensus
- Square brackets mean optional material. POSIX, Microsoft, argparse, and
docopt all use this convention.
- Angle brackets are a recognized way to mark a value the user must replace.
POSIX explicitly permits `<parameter name>`; Microsoft defines angle-bracket
text as a placeholder.
- A vertical bar separates mutually exclusive alternatives. Microsoft and
docopt explicitly document this.
- An ellipsis indicates repetition. POSIX uses `[operand ...]`; docopt uses
`FILE ...` for one or more and `[FILE ...]` for zero or more.
- Metavariable names should explain the role of the value. Python argparse uses
`metavar` for this purpose and generates the structural punctuation itself.
### Important nuance
Traditional terminal help often uses uppercase metavariables such as `FILE` or
`FOO`. Lowercase angle-bracket names such as `<ticker>` remain unambiguous and
are calmer in Telegram's compact UI. Changing case would add churn without
improving comprehension.
POSIX's spaced ellipsis (`operand ...`) means repeated operands. This bot's
`[target...]` means one optional free-text remainder. That is a small local
extension, but it communicates the behavior better than `[target]`, which can
look limited to one word. Document it once and keep it consistent.
## Recommended Schema
Use only constructs the project currently needs:
| Meaning | Format | Example |
|---|---|---|
| Required value | `<name>` | `<ticker>` |
| Required comma-separated values | `<name,...>` | `<option,...>` |
| Optional value | `[name]` | `[date]` |
| Optional remaining text | `[name...]` | `[target...]` |
| Optional alternatives | `[literal | literal <name>]` | `[users | user <username>]` |
Naming rules:
- Lowercase `snake_case`.
- Prefer one plain noun: `<ticker>`, `<quantity>`, `<champion>`.
- Include a unit when it prevents ambiguity: `<vnd_amount>`, `<usd_to_spend>`.
- Do not encode primitive types: avoid `<quantity:number>` and `<date:string>`.
- Do not put format prose inside a placeholder.
- Include a compact value shape only when users must type its punctuation
exactly: `<ratio(owned:new)>`, `<option,...>`.
- Keep literal subcommands bare: `users`, `user`, `cmd`.
- Put spaces around `|`; readability is worth the two characters.
This is presentation metadata, not a machine-validated schema language. Avoid
adding an AST, parser, enums, or type annotations until the bot needs generated
validation or completion.
## Current Command Audit
| Commands | Current | Recommendation | Reason |
|---|---|---|---|
| `/random`, `/wheelofnames` | `<options(comma-separated)>` | `<option,...>` | Shows the literal delimiter without prose. |
| `/stats` | `[users | user <username> | cmd <command_name>]` | Keep | Accurate compact grammar; `command_name` avoids confusing the value with a literal command. |
| `/trongtruonghop`, `/tth` | `[target...]` | Keep | Clearly signals optional multi-word remainder. |
| `/lol` | `[date]` | Keep | Minimal; accepted date shapes belong in the summary/error. |
| `/loldle`, `/wordle` | `[champion]`, `[word]` | Keep | Optional value accurately reflects start-without-argument behavior. |
| Coin commands | `<coin>`, `<usd_amount>`, `<coin> <usd_to_spend>`, `<coin> <usd_to_receive>` | Keep | Names expose currency and transaction intent without type noise. |
| Gold commands | `<vnd_amount>`, `<luong>` | Keep | Units are essential and concise. |
| Stock price/trade commands | `<ticker>`, `<vnd_amount>`, `<quantity> <ticker>` | Keep | Conventional positional metavariables. |
| Stock dividend commands | `<vnd_per_share>`, `<ratio(owned:new)>`, `<ticker>` combinations | Keep | The ratio shape is valuable syntax, not redundant prose. |
Result: change two registrations and their matching usage/tests; leave every
other public parameter string unchanged.
## Rejected Alternatives
### Uppercase metavariables
```text
<TICKER> <QUANTITY>
```
Familiar in man pages, but redundant when angle brackets already mark values.
It is visually louder and would touch every command for no behavior gain.
### Inline type annotations
```text
<quantity:number> <ticker:string>
```
Not a common shell synopsis convention. Longer, falsely formal, and still
cannot express real constraints such as positive integers or known tickers.
### Generic names everywhere
```text
<amount> <value> <input>
```
Short but ambiguous. Minimalism should remove redundancy, not meaning.
### Full docopt grammar
Docopt can represent required groups, nested alternatives, and repetition
precisely. The bot does not need that complexity. Adopt only its familiar
surface notation when a real command requires it.
## Next Steps
1. Change `/random` and `/wheelofnames` parameter metadata to `<option,...>`.
2. Change their handler usage strings and exact-string tests at the same time.
3. Update README/AGENTS guidance: value format belongs in the summary or usage
error unless punctuation is essential, as with `<ratio(owned:new)>`.
4. Keep current registration validation: non-empty descriptions, single-line
parameters, and Telegram's length limit.
5. Do not build a schema parser.
## References
- [POSIX.1-2024, Utility Conventions](https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap12.html)
- [GNU Standards, Command-Line Interfaces](https://www.gnu.org/prep/standards/html_node/Command_002dLine-Interfaces.html)
- [Microsoft command-line syntax key](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/command-line-syntax-key)
- [Python 3 argparse documentation](https://docs.python.org/3/library/argparse.html)
- [docopt usage-pattern grammar](https://github.com/docopt/docopt/blob/master/README.rst)
- [Telegram Bot API](https://core.telegram.org/bots/api#botcommand)
## Unresolved Questions
None. The recommendation is intentionally small and implementable without
changing command parsing or persisted data.