Stats handlers reused the single bounded update context for both upstream
price fetches and the final Telegram reply, while per-upstream HTTP timeouts
equalled the whole-handler budget. One slow upstream drained the deadline and
the reply failed with "context deadline exceeded" (observed on /stock_stats).
- add chathelper.FetchContext: fetches run under a child context that reserves
a tail of the deadline for the reply, which is sent on the original context
- cap kbs/coin/gold/vnappmob HTTP timeouts at 3s so one hung upstream cannot
consume the reply budget
- fetch held stock/coin prices concurrently (bounded) so total latency tracks
the slowest single fetch instead of their sum; per-symbol failures degrade to
a "no price" line and the summary still sends
The CF→AWS data migration (closed 2026-05-16) is long done and the
tooling isn't wired into any production path. Remove the one-shot binary,
its support package, and the migration runbook.
In live code, replace 'JS-parity' / 'same shape as JS' / 'cross-runtime
KV migration' comments with the real, stable reason for each behavior
(wire-format invariant, null-vs-zero distinction, CloudWatch alarm field
name, etc.). 24 files touched across lolschedule, loldle, wordle, twentyq,
trading, misc, util, server, metrics, ai, keylock.
- delete cmd/migrate_cf_data/
- delete internal/migration/
- delete docs/cf-to-aws-migration-runbook.md
Telegram routes outgoing messages with no message_thread_id to a forum
supergroup's General topic. Commands sent in a topic were being answered
in General. chathelper.Reply / ReplyHTML now take *models.Message and
forward both ChatID and MessageThreadID; help.go SendMessage and
loldle trySendSticker do the same. Adds regression tests asserting the
field is forwarded for forum topics and omitted for private/regular groups.
Removes six modules (loldle-ability/emoji/quote/splash, semantle, doantu)
and prunes the framework deps that were only there to serve them:
- ai.Embedder + Client.Embed + embeddingModel const (semantle only)
- Deps.Embedder + BuildOptions.Embedder
- Deps.Env + Build(env) param + ModuleEnv config field + PHOW2SIM allowlist (doantu only)
- internal/champname package (loldle now owns its lookup helpers directly)
- template.yaml: Phow2simAPIURL parameter + PHOW2SIM_API_URL Lambda env
Active catalog: util, misc, wordle, loldle, lolschedule, twentyq, trading.
go build / vet / test all pass.
Phase 3 of the 2026-05-09 review remediation plan. Eliminates the
helper drift (subjectFor / argAfterCommand / nowMillis / reply /
replyHTML / winRate) that previously lived in 3-4 modules, plus the
loldle-specific normalize / findChampion / findByExactName.
- internal/modules/util/chathelper: SubjectFor, ArgAfterCommand,
NowMillis, Reply, ReplyHTML, WinRate. Single canonical SubjectFor
shape (group/supergroup -> chat ID, else user ID); WinRate uses
math.Round to match JS Math.round (the truncation drift caught in
Phase 5b/5c).
- internal/champname: Normalize + generic Find[T] / FindByExactName[T]
with name-extractor closure. Loldle and loldle-emoji both consume
via Champion / EmojiChampion.
Migrations: wordle, loldle, loldle-emoji, misc, util/info,
util/stickerid. Module-local lookup.go + normalize.go in loldle and
loldle-emoji deleted.
go test -race -count=1 ./... clean across all 12 packages. Net ~290
lines removed across handler files.