📜 Recent updates

What we shipped lately. We update Kaching multiple times per week — every change is git-tracked and public.

polish Wave-2 — F-6 today verdict+order, all getUserLang sites, smoke green
2026-05-21

Operator: '繼續修,追求完美' (continue, pursue perfection). All Wave-1 queued items shipped + live-verified in zh-Hant via Telegram Web. F-6 — /today now correct - bot.command('today'): ORDER BY desc(ev_score) — was returning insertion-order top-3 which on staging happened to be 3 RED zero-EV traps. Now surfaces GREEN/YELLOW/RED in EV-desc order. - card-line FTL × 5 locales: add {$verdict} param so e

e7b3dc0
fix user.lang honored across bot handlers + bundle rebuild + deploy:staging branch fix
2026-05-21

Staging smoke test 2026-05-21 found 8 bugs. This commit lands 4 in-session fixes; 4 remain queued. Fixed (this commit): F-1 i18n bundle staleness packages/i18n/src/bundle.generated.ts was 2026-05-20 00:43; iter-7/8 FTL edits never re-bundled. translate() returned empty for any new key → ctx.reply(empty) silently rejected by Telegram. Bundle now regenerated (262 keys × 5 locales). F-3 dep

10de914
docs v2.1 — N-bot future architecture appendix
2026-05-21

