docs: remove completed implementation records

This commit is contained in:
tiennm99 committed 2026-07-21 19:13:34 +07:00
1 parent d14b34d8ce
commit cc7dd4aa10
24 files changed
-1743

No files matched your search

@@ -1,31 +0,0 @@
# 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.
@@ -1,34 +0,0 @@
# 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.
@@ -1,33 +0,0 @@
# 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.
@@ -1,31 +0,0 @@
# 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.
@@ -1,67 +0,0 @@
# 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.
@@ -1,47 +0,0 @@
# Cross-Platform Go Workflow Journal
## Context
Removed Unix-oriented Make targets so Windows, macOS, and Linux contributors
can use the same standard Go workflow with platform-specific environment syntax.
## What Changed
- Deleted `Makefile` and replaced its development shortcuts with documented
`go test`, `go vet`, `go build`, `go run`, and direct Docker commands.
- Documented Telegram webhook inspection and cleanup with PowerShell
`Invoke-RestMethod` and POSIX `curl` examples.
- Deleted `telegram-commands.json`; the runtime module registry already builds
and registers the command menu on every startup, so the JSON duplicated the
authoritative Go definitions.
- Replaced Makefile linker flags with Go's embedded VCS build metadata and kept
the existing seven-character commit SHA behavior for deploy notifications.
- Updated CI and MongoDB test guidance to point contributors to the portable
README workflow.
## Reflection
Removing the task wrapper makes the repository less convenient for habitual
`make` users, but avoids maintaining shell-specific orchestration and duplicate
command-menu data. Standard Go, Docker, and HTTP tools keep each operation
explicit and work across supported development platforms.
## Decisions
- The Go module registry is the single source of truth for Telegram commands.
- Local binaries obtain their short revision from Go build information; the
deployment-provided `SOURCE_COMMIT` remains preferred at runtime.
- Platform differences are documented only where shell syntax or HTTP tooling
differs.
## Verification
- Passed: `go test ./...`
- Passed: `go vet ./...`
- Passed: `go build ./...`
- Unavailable: `golangci-lint run` because the binary is not installed.
## Next Steps
- Run the lint gate when `golangci-lint` is available.
- Keep command registration tests aligned with future public command changes.
@@ -1,51 +0,0 @@
# Testcontainers MongoDB Integration Journal
## Context
MongoDB integration tests previously depended on contributors manually starting
a database and setting `MONGODB_TEST_URL`. The suite now provisions its own
MongoDB 8 instances when Docker is available.
## What Changed
- Added Testcontainers Go and MongoDB module v0.43.0.
- Added a shared lazy test manager that starts one `mongo:8` container per
`storage`, `lol`, and `stats` package and terminates it after that package's
suite.
- Preserved `MONGODB_TEST_URL` as an external-database override.
- Docker-unavailable environments emit an explicit warning and skip MongoDB
tests; a regression test verifies both the warning and skip behavior.
- Once the Docker provider is healthy, container startup and connection-string
failures are fatal. Cleanup failures also make an otherwise passing suite
fail.
- Updated README and CI guidance so normal Go test commands exercise
Testcontainers automatically.
## Reflection
Package-scoped lazy containers balance isolation and startup cost: packages do
not share database processes, while tests inside a package avoid repeatedly
starting MongoDB. Distinguishing an absent Docker daemon from a broken healthy
provider keeps local no-Docker runs usable without hiding real infrastructure
regressions.
## Decisions
- Pin tests and local setup guidance to MongoDB 8.
- Keep explicit external MongoDB support for constrained or pre-provisioned
environments.
- Treat lifecycle failures as test failures whenever Docker is available.
## Verification
- Passed: `go test ./...`
- Passed: `go vet ./...`
- Passed: `go build ./...`
- Passed: `golangci-lint run`
- Passed: `go mod tidy` with no residual module diff.
- Three real MongoDB containers ran, one for each integration-test package, and
all three were cleaned up successfully.
## Next Steps
- Monitor CI duration and container startup reliability after rollout.
@@ -1,64 +0,0 @@
# 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
Telegram's native command menu and `/help` exposed only short descriptions,
leaving users to discover parameters through failed invocations or source
documentation.
## What Changed
- Extended the shared command registration with `Parameters` metadata and
presentation helpers used by both discovery surfaces.
- Added metadata for all 40 public commands, including the exact stats grammar:
`[users | user <username> | cmd <command_name>]`.
- Normalized placeholders to lowercase descriptive names, including meaningful
units or currencies; `[...]` marks optional input, `...` remaining free text,
and parentheses structured input.
- Normalized `/wheelofnames` to `<options(comma-separated)>` across metadata,
usage text, and tests.
- Finalized dividend placeholders as `<vnd_per_share> <ticker>`,
`<ratio(owned:new)> <ticker>`, and
`<vnd_per_share> <ratio(owned:new)> <ticker>` for cash, share, and combined
commands. Parsing remains unchanged.
- Native menu descriptions show parameters followed by the summary, while
`/help` renders the complete invocation followed by the summary. Neither
discovery surface includes example invocations. Dynamic fields are
HTML-escaped in `/help`.
- Registration validation rejects multiline metadata and public descriptions
over Telegram's 256-character limit.
- Updated user and deployment documentation for the shared registry behavior.
## Reflection
Keeping syntax beside each handler registration prevents the native menu,
`/help`, and implementation from drifting independently. Both discovery
surfaces stay compact without sacrificing safe HTML rendering in `/help`.
## Decisions
- Existing command names, handlers, parsers, and persisted data remain
unchanged; normalization is presentation-only.
- No command was added, renamed, or deleted, so no stats migration is needed.
- Discovery surfaces intentionally omit example invocations; handler usage
errors may still include focused examples.
- The complete `/help` output remains within Telegram's 4,096-character limit.
## Verification
- Passed: command presentation, validation, menu, and `/help` tests for all 40
public commands.
- Passed: `go test ./...`, including real MongoDB Testcontainers suites.
- Passed: `go vet ./...`
- Passed: `go build ./...`
- Passed: `golangci-lint run`
## Next Steps
- Require parameter metadata updates alongside future public command contract
changes.
@@ -1,44 +0,0 @@
# 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.
@@ -1,59 +0,0 @@
# Stock and Coin Cost Basis P&L Journal
## Context
Stock and coin portfolios tracked account funding and holdings but not the
remaining acquisition cost of each position, so they could not distinguish
realized sale results from unrealized open-position performance.
## What Changed
- Added persisted per-symbol total remaining `costBasis` to stock and coin
portfolios, with invariant checks on load, update, and save paths.
- Buys add actual spend; partial sells remove proportional weighted-average
basis and report realized P&L; full sells remove the position and its basis.
- Portfolio views now show average entry price and per-position unrealized P&L.
Account P&L remains total account value minus top-ups and is withheld when
missing quotes make valuation partial.
- Stock share dividends preserve total basis while increasing quantity; cash
dividends and top-ups remain outside position basis.
- Sorted, bounded portfolio replies retain summaries while omitting excess
position lines before Telegram's message limit.
## Migration Safety
- Enabled modules scan every portfolio before handlers are installed on every
boot, even when a completion marker already exists.
- Missing legacy basis is initialized from a complete current quote set, giving
each migrated position zero initial unrealized P&L without repricing rows that
already have basis.
- Versioned writes retry conflicts; the shared `system` marker is written only
after all rows succeed and remains an audit record rather than a scan bypass.
- A two-minute overall deadline bounds startup. Invalid data, noncanonical
symbols, missing quotes, exhausted conflicts, or storage failures abort
startup instead of allowing trades with unknown basis.
## Decisions
- Persist total remaining cost, deriving average entry price as basis divided by
held quantity; do not persist trade lots or cumulative realized P&L.
- Migrate only loaded modules, so disabled-module data waits until re-enabled.
- Preserve all command names, parameter contracts, and existing portfolio data.
## Verification
- Passed: focused stock and coin accounting, migration, output, and reply-budget
tests.
- Passed: MongoDB 8 Testcontainers migration and idempotency coverage.
- Passed: `go test ./...`
- Passed: `go vet ./...`
- Passed: `go build ./...`
- Passed: `golangci-lint run`
## Operational Impact
- Deployments with legacy holdings may perform market-price lookups and writes
during startup; a required provider or database failure intentionally keeps
the bot offline until initialization can complete safely.
- Subsequent healthy boots still verify invariants but do not reprice completed
positions.
@@ -1,87 +0,0 @@
---
type: technical-journal
topic: dividend-api-and-migration-cleanup
conducted_at: 2026-07-21T17:04:00+07:00
status: complete
---
# Dividend API and Migration Cleanup Journal
## Context
Portfolio schema migrations were verified complete in production, so their
compatibility code had become permanent startup and maintenance overhead. Coin
positions also inherited a stock-only dividend cursor with no valid use.
Separately, research was needed before designing automatic discovery of
Vietnamese stock dividend events.
## What Happened
- Removed `dividendCheckedAt` from coin positions, validation, buy behavior,
and tests. Stock retains the cursor because dividend events apply there.
- Retired completed stock and coin portfolio migrations plus the completed
stats command-renaming migration and their migration-only tests.
- Preserved recurring startup maintenance: stats query indexes and the LoL
match-cache TTL index remain idempotently initialized and tested.
- Preserved historical migration records in MongoDB's `system` collection and
kept the reusable `internal/systemstate` helper for future migrations.
- Removed legacy numeric-position JSON/BSON decoders after production schema
completion was confirmed. Current models now describe only the supported
nested asset schema.
- Accepted lazy cleanup of stale coin cursor fields. BSON decoding ignores the
old unknown field, and the next portfolio mutation uses versioned
`ReplaceOne`, rewriting that portfolio in the current shape without a new
one-time migration.
## Dividend API Research
SSI iBoard's corporate-actions endpoint is the recommended initial source. It
currently returns anonymous JSON with ticker/date filters, pagination, stable
`CorId` values, cash amounts, ratios, and event dates. It covered verified cash
and share dividend examples.
The endpoint is undocumented and has no published SLA, rate limit, or stability
contract. Any implementation should therefore isolate it behind a replaceable
provider, validate and locally classify events, deduplicate by `CorId`, and ask
the user to confirm before changing a portfolio. VSDC remains the authoritative
notice source; a licensed FiinGroup feed is the stronger future option if this
becomes production-critical.
## Decisions
- Keep dividend state stock-only; coin assets persist only `quantity` and
total remaining `base`.
- Remove completed one-time runtime code rather than continuing to scan already
migrated portfolios on every boot.
- Do not delete system history or general migration infrastructure.
- Do not introduce a cleanup migration solely for stale coin BSON fields;
normal writes remove them safely over time.
- Treat SSI iBoard as a replaceable prototype provider, not a guaranteed public
API contract.
## Verification
- Passed focused tests:
`go test -count=1 ./internal/modules/coin ./internal/modules/stock ./internal/modules/stats ./cmd/server`
- Passed full suite: `go test -count=1 ./...`
- MongoDB 8 tests executed and passed for stats indexes and the LoL TTL index.
- Passed: `go vet ./...`
- Passed: `go build ./...`
- Passed with zero issues: `golangci-lint run`
- Passed: `git diff --check` (expected LF/CRLF working-copy warnings only).
- Independent tester, debugger, and reviewer found no defects.
## Reflection
Migration code is operationally valuable only while incompatible data can
still exist. Removing it after verification narrows startup failure modes and
makes the active persistence contract explicit. Lazy removal is appropriate
for an ignored field because it does not affect reads or correctness; structural
schema changes still require guarded migrations.
## Next
Design the Telegram interaction for listing SSI dividend events, including date
windows, pagination, exact ratio conversion, ambiguity handling, and explicit
user confirmation. Preserve manual dividend commands and keep automatic event
application out of scope until that interaction is approved.
@@ -1,73 +0,0 @@
---
type: technical-journal
topic: stock-dividend-event-buttons
conducted_at: 2026-07-21T18:15:00+07:00
status: complete
---
# Stock Dividend Event Buttons Journal
## Context
`/stock_portfolio` needed to surface recent dividend events for held tickers
without obscuring the portfolio or silently changing financial state. SSI
iBoard was selected as a best-effort discovery source, while the existing
manual dividend commands remain available.
## What Happened
- The portfolio response is sent first. Each discovered cash or explicit share
dividend follows in its own message with an `Apply dividend` button; a ticker
with no relevant event produces no extra message.
- Added a replaceable SSI provider with pagination, local event classification,
stable event IDs, deduplication, and exact ratio handling.
- Added callback registration to the shared module framework and persisted
short-lived pending actions separately from portfolios.
- Successful checks advance `dividendCheckedAt`; failed checks leave the cursor
unchanged and never prevent the portfolio from being displayed.
- Added `openedAt` to distinguish the holding lifecycle and retained applied SSI
event identities for auditability and replay protection.
SSI discovery accepts only day-granularity date windows. Queries therefore use
a cursor overlap at the lower boundary, then locally filter and deduplicate the
returned events. This avoids missing events around a date boundary while stable
SSI event IDs prevent overlap from producing repeated actionable suggestions.
## Key Decisions
- Callback data carries an opaque random token, not trusted dividend values.
Pending actions expire after 24 hours and are bound to the requesting
Telegram user, originating chat, and event message.
- A callback reloads the current portfolio and calculates from the holding at
click time. Another group member, an expired action, or a holding sold and
reopened after suggestion creation cannot apply it.
- Applied SSI event IDs are recorded atomically with the portfolio mutation, so
duplicate clicks and retries cannot apply the same provider event twice.
- Event fetches occur outside the per-user mutation lock. Cursor persistence
reloads and merges under that lock, preserving concurrent buys, sells, and
manual dividends without holding a lock across network calls.
- Notification or provider failures do not advance the affected cursor. A later
portfolio request can safely retry rather than lose an event.
## Verification
- Focused stock and module tests passed.
- Full suite passed: `go test -count=1 ./...`.
- Stock race tests and 20-iteration concurrency stress tests passed.
- `go vet ./...` and `go build ./...` passed.
- `golangci-lint run` completed with zero issues.
- Independent testing, debugging, and code review found no blockers.
## Risks and Limitations
- SSI iBoard is undocumented and has no published stability or availability
guarantee; the provider can require replacement if its contract changes.
- The portfolio has no dated transaction lots, so current quantity is not proof
of record-date entitlement. Users must verify the issuer notice.
- Manual commands do not record an SSI event ID. Applying manually and later
accepting the related button can count the same dividend twice.
## Next
Observe SSI response stability and callback behavior in real use. Commit these
changes only if the user requests it.