Skip to content

feat: Update quiz stat and enhance on-demand quiz handling#74

Open
Bayashat wants to merge 10 commits into
mainfrom
fix/quiz-stats
Open

feat: Update quiz stat and enhance on-demand quiz handling#74
Bayashat wants to merge 10 commits into
mainfrom
fix/quiz-stats

Conversation

@Bayashat
Copy link
Copy Markdown
Owner

πŸ“ Description

πŸš€ Type of Change

  • πŸ› Bug Fix (Fix an issue)
  • ✨ New Feature (Add a new feature)
  • πŸ—οΈ Infrastructure (CDK/AWS resource changes)
  • ♻️ Refactoring (Code refactoring, no logic changes)
  • πŸ“š Documentation (Documentation update)

πŸ—οΈ Infrastructure Changes (Crucial)

  • Resources Created: (e.g., New DynamoDB Table, SQS Queue)
  • Resources Modified: (e.g., Increased Lambda Timeout, Changed IAM Role)
  • Resources Deleted: (e.g., Removed unused Lambda Function)
  • Cost Impact: (e.g., Will this increase monthly AWS bill?)

βœ… Checklist

  • I have performed a self-review of my code.
  • I have run pre-commit run --all-files locally and fixed all issues.
  • I have added/updated Unit Tests (pytest).
  • My changes do not generate new warnings.
  • (If Infra change) I have run cdk diff locally to verify changes.

πŸ”— Related Issues

  • Closes #
  • Related to #
  • Fixes #

Copilot AI review requested due to automatic review settings April 29, 2026 13:22
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 29, 2026

πŸ“Š Infrastructure Changes Preview (Zerde Telegram Bot)

This PR will modify the following AWS resources:

ℹ️ No infrastructure changes detected

This PR only contains code changes (Lambda functions, etc.)

πŸ“‹ Full CDK Diff Output
b'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n'
b'!!                                                                                                                   !!\n'
b'!!  Node 20 has reached end-of-life on 2026-04-30 and will no longer be supported in new releases after 2026-10-30.  !!\n'
b'!!  Please upgrade to a supported node version as soon as possible.                                                  !!\n'
b'!!                                                                                                                   !!\n'
b'!!  This software is currently running on node v20.20.0.                                                             !!\n'
b'!!  As of the current release of this software, supported node releases are:                                         !!\n'
b'!!  - ^24.0.0 (Planned end-of-life: 2028-04-30)                                                                      !!\n'
b'!!  - ^22.0.0 (Planned end-of-life: 2027-04-30)                                                                      !!\n'
b'!!  - ^20.0.0 (Planned end-of-life: 2026-04-30) [DEPRECATED]                                                         !!\n'
b'!!                                                                                                                   !!\n'
b'!!  This warning can be silenced by setting the JSII_SILENCE_WARNING_DEPRECATED_NODE_VERSION environment variable.   !!\n'
b'!!                                                                                                                   !!\n'
b'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n'
#0 building with "default" instance using docker driver

#1 [internal] load build definition from Dockerfile
#1 transferring dockerfile: 1.82kB done
#1 DONE 0.0s

#2 [internal] load metadata for public.ecr.aws/sam/build-python3.13:latest
#2 DONE 0.1s

#3 [internal] load .dockerignore
#3 transferring context: 2B done
#3 DONE 0.0s

#4 [1/2] FROM public.ecr.aws/sam/build-python3.13:latest@sha256:be015b4dbfce398c76feb589c307073a48aed25b6accee4db41a481b78a490d2
#4 DONE 0.0s

#5 [2/2] RUN     python -m venv /usr/app/venv &&     mkdir /tmp/pip-cache &&     chmod -R 777 /tmp/pip-cache &&     pip install --upgrade pip &&     mkdir /tmp/poetry-cache &&     chmod -R 777 /tmp/poetry-cache &&     mkdir /tmp/uv-cache &&     chmod -R 777 /tmp/uv-cache &&     pip install pipenv==2022.4.8 poetry==1.5.1 uv==0.6.9 &&     rm -rf /tmp/pip-cache/* /tmp/poetry-cache/* /tmp/uv-cache/*
#5 CACHED

#6 exporting to image
#6 exporting layers done
#6 writing image sha256:061e0ba905fce6c09d786a1a1e023320dc3da30ff1300cf2664af3760f85f75c done
#6 naming to docker.io/library/cdk-2f59e732e8ae4d02a5184d9228e694ce8e11ea332b6fffa637cf82fc00d887dc done
#6 DONE 0.0s
#0 building with "default" instance using docker driver

