From 06eb6ae5e7e1333dad1988e3a8c672501506e339 Mon Sep 17 00:00:00 2001 From: Satoshi Qazi Muhammed Date: Tue, 21 Jul 2026 07:51:22 -0700 Subject: [PATCH 1/5] fix(ai): prioritize Groq's most stable model, stop repeating mining disclaimer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User decision after the Groq reliability fix (previous PR): prioritize Groq's smallest/fastest model, llama-3.1-8b-instant, over gpt-oss-120b — it's long out of preview and has historically the best free-tier availability, at the cost of gpt-oss-120b's better Turkish/Kurdish fluency (which is why it was chosen originally). Model order is now llama-3.1-8b-instant -> gpt-oss-120b -> llama-3.3-70b-versatile before the (currently uncredited) Anthropic fallback. Also fixed a real UX complaint: asking about the Mining Simulation made the model repeat "this isn't real mining / it's just an estimate" in nearly every paragraph. Added an explicit instruction to state that once, briefly, near the start of the answer, and not repeat it — verified live, the disclaimer now appears once per response instead of several times. --- package.json | 2 +- src/version.json | 6 +++--- supabase/functions/ask/index.ts | 21 ++++++++++++++------- supabase/functions/telegram-bot/index.ts | 21 ++++++++++++++------- 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index 15c6075..73458c5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pezkuwi-telegram-miniapp", - "version": "1.0.241", + "version": "1.0.242", "type": "module", "description": "Pezkuwichain Telegram Mini App - Forum, Announcements, Rewards", "author": "Pezkuwichain Team", diff --git a/src/version.json b/src/version.json index 9833611..89e672c 100644 --- a/src/version.json +++ b/src/version.json @@ -1,5 +1,5 @@ { - "version": "1.0.241", - "buildTime": "2026-07-21T14:31:14.612Z", - "buildNumber": 1784644274612 + "version": "1.0.242", + "buildTime": "2026-07-21T14:51:23.002Z", + "buildNumber": 1784645483003 } diff --git a/supabase/functions/ask/index.ts b/supabase/functions/ask/index.ts index 02d3395..ae74187 100644 --- a/supabase/functions/ask/index.ts +++ b/supabase/functions/ask/index.ts @@ -150,6 +150,7 @@ Inside the Trust Score card there is a small "Mining Simulation" square with a d - If your Trust Score is 0, the counter cannot start — the app shows a warning that your trust score must be greater than 0. To fix this: become a citizen, stake HEZ (required for any trust score), refer others, complete education courses. - Colors: red square = inactive (tap to start), gold = actively mining. - The small Telegram icon next to it opens the official channel: https://t.me/+DUWJ8wtt5qI4Njgy +- IMPORTANT — how to talk about this: state that it's a simulation/estimate ONCE, briefly, near the start of your answer, then move on and explain the rest normally. Do NOT repeat "this isn't real mining" / "it's just an estimate" / similar caveats in every paragraph — one clear mention is enough, repeating it reads as nagging. "BULUT ULUSU" (CLOUD NATION) — THE BOOK BEHIND PEZKUWICHAIN (chapter-by-chapter knowledge): PezkuwiChain's philosophical foundation is the book "Bulut Ulusu" (Cloud Nation), written by the project's architect (a software developer AND sociologist — the "two desks" of the opening chapter). Available in Turkish, English and Kurdish. Core theses: @@ -233,13 +234,19 @@ async function allowed(ip: string): Promise { // asked — confirmed live 2026-07-21 by hitting this endpoint repeatedly with // trivial questions ("merhaba") and seeing a ~50% failure rate with 15s+ // between calls (ruling out our own per-IP rate limiter above), which 2 -// retries on the same model did not fully fix. Falls back to -// llama-3.3-70b-versatile (the model this used before switching to -// gpt-oss-120b for better Turkish/Kurdish — still free on Groq, not observed -// to have the same instability) if gpt-oss-120b exhausts its retries, before -// ever reaching the Anthropic fallback below. Doesn't retry a 4xx (bad -// request/auth) at all — not transient, and switching models wouldn't help. -const GROQ_MODELS = ['openai/gpt-oss-120b', 'llama-3.3-70b-versatile']; +// retries on the same model did not fully fix. +// +// 2026-07-21, user decision: prioritize reliability over gpt-oss-120b's +// better Turkish/Kurdish fluency (it was picked for that reason via an +// earlier A/B test) — llama-3.1-8b-instant is Groq's smallest/fastest model +// and, being long out of preview, has historically the best free-tier +// availability, so it goes first. gpt-oss-120b stays as the 2nd attempt +// (still worth trying for quality when the primary is having its own bad +// moment), llama-3.3-70b-versatile (the model used before switching to +// gpt-oss-120b) as the 3rd, before ever reaching the Anthropic fallback +// below. Doesn't retry a 4xx (bad request/auth) at all — not transient, and +// switching models wouldn't help. +const GROQ_MODELS = ['llama-3.1-8b-instant', 'openai/gpt-oss-120b', 'llama-3.3-70b-versatile']; async function callGroqWithRetry(messages: unknown[], retriesPerModel = 2): Promise { for (const model of GROQ_MODELS) { diff --git a/supabase/functions/telegram-bot/index.ts b/supabase/functions/telegram-bot/index.ts index 9326611..1033a87 100644 --- a/supabase/functions/telegram-bot/index.ts +++ b/supabase/functions/telegram-bot/index.ts @@ -230,6 +230,7 @@ Inside the Trust Score card there is a small "Mining Simulation" square with a d - If your Trust Score is 0, the counter cannot start — the app shows a warning that your trust score must be greater than 0. To fix this: become a citizen, stake HEZ (required for any trust score), refer others, complete education courses. - Colors: red square = inactive (tap to start), gold = actively mining. - The small Telegram icon next to it opens the official channel: https://t.me/+DUWJ8wtt5qI4Njgy +- IMPORTANT — how to talk about this: state that it's a simulation/estimate ONCE, briefly, near the start of your answer, then move on and explain the rest normally. Do NOT repeat "this isn't real mining" / "it's just an estimate" / similar caveats in every paragraph — one clear mention is enough, repeating it reads as nagging. "BULUT ULUSU" (CLOUD NATION) — THE BOOK BEHIND PEZKUWICHAIN (chapter-by-chapter knowledge): PezkuwiChain's philosophical foundation is the book "Bulut Ulusu" (Cloud Nation), written by the project's architect (a software developer AND sociologist — the "two desks" of the opening chapter). Available in Turkish, English and Kurdish. Core theses: @@ -274,13 +275,19 @@ License: Apache 2.0, Copyright 2026 Kurdistan Tech Institute. Lead Architect: Sa // asked — confirmed live 2026-07-21 by hitting this endpoint repeatedly with // trivial questions ("merhaba") and seeing a ~50% failure rate with 15s+ // between calls (ruling out our own per-IP rate limiter), which 2 retries on -// the same model did not fully fix. Falls back to llama-3.3-70b-versatile -// (the model this used before switching to gpt-oss-120b for better Turkish/ -// Kurdish — still free on Groq, and not observed to have the same instability) -// if gpt-oss-120b exhausts its retries, before ever reaching the Anthropic -// fallback below. Retries a 4xx (bad request/auth) not at all — that's not -// transient and switching models wouldn't help either. -const GROQ_MODELS = ['openai/gpt-oss-120b', 'llama-3.3-70b-versatile']; +// the same model did not fully fix. +// +// 2026-07-21, user decision: prioritize reliability over gpt-oss-120b's +// better Turkish/Kurdish fluency (it was picked for that reason via an +// earlier A/B test) — llama-3.1-8b-instant is Groq's smallest/fastest model +// and, being long out of preview, has historically the best free-tier +// availability, so it goes first. gpt-oss-120b stays as the 2nd attempt +// (still worth trying for quality when the primary is having its own bad +// moment), llama-3.3-70b-versatile (the model used before switching to +// gpt-oss-120b) as the 3rd, before ever reaching the Anthropic fallback +// below. Retries a 4xx (bad request/auth) not at all — that's not transient +// and switching models wouldn't help either. +const GROQ_MODELS = ['llama-3.1-8b-instant', 'openai/gpt-oss-120b', 'llama-3.3-70b-versatile']; async function callGroqWithRetry( systemPrompt: string, From 54f565621c61da88d02d2efaecd6ebcd6ea62727 Mon Sep 17 00:00:00 2001 From: Satoshi Qazi Muhammed Date: Wed, 29 Jul 2026 20:21:37 -0700 Subject: [PATCH 2/5] fix(auth): namespace edge functions, restore miniapp sign-in MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Supabase edge-function volume on the host is shared with pwap-web, which deploys into it by rsyncing its whole tree. Both projects defined a function called telegram-auth, so on 2026-06-28 pwap-web's login-widget handler replaced this project's initData handler. Sign-in and every wallet screen behind it have returned 401 ever since; nothing failed loudly because the name still resolved. Rename this project's two colliding functions to a tgm- namespace so the two deploys can no longer reach the same directory, and point the client at the new name. process-withdraw is renamed too: it is currently unreferenced here, but it moves platform funds, so leaving it shadowed by another project's version is not something to keep. Also deploy functions from CI. They were last pushed by hand in April, so seven of them had drifted behind the repo and one had never shipped at all. The new step writes through the host's ownership gate, which refuses any name this project does not own — the drift and the collision both stop here. Ownership is recorded in /opt/supabase-self-hosted/functions-registry.json. --- .github/workflows/deploy.yml | 41 +++++++++++++++++++ package.json | 2 +- src/lib/supabase.ts | 5 ++- src/version.json | 6 +-- .../index.ts | 0 .../index.ts | 0 6 files changed, 49 insertions(+), 5 deletions(-) rename supabase/functions/{process-withdraw => tgm-process-withdraw}/index.ts (100%) rename supabase/functions/{telegram-auth => tgm-telegram-auth}/index.ts (100%) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index a563e46..2740ea9 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -63,3 +63,44 @@ jobs: username: ${{ secrets.VPS2_USER }} key: ${{ secrets.VPS2_SSH_KEY }} script: bash /opt/cleanup-miniapp.sh + + # Edge functions live in a Supabase volume shared with other projects, so they + # are written through the ownership gate on the host rather than copied in + # directly. The gate refuses any name this project does not own, which is what + # stops a repeat of the 2026-06-28 incident where another project's deploy + # silently replaced telegram-auth and broke sign-in for a month. + deploy-functions: + name: Deploy edge functions + needs: deploy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Package functions + run: tar czf functions.tgz -C supabase functions + + - name: Copy to staging on VPS + uses: appleboy/scp-action@v1.0.0 + with: + host: ${{ secrets.VPS2_HOST }} + username: ${{ secrets.VPS2_USER }} + key: ${{ secrets.VPS2_SSH_KEY }} + source: 'functions.tgz' + target: '/opt/miniapp-deploy-staging' + + - name: Deploy through ownership gate + uses: appleboy/ssh-action@v1.0.0 + with: + host: ${{ secrets.VPS2_HOST }} + username: ${{ secrets.VPS2_USER }} + key: ${{ secrets.VPS2_SSH_KEY }} + script: | + set -e + BASE=/opt/miniapp-deploy-staging + trap 'rm -rf "$BASE"' EXIT + rm -rf "$BASE/functions" + tar xzf "$BASE/functions.tgz" -C "$BASE" + supabase-deploy-functions \ + --project pezkuwi-telegram-miniapp \ + --src "$BASE/functions" \ + --restart diff --git a/package.json b/package.json index 73458c5..6fd93af 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pezkuwi-telegram-miniapp", - "version": "1.0.242", + "version": "1.0.243", "type": "module", "description": "Pezkuwichain Telegram Mini App - Forum, Announcements, Rewards", "author": "Pezkuwichain Team", diff --git a/src/lib/supabase.ts b/src/lib/supabase.ts index ab4e436..72091c8 100644 --- a/src/lib/supabase.ts +++ b/src/lib/supabase.ts @@ -11,7 +11,10 @@ export async function signInWithTelegram(initData: string) { throw new Error('No Telegram initData provided'); } - const { data, error } = await supabase.functions.invoke('telegram-auth', { + // Namespaced: the shared Supabase instance also hosts pwap-web, whose own + // login-widget handler owns the bare 'telegram-auth' name. See + // /opt/supabase-self-hosted/functions-registry.json on the host. + const { data, error } = await supabase.functions.invoke('tgm-telegram-auth', { body: { initData }, }); diff --git a/src/version.json b/src/version.json index 89e672c..7d8739d 100644 --- a/src/version.json +++ b/src/version.json @@ -1,5 +1,5 @@ { - "version": "1.0.242", - "buildTime": "2026-07-21T14:51:23.002Z", - "buildNumber": 1784645483003 + "version": "1.0.243", + "buildTime": "2026-07-30T03:21:37.873Z", + "buildNumber": 1785381697873 } diff --git a/supabase/functions/process-withdraw/index.ts b/supabase/functions/tgm-process-withdraw/index.ts similarity index 100% rename from supabase/functions/process-withdraw/index.ts rename to supabase/functions/tgm-process-withdraw/index.ts diff --git a/supabase/functions/telegram-auth/index.ts b/supabase/functions/tgm-telegram-auth/index.ts similarity index 100% rename from supabase/functions/telegram-auth/index.ts rename to supabase/functions/tgm-telegram-auth/index.ts From 35723996e141a1a42d35fd005d937daf973062a3 Mon Sep 17 00:00:00 2001 From: Satoshi Qazi Muhammed Date: Wed, 29 Jul 2026 21:55:01 -0700 Subject: [PATCH 3/5] chore: keep version at 1.0.243 The merge resolution took main's 1.0.242 for the version stamp, which moves it backwards from this branch. Restore 1.0.243. --- package.json | 2 +- src/version.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 73458c5..6fd93af 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pezkuwi-telegram-miniapp", - "version": "1.0.242", + "version": "1.0.243", "type": "module", "description": "Pezkuwichain Telegram Mini App - Forum, Announcements, Rewards", "author": "Pezkuwichain Team", diff --git a/src/version.json b/src/version.json index 89e672c..be8ebc1 100644 --- a/src/version.json +++ b/src/version.json @@ -1,5 +1,5 @@ { - "version": "1.0.242", + "version": "1.0.243", "buildTime": "2026-07-21T14:51:23.002Z", "buildNumber": 1784645483003 } From 41bfd7032292ed1da0601f0d413db85af2d9c774 Mon Sep 17 00:00:00 2001 From: Satoshi Qazi Muhammed Date: Wed, 29 Jul 2026 22:36:06 -0700 Subject: [PATCH 4/5] feat(db): add ai_chat_log so the ask endpoint is actually rate limited `ask` has never been deployed, and the CI step in this branch will publish it. Its limiter counts rows in ai_chat_log to cap requests at 8/min and 120/day per IP, but no migration ever created that table, and the limiter fails open when the count cannot be read. Shipping `ask` without this would put an unauthenticated endpoint with Access-Control-Allow-Origin: * in front of paid model APIs with no limit at all. Applied to the live database as well. --- supabase/migrations/20260730_ai_chat_log.sql | 28 ++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 supabase/migrations/20260730_ai_chat_log.sql diff --git a/supabase/migrations/20260730_ai_chat_log.sql b/supabase/migrations/20260730_ai_chat_log.sql new file mode 100644 index 0000000..025bb71 --- /dev/null +++ b/supabase/migrations/20260730_ai_chat_log.sql @@ -0,0 +1,28 @@ +-- Rate-limit ledger for the public `ask` edge function (news.pex.mom assistant). +-- +-- `ask` is unauthenticated and sends `Access-Control-Allow-Origin: *`, so this +-- table is its only throttle: 8 requests per IP per minute, 120 per day. The +-- limiter counts rows here and fails open when the count cannot be read, which +-- means shipping `ask` without this table would leave a public endpoint calling +-- paid model APIs with no limit at all. + +create table if not exists public.ai_chat_log ( + id bigserial primary key, + ip text not null, + created_at timestamptz not null default now() +); + +-- The limiter always filters on both columns together (ip = ? and created_at >= ?). +create index if not exists ai_chat_log_ip_created_at_idx + on public.ai_chat_log (ip, created_at desc); + +-- Only the service role touches this table; the function reaches it through +-- PostgREST with the service key, which bypasses RLS. Enabling RLS without any +-- policy therefore keeps the behaviour intact while denying anon and +-- authenticated clients, who have no reason to read a table of IP addresses. +alter table public.ai_chat_log enable row level security; + +revoke all on public.ai_chat_log from anon, authenticated; + +comment on table public.ai_chat_log is + 'Rate-limit ledger for the public ask endpoint. Holds IP addresses; prune rows older than the 24h window the limiter uses.'; From 6c9883b858dae976e915f830e818b0499432a785 Mon Sep 17 00:00:00 2001 From: Satoshi Qazi Muhammed Date: Wed, 29 Jul 2026 23:35:31 -0700 Subject: [PATCH 5/5] fix(bot): keep the PEX.network button in the DKS welcome MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The button is live but has never existed in this repo — `git log -S "Buy/Sell Crypto"` returns nothing, so it was added by hand on the server and missed when 9bb9d2c synced git with the deployed source. Deploying telegram-bot from CI would therefore have silently dropped it. Restoring it here keeps what is actually running. Removing it should be a deliberate decision, not a side effect of the first automated deploy. --- supabase/functions/telegram-bot/index.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/supabase/functions/telegram-bot/index.ts b/supabase/functions/telegram-bot/index.ts index 1033a87..1586e33 100644 --- a/supabase/functions/telegram-bot/index.ts +++ b/supabase/functions/telegram-bot/index.ts @@ -563,6 +563,12 @@ async function sendDksWelcome(token: string, chatId: number) { web_app: { url: MINI_APP_URLS.dks }, }, ], + [ + { + text: '💱 Buy/Sell Crypto — PEX.network', + url: 'https://pex.network', + }, + ], [ { text: '📢 Join Channel / Kanalê Tev Bibin',