mirror of
https://github.com/tiennm99/miti99bot.git
synced 2026-09-02 16:20:35 +00:00
docs(stock): document dividend commands
This commit is contained in:
@@ -19,6 +19,20 @@ Atlas via long polling and an in-process cron scheduler.
|
||||
|
||||
Disable modules with the `MODULES` environment variable.
|
||||
|
||||
### Stock dividend commands
|
||||
|
||||
Stock dividends are manual portfolio adjustments:
|
||||
|
||||
- `/stock_cash_dividend <vnd_per_share> <TICKER>` credits a positive whole-VND amount for each pre-event share held. Example: `/stock_cash_dividend 1500 TCB`.
|
||||
- `/stock_share_dividend <owned:new> <TICKER>` adds `floor(pre_event_shares × new / owned)` whole shares. Example: `/stock_share_dividend 100:10 TCB`.
|
||||
- `/stock_dividend <vnd_per_share> <owned:new> <TICKER>` applies both parts from the same pre-event holding and saves them together. Example: `/stock_dividend 1500 100:10 TCB`.
|
||||
|
||||
Ratios use `owned:new` exactly as written in the issuer notice. Equivalent
|
||||
unreduced ratios are accepted and the entered ratio is preserved in the reply.
|
||||
The bot validates syntax, tickers, and arithmetic safety, but does not look up
|
||||
notices or prevent duplicate calls. The caller is responsible for verifying the
|
||||
notice and avoiding accidental repeated adjustments.
|
||||
|
||||
## Layout
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# Stock Dividend Command Naming Journal
|
||||
|
||||
## Context
|
||||
|
||||
Researched official VSDC dividend notices and brainstormed clearer stock command
|
||||
contracts for cash, share, and mixed dividend events.
|
||||
|
||||
## What Happened
|
||||
|
||||
- Approved `/stock_cash_dividend <vnd_per_share> <TICKER>` for cash dividends.
|
||||
- Approved `/stock_share_dividend <owned:new> <TICKER>` for share dividends.
|
||||
- Approved `/stock_dividend <vnd_per_share> <owned:new> <TICKER>` for mixed
|
||||
cash-and-share dividends.
|
||||
- Official examples support ratios such as `4:1` and `100:10`.
|
||||
- No implementation changes made yet.
|
||||
|
||||
## Decisions
|
||||
|
||||
- Share ratios use `owned:new`; both parts must be positive whole numbers.
|
||||
- New shares use integer floor division. Fractional entitlements discarded.
|
||||
- Cash input means VND paid per pre-event share.
|
||||
- Mixed dividends calculate cash and new shares from the same pre-event holding,
|
||||
then persist both results atomically.
|
||||
- Stats history needs a one-time, idempotent migration: existing
|
||||
`/stock_dividend` usage becomes `/stock_cash_dividend`, and `/stock_bonus`
|
||||
usage becomes `/stock_share_dividend`. The new mixed `/stock_dividend` starts
|
||||
with fresh stats.
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Create an implementation plan covering handlers, registration, user-facing
|
||||
text, command menu, atomic storage behavior, stats migrations, and tests.
|
||||
- Implement the approved zero-result behavior: reject share-only payouts, but
|
||||
still credit cash and report zero new shares for mixed payouts.
|
||||
@@ -0,0 +1,33 @@
|
||||
# Stock Dividend Command Plan Journal
|
||||
|
||||
## Context
|
||||
|
||||
Created the implementation plan at
|
||||
`plans/260720-1616-stock-dividend-commands/` from the approved research and
|
||||
brainstorm decisions.
|
||||
|
||||
## What Happened
|
||||
|
||||
- Added three pending phases: implement ratio dividend commands, migrate command
|
||||
statistics, and verify user-facing contracts.
|
||||
- Planned `/stock_cash_dividend` with VND/share, `/stock_share_dividend` with an
|
||||
`owned:new` ratio, and combined `/stock_dividend` using both inputs.
|
||||
- Preserved floor rounding, pre-event holdings, and one atomic portfolio save.
|
||||
- Defined zero-share behavior: reject share-only events; combined events still
|
||||
credit cash.
|
||||
- Tightened migration design after review: each stats row gets a `prepared`
|
||||
checkpoint containing its exact final target count. Crash retries set that
|
||||
count instead of incrementing again.
|
||||
- Could not persist the active-plan selection because `CK_SESSION_ID` was unset.
|
||||
|
||||
## Status
|
||||
|
||||
- Plan: pending
|
||||
- Progress: 0/3 phases complete
|
||||
- Source implementation: not started
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Execute the three planned phases, beginning with command contracts and tests.
|
||||
- Keep the stats migration before module registration so the reused
|
||||
`/stock_dividend` name cannot misattribute historical usage.
|
||||
@@ -0,0 +1,31 @@
|
||||
# Stock Dividend Plan Validation Journal
|
||||
|
||||
## Context
|
||||
|
||||
Validated `plans/260720-1616-stock-dividend-commands/plan.md` and its three
|
||||
pending phase documents before implementation.
|
||||
|
||||
## Validation Result
|
||||
|
||||
- Standard verification: 30 checked, 30 verified, 0 failed, 0 unverified.
|
||||
- Confirmed cash input is a positive whole VND amount per share.
|
||||
- Confirmed any positive whole-number `owned:new` ratio is accepted and echoed
|
||||
unreduced.
|
||||
- Confirmed repeated manual calls are allowed. No event ledger or duplicate-call
|
||||
restriction; caller owns correctness.
|
||||
- Confirmed permanent global and per-row migration markers. Incomplete runs
|
||||
resume from `prepared` checkpoints using their exact target counts.
|
||||
- Propagated these decisions through all three phase documents.
|
||||
- Whole-plan consistency sweep reconciled one stale float-acceptance reference
|
||||
with integer-input wording and found zero contradictions.
|
||||
|
||||
## Status
|
||||
|
||||
- Plan validation: complete
|
||||
- Plan implementation: not started
|
||||
- Source changes: none
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Execute the validated phases in order: command behavior, stats migration, then
|
||||
user-contract and full-project verification.
|
||||
@@ -0,0 +1,67 @@
|
||||
# Stock Dividend Commands Journal
|
||||
|
||||
## Context
|
||||
|
||||
Implemented the validated stock-dividend plan: clearer manual commands,
|
||||
ratio-based share entitlement, and historical stats preservation.
|
||||
|
||||
## What Changed
|
||||
|
||||
- Added `/stock_cash_dividend <vnd_per_share> <TICKER>` for positive whole-VND
|
||||
cash credits.
|
||||
- Added `/stock_share_dividend <owned:new> <TICKER>` with unreduced ratio
|
||||
preservation and floor-rounded whole shares.
|
||||
- Changed `/stock_dividend <vnd_per_share> <owned:new> <TICKER>` to apply cash
|
||||
and shares from the same pre-event holding with one portfolio save.
|
||||
- Share-only zero entitlement rejects with the minimum holding; combined events
|
||||
still credit cash when shares round to zero.
|
||||
- Updated registration, command menu, usage text, README, and contract tests;
|
||||
removed `/stock_bonus` from active commands.
|
||||
|
||||
## Stats Migration
|
||||
|
||||
- Migrates `stock_dividend -> stock_cash_dividend` and
|
||||
`stock_bonus -> stock_share_dividend`, including anonymous and per-user rows.
|
||||
- Merges existing target counts without loss.
|
||||
- Permanent global and per-row markers retain migration history.
|
||||
- Each row stores a `prepared` exact target count before mutation. Retries set
|
||||
that count after any write-boundary failure, preventing double increments.
|
||||
|
||||
## Review Findings
|
||||
|
||||
- Guarded `strconv.ParseInt` range errors so its saturated return value cannot be
|
||||
accepted as valid input.
|
||||
- Added exact `int64` share formatting so quantities above `2^53` do not lose
|
||||
digits through `float64` conversion.
|
||||
- Enforced exact float-backed VND balance addition at the `2^53` boundary;
|
||||
inexact sums reject without saving.
|
||||
- Reviewer: 9/10, approve. Adversarial review: PASS; no disproven claims or
|
||||
reachable regressions.
|
||||
|
||||
## Decisions
|
||||
|
||||
- Ratios remain positive integer `owned:new` values and are echoed as entered;
|
||||
no normalization.
|
||||
- Commands are manual adjustments. Repeated calls remain allowed, with no event
|
||||
ledger or duplicate-call guard; caller owns correctness.
|
||||
- Overflow, exactness, ticker, and syntax validation remain mandatory despite
|
||||
the manual workflow.
|
||||
|
||||
## Verification
|
||||
|
||||
- Passed: `go test ./internal/modules/stock`
|
||||
- Passed: `go test ./internal/modules/stats`
|
||||
- Passed: `go test ./cmd/server`
|
||||
- Passed: `go test ./...`
|
||||
- Passed: `go vet ./...`
|
||||
- Passed: `telegram-commands.json` PowerShell `ConvertFrom-Json`
|
||||
- Passed: `git diff --check` (line-ending warnings only)
|
||||
- Skipped: Mongo-backed tests because `MONGODB_TEST_URL` was unset.
|
||||
- Skipped: `golangci-lint run` because the binary was not installed.
|
||||
|
||||
## Next Considerations
|
||||
|
||||
- Run Mongo-backed migration tests when a test database is available.
|
||||
- Run the lint gate when `golangci-lint` is installed.
|
||||
- After deployment, verify migrated counts and retained system markers before
|
||||
considering migration-runtime cleanup; keep historical stats and markers.
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
---
|
||||
phase: 1
|
||||
title: Implement Ratio Dividend Commands
|
||||
status: completed
|
||||
effort: ''
|
||||
priority: P1
|
||||
dependencies: []
|
||||
---
|
||||
|
||||
# Phase 1: Implement Ratio Dividend Commands
|
||||
|
||||
<!-- Updated: Validation Session 1 - manual-input policy and ratio/cash contracts -->
|
||||
|
||||
## Context Links
|
||||
|
||||
- [Approved brainstorm](../reports/260720-1612-stock-dividend-command-brainstorm.md)
|
||||
- [VSDC ratio research](../reports/260720-1608-dividend-notice-ratio-research.md)
|
||||
|
||||
## Overview
|
||||
|
||||
Replace the two ambiguous adjustment handlers with cash-only, share-only, and
|
||||
combined dividend contracts. Centralize validated ratio math so all handlers
|
||||
use the same overflow-safe, floor-rounded calculation.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Functional: register `stock_cash_dividend`, `stock_share_dividend`, and
|
||||
`stock_dividend` with the approved argument order and clear usage examples.
|
||||
- Functional: accept cash only as positive whole VND per share; reject signs,
|
||||
decimals, zero, parse overflow, and non-finite representations.
|
||||
- Functional: accept only positive whole-number `owned:new` parts; reject
|
||||
missing/extra colons, decimals, signs, zero, parse overflow, and invalid ticker.
|
||||
- Functional: accept equivalent unreduced ratios and preserve the user's exact
|
||||
valid ratio text in the success reply; do not require or display reduction.
|
||||
- Functional: compute `floor(held * new / owned)` without overflowing `int64`;
|
||||
compute the minimum holding for a non-zero share result safely.
|
||||
- Functional: share-only rejects a zero result and reports that minimum;
|
||||
combined credits cash and reports zero shares.
|
||||
- Non-functional: cash and shares use the same pre-event holding; mutate only
|
||||
after all validation; call `SavePortfolio` exactly once per successful event.
|
||||
- Non-functional: allow intentional repeated calls; add no event ID, notice
|
||||
lookup, history ledger, or duplicate-event guard.
|
||||
|
||||
## Architecture
|
||||
|
||||
Add a small dividend calculation helper beside the stock handlers. Parse cash
|
||||
and ratio parts into positive integers while retaining the validated ratio
|
||||
string for replies. Calculate quotient and remainder before
|
||||
multiplication (or use checked operations) to preserve floor semantics without
|
||||
`held * new` overflow. Each handler loads once, snapshots `held`, calculates
|
||||
all outputs, mutates the in-memory portfolio, then saves once. The combined
|
||||
handler must not let newly issued shares participate in its cash calculation.
|
||||
Treat every successful invocation as an intentional manual adjustment.
|
||||
|
||||
## Related Code Files
|
||||
|
||||
- Create: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\internal\modules\stock\dividends.go` — ratio parsing and checked entitlement math.
|
||||
- Create: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\internal\modules\stock\dividends_test.go` — parser, floor, minimum, and overflow boundaries.
|
||||
- Modify: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\internal\modules\stock\handlers.go` — three handlers and user-facing replies.
|
||||
- Modify: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\internal\modules\stock\handlers_test.go` — contracts, failures, pre-event basis, and one-save behavior.
|
||||
- Modify: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\internal\modules\stock\stock.go` — registry names, descriptions, handlers.
|
||||
- Modify: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\internal\modules\stock\portfolio_test.go` — portfolio outcomes where helper coverage belongs.
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
1. Write table tests first for whole-VND parsing, `4:1`, `100:10`, equivalent
|
||||
unreduced ratios, malformed inputs, `int64` boundaries, exact division,
|
||||
floor division, preserved ratio text, and safe minimum holdings.
|
||||
2. Add handler tests for usage text, invalid cash/ratio/ticker, no holdings,
|
||||
zero-result divergence, and persistence failures.
|
||||
3. Add combined tests proving cash and shares derive from the same snapshot and
|
||||
one store write commits both; use an instrumented test store to count saves.
|
||||
4. Implement parsing and overflow-safe integer entitlement helpers. Require
|
||||
positive whole VND/share and reject fractional or overflowing totals.
|
||||
5. Replace `handleBonus`/old cash `handleDividend` routing with explicit cash,
|
||||
share, and combined handlers. Replies include ratio, old holding, cash, new
|
||||
shares, and final holding as applicable.
|
||||
6. Update the command registry to eight stock commands and remove public
|
||||
registration of `stock_bonus`.
|
||||
7. Run `gofmt` and focused stock tests.
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- [x] All three approved commands and examples are registered exactly.
|
||||
- [x] Cash rejects fractional VND; valid unreduced ratios are accepted and echoed unchanged.
|
||||
- [x] Share math floors without overflow for every accepted `int64` input.
|
||||
- [x] Share-only zero entitlement makes no change; combined zero entitlement credits cash and reports zero shares.
|
||||
- [x] Successful combined events use pre-event holdings and one `SavePortfolio`.
|
||||
- [x] Repeating a valid command applies the adjustment again; no deduplication state exists.
|
||||
- [x] `go test ./internal/modules/stock` passes.
|
||||
|
||||
## Risk Assessment
|
||||
|
||||
- Overflow or invalid numeric acceptance could silently over-credit portfolios.
|
||||
Mitigate with integer parsing, quotient/remainder math, checked cash totals,
|
||||
and boundary tests.
|
||||
- Partial mutation could diverge balances. Validate first, mutate in memory,
|
||||
persist once; verify the unchanged state on every rejected path.
|
||||
- Manual repeated calls can double-credit an event by design. State caller
|
||||
responsibility clearly; do not silently infer or suppress duplicates.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
No new authorization surface. Continue sender checks and strict ticker/input
|
||||
validation; do not echo unbounded raw input.
|
||||
|
||||
## Next Steps
|
||||
|
||||
Phase 2 migrates persisted stats before the renamed commands are deployed.
|
||||
@@ -0,0 +1,113 @@
|
||||
---
|
||||
phase: 2
|
||||
title: Migrate Command Statistics
|
||||
status: completed
|
||||
effort: ''
|
||||
priority: P1
|
||||
dependencies:
|
||||
- 1
|
||||
---
|
||||
|
||||
# Phase 2: Migrate Command Statistics
|
||||
|
||||
<!-- Updated: Validation Session 1 - prepared-checkpoint retry and retention -->
|
||||
|
||||
## Context Links
|
||||
|
||||
- [Approved compatibility decision](../reports/260720-1612-stock-dividend-command-brainstorm.md#compatibility-and-touchpoints)
|
||||
- [Project stats compatibility rules](../../AGENTS.md#stats-compatibility)
|
||||
|
||||
## Overview
|
||||
|
||||
Move historical usage to the commands that retain the old meanings, then leave
|
||||
`stock_dividend` empty for new combined-event usage. Guard the one-time move in
|
||||
the shared `system` collection and run it during server startup.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Functional: migrate `stock_dividend -> stock_cash_dividend` and
|
||||
`stock_bonus -> stock_share_dividend`.
|
||||
- Functional: include command-total rows (`uid=0`) and every per-user row;
|
||||
merge source counts into existing target rows rather than overwrite them.
|
||||
- Functional: preserve user ID/username metadata, remove migrated source rows,
|
||||
and write the completion marker only after both mappings finish.
|
||||
- Functional: a completed marker makes subsequent startups a no-op; tests cover
|
||||
target merging and repeated invocation for memory and MongoDB stores.
|
||||
- Functional: an incomplete migration resumes both remaining source rows and
|
||||
`prepared` row checkpoints, including a checkpoint whose source was deleted.
|
||||
- Functional: retain global and per-row markers permanently as migration history.
|
||||
- Non-functional: migration errors fail startup before module registration, so
|
||||
new command meanings never run against unmigrated history.
|
||||
|
||||
## Architecture
|
||||
|
||||
Extend stats startup maintenance to receive both `stats` and `system`
|
||||
collections. Use the existing typed stats documents and `systemstate.Store`.
|
||||
A stable marker such as `migration:stock-dividend-command-stats-v1` records
|
||||
global completion. For each source row, first persist a stable per-row
|
||||
`prepared` checkpoint in `system` containing the exact final target count.
|
||||
Retries set the target to that checkpointed count instead of adding again,
|
||||
then delete the source and mark the row complete. Preserve the best available
|
||||
username deterministically. Mark global completion only after every row is
|
||||
complete. On startup without a global completion marker, enumerate both source
|
||||
rows and prepared checkpoints so deletion-before-row-complete can recover.
|
||||
Retain all markers as migration history; add no cleanup path.
|
||||
|
||||
## Related Code Files
|
||||
|
||||
- Modify: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\internal\modules\stats\startup.go` — startup signature, marker guard, and migration orchestration.
|
||||
- Create: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\internal\modules\stats\startup_test.go` — memory migration, merges, anonymous/users, failures, idempotency.
|
||||
- Modify: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\internal\modules\stats\startup_mongo_test.go` — Mongo indexes plus migration parity and rerun checks.
|
||||
- Modify: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\internal\modules\stats\stats_test.go` — visible stats attribution after migration if needed.
|
||||
- Modify: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\cmd\server\main.go` — pass `stats` and shared `system` collections before module build.
|
||||
- Reference: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\internal\systemstate\systemstate.go` — existing marker store; no schema change expected.
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
1. Add memory tests seeding source-only, target-only, merged anonymous, merged
|
||||
per-user, multiple users, and both command mappings.
|
||||
2. Assert exact post-migration keys/counts/metadata, source removal, marker
|
||||
content, and no change after a second startup call.
|
||||
3. Add injected-failure tests at prepare, target-write, source-delete, and
|
||||
row-complete boundaries. Retry each case—including source already deleted—
|
||||
and prove counts never duplicate.
|
||||
4. Implement deterministic global and per-row marker keys. A prepared marker
|
||||
stores the exact merged target count; retries overwrite with that value,
|
||||
never increment an already migrated target again.
|
||||
5. Implement the mapping helper using deterministic `usageKey` values and the
|
||||
existing typed store. Keep mapping data declarative and local to stats.
|
||||
6. Extend `InitStore` to create indexes and run the guarded migration; wrap
|
||||
errors with migration/command context.
|
||||
7. Wire `provider.Collection(systemstate.CollectionName)` from server startup
|
||||
and preserve fail-fast logging before command registration.
|
||||
8. Mirror critical merge, partial-retry, and idempotency cases in Mongo tests.
|
||||
9. Run `gofmt`, focused stats tests, and focused server tests.
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- [x] Old cash usage appears only under `stock_cash_dividend`.
|
||||
- [x] Old bonus usage appears only under `stock_share_dividend`.
|
||||
- [x] Existing target counts merge for anonymous and per-user rows without loss.
|
||||
- [x] Retries after every partial-write boundary cannot duplicate counts.
|
||||
- [x] Prepared checkpoints resume even when their source rows no longer exist.
|
||||
- [x] Completed migration is idempotent and marker-backed in memory and MongoDB.
|
||||
- [x] Global and per-row migration markers remain after completion.
|
||||
- [x] Startup aborts on migration failure and `go test ./internal/modules/stats ./cmd/server` passes.
|
||||
|
||||
## Risk Assessment
|
||||
|
||||
- Reusing `stock_dividend` before migration would mislabel history. Keep the
|
||||
migration before module construction and treat errors as fatal.
|
||||
- A mid-migration process crash may leave partial work. Prepare each row's exact
|
||||
final count before touching the target; retry by setting that value, not by
|
||||
adding again. Scan prepared checkpoints independently from source rows. Do
|
||||
not mark row/global completion early or delete historical markers.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
The migration touches counts and public usernames only. Never log full records;
|
||||
log marker/mapping names and aggregate counts.
|
||||
|
||||
## Next Steps
|
||||
|
||||
Phase 3 aligns all user-facing surfaces and runs the repository-wide gate.
|
||||
@@ -0,0 +1,95 @@
|
||||
---
|
||||
phase: 3
|
||||
title: Verify User Contracts
|
||||
status: completed
|
||||
effort: ''
|
||||
priority: P1
|
||||
dependencies:
|
||||
- 1
|
||||
- 2
|
||||
---
|
||||
|
||||
# Phase 3: Verify User Contracts
|
||||
|
||||
<!-- Updated: Validation Session 1 - document manual caller responsibility -->
|
||||
|
||||
## Context Links
|
||||
|
||||
- [Approved command contracts](../reports/260720-1612-stock-dividend-command-brainstorm.md#approved-behavior)
|
||||
- [Repository development rules](../../AGENTS.md#command-changes)
|
||||
|
||||
## Overview
|
||||
|
||||
Synchronize Telegram command-menu metadata and README documentation with the
|
||||
implemented contracts, then run focused and repository-wide verification.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Functional: command names, descriptions, argument order, examples, errors,
|
||||
and menu behavior agree across registry, handlers, JSON, tests, and README.
|
||||
- Functional: remove `stock_bonus` from active user surfaces; document that
|
||||
cash is VND/share and share input is the `owned:new` notice ratio.
|
||||
- Functional: document positive whole-VND input, acceptance of unreduced ratios,
|
||||
preserved ratio text, and deliberate repeat-call behavior.
|
||||
- Non-functional: preserve plan-approved migration behavior and run every gate
|
||||
required for command, storage, migration, and shared startup changes.
|
||||
|
||||
## Architecture
|
||||
|
||||
Treat registered Go commands as runtime truth and `telegram-commands.json` as
|
||||
the manual BotFather/menu source. Tests assert the final eight-command stock
|
||||
registry and registered menu contents. README gives concise user-visible syntax
|
||||
and the floor/pre-event behavior needed to use notices correctly. It states
|
||||
that commands are manual adjustments: the caller verifies the notice and avoids
|
||||
accidental duplicates; the bot enforces syntax and storage safety only.
|
||||
|
||||
## Related Code Files
|
||||
|
||||
- Modify: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\telegram-commands.json` — replace old dividend/bonus entries with three approved commands.
|
||||
- Modify: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\README.md` — document syntax, VND/share, ratio direction, floor rounding, and combined behavior.
|
||||
- Modify: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\internal\modules\stock\handlers_test.go` — final registry and user-facing text assertions.
|
||||
- Modify: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\cmd\server\command_menu_test.go` — command-menu presence and removal checks.
|
||||
- Verify: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\internal\modules\stats\startup_test.go` — migration contracts remain green.
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
1. Replace `stock_bonus` and old cash-only `stock_dividend` menu descriptions
|
||||
with `stock_cash_dividend`, `stock_share_dividend`, and combined
|
||||
`stock_dividend`; keep Telegram ordering coherent.
|
||||
2. Add a compact README stock-command section with all three syntaxes and one
|
||||
mixed example. State positive whole VND/share, `owned:new`, accepted
|
||||
unreduced ratios, preserved ratio replies, integer floor rounding,
|
||||
pre-event basis, and caller responsibility for repeat events.
|
||||
3. Update registry/menu tests to assert new commands and reject old public
|
||||
`stock_bonus`; ensure descriptions stay within Telegram limits.
|
||||
4. Run `gofmt` over every changed Go file.
|
||||
5. Run focused packages: `go test ./internal/modules/stock`,
|
||||
`go test ./internal/modules/stats`, and `go test ./cmd/server`.
|
||||
6. Run `go test ./...` and `go vet ./...`.
|
||||
7. If `golangci-lint` is available, run `golangci-lint run`; record a skipped
|
||||
gate explicitly when the binary is absent.
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- [x] Registry, handlers, JSON, README, and menu tests expose the same three contracts.
|
||||
- [x] No active user-facing surface advertises `stock_bonus` or old cash-only `/stock_dividend` syntax.
|
||||
- [x] README distinguishes manual correctness responsibility from mandatory parser/overflow safety.
|
||||
- [x] Focused tests, `go test ./...`, and `go vet ./...` pass.
|
||||
- [x] `golangci-lint run` passes when available.
|
||||
- [x] No unresolved questions remain.
|
||||
|
||||
## Risk Assessment
|
||||
|
||||
- Stale menu/docs can cause financially wrong manual entries. Search all active
|
||||
surfaces for old names and syntax, while leaving migration fixtures intact.
|
||||
- Mongo integration tests may require local infrastructure. Keep unit coverage
|
||||
mandatory and report environment-based integration skips accurately.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
Documentation must use synthetic holdings and tickers only; no tokens,
|
||||
production data, or private portfolio records.
|
||||
|
||||
## Next Steps
|
||||
|
||||
Implementation can proceed phase-by-phase after plan approval.
|
||||
@@ -0,0 +1,133 @@
|
||||
---
|
||||
title: Stock Dividend Commands
|
||||
description: >-
|
||||
Replace ambiguous stock adjustments with cash-only, share-only, and combined
|
||||
dividend commands while preserving historical stats.
|
||||
status: completed
|
||||
priority: P1
|
||||
branch: main
|
||||
tags:
|
||||
- feature
|
||||
- backend
|
||||
- database
|
||||
blockedBy: []
|
||||
blocks: []
|
||||
created: '2026-07-20T09:16:13.694Z'
|
||||
createdBy: 'ck:plan'
|
||||
source: skill
|
||||
---
|
||||
|
||||
# Stock Dividend Commands
|
||||
|
||||
## Overview
|
||||
|
||||
Add three explicit public contracts: cash dividend in VND/share, share dividend
|
||||
in `owned:new` ratio form, and a combined command. Use integer floor rounding,
|
||||
pre-event holdings, and one portfolio save. Rename historical stats through an
|
||||
idempotent startup migration before `/stock_dividend` gains its new meaning.
|
||||
|
||||
## Phases
|
||||
|
||||
| Phase | Name | Status |
|
||||
|-------|------|--------|
|
||||
| 1 | [Implement Ratio Dividend Commands](./phase-01-implement-ratio-dividend-commands.md) | Completed |
|
||||
| 2 | [Migrate Command Statistics](./phase-02-migrate-command-statistics.md) | Completed |
|
||||
| 3 | [Verify User Contracts](./phase-03-verify-user-contracts.md) | Completed |
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Approved design: [Stock Dividend Command Brainstorm](../reports/260720-1612-stock-dividend-command-brainstorm.md)
|
||||
- Evidence: [Dividend Notice Ratio Research](../reports/260720-1608-dividend-notice-ratio-research.md)
|
||||
- Existing Go module, typed storage, `system` marker store, and stats startup path
|
||||
|
||||
## Contracts
|
||||
|
||||
- `/stock_cash_dividend <vnd_per_share> <TICKER>` credits a positive whole-VND amount per share.
|
||||
- `/stock_share_dividend <owned:new> <TICKER>` accepts any positive integer ratio, preserves its entered form in replies, and adds floor-rounded shares; zero result rejects.
|
||||
- `/stock_dividend <vnd_per_share> <owned:new> <TICKER>` applies both from pre-event holdings; zero shares still credits cash.
|
||||
- Stats move `stock_dividend -> stock_cash_dividend` and `stock_bonus -> stock_share_dividend`; combined usage starts fresh.
|
||||
- Commands are deliberate manual adjustments: repeated calls are allowed and
|
||||
no issuer-event deduplication or ratio reduction is imposed.
|
||||
|
||||
## Validation Gate
|
||||
|
||||
- Focused stock, stats migration, startup, and command-menu tests.
|
||||
- `gofmt` changed Go files; run `go test ./...` and `go vet ./...`.
|
||||
- Run `golangci-lint run` when installed.
|
||||
|
||||
## Completion Criteria
|
||||
|
||||
- Commands, replies, menu JSON, and README agree on names and argument order.
|
||||
- Ratio math cannot overflow and always floors; combined state persists once.
|
||||
- Stats migration merges anonymous/per-user targets and repeated startup is a no-op.
|
||||
- No unresolved questions.
|
||||
|
||||
## Validation Log
|
||||
|
||||
### Session 1 — 2026-07-20
|
||||
|
||||
**Trigger:** User requested `/ck:plan validate` before implementation.
|
||||
**Questions asked:** 4
|
||||
|
||||
### Verification Results
|
||||
|
||||
- **Tier:** Standard (Fact Checker + Contract Verifier)
|
||||
- **Claims checked:** 30
|
||||
- **Verified:** 30 | **Failed:** 0 | **Unverified:** 0
|
||||
- Verified current handlers/registry/portfolio storage, stats startup caller and
|
||||
persisted row shape, shared system marker store, command-menu flow, tests,
|
||||
README/JSON surfaces, and repository verification commands.
|
||||
- Planned create-paths correctly do not exist yet: `dividends.go`,
|
||||
`dividends_test.go`, and stats `startup_test.go`.
|
||||
- **Failures:** None.
|
||||
|
||||
#### Questions & Answers
|
||||
|
||||
1. **[Assumption]** Should cash dividends require a positive whole VND amount per share and reject decimals?
|
||||
- Options: Require positive whole VND (Recommended) | Preserve positive finite decimal input
|
||||
- **Answer:** Require positive whole VND.
|
||||
- **Rationale:** Matches approved manual-entry contract and avoids fractional VND credits.
|
||||
2. **[Architecture]** Should share ratios accept any positive integer form and preserve the entered form without requiring reduction?
|
||||
- Options: Accept and preserve any positive ratio (Recommended) | Require reduced ratios | Normalize replies
|
||||
- **Answer:** Accept and preserve any positive ratio.
|
||||
- **Rationale:** Mirrors issuer notices while avoiding unnecessary restrictions.
|
||||
3. **[Scope]** Should repeated dividend commands be allowed without an issuer-event deduplication ledger?
|
||||
- Options: Allow repeated manual adjustments (Recommended) | Add event IDs and deduplication
|
||||
- **Answer:** Allow repeated manual adjustments; caller owns correctness.
|
||||
- **Custom input:** "this is for user do manually, so not restrict anything, user call it will have reponsibility to make sure call it correct"
|
||||
- **Rationale:** The feature is a manual portfolio adjustment, not an issuer-event ledger.
|
||||
4. **[Risk]** Should migration retries scan prepared row checkpoints and retain all migration markers permanently?
|
||||
- Options: Retry prepared rows and retain markers (Recommended) | Use global marker only | Clean row markers after completion
|
||||
- **Answer:** Retry prepared rows and retain markers permanently.
|
||||
- **Rationale:** Makes partial retries auditable and prevents double-counting.
|
||||
|
||||
#### Confirmed Decisions
|
||||
|
||||
- Manual responsibility does not bypass storage-safety validation: cash remains
|
||||
positive whole VND; ratio parts remain positive integers; ticker and overflow
|
||||
checks remain mandatory.
|
||||
- No ratio canonicalization, notice lookup, event ID, or duplicate-call guard.
|
||||
- Migration completion requires reconciling both source rows and prepared row
|
||||
checkpoints; global and row markers remain as history.
|
||||
|
||||
#### Action Items
|
||||
|
||||
- [x] Propagate manual-input and repeat-call rules to Phase 1.
|
||||
- [x] Propagate checkpoint retry/retention rules to Phase 2.
|
||||
- [x] Propagate user-facing responsibility wording to Phase 3.
|
||||
|
||||
#### Impact on Phases
|
||||
|
||||
- Phase 1: tighten cash parsing; preserve ratio text; explicitly allow repeats.
|
||||
- Phase 2: scan prepared checkpoints on retry; retain all markers.
|
||||
- Phase 3: document manual responsibility and safety-validation boundary.
|
||||
|
||||
### Whole-Plan Consistency Sweep
|
||||
|
||||
- Files reread: `plan.md` and all three `phase-*.md` files.
|
||||
- Decision deltas checked: 4.
|
||||
- Reconciled stale references: 1 (`float acceptance` replaced by integer-input wording).
|
||||
- Verified command names, input order, whole-VND rule, unreduced-ratio policy,
|
||||
repeat-call policy, zero-share behavior, migration retry flow, and marker
|
||||
retention agree across overview, requirements, steps, risks, and criteria.
|
||||
- Unresolved contradictions: 0.
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
---
|
||||
type: pm-completion-report
|
||||
plan: stock-dividend-commands
|
||||
status: completed
|
||||
created_at: 2026-07-20T17:15:00+07:00
|
||||
---
|
||||
|
||||
# Plan Complete: Stock Dividend Commands
|
||||
|
||||
## Summary
|
||||
|
||||
| Metric | Result |
|
||||
|---|---|
|
||||
| Plan status | Completed |
|
||||
| Phase progress | 3/3 (100%) |
|
||||
| Success criteria | 21/21 checked |
|
||||
| Unresolved mappings | 0 |
|
||||
| Review | 9/10, approved |
|
||||
| Adversarial review | Passed |
|
||||
|
||||
## Delivered
|
||||
|
||||
- Explicit cash-only, share-only, and combined dividend contracts.
|
||||
- Overflow-safe floor entitlement math using pre-event holdings and one save.
|
||||
- Idempotent stats renames with retained migration checkpoints.
|
||||
- Registry, Telegram menu, tests, and README aligned with public contracts.
|
||||
|
||||
## Verification
|
||||
|
||||
- Focused stock, stats, server, and command-menu tests: passed.
|
||||
- `go test ./...`: passed.
|
||||
- `go vet ./...`: passed.
|
||||
- Whole-plan consistency sweep: passed; no unresolved mappings.
|
||||
|
||||
## Known Limitation
|
||||
|
||||
- MongoDB partial-boundary execution unavailable in the verification
|
||||
environment. Deterministic retry behavior remains covered by available
|
||||
focused verification; no completion blocker recorded.
|
||||
|
||||
## Unresolved Questions
|
||||
|
||||
None.
|
||||
@@ -0,0 +1,112 @@
|
||||
---
|
||||
type: research-report
|
||||
topic: dividend-notice-ratio-examples
|
||||
conducted_at: 2026-07-20T16:08:21+07:00
|
||||
status: complete
|
||||
---
|
||||
|
||||
# Research Report: Dividend Notice Ratio Examples
|
||||
|
||||
## Summary
|
||||
|
||||
Official VSDC notices support ratio-based share-dividend input. Notices express
|
||||
the ratio as existing shares or rights to new shares, such as `4:1` and
|
||||
`100:10`. Resulting fractional shares are rounded down and discarded.
|
||||
|
||||
Keep cash input as VND per existing share. Although notices also state a cash
|
||||
percentage, that percentage is based on par value; accepting the actual VND per
|
||||
share avoids needing par-value data.
|
||||
|
||||
## Methodology
|
||||
|
||||
- Sources: 2 recent official VSDC notices
|
||||
- Notice dates: 2026-05-05 and 2026-06-26
|
||||
- Terms: `trả cổ tức bằng tiền`, `trả cổ tức bằng cổ phiếu`, `tỷ lệ thực hiện`
|
||||
- Scope: input semantics and rounding for the three proposed Telegram commands
|
||||
|
||||
## Findings
|
||||
|
||||
### IDC mixed dividend
|
||||
|
||||
- Cash: 15% per share, explicitly `1 share receives 1,500 VND`.
|
||||
- Shares: `100:10`, meaning 100 existing rights receive 10 new shares.
|
||||
- Example: 139 existing shares produce `139 / 100 * 10 = 13.9`, rounded down
|
||||
to 13 new shares; the 0.9 fraction is discarded.
|
||||
|
||||
Source: [IDC: cash and stock dividends for 2025](https://www.vsd.vn/vi/ad/197421)
|
||||
|
||||
### PTB mixed dividend
|
||||
|
||||
- Cash: 5% per share, explicitly `1 share receives 500 VND`.
|
||||
- Shares: `4:1`, meaning 4 existing shares receive 1 new share.
|
||||
- Example: 2,026 existing shares produce `2,026 / 4 * 1 = 506.5`, rounded down
|
||||
to 506 new shares; the 0.5 fraction is discarded.
|
||||
|
||||
Source: [PTB: cash and stock dividends for 2025](https://vsd.vn/vi/ad/195203)
|
||||
|
||||
## Comparative Analysis
|
||||
|
||||
| Input | Benefit | Problem |
|
||||
|---|---|---|
|
||||
| Absolute new-share quantity | Matches current `/stock_bonus` behavior | User must calculate entitlement manually |
|
||||
| Percentage | Familiar for rates such as 10% | Ambiguous parsing and less faithful to notice wording |
|
||||
| `owned:new` ratio | Mirrors VSDC notices; easy to audit | Requires integer parsing and floor rounding |
|
||||
|
||||
Recommendation: accept the `owned:new` ratio.
|
||||
|
||||
## Command Recommendation
|
||||
|
||||
```text
|
||||
/stock_cash_dividend <vnd_per_share> <TICKER>
|
||||
/stock_share_dividend <owned:new> <TICKER>
|
||||
/stock_dividend <vnd_per_share> <owned:new> <TICKER>
|
||||
```
|
||||
|
||||
Examples:
|
||||
|
||||
```text
|
||||
/stock_cash_dividend 1500 IDC
|
||||
/stock_share_dividend 100:10 IDC
|
||||
/stock_dividend 1500 100:10 IDC
|
||||
|
||||
/stock_cash_dividend 500 PTB
|
||||
/stock_share_dividend 4:1 PTB
|
||||
/stock_dividend 500 4:1 PTB
|
||||
```
|
||||
|
||||
Calculation:
|
||||
|
||||
```text
|
||||
new_shares = floor(existing_shares * new / owned)
|
||||
cash_vnd = existing_shares * vnd_per_share
|
||||
```
|
||||
|
||||
For a mixed dividend, calculate both values from the same pre-event holding,
|
||||
then save cash and shares atomically.
|
||||
|
||||
## Validation and Pitfalls
|
||||
|
||||
- Require positive whole-number ratio parts; reject `0:1`, `4:0`, negatives,
|
||||
decimals, missing colon, and extra colons.
|
||||
- Reduce equivalent ratios internally if useful, but preserve the entered ratio
|
||||
in the reply for auditability.
|
||||
- Use integer arithmetic and floor division for shares; avoid floating-point
|
||||
rounding.
|
||||
- Reject events producing zero new shares, or explicitly confirm zero payout;
|
||||
recommended behavior: reject with the minimum holding required.
|
||||
- Calculate cash before adding new shares so newly distributed shares do not
|
||||
receive cash from the same event.
|
||||
- Keep cash input in VND/share. Do not derive it from a percentage unless the
|
||||
portfolio also stores the security's par value.
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Confirm zero-share-result behavior.
|
||||
2. Finalize the three command contracts and reply wording.
|
||||
3. Plan command renames, combined atomic update, stats migrations, and tests.
|
||||
|
||||
## Unresolved Questions
|
||||
|
||||
- When a valid ratio yields zero new shares, should the command reject the
|
||||
event or record a zero-share result while still applying cash in the combined
|
||||
command?
|
||||
@@ -0,0 +1,165 @@
|
||||
---
|
||||
type: brainstorm-report
|
||||
topic: stock-dividend-command-naming
|
||||
created_at: 2026-07-20T16:12:33+07:00
|
||||
status: approved
|
||||
modes:
|
||||
html: false
|
||||
wiki: false
|
||||
---
|
||||
|
||||
# Brainstorm Report: Stock Dividend Commands
|
||||
|
||||
## Summary
|
||||
|
||||
Approved three explicit commands:
|
||||
|
||||
```text
|
||||
/stock_cash_dividend <vnd_per_share> <TICKER>
|
||||
/stock_share_dividend <owned:new> <TICKER>
|
||||
/stock_dividend <vnd_per_share> <owned:new> <TICKER>
|
||||
```
|
||||
|
||||
Cash uses VND per existing share. Share distributions use the official-notice
|
||||
ratio form, such as `4:1` or `100:10`. Mixed dividends calculate both outcomes
|
||||
from the pre-event holding and persist them atomically.
|
||||
|
||||
## Problem-First Analysis
|
||||
|
||||
### Solution-Jumping Diagnosis
|
||||
|
||||
The original names encoded outcomes inconsistently: `/stock_bonus` added shares
|
||||
while `/stock_dividend` added cash. Users could not distinguish a true bonus
|
||||
share event from a stock dividend or represent a mixed dividend notice.
|
||||
|
||||
### Underlying Problem
|
||||
|
||||
Users need command names and inputs that map directly to Vietnamese dividend
|
||||
notices, while preserving simple manual paper-portfolio accounting.
|
||||
|
||||
### Assumptions and Validation
|
||||
|
||||
| Assumption | Risk if wrong | Validation |
|
||||
|---|---|---|
|
||||
| Notices provide share ratios | Users must calculate quantities | Confirmed by VSDC `4:1` and `100:10` notices |
|
||||
| Cash per share is sufficient | Percentage input may be expected | Notices explicitly state VND received per share |
|
||||
| Fractions round down | Portfolio could over-credit shares | Confirmed by both VSDC examples |
|
||||
| Mixed event uses one record-date holding | Cash may include newly issued shares | Calculate both before mutation |
|
||||
|
||||
### Problem Statement
|
||||
|
||||
Paper-trading users cannot accurately record cash-only, share-only, and mixed
|
||||
dividends because current command semantics are incomplete and `stock_bonus`
|
||||
does not necessarily mean a stock dividend. Success means each notice maps to
|
||||
one obvious command and produces auditable integer-share and cash results.
|
||||
|
||||
### Alternative Framings
|
||||
|
||||
1. Keep current commands: smallest change, but mixed events need two commands
|
||||
and terminology remains ambiguous.
|
||||
2. Use explicit cash/share commands plus a combined command: clear, direct,
|
||||
matches actual notices. Selected.
|
||||
3. Add a generic corporate-action command with subtypes: extensible but too
|
||||
complex for three small manual operations.
|
||||
|
||||
### Evidence Status
|
||||
|
||||
Strong for syntax and rounding: two recent official VSDC mixed-dividend notices
|
||||
use cash-per-share explanations, `owned:new` ratios, and floor rounding.
|
||||
|
||||
### Validation Plan
|
||||
|
||||
- Unit-test ratio parsing, overflow boundaries, and floor division.
|
||||
- Table-test cash-only, share-only, and combined handlers.
|
||||
- Verify combined calculation uses the same pre-event holding.
|
||||
- Test one-time stats migrations for anonymous and per-user rows.
|
||||
- Reject the design if real notices require unsupported fractional settlement
|
||||
rather than discarded fractions.
|
||||
|
||||
### Stakeholder Message
|
||||
|
||||
Use explicit cash and share commands for single-form notices, and the combined
|
||||
command for mixed notices. Inputs mirror VSDC wording, reducing manual math and
|
||||
making bot replies easy to compare against source notices.
|
||||
|
||||
## Evaluated Approaches
|
||||
|
||||
| Approach | Pros | Cons | Decision |
|
||||
|---|---|---|---|
|
||||
| Absolute new-share quantity | Reuses current handler behavior | Manual calculation; hides rounding | Reject |
|
||||
| Percentage share input | Familiar shorthand | Ambiguous; less faithful to notices | Reject |
|
||||
| `owned:new` share ratio | Mirrors notices; deterministic | Needs parser and integer safety | Approve |
|
||||
|
||||
## Approved Behavior
|
||||
|
||||
### Cash-only
|
||||
|
||||
```text
|
||||
/stock_cash_dividend 1500 IDC
|
||||
cash = existing_shares * 1500 VND
|
||||
```
|
||||
|
||||
### Share-only
|
||||
|
||||
```text
|
||||
/stock_share_dividend 100:10 IDC
|
||||
new_shares = floor(existing_shares * 10 / 100)
|
||||
```
|
||||
|
||||
Reject a share-only event when the valid ratio produces zero new shares and
|
||||
report the minimum holding needed.
|
||||
|
||||
### Mixed
|
||||
|
||||
```text
|
||||
/stock_dividend 1500 100:10 IDC
|
||||
```
|
||||
|
||||
Calculate cash and new shares from the same pre-event holding. When the share
|
||||
result is zero, still credit cash and report zero new shares. Save once so cash
|
||||
and shares cannot diverge after a partial failure.
|
||||
|
||||
## Compatibility and Touchpoints
|
||||
|
||||
- Rename `/stock_bonus` to `/stock_share_dividend`.
|
||||
- Move historical `/stock_bonus` stats to `/stock_share_dividend`.
|
||||
- Move historical cash-only `/stock_dividend` stats to
|
||||
`/stock_cash_dividend` before reusing `/stock_dividend` for mixed events.
|
||||
- Update `internal/modules/stock/stock.go`, handlers, handler tests, and
|
||||
`telegram-commands.json`.
|
||||
- Add idempotent startup migration through the shared `system` collection;
|
||||
cover anonymous rows, per-user rows, target-row merging, and repeated startup.
|
||||
|
||||
## Risks
|
||||
|
||||
- Integer multiplication can overflow before division; validate bounds or use a
|
||||
safe quotient/remainder calculation.
|
||||
- Reusing `/stock_dividend` without migrating old stats mislabels historical
|
||||
cash-only usage as combined usage.
|
||||
- Applying shares before cash calculation overpays the same event.
|
||||
- Accepting decimal or zero ratio components creates undefined rounding.
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- `4:1` and `100:10` parse; malformed or non-positive ratios fail clearly.
|
||||
- Share calculations use integer floor semantics.
|
||||
- Cash/share/mixed commands match their documented examples.
|
||||
- Mixed updates are atomic and use pre-event holdings.
|
||||
- Existing command statistics remain preserved under the correct new meanings.
|
||||
- Focused tests, `go test ./...`, and `go vet ./...` pass.
|
||||
|
||||
## Sources
|
||||
|
||||
- [VSDC IDC mixed dividend notice](https://www.vsd.vn/vi/ad/197421)
|
||||
- [VSDC PTB mixed dividend notice](https://vsd.vn/vi/ad/195203)
|
||||
- [Supporting research report](./260720-1608-dividend-notice-ratio-research.md)
|
||||
|
||||
## Next Steps
|
||||
|
||||
Create a tests-first implementation plan because this change renames public
|
||||
commands, changes persisted stats attribution, and modifies financial
|
||||
calculation behavior.
|
||||
|
||||
## Unresolved Questions
|
||||
|
||||
None.
|
||||
Reference in New Issue
Block a user