#1 [internal] load build definition from Dockerfile
#1 transferring dockerfile: 1.82kB done
#1 DONE 0.0s

#2 [internal] load metadata for public.ecr.aws/sam/build-python3.13:latest
#2 DONE 0.1s

#3 [internal] load .dockerignore
#3 transferring context: 2B done
#3 DONE 0.0s

#4 [1/2] FROM public.ecr.aws/sam/build-python3.13:latest@sha256:be015b4dbfce398c76feb589c307073a48aed25b6accee4db41a481b78a490d2
#4 DONE 0.0s

#5 [2/2] RUN     python -m venv /usr/app/venv &&     mkdir /tmp/pip-cache &&     chmod -R 777 /tmp/pip-cache &&     pip install --upgrade pip &&     mkdir /tmp/poetry-cache &&     chmod -R 777 /tmp/poetry-cache &&     mkdir /tmp/uv-cache &&     chmod -R 777 /tmp/uv-cache &&     pip install pipenv==2022.4.8 poetry==1.5.1 uv==0.6.9 &&     rm -rf /tmp/pip-cache/* /tmp/poetry-cache/* /tmp/uv-cache/*
#5 CACHED

#6 exporting to image
#6 exporting layers done
#6 writing image sha256:061e0ba905fce6c09d786a1a1e023320dc3da30ff1300cf2664af3760f85f75c done
#6 naming to docker.io/library/cdk-2f59e732e8ae4d02a5184d9228e694ce8e11ea332b6fffa637cf82fc00d887dc 0.0s done
#6 DONE 0.0s
#0 building with "default" instance using docker driver

#1 [internal] load build definition from Dockerfile
#1 transferring dockerfile: 1.82kB done
#1 DONE 0.0s

#2 [internal] load metadata for public.ecr.aws/sam/build-python3.13:latest
#2 DONE 0.1s

#3 [internal] load .dockerignore
#3 transferring context: 2B done
#3 DONE 0.0s

#4 [1/2] FROM public.ecr.aws/sam/build-python3.13:latest@sha256:be015b4dbfce398c76feb589c307073a48aed25b6accee4db41a481b78a490d2
#4 DONE 0.0s

#5 [2/2] RUN     python -m venv /usr/app/venv &&     mkdir /tmp/pip-cache &&     chmod -R 777 /tmp/pip-cache &&     pip install --upgrade pip &&     mkdir /tmp/poetry-cache &&     chmod -R 777 /tmp/poetry-cache &&     mkdir /tmp/uv-cache &&     chmod -R 777 /tmp/uv-cache &&     pip install pipenv==2022.4.8 poetry==1.5.1 uv==0.6.9 &&     rm -rf /tmp/pip-cache/* /tmp/poetry-cache/* /tmp/uv-cache/*
#5 CACHED

#6 exporting to image
#6 exporting layers done
#6 writing image sha256:061e0ba905fce6c09d786a1a1e023320dc3da30ff1300cf2664af3760f85f75c done
#6 naming to docker.io/library/cdk-2f59e732e8ae4d02a5184d9228e694ce8e11ea332b6fffa637cf82fc00d887dc done
#6 DONE 0.0s
start: Building zerde-serverless-telegram-bot-dev Template
success: Built zerde-serverless-telegram-bot-dev Template
start: Publishing zerde-serverless-telegram-bot-dev Template (current_account-current_region-f07c48c1)
success: Published zerde-serverless-telegram-bot-dev Template (current_account-current_region-f07c48c1)
Hold on while we create a read-only change set to get a diff with accurate replacement information (use --method=template to use a less accurate but faster template-only diff)

Stack ZerdeServerlessTelegramBotStack-dev (zerde-serverless-telegram-bot-dev)
Resources
[~] AWS::Lambda::LayerVersion ZerdeServerlessZerdeCommonLayer ZerdeServerlessZerdeCommonLayer41490F86 replace
 └─ [~] Content (requires replacement)
     └─ [~] .S3Key:
         β”œβ”€ [-] 0dcc5891de830f6f76afa33dfb31eed76e8777a2639f009c03225b20751af5e3.zip
         └─ [+] f8f2950830663974b9f717aca59d0b7537ee8cf4e11e3a77bb43eb681492056a.zip
[~] AWS::SQS::Queue ZerdeServerlessMessaging/ZerdeServerlessTimeoutTasksQueue ZerdeServerlessMessagingZerdeServerlessTimeoutTasksQueueF4025D17
 └─ [~] VisibilityTimeout
     β”œβ”€ [-] 180
     └─ [+] 1800
