diff --git a/docs/journals/260703-0408-wheelofnames-command.md b/docs/journals/260703-0408-wheelofnames-command.md new file mode 100644 index 0000000..a6aed8d --- /dev/null +++ b/docs/journals/260703-0408-wheelofnames-command.md @@ -0,0 +1,31 @@ +# Wheelofnames Command Journal + +## Context + +Executed plan `plans/260703-0404-wheelofnames-misc-command/plan.md`. + +## What Changed + +- Added public `/wheelofnames` command to `misc`. +- Command parses comma-separated options, trims whitespace, ignores empty entries, and returns one random valid option. +- Updated command registration tests and handler tests. +- Updated `telegram-commands.json` and README command list. +- Synced plan phases to completed. + +## Decisions + +- Plain text reply only; no HTML parse mode needed. +- Non-cryptographic randomness acceptable for casual choice selection. +- Duplicate options preserved, allowing intentional weighting. +- No stats migration needed because command is additive. + +## Validation + +- `go test ./internal/modules/misc` +- `go test ./cmd/server ./internal/modules/misc` +- `go test ./...` +- `go vet ./...` + +## Unresolved Questions + +None. diff --git a/plans/260703-0404-wheelofnames-misc-command/phase-01-implement-command.md b/plans/260703-0404-wheelofnames-misc-command/phase-01-implement-command.md new file mode 100644 index 0000000..6d42833 --- /dev/null +++ b/plans/260703-0404-wheelofnames-misc-command/phase-01-implement-command.md @@ -0,0 +1,86 @@ +--- +phase: 1 +title: Implement command +status: completed +priority: P2 +dependencies: [] +--- + +# Phase 1: Implement command + +## Overview + +Add the `/wheelofnames` command inside `internal/modules/misc/misc.go`, using the current misc module pattern: small command factory returning `modules.Command`, `chathelper.ArgAfterCommand` for parsing, and `chathelper.Reply` for plain text response. + +## Requirements + +- Functional: parse text after `/wheelofnames` as comma-separated options. +- Functional: trim whitespace and drop empty options. +- Functional: reply usage when no valid options exist. +- Functional: randomly pick one option from valid entries; preserve duplicates as weighting. +- Non-functional: keep implementation local to misc; no storage dependency; no new module. + +## Architecture + +Flow: + +```text +Telegram update + -> dispatcher matches wheelofnames + -> wheelOfNamesCommand handler + -> chathelper.ArgAfterCommand + -> splitWheelOptions + -> math/rand/v2 rand.N(len(options)) + -> chathelper.Reply +``` + +Use a tiny pure helper for parsing: + +```go +func splitWheelOptions(arg string) []string { + parts := strings.Split(arg, ",") + out := make([]string, 0, len(parts)) + for _, part := range parts { + if s := strings.TrimSpace(part); s != "" { + out = append(out, s) + } + } + return out +} +``` + +No crypto-grade randomness required; this is a casual selection command, not auth, payment, or security behavior. + +## Related Code Files + +- Modify: `/config/workspace/tiennm99/miti99bot/internal/modules/misc/misc.go` +- Create: none +- Delete: none + +## Implementation Steps + +1. Add `math/rand/v2` import, unless existing Go version/toolchain rejects it; fallback to standard `math/rand` only if needed. +2. Update package comment to include `/wheelofnames`. +3. Add `wheelOfNamesUsage` constant, e.g. `Usage: /wheelofnames , , ...`. +4. Add `wheelOfNamesCommand()` returning public `modules.Command`. +5. Add command to `New()` after other public misc commands or near `/ping`. +6. Add `splitWheelOptions(arg string) []string` helper near the command. +7. Handler: + - return nil for nil message + - parse args with `chathelper.ArgAfterCommand(update.Message.Text)` + - reply usage if parsed options length is zero + - pick `options[rand.N(len(options))]` + - reply selected option as plain text + +## Success Criteria + +- [x] `misc.New` registers `wheelofnames` as public command. +- [x] Handler replies usage for missing/empty option list. +- [x] Handler never returns an empty option. +- [x] Handler uses plain text reply, preserving forum topic behavior through `chathelper.Reply`. + +## Risk Assessment + +Main risk: flaky tests if randomness is asserted too strictly. Mitigate by testing deterministic one-option input and set membership for multi-option input. + +Security: no HTML parse mode; user-supplied option text is plain text, so no HTML escaping needed. diff --git a/plans/260703-0404-wheelofnames-misc-command/phase-02-update-command-surfaces.md b/plans/260703-0404-wheelofnames-misc-command/phase-02-update-command-surfaces.md new file mode 100644 index 0000000..088ccf4 --- /dev/null +++ b/plans/260703-0404-wheelofnames-misc-command/phase-02-update-command-surfaces.md @@ -0,0 +1,54 @@ +--- +phase: 2 +title: Update command surfaces +status: completed +priority: P2 +dependencies: + - 1 +--- + +# Phase 2: Update command surfaces + +## Overview + +Update all user-facing command surfaces required by `AGENTS.md` for a new Telegram command. This is an additive command, so no stats migration is needed. + +## Requirements + +- Functional: command appears in `/help` because it is public and registered in the misc module. +- Functional: command appears in `telegram-commands.json` for Telegram command menu setup. +- Functional: README misc module summary reflects the new command. +- Non-functional: no command rename/delete, so preserve stats behavior by doing nothing special. + +## Architecture + +The source of runtime behavior is `internal/modules/misc/misc.go`. `telegram-commands.json` is a manual Telegram command menu source, and `README.md` is the human-facing module overview. + +Stats compatibility note: +- Adding `/wheelofnames` creates new command usage rows naturally when the stats hook records invocations. +- No existing stats rows need migration because no command is renamed or deleted. + +## Related Code Files + +- Modify: `/config/workspace/tiennm99/miti99bot/telegram-commands.json` +- Modify: `/config/workspace/tiennm99/miti99bot/README.md` +- Create: none +- Delete: none + +## Implementation Steps + +1. Add command entry to `telegram-commands.json` near other misc commands: + - `command`: `wheelofnames` + - `description`: concise public description, e.g. `Pick one random comma-separated option` +2. Update README Modules table for `misc` to include `/wheelofnames`. +3. Do not update stats migrations or system state; this is add-only behavior. + +## Success Criteria + +- [x] `telegram-commands.json` remains valid JSON. +- [x] README `misc` command list includes `/wheelofnames`. +- [x] No migration or legacy stats marker added. + +## Risk Assessment + +Risk: runtime registration and manual command menu source drift. Mitigate by updating both `misc.go` and `telegram-commands.json` in same implementation. diff --git a/plans/260703-0404-wheelofnames-misc-command/phase-03-validate-behavior.md b/plans/260703-0404-wheelofnames-misc-command/phase-03-validate-behavior.md new file mode 100644 index 0000000..a2cd48f --- /dev/null +++ b/plans/260703-0404-wheelofnames-misc-command/phase-03-validate-behavior.md @@ -0,0 +1,68 @@ +--- +phase: 3 +title: Validate behavior +status: completed +priority: P2 +dependencies: + - 1 + - 2 +--- + +# Phase 3: Validate behavior + +## Overview + +Add focused tests for the new handler and run command-surface validation required for command changes. + +## Requirements + +- Functional: tests cover registration, usage reply, one-option selection, trimming, and empty segment handling. +- Non-functional: run focused tests first, then full suite and vet because command/menu/shared behavior changed. + +## Architecture + +Use existing misc test harness: +- `installMisc` in `internal/modules/misc/handlers_test.go` wires the misc module to `testutil.RecordingBot`. +- `TestNew_RegistersExpectedCommands` in `internal/modules/misc/misc_test.go` locks command names and visibility. + +Avoid brittle randomness assertions: +- Single-option input should return that option exactly. +- Multi-option input should assert the reply is one of the non-empty trimmed options. + +## Related Code Files + +- Modify: `/config/workspace/tiennm99/miti99bot/internal/modules/misc/misc_test.go` +- Modify: `/config/workspace/tiennm99/miti99bot/internal/modules/misc/handlers_test.go` +- Create: none +- Delete: none + +## Implementation Steps + +1. Update `TestNew_RegistersExpectedCommands` expected map: + - add `wheelofnames: modules.VisibilityPublic` +2. Add handler tests: + - `/wheelofnames` returns usage. + - `/wheelofnames , ,` returns usage. + - `/wheelofnames Alice` returns `Alice`. + - `/wheelofnames Alice, Bob, Carol` returns one of those exact strings. + - `/wheelofnames , Alice , , Bob ,` returns `Alice` or `Bob`, never empty/spaced. +3. Run formatting and focused tests: + - `gofmt -w internal/modules/misc/misc.go internal/modules/misc/misc_test.go internal/modules/misc/handlers_test.go` + - `go test ./internal/modules/misc` +4. Run broader validation because command menu/user-facing contract changes: + - `go test ./cmd/server ./internal/modules/misc` + - `go test ./...` + - `go vet ./...` + +## Success Criteria + +- [x] Focused misc tests pass. +- [x] Command menu/server tests pass. +- [x] Full `go test ./...` passes. +- [x] Full `go vet ./...` passes. + +## Risk Assessment + +Risk: random selection makes tests nondeterministic. Mitigate by avoiding exact expected value for multi-option tests. + +Rollback: remove `wheelOfNamesCommand`, helper, tests, README entry, and `telegram-commands.json` entry. diff --git a/plans/260703-0404-wheelofnames-misc-command/plan.md b/plans/260703-0404-wheelofnames-misc-command/plan.md new file mode 100644 index 0000000..39d626f --- /dev/null +++ b/plans/260703-0404-wheelofnames-misc-command/plan.md @@ -0,0 +1,63 @@ +--- +title: Wheel of Names Misc Command +description: >- + Add public /wheelofnames command to pick one random comma-separated option in + the misc module. +status: completed +priority: P2 +branch: main +tags: + - feature + - backend +blockedBy: [] +blocks: [] +created: '2026-07-03T04:04:35.848Z' +createdBy: 'ck:plan' +source: skill +--- + +# Wheel of Names Misc Command + +## Overview + +Add `/wheelofnames` to the existing `misc` module. The command accepts comma-separated options after the command text, trims whitespace, ignores empty entries, then replies with one randomly selected option. No storage, migrations, auth changes, or new module needed. + +Assumptions: +- Public command, visible in `/help` and Telegram command menu. +- Usage reply when no valid comma-separated entries remain. +- One valid entry is allowed and returns that entry. +- Duplicate entries stay duplicated, so users can weight an option intentionally. + +## Phases + +| Phase | Name | Status | +|-------|------|--------| +| 1 | [Implement command](./phase-01-implement-command.md) | Completed | +| 2 | [Update command surfaces](./phase-02-update-command-surfaces.md) | Completed | +| 3 | [Validate behavior](./phase-03-validate-behavior.md) | Completed | + +## Cross-Plan Dependencies + +None. No unfinished project plans found under `plans/`. + +## Key Files + +| File | Action | +|------|--------| +| `internal/modules/misc/misc.go` | Add command registration, parser/helper, handler | +| `internal/modules/misc/misc_test.go` | Update registration expectations | +| `internal/modules/misc/handlers_test.go` | Add handler behavior tests | +| `telegram-commands.json` | Add public Telegram command menu entry | +| `README.md` | Update misc module command list | + +## Acceptance Criteria + +- `/wheelofnames a, b, c` replies with exactly one trimmed item from `a`, `b`, `c`. +- `/wheelofnames` and `/wheelofnames , ,` reply with usage text. +- Empty comma segments do not appear as choices. +- Command is public and included in module registration, `/help`, and `telegram-commands.json`. +- Focused tests pass, then full `go test ./...` and `go vet ./...` pass. + +## Unresolved Questions + +None. diff --git a/plans/260703-0404-wheelofnames-misc-command/reports/pm-260703-0408-wheelofnames-complete.md b/plans/260703-0404-wheelofnames-misc-command/reports/pm-260703-0408-wheelofnames-complete.md new file mode 100644 index 0000000..3cfe052 --- /dev/null +++ b/plans/260703-0404-wheelofnames-misc-command/reports/pm-260703-0408-wheelofnames-complete.md @@ -0,0 +1,34 @@ +# Plan Complete: Wheel of Names Misc Command + +## Summary + +| Field | Value | +|---|---| +| Plan | `plans/260703-0404-wheelofnames-misc-command/plan.md` | +| Status | completed | +| Phases | 3/3 | +| Files changed | 5 implementation/docs files + plan files | +| Tests | `go test ./internal/modules/misc`, `go test ./cmd/server ./internal/modules/misc`, `go test ./...`, `go vet ./...` | + +## Work Completed + +- [x] Added public `/wheelofnames` command in `misc`. +- [x] Parses comma-separated options, trims whitespace, ignores empty entries. +- [x] Replies usage when no valid option exists. +- [x] Picks one valid option with casual randomness. +- [x] Updated README and `telegram-commands.json`. +- [x] Added focused handler and registration tests. + +## Documentation Updates + +- README module command list updated. +- No `docs/` update needed; no architecture, setup, security, or deploy behavior changed. + +## Known Limitations + +- Randomness is non-cryptographic by design. +- Duplicate options are preserved as weighting. + +## Unresolved Questions + +None.