mirror of
https://github.com/tiennm99/miti99bot.git
synced 2026-08-23 22:27:03 +00:00
docs(stock): record stock info delivery
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
# Stock Info Command
|
||||
|
||||
**Date**: 2026-07-23 12:25
|
||||
**Severity**: Medium
|
||||
**Component**: `stock` module, SSI quote client, command docs/tests
|
||||
**Status**: Resolved
|
||||
|
||||
## What Happened
|
||||
|
||||
We added a new read-only `/stock_info <ticker>` command to show a compact SSI iBoard quote snapshot with company, exchange, current price, gain/loss since open, change versus reference price, open/high/low, and volume. `/stock_price` stayed unchanged on purpose.
|
||||
|
||||
The implementation had to be forced into a safer shape after review. The first pass reused the same SSI quote DTO for legacy price paths, which was a bad idea for an undocumented upstream schema. We split the detail response into its own DTO so the old decode path would not get dragged into the new fields, and we kept `/stock_price` on the existing fallback chain.
|
||||
|
||||
## The Brutal Truth
|
||||
|
||||
This was the kind of change that looks simple until it starts biting in review. The upstream API is undocumented, so every assumption becomes a liability. The frustrating part is that we had to spend time proving that the “easy” version would have been brittle: redirects, malformed fields, and bogus math all showed up as real failure modes. That is annoying, but it is also exactly why the extra guardrails were necessary.
|
||||
|
||||
## Technical Details
|
||||
|
||||
- `/stock_info` uses exactly one SSI GET and no KBS/VCI fallback.
|
||||
- Since-open change is computed from `matchedPrice - openPrice`; reference change remains separate.
|
||||
- Review blockers fixed:
|
||||
- separate SSI detail DTO to protect legacy `/stock_price` decoding
|
||||
- redirect refusal so the command cannot silently fan out into extra requests
|
||||
- finite-safe change math to avoid `Inf%`
|
||||
- explicit zero volume preserved as `0` while nil/invalid volume stays `N/A`
|
||||
- company/exchange text bounded so Telegram replies stay safe
|
||||
- Best-effort behavior is still required because SSI is undocumented.
|
||||
- Verification passed: focused stock tests, race tests, `go vet ./...`, `go build ./...`, `golangci-lint run`, and repository test gates.
|
||||
|
||||
## What We Tried
|
||||
|
||||
- Started with a shared quote structure and a direct SSI detail fetch.
|
||||
- Tightened the handler and formatting tests around the compact output.
|
||||
- Reworked the client after adversarial review exposed the legacy decode and redirect risks.
|
||||
|
||||
## Root Cause Analysis
|
||||
|
||||
The root mistake was treating an undocumented provider like a stable contract. That made the first design too optimistic: one shared DTO, unchecked redirect behavior, and derived math that assumed normal values. The code worked until review forced the ugly cases into the open.
|
||||
|
||||
## Lessons Learned
|
||||
|
||||
When the upstream schema is not under our control, isolate the new path instead of extending old contracts in place. Keep the user-facing command additive, keep the legacy command stable, and assume the provider will return missing, malformed, or absurd values.
|
||||
|
||||
## Next Steps
|
||||
|
||||
Keep `/stock_info` best-effort and monitor for SSI schema drift. If the upstream shape changes again, update only the detail path and leave `/stock_price` untouched. No migration work is needed; the owner is the stock module maintainer.
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
phase: 1
|
||||
title: Model SSI Quote Details
|
||||
status: completed
|
||||
priority: P2
|
||||
dependencies: []
|
||||
---
|
||||
|
||||
# Phase 1: Model SSI Quote Details
|
||||
|
||||
## Overview
|
||||
|
||||
Extend the existing SSI single-stock response with a read-only detailed quote
|
||||
model and a dedicated one-request fetch method. Do not change `FetchPrice`.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Functional: capture symbol, Vietnamese/English company name, exchange,
|
||||
matched/open/reference/high/low prices, and normal traded quantity from SSI.
|
||||
- Functional: perform one GET to `/stock/<ticker>` with existing SSI headers.
|
||||
- Functional: reject missing/non-positive matched price as `ErrNoPrice`.
|
||||
- Non-functional: preserve KBS/VCI/SSI fallback behavior for `FetchPrice` and
|
||||
batch portfolio pricing.
|
||||
|
||||
## Architecture
|
||||
|
||||
Add an SSI-specific quote DTO and dedicated fetch method on `PriceClient`.
|
||||
Reuse `newSSIRequest`, `doSSIJSON`, `baseURL`, and the shared HTTP client.
|
||||
The command receives the single decoded response directly; it never calls
|
||||
`FetchPrice`.
|
||||
|
||||
## Related Code Files
|
||||
|
||||
- Modify: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\internal\modules\stock\prices_ssi.go`
|
||||
- Modify: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\internal\modules\stock\prices_test.go`
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
1. Extend the SSI quote struct with only the fields used by `/stock_info`.
|
||||
2. Add a dedicated detailed-quote fetch method that issues one GET.
|
||||
3. Keep current `fetchSSIPrice`, `FetchPrice`, and `FetchPrices` contracts intact.
|
||||
4. Test path, headers, one-call count, decoded fields, invalid price, HTTP, and decode errors.
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- [x] Detailed quote fetch uses exactly one SSI GET.
|
||||
- [x] Required and optional fields decode without inventing fallback requests.
|
||||
- [x] Existing price and batch provider tests remain unchanged and pass.
|
||||
|
||||
## Risk Assessment
|
||||
|
||||
SSI is undocumented and may omit fields. Keep optional fields nullable by value
|
||||
and make the handler degrade to `N/A`; isolate the new method from trading and
|
||||
portfolio callers.
|
||||
@@ -0,0 +1,58 @@
|
||||
---
|
||||
phase: 2
|
||||
title: "Add Stock Info Command"
|
||||
status: completed
|
||||
priority: P2
|
||||
dependencies: [1]
|
||||
---
|
||||
|
||||
# Phase 2: Add Stock Info Command
|
||||
|
||||
## Overview
|
||||
|
||||
Register `/stock_info <ticker>` and render a compact, sender-independent quote
|
||||
snapshot from the Phase 1 SSI detail method.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Functional: exact syntax `/stock_info <ticker>` and public metadata `<ticker>`.
|
||||
- Functional: normalize ticker; handle usage, unknown ticker, no price, upstream,
|
||||
and decode failures with friendly replies.
|
||||
- Functional: show Vietnamese company name with English fallback, exchange,
|
||||
current price, since-open amount/percent, reference amount/percent,
|
||||
open/high/low, and normal traded quantity.
|
||||
- Non-functional: read-only, senderless, one SSI request, Telegram-safe text.
|
||||
|
||||
## Architecture
|
||||
|
||||
Create a narrow handler/formatter file. Calculate changes from matched price
|
||||
against positive open/reference prices; otherwise show `N/A`. Reuse existing
|
||||
VND, sign, and integer formatting where their output matches the command.
|
||||
|
||||
## Related Code Files
|
||||
|
||||
- Create: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\internal\modules\stock\stock_info.go`
|
||||
- Create: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\internal\modules\stock\stock_info_test.go`
|
||||
- Modify: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\internal\modules\stock\stock.go`
|
||||
- Modify: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\internal\modules\stock\handlers_test.go`
|
||||
- Modify: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\cmd\server\command_menu_test.go`
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
1. Implement exact argument validation and ticker normalization.
|
||||
2. Fetch with `chathelper.FetchContext` through the one-call SSI detail method.
|
||||
3. Format compact fields with signed amount/percent and `N/A` for unavailable comparisons.
|
||||
4. Register the command and update shared command-discovery expectations.
|
||||
5. Test calculations, signs, missing fields, company fallback, senderless use,
|
||||
request count, usage, no-price, and upstream errors.
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- [x] `/stock_info TCB` returns the agreed compact quote in one SSI call.
|
||||
- [x] Since-open and reference changes are mathematically correct and signed.
|
||||
- [x] `/stock_price` registration, output, and fallbacks remain unchanged.
|
||||
|
||||
## Risk Assessment
|
||||
|
||||
Avoid calling `FetchPrice` from the new handler because it can trigger multiple
|
||||
providers. Keep the detailed quote method private to the new command path.
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
phase: 3
|
||||
title: "Verify and Document"
|
||||
status: completed
|
||||
priority: P2
|
||||
dependencies: [1, 2]
|
||||
---
|
||||
|
||||
# Phase 3: Verify and Document
|
||||
|
||||
## Overview
|
||||
|
||||
Align public documentation and prove the new one-call command does not change
|
||||
existing quote, portfolio, event, or dividend behavior.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Functional: document syntax, compact fields, one-call SSI-only behavior, and
|
||||
best-effort upstream limitation in README.
|
||||
- Non-functional: satisfy focused, repository, race, vet, build, lint, and diff gates.
|
||||
|
||||
## Architecture
|
||||
|
||||
No new runtime behavior. Verify command metadata/usage/docs as one contract and
|
||||
exercise existing `/stock_price` plus portfolio quote callers as regressions.
|
||||
|
||||
## Related Code Files
|
||||
|
||||
- Modify: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\README.md`
|
||||
- Verify: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\internal\modules\stock\prices_test.go`
|
||||
- Verify: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\internal\modules\stock\stock_info_test.go`
|
||||
- Verify: `C:\Users\miti99\Workspaces\tiennm99\miti99bot\cmd\server\command_menu_test.go`
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
1. Update README with `/stock_info <ticker>` and its SSI-only behavior.
|
||||
2. Run `gofmt` and focused stock/server command-discovery tests.
|
||||
3. Run `go test -count=1 ./...` and stock race tests.
|
||||
4. Run `go vet ./...`, `go build ./...`, `golangci-lint run`, and `git diff --check`.
|
||||
5. Review all price callers and public contracts for unintended changes.
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- [x] README, registration metadata, handler usage, and tests match exactly.
|
||||
- [x] All focused and repository gates pass with no `/stock_price` regression.
|
||||
- [x] Review confirms one SSI call and no storage/schema/provider-fallback changes.
|
||||
|
||||
## Risk Assessment
|
||||
|
||||
The SSI endpoint is undocumented. Document best-effort behavior and keep the
|
||||
new surface additive so it can be removed without migration or data cleanup.
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
title: Stock Info Command
|
||||
description: >-
|
||||
Add a one-call SSI quote-detail command while preserving /stock_price and its
|
||||
provider fallbacks.
|
||||
status: completed
|
||||
priority: P2
|
||||
branch: main
|
||||
tags:
|
||||
- feature
|
||||
- stock
|
||||
- telegram
|
||||
- api
|
||||
blockedBy: []
|
||||
blocks: []
|
||||
created: '2026-07-23T03:17:04.304Z'
|
||||
createdBy: 'ck:plan'
|
||||
source: skill
|
||||
---
|
||||
|
||||
# Stock Info Command
|
||||
|
||||
## Overview
|
||||
|
||||
Add public `/stock_info <ticker>` for a compact SSI quote snapshot. The command
|
||||
uses exactly one SSI single-ticker GET and reports company, exchange, current
|
||||
price, since-open and reference changes, open/high/low, and volume. Existing
|
||||
`/stock_price`, batch quotes, portfolio valuation, and provider fallbacks stay
|
||||
unchanged.
|
||||
|
||||
## Phases
|
||||
|
||||
| Phase | Name | Status |
|
||||
|-------|------|--------|
|
||||
| 1 | [Model SSI Quote Details](./phase-01-model-ssi-quote-details.md) | Completed |
|
||||
| 2 | [Add Stock Info Command](./phase-02-add-stock-info-command.md) | Completed |
|
||||
| 3 | [Verify and Document](./phase-03-verify-and-document.md) | Completed |
|
||||
|
||||
## Dependencies
|
||||
|
||||
- No cross-plan dependencies; all existing stock plans are completed.
|
||||
- Reuse the current SSI request headers, client, timeout, and response envelope.
|
||||
- No storage, portfolio, stats, event, dividend, migration, or environment changes.
|
||||
|
||||
## Contract
|
||||
|
||||
- Syntax: `/stock_info <ticker>`.
|
||||
- One SSI request only; never fall back to KBS or VCI.
|
||||
- Missing optional quote fields render consistently as `N/A`.
|
||||
- A missing/non-positive matched price returns a friendly no-info response.
|
||||
|
||||
## Validation
|
||||
|
||||
- Focused provider/handler/metadata tests plus `/stock_price` regression coverage.
|
||||
- `go test -count=1 ./...`, stock race tests, `go vet ./...`, `go build ./...`,
|
||||
`golangci-lint run`, and `git diff --check`.
|
||||
|
||||
## Open Questions
|
||||
|
||||
None.
|
||||
@@ -0,0 +1,33 @@
|
||||
# PM Completion Report
|
||||
|
||||
- Plan: `Stock Info Command`
|
||||
- Plan status: `completed`
|
||||
- Date: `2026-07-23 12:24`
|
||||
|
||||
## Delivery
|
||||
|
||||
- Phase 1: completed
|
||||
- Phase 2: completed
|
||||
- Phase 3: completed
|
||||
- Plan summary aligned to verified implementation and harness evidence
|
||||
|
||||
## Evidence
|
||||
|
||||
- Focused stock and server tests passed
|
||||
- Stock race tests passed
|
||||
- Full repository test suite passed
|
||||
- `go vet` passed
|
||||
- `go build` passed
|
||||
- `golangci-lint run` passed with 0 issues
|
||||
- `git diff --check` passed
|
||||
- Live SSI quote verification passed
|
||||
|
||||
## Reconciliation
|
||||
|
||||
- No unresolved phase mappings
|
||||
- No blockers
|
||||
- No docs gap recorded in plan artifacts
|
||||
|
||||
## Next Step
|
||||
|
||||
- Main agent: finish any remaining implementation-plan closure work, then handle commit and push in the normal ship flow if still desired.
|
||||
Reference in New Issue
Block a user