Per operator question: can a second formal bot point to same content backend? Can staging bot be promoted to another prod? Answer: yes. Appendix documents the path; deferred to Phase 6+ (not blocking Phase 3 single-bot cutover). Sections: - Why N-bot is well-supported (Telegram user_id global, etc.) - 3 code changes (env vars + webhook routing + schema migration 0010) - Push routing pseudocode (r

2e7fbdd
docs v2 — full-replacement strategy with mars2049.online as canonical domain
2026-05-21

Operator pivot 2026-05-21: - User accepts full brand swap (was: worried about losing 10-20k users by changing name). Original team unreachable → no chat_id list will arrive. - Goal: leverage every existing asset, replace everything else. Discovery delta (over v1): - `mars2049.online` is operator-owned (GoDaddy, exp 2027-03), DNS already on Cloudflare (brady.ns + iris.ns). 1.7 years runway, ze

b386c7d
docs inventory all Kaching Keychain entries
2026-05-21

Per operator request: sync all records / passwords / knowledge (including ad marketing config) to Keychain; produce single index doc. Added 17 operational references to Keychain alongside the 11 true-secret entries already there: True secrets (11): - Cloudflare API Token (pre-existing) - kaching-bot-token (legacy staging) - kaching-mars2049-bot-token (Mars2049 prod) - kaching-bot-webhook-secret

c4f10e3
docs Mars2049 → Kaching bot migration transition plan
2026-05-21

Discovery phase complete (read-only; no Telegram-side or worker-side changes made). Captured via Bot API + @BotFather UI inspection through Chrome MCP. Token + old webhook URL stashed in Keychain only. Key findings (legacy state): - Bot id 7949511493, username @Mars2049_Bot, display "Mars2049_Bot" - has_main_web_app: true; menu button URL = https://mars-launch.miniapp.mobi/ with label "Play"; s

934f540
feat client-side reward completion + dashboard config wired
2026-05-21

Pulled from operator's GigaPub partner dashboard (app 760): - BLOCK_ID = "main" (the single Active placement in app 760) - PROJECT_ID = 760 (the app id, used by client SDK script tag) - Integration model per docs.giga.pub/integration-guide.html: pure client- side reward. `<script src="https://ad.gigapub.tech/script?id=760">` loads SDK; `window.showGiga('main').then()` fires after user watche

47ca995
feat swap Adsgram+Monetag → GigaPub (single provider)
2026-05-21

User direction: actual ad provider is GigaPub, not Adsgram/Monetag (which were design-doc placeholders we never signed up for). Code changes: - packages/ad-mediation/src: AdEnv now exposes GIGAPUB_BLOCK_ID + GIGAPUB_HMAC_SECRET (was ADSGRAM_* + MONETAG_*). AdNetwork type union is just 'gigapub' now. requestAdSlot routes to gigapub when block id is set, no_fill otherwise. handleCompletion no

2ef9708
deploy create kaching-app Pages + 3 HMAC secrets + script drift fix
2026-05-21

User: "整個 Kaching 產品可以送審上架了的要求 ... 你自己去鑰匙圈找" — full authority to use CF API token from Keychain and execute operator-tier setup that I CAN do (skipping items that require buying domains, signing up to third-party services, or having two Telegram accounts). Closed prod blockers: - Cloudflare Pages `kaching-app` project created (production-branch=main); mini-app-web built + deployed; all 9 critic

5258915
polish close final 2 caveats — C-4 multi-lang + E-1 slot.report
2026-05-21

User: "全自動,到完成" — autonomous run to finish all closure-plan items. C-4 (api-wired 9→10) — multi-lang data-model Path A: - migrations/0009_bonuses_multilang.sql: 10 NULL-able TEXT columns added to bonuses (title_{en,ja,vi,zh_hans,zh_hant} + summary_{...}) so the spec at 13-data-model.md matches code; rollback = drop or ignore (NULL fallback) - packages/db/src/schema.ts mirrors - apps/collector

8f7d7b3
polish close 5/7 design-docs-alignment caveats under full authority
2026-05-21

User invoked polish-loop --scope=design-docs-alignment --authority=full --apply-closure-plan=2026-05-21. Took recommended Path A on each decision item. Closed: - D-2 (dark-pattern-free 9→10): responsible-gambling.astro:40 + terms.astro:28 rewritten — removed over-promised "we honour their network's GAMSTOP/OASIS" line; replaced with truthful aggregator-stance ("not a licensed operator; /set

ace46b3
docs inventory design-docs-alignment caveats + per-item resolution path
2026-05-21

Audit of docs/polish-locks/design-docs-alignment.lock.yaml § caveats: - 2 SUPERSEDED (C-3 markers 5/6 closed via FLEET-N-024 tracker; C-5 M10 API done in 12b) - 1 partial-superseded (D-1 Cashback M14 — iter-6 RG gate + $20 cap landed; structural residual still user A/B) - 4 real-open (C-1 plural expansion 0.3d / C-2 CI guard 0.5d / C-4 multi-lang data-model 1.0d / D-2 GAMSTOP retract 0.1d) - 1 ext

28831b5
ops provision 5-locale commands + description + short_description via Bot API
2026-05-21

Closes "Telegram bot register" operator action in docs/external-actions.md. All commercial-grade bot directory metadata now set without computer-use intervention (Bot API calls only). ## Completed via Bot API today (session 454) - `setMyCommands` × 5 locales (default + zh + en + ja + vi), 11 cmds each: start / today / search / invite / streak / quest / subscribe / lang / settings / help / sto

e5aebf4
docs close M-6 marker — link 00-scenarios.md:344 + tracker to commit 21c2611
2026-05-21

Companion to 21c2611 (feat: DEFAULT_RTP_BY_GAME constant) — closes the documentation side of FLEET-N-024 M-6 marker: - 00-scenarios.md:344 ⚠️ TO VERIFY → 📌 RESOLVED with full house_edge defaults table + override path + cross-link to code - FLEET-N-024-tracker.md M-6 row status → ✅ closed; summary 4/6 → 5/6 closed; open count 2 → 1 (only M-4 slot.report API remains, external dependency defe

d7d2890
feat FLEET-N-024 M-6 — DEFAULT_RTP_BY_GAME constant + collector wiring
2026-05-21

Closes M-6 (house_edge defaults) — the last code-side marker in FLEET-N-024. M-4 (slot.report API shape) remains open, deferred to Phase F collector sprint (requires external API probe, not codifiable in this cycle). ## Changes - `packages/ev-calculator/src/index.ts`: NEW exported const `DEFAULT_RTP_BY_GAME` with industry-standard RTPs per FLEET-N-024 § M-6 product decision (slot 0.96, table

21c2611
fix /user/me composite — add missing stats sub-object + provision prod secrets
2026-05-20

Self-audit revealed two drifts between claimed-shipped and actual-running: ## /user/me composite missing `stats` Actor A iter-7 P3 claim: 8-key composite (profile + preferences + stats + streak + quests + cashback + badges + rg_status). E2E probe confirmed only 7 keys — stats was named in the return shape but never wired. Fixed: 3 sub-query aggregate via c.env.DB.prepare() (1 D1 sub-request): -

e2a7d7f
ops Phase 1 ASO + locale drafts — 3 platforms × 3 locales
2026-05-20

Drafts written for product-ops Phase 1 (ASO + locale): - 01-aso/tg-miniapp.md: BotFather description + about + commands + welcome message × zh-Hant / en / ja - 01-aso/web.md: meta title + description + OG cards for /, /bonuses, /operators × zh-Hant / en / ja - 01-aso/seo.md: 10 target keywords × 3 locales (manual since no GSC MCP); content pillars (EV literacy / freshness / trust); on-pag

a61ef45
ops Phase 0 pre-submit audit — DOGFOOD product-ops v1.0
2026-05-20

First real run of product-ops skill on this project. Phase 0 actions: - Triaged gitleaks 15 hits → all false-positive (i18n key field patterns: badge-streak-30-criteria etc.). Added .gitleaks.toml allowlist for the specific paths + regex patterns. Re-scan: 0 leaks. - Leveraged iter-8 polish-loop work (CHANGELOG + 4 design docs, 1,617 lines) for release-readiness / editor/vc/vet-eye / i18n-n

85686d2
deploy 3 Workers × 2 envs + R2 lifecycle + smoke green
2026-05-20

iter-8 Actor A + B all deployed end-to-end. Smoke tests green; DLQs bound; R2 lifecycle applied to 4 buckets. Fixed scripts/apply-r2-lifecycle.sh — wrangler 4.x renamed `r2 bucket lifecycle put` → `set`. Verified-by-session: 421_gambli_path-a-iter-5-me-search-3-band

63fc6f0
fix storage GC + perf N+1 + Queue consumer + R2 lifecycle
2026-05-20

Actor B closes the perf + storage gaps surfaced by iter-8 audit (D1 perf 6 / storage-GC 6 / quota-guards 6 — alongside Actor A P0 critical fixes in 4ae74c6). ## Storage GC (4 sub-tasks) ### SG-A — gdpr-finalize.ts cron (NEW) Runbook docs/design/26-runbooks/gdpr-delete-request.md:41 referenced this file but it didn't exist. Created daily 03:00 UTC cron in apps/collector-cron: - Query users WHERE

b1a618e
fix 14 critical fixes — dailyMaintenance bug + RG enforcement + webhook HMAC + bot drift
2026-05-20

iter-8 4 deep critics (D1 perf / storage-GC / quota-guards / product-completion) all returned 6-7 (NOT just polish — found real production bugs + security gaps). Actor A pass closes the 14 P0 items. ## CB-1 — dailyMaintenance bug (PRODUCTION-CORRUPTING) collector-cron line 329 `UPDATE bonuses SET status='expired' WHERE status='active'` — missing `AND expiry < unixepoch()`. EVERY cron tick wiped a

4ae74c6
deploy mini-app-api both deployed; mini-app-web staging up
2026-05-20

Phase F-5 staging deploy complete. Path A end-to-end live on staging. ## Deployments - mini-app-api staging: kaching-mini-app-api-staging (v a1b5a7be...) - mini-app-api prod: kaching-mini-app-api-prod (v e4ae1eb3...) - mini-app-web staging: https://8eef930e.kaching-app-staging.pages.dev ## Smoke verification - /healthz: 200 OK (both envs) - /api/v1/public/stats: 200 OK + valid JSON - /api/v1/

fe58233
docs F-3 + F-4 — 14-api-contract polish + FLEET-N-024 4/6 closed
2026-05-20

Iter-7 api-wired-deep critic returned 7 (estimated 9). Closed remaining doc gaps in one pass. ## F-3 — Spec sync (14-api-contract.md +599/-117) ### Path renames spec → prod-aligned (4 patterns) - /user/quests → /user/quest (singular) - /user/quests/:id/claim → /user/quest/claim with body {user_quest_id} - /user/ad/serve → /user/ad/request - /user/stars/invoice → /user/subscribe/invoice - Removed

9d4bcc5
chore final pre-pivot hex sweep — 4 leftover literals after bulk re-skin
2026-05-20

Phase F-2 actor pass found the bulk UI re-skin already in (commits f83c8df + 8fbba5b from concurrent session). 4 pre-pivot literals slipped past: - apps/mini-app-web/public/styles/tokens.css:29 — `--tg-theme-destructive-text-color: #d14e4e` → `#ef4444` (Path A canonical red) - apps/mini-app-web/src/pages/bonus/[id].astro — unused `verdictColorClass` removed (typecheck hint cleanup) - apps/mini-ap

b0ed2e9
design cosmic hero + /bonuses index page + zh-Hant copy split
2026-05-20

- index.astro: rebuilt with cosmic SVG radar hero (Path A), copy split via isZh heuristic (5-locale Fluent bundle migration to follow) - bonus/[id].astro: editorial detail layout, sticky claim CTA with emerald glow restraint (one per viewport) - BonusCard.astro, Layout.astro: cosmic accent integration - bonuses.astro (NEW): /bonuses listing landing page wired to API - path-a-patterns.css (NEW)

f83c8df
feat Path A regression-lock — pre-pivot hex can't sneak back
2026-05-20

After the 2026-05-19 Path A pivot (Kaching Green #28a85c → Kaching Emerald #10b981, deep navy #0a1730 → #0a0f1f), the spec tokens lived only in prototypes/tokens/{tokens.ts,tokens.css} with no automated guard against accidental rollback. With 100+ files touching design docs in this round, a stale paste could easily reintroduce the retired palette unnoticed. Add @kaching/brand-tokens — tiny packag

8fbba5b
fix 0006 v2 — sentinel-zero pivot after FK rebuild rejection; staging + prod migrated
2026-05-20

v1 0006_user_rg_and_nullable_age.sql attempted SQLite table-rebuild to make `users.age_confirmed_at` NULL-able. D1 rejected at commit: FOREIGN KEY constraint failed: SQLITE_CONSTRAINT (extended: 7500) D1 enforces FK at tx commit even with `PRAGMA foreign_keys=OFF`. Other tables (user_preferences / streaks / quests / cashback_credits / referrals / etc.) reference users.telegram_id → rebuild chur

a974a28
design Path A T1/T2/T3 landed via autonomous Claude Design driver — layout-hierarchy 9→10
2026-05-20

polish-loop v4 design-driver-protocol executed end-to-end via Chrome MCP: navigate claude.ai/design → existing Kaching prototype → paste pushback message per `docs/design/design-requests/web-templates-pathA-followup.md` → poll → click Share → Handoff to Claude Code → capture URL → curl bundle → extract → README banner. ## Bundle - URL: https://api.anthropic.com/v1/design/h/vhBo6CUjY1TyErmKK6iZtw

a06d24c
api 4 production handler fixes — /auth/verify shape + /user/age-confirm + /user/me composite + /user/badges
2026-05-20

Iter-7 api-wired-deep critic (score 7, was estimated 9) found 4 spec↔prod handler gaps causing real user-facing failures. ## P1 — /auth/verify return shape (PRODUCTION-BLOCKING) Pre: returned {jwt, user} Post: returns {jwt, expires_at, user_id, age_confirm_required, rg_status: {self_excluded_until, cooloff_until}} The Mini App deep-link age gate (02-miniapp-spec § 1.5) requires age_confirm_requi

0a49f18
i18n 5-locale polish — banned emoji, ja brand voice, vi calques, zh loan-syntax, EV/wagering inline gloss
2026-05-20

Iter-7 three deep critics (i18n-localization 8 / api-wired-deep 7 / copy-clarity-per-locale 7) flagged ~15 mechanical locale text issues across 5 .ftl files. This commit addresses ALL locale polish; production code + spec sync fixes are next. ## Brand voice violations fixed ### Banned emoji 🎉 (brand spec 31-bot-uiux.md:70 hard ban on 🎉🎊🥳🤑) - subscribe-success / vip-upgraded / svip-upgraded

fe0390d