[~] AWS::Lambda::Function ZerdeServerlessBot/ZerdeServerlessBotLambda ZerdeServerlessBotZerdeServerlessBotLambdaA4D02A14
 β”œβ”€ [~] Code
 β”‚   └─ [~] .S3Key:
 β”‚       β”œβ”€ [-] df87ab2e1e02879d3be2c59b3598082f9e21c7b1efa245cdbe230096d7d9e4fb.zip
 β”‚       └─ [+] 21ce7df272fb44d8cf2ab46b857179461122b101e3c5983cd0bb5ccb2e6a2c63.zip
 └─ [~] Timeout
     β”œβ”€ [-] 90
     └─ [+] 300
[~] AWS::Lambda::Function ZerdeServerlessQuiz/ZerdeServerlessQuizLambda ZerdeServerlessQuizZerdeServerlessQuizLambda4D9EA339
 └─ [~] Code
     └─ [~] .S3Key:
         β”œβ”€ [-] d9d7c1ef28c4be304708c4a3e7fae5d324d5b70daf1c3eb4d2355715272c9f83.zip
         └─ [+] e2d6dd7fb44af1be6765cc98e84619cdca446c78ea57f416cbabe9764c82f643.zip



✨  Number of stacks with differences: 1

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the quiz stats presentation in the Bot Lambda and enhances Quiz Lambda on-demand (/genquiz) behavior by sourcing certain topics from the bank with an independent per-chat rotation queue.

Changes:

  • Extend /quizstats to display weekly score, season wins, and all-time score (and update localized strings accordingly).
  • Add a genquiz-specific DynamoDB-backed question queue and selection flow so /genquiz bank picks don’t interfere with daily rotation.
  • Introduce topic aliases mapping /genquiz topics (e.g. aws, clf-c02) to the banked cloud category, and adjust tests for the new output.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/test_quiz_handler.py Updates /quizstats test expectations for new fields and week-based ranking.
src/quiz/services/repository.py Adds DynamoDB read/write helpers for a genquiz-specific bank question queue.
src/quiz/services/quiz_service.py Adds bank-topic alias mapping and a genquiz bank-pick path with independent rotation seed/keys.
src/bot/services/handlers/quiz.py Passes new stat fields into the translation template for /quizstats.
src/bot/core/translations.py Updates quizstats_response strings across languages to the new stats layout/fields.

πŸ’‘ Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/quiz/services/quiz_service.py Outdated
Comment on lines +418 to +426
announcement = self.build_announcement(lang, difficulty, source_label=question.get("source_label"))
self._sender.send_message(str(chat_id), announcement)
poll_result = self._sender.send_quiz_poll(
chat_id=chat_id,
question=question["question"],
options=question["options"],
correct_option_id=question["correct_option_index"],
explanation=question.get("explanation"),
)
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

process_on_demand_quiz() sends the announcement for bank-sourced genquiz but ignores the return value of self._sender.send_message(...). Since send_message() returns None on failure, this can silently proceed to send a poll even when the announcement failed (unlike process_daily_quiz, which treats announcement failure as a hard failure). Consider checking the result and returning an error (or at least recording a failed step) to keep failure handling consistent and debuggable.

Copilot uses AI. Check for mistakes.
Comment on lines +228 to +244
def _pick_banked_question_for_genquiz(self, category: str, chat_id: str, difficulty: str) -> dict | None:
"""Pick the next on-demand question from the bank using a genquiz-specific per-chat queue.

Uses a different DynamoDB key and shuffle seed from the daily rotation so that
genquiz picks are unlikely to collide with upcoming daily questions.
Daily category queue is never read or written by this method.
"""
sources = _BANKED_CATEGORIES[category]
remaining = self._repo.get_genquiz_question_queue(category, chat_id)
if not remaining:
all_keys = self._repo.get_bank_question_ids(category, sources)
if not all_keys:
return None
# Different seed from daily ("genquiz:" prefix) β†’ different shuffle order
rng = random.Random(f"genquiz:{chat_id}::{len(all_keys)}")
remaining = rng.sample(all_keys, len(all_keys))
logger.info(
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_pick_banked_question_for_genquiz() duplicates almost all of _pick_banked_question_for_chat() with only the queue getter/saver and seed differing. This duplication increases the chance of the two paths drifting (e.g., bug fixes or new return fields added to one but not the other). Consider factoring out a shared helper that accepts the queue read/write functions and seed prefix, so both daily and genquiz bank selection stay in sync.

Copilot uses AI. Check for mistakes.
@Bayashat Bayashat deployed to development May 1, 2026 11:12 — with GitHub Actions Active
@Bayashat Bayashat deployed to production May 9, 2026 13:13 — with GitHub Actions Active
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants