docs(plan): add coin sell message plan

This commit is contained in:
2026-06-20 09:52:35 +07:00
parent ef1817b43e
commit 6a96f09f51
2 changed files with 134 additions and 0 deletions
@@ -0,0 +1,68 @@
---
phase: 1
title: Update sell message and tests
status: completed
priority: P2
dependencies: []
effort: 30-45m
---
# Phase 1: Update sell message and tests
## Overview
Improve `/coin_sell` insufficient-holdings replies so users see the failed sell amount and available-to-sell value in USD, with coin quantity and current price as supporting context.
## Requirements
- Functional: If user has some holdings but less than requested USD sell amount, reply:
- `Not enough <COIN> to sell <requested USD>.`
- `Available to sell: <available USD> (<held qty> <COIN> @ <price USD>).`
- `Try <available USD> or less.`
- Functional: If user has zero holdings, reply:
- `No <COIN> available to sell.`
- `Try /coin_buy <COIN> <usd_amount> first.`
- Functional: Keep successful sell response unchanged.
- Non-functional: Preserve current portfolio mutation semantics and command argument contract.
## Architecture
`handleSell` already resolves the USD amount, fetches price, computes required coin quantity, and receives held quantity from `Portfolio.DeductAsset` on failure. Reuse that held quantity to format a user-facing reply through a small helper or localized branch inside `handleSell`.
No new storage, price, command registration, or module boundary changes.
## Related Code Files
- Modify: `internal/modules/coin/handlers.go` — format improved insufficient sell reply.
- Modify: `internal/modules/coin/handlers_test.go` — assert partial-holding and zero-holding wording.
- Delete: none.
- Create: none.
## Implementation Steps
1. Add or inline a small formatter for insufficient sell replies.
2. In `handleSell`, keep `held` from `DeductAsset`.
3. If `held` normalizes to zero, return the zero-holdings message.
4. Otherwise compute `availableUSD := held * price.USD` and return the three-line available-to-sell message.
5. Update `TestHandleSellInsufficientCoin` to assert the zero-holdings copy.
6. Update `TestHandleSellInsufficientCoinWithHoldings` to assert requested USD, available USD, coin quantity, price, and retry hint; keep mutation assertion.
7. Run focused and full tests.
## Success Criteria
- [x] Partial-holdings insufficient sell message uses requested USD as primary value.
- [x] Partial-holdings insufficient sell message includes available-to-sell USD, coin quantity, and price.
- [x] Zero-holdings insufficient sell message does not show `$0.00 (0 ETH @ price)`.
- [x] Failed sell leaves portfolio unchanged.
- [x] `go test ./internal/modules/coin -count=1` passes.
- [x] `go test ./... -count=1` passes.
## Risk Assessment
- Risk: message includes USD cash-like wording and remains ambiguous. Mitigation: use `Available to sell`, not `have`.
- Risk: floating point precision leaks into text. Mitigation: use existing `FormatUSD` and `FormatCoinQty`.
- Risk: tests become too brittle around full text. Mitigation: assert meaningful substrings, not every newline.
## Unresolved Questions
None.
@@ -0,0 +1,66 @@
---
title: Improve coin sell insufficient message
description: >-
Make /coin_sell insufficient-holdings replies explain available-to-sell USD
value, with coin quantity and price as context.
status: completed
priority: P2
branch: main
tags:
- bugfix
- backend
- ux
blockedBy: []
blocks: []
created: '2026-06-20T02:12:55.097Z'
createdBy: 'ck:plan'
source: skill
---
# Improve coin sell insufficient message
## Overview
`/coin_sell <COIN> <usd_amount>` sells a USD amount of crypto. When holdings are insufficient, the reply must stay in the user's USD framing while making clear the limiting balance is coin holdings, not USD cash.
Recommended UX:
```text
Not enough BTC to sell $600.00.
Available to sell: $500.00 (0.01 BTC @ $50,000.00).
Try $500.00 or less.
```
Zero holdings should use a clearer special case:
```text
No ETH available to sell.
Try /coin_buy ETH <usd_amount> first.
```
## Phases
| Phase | Name | Status |
|-------|------|--------|
| 1 | [Update sell message and tests](./phase-01-update-sell-message-and-tests.md) | Completed |
## Dependencies
- No blocking active plan. Existing coin module plan `plans/260612-1005-coin-module-price-fallback/plan.md` is completed and only provides context.
## Scope
- In scope: sell insufficient-holdings message in `internal/modules/coin/handlers.go`; regression tests in `internal/modules/coin/handlers_test.go`.
- Out of scope: changing command arguments, portfolio math, price providers, command registration, storage schema, buy wording, docs.
## Success Criteria
- `/coin_sell 600 BTC` after holding only `$500` worth of BTC says not enough BTC to sell `$600`, shows `$500` available, includes `0.01 BTC @ $50,000.00`, and suggests `$500.00 or less`.
- `/coin_sell 10 ETH` with zero ETH says no ETH available to sell and suggests buying ETH first.
- Failed sell still does not mutate portfolio.
- Existing successful sell response remains unchanged.
- `go test ./internal/modules/coin -count=1` and `go test ./... -count=1` pass.
## Unresolved Questions
None.