{"repo": "bayashat/zerde-serverless-bot", "files": {".github/workflows/deploy.yml": {"78c653c642fcfd4430e04e8299340425b7f431ce": {"t": 1785746338.2065327, "n": 8983, "h": "f92638feae0f3f66", "c": "name: Deploy to AWS\n\non:\n push:\n branches:\n - main\n\n workflow_dispatch:\n inputs:\n environment:\n description: \"Target Environment\"\n required: true\n default: \"dev\"\n type: choice\n options:\n - dev\n - prod\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n\njobs:\n deploy:\n name: Deploy to AWS\n runs-on: ubuntu-24.04-arm\n # Manual prod deploys require a GitHub Environment (e.g. \"production\") with approvers; dev is ungated.\n environment: ${{ (github.event_name == 'workflow_dispatch' && inputs.environment == 'prod') && 'production' || 'development' }}\n permissions:\n contents: read\n id-token: write\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n\n - name: Determine Target Environment\n id: determine-env\n run: |\n if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ]; then\n echo \"TARGET_ENV=${{ inputs.environment }}\" >> $GITHUB_ENV\n echo \"Selected manual deployment to: ${{ inputs.environment }}\"\n else\n echo \"TARGET_ENV=dev\" >> $GITHUB_ENV\n echo \"Push event detected. Defaulting deployment to: dev\"\n fi\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n # CLI (npm aws-cdk) version numbering != Python aws-cdk-lib; use a recent 2.1k+ CLI for schema support.\n - name: Install AWS CDK CLI (pinned)\n run: |\n npm install -g aws-cdk@2.1119.0\n uv run cdk --version\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n # API keys and tokens are stored in SSM Parameter Store โ CDK only needs non-secret config.\n - name: CDK Deploy\n working-directory: ./infra\n env:\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG || 'kk' }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE || 'https://api.telegram.org/bot' }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER || 'gemini' }}\n GEMINI_MODEL: ${{ vars.GEMINI_MODEL || 'gemini-3.1-flash-lite' }}\n NEWS_GEMINI_MODEL: ${{ vars.NEWS_GEMINI_MODEL || 'gemini-3.1-flash-lite' }}\n QUIZ_GEMINI_MODEL: ${{ vars.QUIZ_GEMINI_MODEL || 'gemini-3.1-flash-lite' }}\n WTF_GEMINI_MODEL: ${{ vars.WTF_GEMINI_MODEL }}\n GEMINI_RPD_LIMIT: ${{ vars.GEMINI_RPD_LIMIT || '500' }}\n GEMINI_EMBEDDING_RPD_LIMIT: ${{ vars.GEMINI_EMBEDDING_RPD_LIMIT || '1000' }}\n GEMINI_API_BASE: ${{ vars.GEMINI_API_BASE || 'https://generativelanguage.googleapis.com/v1beta/models' }}\n FALLBACK_MODEL: ${{ vars.FALLBACK_MODEL }}\n GROQ_MODEL: ${{ vars.GROQ_MODEL }}\n GROQ_API_BASE: ${{ vars.GROQ_API_BASE || 'https://api.groq.com/openai/v1' }}\n DEEPSEEK_MODEL: ${{ vars.DEEPSEEK_MODEL || 'deepseek-chat' }}\n DEEPSEEK_API_BASE: ${{ vars.DEEPSEEK_API_BASE || 'https://api.deepseek.com' }}\n SPAM_RULE_ENFORCE_THRESHOLD: ${{ vars.SPAM_RULE_ENFORCE_THRESHOLD || '0.8' }}\n SPAM_RULE_AI_THRESHOLD: ${{ vars.SPAM_RULE_AI_THRESHOLD || '0.15' }}\n SPAM_AI_CONFIDENCE_THRESHOLD: ${{ vars.SPAM_AI_CONFIDENCE_THRESHOLD || '0.85' }}\n SPAM_REVIEW_ADMIN_MENTIONS: ${{ vars.SPAM_REVIEW_ADMIN_MENTIONS || '{}' }}\n ADMIN_USER_ID: ${{ secrets.ADMIN_USER_ID }}\n CHATS_KK: ${{ vars.CHATS_KK }}\n CHATS_ZH: ${{ vars.CHATS_ZH }}\n CHATS_RU: ${{ vars.CHATS_RU }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n QUIZ_CHATS_KK: ${{ vars.QUIZ_CHATS_KK }}\n QUIZ_CHATS_ZH: ${{ vars.QUIZ_CHATS_ZH }}\n QUIZ_CHATS_RU: ${{ vars.QUIZ_CHATS_RU }}\n CAPTCHA_TIMEOUT_SECONDS: ${{ vars.CAPTCHA_TIMEOUT_SECONDS || '120' }}\n KICK_BAN_DURATION_SECONDS: ${{ vars.KICK_BAN_DURATION_SECONDS || '31' }}\n VOTEBAN_THRESHOLD: ${{ vars.VOTEBAN_THRESHOLD || '7' }}\n VOTEBAN_FORGIVE_THRESHOLD: ${{ vars.VOTEBAN_FORGIVE_THRESHOLD || '7' }}\n CAPTCHA_MAX_ATTEMPTS: ${{ vars.CAPTCHA_MAX_ATTEMPTS || '3' }}\n QUIZ_LLM_RPD: ${{ vars.QUIZ_LLM_RPD || '20' }}\n GROUP_MEMORY_ENABLED: ${{ vars.GROUP_MEMORY_ENABLED || 'true' }}\n GROUP_MEMORY_RECENT_LIMIT: ${{ vars.GROUP_MEMORY_RECENT_LIMIT || '300' }}\n GROUP_MEMORY_RETENTION_DAYS: ${{ vars.GROUP_MEMORY_RETENTION_DAYS || '3650' }}\n GROUP_MEMORY_DAILY_SUMMARY_DAYS: ${{ vars.GROUP_MEMORY_DAILY_SUMMARY_DAYS || '7' }}\n GROUP_MEMORY_DAILY_SUMMARY_MESSAGE_LIMIT: ${{ vars.GROUP_MEMORY_DAILY_SUMMARY_MESSAGE_LIMIT || '500' }}\n VECTOR_MEMORY_ENABLED: ${{ vars.VECTOR_MEMORY_ENABLED || 'true' }}\n VECTOR_MEMORY_PROVIDER: ${{ vars.VECTOR_MEMORY_PROVIDER || 's3_vectors' }}\n VECTOR_MEMORY_DIMENSIONS: ${{ vars.VECTOR_MEMORY_DIMENSIONS || '768' }}\n VECTOR_MEMORY_EMBEDDING_MODEL: ${{ vars.VECTOR_MEMORY_EMBEDDING_MODEL || 'gemini-embedding-2' }}\n VECTOR_MEMORY_INDEX_THROTTLE_SECONDS: ${{ vars.VECTOR_MEMORY_INDEX_THROTTLE_SECONDS || '3' }}\n VECTOR_MEMORY_BACKFILL_BATCH_SIZE: ${{ vars.VECTOR_MEMORY_BACKFILL_BATCH_SIZE || '50' }}\n VECTOR_MEMORY_MAX_DISTANCE: ${{ vars.VECTOR_MEMORY_MAX_DISTANCE || '0.85' }}\n VECTOR_MEMORY_VECTOR_BUCKET_NAME: ${{ vars.VECTOR_MEMORY_VECTOR_BUCKET_NAME }}\n VECTOR_MEMORY_INDEX_NAME: ${{ vars.VECTOR_MEMORY_INDEX_NAME }}\n AGENT_ENABLED: ${{ vars.AGENT_ENABLED || 'true' }}\n AGENT_BOT_USERNAME: ${{ vars.AGENT_BOT_USERNAME || '@zerde_kz_bot' }}\n AGENT_RECENT_CONTEXT_LIMIT: ${{ vars.AGENT_RECENT_CONTEXT_LIMIT || '100' }}\n AGENT_DAILY_PROACTIVE_LIMIT: ${{ vars.AGENT_DAILY_PROACTIVE_LIMIT || '10' }}\n AGENT_PROACTIVE_FINAL_THRESHOLD: ${{ vars.AGENT_PROACTIVE_FINAL_THRESHOLD || '0.72' }}\n AGENT_PROACTIVE_DECISION_GROQ_MODELS: ${{ vars.AGENT_PROACTIVE_DECISION_GROQ_MODELS || 'llama-3.1-8b-instant,meta-llama/llama-4-scout-17b-16e-instruct,qwen/qwen3-32b' }}\n AGENT_PROACTIVE_DECISION_CONTEXT_CHARS: ${{ vars.AGENT_PROACTIVE_DECISION_CONTEXT_CHARS || '4000' }}\n AGENT_PROACTIVE_DECISION_ALLOW_DEEPSEEK_FALLBACK: ${{ vars.AGENT_PROACTIVE_DECISION_ALLOW_DEEPSEEK_FALLBACK || 'false' }}\n AMBIENT_REACTIONS_ENABLED: ${{ vars.AMBIENT_REACTIONS_ENABLED || 'true' }}\n AMBIENT_REACTIONS_SAMPLE_RATE: ${{ vars.AMBIENT_REACTIONS_SAMPLE_RATE || '0.80' }}\n AMBIENT_REACTIONS_CONFIDENCE_THRESHOLD: ${{ vars.AMBIENT_REACTIONS_CONFIDENCE_THRESHOLD || '0.80' }}\n AMBIENT_REACTIONS_DECISION_GROQ_MODELS: ${{ vars.AMBIENT_REACTIONS_DECISION_GROQ_MODELS || 'llama-3.1-8b-instant,qwen/qwen3-32b,meta-llama/llama-4-scout-17b-16e-instruct' }}\n AMBIENT_REACTIONS_DECISION_CONTEXT_CHARS: ${{ vars.AMBIENT_REACTIONS_DECISION_CONTEXT_CHARS || '3000' }}\n AMBIENT_REACTIONS_MIN_GAP_PER_CHAT_SECONDS: ${{ vars.AMBIENT_REACTIONS_MIN_GAP_PER_CHAT_SECONDS || '60' }}\n AMBIENT_REACTIONS_MIN_GAP_PER_USER_SECONDS: ${{ vars.AMBIENT_REACTIONS_MIN_GAP_PER_USER_SECONDS || '300' }}\n AMBIENT_REACTIONS_MAX_PER_CHAT_PER_HOUR: ${{ vars.AMBIENT_REACTIONS_MAX_PER_CHAT_PER_HOUR || '12' }}\n AMBIENT_REACTIONS_MAX_PER_CHAT_PER_DAY: ${{ vars.AMBIENT_REACTIONS_MAX_PER_CHAT_PER_DAY || '100' }}\n run: |\n echo \"๐ Deploying to ${{ env.TARGET_ENV }} environment...\"\n if [ \"${{ env.TARGET_ENV }}\" = \"prod\" ]; then\n # Human approval is enforced by the GitHub \"production\" Environment.\n # Keep CDK non-interactive so the runner never waits for stdin.\n uv run cdk deploy -c env=prod --require-approval never --all\n else\n uv run cdk deploy -c env=dev --require-approval never --all\n fi\n\n - name: Get Deployment Outputs\n if: success()\n working-directory: ./infra\n run: |\n echo \"## ๐ Deployment Successful (Zerde Telegram Bot)\" >> $GITHUB_STEP_SUMMARY\n echo \"Deployed to: **${{ env.TARGET_ENV }}**\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Stack Outputs:\" >> $GITHUB_STEP_SUMMARY\n\n STACK_NAME=\"zerde-serverless-telegram-bot-${{ env.TARGET_ENV }}\"\n\n aws cloudformation describe-stacks \\\n --stack-name $STACK_NAME \\\n --region eu-central-1 \\\n --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' \\\n --output table >> $GITHUB_STEP_SUMMARY || echo \"Could not fetch outputs\" >> $GITHUB_STEP_SUMMARY\n"}, "3b63b60c2a93578e47a8b6b3ca7eb86a212d2b1e": {"t": 1785762166.7667673, "n": 8983, "h": "f92638feae0f3f66", "c": "name: Deploy to AWS\n\non:\n push:\n branches:\n - main\n\n workflow_dispatch:\n inputs:\n environment:\n description: \"Target Environment\"\n required: true\n default: \"dev\"\n type: choice\n options:\n - dev\n - prod\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n\njobs:\n deploy:\n name: Deploy to AWS\n runs-on: ubuntu-24.04-arm\n # Manual prod deploys require a GitHub Environment (e.g. \"production\") with approvers; dev is ungated.\n environment: ${{ (github.event_name == 'workflow_dispatch' && inputs.environment == 'prod') && 'production' || 'development' }}\n permissions:\n contents: read\n id-token: write\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n\n - name: Determine Target Environment\n id: determine-env\n run: |\n if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ]; then\n echo \"TARGET_ENV=${{ inputs.environment }}\" >> $GITHUB_ENV\n echo \"Selected manual deployment to: ${{ inputs.environment }}\"\n else\n echo \"TARGET_ENV=dev\" >> $GITHUB_ENV\n echo \"Push event detected. Defaulting deployment to: dev\"\n fi\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n # CLI (npm aws-cdk) version numbering != Python aws-cdk-lib; use a recent 2.1k+ CLI for schema support.\n - name: Install AWS CDK CLI (pinned)\n run: |\n npm install -g aws-cdk@2.1119.0\n uv run cdk --version\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n # API keys and tokens are stored in SSM Parameter Store โ CDK only needs non-secret config.\n - name: CDK Deploy\n working-directory: ./infra\n env:\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG || 'kk' }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE || 'https://api.telegram.org/bot' }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER || 'gemini' }}\n GEMINI_MODEL: ${{ vars.GEMINI_MODEL || 'gemini-3.1-flash-lite' }}\n NEWS_GEMINI_MODEL: ${{ vars.NEWS_GEMINI_MODEL || 'gemini-3.1-flash-lite' }}\n QUIZ_GEMINI_MODEL: ${{ vars.QUIZ_GEMINI_MODEL || 'gemini-3.1-flash-lite' }}\n WTF_GEMINI_MODEL: ${{ vars.WTF_GEMINI_MODEL }}\n GEMINI_RPD_LIMIT: ${{ vars.GEMINI_RPD_LIMIT || '500' }}\n GEMINI_EMBEDDING_RPD_LIMIT: ${{ vars.GEMINI_EMBEDDING_RPD_LIMIT || '1000' }}\n GEMINI_API_BASE: ${{ vars.GEMINI_API_BASE || 'https://generativelanguage.googleapis.com/v1beta/models' }}\n FALLBACK_MODEL: ${{ vars.FALLBACK_MODEL }}\n GROQ_MODEL: ${{ vars.GROQ_MODEL }}\n GROQ_API_BASE: ${{ vars.GROQ_API_BASE || 'https://api.groq.com/openai/v1' }}\n DEEPSEEK_MODEL: ${{ vars.DEEPSEEK_MODEL || 'deepseek-chat' }}\n DEEPSEEK_API_BASE: ${{ vars.DEEPSEEK_API_BASE || 'https://api.deepseek.com' }}\n SPAM_RULE_ENFORCE_THRESHOLD: ${{ vars.SPAM_RULE_ENFORCE_THRESHOLD || '0.8' }}\n SPAM_RULE_AI_THRESHOLD: ${{ vars.SPAM_RULE_AI_THRESHOLD || '0.15' }}\n SPAM_AI_CONFIDENCE_THRESHOLD: ${{ vars.SPAM_AI_CONFIDENCE_THRESHOLD || '0.85' }}\n SPAM_REVIEW_ADMIN_MENTIONS: ${{ vars.SPAM_REVIEW_ADMIN_MENTIONS || '{}' }}\n ADMIN_USER_ID: ${{ secrets.ADMIN_USER_ID }}\n CHATS_KK: ${{ vars.CHATS_KK }}\n CHATS_ZH: ${{ vars.CHATS_ZH }}\n CHATS_RU: ${{ vars.CHATS_RU }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n QUIZ_CHATS_KK: ${{ vars.QUIZ_CHATS_KK }}\n QUIZ_CHATS_ZH: ${{ vars.QUIZ_CHATS_ZH }}\n QUIZ_CHATS_RU: ${{ vars.QUIZ_CHATS_RU }}\n CAPTCHA_TIMEOUT_SECONDS: ${{ vars.CAPTCHA_TIMEOUT_SECONDS || '120' }}\n KICK_BAN_DURATION_SECONDS: ${{ vars.KICK_BAN_DURATION_SECONDS || '31' }}\n VOTEBAN_THRESHOLD: ${{ vars.VOTEBAN_THRESHOLD || '7' }}\n VOTEBAN_FORGIVE_THRESHOLD: ${{ vars.VOTEBAN_FORGIVE_THRESHOLD || '7' }}\n CAPTCHA_MAX_ATTEMPTS: ${{ vars.CAPTCHA_MAX_ATTEMPTS || '3' }}\n QUIZ_LLM_RPD: ${{ vars.QUIZ_LLM_RPD || '20' }}\n GROUP_MEMORY_ENABLED: ${{ vars.GROUP_MEMORY_ENABLED || 'true' }}\n GROUP_MEMORY_RECENT_LIMIT: ${{ vars.GROUP_MEMORY_RECENT_LIMIT || '300' }}\n GROUP_MEMORY_RETENTION_DAYS: ${{ vars.GROUP_MEMORY_RETENTION_DAYS || '3650' }}\n GROUP_MEMORY_DAILY_SUMMARY_DAYS: ${{ vars.GROUP_MEMORY_DAILY_SUMMARY_DAYS || '7' }}\n GROUP_MEMORY_DAILY_SUMMARY_MESSAGE_LIMIT: ${{ vars.GROUP_MEMORY_DAILY_SUMMARY_MESSAGE_LIMIT || '500' }}\n VECTOR_MEMORY_ENABLED: ${{ vars.VECTOR_MEMORY_ENABLED || 'true' }}\n VECTOR_MEMORY_PROVIDER: ${{ vars.VECTOR_MEMORY_PROVIDER || 's3_vectors' }}\n VECTOR_MEMORY_DIMENSIONS: ${{ vars.VECTOR_MEMORY_DIMENSIONS || '768' }}\n VECTOR_MEMORY_EMBEDDING_MODEL: ${{ vars.VECTOR_MEMORY_EMBEDDING_MODEL || 'gemini-embedding-2' }}\n VECTOR_MEMORY_INDEX_THROTTLE_SECONDS: ${{ vars.VECTOR_MEMORY_INDEX_THROTTLE_SECONDS || '3' }}\n VECTOR_MEMORY_BACKFILL_BATCH_SIZE: ${{ vars.VECTOR_MEMORY_BACKFILL_BATCH_SIZE || '50' }}\n VECTOR_MEMORY_MAX_DISTANCE: ${{ vars.VECTOR_MEMORY_MAX_DISTANCE || '0.85' }}\n VECTOR_MEMORY_VECTOR_BUCKET_NAME: ${{ vars.VECTOR_MEMORY_VECTOR_BUCKET_NAME }}\n VECTOR_MEMORY_INDEX_NAME: ${{ vars.VECTOR_MEMORY_INDEX_NAME }}\n AGENT_ENABLED: ${{ vars.AGENT_ENABLED || 'true' }}\n AGENT_BOT_USERNAME: ${{ vars.AGENT_BOT_USERNAME || '@zerde_kz_bot' }}\n AGENT_RECENT_CONTEXT_LIMIT: ${{ vars.AGENT_RECENT_CONTEXT_LIMIT || '100' }}\n AGENT_DAILY_PROACTIVE_LIMIT: ${{ vars.AGENT_DAILY_PROACTIVE_LIMIT || '10' }}\n AGENT_PROACTIVE_FINAL_THRESHOLD: ${{ vars.AGENT_PROACTIVE_FINAL_THRESHOLD || '0.72' }}\n AGENT_PROACTIVE_DECISION_GROQ_MODELS: ${{ vars.AGENT_PROACTIVE_DECISION_GROQ_MODELS || 'llama-3.1-8b-instant,meta-llama/llama-4-scout-17b-16e-instruct,qwen/qwen3-32b' }}\n AGENT_PROACTIVE_DECISION_CONTEXT_CHARS: ${{ vars.AGENT_PROACTIVE_DECISION_CONTEXT_CHARS || '4000' }}\n AGENT_PROACTIVE_DECISION_ALLOW_DEEPSEEK_FALLBACK: ${{ vars.AGENT_PROACTIVE_DECISION_ALLOW_DEEPSEEK_FALLBACK || 'false' }}\n AMBIENT_REACTIONS_ENABLED: ${{ vars.AMBIENT_REACTIONS_ENABLED || 'true' }}\n AMBIENT_REACTIONS_SAMPLE_RATE: ${{ vars.AMBIENT_REACTIONS_SAMPLE_RATE || '0.80' }}\n AMBIENT_REACTIONS_CONFIDENCE_THRESHOLD: ${{ vars.AMBIENT_REACTIONS_CONFIDENCE_THRESHOLD || '0.80' }}\n AMBIENT_REACTIONS_DECISION_GROQ_MODELS: ${{ vars.AMBIENT_REACTIONS_DECISION_GROQ_MODELS || 'llama-3.1-8b-instant,qwen/qwen3-32b,meta-llama/llama-4-scout-17b-16e-instruct' }}\n AMBIENT_REACTIONS_DECISION_CONTEXT_CHARS: ${{ vars.AMBIENT_REACTIONS_DECISION_CONTEXT_CHARS || '3000' }}\n AMBIENT_REACTIONS_MIN_GAP_PER_CHAT_SECONDS: ${{ vars.AMBIENT_REACTIONS_MIN_GAP_PER_CHAT_SECONDS || '60' }}\n AMBIENT_REACTIONS_MIN_GAP_PER_USER_SECONDS: ${{ vars.AMBIENT_REACTIONS_MIN_GAP_PER_USER_SECONDS || '300' }}\n AMBIENT_REACTIONS_MAX_PER_CHAT_PER_HOUR: ${{ vars.AMBIENT_REACTIONS_MAX_PER_CHAT_PER_HOUR || '12' }}\n AMBIENT_REACTIONS_MAX_PER_CHAT_PER_DAY: ${{ vars.AMBIENT_REACTIONS_MAX_PER_CHAT_PER_DAY || '100' }}\n run: |\n echo \"๐ Deploying to ${{ env.TARGET_ENV }} environment...\"\n if [ \"${{ env.TARGET_ENV }}\" = \"prod\" ]; then\n # Human approval is enforced by the GitHub \"production\" Environment.\n # Keep CDK non-interactive so the runner never waits for stdin.\n uv run cdk deploy -c env=prod --require-approval never --all\n else\n uv run cdk deploy -c env=dev --require-approval never --all\n fi\n\n - name: Get Deployment Outputs\n if: success()\n working-directory: ./infra\n run: |\n echo \"## ๐ Deployment Successful (Zerde Telegram Bot)\" >> $GITHUB_STEP_SUMMARY\n echo \"Deployed to: **${{ env.TARGET_ENV }}**\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Stack Outputs:\" >> $GITHUB_STEP_SUMMARY\n\n STACK_NAME=\"zerde-serverless-telegram-bot-${{ env.TARGET_ENV }}\"\n\n aws cloudformation describe-stacks \\\n --stack-name $STACK_NAME \\\n --region eu-central-1 \\\n --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' \\\n --output table >> $GITHUB_STEP_SUMMARY || echo \"Could not fetch outputs\" >> $GITHUB_STEP_SUMMARY\n"}, "db9d171ed3e4de94443d38e199c676441376f0ba": {"t": 1785762168.7447083, "n": 8898, "h": "932496bcf07ee76b", "c": "name: Deploy to AWS\n\non:\n push:\n branches:\n - main\n\n workflow_dispatch:\n inputs:\n environment:\n description: \"Target Environment\"\n required: true\n default: \"dev\"\n type: choice\n options:\n - dev\n - prod\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n\njobs:\n deploy:\n name: Deploy to AWS\n runs-on: ubuntu-24.04-arm\n # Manual prod deploys require a GitHub Environment (e.g. \"production\") with approvers; dev is ungated.\n environment: ${{ (github.event_name == 'workflow_dispatch' && inputs.environment == 'prod') && 'production' || 'development' }}\n permissions:\n contents: read\n id-token: write\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n\n - name: Determine Target Environment\n id: determine-env\n run: |\n if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ]; then\n echo \"TARGET_ENV=${{ inputs.environment }}\" >> $GITHUB_ENV\n echo \"Selected manual deployment to: ${{ inputs.environment }}\"\n else\n echo \"TARGET_ENV=dev\" >> $GITHUB_ENV\n echo \"Push event detected. Defaulting deployment to: dev\"\n fi\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n # CLI (npm aws-cdk) version numbering != Python aws-cdk-lib; use a recent 2.1k+ CLI for schema support.\n - name: Install AWS CDK CLI (pinned)\n run: |\n npm install -g aws-cdk@2.1119.0\n uv run cdk --version\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n # API keys and tokens are stored in SSM Parameter Store โ CDK only needs non-secret config.\n - name: CDK Deploy\n working-directory: ./infra\n env:\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG || 'kk' }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE || 'https://api.telegram.org/bot' }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER || 'gemini' }}\n GEMINI_MODEL: ${{ vars.GEMINI_MODEL || 'gemini-3.1-flash-lite' }}\n NEWS_GEMINI_MODEL: ${{ vars.NEWS_GEMINI_MODEL || 'gemini-3.1-flash-lite' }}\n QUIZ_GEMINI_MODEL: ${{ vars.QUIZ_GEMINI_MODEL || 'gemini-3.1-flash-lite' }}\n WTF_GEMINI_MODEL: ${{ vars.WTF_GEMINI_MODEL }}\n GEMINI_RPD_LIMIT: ${{ vars.GEMINI_RPD_LIMIT || '500' }}\n GEMINI_EMBEDDING_RPD_LIMIT: ${{ vars.GEMINI_EMBEDDING_RPD_LIMIT || '1000' }}\n GEMINI_API_BASE: ${{ vars.GEMINI_API_BASE || 'https://generativelanguage.googleapis.com/v1beta/models' }}\n FALLBACK_MODEL: ${{ vars.FALLBACK_MODEL }}\n GROQ_MODEL: ${{ vars.GROQ_MODEL }}\n GROQ_API_BASE: ${{ vars.GROQ_API_BASE || 'https://api.groq.com/openai/v1' }}\n DEEPSEEK_MODEL: ${{ vars.DEEPSEEK_MODEL || 'deepseek-chat' }}\n DEEPSEEK_API_BASE: ${{ vars.DEEPSEEK_API_BASE || 'https://api.deepseek.com' }}\n SPAM_RULE_ENFORCE_THRESHOLD: ${{ vars.SPAM_RULE_ENFORCE_THRESHOLD || '0.8' }}\n SPAM_RULE_AI_THRESHOLD: ${{ vars.SPAM_RULE_AI_THRESHOLD || '0.15' }}\n SPAM_AI_CONFIDENCE_THRESHOLD: ${{ vars.SPAM_AI_CONFIDENCE_THRESHOLD || '0.85' }}\n ADMIN_USER_ID: ${{ secrets.ADMIN_USER_ID }}\n CHATS_KK: ${{ vars.CHATS_KK }}\n CHATS_ZH: ${{ vars.CHATS_ZH }}\n CHATS_RU: ${{ vars.CHATS_RU }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n QUIZ_CHATS_KK: ${{ vars.QUIZ_CHATS_KK }}\n QUIZ_CHATS_ZH: ${{ vars.QUIZ_CHATS_ZH }}\n QUIZ_CHATS_RU: ${{ vars.QUIZ_CHATS_RU }}\n CAPTCHA_TIMEOUT_SECONDS: ${{ vars.CAPTCHA_TIMEOUT_SECONDS || '120' }}\n KICK_BAN_DURATION_SECONDS: ${{ vars.KICK_BAN_DURATION_SECONDS || '31' }}\n VOTEBAN_THRESHOLD: ${{ vars.VOTEBAN_THRESHOLD || '7' }}\n VOTEBAN_FORGIVE_THRESHOLD: ${{ vars.VOTEBAN_FORGIVE_THRESHOLD || '7' }}\n CAPTCHA_MAX_ATTEMPTS: ${{ vars.CAPTCHA_MAX_ATTEMPTS || '3' }}\n QUIZ_LLM_RPD: ${{ vars.QUIZ_LLM_RPD || '20' }}\n GROUP_MEMORY_ENABLED: ${{ vars.GROUP_MEMORY_ENABLED || 'true' }}\n GROUP_MEMORY_RECENT_LIMIT: ${{ vars.GROUP_MEMORY_RECENT_LIMIT || '300' }}\n GROUP_MEMORY_RETENTION_DAYS: ${{ vars.GROUP_MEMORY_RETENTION_DAYS || '3650' }}\n GROUP_MEMORY_DAILY_SUMMARY_DAYS: ${{ vars.GROUP_MEMORY_DAILY_SUMMARY_DAYS || '7' }}\n GROUP_MEMORY_DAILY_SUMMARY_MESSAGE_LIMIT: ${{ vars.GROUP_MEMORY_DAILY_SUMMARY_MESSAGE_LIMIT || '500' }}\n VECTOR_MEMORY_ENABLED: ${{ vars.VECTOR_MEMORY_ENABLED || 'true' }}\n VECTOR_MEMORY_PROVIDER: ${{ vars.VECTOR_MEMORY_PROVIDER || 's3_vectors' }}\n VECTOR_MEMORY_DIMENSIONS: ${{ vars.VECTOR_MEMORY_DIMENSIONS || '768' }}\n VECTOR_MEMORY_EMBEDDING_MODEL: ${{ vars.VECTOR_MEMORY_EMBEDDING_MODEL || 'gemini-embedding-2' }}\n VECTOR_MEMORY_INDEX_THROTTLE_SECONDS: ${{ vars.VECTOR_MEMORY_INDEX_THROTTLE_SECONDS || '3' }}\n VECTOR_MEMORY_BACKFILL_BATCH_SIZE: ${{ vars.VECTOR_MEMORY_BACKFILL_BATCH_SIZE || '50' }}\n VECTOR_MEMORY_MAX_DISTANCE: ${{ vars.VECTOR_MEMORY_MAX_DISTANCE || '0.85' }}\n VECTOR_MEMORY_VECTOR_BUCKET_NAME: ${{ vars.VECTOR_MEMORY_VECTOR_BUCKET_NAME }}\n VECTOR_MEMORY_INDEX_NAME: ${{ vars.VECTOR_MEMORY_INDEX_NAME }}\n AGENT_ENABLED: ${{ vars.AGENT_ENABLED || 'true' }}\n AGENT_BOT_USERNAME: ${{ vars.AGENT_BOT_USERNAME || '@zerde_kz_bot' }}\n AGENT_RECENT_CONTEXT_LIMIT: ${{ vars.AGENT_RECENT_CONTEXT_LIMIT || '100' }}\n AGENT_DAILY_PROACTIVE_LIMIT: ${{ vars.AGENT_DAILY_PROACTIVE_LIMIT || '10' }}\n AGENT_PROACTIVE_FINAL_THRESHOLD: ${{ vars.AGENT_PROACTIVE_FINAL_THRESHOLD || '0.72' }}\n AGENT_PROACTIVE_DECISION_GROQ_MODELS: ${{ vars.AGENT_PROACTIVE_DECISION_GROQ_MODELS || 'llama-3.1-8b-instant,meta-llama/llama-4-scout-17b-16e-instruct,qwen/qwen3-32b' }}\n AGENT_PROACTIVE_DECISION_CONTEXT_CHARS: ${{ vars.AGENT_PROACTIVE_DECISION_CONTEXT_CHARS || '4000' }}\n AGENT_PROACTIVE_DECISION_ALLOW_DEEPSEEK_FALLBACK: ${{ vars.AGENT_PROACTIVE_DECISION_ALLOW_DEEPSEEK_FALLBACK || 'false' }}\n AMBIENT_REACTIONS_ENABLED: ${{ vars.AMBIENT_REACTIONS_ENABLED || 'true' }}\n AMBIENT_REACTIONS_SAMPLE_RATE: ${{ vars.AMBIENT_REACTIONS_SAMPLE_RATE || '0.80' }}\n AMBIENT_REACTIONS_CONFIDENCE_THRESHOLD: ${{ vars.AMBIENT_REACTIONS_CONFIDENCE_THRESHOLD || '0.80' }}\n AMBIENT_REACTIONS_DECISION_GROQ_MODELS: ${{ vars.AMBIENT_REACTIONS_DECISION_GROQ_MODELS || 'llama-3.1-8b-instant,qwen/qwen3-32b,meta-llama/llama-4-scout-17b-16e-instruct' }}\n AMBIENT_REACTIONS_DECISION_CONTEXT_CHARS: ${{ vars.AMBIENT_REACTIONS_DECISION_CONTEXT_CHARS || '3000' }}\n AMBIENT_REACTIONS_MIN_GAP_PER_CHAT_SECONDS: ${{ vars.AMBIENT_REACTIONS_MIN_GAP_PER_CHAT_SECONDS || '60' }}\n AMBIENT_REACTIONS_MIN_GAP_PER_USER_SECONDS: ${{ vars.AMBIENT_REACTIONS_MIN_GAP_PER_USER_SECONDS || '300' }}\n AMBIENT_REACTIONS_MAX_PER_CHAT_PER_HOUR: ${{ vars.AMBIENT_REACTIONS_MAX_PER_CHAT_PER_HOUR || '12' }}\n AMBIENT_REACTIONS_MAX_PER_CHAT_PER_DAY: ${{ vars.AMBIENT_REACTIONS_MAX_PER_CHAT_PER_DAY || '100' }}\n run: |\n echo \"๐ Deploying to ${{ env.TARGET_ENV }} environment...\"\n if [ \"${{ env.TARGET_ENV }}\" = \"prod\" ]; then\n # Human approval is enforced by the GitHub \"production\" Environment.\n # Keep CDK non-interactive so the runner never waits for stdin.\n uv run cdk deploy -c env=prod --require-approval never --all\n else\n uv run cdk deploy -c env=dev --require-approval never --all\n fi\n\n - name: Get Deployment Outputs\n if: success()\n working-directory: ./infra\n run: |\n echo \"## ๐ Deployment Successful (Zerde Telegram Bot)\" >> $GITHUB_STEP_SUMMARY\n echo \"Deployed to: **${{ env.TARGET_ENV }}**\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Stack Outputs:\" >> $GITHUB_STEP_SUMMARY\n\n STACK_NAME=\"zerde-serverless-telegram-bot-${{ env.TARGET_ENV }}\"\n\n aws cloudformation describe-stacks \\\n --stack-name $STACK_NAME \\\n --region eu-central-1 \\\n --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' \\\n --output table >> $GITHUB_STEP_SUMMARY || echo \"Could not fetch outputs\" >> $GITHUB_STEP_SUMMARY\n"}, "ed58f0e00b9c34d21c0c6d95f91276dac8924a7f": {"t": 1785762172.5604544, "n": 8273, "h": "5e6c71738efbdf86", "c": "name: Deploy to AWS\n\non:\n push:\n branches:\n - main\n\n workflow_dispatch:\n inputs:\n environment:\n description: \"Target Environment\"\n required: true\n default: \"dev\"\n type: choice\n options:\n - dev\n - prod\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n\njobs:\n deploy:\n name: Deploy to AWS\n runs-on: ubuntu-24.04-arm\n # Manual prod deploys require a GitHub Environment (e.g. \"production\") with approvers; dev is ungated.\n environment: ${{ (github.event_name == 'workflow_dispatch' && inputs.environment == 'prod') && 'production' || 'development' }}\n permissions:\n contents: read\n id-token: write\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n\n - name: Determine Target Environment\n id: determine-env\n run: |\n if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ]; then\n echo \"TARGET_ENV=${{ inputs.environment }}\" >> $GITHUB_ENV\n echo \"Selected manual deployment to: ${{ inputs.environment }}\"\n else\n echo \"TARGET_ENV=dev\" >> $GITHUB_ENV\n echo \"Push event detected. Defaulting deployment to: dev\"\n fi\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n # CLI (npm aws-cdk) version numbering != Python aws-cdk-lib; use a recent 2.1k+ CLI for schema support.\n - name: Install AWS CDK CLI (pinned)\n run: |\n npm install -g aws-cdk@2.1119.0\n uv run cdk --version\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n # API keys and tokens are stored in SSM Parameter Store โ CDK only needs non-secret config.\n - name: CDK Deploy\n working-directory: ./infra\n env:\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG || 'kk' }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE || 'https://api.telegram.org/bot' }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER || 'gemini' }}\n GEMINI_MODEL: ${{ vars.GEMINI_MODEL || 'gemini-3.1-flash-lite' }}\n NEWS_GEMINI_MODEL: ${{ vars.NEWS_GEMINI_MODEL || 'gemini-3.1-flash-lite' }}\n QUIZ_GEMINI_MODEL: ${{ vars.QUIZ_GEMINI_MODEL || 'gemini-3.1-flash-lite' }}\n WTF_GEMINI_MODEL: ${{ vars.WTF_GEMINI_MODEL }}\n GEMINI_RPD_LIMIT: ${{ vars.GEMINI_RPD_LIMIT || '500' }}\n GEMINI_EMBEDDING_RPD_LIMIT: ${{ vars.GEMINI_EMBEDDING_RPD_LIMIT || '1000' }}\n GEMINI_API_BASE: ${{ vars.GEMINI_API_BASE || 'https://generativelanguage.googleapis.com/v1beta/models' }}\n FALLBACK_MODEL: ${{ vars.FALLBACK_MODEL }}\n GROQ_MODEL: ${{ vars.GROQ_MODEL }}\n GROQ_API_BASE: ${{ vars.GROQ_API_BASE || 'https://api.groq.com/openai/v1' }}\n DEEPSEEK_MODEL: ${{ vars.DEEPSEEK_MODEL || 'deepseek-chat' }}\n DEEPSEEK_API_BASE: ${{ vars.DEEPSEEK_API_BASE || 'https://api.deepseek.com' }}\n SPAM_RULE_ENFORCE_THRESHOLD: ${{ vars.SPAM_RULE_ENFORCE_THRESHOLD || '0.8' }}\n SPAM_RULE_AI_THRESHOLD: ${{ vars.SPAM_RULE_AI_THRESHOLD || '0.15' }}\n SPAM_AI_CONFIDENCE_THRESHOLD: ${{ vars.SPAM_AI_CONFIDENCE_THRESHOLD || '0.85' }}\n ADMIN_USER_ID: ${{ secrets.ADMIN_USER_ID }}\n CHATS_KK: ${{ vars.CHATS_KK }}\n CHATS_ZH: ${{ vars.CHATS_ZH }}\n CHATS_RU: ${{ vars.CHATS_RU }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n QUIZ_CHATS_KK: ${{ vars.QUIZ_CHATS_KK }}\n QUIZ_CHATS_ZH: ${{ vars.QUIZ_CHATS_ZH }}\n QUIZ_CHATS_RU: ${{ vars.QUIZ_CHATS_RU }}\n CAPTCHA_TIMEOUT_SECONDS: ${{ vars.CAPTCHA_TIMEOUT_SECONDS || '120' }}\n KICK_BAN_DURATION_SECONDS: ${{ vars.KICK_BAN_DURATION_SECONDS || '31' }}\n VOTEBAN_THRESHOLD: ${{ vars.VOTEBAN_THRESHOLD || '7' }}\n VOTEBAN_FORGIVE_THRESHOLD: ${{ vars.VOTEBAN_FORGIVE_THRESHOLD || '7' }}\n CAPTCHA_MAX_ATTEMPTS: ${{ vars.CAPTCHA_MAX_ATTEMPTS || '3' }}\n QUIZ_LLM_RPD: ${{ vars.QUIZ_LLM_RPD || '20' }}\n GROUP_MEMORY_ENABLED: ${{ vars.GROUP_MEMORY_ENABLED || 'true' }}\n GROUP_MEMORY_RECENT_LIMIT: ${{ vars.GROUP_MEMORY_RECENT_LIMIT || '300' }}\n GROUP_MEMORY_RETENTION_DAYS: ${{ vars.GROUP_MEMORY_RETENTION_DAYS || '3650' }}\n GROUP_MEMORY_DAILY_SUMMARY_DAYS: ${{ vars.GROUP_MEMORY_DAILY_SUMMARY_DAYS || '7' }}\n GROUP_MEMORY_DAILY_SUMMARY_MESSAGE_LIMIT: ${{ vars.GROUP_MEMORY_DAILY_SUMMARY_MESSAGE_LIMIT || '500' }}\n VECTOR_MEMORY_ENABLED: ${{ vars.VECTOR_MEMORY_ENABLED || 'true' }}\n VECTOR_MEMORY_PROVIDER: ${{ vars.VECTOR_MEMORY_PROVIDER || 's3_vectors' }}\n VECTOR_MEMORY_DIMENSIONS: ${{ vars.VECTOR_MEMORY_DIMENSIONS || '768' }}\n VECTOR_MEMORY_EMBEDDING_MODEL: ${{ vars.VECTOR_MEMORY_EMBEDDING_MODEL || 'gemini-embedding-2' }}\n VECTOR_MEMORY_INDEX_THROTTLE_SECONDS: ${{ vars.VECTOR_MEMORY_INDEX_THROTTLE_SECONDS || '3' }}\n VECTOR_MEMORY_BACKFILL_BATCH_SIZE: ${{ vars.VECTOR_MEMORY_BACKFILL_BATCH_SIZE || '50' }}\n VECTOR_MEMORY_MAX_DISTANCE: ${{ vars.VECTOR_MEMORY_MAX_DISTANCE || '0.85' }}\n VECTOR_MEMORY_VECTOR_BUCKET_NAME: ${{ vars.VECTOR_MEMORY_VECTOR_BUCKET_NAME }}\n VECTOR_MEMORY_INDEX_NAME: ${{ vars.VECTOR_MEMORY_INDEX_NAME }}\n AGENT_ENABLED: ${{ vars.AGENT_ENABLED || 'true' }}\n AGENT_BOT_USERNAME: ${{ vars.AGENT_BOT_USERNAME || '@zerde_kz_bot' }}\n AGENT_RECENT_CONTEXT_LIMIT: ${{ vars.AGENT_RECENT_CONTEXT_LIMIT || '100' }}\n AGENT_DAILY_PROACTIVE_LIMIT: ${{ vars.AGENT_DAILY_PROACTIVE_LIMIT || '10' }}\n AGENT_PROACTIVE_SCORE_THRESHOLD: ${{ vars.AGENT_PROACTIVE_SCORE_THRESHOLD || '0.62' }}\n AGENT_PROACTIVE_FINAL_THRESHOLD: ${{ vars.AGENT_PROACTIVE_FINAL_THRESHOLD || '0.72' }}\n AMBIENT_REACTIONS_ENABLED: ${{ vars.AMBIENT_REACTIONS_ENABLED || 'true' }}\n AMBIENT_REACTIONS_SAMPLE_RATE: ${{ vars.AMBIENT_REACTIONS_SAMPLE_RATE || '0.80' }}\n AMBIENT_REACTIONS_CONFIDENCE_THRESHOLD: ${{ vars.AMBIENT_REACTIONS_CONFIDENCE_THRESHOLD || '0.80' }}\n AMBIENT_REACTIONS_MIN_GAP_PER_CHAT_SECONDS: ${{ vars.AMBIENT_REACTIONS_MIN_GAP_PER_CHAT_SECONDS || '60' }}\n AMBIENT_REACTIONS_MIN_GAP_PER_USER_SECONDS: ${{ vars.AMBIENT_REACTIONS_MIN_GAP_PER_USER_SECONDS || '300' }}\n AMBIENT_REACTIONS_MAX_PER_CHAT_PER_HOUR: ${{ vars.AMBIENT_REACTIONS_MAX_PER_CHAT_PER_HOUR || '12' }}\n AMBIENT_REACTIONS_MAX_PER_CHAT_PER_DAY: ${{ vars.AMBIENT_REACTIONS_MAX_PER_CHAT_PER_DAY || '100' }}\n run: |\n echo \"๐ Deploying to ${{ env.TARGET_ENV }} environment...\"\n if [ \"${{ env.TARGET_ENV }}\" = \"prod\" ]; then\n # Human approval is enforced by the GitHub \"production\" Environment.\n # Keep CDK non-interactive so the runner never waits for stdin.\n uv run cdk deploy -c env=prod --require-approval never --all\n else\n uv run cdk deploy -c env=dev --require-approval never --all\n fi\n\n - name: Get Deployment Outputs\n if: success()\n working-directory: ./infra\n run: |\n echo \"## ๐ Deployment Successful (Zerde Telegram Bot)\" >> $GITHUB_STEP_SUMMARY\n echo \"Deployed to: **${{ env.TARGET_ENV }}**\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Stack Outputs:\" >> $GITHUB_STEP_SUMMARY\n\n STACK_NAME=\"zerde-serverless-telegram-bot-${{ env.TARGET_ENV }}\"\n\n aws cloudformation describe-stacks \\\n --stack-name $STACK_NAME \\\n --region eu-central-1 \\\n --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' \\\n --output table >> $GITHUB_STEP_SUMMARY || echo \"Could not fetch outputs\" >> $GITHUB_STEP_SUMMARY\n"}, "b80a65f49f6a828f74487caef09405545a5ec3ef": {"t": 1785762173.999928, "n": 7528, "h": "3e203d886f767dee", "c": "name: Deploy to AWS\n\non:\n push:\n branches:\n - main\n\n workflow_dispatch:\n inputs:\n environment:\n description: \"Target Environment\"\n required: true\n default: \"dev\"\n type: choice\n options:\n - dev\n - prod\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n\njobs:\n deploy:\n name: Deploy to AWS\n runs-on: ubuntu-24.04-arm\n # Manual prod deploys require a GitHub Environment (e.g. \"production\") with approvers; dev is ungated.\n environment: ${{ (github.event_name == 'workflow_dispatch' && inputs.environment == 'prod') && 'production' || 'development' }}\n permissions:\n contents: read\n id-token: write\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n\n - name: Determine Target Environment\n id: determine-env\n run: |\n if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ]; then\n echo \"TARGET_ENV=${{ inputs.environment }}\" >> $GITHUB_ENV\n echo \"Selected manual deployment to: ${{ inputs.environment }}\"\n else\n echo \"TARGET_ENV=dev\" >> $GITHUB_ENV\n echo \"Push event detected. Defaulting deployment to: dev\"\n fi\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n # CLI (npm aws-cdk) version numbering != Python aws-cdk-lib; use a recent 2.1k+ CLI for schema support.\n - name: Install AWS CDK CLI (pinned)\n run: |\n npm install -g aws-cdk@2.1119.0\n uv run cdk --version\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n # API keys and tokens are stored in SSM Parameter Store โ CDK only needs non-secret config.\n - name: CDK Deploy\n working-directory: ./infra\n env:\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG || 'kk' }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE || 'https://api.telegram.org/bot' }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER || 'gemini' }}\n GEMINI_MODEL: ${{ vars.GEMINI_MODEL || 'gemini-3.1-flash-lite' }}\n NEWS_GEMINI_MODEL: ${{ vars.NEWS_GEMINI_MODEL || 'gemini-3.1-flash-lite' }}\n QUIZ_GEMINI_MODEL: ${{ vars.QUIZ_GEMINI_MODEL || 'gemini-3.1-flash-lite' }}\n WTF_GEMINI_MODEL: ${{ vars.WTF_GEMINI_MODEL }}\n GEMINI_RPD_LIMIT: ${{ vars.GEMINI_RPD_LIMIT || '500' }}\n GEMINI_EMBEDDING_RPD_LIMIT: ${{ vars.GEMINI_EMBEDDING_RPD_LIMIT || '1000' }}\n GEMINI_API_BASE: ${{ vars.GEMINI_API_BASE || 'https://generativelanguage.googleapis.com/v1beta/models' }}\n FALLBACK_MODEL: ${{ vars.FALLBACK_MODEL }}\n GROQ_MODEL: ${{ vars.GROQ_MODEL }}\n GROQ_API_BASE: ${{ vars.GROQ_API_BASE || 'https://api.groq.com/openai/v1' }}\n DEEPSEEK_MODEL: ${{ vars.DEEPSEEK_MODEL || 'deepseek-chat' }}\n DEEPSEEK_API_BASE: ${{ vars.DEEPSEEK_API_BASE || 'https://api.deepseek.com' }}\n SPAM_RULE_ENFORCE_THRESHOLD: ${{ vars.SPAM_RULE_ENFORCE_THRESHOLD || '0.8' }}\n SPAM_RULE_AI_THRESHOLD: ${{ vars.SPAM_RULE_AI_THRESHOLD || '0.15' }}\n SPAM_AI_CONFIDENCE_THRESHOLD: ${{ vars.SPAM_AI_CONFIDENCE_THRESHOLD || '0.85' }}\n ADMIN_USER_ID: ${{ secrets.ADMIN_USER_ID }}\n CHATS_KK: ${{ vars.CHATS_KK }}\n CHATS_ZH: ${{ vars.CHATS_ZH }}\n CHATS_RU: ${{ vars.CHATS_RU }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n QUIZ_CHATS_KK: ${{ vars.QUIZ_CHATS_KK }}\n QUIZ_CHATS_ZH: ${{ vars.QUIZ_CHATS_ZH }}\n QUIZ_CHATS_RU: ${{ vars.QUIZ_CHATS_RU }}\n CAPTCHA_TIMEOUT_SECONDS: ${{ vars.CAPTCHA_TIMEOUT_SECONDS || '120' }}\n KICK_BAN_DURATION_SECONDS: ${{ vars.KICK_BAN_DURATION_SECONDS || '31' }}\n VOTEBAN_THRESHOLD: ${{ vars.VOTEBAN_THRESHOLD || '7' }}\n VOTEBAN_FORGIVE_THRESHOLD: ${{ vars.VOTEBAN_FORGIVE_THRESHOLD || '7' }}\n CAPTCHA_MAX_ATTEMPTS: ${{ vars.CAPTCHA_MAX_ATTEMPTS || '3' }}\n QUIZ_LLM_RPD: ${{ vars.QUIZ_LLM_RPD || '20' }}\n GROUP_MEMORY_ENABLED: ${{ vars.GROUP_MEMORY_ENABLED || 'true' }}\n GROUP_MEMORY_RECENT_LIMIT: ${{ vars.GROUP_MEMORY_RECENT_LIMIT || '300' }}\n GROUP_MEMORY_RETENTION_DAYS: ${{ vars.GROUP_MEMORY_RETENTION_DAYS || '3650' }}\n GROUP_MEMORY_DAILY_SUMMARY_DAYS: ${{ vars.GROUP_MEMORY_DAILY_SUMMARY_DAYS || '7' }}\n GROUP_MEMORY_DAILY_SUMMARY_MESSAGE_LIMIT: ${{ vars.GROUP_MEMORY_DAILY_SUMMARY_MESSAGE_LIMIT || '500' }}\n VECTOR_MEMORY_ENABLED: ${{ vars.VECTOR_MEMORY_ENABLED || 'true' }}\n VECTOR_MEMORY_PROVIDER: ${{ vars.VECTOR_MEMORY_PROVIDER || 's3_vectors' }}\n VECTOR_MEMORY_DIMENSIONS: ${{ vars.VECTOR_MEMORY_DIMENSIONS || '768' }}\n VECTOR_MEMORY_EMBEDDING_MODEL: ${{ vars.VECTOR_MEMORY_EMBEDDING_MODEL || 'gemini-embedding-2' }}\n VECTOR_MEMORY_INDEX_THROTTLE_SECONDS: ${{ vars.VECTOR_MEMORY_INDEX_THROTTLE_SECONDS || '3' }}\n VECTOR_MEMORY_BACKFILL_BATCH_SIZE: ${{ vars.VECTOR_MEMORY_BACKFILL_BATCH_SIZE || '50' }}\n VECTOR_MEMORY_MAX_DISTANCE: ${{ vars.VECTOR_MEMORY_MAX_DISTANCE || '0.85' }}\n VECTOR_MEMORY_VECTOR_BUCKET_NAME: ${{ vars.VECTOR_MEMORY_VECTOR_BUCKET_NAME }}\n VECTOR_MEMORY_INDEX_NAME: ${{ vars.VECTOR_MEMORY_INDEX_NAME }}\n AGENT_ENABLED: ${{ vars.AGENT_ENABLED || 'true' }}\n AGENT_BOT_USERNAME: ${{ vars.AGENT_BOT_USERNAME || '@zerde_kz_bot' }}\n AGENT_RECENT_CONTEXT_LIMIT: ${{ vars.AGENT_RECENT_CONTEXT_LIMIT || '100' }}\n AGENT_DAILY_PROACTIVE_LIMIT: ${{ vars.AGENT_DAILY_PROACTIVE_LIMIT || '10' }}\n AGENT_PROACTIVE_SCORE_THRESHOLD: ${{ vars.AGENT_PROACTIVE_SCORE_THRESHOLD || '0.62' }}\n AGENT_PROACTIVE_FINAL_THRESHOLD: ${{ vars.AGENT_PROACTIVE_FINAL_THRESHOLD || '0.72' }}\n run: |\n echo \"๐ Deploying to ${{ env.TARGET_ENV }} environment...\"\n if [ \"${{ env.TARGET_ENV }}\" = \"prod\" ]; then\n # Human approval is enforced by the GitHub \"production\" Environment.\n # Keep CDK non-interactive so the runner never waits for stdin.\n uv run cdk deploy -c env=prod --require-approval never --all\n else\n uv run cdk deploy -c env=dev --require-approval never --all\n fi\n\n - name: Get Deployment Outputs\n if: success()\n working-directory: ./infra\n run: |\n echo \"## ๐ Deployment Successful (Zerde Telegram Bot)\" >> $GITHUB_STEP_SUMMARY\n echo \"Deployed to: **${{ env.TARGET_ENV }}**\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Stack Outputs:\" >> $GITHUB_STEP_SUMMARY\n\n STACK_NAME=\"zerde-serverless-telegram-bot-${{ env.TARGET_ENV }}\"\n\n aws cloudformation describe-stacks \\\n --stack-name $STACK_NAME \\\n --region eu-central-1 \\\n --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' \\\n --output table >> $GITHUB_STEP_SUMMARY || echo \"Could not fetch outputs\" >> $GITHUB_STEP_SUMMARY\n"}, "4599d67b5bc86975d3d1a691aaa2a90006938f01": {"t": 1785762178.5292017, "n": 7278, "h": "9cae49affe369760", "c": "name: Deploy to AWS\n\non:\n push:\n branches:\n - main\n\n workflow_dispatch:\n inputs:\n environment:\n description: \"Target Environment\"\n required: true\n default: \"dev\"\n type: choice\n options:\n - dev\n - prod\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n\njobs:\n deploy:\n name: Deploy to AWS\n runs-on: ubuntu-24.04-arm\n # Manual prod deploys require a GitHub Environment (e.g. \"production\") with approvers; dev is ungated.\n environment: ${{ (github.event_name == 'workflow_dispatch' && inputs.environment == 'prod') && 'production' || 'development' }}\n permissions:\n contents: read\n id-token: write\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n\n - name: Determine Target Environment\n id: determine-env\n run: |\n if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ]; then\n echo \"TARGET_ENV=${{ inputs.environment }}\" >> $GITHUB_ENV\n echo \"Selected manual deployment to: ${{ inputs.environment }}\"\n else\n echo \"TARGET_ENV=dev\" >> $GITHUB_ENV\n echo \"Push event detected. Defaulting deployment to: dev\"\n fi\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n # CLI (npm aws-cdk) version numbering != Python aws-cdk-lib; use a recent 2.1k+ CLI for schema support.\n - name: Install AWS CDK CLI (pinned)\n run: |\n npm install -g aws-cdk@2.1119.0\n uv run cdk --version\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n # API keys and tokens are stored in SSM Parameter Store โ CDK only needs non-secret config.\n - name: CDK Deploy\n working-directory: ./infra\n env:\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG || 'kk' }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE || 'https://api.telegram.org/bot' }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER || 'gemini' }}\n NEWS_GEMINI_MODEL: ${{ vars.NEWS_GEMINI_MODEL || 'gemini-3.1-flash-lite' }}\n QUIZ_GEMINI_MODEL: ${{ vars.QUIZ_GEMINI_MODEL || 'gemini-3.1-flash-lite' }}\n WTF_GEMINI_MODEL: ${{ vars.WTF_GEMINI_MODEL }}\n GEMINI_RPD_LIMIT: ${{ vars.GEMINI_RPD_LIMIT || '500' }}\n GEMINI_API_BASE: ${{ vars.GEMINI_API_BASE || 'https://generativelanguage.googleapis.com/v1beta/models' }}\n FALLBACK_MODEL: ${{ vars.FALLBACK_MODEL }}\n GROQ_MODEL: ${{ vars.GROQ_MODEL }}\n GROQ_API_BASE: ${{ vars.GROQ_API_BASE || 'https://api.groq.com/openai/v1' }}\n DEEPSEEK_MODEL: ${{ vars.DEEPSEEK_MODEL || 'deepseek-chat' }}\n DEEPSEEK_API_BASE: ${{ vars.DEEPSEEK_API_BASE || 'https://api.deepseek.com' }}\n SPAM_RULE_ENFORCE_THRESHOLD: ${{ vars.SPAM_RULE_ENFORCE_THRESHOLD || '0.8' }}\n SPAM_RULE_AI_THRESHOLD: ${{ vars.SPAM_RULE_AI_THRESHOLD || '0.15' }}\n SPAM_AI_CONFIDENCE_THRESHOLD: ${{ vars.SPAM_AI_CONFIDENCE_THRESHOLD || '0.85' }}\n ADMIN_USER_ID: ${{ secrets.ADMIN_USER_ID }}\n CHATS_KK: ${{ vars.CHATS_KK }}\n CHATS_ZH: ${{ vars.CHATS_ZH }}\n CHATS_RU: ${{ vars.CHATS_RU }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n QUIZ_CHATS_KK: ${{ vars.QUIZ_CHATS_KK }}\n QUIZ_CHATS_ZH: ${{ vars.QUIZ_CHATS_ZH }}\n QUIZ_CHATS_RU: ${{ vars.QUIZ_CHATS_RU }}\n CAPTCHA_TIMEOUT_SECONDS: ${{ vars.CAPTCHA_TIMEOUT_SECONDS || '120' }}\n KICK_BAN_DURATION_SECONDS: ${{ vars.KICK_BAN_DURATION_SECONDS || '31' }}\n VOTEBAN_THRESHOLD: ${{ vars.VOTEBAN_THRESHOLD || '7' }}\n VOTEBAN_FORGIVE_THRESHOLD: ${{ vars.VOTEBAN_FORGIVE_THRESHOLD || '7' }}\n CAPTCHA_MAX_ATTEMPTS: ${{ vars.CAPTCHA_MAX_ATTEMPTS || '3' }}\n QUIZ_LLM_RPD: ${{ vars.QUIZ_LLM_RPD || '20' }}\n GROUP_MEMORY_ENABLED: ${{ vars.GROUP_MEMORY_ENABLED || 'true' }}\n GROUP_MEMORY_RECENT_LIMIT: ${{ vars.GROUP_MEMORY_RECENT_LIMIT || '300' }}\n GROUP_MEMORY_RETENTION_DAYS: ${{ vars.GROUP_MEMORY_RETENTION_DAYS || '3650' }}\n GROUP_MEMORY_DAILY_SUMMARY_DAYS: ${{ vars.GROUP_MEMORY_DAILY_SUMMARY_DAYS || '7' }}\n GROUP_MEMORY_DAILY_SUMMARY_MESSAGE_LIMIT: ${{ vars.GROUP_MEMORY_DAILY_SUMMARY_MESSAGE_LIMIT || '500' }}\n VECTOR_MEMORY_ENABLED: ${{ vars.VECTOR_MEMORY_ENABLED || 'true' }}\n VECTOR_MEMORY_PROVIDER: ${{ vars.VECTOR_MEMORY_PROVIDER || 's3_vectors' }}\n VECTOR_MEMORY_DIMENSIONS: ${{ vars.VECTOR_MEMORY_DIMENSIONS || '768' }}\n VECTOR_MEMORY_EMBEDDING_MODEL: ${{ vars.VECTOR_MEMORY_EMBEDDING_MODEL || 'gemini-embedding-2' }}\n VECTOR_MEMORY_INDEX_THROTTLE_SECONDS: ${{ vars.VECTOR_MEMORY_INDEX_THROTTLE_SECONDS || '3' }}\n VECTOR_MEMORY_BACKFILL_BATCH_SIZE: ${{ vars.VECTOR_MEMORY_BACKFILL_BATCH_SIZE || '50' }}\n VECTOR_MEMORY_VECTOR_BUCKET_NAME: ${{ vars.VECTOR_MEMORY_VECTOR_BUCKET_NAME }}\n VECTOR_MEMORY_INDEX_NAME: ${{ vars.VECTOR_MEMORY_INDEX_NAME }}\n AGENT_ENABLED: ${{ vars.AGENT_ENABLED || 'true' }}\n AGENT_BOT_USERNAME: ${{ vars.AGENT_BOT_USERNAME || '@zerde_kz_bot' }}\n AGENT_RECENT_CONTEXT_LIMIT: ${{ vars.AGENT_RECENT_CONTEXT_LIMIT || '100' }}\n AGENT_DAILY_PROACTIVE_LIMIT: ${{ vars.AGENT_DAILY_PROACTIVE_LIMIT || '10' }}\n AGENT_PROACTIVE_SCORE_THRESHOLD: ${{ vars.AGENT_PROACTIVE_SCORE_THRESHOLD || '0.62' }}\n AGENT_PROACTIVE_FINAL_THRESHOLD: ${{ vars.AGENT_PROACTIVE_FINAL_THRESHOLD || '0.72' }}\n run: |\n echo \"๐ Deploying to ${{ env.TARGET_ENV }} environment...\"\n if [ \"${{ env.TARGET_ENV }}\" = \"prod\" ]; then\n # Human approval is enforced by the GitHub \"production\" Environment.\n # Keep CDK non-interactive so the runner never waits for stdin.\n uv run cdk deploy -c env=prod --require-approval never --all\n else\n uv run cdk deploy -c env=dev --require-approval never --all\n fi\n\n - name: Get Deployment Outputs\n if: success()\n working-directory: ./infra\n run: |\n echo \"## ๐ Deployment Successful (Zerde Telegram Bot)\" >> $GITHUB_STEP_SUMMARY\n echo \"Deployed to: **${{ env.TARGET_ENV }}**\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Stack Outputs:\" >> $GITHUB_STEP_SUMMARY\n\n STACK_NAME=\"zerde-serverless-telegram-bot-${{ env.TARGET_ENV }}\"\n\n aws cloudformation describe-stacks \\\n --stack-name $STACK_NAME \\\n --region eu-central-1 \\\n --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' \\\n --output table >> $GITHUB_STEP_SUMMARY || echo \"Could not fetch outputs\" >> $GITHUB_STEP_SUMMARY\n"}, "df65520014de232e57b99eca6bb0a5d7de6d0b1b": {"t": 1785762179.7399454, "n": 5810, "h": "41c4e30e3413d798", "c": "name: Deploy to AWS\n\non:\n push:\n branches:\n - main\n\n workflow_dispatch:\n inputs:\n environment:\n description: \"Target Environment\"\n required: true\n default: \"dev\"\n type: choice\n options:\n - dev\n - prod\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n\njobs:\n deploy:\n name: Deploy to AWS\n runs-on: ubuntu-24.04-arm\n # Manual prod deploys require a GitHub Environment (e.g. \"production\") with approvers; dev is ungated.\n environment: ${{ (github.event_name == 'workflow_dispatch' && inputs.environment == 'prod') && 'production' || 'development' }}\n permissions:\n contents: read\n id-token: write\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n\n - name: Determine Target Environment\n id: determine-env\n run: |\n if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ]; then\n echo \"TARGET_ENV=${{ inputs.environment }}\" >> $GITHUB_ENV\n echo \"Selected manual deployment to: ${{ inputs.environment }}\"\n else\n echo \"TARGET_ENV=dev\" >> $GITHUB_ENV\n echo \"Push event detected. Defaulting deployment to: dev\"\n fi\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n # CLI (npm aws-cdk) version numbering != Python aws-cdk-lib; use a recent 2.1k+ CLI for schema support.\n - name: Install AWS CDK CLI (pinned)\n run: |\n npm install -g aws-cdk@2.1119.0\n uv run cdk --version\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n # API keys and tokens are stored in SSM Parameter Store โ CDK only needs non-secret config.\n - name: CDK Deploy\n working-directory: ./infra\n env:\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG || 'kk' }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE || 'https://api.telegram.org/bot' }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER || 'gemini' }}\n NEWS_GEMINI_MODEL: ${{ vars.NEWS_GEMINI_MODEL }}\n QUIZ_GEMINI_MODEL: ${{ vars.QUIZ_GEMINI_MODEL }}\n WTF_GEMINI_MODEL: ${{ vars.WTF_GEMINI_MODEL }}\n GEMINI_RPD_LIMIT: ${{ vars.GEMINI_RPD_LIMIT }}\n GEMINI_API_BASE: ${{ vars.GEMINI_API_BASE || 'https://generativelanguage.googleapis.com/v1beta/models' }}\n FALLBACK_MODEL: ${{ vars.FALLBACK_MODEL }}\n GROQ_MODEL: ${{ vars.GROQ_MODEL }}\n GROQ_API_BASE: ${{ vars.GROQ_API_BASE || 'https://api.groq.com/openai/v1' }}\n DEEPSEEK_MODEL: ${{ vars.DEEPSEEK_MODEL }}\n DEEPSEEK_API_BASE: ${{ vars.DEEPSEEK_API_BASE || 'https://api.deepseek.com' }}\n ADMIN_USER_ID: ${{ secrets.ADMIN_USER_ID }}\n CHATS_KK: ${{ vars.CHATS_KK }}\n CHATS_ZH: ${{ vars.CHATS_ZH }}\n CHATS_RU: ${{ vars.CHATS_RU }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n QUIZ_CHATS_KK: ${{ vars.QUIZ_CHATS_KK }}\n QUIZ_CHATS_ZH: ${{ vars.QUIZ_CHATS_ZH }}\n QUIZ_CHATS_RU: ${{ vars.QUIZ_CHATS_RU }}\n CAPTCHA_TIMEOUT_SECONDS: ${{ vars.CAPTCHA_TIMEOUT_SECONDS || '120' }}\n KICK_BAN_DURATION_SECONDS: ${{ vars.KICK_BAN_DURATION_SECONDS || '31' }}\n VOTEBAN_THRESHOLD: ${{ vars.VOTEBAN_THRESHOLD || '7' }}\n VOTEBAN_FORGIVE_THRESHOLD: ${{ vars.VOTEBAN_FORGIVE_THRESHOLD || '7' }}\n CAPTCHA_MAX_ATTEMPTS: ${{ vars.CAPTCHA_MAX_ATTEMPTS || '3' }}\n QUIZ_LLM_RPD: ${{ vars.QUIZ_LLM_RPD }}\n GROUP_MEMORY_ENABLED: ${{ vars.GROUP_MEMORY_ENABLED || 'true' }}\n GROUP_MEMORY_RECENT_LIMIT: ${{ vars.GROUP_MEMORY_RECENT_LIMIT || '300' }}\n GROUP_MEMORY_RETENTION_DAYS: ${{ vars.GROUP_MEMORY_RETENTION_DAYS || '30' }}\n AGENT_ENABLED: ${{ vars.AGENT_ENABLED || 'true' }}\n AGENT_BOT_USERNAME: ${{ vars.AGENT_BOT_USERNAME || '@zerde_kz_bot' }}\n AGENT_RECENT_CONTEXT_LIMIT: ${{ vars.AGENT_RECENT_CONTEXT_LIMIT || '100' }}\n AGENT_DAILY_PROACTIVE_LIMIT: ${{ vars.AGENT_DAILY_PROACTIVE_LIMIT || '10' }}\n run: |\n echo \"๐ Deploying to ${{ env.TARGET_ENV }} environment...\"\n if [ \"${{ env.TARGET_ENV }}\" = \"prod\" ]; then\n # Human approval is enforced by the GitHub \"production\" Environment.\n # Keep CDK non-interactive so the runner never waits for stdin.\n uv run cdk deploy -c env=prod --require-approval never --all\n else\n uv run cdk deploy -c env=dev --require-approval never --all\n fi\n\n - name: Get Deployment Outputs\n if: success()\n working-directory: ./infra\n run: |\n echo \"## ๐ Deployment Successful (Zerde Telegram Bot)\" >> $GITHUB_STEP_SUMMARY\n echo \"Deployed to: **${{ env.TARGET_ENV }}**\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Stack Outputs:\" >> $GITHUB_STEP_SUMMARY\n\n STACK_NAME=\"zerde-serverless-telegram-bot-${{ env.TARGET_ENV }}\"\n\n aws cloudformation describe-stacks \\\n --stack-name $STACK_NAME \\\n --region eu-central-1 \\\n --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' \\\n --output table >> $GITHUB_STEP_SUMMARY || echo \"Could not fetch outputs\" >> $GITHUB_STEP_SUMMARY\n"}, "3dec0a564f626ae04add95d35b0133735970fd2f": {"t": 1785762190.3928723, "n": 5250, "h": "5813faccd1e8ae89", "c": "name: Deploy to AWS\n\non:\n push:\n branches:\n - main\n\n workflow_dispatch:\n inputs:\n environment:\n description: \"Target Environment\"\n required: true\n default: \"dev\"\n type: choice\n options:\n - dev\n - prod\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n\njobs:\n deploy:\n name: Deploy to AWS\n runs-on: ubuntu-24.04-arm\n # Manual prod deploys require a GitHub Environment (e.g. \"production\") with approvers; dev is ungated.\n environment: ${{ (github.event_name == 'workflow_dispatch' && inputs.environment == 'prod') && 'production' || 'development' }}\n permissions:\n contents: read\n id-token: write\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n\n - name: Determine Target Environment\n id: determine-env\n run: |\n if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ]; then\n echo \"TARGET_ENV=${{ inputs.environment }}\" >> $GITHUB_ENV\n echo \"Selected manual deployment to: ${{ inputs.environment }}\"\n else\n echo \"TARGET_ENV=dev\" >> $GITHUB_ENV\n echo \"Push event detected. Defaulting deployment to: dev\"\n fi\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n # CLI (npm aws-cdk) version numbering != Python aws-cdk-lib; use a recent 2.1k+ CLI for schema support.\n - name: Install AWS CDK CLI (pinned)\n run: |\n npm install -g aws-cdk@2.1119.0\n uv run cdk --version\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n # API keys and tokens are stored in SSM Parameter Store โ CDK only needs non-secret config.\n - name: CDK Deploy\n working-directory: ./infra\n env:\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG || 'kk' }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE || 'https://api.telegram.org/bot' }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER || 'gemini' }}\n NEWS_GEMINI_MODEL: ${{ vars.NEWS_GEMINI_MODEL }}\n QUIZ_GEMINI_MODEL: ${{ vars.QUIZ_GEMINI_MODEL }}\n WTF_GEMINI_MODEL: ${{ vars.WTF_GEMINI_MODEL }}\n GEMINI_RPD_LIMIT: ${{ vars.GEMINI_RPD_LIMIT }}\n GEMINI_API_BASE: ${{ vars.GEMINI_API_BASE || 'https://generativelanguage.googleapis.com/v1beta/models' }}\n FALLBACK_MODEL: ${{ vars.FALLBACK_MODEL }}\n GROQ_MODEL: ${{ vars.GROQ_MODEL }}\n GROQ_API_BASE: ${{ vars.GROQ_API_BASE || 'https://api.groq.com/openai/v1' }}\n DEEPSEEK_MODEL: ${{ vars.DEEPSEEK_MODEL }}\n DEEPSEEK_API_BASE: ${{ vars.DEEPSEEK_API_BASE || 'https://api.deepseek.com' }}\n ADMIN_USER_ID: ${{ secrets.ADMIN_USER_ID }}\n CHATS_KK: ${{ vars.CHATS_KK }}\n CHATS_ZH: ${{ vars.CHATS_ZH }}\n CHATS_RU: ${{ vars.CHATS_RU }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n QUIZ_CHATS_KK: ${{ vars.QUIZ_CHATS_KK }}\n QUIZ_CHATS_ZH: ${{ vars.QUIZ_CHATS_ZH }}\n QUIZ_CHATS_RU: ${{ vars.QUIZ_CHATS_RU }}\n CAPTCHA_TIMEOUT_SECONDS: ${{ vars.CAPTCHA_TIMEOUT_SECONDS || '120' }}\n KICK_BAN_DURATION_SECONDS: ${{ vars.KICK_BAN_DURATION_SECONDS || '31' }}\n VOTEBAN_THRESHOLD: ${{ vars.VOTEBAN_THRESHOLD || '7' }}\n VOTEBAN_FORGIVE_THRESHOLD: ${{ vars.VOTEBAN_FORGIVE_THRESHOLD || '7' }}\n CAPTCHA_MAX_ATTEMPTS: ${{ vars.CAPTCHA_MAX_ATTEMPTS || '3' }}\n QUIZ_LLM_RPD: ${{ vars.QUIZ_LLM_RPD }}\n run: |\n echo \"๐ Deploying to ${{ env.TARGET_ENV }} environment...\"\n if [ \"${{ env.TARGET_ENV }}\" = \"prod\" ]; then\n # Human approval is enforced by the GitHub \"production\" Environment.\n # Keep CDK non-interactive so the runner never waits for stdin.\n uv run cdk deploy -c env=prod --require-approval never --all\n else\n uv run cdk deploy -c env=dev --require-approval never --all\n fi\n\n - name: Get Deployment Outputs\n if: success()\n working-directory: ./infra\n run: |\n echo \"## ๐ Deployment Successful (Zerde Telegram Bot)\" >> $GITHUB_STEP_SUMMARY\n echo \"Deployed to: **${{ env.TARGET_ENV }}**\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Stack Outputs:\" >> $GITHUB_STEP_SUMMARY\n\n STACK_NAME=\"zerde-serverless-telegram-bot-${{ env.TARGET_ENV }}\"\n\n aws cloudformation describe-stacks \\\n --stack-name $STACK_NAME \\\n --region eu-central-1 \\\n --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' \\\n --output table >> $GITHUB_STEP_SUMMARY || echo \"Could not fetch outputs\" >> $GITHUB_STEP_SUMMARY\n"}, "d3cb1b535a9c4346add997f75e09177134440fed": {"t": 1785762192.5816777, "n": 5463, "h": "1188a15201234e1d", "c": "name: Deploy to AWS\n\non:\n push:\n branches:\n - main\n\n workflow_dispatch:\n inputs:\n environment:\n description: \"Target Environment\"\n required: true\n default: \"dev\"\n type: choice\n options:\n - dev\n - prod\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n\njobs:\n deploy:\n name: Deploy to AWS\n runs-on: ubuntu-latest\n permissions:\n contents: read\n id-token: write\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n\n - name: Determine Target Environment\n id: determine-env\n run: |\n if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ]; then\n echo \"TARGET_ENV=${{ inputs.environment }}\" >> $GITHUB_ENV\n echo \"Selected manual deployment to: ${{ inputs.environment }}\"\n else\n echo \"TARGET_ENV=dev\" >> $GITHUB_ENV\n echo \"Push event detected. Defaulting deployment to: dev\"\n fi\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n uv run cdk --version\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n # Secrets: tokens and API keys. Variables: models, chat IDs, thresholds (see infra/stack.py).\n - name: CDK Deploy\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n GEMINI_API_KEY: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_GEMINI_API_KEY || secrets.DEV_GEMINI_API_KEY }}\n GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}\n DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}\n LLAMA_API_KEY: ${{ secrets.LLAMA_API_KEY }}\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG || 'kk' }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE || 'https://api.telegram.org/bot' }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER || 'gemini' }}\n NEWS_GEMINI_MODEL: ${{ vars.NEWS_GEMINI_MODEL || 'gemini-3-flash-preview' }}\n QUIZ_GEMINI_MODEL: ${{ vars.QUIZ_GEMINI_MODEL || 'gemini-2.5-flash-lite' }}\n WTF_GEMINI_MODEL: ${{ vars.WTF_GEMINI_MODEL || 'gemini-3.1-flash-lite-preview' }}\n GEMINI_RPD_LIMIT: ${{ vars.GEMINI_RPD_LIMIT || '500' }}\n GEMINI_API_BASE: ${{ vars.GEMINI_API_BASE || 'https://generativelanguage.googleapis.com/v1beta/models' }}\n FALLBACK_MODEL: ${{ vars.FALLBACK_MODEL || 'gemini-2.5-flash' }}\n WTF_FALLBACK_PROVIDER: ${{ vars.WTF_FALLBACK_PROVIDER || 'deepseek' }}\n GROQ_MODEL: ${{ vars.GROQ_MODEL || 'llama-3.3-70b-versatile' }}\n GROQ_API_BASE: ${{ vars.GROQ_API_BASE || 'https://api.groq.com/openai/v1' }}\n LLAMA_MODEL: ${{ vars.LLAMA_MODEL || 'Llama-4-Scout-17B-16E-Instruct-FP8' }}\n LLAMA_API_BASE: ${{ vars.LLAMA_API_BASE || 'https://api.llama.com/v1' }}\n DEEPSEEK_MODEL: ${{ vars.DEEPSEEK_MODEL || 'deepseek-chat' }}\n DEEPSEEK_API_BASE: ${{ vars.DEEPSEEK_API_BASE || 'https://api.deepseek.com' }}\n ADMIN_USER_ID: ${{ secrets.ADMIN_USER_ID }}\n CHATS_KK: ${{ vars.CHATS_KK }}\n CHATS_ZH: ${{ vars.CHATS_ZH }}\n CHATS_RU: ${{ vars.CHATS_RU }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n QUIZ_CHATS_KK: ${{ vars.QUIZ_CHATS_KK }}\n QUIZ_CHATS_ZH: ${{ vars.QUIZ_CHATS_ZH }}\n QUIZ_CHATS_RU: ${{ vars.QUIZ_CHATS_RU }}\n CAPTCHA_TIMEOUT_SECONDS: ${{ vars.CAPTCHA_TIMEOUT_SECONDS || '120' }}\n KICK_BAN_DURATION_SECONDS: ${{ vars.KICK_BAN_DURATION_SECONDS || '31' }}\n VOTEBAN_THRESHOLD: ${{ vars.VOTEBAN_THRESHOLD || '7' }}\n VOTEBAN_FORGIVE_THRESHOLD: ${{ vars.VOTEBAN_FORGIVE_THRESHOLD || '7' }}\n run: |\n echo \"๐ Deploying to ${{ env.TARGET_ENV }} environment...\"\n uv run cdk deploy -c env=${{ env.TARGET_ENV }} --require-approval never --all\n\n - name: Get Deployment Outputs\n if: success()\n working-directory: ./infra\n run: |\n echo \"## ๐ Deployment Successful (Zerde Telegram Bot)\" >> $GITHUB_STEP_SUMMARY\n echo \"Deployed to: **${{ env.TARGET_ENV }}**\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Stack Outputs:\" >> $GITHUB_STEP_SUMMARY\n\n STACK_NAME=\"zerde-serverless-telegram-bot-${{ env.TARGET_ENV }}\"\n\n aws cloudformation describe-stacks \\\n --stack-name $STACK_NAME \\\n --region eu-central-1 \\\n --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' \\\n --output table >> $GITHUB_STEP_SUMMARY || echo \"Could not fetch outputs\" >> $GITHUB_STEP_SUMMARY\n"}, "723c3b83954f7bddcf929ed8f9f70f53c281e8c7": {"t": 1785762201.6162353, "n": 5462, "h": "4f1dc3455585fc85", "c": "name: Deploy to AWS\n\non:\n push:\n branches:\n - main\n\n workflow_dispatch:\n inputs:\n environment:\n description: \"Target Environment\"\n required: true\n default: \"dev\"\n type: choice\n options:\n - dev\n - prod\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n\njobs:\n deploy:\n name: Deploy to AWS\n runs-on: ubuntu-latest\n permissions:\n contents: read\n id-token: write\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n\n - name: Determine Target Environment\n id: determine-env\n run: |\n if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ]; then\n echo \"TARGET_ENV=${{ inputs.environment }}\" >> $GITHUB_ENV\n echo \"Selected manual deployment to: ${{ inputs.environment }}\"\n else\n echo \"TARGET_ENV=dev\" >> $GITHUB_ENV\n echo \"Push event detected. Defaulting deployment to: dev\"\n fi\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n uv run cdk --version\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n # Secrets: tokens and API keys. Variables: models, chat IDs, thresholds (see infra/stack.py).\n - name: CDK Deploy\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n GEMINI_API_KEY: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_GEMINI_API_KEY || secrets.DEV_GEMINI_API_KEY }}\n GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}\n DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}\n LLAMA_API_KEY: ${{ secrets.LLAMA_API_KEY }}\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG || 'kk' }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE || 'https://api.telegram.org/bot' }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER || 'gemini' }}\n NEWS_GEMINI_MODEL: ${{ vars.NEWS_GEMINI_MODEL || 'gemini-3-flash-preview' }}\n QUIZ_GEMINI_MODEL: ${{ vars.QUIZ_GEMINI_MODEL || 'gemini-2.5-flash-lite' }}\n WTF_GEMINI_MODEL: ${{ vars.WTF_GEMINI_MODEL || 'gemini-3.1-flash-lite-preview' }}\n GEMINI_RPD_LIMIT: ${{ vars.GEMINI_RPD_LIMIT || '500' }}\n GEMINI_API_BASE: ${{ vars.GEMINI_API_BASE || 'https://generativelanguage.googleapis.com/v1beta/models' }}\n FALLBACK_MODEL: ${{ vars.FALLBACK_MODEL || 'gemini-2.5-flash' }}\n WTF_FALLBACK_PROVIDER: ${{ vars.WTF_FALLBACK_PROVIDER || 'deepseek' }}\n GROQ_MODEL: ${{ vars.GROQ_MODEL || 'llama-3.3-70b-versatile' }}\n GROQ_API_BASE: ${{ vars.GROQ_API_BASE || 'https://api.groq.com/openai/v1' }}\n LLAMA_MODEL: ${{ vars.LLAMA_MODEL || 'Llama-4-Scout-17B-16E-Instruct-FP8' }}\n LLAMA_API_BASE: ${{ vars.LLAMA_API_BASE || 'https://api.llama.com/v1' }}\n DEEPSEEK_MODEL: ${{ vars.DEEPSEEK_MODEL || 'deepseek-chat' }}\n DEEPSEEK_API_BASE: ${{ vars.DEEPSEEK_API_BASE || 'https://api.deepseek.com' }}\n ADMIN_USER_ID: ${{ secrets.ADMIN_USER_ID }}\n CHATS_KK: ${{ vars.CHATS_KK }}\n CHATS_ZH: ${{ vars.CHATS_ZH }}\n CHATS_RU: ${{ vars.CHATS_RU }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n QUIZ_CHATS_KK: ${{ vars.QUIZ_CHATS_KK }}\n QUIZ_CHATS_ZH: ${{ vars.QUIZ_CHATS_ZH }}\n QUIZ_CHATS_RU: ${{ vars.QUIZ_CHATS_RU }}\n CAPTCHA_TIMEOUT_SECONDS: ${{ vars.CAPTCHA_TIMEOUT_SECONDS || '60' }}\n KICK_BAN_DURATION_SECONDS: ${{ vars.KICK_BAN_DURATION_SECONDS || '31' }}\n VOTEBAN_THRESHOLD: ${{ vars.VOTEBAN_THRESHOLD || '7' }}\n VOTEBAN_FORGIVE_THRESHOLD: ${{ vars.VOTEBAN_FORGIVE_THRESHOLD || '7' }}\n run: |\n echo \"๐ Deploying to ${{ env.TARGET_ENV }} environment...\"\n uv run cdk deploy -c env=${{ env.TARGET_ENV }} --require-approval never --all\n\n - name: Get Deployment Outputs\n if: success()\n working-directory: ./infra\n run: |\n echo \"## ๐ Deployment Successful (Zerde Telegram Bot)\" >> $GITHUB_STEP_SUMMARY\n echo \"Deployed to: **${{ env.TARGET_ENV }}**\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Stack Outputs:\" >> $GITHUB_STEP_SUMMARY\n\n STACK_NAME=\"zerde-serverless-telegram-bot-${{ env.TARGET_ENV }}\"\n\n aws cloudformation describe-stacks \\\n --stack-name $STACK_NAME \\\n --region eu-central-1 \\\n --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' \\\n --output table >> $GITHUB_STEP_SUMMARY || echo \"Could not fetch outputs\" >> $GITHUB_STEP_SUMMARY\n"}, "f3bb730a668c177fbcc7662a59dc6632032e7ab0": {"t": 1785762204.3637223, "n": 5156, "h": "cf609801f5f7be16", "c": "name: Deploy to AWS\n\non:\n push:\n branches:\n - main\n\n workflow_dispatch:\n inputs:\n environment:\n description: \"Target Environment\"\n required: true\n default: \"dev\"\n type: choice\n options:\n - dev\n - prod\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n\njobs:\n deploy:\n name: Deploy to AWS\n runs-on: ubuntu-latest\n permissions:\n contents: read\n id-token: write\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n\n - name: Determine Target Environment\n id: determine-env\n run: |\n if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ]; then\n echo \"TARGET_ENV=${{ inputs.environment }}\" >> $GITHUB_ENV\n echo \"Selected manual deployment to: ${{ inputs.environment }}\"\n else\n echo \"TARGET_ENV=dev\" >> $GITHUB_ENV\n echo \"Push event detected. Defaulting deployment to: dev\"\n fi\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n uv run cdk --version\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n # Secrets: tokens and API keys. Variables: models, chat IDs, thresholds (see infra/stack.py).\n - name: CDK Deploy\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n GEMINI_API_KEY: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_GEMINI_API_KEY || secrets.DEV_GEMINI_API_KEY }}\n GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}\n DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}\n LLAMA_API_KEY: ${{ secrets.LLAMA_API_KEY }}\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG || 'kk' }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE || 'https://api.telegram.org/bot' }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER || 'gemini' }}\n NEWS_GEMINI_MODEL: ${{ vars.NEWS_GEMINI_MODEL || 'gemini-3-flash-preview' }}\n QUIZ_GEMINI_MODEL: ${{ vars.QUIZ_GEMINI_MODEL || 'gemini-2.5-flash-lite' }}\n WTF_GEMINI_MODEL: ${{ vars.WTF_GEMINI_MODEL || 'gemini-3.1-flash-lite-preview' }}\n GEMINI_RPD_LIMIT: ${{ vars.GEMINI_RPD_LIMIT || '500' }}\n GEMINI_API_BASE: ${{ vars.GEMINI_API_BASE || 'https://generativelanguage.googleapis.com/v1beta/models' }}\n FALLBACK_MODEL: ${{ vars.FALLBACK_MODEL || 'gemini-2.5-flash' }}\n WTF_FALLBACK_PROVIDER: ${{ vars.WTF_FALLBACK_PROVIDER || 'deepseek' }}\n GROQ_MODEL: ${{ vars.GROQ_MODEL || 'llama-3.3-70b-versatile' }}\n GROQ_API_BASE: ${{ vars.GROQ_API_BASE || 'https://api.groq.com/openai/v1' }}\n LLAMA_MODEL: ${{ vars.LLAMA_MODEL || 'Llama-4-Scout-17B-16E-Instruct-FP8' }}\n LLAMA_API_BASE: ${{ vars.LLAMA_API_BASE || 'https://api.llama.com/v1' }}\n DEEPSEEK_MODEL: ${{ vars.DEEPSEEK_MODEL || 'deepseek-chat' }}\n DEEPSEEK_API_BASE: ${{ vars.DEEPSEEK_API_BASE || 'https://api.deepseek.com' }}\n ADMIN_USER_ID: ${{ secrets.ADMIN_USER_ID }}\n CHATS_KK: ${{ vars.CHATS_KK }}\n CHATS_ZH: ${{ vars.CHATS_ZH }}\n CHATS_RU: ${{ vars.CHATS_RU }}\n CAPTCHA_TIMEOUT_SECONDS: ${{ vars.CAPTCHA_TIMEOUT_SECONDS || '60' }}\n KICK_BAN_DURATION_SECONDS: ${{ vars.KICK_BAN_DURATION_SECONDS || '31' }}\n VOTEBAN_THRESHOLD: ${{ vars.VOTEBAN_THRESHOLD || '7' }}\n VOTEBAN_FORGIVE_THRESHOLD: ${{ vars.VOTEBAN_FORGIVE_THRESHOLD || '7' }}\n run: |\n echo \"๐ Deploying to ${{ env.TARGET_ENV }} environment...\"\n uv run cdk deploy -c env=${{ env.TARGET_ENV }} --require-approval never --all\n\n - name: Get Deployment Outputs\n if: success()\n working-directory: ./infra\n run: |\n echo \"## ๐ Deployment Successful (Zerde Telegram Bot)\" >> $GITHUB_STEP_SUMMARY\n echo \"Deployed to: **${{ env.TARGET_ENV }}**\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Stack Outputs:\" >> $GITHUB_STEP_SUMMARY\n\n STACK_NAME=\"zerde-serverless-telegram-bot-${{ env.TARGET_ENV }}\"\n\n aws cloudformation describe-stacks \\\n --stack-name $STACK_NAME \\\n --region eu-central-1 \\\n --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' \\\n --output table >> $GITHUB_STEP_SUMMARY || echo \"Could not fetch outputs\" >> $GITHUB_STEP_SUMMARY\n"}, "c6cdedc1a89beca18eb5c0823c4d458545112552": {"t": 1785762205.678688, "n": 5062, "h": "9f3e70f135a5ef05", "c": "name: Deploy to AWS\n\non:\n push:\n branches:\n - main\n\n workflow_dispatch:\n inputs:\n environment:\n description: 'Target Environment'\n required: true\n default: 'dev'\n type: choice\n options:\n - dev\n - prod\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n\njobs:\n deploy:\n name: Deploy to AWS\n runs-on: ubuntu-latest\n permissions:\n contents: read\n id-token: write\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n\n - name: Determine Target Environment\n id: determine-env\n run: |\n if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ]; then\n # If manual trigger, use user-selected input (dev or prod)\n echo \"TARGET_ENV=${{ inputs.environment }}\" >> $GITHUB_ENV\n echo \"Selected manual deployment to: ${{ inputs.environment }}\"\n else\n # If Push to main, force deployment to dev\n echo \"TARGET_ENV=dev\" >> $GITHUB_ENV\n echo \"Push event detected. Defaulting deployment to: dev\"\n fi\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n uv run cdk --version\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n # - name: CDK Bootstrap (usually only needs to run once, but kept here as a safeguard)\n # working-directory: ./infra\n # env:\n # TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n # TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n # GEMINI_API_KEY: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_GEMINI_API_KEY || secrets.DEV_GEMINI_API_KEY }}\n # NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n # NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n # NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n # AI_PROVIDER: ${{ vars.AI_PROVIDER }}\n # LLM_MODEL: ${{ vars.LLM_MODEL }}\n # DEFAULT_LANG: ${{ vars.DEFAULT_LANG }}\n # TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE }}\n # run: |\n # uv run cdk bootstrap aws://$(aws sts get-caller-identity --query Account --output text)/eu-central-1 || echo \"Bootstrap may already be done\"\n # continue-on-error: true\n\n - name: CDK Deploy\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n GEMINI_API_KEY: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_GEMINI_API_KEY || secrets.DEV_GEMINI_API_KEY }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER }}\n LLM_MODEL: ${{ vars.LLM_MODEL }}\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE }}\n QUIZ_CHATS_KK: ${{ vars.QUIZ_CHATS_KK }}\n QUIZ_CHATS_ZH: ${{ vars.QUIZ_CHATS_ZH }}\n QUIZ_CHATS_RU: ${{ vars.QUIZ_CHATS_RU }}\n GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}\n ADMIN_USER_ID: ${{ secrets.ADMIN_USER_ID }}\n run: |\n echo \"๐ Deploying to ${{ env.TARGET_ENV }} environment...\"\n uv run cdk deploy -c env=${{ env.TARGET_ENV }} --require-approval never --all\n\n - name: Get Deployment Outputs\n if: success()\n working-directory: ./infra\n run: |\n echo \"## ๐ Deployment Successful (Zerde Telegram Bot)\" >> $GITHUB_STEP_SUMMARY\n echo \"Deployed to: **${{ env.TARGET_ENV }}**\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Stack Outputs:\" >> $GITHUB_STEP_SUMMARY\n\n # Get the stack name based on the environment (zerde-serverless-telegram-bot-{env})\n STACK_NAME=\"zerde-serverless-telegram-bot-${{ env.TARGET_ENV }}\"\n\n aws cloudformation describe-stacks \\\n --stack-name $STACK_NAME \\\n --region eu-central-1 \\\n --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' \\\n --output table >> $GITHUB_STEP_SUMMARY || echo \"Could not fetch outputs\" >> $GITHUB_STEP_SUMMARY\n"}, "8cefb0936bead74357960f11d0da536263a3189d": {"t": 1785762208.7696738, "n": 5159, "h": "ff235d1211c0cea3", "c": "name: Deploy to AWS\n\non:\n push:\n branches:\n - main\n\n workflow_dispatch:\n inputs:\n environment:\n description: 'Target Environment'\n required: true\n default: 'dev'\n type: choice\n options:\n - dev\n - prod\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n\njobs:\n deploy:\n name: Deploy to AWS\n runs-on: ubuntu-latest\n permissions:\n contents: read\n id-token: write\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n\n - name: Determine Target Environment\n id: determine-env\n run: |\n if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ]; then\n # If manual trigger, use user-selected input (dev or prod)\n echo \"TARGET_ENV=${{ inputs.environment }}\" >> $GITHUB_ENV\n echo \"Selected manual deployment to: ${{ inputs.environment }}\"\n else\n # If Push to main, force deployment to dev\n echo \"TARGET_ENV=dev\" >> $GITHUB_ENV\n echo \"Push event detected. Defaulting deployment to: dev\"\n fi\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n uv run cdk --version\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n # - name: CDK Bootstrap (usually only needs to run once, but kept here as a safeguard)\n # working-directory: ./infra\n # env:\n # TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n # TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n # GEMINI_API_KEY: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_GEMINI_API_KEY || secrets.DEV_GEMINI_API_KEY }}\n # NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n # NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n # NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n # AI_PROVIDER: ${{ vars.AI_PROVIDER }}\n # LLM_MODEL: ${{ vars.LLM_MODEL }}\n # DEFAULT_LANG: ${{ vars.DEFAULT_LANG }}\n # TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE }}\n # run: |\n # uv run cdk bootstrap aws://$(aws sts get-caller-identity --query Account --output text)/eu-central-1 || echo \"Bootstrap may already be done\"\n # continue-on-error: true\n\n - name: CDK Deploy\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n GEMINI_API_KEY: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_GEMINI_API_KEY || secrets.DEV_GEMINI_API_KEY }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER }}\n LLM_MODEL: ${{ vars.LLM_MODEL }}\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE }}\n QUIZ_CHATS_KK: ${{ vars.QUIZ_CHATS_KK }}\n QUIZ_CHATS_ZH: ${{ vars.QUIZ_CHATS_ZH }}\n QUIZ_CHATS_RU: ${{ vars.QUIZ_CHATS_RU }}\n QUIZAPI_KEY: ${{ secrets.QUIZAPI_KEY }}\n GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}\n QUIZ_CHATS: ${{ env.TARGET_ENV == 'prod' && vars.PROD_QUIZ_CHATS || vars.DEV_QUIZ_CHATS }}\n run: |\n echo \"๐ Deploying to ${{ env.TARGET_ENV }} environment...\"\n uv run cdk deploy -c env=${{ env.TARGET_ENV }} --require-approval never --all\n\n - name: Get Deployment Outputs\n if: success()\n working-directory: ./infra\n run: |\n echo \"## ๐ Deployment Successful (Zerde Telegram Bot)\" >> $GITHUB_STEP_SUMMARY\n echo \"Deployed to: **${{ env.TARGET_ENV }}**\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Stack Outputs:\" >> $GITHUB_STEP_SUMMARY\n\n # Get the stack name based on the environment (zerde-serverless-telegram-bot-{env})\n STACK_NAME=\"zerde-serverless-telegram-bot-${{ env.TARGET_ENV }}\"\n\n aws cloudformation describe-stacks \\\n --stack-name $STACK_NAME \\\n --region eu-central-1 \\\n --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' \\\n --output table >> $GITHUB_STEP_SUMMARY || echo \"Could not fetch outputs\" >> $GITHUB_STEP_SUMMARY\n"}, "5408a33fad69e33fbe7d01350ebf5f97ce855494": {"t": 1785762211.786489, "n": 5006, "h": "f566dd4ed3a1bb04", "c": "name: Deploy to AWS\n\non:\n push:\n branches:\n - main\n\n workflow_dispatch:\n inputs:\n environment:\n description: 'Target Environment'\n required: true\n default: 'dev'\n type: choice\n options:\n - dev\n - prod\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n\njobs:\n deploy:\n name: Deploy to AWS\n runs-on: ubuntu-latest\n permissions:\n contents: read\n id-token: write\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n\n - name: Determine Target Environment\n id: determine-env\n run: |\n if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ]; then\n # If manual trigger, use user-selected input (dev or prod)\n echo \"TARGET_ENV=${{ inputs.environment }}\" >> $GITHUB_ENV\n echo \"Selected manual deployment to: ${{ inputs.environment }}\"\n else\n # If Push to main, force deployment to dev\n echo \"TARGET_ENV=dev\" >> $GITHUB_ENV\n echo \"Push event detected. Defaulting deployment to: dev\"\n fi\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n uv run cdk --version\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n # - name: CDK Bootstrap (usually only needs to run once, but kept here as a safeguard)\n # working-directory: ./infra\n # env:\n # TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n # TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n # GEMINI_API_KEY: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_GEMINI_API_KEY || secrets.DEV_GEMINI_API_KEY }}\n # NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n # NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n # NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n # AI_PROVIDER: ${{ vars.AI_PROVIDER }}\n # LLM_MODEL: ${{ vars.LLM_MODEL }}\n # DEFAULT_LANG: ${{ vars.DEFAULT_LANG }}\n # TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE }}\n # run: |\n # uv run cdk bootstrap aws://$(aws sts get-caller-identity --query Account --output text)/eu-central-1 || echo \"Bootstrap may already be done\"\n # continue-on-error: true\n\n - name: CDK Deploy\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n GEMINI_API_KEY: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_GEMINI_API_KEY || secrets.DEV_GEMINI_API_KEY }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER }}\n LLM_MODEL: ${{ vars.LLM_MODEL }}\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE }}\n QUIZAPI_KEY: ${{ secrets.QUIZAPI_KEY }}\n GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}\n QUIZ_CHATS: ${{ env.TARGET_ENV == 'prod' && vars.PROD_QUIZ_CHATS || vars.DEV_QUIZ_CHATS }}\n run: |\n echo \"๐ Deploying to ${{ env.TARGET_ENV }} environment...\"\n uv run cdk deploy -c env=${{ env.TARGET_ENV }} --require-approval never --all\n\n - name: Get Deployment Outputs\n if: success()\n working-directory: ./infra\n run: |\n echo \"## ๐ Deployment Successful (Zerde Telegram Bot)\" >> $GITHUB_STEP_SUMMARY\n echo \"Deployed to: **${{ env.TARGET_ENV }}**\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Stack Outputs:\" >> $GITHUB_STEP_SUMMARY\n\n # Get the stack name based on the environment (zerde-serverless-telegram-bot-{env})\n STACK_NAME=\"zerde-serverless-telegram-bot-${{ env.TARGET_ENV }}\"\n\n aws cloudformation describe-stacks \\\n --stack-name $STACK_NAME \\\n --region eu-central-1 \\\n --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' \\\n --output table >> $GITHUB_STEP_SUMMARY || echo \"Could not fetch outputs\" >> $GITHUB_STEP_SUMMARY\n"}, "15173cad5f72cc6bdb1a3f5fdafce474129bfbfc": {"t": 1785762215.7424743, "n": 4954, "h": "48f303a56aff0645", "c": "name: Deploy to AWS\n\non:\n push:\n branches:\n - main\n\n workflow_dispatch:\n inputs:\n environment:\n description: 'Target Environment'\n required: true\n default: 'dev'\n type: choice\n options:\n - dev\n - prod\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n\njobs:\n deploy:\n name: Deploy to AWS\n runs-on: ubuntu-latest\n permissions:\n contents: read\n id-token: write\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n\n - name: Determine Target Environment\n id: determine-env\n run: |\n if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ]; then\n # If manual trigger, use user-selected input (dev or prod)\n echo \"TARGET_ENV=${{ inputs.environment }}\" >> $GITHUB_ENV\n echo \"Selected manual deployment to: ${{ inputs.environment }}\"\n else\n # If Push to main, force deployment to dev\n echo \"TARGET_ENV=dev\" >> $GITHUB_ENV\n echo \"Push event detected. Defaulting deployment to: dev\"\n fi\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n uv run cdk --version\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n # - name: CDK Bootstrap (usually only needs to run once, but kept here as a safeguard)\n # working-directory: ./infra\n # env:\n # TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n # TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n # GEMINI_API_KEY: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_GEMINI_API_KEY || secrets.DEV_GEMINI_API_KEY }}\n # NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n # NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n # NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n # AI_PROVIDER: ${{ vars.AI_PROVIDER }}\n # LLM_MODEL: ${{ vars.LLM_MODEL }}\n # DEFAULT_LANG: ${{ vars.DEFAULT_LANG }}\n # TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE }}\n # run: |\n # uv run cdk bootstrap aws://$(aws sts get-caller-identity --query Account --output text)/eu-central-1 || echo \"Bootstrap may already be done\"\n # continue-on-error: true\n\n - name: CDK Deploy\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n GEMINI_API_KEY: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_GEMINI_API_KEY || secrets.DEV_GEMINI_API_KEY }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER }}\n LLM_MODEL: ${{ vars.LLM_MODEL }}\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE }}\n QUIZAPI_KEY: ${{ secrets.QUIZAPI_KEY }}\n QUIZ_CHATS: ${{ env.TARGET_ENV == 'prod' && vars.PROD_QUIZ_CHATS || vars.DEV_QUIZ_CHATS }}\n run: |\n echo \"๐ Deploying to ${{ env.TARGET_ENV }} environment...\"\n uv run cdk deploy -c env=${{ env.TARGET_ENV }} --require-approval never --all\n\n - name: Get Deployment Outputs\n if: success()\n working-directory: ./infra\n run: |\n echo \"## ๐ Deployment Successful (Zerde Telegram Bot)\" >> $GITHUB_STEP_SUMMARY\n echo \"Deployed to: **${{ env.TARGET_ENV }}**\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Stack Outputs:\" >> $GITHUB_STEP_SUMMARY\n\n # Get the stack name based on the environment (zerde-serverless-telegram-bot-{env})\n STACK_NAME=\"zerde-serverless-telegram-bot-${{ env.TARGET_ENV }}\"\n\n aws cloudformation describe-stacks \\\n --stack-name $STACK_NAME \\\n --region eu-central-1 \\\n --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' \\\n --output table >> $GITHUB_STEP_SUMMARY || echo \"Could not fetch outputs\" >> $GITHUB_STEP_SUMMARY\n"}, "0eef8c261ddc38e968237ba55d610d96fd28007e": {"t": 1785762217.5565028, "n": 4803, "h": "e347f0577ad48061", "c": "name: Deploy to AWS\n\non:\n push:\n branches:\n - main\n\n workflow_dispatch:\n inputs:\n environment:\n description: 'Target Environment'\n required: true\n default: 'dev'\n type: choice\n options:\n - dev\n - prod\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n\njobs:\n deploy:\n name: Deploy to AWS\n runs-on: ubuntu-latest\n permissions:\n contents: read\n id-token: write\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n\n - name: Determine Target Environment\n id: determine-env\n run: |\n if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ]; then\n # If manual trigger, use user-selected input (dev or prod)\n echo \"TARGET_ENV=${{ inputs.environment }}\" >> $GITHUB_ENV\n echo \"Selected manual deployment to: ${{ inputs.environment }}\"\n else\n # If Push to main, force deployment to dev\n echo \"TARGET_ENV=dev\" >> $GITHUB_ENV\n echo \"Push event detected. Defaulting deployment to: dev\"\n fi\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n uv run cdk --version\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n # - name: CDK Bootstrap (usually only needs to run once, but kept here as a safeguard)\n # working-directory: ./infra\n # env:\n # TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n # TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n # GEMINI_API_KEY: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_GEMINI_API_KEY || secrets.DEV_GEMINI_API_KEY }}\n # NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n # NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n # NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n # AI_PROVIDER: ${{ vars.AI_PROVIDER }}\n # LLM_MODEL: ${{ vars.LLM_MODEL }}\n # DEFAULT_LANG: ${{ vars.DEFAULT_LANG }}\n # TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE }}\n # run: |\n # uv run cdk bootstrap aws://$(aws sts get-caller-identity --query Account --output text)/eu-central-1 || echo \"Bootstrap may already be done\"\n # continue-on-error: true\n\n - name: CDK Deploy\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n GEMINI_API_KEY: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_GEMINI_API_KEY || secrets.DEV_GEMINI_API_KEY }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER }}\n LLM_MODEL: ${{ vars.LLM_MODEL }}\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE }}\n run: |\n echo \"๐ Deploying to ${{ env.TARGET_ENV }} environment...\"\n uv run cdk deploy -c env=${{ env.TARGET_ENV }} --require-approval never --all\n\n - name: Get Deployment Outputs\n if: success()\n working-directory: ./infra\n run: |\n echo \"## ๐ Deployment Successful (Zerde Telegram Bot)\" >> $GITHUB_STEP_SUMMARY\n echo \"Deployed to: **${{ env.TARGET_ENV }}**\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Stack Outputs:\" >> $GITHUB_STEP_SUMMARY\n\n # Get the stack name based on the environment (zerde-serverless-telegram-bot-{env})\n STACK_NAME=\"zerde-serverless-telegram-bot-${{ env.TARGET_ENV }}\"\n\n aws cloudformation describe-stacks \\\n --stack-name $STACK_NAME \\\n --region eu-central-1 \\\n --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' \\\n --output table >> $GITHUB_STEP_SUMMARY || echo \"Could not fetch outputs\" >> $GITHUB_STEP_SUMMARY\n"}, "2dd04c7335e3ab605bf560817c5252867c5ab837": {"t": 1785762219.3301537, "n": 4816, "h": "f80325eb5902c1ed", "c": "name: Deploy to AWS\n\non:\n push:\n branches:\n - main\n\n workflow_dispatch:\n inputs:\n environment:\n description: 'Target Environment'\n required: true\n default: 'dev'\n type: choice\n options:\n - dev\n - prod\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n\njobs:\n deploy:\n name: Deploy to AWS\n runs-on: ubuntu-latest\n permissions:\n contents: read\n id-token: write\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n\n - name: Determine Target Environment\n id: determine-env\n run: |\n if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ]; then\n # If manual trigger, use user-selected input (dev or prod)\n echo \"TARGET_ENV=${{ inputs.environment }}\" >> $GITHUB_ENV\n echo \"Selected manual deployment to: ${{ inputs.environment }}\"\n else\n # If Push to main, force deployment to dev\n echo \"TARGET_ENV=dev\" >> $GITHUB_ENV\n echo \"Push event detected. Defaulting deployment to: dev\"\n fi\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: Verify CDK installation\n run: |\n uv run cdk --version\n\n - name: CDK Bootstrap (usually only needs to run once, but kept here as a safeguard)\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n GEMINI_API_KEY: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_GEMINI_API_KEY || secrets.DEV_GEMINI_API_KEY }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER }}\n LLM_MODEL: ${{ vars.LLM_MODEL }}\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE }}\n run: |\n uv run cdk bootstrap aws://$(aws sts get-caller-identity --query Account --output text)/eu-central-1 || echo \"Bootstrap may already be done\"\n continue-on-error: true\n\n - name: CDK Deploy\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n GEMINI_API_KEY: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_GEMINI_API_KEY || secrets.DEV_GEMINI_API_KEY }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER }}\n LLM_MODEL: ${{ vars.LLM_MODEL }}\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE }}\n run: |\n echo \"๐ Deploying to ${{ env.TARGET_ENV }} environment...\"\n uv run cdk deploy -c env=${{ env.TARGET_ENV }} --require-approval never --all\n\n - name: Get Deployment Outputs\n if: success()\n working-directory: ./infra\n run: |\n echo \"## ๐ Deployment Successful (Zerde Telegram Bot)\" >> $GITHUB_STEP_SUMMARY\n echo \"Deployed to: **${{ env.TARGET_ENV }}**\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Stack Outputs:\" >> $GITHUB_STEP_SUMMARY\n\n # Get the stack name based on the environment (zerde-serverless-telegram-bot-{env})\n STACK_NAME=\"zerde-serverless-telegram-bot-${{ env.TARGET_ENV }}\"\n\n aws cloudformation describe-stacks \\\n --stack-name $STACK_NAME \\\n --region eu-central-1 \\\n --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' \\\n --output table >> $GITHUB_STEP_SUMMARY || echo \"Could not fetch outputs\" >> $GITHUB_STEP_SUMMARY\n"}, "8af684aa8de709bd7a88c5a31c4974ac61540f86": {"t": 1785762221.9892135, "n": 4591, "h": "1effc851208433bd", "c": "name: Deploy to AWS\n\non:\n push:\n branches:\n - main\n\n workflow_dispatch:\n inputs:\n environment:\n description: 'Target Environment'\n required: true\n default: 'dev'\n type: choice\n options:\n - dev\n - prod\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n\njobs:\n deploy:\n name: Deploy to AWS\n runs-on: ubuntu-latest\n permissions:\n contents: read\n id-token: write\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n\n - name: Determine Target Environment\n id: determine-env\n run: |\n if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ]; then\n # If manual trigger, use user-selected input (dev or prod)\n echo \"TARGET_ENV=${{ inputs.environment }}\" >> $GITHUB_ENV\n echo \"Selected manual deployment to: ${{ inputs.environment }}\"\n else\n # If Push to main, force deployment to dev\n echo \"TARGET_ENV=dev\" >> $GITHUB_ENV\n echo \"Push event detected. Defaulting deployment to: dev\"\n fi\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: Verify CDK installation\n run: |\n uv run cdk --version\n\n - name: CDK Bootstrap (usually only needs to run once, but kept here as a safeguard)\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n NEWS_CHAT_IDS: ${{ env.TARGET_ENV == 'prod' && vars.PROD_NEWS_CHAT_IDS || vars.DEV_NEWS_CHAT_IDS }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER }}\n GEMINI_API_KEY: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_GEMINI_API_KEY || secrets.DEV_GEMINI_API_KEY }}\n run: |\n uv run cdk bootstrap aws://$(aws sts get-caller-identity --query Account --output text)/eu-central-1 || echo \"Bootstrap may already be done\"\n continue-on-error: true\n\n - name: CDK Deploy\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n GEMINI_API_KEY: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_GEMINI_API_KEY || secrets.DEV_GEMINI_API_KEY }}\n NEWS_CHAT_IDS: ${{ env.TARGET_ENV == 'prod' && vars.PROD_NEWS_CHAT_IDS || vars.DEV_NEWS_CHAT_IDS }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER }}\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE }}\n LLM_MODEL: ${{ vars.LLM_MODEL }}\n run: |\n echo \"๐ Deploying to ${{ env.TARGET_ENV }} environment...\"\n uv run cdk deploy -c env=${{ env.TARGET_ENV }} --require-approval never --all\n\n - name: Get Deployment Outputs\n if: success()\n working-directory: ./infra\n run: |\n echo \"## ๐ Deployment Successful (Zerde Telegram Bot)\" >> $GITHUB_STEP_SUMMARY\n echo \"Deployed to: **${{ env.TARGET_ENV }}**\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Stack Outputs:\" >> $GITHUB_STEP_SUMMARY\n\n # Get the stack name based on the environment (ZerdeTelegramBotStack-dev or ZerdeTelegramBotStack-prod)\n STACK_NAME=\"ZerdeTelegramBotStack-${{ env.TARGET_ENV }}\"\n\n aws cloudformation describe-stacks \\\n --stack-name $STACK_NAME \\\n --region eu-central-1 \\\n --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' \\\n --output table >> $GITHUB_STEP_SUMMARY || echo \"Could not fetch outputs\" >> $GITHUB_STEP_SUMMARY\n"}, "db36311c3938430e293b92f17c14633d4e2856a9": {"t": 1785762225.7229369, "n": 4418, "h": "cf03be78e5b1936c", "c": "name: Deploy to AWS\n\non:\n push:\n branches:\n - main\n\n workflow_dispatch:\n inputs:\n environment:\n description: 'Target Environment'\n required: true\n default: 'dev'\n type: choice\n options:\n - dev\n - prod\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n\njobs:\n deploy:\n name: Deploy to AWS\n runs-on: ubuntu-latest\n permissions:\n contents: read\n id-token: write\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n\n - name: Determine Target Environment\n id: determine-env\n run: |\n if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ]; then\n # If manual trigger, use user-selected input (dev or prod)\n echo \"TARGET_ENV=${{ inputs.environment }}\" >> $GITHUB_ENV\n echo \"Selected manual deployment to: ${{ inputs.environment }}\"\n else\n # If Push to main, force deployment to dev\n echo \"TARGET_ENV=dev\" >> $GITHUB_ENV\n echo \"Push event detected. Defaulting deployment to: dev\"\n fi\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: Verify CDK installation\n run: |\n uv run cdk --version\n\n - name: CDK Bootstrap (usually only needs to run once, but kept here as a safeguard)\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n NEWS_CHAT_IDS: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_NEWS_CHAT_IDS || secrets.DEV_NEWS_CHAT_IDS }}\n AI_PROVIDER: gemini\n GEMINI_API_KEY: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_GEMINI_API_KEY || secrets.DEV_GEMINI_API_KEY }}\n run: |\n uv run cdk bootstrap aws://$(aws sts get-caller-identity --query Account --output text)/eu-central-1 || echo \"Bootstrap may already be done\"\n continue-on-error: true\n\n - name: CDK Deploy\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n NEWS_CHAT_IDS: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_NEWS_CHAT_IDS || secrets.DEV_NEWS_CHAT_IDS }}\n AI_PROVIDER: gemini\n GEMINI_API_KEY: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_GEMINI_API_KEY || secrets.DEV_GEMINI_API_KEY }}\n run: |\n echo \"๐ Deploying to ${{ env.TARGET_ENV }} environment...\"\n uv run cdk deploy -c env=${{ env.TARGET_ENV }} --require-approval never --all\n\n - name: Get Deployment Outputs\n if: success()\n working-directory: ./infra\n run: |\n echo \"## ๐ Deployment Successful (Zerde Telegram Bot)\" >> $GITHUB_STEP_SUMMARY\n echo \"Deployed to: **${{ env.TARGET_ENV }}**\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Stack Outputs:\" >> $GITHUB_STEP_SUMMARY\n\n # Get the stack name based on the environment (ZerdeTelegramBotStack-dev or ZerdeTelegramBotStack-prod)\n STACK_NAME=\"ZerdeTelegramBotStack-${{ env.TARGET_ENV }}\"\n\n aws cloudformation describe-stacks \\\n --stack-name $STACK_NAME \\\n --region eu-central-1 \\\n --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' \\\n --output table >> $GITHUB_STEP_SUMMARY || echo \"Could not fetch outputs\" >> $GITHUB_STEP_SUMMARY\n"}, "18b4ae36fcd36a8127118bd9dea193ae13ae4096": {"t": 1785762228.4355981, "n": 4398, "h": "dbbde000086c63ed", "c": "name: Deploy to AWS\n\non:\n push:\n branches:\n - main\n\n workflow_dispatch:\n inputs:\n environment:\n description: 'Target Environment'\n required: true\n default: 'dev'\n type: choice\n options:\n - dev\n - prod\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n\njobs:\n deploy:\n name: Deploy to AWS\n runs-on: ubuntu-latest\n permissions:\n contents: read\n id-token: write\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n\n - name: Determine Target Environment\n id: determine-env\n run: |\n if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ]; then\n # If manual trigger, use user-selected input (dev or prod)\n echo \"TARGET_ENV=${{ inputs.environment }}\" >> $GITHUB_ENV\n echo \"Selected manual deployment to: ${{ inputs.environment }}\"\n else\n # If Push to main, force deployment to dev\n echo \"TARGET_ENV=dev\" >> $GITHUB_ENV\n echo \"Push event detected. Defaulting deployment to: dev\"\n fi\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: Verify CDK installation\n run: |\n uv run cdk --version\n\n - name: CDK Bootstrap (usually only needs to run once, but kept here as a safeguard)\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n NEWS_CHAT_IDS: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_NEWS_CHAT_ID || secrets.DEV_NEWS_CHAT_ID }}\n AI_PROVIDER: groq\n GROQ_API_KEY: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_GROQ_API_KEY || secrets.DEV_GROQ_API_KEY }}\n run: |\n uv run cdk bootstrap aws://$(aws sts get-caller-identity --query Account --output text)/eu-central-1 || echo \"Bootstrap may already be done\"\n continue-on-error: true\n\n - name: CDK Deploy\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n NEWS_CHAT_IDS: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_NEWS_CHAT_ID || secrets.DEV_NEWS_CHAT_ID }}\n AI_PROVIDER: groq\n GROQ_API_KEY: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_GROQ_API_KEY || secrets.DEV_GROQ_API_KEY }}\n run: |\n echo \"๐ Deploying to ${{ env.TARGET_ENV }} environment...\"\n uv run cdk deploy -c env=${{ env.TARGET_ENV }} --require-approval never --all\n\n - name: Get Deployment Outputs\n if: success()\n working-directory: ./infra\n run: |\n echo \"## ๐ Deployment Successful (Zerde Telegram Bot)\" >> $GITHUB_STEP_SUMMARY\n echo \"Deployed to: **${{ env.TARGET_ENV }}**\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Stack Outputs:\" >> $GITHUB_STEP_SUMMARY\n\n # Get the stack name based on the environment (ZerdeTelegramBotStack-dev or ZerdeTelegramBotStack-prod)\n STACK_NAME=\"ZerdeTelegramBotStack-${{ env.TARGET_ENV }}\"\n\n aws cloudformation describe-stacks \\\n --stack-name $STACK_NAME \\\n --region eu-central-1 \\\n --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' \\\n --output table >> $GITHUB_STEP_SUMMARY || echo \"Could not fetch outputs\" >> $GITHUB_STEP_SUMMARY\n"}, "5d5bde3707bc97d44e9e838bfd826743107f5d54": {"t": 1785762229.5974853, "n": 3888, "h": "7a99261c812498a8", "c": "name: Deploy to AWS\n\non:\n push:\n branches:\n - main\n\n workflow_dispatch:\n inputs:\n environment:\n description: 'Target Environment'\n required: true\n default: 'dev'\n type: choice\n options:\n - dev\n - prod\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n\njobs:\n deploy:\n name: Deploy to AWS\n runs-on: ubuntu-latest\n permissions:\n contents: read\n id-token: write\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n\n - name: Determine Target Environment\n id: determine-env\n run: |\n if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ]; then\n # If manual trigger, use user-selected input (dev or prod)\n echo \"TARGET_ENV=${{ inputs.environment }}\" >> $GITHUB_ENV\n echo \"Selected manual deployment to: ${{ inputs.environment }}\"\n else\n # If Push to main, force deployment to dev\n echo \"TARGET_ENV=dev\" >> $GITHUB_ENV\n echo \"Push event detected. Defaulting deployment to: dev\"\n fi\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: Verify CDK installation\n run: |\n uv run cdk --version\n\n - name: CDK Bootstrap (usually only needs to run once, but kept here as a safeguard)\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n run: |\n uv run cdk bootstrap aws://$(aws sts get-caller-identity --query Account --output text)/eu-central-1 || echo \"Bootstrap may already be done\"\n continue-on-error: true\n\n - name: CDK Deploy\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n run: |\n echo \"๐ Deploying to ${{ env.TARGET_ENV }} environment...\"\n uv run cdk deploy -c env=${{ env.TARGET_ENV }} --require-approval never --all\n\n - name: Get Deployment Outputs\n if: success()\n working-directory: ./infra\n run: |\n echo \"## ๐ Deployment Successful (Zerde Telegram Bot)\" >> $GITHUB_STEP_SUMMARY\n echo \"Deployed to: **${{ env.TARGET_ENV }}**\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Stack Outputs:\" >> $GITHUB_STEP_SUMMARY\n\n # Get the stack name based on the environment (ZerdeTelegramBotStack-dev or ZerdeTelegramBotStack-prod)\n STACK_NAME=\"ZerdeTelegramBotStack-${{ env.TARGET_ENV }}\"\n\n aws cloudformation describe-stacks \\\n --stack-name $STACK_NAME \\\n --region eu-central-1 \\\n --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' \\\n --output table >> $GITHUB_STEP_SUMMARY || echo \"Could not fetch outputs\" >> $GITHUB_STEP_SUMMARY\n"}, "f2e74a5ea5a501add4f2e327c543349350150671": {"t": 1785762231.8399327, "n": 3580, "h": "8485136e4f227afc", "c": "name: Deploy to AWS\n\non:\n push:\n branches:\n - main\n\n workflow_dispatch:\n inputs:\n environment:\n description: 'Target Environment'\n required: true\n default: 'dev'\n type: choice\n options:\n - dev\n - prod\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n\njobs:\n deploy:\n name: Deploy to AWS\n runs-on: ubuntu-latest\n permissions:\n contents: read\n id-token: write\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n\n - name: Determine Target Environment\n id: determine-env\n run: |\n if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ]; then\n # If manual trigger, use user-selected input (dev or prod)\n echo \"TARGET_ENV=${{ inputs.environment }}\" >> $GITHUB_ENV\n echo \"Selected manual deployment to: ${{ inputs.environment }}\"\n else\n # If Push to main, force deployment to dev\n echo \"TARGET_ENV=dev\" >> $GITHUB_ENV\n echo \"Push event detected. Defaulting deployment to: dev\"\n fi\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: Verify CDK installation\n run: |\n uv run cdk --version\n\n - name: CDK Bootstrap (usually only needs to run once, but kept here as a safeguard)\n working-directory: ./infra\n run: |\n uv run cdk bootstrap aws://$(aws sts get-caller-identity --query Account --output text)/eu-central-1 || echo \"Bootstrap may already be done\"\n continue-on-error: true\n\n - name: CDK Deploy\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n run: |\n echo \"๐ Deploying to ${{ env.TARGET_ENV }} environment...\"\n uv run cdk deploy -c env=${{ env.TARGET_ENV }} --require-approval never --all\n\n - name: Get Deployment Outputs\n if: success()\n working-directory: ./infra\n run: |\n echo \"## ๐ Deployment Successful (Zerde Telegram Bot)\" >> $GITHUB_STEP_SUMMARY\n echo \"Deployed to: **${{ env.TARGET_ENV }}**\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Stack Outputs:\" >> $GITHUB_STEP_SUMMARY\n\n # Get the stack name based on the environment (ZerdeTelegramBotStack-dev or ZerdeTelegramBotStack-prod)\n STACK_NAME=\"ZerdeTelegramBotStack-${{ env.TARGET_ENV }}\"\n\n aws cloudformation describe-stacks \\\n --stack-name $STACK_NAME \\\n --region eu-central-1 \\\n --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' \\\n --output table >> $GITHUB_STEP_SUMMARY || echo \"Could not fetch outputs\" >> $GITHUB_STEP_SUMMARY\n"}, "ce3bf0b164aab5027b3d1250d7ad8606042dbc4b": {"t": 1785762233.3254964, "n": 3549, "h": "0fb5cfba0daf7d77", "c": "name: Deploy to AWS\n\non:\n push:\n branches:\n - main\n\n workflow_dispatch:\n inputs:\n environment:\n description: 'Target Environment'\n required: true\n default: 'dev'\n type: choice\n options:\n - dev\n - prod\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n\njobs:\n deploy:\n name: Deploy to AWS\n runs-on: ubuntu-latest\n permissions:\n contents: read\n id-token: write\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n\n - name: Determine Target Environment\n id: determine-env\n run: |\n if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ]; then\n # If manual trigger, use user-selected input (dev or prod)\n echo \"TARGET_ENV=${{ inputs.environment }}\" >> $GITHUB_ENV\n echo \"Selected manual deployment to: ${{ inputs.environment }}\"\n else\n # If Push to main, force deployment to dev\n echo \"TARGET_ENV=dev\" >> $GITHUB_ENV\n echo \"Push event detected. Defaulting deployment to: dev\"\n fi\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: Verify CDK installation\n run: |\n uv run cdk --version\n\n - name: CDK Bootstrap (usually only needs to run once, but kept here as a safeguard)\n working-directory: ./infra\n run: |\n uv run cdk bootstrap aws://$(aws sts get-caller-identity --query Account --output text)/eu-central-1 || echo \"Bootstrap may already be done\"\n continue-on-error: true\n\n - name: CDK Deploy\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_BOT_TOKEN || secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ env.TARGET_ENV == 'prod' && secrets.PROD_TELEGRAM_WEBHOOK_SECRET_TOKEN || secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n run: |\n echo \"๐ Deploying to ${{ env.TARGET_ENV }} environment...\"\n uv run cdk deploy -c env=${{ env.TARGET_ENV }} --require-approval never --all\n\n - name: Get Deployment Outputs\n if: success()\n working-directory: ./infra\n run: |\n echo \"## ๐ Deployment Successful (Serverless Telegram Bot Starter)\" >> $GITHUB_STEP_SUMMARY\n echo \"Deployed to: **${{ env.TARGET_ENV }}**\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Stack Outputs:\" >> $GITHUB_STEP_SUMMARY\n\n # Get the stack name based on the environment (TelegramBotStack-dev or TelegramBotStack-prod)\n STACK_NAME=\"TelegramBotStack-${{ env.TARGET_ENV }}\"\n\n aws cloudformation describe-stacks \\\n --stack-name $STACK_NAME \\\n --region eu-central-1 \\\n --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' \\\n --output table >> $GITHUB_STEP_SUMMARY || echo \"Could not fetch outputs\" >> $GITHUB_STEP_SUMMARY\n"}}, ".github/workflows/pr_check.yml": {"78c653c642fcfd4430e04e8299340425b7f431ce": {"t": 1785746340.8912055, "n": 11776, "h": "9dde0b819bc779ed", "c": "name: PR Check\n\non:\n pull_request:\n branches:\n - main\n types: [opened, synchronize, reopened]\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n pull-requests: write # Allow bot to write diff results to PR comments\n\njobs:\n quality-check:\n name: Code Quality Checks\n runs-on: ubuntu-latest\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff preview\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Run pre-commit hooks\n run: |\n uv run pre-commit run --all-files\n\n - name: Run Unit Tests\n run: |\n uv run pytest tests/ -v\n\n infra-preview:\n needs: quality-check\n name: Infrastructure Changes Preview\n runs-on: ubuntu-24.04-arm\n if: github.event.pull_request.head.repo.full_name == github.repository\n\n # API keys and tokens are stored in SSM Parameter Store โ CDK only needs non-secret config.\n env:\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG || 'kk' }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE || 'https://api.telegram.org/bot' }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER || 'gemini' }}\n GEMINI_MODEL: ${{ vars.GEMINI_MODEL }}\n WTF_GEMINI_MODEL: ${{ vars.WTF_GEMINI_MODEL }}\n GEMINI_RPD_LIMIT: ${{ vars.GEMINI_RPD_LIMIT }}\n GEMINI_EMBEDDING_RPD_LIMIT: ${{ vars.GEMINI_EMBEDDING_RPD_LIMIT || '1000' }}\n GEMINI_API_BASE: ${{ vars.GEMINI_API_BASE || 'https://generativelanguage.googleapis.com/v1beta/models' }}\n FALLBACK_MODEL: ${{ vars.FALLBACK_MODEL }}\n GROQ_MODEL: ${{ vars.GROQ_MODEL }}\n GROQ_API_BASE: ${{ vars.GROQ_API_BASE || 'https://api.groq.com/openai/v1' }}\n DEEPSEEK_MODEL: ${{ vars.DEEPSEEK_MODEL }}\n DEEPSEEK_API_BASE: ${{ vars.DEEPSEEK_API_BASE || 'https://api.deepseek.com' }}\n SPAM_RULE_ENFORCE_THRESHOLD: ${{ vars.SPAM_RULE_ENFORCE_THRESHOLD || '0.8' }}\n SPAM_RULE_AI_THRESHOLD: ${{ vars.SPAM_RULE_AI_THRESHOLD || '0.15' }}\n SPAM_AI_CONFIDENCE_THRESHOLD: ${{ vars.SPAM_AI_CONFIDENCE_THRESHOLD || '0.85' }}\n SPAM_REVIEW_ADMIN_MENTIONS: ${{ vars.SPAM_REVIEW_ADMIN_MENTIONS || '{}' }}\n ADMIN_USER_ID: ${{ secrets.ADMIN_USER_ID }}\n CHATS_KK: ${{ vars.CHATS_KK }}\n CHATS_ZH: ${{ vars.CHATS_ZH }}\n CHATS_RU: ${{ vars.CHATS_RU }}\n CAPTCHA_TIMEOUT_SECONDS: ${{ vars.CAPTCHA_TIMEOUT_SECONDS }}\n KICK_BAN_DURATION_SECONDS: ${{ vars.KICK_BAN_DURATION_SECONDS }}\n VOTEBAN_THRESHOLD: ${{ vars.VOTEBAN_THRESHOLD }}\n VOTEBAN_FORGIVE_THRESHOLD: ${{ vars.VOTEBAN_FORGIVE_THRESHOLD }}\n CAPTCHA_MAX_ATTEMPTS: ${{ vars.CAPTCHA_MAX_ATTEMPTS || '3' }}\n QUIZ_LLM_RPD: ${{ vars.QUIZ_LLM_RPD }}\n NEWS_GEMINI_MODEL: ${{ vars.NEWS_GEMINI_MODEL }}\n QUIZ_GEMINI_MODEL: ${{ vars.QUIZ_GEMINI_MODEL }}\n QUIZ_CHATS_KK: ${{ vars.QUIZ_CHATS_KK }}\n QUIZ_CHATS_ZH: ${{ vars.QUIZ_CHATS_ZH }}\n QUIZ_CHATS_RU: ${{ vars.QUIZ_CHATS_RU }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n GROUP_MEMORY_ENABLED: ${{ vars.GROUP_MEMORY_ENABLED || 'true' }}\n GROUP_MEMORY_RECENT_LIMIT: ${{ vars.GROUP_MEMORY_RECENT_LIMIT || '300' }}\n GROUP_MEMORY_RETENTION_DAYS: ${{ vars.GROUP_MEMORY_RETENTION_DAYS || '3650' }}\n GROUP_MEMORY_DAILY_SUMMARY_DAYS: ${{ vars.GROUP_MEMORY_DAILY_SUMMARY_DAYS || '7' }}\n GROUP_MEMORY_DAILY_SUMMARY_MESSAGE_LIMIT: ${{ vars.GROUP_MEMORY_DAILY_SUMMARY_MESSAGE_LIMIT || '500' }}\n VECTOR_MEMORY_ENABLED: ${{ vars.VECTOR_MEMORY_ENABLED || 'true' }}\n VECTOR_MEMORY_PROVIDER: ${{ vars.VECTOR_MEMORY_PROVIDER || 's3_vectors' }}\n VECTOR_MEMORY_DIMENSIONS: ${{ vars.VECTOR_MEMORY_DIMENSIONS || '768' }}\n VECTOR_MEMORY_EMBEDDING_MODEL: ${{ vars.VECTOR_MEMORY_EMBEDDING_MODEL || 'gemini-embedding-2' }}\n VECTOR_MEMORY_INDEX_THROTTLE_SECONDS: ${{ vars.VECTOR_MEMORY_INDEX_THROTTLE_SECONDS || '3' }}\n VECTOR_MEMORY_BACKFILL_BATCH_SIZE: ${{ vars.VECTOR_MEMORY_BACKFILL_BATCH_SIZE || '50' }}\n VECTOR_MEMORY_MAX_DISTANCE: ${{ vars.VECTOR_MEMORY_MAX_DISTANCE || '0.85' }}\n VECTOR_MEMORY_VECTOR_BUCKET_NAME: ${{ vars.VECTOR_MEMORY_VECTOR_BUCKET_NAME }}\n VECTOR_MEMORY_INDEX_NAME: ${{ vars.VECTOR_MEMORY_INDEX_NAME }}\n AGENT_ENABLED: ${{ vars.AGENT_ENABLED || 'true' }}\n AGENT_BOT_USERNAME: ${{ vars.AGENT_BOT_USERNAME || '@zerde_kz_bot' }}\n AGENT_RECENT_CONTEXT_LIMIT: ${{ vars.AGENT_RECENT_CONTEXT_LIMIT || '100' }}\n AGENT_DAILY_PROACTIVE_LIMIT: ${{ vars.AGENT_DAILY_PROACTIVE_LIMIT || '10' }}\n AGENT_PROACTIVE_FINAL_THRESHOLD: ${{ vars.AGENT_PROACTIVE_FINAL_THRESHOLD || '0.72' }}\n AGENT_PROACTIVE_DECISION_GROQ_MODELS: ${{ vars.AGENT_PROACTIVE_DECISION_GROQ_MODELS || 'llama-3.1-8b-instant,meta-llama/llama-4-scout-17b-16e-instruct,qwen/qwen3-32b' }}\n AGENT_PROACTIVE_DECISION_CONTEXT_CHARS: ${{ vars.AGENT_PROACTIVE_DECISION_CONTEXT_CHARS || '4000' }}\n AGENT_PROACTIVE_DECISION_ALLOW_DEEPSEEK_FALLBACK: ${{ vars.AGENT_PROACTIVE_DECISION_ALLOW_DEEPSEEK_FALLBACK || 'false' }}\n AMBIENT_REACTIONS_ENABLED: ${{ vars.AMBIENT_REACTIONS_ENABLED || 'true' }}\n AMBIENT_REACTIONS_SAMPLE_RATE: ${{ vars.AMBIENT_REACTIONS_SAMPLE_RATE || '0.80' }}\n AMBIENT_REACTIONS_CONFIDENCE_THRESHOLD: ${{ vars.AMBIENT_REACTIONS_CONFIDENCE_THRESHOLD || '0.80' }}\n AMBIENT_REACTIONS_DECISION_GROQ_MODELS: ${{ vars.AMBIENT_REACTIONS_DECISION_GROQ_MODELS || 'llama-3.1-8b-instant,qwen/qwen3-32b,meta-llama/llama-4-scout-17b-16e-instruct' }}\n AMBIENT_REACTIONS_DECISION_CONTEXT_CHARS: ${{ vars.AMBIENT_REACTIONS_DECISION_CONTEXT_CHARS || '3000' }}\n AMBIENT_REACTIONS_MIN_GAP_PER_CHAT_SECONDS: ${{ vars.AMBIENT_REACTIONS_MIN_GAP_PER_CHAT_SECONDS || '60' }}\n AMBIENT_REACTIONS_MIN_GAP_PER_USER_SECONDS: ${{ vars.AMBIENT_REACTIONS_MIN_GAP_PER_USER_SECONDS || '300' }}\n AMBIENT_REACTIONS_MAX_PER_CHAT_PER_HOUR: ${{ vars.AMBIENT_REACTIONS_MAX_PER_CHAT_PER_HOUR || '12' }}\n AMBIENT_REACTIONS_MAX_PER_CHAT_PER_DAY: ${{ vars.AMBIENT_REACTIONS_MAX_PER_CHAT_PER_DAY || '100' }}\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n # npm package \"aws-cdk\" is the CLI only; its version is NOT the same as Python \"aws-cdk-lib\"\n # (since ~2.179, CLI uses 2.1xxx numbering). Install a recent CLI so cloud-assembly schema matches.\n - name: Install AWS CDK CLI (pinned)\n run: |\n npm install -g aws-cdk@2.1119.0\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: CDK Synth (Verify Compilation)\n working-directory: ./infra\n run: |\n uv run cdk synth -c env=dev\n\n - name: CDK Diff (Preview Changes)\n id: cdk-diff\n working-directory: ./infra\n run: |\n set +e\n uv run cdk diff -c env=dev > /tmp/cdk-diff.txt 2>&1\n diffexit=$?\n set -e\n # CDK: 0 = no changes, 1 = differences, other = real failure\n if [ \"$diffexit\" -ne 0 ] && [ \"$diffexit\" -ne 1 ]; then\n echo \"cdk diff failed with exit $diffexit\"\n cat /tmp/cdk-diff.txt\n exit \"$diffexit\"\n fi\n\n echo \"## ๐ Infrastructure Changes Preview (Zerde Telegram Bot)\" > /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR will modify the following AWS resources:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n if ! grep -q \"Stack ZerdeTelegramBotStack-dev\" /tmp/cdk-diff.txt && ! grep -q \"There were no differences\" /tmp/cdk-diff.txt; then\n echo \"### โน๏ธ No infrastructure changes detected\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR only contains code changes (Lambda functions, etc.)\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n else\n echo \"### โ
Resources to be Created:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\+.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*+/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n echo \"### โ Resources to be Deleted:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\-.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*-/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n echo \"### โ ๏ธ Resources to be Modified:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*~.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*~/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n echo \"### ๐ง Property Changes:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*[+\\-~].*:\" /tmp/cdk-diff.txt | grep -v \"AWS::\" | head -30 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n fi\n\n echo \"\" >> /tmp/diff-report.md\n echo \"๐ Full CDK Diff Output
\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo '```diff' >> /tmp/diff-report.md\n cat /tmp/cdk-diff.txt >> /tmp/diff-report.md\n echo '```' >> /tmp/diff-report.md\n echo \" \" >> /tmp/diff-report.md\n\n cat /tmp/diff-report.md\n\n - name: Comment PR with Infrastructure Diff\n uses: actions/github-script@v7\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n script: |\n const fs = require('fs');\n const report = fs.readFileSync('/tmp/diff-report.md', 'utf8');\n\n const { data: comments } = await github.rest.issues.listComments({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n });\n\n const botComment = comments.find(comment =>\n comment.user.type === 'Bot' &&\n comment.body.includes('Infrastructure Changes Preview')\n );\n\n if (botComment) {\n await github.rest.issues.updateComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n comment_id: botComment.id,\n body: report\n });\n } else {\n await github.rest.issues.createComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n body: report\n });\n }\n"}, "3b63b60c2a93578e47a8b6b3ca7eb86a212d2b1e": {"t": 1785762129.622388, "n": 11776, "h": "9dde0b819bc779ed", "c": "name: PR Check\n\non:\n pull_request:\n branches:\n - main\n types: [opened, synchronize, reopened]\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n pull-requests: write # Allow bot to write diff results to PR comments\n\njobs:\n quality-check:\n name: Code Quality Checks\n runs-on: ubuntu-latest\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff preview\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Run pre-commit hooks\n run: |\n uv run pre-commit run --all-files\n\n - name: Run Unit Tests\n run: |\n uv run pytest tests/ -v\n\n infra-preview:\n needs: quality-check\n name: Infrastructure Changes Preview\n runs-on: ubuntu-24.04-arm\n if: github.event.pull_request.head.repo.full_name == github.repository\n\n # API keys and tokens are stored in SSM Parameter Store โ CDK only needs non-secret config.\n env:\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG || 'kk' }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE || 'https://api.telegram.org/bot' }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER || 'gemini' }}\n GEMINI_MODEL: ${{ vars.GEMINI_MODEL }}\n WTF_GEMINI_MODEL: ${{ vars.WTF_GEMINI_MODEL }}\n GEMINI_RPD_LIMIT: ${{ vars.GEMINI_RPD_LIMIT }}\n GEMINI_EMBEDDING_RPD_LIMIT: ${{ vars.GEMINI_EMBEDDING_RPD_LIMIT || '1000' }}\n GEMINI_API_BASE: ${{ vars.GEMINI_API_BASE || 'https://generativelanguage.googleapis.com/v1beta/models' }}\n FALLBACK_MODEL: ${{ vars.FALLBACK_MODEL }}\n GROQ_MODEL: ${{ vars.GROQ_MODEL }}\n GROQ_API_BASE: ${{ vars.GROQ_API_BASE || 'https://api.groq.com/openai/v1' }}\n DEEPSEEK_MODEL: ${{ vars.DEEPSEEK_MODEL }}\n DEEPSEEK_API_BASE: ${{ vars.DEEPSEEK_API_BASE || 'https://api.deepseek.com' }}\n SPAM_RULE_ENFORCE_THRESHOLD: ${{ vars.SPAM_RULE_ENFORCE_THRESHOLD || '0.8' }}\n SPAM_RULE_AI_THRESHOLD: ${{ vars.SPAM_RULE_AI_THRESHOLD || '0.15' }}\n SPAM_AI_CONFIDENCE_THRESHOLD: ${{ vars.SPAM_AI_CONFIDENCE_THRESHOLD || '0.85' }}\n SPAM_REVIEW_ADMIN_MENTIONS: ${{ vars.SPAM_REVIEW_ADMIN_MENTIONS || '{}' }}\n ADMIN_USER_ID: ${{ secrets.ADMIN_USER_ID }}\n CHATS_KK: ${{ vars.CHATS_KK }}\n CHATS_ZH: ${{ vars.CHATS_ZH }}\n CHATS_RU: ${{ vars.CHATS_RU }}\n CAPTCHA_TIMEOUT_SECONDS: ${{ vars.CAPTCHA_TIMEOUT_SECONDS }}\n KICK_BAN_DURATION_SECONDS: ${{ vars.KICK_BAN_DURATION_SECONDS }}\n VOTEBAN_THRESHOLD: ${{ vars.VOTEBAN_THRESHOLD }}\n VOTEBAN_FORGIVE_THRESHOLD: ${{ vars.VOTEBAN_FORGIVE_THRESHOLD }}\n CAPTCHA_MAX_ATTEMPTS: ${{ vars.CAPTCHA_MAX_ATTEMPTS || '3' }}\n QUIZ_LLM_RPD: ${{ vars.QUIZ_LLM_RPD }}\n NEWS_GEMINI_MODEL: ${{ vars.NEWS_GEMINI_MODEL }}\n QUIZ_GEMINI_MODEL: ${{ vars.QUIZ_GEMINI_MODEL }}\n QUIZ_CHATS_KK: ${{ vars.QUIZ_CHATS_KK }}\n QUIZ_CHATS_ZH: ${{ vars.QUIZ_CHATS_ZH }}\n QUIZ_CHATS_RU: ${{ vars.QUIZ_CHATS_RU }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n GROUP_MEMORY_ENABLED: ${{ vars.GROUP_MEMORY_ENABLED || 'true' }}\n GROUP_MEMORY_RECENT_LIMIT: ${{ vars.GROUP_MEMORY_RECENT_LIMIT || '300' }}\n GROUP_MEMORY_RETENTION_DAYS: ${{ vars.GROUP_MEMORY_RETENTION_DAYS || '3650' }}\n GROUP_MEMORY_DAILY_SUMMARY_DAYS: ${{ vars.GROUP_MEMORY_DAILY_SUMMARY_DAYS || '7' }}\n GROUP_MEMORY_DAILY_SUMMARY_MESSAGE_LIMIT: ${{ vars.GROUP_MEMORY_DAILY_SUMMARY_MESSAGE_LIMIT || '500' }}\n VECTOR_MEMORY_ENABLED: ${{ vars.VECTOR_MEMORY_ENABLED || 'true' }}\n VECTOR_MEMORY_PROVIDER: ${{ vars.VECTOR_MEMORY_PROVIDER || 's3_vectors' }}\n VECTOR_MEMORY_DIMENSIONS: ${{ vars.VECTOR_MEMORY_DIMENSIONS || '768' }}\n VECTOR_MEMORY_EMBEDDING_MODEL: ${{ vars.VECTOR_MEMORY_EMBEDDING_MODEL || 'gemini-embedding-2' }}\n VECTOR_MEMORY_INDEX_THROTTLE_SECONDS: ${{ vars.VECTOR_MEMORY_INDEX_THROTTLE_SECONDS || '3' }}\n VECTOR_MEMORY_BACKFILL_BATCH_SIZE: ${{ vars.VECTOR_MEMORY_BACKFILL_BATCH_SIZE || '50' }}\n VECTOR_MEMORY_MAX_DISTANCE: ${{ vars.VECTOR_MEMORY_MAX_DISTANCE || '0.85' }}\n VECTOR_MEMORY_VECTOR_BUCKET_NAME: ${{ vars.VECTOR_MEMORY_VECTOR_BUCKET_NAME }}\n VECTOR_MEMORY_INDEX_NAME: ${{ vars.VECTOR_MEMORY_INDEX_NAME }}\n AGENT_ENABLED: ${{ vars.AGENT_ENABLED || 'true' }}\n AGENT_BOT_USERNAME: ${{ vars.AGENT_BOT_USERNAME || '@zerde_kz_bot' }}\n AGENT_RECENT_CONTEXT_LIMIT: ${{ vars.AGENT_RECENT_CONTEXT_LIMIT || '100' }}\n AGENT_DAILY_PROACTIVE_LIMIT: ${{ vars.AGENT_DAILY_PROACTIVE_LIMIT || '10' }}\n AGENT_PROACTIVE_FINAL_THRESHOLD: ${{ vars.AGENT_PROACTIVE_FINAL_THRESHOLD || '0.72' }}\n AGENT_PROACTIVE_DECISION_GROQ_MODELS: ${{ vars.AGENT_PROACTIVE_DECISION_GROQ_MODELS || 'llama-3.1-8b-instant,meta-llama/llama-4-scout-17b-16e-instruct,qwen/qwen3-32b' }}\n AGENT_PROACTIVE_DECISION_CONTEXT_CHARS: ${{ vars.AGENT_PROACTIVE_DECISION_CONTEXT_CHARS || '4000' }}\n AGENT_PROACTIVE_DECISION_ALLOW_DEEPSEEK_FALLBACK: ${{ vars.AGENT_PROACTIVE_DECISION_ALLOW_DEEPSEEK_FALLBACK || 'false' }}\n AMBIENT_REACTIONS_ENABLED: ${{ vars.AMBIENT_REACTIONS_ENABLED || 'true' }}\n AMBIENT_REACTIONS_SAMPLE_RATE: ${{ vars.AMBIENT_REACTIONS_SAMPLE_RATE || '0.80' }}\n AMBIENT_REACTIONS_CONFIDENCE_THRESHOLD: ${{ vars.AMBIENT_REACTIONS_CONFIDENCE_THRESHOLD || '0.80' }}\n AMBIENT_REACTIONS_DECISION_GROQ_MODELS: ${{ vars.AMBIENT_REACTIONS_DECISION_GROQ_MODELS || 'llama-3.1-8b-instant,qwen/qwen3-32b,meta-llama/llama-4-scout-17b-16e-instruct' }}\n AMBIENT_REACTIONS_DECISION_CONTEXT_CHARS: ${{ vars.AMBIENT_REACTIONS_DECISION_CONTEXT_CHARS || '3000' }}\n AMBIENT_REACTIONS_MIN_GAP_PER_CHAT_SECONDS: ${{ vars.AMBIENT_REACTIONS_MIN_GAP_PER_CHAT_SECONDS || '60' }}\n AMBIENT_REACTIONS_MIN_GAP_PER_USER_SECONDS: ${{ vars.AMBIENT_REACTIONS_MIN_GAP_PER_USER_SECONDS || '300' }}\n AMBIENT_REACTIONS_MAX_PER_CHAT_PER_HOUR: ${{ vars.AMBIENT_REACTIONS_MAX_PER_CHAT_PER_HOUR || '12' }}\n AMBIENT_REACTIONS_MAX_PER_CHAT_PER_DAY: ${{ vars.AMBIENT_REACTIONS_MAX_PER_CHAT_PER_DAY || '100' }}\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n # npm package \"aws-cdk\" is the CLI only; its version is NOT the same as Python \"aws-cdk-lib\"\n # (since ~2.179, CLI uses 2.1xxx numbering). Install a recent CLI so cloud-assembly schema matches.\n - name: Install AWS CDK CLI (pinned)\n run: |\n npm install -g aws-cdk@2.1119.0\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: CDK Synth (Verify Compilation)\n working-directory: ./infra\n run: |\n uv run cdk synth -c env=dev\n\n - name: CDK Diff (Preview Changes)\n id: cdk-diff\n working-directory: ./infra\n run: |\n set +e\n uv run cdk diff -c env=dev > /tmp/cdk-diff.txt 2>&1\n diffexit=$?\n set -e\n # CDK: 0 = no changes, 1 = differences, other = real failure\n if [ \"$diffexit\" -ne 0 ] && [ \"$diffexit\" -ne 1 ]; then\n echo \"cdk diff failed with exit $diffexit\"\n cat /tmp/cdk-diff.txt\n exit \"$diffexit\"\n fi\n\n echo \"## ๐ Infrastructure Changes Preview (Zerde Telegram Bot)\" > /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR will modify the following AWS resources:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n if ! grep -q \"Stack ZerdeTelegramBotStack-dev\" /tmp/cdk-diff.txt && ! grep -q \"There were no differences\" /tmp/cdk-diff.txt; then\n echo \"### โน๏ธ No infrastructure changes detected\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR only contains code changes (Lambda functions, etc.)\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n else\n echo \"### โ
Resources to be Created:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\+.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*+/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n echo \"### โ Resources to be Deleted:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\-.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*-/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n echo \"### โ ๏ธ Resources to be Modified:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*~.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*~/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n echo \"### ๐ง Property Changes:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*[+\\-~].*:\" /tmp/cdk-diff.txt | grep -v \"AWS::\" | head -30 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n fi\n\n echo \"\" >> /tmp/diff-report.md\n echo \"๐ Full CDK Diff Output
\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo '```diff' >> /tmp/diff-report.md\n cat /tmp/cdk-diff.txt >> /tmp/diff-report.md\n echo '```' >> /tmp/diff-report.md\n echo \" \" >> /tmp/diff-report.md\n\n cat /tmp/diff-report.md\n\n - name: Comment PR with Infrastructure Diff\n uses: actions/github-script@v7\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n script: |\n const fs = require('fs');\n const report = fs.readFileSync('/tmp/diff-report.md', 'utf8');\n\n const { data: comments } = await github.rest.issues.listComments({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n });\n\n const botComment = comments.find(comment =>\n comment.user.type === 'Bot' &&\n comment.body.includes('Infrastructure Changes Preview')\n );\n\n if (botComment) {\n await github.rest.issues.updateComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n comment_id: botComment.id,\n body: report\n });\n } else {\n await github.rest.issues.createComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n body: report\n });\n }\n"}, "db9d171ed3e4de94443d38e199c676441376f0ba": {"t": 1785762131.4297967, "n": 11695, "h": "333cdf89be590149", "c": "name: PR Check\n\non:\n pull_request:\n branches:\n - main\n types: [opened, synchronize, reopened]\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n pull-requests: write # Allow bot to write diff results to PR comments\n\njobs:\n quality-check:\n name: Code Quality Checks\n runs-on: ubuntu-latest\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff preview\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Run pre-commit hooks\n run: |\n uv run pre-commit run --all-files\n\n - name: Run Unit Tests\n run: |\n uv run pytest tests/ -v\n\n infra-preview:\n needs: quality-check\n name: Infrastructure Changes Preview\n runs-on: ubuntu-24.04-arm\n if: github.event.pull_request.head.repo.full_name == github.repository\n\n # API keys and tokens are stored in SSM Parameter Store โ CDK only needs non-secret config.\n env:\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG || 'kk' }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE || 'https://api.telegram.org/bot' }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER || 'gemini' }}\n GEMINI_MODEL: ${{ vars.GEMINI_MODEL }}\n WTF_GEMINI_MODEL: ${{ vars.WTF_GEMINI_MODEL }}\n GEMINI_RPD_LIMIT: ${{ vars.GEMINI_RPD_LIMIT }}\n GEMINI_EMBEDDING_RPD_LIMIT: ${{ vars.GEMINI_EMBEDDING_RPD_LIMIT || '1000' }}\n GEMINI_API_BASE: ${{ vars.GEMINI_API_BASE || 'https://generativelanguage.googleapis.com/v1beta/models' }}\n FALLBACK_MODEL: ${{ vars.FALLBACK_MODEL }}\n GROQ_MODEL: ${{ vars.GROQ_MODEL }}\n GROQ_API_BASE: ${{ vars.GROQ_API_BASE || 'https://api.groq.com/openai/v1' }}\n DEEPSEEK_MODEL: ${{ vars.DEEPSEEK_MODEL }}\n DEEPSEEK_API_BASE: ${{ vars.DEEPSEEK_API_BASE || 'https://api.deepseek.com' }}\n SPAM_RULE_ENFORCE_THRESHOLD: ${{ vars.SPAM_RULE_ENFORCE_THRESHOLD || '0.8' }}\n SPAM_RULE_AI_THRESHOLD: ${{ vars.SPAM_RULE_AI_THRESHOLD || '0.15' }}\n SPAM_AI_CONFIDENCE_THRESHOLD: ${{ vars.SPAM_AI_CONFIDENCE_THRESHOLD || '0.85' }}\n ADMIN_USER_ID: ${{ secrets.ADMIN_USER_ID }}\n CHATS_KK: ${{ vars.CHATS_KK }}\n CHATS_ZH: ${{ vars.CHATS_ZH }}\n CHATS_RU: ${{ vars.CHATS_RU }}\n CAPTCHA_TIMEOUT_SECONDS: ${{ vars.CAPTCHA_TIMEOUT_SECONDS }}\n KICK_BAN_DURATION_SECONDS: ${{ vars.KICK_BAN_DURATION_SECONDS }}\n VOTEBAN_THRESHOLD: ${{ vars.VOTEBAN_THRESHOLD }}\n VOTEBAN_FORGIVE_THRESHOLD: ${{ vars.VOTEBAN_FORGIVE_THRESHOLD }}\n CAPTCHA_MAX_ATTEMPTS: ${{ vars.CAPTCHA_MAX_ATTEMPTS || '3' }}\n QUIZ_LLM_RPD: ${{ vars.QUIZ_LLM_RPD }}\n NEWS_GEMINI_MODEL: ${{ vars.NEWS_GEMINI_MODEL }}\n QUIZ_GEMINI_MODEL: ${{ vars.QUIZ_GEMINI_MODEL }}\n QUIZ_CHATS_KK: ${{ vars.QUIZ_CHATS_KK }}\n QUIZ_CHATS_ZH: ${{ vars.QUIZ_CHATS_ZH }}\n QUIZ_CHATS_RU: ${{ vars.QUIZ_CHATS_RU }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n GROUP_MEMORY_ENABLED: ${{ vars.GROUP_MEMORY_ENABLED || 'true' }}\n GROUP_MEMORY_RECENT_LIMIT: ${{ vars.GROUP_MEMORY_RECENT_LIMIT || '300' }}\n GROUP_MEMORY_RETENTION_DAYS: ${{ vars.GROUP_MEMORY_RETENTION_DAYS || '3650' }}\n GROUP_MEMORY_DAILY_SUMMARY_DAYS: ${{ vars.GROUP_MEMORY_DAILY_SUMMARY_DAYS || '7' }}\n GROUP_MEMORY_DAILY_SUMMARY_MESSAGE_LIMIT: ${{ vars.GROUP_MEMORY_DAILY_SUMMARY_MESSAGE_LIMIT || '500' }}\n VECTOR_MEMORY_ENABLED: ${{ vars.VECTOR_MEMORY_ENABLED || 'true' }}\n VECTOR_MEMORY_PROVIDER: ${{ vars.VECTOR_MEMORY_PROVIDER || 's3_vectors' }}\n VECTOR_MEMORY_DIMENSIONS: ${{ vars.VECTOR_MEMORY_DIMENSIONS || '768' }}\n VECTOR_MEMORY_EMBEDDING_MODEL: ${{ vars.VECTOR_MEMORY_EMBEDDING_MODEL || 'gemini-embedding-2' }}\n VECTOR_MEMORY_INDEX_THROTTLE_SECONDS: ${{ vars.VECTOR_MEMORY_INDEX_THROTTLE_SECONDS || '3' }}\n VECTOR_MEMORY_BACKFILL_BATCH_SIZE: ${{ vars.VECTOR_MEMORY_BACKFILL_BATCH_SIZE || '50' }}\n VECTOR_MEMORY_MAX_DISTANCE: ${{ vars.VECTOR_MEMORY_MAX_DISTANCE || '0.85' }}\n VECTOR_MEMORY_VECTOR_BUCKET_NAME: ${{ vars.VECTOR_MEMORY_VECTOR_BUCKET_NAME }}\n VECTOR_MEMORY_INDEX_NAME: ${{ vars.VECTOR_MEMORY_INDEX_NAME }}\n AGENT_ENABLED: ${{ vars.AGENT_ENABLED || 'true' }}\n AGENT_BOT_USERNAME: ${{ vars.AGENT_BOT_USERNAME || '@zerde_kz_bot' }}\n AGENT_RECENT_CONTEXT_LIMIT: ${{ vars.AGENT_RECENT_CONTEXT_LIMIT || '100' }}\n AGENT_DAILY_PROACTIVE_LIMIT: ${{ vars.AGENT_DAILY_PROACTIVE_LIMIT || '10' }}\n AGENT_PROACTIVE_FINAL_THRESHOLD: ${{ vars.AGENT_PROACTIVE_FINAL_THRESHOLD || '0.72' }}\n AGENT_PROACTIVE_DECISION_GROQ_MODELS: ${{ vars.AGENT_PROACTIVE_DECISION_GROQ_MODELS || 'llama-3.1-8b-instant,meta-llama/llama-4-scout-17b-16e-instruct,qwen/qwen3-32b' }}\n AGENT_PROACTIVE_DECISION_CONTEXT_CHARS: ${{ vars.AGENT_PROACTIVE_DECISION_CONTEXT_CHARS || '4000' }}\n AGENT_PROACTIVE_DECISION_ALLOW_DEEPSEEK_FALLBACK: ${{ vars.AGENT_PROACTIVE_DECISION_ALLOW_DEEPSEEK_FALLBACK || 'false' }}\n AMBIENT_REACTIONS_ENABLED: ${{ vars.AMBIENT_REACTIONS_ENABLED || 'true' }}\n AMBIENT_REACTIONS_SAMPLE_RATE: ${{ vars.AMBIENT_REACTIONS_SAMPLE_RATE || '0.80' }}\n AMBIENT_REACTIONS_CONFIDENCE_THRESHOLD: ${{ vars.AMBIENT_REACTIONS_CONFIDENCE_THRESHOLD || '0.80' }}\n AMBIENT_REACTIONS_DECISION_GROQ_MODELS: ${{ vars.AMBIENT_REACTIONS_DECISION_GROQ_MODELS || 'llama-3.1-8b-instant,qwen/qwen3-32b,meta-llama/llama-4-scout-17b-16e-instruct' }}\n AMBIENT_REACTIONS_DECISION_CONTEXT_CHARS: ${{ vars.AMBIENT_REACTIONS_DECISION_CONTEXT_CHARS || '3000' }}\n AMBIENT_REACTIONS_MIN_GAP_PER_CHAT_SECONDS: ${{ vars.AMBIENT_REACTIONS_MIN_GAP_PER_CHAT_SECONDS || '60' }}\n AMBIENT_REACTIONS_MIN_GAP_PER_USER_SECONDS: ${{ vars.AMBIENT_REACTIONS_MIN_GAP_PER_USER_SECONDS || '300' }}\n AMBIENT_REACTIONS_MAX_PER_CHAT_PER_HOUR: ${{ vars.AMBIENT_REACTIONS_MAX_PER_CHAT_PER_HOUR || '12' }}\n AMBIENT_REACTIONS_MAX_PER_CHAT_PER_DAY: ${{ vars.AMBIENT_REACTIONS_MAX_PER_CHAT_PER_DAY || '100' }}\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n # npm package \"aws-cdk\" is the CLI only; its version is NOT the same as Python \"aws-cdk-lib\"\n # (since ~2.179, CLI uses 2.1xxx numbering). Install a recent CLI so cloud-assembly schema matches.\n - name: Install AWS CDK CLI (pinned)\n run: |\n npm install -g aws-cdk@2.1119.0\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: CDK Synth (Verify Compilation)\n working-directory: ./infra\n run: |\n uv run cdk synth -c env=dev\n\n - name: CDK Diff (Preview Changes)\n id: cdk-diff\n working-directory: ./infra\n run: |\n set +e\n uv run cdk diff -c env=dev > /tmp/cdk-diff.txt 2>&1\n diffexit=$?\n set -e\n # CDK: 0 = no changes, 1 = differences, other = real failure\n if [ \"$diffexit\" -ne 0 ] && [ \"$diffexit\" -ne 1 ]; then\n echo \"cdk diff failed with exit $diffexit\"\n cat /tmp/cdk-diff.txt\n exit \"$diffexit\"\n fi\n\n echo \"## ๐ Infrastructure Changes Preview (Zerde Telegram Bot)\" > /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR will modify the following AWS resources:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n if ! grep -q \"Stack ZerdeTelegramBotStack-dev\" /tmp/cdk-diff.txt && ! grep -q \"There were no differences\" /tmp/cdk-diff.txt; then\n echo \"### โน๏ธ No infrastructure changes detected\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR only contains code changes (Lambda functions, etc.)\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n else\n echo \"### โ
Resources to be Created:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\+.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*+/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n echo \"### โ Resources to be Deleted:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\-.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*-/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n echo \"### โ ๏ธ Resources to be Modified:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*~.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*~/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n echo \"### ๐ง Property Changes:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*[+\\-~].*:\" /tmp/cdk-diff.txt | grep -v \"AWS::\" | head -30 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n fi\n\n echo \"\" >> /tmp/diff-report.md\n echo \"๐ Full CDK Diff Output
\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo '```diff' >> /tmp/diff-report.md\n cat /tmp/cdk-diff.txt >> /tmp/diff-report.md\n echo '```' >> /tmp/diff-report.md\n echo \" \" >> /tmp/diff-report.md\n\n cat /tmp/diff-report.md\n\n - name: Comment PR with Infrastructure Diff\n uses: actions/github-script@v7\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n script: |\n const fs = require('fs');\n const report = fs.readFileSync('/tmp/diff-report.md', 'utf8');\n\n const { data: comments } = await github.rest.issues.listComments({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n });\n\n const botComment = comments.find(comment =>\n comment.user.type === 'Bot' &&\n comment.body.includes('Infrastructure Changes Preview')\n );\n\n if (botComment) {\n await github.rest.issues.updateComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n comment_id: botComment.id,\n body: report\n });\n } else {\n await github.rest.issues.createComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n body: report\n });\n }\n"}, "ed58f0e00b9c34d21c0c6d95f91276dac8924a7f": {"t": 1785762132.910221, "n": 11086, "h": "c1d2361e3536f272", "c": "name: PR Check\n\non:\n pull_request:\n branches:\n - main\n types: [opened, synchronize, reopened]\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n pull-requests: write # Allow bot to write diff results to PR comments\n\njobs:\n quality-check:\n name: Code Quality Checks\n runs-on: ubuntu-latest\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff preview\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Run pre-commit hooks\n run: |\n uv run pre-commit run --all-files\n\n - name: Run Unit Tests\n run: |\n uv run pytest tests/ -v\n\n infra-preview:\n needs: quality-check\n name: Infrastructure Changes Preview\n runs-on: ubuntu-24.04-arm\n if: github.event.pull_request.head.repo.full_name == github.repository\n\n # API keys and tokens are stored in SSM Parameter Store โ CDK only needs non-secret config.\n env:\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG || 'kk' }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE || 'https://api.telegram.org/bot' }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER || 'gemini' }}\n GEMINI_MODEL: ${{ vars.GEMINI_MODEL }}\n WTF_GEMINI_MODEL: ${{ vars.WTF_GEMINI_MODEL }}\n GEMINI_RPD_LIMIT: ${{ vars.GEMINI_RPD_LIMIT }}\n GEMINI_EMBEDDING_RPD_LIMIT: ${{ vars.GEMINI_EMBEDDING_RPD_LIMIT || '1000' }}\n GEMINI_API_BASE: ${{ vars.GEMINI_API_BASE || 'https://generativelanguage.googleapis.com/v1beta/models' }}\n FALLBACK_MODEL: ${{ vars.FALLBACK_MODEL }}\n GROQ_MODEL: ${{ vars.GROQ_MODEL }}\n GROQ_API_BASE: ${{ vars.GROQ_API_BASE || 'https://api.groq.com/openai/v1' }}\n DEEPSEEK_MODEL: ${{ vars.DEEPSEEK_MODEL }}\n DEEPSEEK_API_BASE: ${{ vars.DEEPSEEK_API_BASE || 'https://api.deepseek.com' }}\n SPAM_RULE_ENFORCE_THRESHOLD: ${{ vars.SPAM_RULE_ENFORCE_THRESHOLD || '0.8' }}\n SPAM_RULE_AI_THRESHOLD: ${{ vars.SPAM_RULE_AI_THRESHOLD || '0.15' }}\n SPAM_AI_CONFIDENCE_THRESHOLD: ${{ vars.SPAM_AI_CONFIDENCE_THRESHOLD || '0.85' }}\n ADMIN_USER_ID: ${{ secrets.ADMIN_USER_ID }}\n CHATS_KK: ${{ vars.CHATS_KK }}\n CHATS_ZH: ${{ vars.CHATS_ZH }}\n CHATS_RU: ${{ vars.CHATS_RU }}\n CAPTCHA_TIMEOUT_SECONDS: ${{ vars.CAPTCHA_TIMEOUT_SECONDS }}\n KICK_BAN_DURATION_SECONDS: ${{ vars.KICK_BAN_DURATION_SECONDS }}\n VOTEBAN_THRESHOLD: ${{ vars.VOTEBAN_THRESHOLD }}\n VOTEBAN_FORGIVE_THRESHOLD: ${{ vars.VOTEBAN_FORGIVE_THRESHOLD }}\n CAPTCHA_MAX_ATTEMPTS: ${{ vars.CAPTCHA_MAX_ATTEMPTS || '3' }}\n QUIZ_LLM_RPD: ${{ vars.QUIZ_LLM_RPD }}\n NEWS_GEMINI_MODEL: ${{ vars.NEWS_GEMINI_MODEL }}\n QUIZ_GEMINI_MODEL: ${{ vars.QUIZ_GEMINI_MODEL }}\n QUIZ_CHATS_KK: ${{ vars.QUIZ_CHATS_KK }}\n QUIZ_CHATS_ZH: ${{ vars.QUIZ_CHATS_ZH }}\n QUIZ_CHATS_RU: ${{ vars.QUIZ_CHATS_RU }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n GROUP_MEMORY_ENABLED: ${{ vars.GROUP_MEMORY_ENABLED || 'true' }}\n GROUP_MEMORY_RECENT_LIMIT: ${{ vars.GROUP_MEMORY_RECENT_LIMIT || '300' }}\n GROUP_MEMORY_RETENTION_DAYS: ${{ vars.GROUP_MEMORY_RETENTION_DAYS || '3650' }}\n GROUP_MEMORY_DAILY_SUMMARY_DAYS: ${{ vars.GROUP_MEMORY_DAILY_SUMMARY_DAYS || '7' }}\n GROUP_MEMORY_DAILY_SUMMARY_MESSAGE_LIMIT: ${{ vars.GROUP_MEMORY_DAILY_SUMMARY_MESSAGE_LIMIT || '500' }}\n VECTOR_MEMORY_ENABLED: ${{ vars.VECTOR_MEMORY_ENABLED || 'true' }}\n VECTOR_MEMORY_PROVIDER: ${{ vars.VECTOR_MEMORY_PROVIDER || 's3_vectors' }}\n VECTOR_MEMORY_DIMENSIONS: ${{ vars.VECTOR_MEMORY_DIMENSIONS || '768' }}\n VECTOR_MEMORY_EMBEDDING_MODEL: ${{ vars.VECTOR_MEMORY_EMBEDDING_MODEL || 'gemini-embedding-2' }}\n VECTOR_MEMORY_INDEX_THROTTLE_SECONDS: ${{ vars.VECTOR_MEMORY_INDEX_THROTTLE_SECONDS || '3' }}\n VECTOR_MEMORY_BACKFILL_BATCH_SIZE: ${{ vars.VECTOR_MEMORY_BACKFILL_BATCH_SIZE || '50' }}\n VECTOR_MEMORY_MAX_DISTANCE: ${{ vars.VECTOR_MEMORY_MAX_DISTANCE || '0.85' }}\n VECTOR_MEMORY_VECTOR_BUCKET_NAME: ${{ vars.VECTOR_MEMORY_VECTOR_BUCKET_NAME }}\n VECTOR_MEMORY_INDEX_NAME: ${{ vars.VECTOR_MEMORY_INDEX_NAME }}\n AGENT_ENABLED: ${{ vars.AGENT_ENABLED || 'true' }}\n AGENT_BOT_USERNAME: ${{ vars.AGENT_BOT_USERNAME || '@zerde_kz_bot' }}\n AGENT_RECENT_CONTEXT_LIMIT: ${{ vars.AGENT_RECENT_CONTEXT_LIMIT || '100' }}\n AGENT_DAILY_PROACTIVE_LIMIT: ${{ vars.AGENT_DAILY_PROACTIVE_LIMIT || '10' }}\n AGENT_PROACTIVE_SCORE_THRESHOLD: ${{ vars.AGENT_PROACTIVE_SCORE_THRESHOLD || '0.62' }}\n AGENT_PROACTIVE_FINAL_THRESHOLD: ${{ vars.AGENT_PROACTIVE_FINAL_THRESHOLD || '0.72' }}\n AMBIENT_REACTIONS_ENABLED: ${{ vars.AMBIENT_REACTIONS_ENABLED || 'true' }}\n AMBIENT_REACTIONS_SAMPLE_RATE: ${{ vars.AMBIENT_REACTIONS_SAMPLE_RATE || '0.80' }}\n AMBIENT_REACTIONS_CONFIDENCE_THRESHOLD: ${{ vars.AMBIENT_REACTIONS_CONFIDENCE_THRESHOLD || '0.80' }}\n AMBIENT_REACTIONS_MIN_GAP_PER_CHAT_SECONDS: ${{ vars.AMBIENT_REACTIONS_MIN_GAP_PER_CHAT_SECONDS || '60' }}\n AMBIENT_REACTIONS_MIN_GAP_PER_USER_SECONDS: ${{ vars.AMBIENT_REACTIONS_MIN_GAP_PER_USER_SECONDS || '300' }}\n AMBIENT_REACTIONS_MAX_PER_CHAT_PER_HOUR: ${{ vars.AMBIENT_REACTIONS_MAX_PER_CHAT_PER_HOUR || '12' }}\n AMBIENT_REACTIONS_MAX_PER_CHAT_PER_DAY: ${{ vars.AMBIENT_REACTIONS_MAX_PER_CHAT_PER_DAY || '100' }}\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n # npm package \"aws-cdk\" is the CLI only; its version is NOT the same as Python \"aws-cdk-lib\"\n # (since ~2.179, CLI uses 2.1xxx numbering). Install a recent CLI so cloud-assembly schema matches.\n - name: Install AWS CDK CLI (pinned)\n run: |\n npm install -g aws-cdk@2.1119.0\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: CDK Synth (Verify Compilation)\n working-directory: ./infra\n run: |\n uv run cdk synth -c env=dev\n\n - name: CDK Diff (Preview Changes)\n id: cdk-diff\n working-directory: ./infra\n run: |\n set +e\n uv run cdk diff -c env=dev > /tmp/cdk-diff.txt 2>&1\n diffexit=$?\n set -e\n # CDK: 0 = no changes, 1 = differences, other = real failure\n if [ \"$diffexit\" -ne 0 ] && [ \"$diffexit\" -ne 1 ]; then\n echo \"cdk diff failed with exit $diffexit\"\n cat /tmp/cdk-diff.txt\n exit \"$diffexit\"\n fi\n\n echo \"## ๐ Infrastructure Changes Preview (Zerde Telegram Bot)\" > /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR will modify the following AWS resources:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n if ! grep -q \"Stack ZerdeTelegramBotStack-dev\" /tmp/cdk-diff.txt && ! grep -q \"There were no differences\" /tmp/cdk-diff.txt; then\n echo \"### โน๏ธ No infrastructure changes detected\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR only contains code changes (Lambda functions, etc.)\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n else\n echo \"### โ
Resources to be Created:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\+.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*+/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n echo \"### โ Resources to be Deleted:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\-.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*-/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n echo \"### โ ๏ธ Resources to be Modified:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*~.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*~/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n echo \"### ๐ง Property Changes:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*[+\\-~].*:\" /tmp/cdk-diff.txt | grep -v \"AWS::\" | head -30 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n fi\n\n echo \"\" >> /tmp/diff-report.md\n echo \"๐ Full CDK Diff Output
\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo '```diff' >> /tmp/diff-report.md\n cat /tmp/cdk-diff.txt >> /tmp/diff-report.md\n echo '```' >> /tmp/diff-report.md\n echo \" \" >> /tmp/diff-report.md\n\n cat /tmp/diff-report.md\n\n - name: Comment PR with Infrastructure Diff\n uses: actions/github-script@v7\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n script: |\n const fs = require('fs');\n const report = fs.readFileSync('/tmp/diff-report.md', 'utf8');\n\n const { data: comments } = await github.rest.issues.listComments({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n });\n\n const botComment = comments.find(comment =>\n comment.user.type === 'Bot' &&\n comment.body.includes('Infrastructure Changes Preview')\n );\n\n if (botComment) {\n await github.rest.issues.updateComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n comment_id: botComment.id,\n body: report\n });\n } else {\n await github.rest.issues.createComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n body: report\n });\n }\n"}, "df65520014de232e57b99eca6bb0a5d7de6d0b1b": {"t": 1785762156.759, "n": 8885, "h": "4a9000d68831e812", "c": "name: PR Check\n\non:\n pull_request:\n branches:\n - main\n types: [opened, synchronize, reopened]\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n pull-requests: write # Allow bot to write diff results to PR comments\n\njobs:\n quality-check:\n name: Code Quality Checks\n runs-on: ubuntu-latest\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff preview\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Run pre-commit hooks\n run: |\n uv run pre-commit run --all-files\n\n - name: Run Unit Tests\n run: |\n uv run pytest tests/ -v\n\n infra-preview:\n needs: quality-check\n name: Infrastructure Changes Preview\n runs-on: ubuntu-24.04-arm\n if: github.event.pull_request.head.repo.full_name == github.repository\n\n # API keys and tokens are stored in SSM Parameter Store โ CDK only needs non-secret config.\n env:\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG || 'kk' }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE || 'https://api.telegram.org/bot' }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER || 'gemini' }}\n GEMINI_MODEL: ${{ vars.GEMINI_MODEL }}\n WTF_GEMINI_MODEL: ${{ vars.WTF_GEMINI_MODEL }}\n GEMINI_RPD_LIMIT: ${{ vars.GEMINI_RPD_LIMIT }}\n GEMINI_API_BASE: ${{ vars.GEMINI_API_BASE || 'https://generativelanguage.googleapis.com/v1beta/models' }}\n FALLBACK_MODEL: ${{ vars.FALLBACK_MODEL }}\n GROQ_MODEL: ${{ vars.GROQ_MODEL }}\n GROQ_API_BASE: ${{ vars.GROQ_API_BASE || 'https://api.groq.com/openai/v1' }}\n DEEPSEEK_MODEL: ${{ vars.DEEPSEEK_MODEL }}\n DEEPSEEK_API_BASE: ${{ vars.DEEPSEEK_API_BASE || 'https://api.deepseek.com' }}\n ADMIN_USER_ID: ${{ secrets.ADMIN_USER_ID }}\n CHATS_KK: ${{ vars.CHATS_KK }}\n CHATS_ZH: ${{ vars.CHATS_ZH }}\n CHATS_RU: ${{ vars.CHATS_RU }}\n CAPTCHA_TIMEOUT_SECONDS: ${{ vars.CAPTCHA_TIMEOUT_SECONDS }}\n KICK_BAN_DURATION_SECONDS: ${{ vars.KICK_BAN_DURATION_SECONDS }}\n VOTEBAN_THRESHOLD: ${{ vars.VOTEBAN_THRESHOLD }}\n VOTEBAN_FORGIVE_THRESHOLD: ${{ vars.VOTEBAN_FORGIVE_THRESHOLD }}\n CAPTCHA_MAX_ATTEMPTS: ${{ vars.CAPTCHA_MAX_ATTEMPTS || '3' }}\n QUIZ_LLM_RPD: ${{ vars.QUIZ_LLM_RPD }}\n NEWS_GEMINI_MODEL: ${{ vars.NEWS_GEMINI_MODEL }}\n QUIZ_GEMINI_MODEL: ${{ vars.QUIZ_GEMINI_MODEL }}\n QUIZ_CHATS_KK: ${{ vars.QUIZ_CHATS_KK }}\n QUIZ_CHATS_ZH: ${{ vars.QUIZ_CHATS_ZH }}\n QUIZ_CHATS_RU: ${{ vars.QUIZ_CHATS_RU }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n GROUP_MEMORY_ENABLED: ${{ vars.GROUP_MEMORY_ENABLED || 'true' }}\n GROUP_MEMORY_RECENT_LIMIT: ${{ vars.GROUP_MEMORY_RECENT_LIMIT || '300' }}\n GROUP_MEMORY_RETENTION_DAYS: ${{ vars.GROUP_MEMORY_RETENTION_DAYS || '30' }}\n AGENT_ENABLED: ${{ vars.AGENT_ENABLED || 'true' }}\n AGENT_BOT_USERNAME: ${{ vars.AGENT_BOT_USERNAME || '@zerde_kz_bot' }}\n AGENT_RECENT_CONTEXT_LIMIT: ${{ vars.AGENT_RECENT_CONTEXT_LIMIT || '100' }}\n AGENT_DAILY_PROACTIVE_LIMIT: ${{ vars.AGENT_DAILY_PROACTIVE_LIMIT || '10' }}\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n # npm package \"aws-cdk\" is the CLI only; its version is NOT the same as Python \"aws-cdk-lib\"\n # (since ~2.179, CLI uses 2.1xxx numbering). Install a recent CLI so cloud-assembly schema matches.\n - name: Install AWS CDK CLI (pinned)\n run: |\n npm install -g aws-cdk@2.1119.0\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: CDK Synth (Verify Compilation)\n working-directory: ./infra\n run: |\n uv run cdk synth -c env=dev\n\n - name: CDK Diff (Preview Changes)\n id: cdk-diff\n working-directory: ./infra\n run: |\n set +e\n uv run cdk diff -c env=dev > /tmp/cdk-diff.txt 2>&1\n diffexit=$?\n set -e\n # CDK: 0 = no changes, 1 = differences, other = real failure\n if [ \"$diffexit\" -ne 0 ] && [ \"$diffexit\" -ne 1 ]; then\n echo \"cdk diff failed with exit $diffexit\"\n cat /tmp/cdk-diff.txt\n exit \"$diffexit\"\n fi\n\n echo \"## ๐ Infrastructure Changes Preview (Zerde Telegram Bot)\" > /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR will modify the following AWS resources:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n if ! grep -q \"Stack ZerdeTelegramBotStack-dev\" /tmp/cdk-diff.txt && ! grep -q \"There were no differences\" /tmp/cdk-diff.txt; then\n echo \"### โน๏ธ No infrastructure changes detected\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR only contains code changes (Lambda functions, etc.)\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n else\n echo \"### โ
Resources to be Created:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\+.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*+/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n echo \"### โ Resources to be Deleted:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\-.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*-/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n echo \"### โ ๏ธ Resources to be Modified:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*~.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*~/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n echo \"### ๐ง Property Changes:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*[+\\-~].*:\" /tmp/cdk-diff.txt | grep -v \"AWS::\" | head -30 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n fi\n\n echo \"\" >> /tmp/diff-report.md\n echo \"๐ Full CDK Diff Output
\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo '```diff' >> /tmp/diff-report.md\n cat /tmp/cdk-diff.txt >> /tmp/diff-report.md\n echo '```' >> /tmp/diff-report.md\n echo \" \" >> /tmp/diff-report.md\n\n cat /tmp/diff-report.md\n\n - name: Comment PR with Infrastructure Diff\n uses: actions/github-script@v7\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n script: |\n const fs = require('fs');\n const report = fs.readFileSync('/tmp/diff-report.md', 'utf8');\n\n const { data: comments } = await github.rest.issues.listComments({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n });\n\n const botComment = comments.find(comment =>\n comment.user.type === 'Bot' &&\n comment.body.includes('Infrastructure Changes Preview')\n );\n\n if (botComment) {\n await github.rest.issues.updateComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n comment_id: botComment.id,\n body: report\n });\n } else {\n await github.rest.issues.createComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n body: report\n });\n }\n"}, "3dec0a564f626ae04add95d35b0133735970fd2f": {"t": 1785762159.7990632, "n": 8353, "h": "94d2cd96e9a826bd", "c": "name: PR Check\n\non:\n pull_request:\n branches:\n - main\n types: [opened, synchronize, reopened]\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n pull-requests: write # Allow bot to write diff results to PR comments\n\njobs:\n quality-check:\n name: Code Quality Checks\n runs-on: ubuntu-latest\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff preview\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Run pre-commit hooks\n run: |\n uv run pre-commit run --all-files\n\n - name: Run Unit Tests\n run: |\n uv run pytest tests/ -v\n\n infra-preview:\n needs: quality-check\n name: Infrastructure Changes Preview\n runs-on: ubuntu-24.04-arm\n if: github.event.pull_request.head.repo.full_name == github.repository\n\n # API keys and tokens are stored in SSM Parameter Store โ CDK only needs non-secret config.\n env:\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG || 'kk' }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE || 'https://api.telegram.org/bot' }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER || 'gemini' }}\n GEMINI_MODEL: ${{ vars.GEMINI_MODEL }}\n WTF_GEMINI_MODEL: ${{ vars.WTF_GEMINI_MODEL }}\n GEMINI_RPD_LIMIT: ${{ vars.GEMINI_RPD_LIMIT }}\n GEMINI_API_BASE: ${{ vars.GEMINI_API_BASE || 'https://generativelanguage.googleapis.com/v1beta/models' }}\n FALLBACK_MODEL: ${{ vars.FALLBACK_MODEL }}\n GROQ_MODEL: ${{ vars.GROQ_MODEL }}\n GROQ_API_BASE: ${{ vars.GROQ_API_BASE || 'https://api.groq.com/openai/v1' }}\n DEEPSEEK_MODEL: ${{ vars.DEEPSEEK_MODEL }}\n DEEPSEEK_API_BASE: ${{ vars.DEEPSEEK_API_BASE || 'https://api.deepseek.com' }}\n ADMIN_USER_ID: ${{ secrets.ADMIN_USER_ID }}\n CHATS_KK: ${{ vars.CHATS_KK }}\n CHATS_ZH: ${{ vars.CHATS_ZH }}\n CHATS_RU: ${{ vars.CHATS_RU }}\n CAPTCHA_TIMEOUT_SECONDS: ${{ vars.CAPTCHA_TIMEOUT_SECONDS }}\n KICK_BAN_DURATION_SECONDS: ${{ vars.KICK_BAN_DURATION_SECONDS }}\n VOTEBAN_THRESHOLD: ${{ vars.VOTEBAN_THRESHOLD }}\n VOTEBAN_FORGIVE_THRESHOLD: ${{ vars.VOTEBAN_FORGIVE_THRESHOLD }}\n CAPTCHA_MAX_ATTEMPTS: ${{ vars.CAPTCHA_MAX_ATTEMPTS || '3' }}\n QUIZ_LLM_RPD: ${{ vars.QUIZ_LLM_RPD }}\n NEWS_GEMINI_MODEL: ${{ vars.NEWS_GEMINI_MODEL }}\n QUIZ_GEMINI_MODEL: ${{ vars.QUIZ_GEMINI_MODEL }}\n QUIZ_CHATS_KK: ${{ vars.QUIZ_CHATS_KK }}\n QUIZ_CHATS_ZH: ${{ vars.QUIZ_CHATS_ZH }}\n QUIZ_CHATS_RU: ${{ vars.QUIZ_CHATS_RU }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n # npm package \"aws-cdk\" is the CLI only; its version is NOT the same as Python \"aws-cdk-lib\"\n # (since ~2.179, CLI uses 2.1xxx numbering). Install a recent CLI so cloud-assembly schema matches.\n - name: Install AWS CDK CLI (pinned)\n run: |\n npm install -g aws-cdk@2.1119.0\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: CDK Synth (Verify Compilation)\n working-directory: ./infra\n run: |\n uv run cdk synth -c env=dev\n\n - name: CDK Diff (Preview Changes)\n id: cdk-diff\n working-directory: ./infra\n run: |\n set +e\n uv run cdk diff -c env=dev > /tmp/cdk-diff.txt 2>&1\n diffexit=$?\n set -e\n # CDK: 0 = no changes, 1 = differences, other = real failure\n if [ \"$diffexit\" -ne 0 ] && [ \"$diffexit\" -ne 1 ]; then\n echo \"cdk diff failed with exit $diffexit\"\n cat /tmp/cdk-diff.txt\n exit \"$diffexit\"\n fi\n\n echo \"## ๐ Infrastructure Changes Preview (Zerde Telegram Bot)\" > /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR will modify the following AWS resources:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n if ! grep -q \"Stack ZerdeTelegramBotStack-dev\" /tmp/cdk-diff.txt && ! grep -q \"There were no differences\" /tmp/cdk-diff.txt; then\n echo \"### โน๏ธ No infrastructure changes detected\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR only contains code changes (Lambda functions, etc.)\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n else\n echo \"### โ
Resources to be Created:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\+.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*+/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n echo \"### โ Resources to be Deleted:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\-.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*-/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n echo \"### โ ๏ธ Resources to be Modified:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*~.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*~/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n echo \"### ๐ง Property Changes:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*[+\\-~].*:\" /tmp/cdk-diff.txt | grep -v \"AWS::\" | head -30 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n fi\n\n echo \"\" >> /tmp/diff-report.md\n echo \"๐ Full CDK Diff Output
\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo '```diff' >> /tmp/diff-report.md\n cat /tmp/cdk-diff.txt >> /tmp/diff-report.md\n echo '```' >> /tmp/diff-report.md\n echo \" \" >> /tmp/diff-report.md\n\n cat /tmp/diff-report.md\n\n - name: Comment PR with Infrastructure Diff\n uses: actions/github-script@v7\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n script: |\n const fs = require('fs');\n const report = fs.readFileSync('/tmp/diff-report.md', 'utf8');\n\n const { data: comments } = await github.rest.issues.listComments({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n });\n\n const botComment = comments.find(comment =>\n comment.user.type === 'Bot' &&\n comment.body.includes('Infrastructure Changes Preview')\n );\n\n if (botComment) {\n await github.rest.issues.updateComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n comment_id: botComment.id,\n body: report\n });\n } else {\n await github.rest.issues.createComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n body: report\n });\n }\n"}, "d3cb1b535a9c4346add997f75e09177134440fed": {"t": 1785762163.722427, "n": 8078, "h": "7c955d049fed9b8e", "c": "name: PR Check\n\non:\n pull_request:\n branches:\n - main\n types: [opened, synchronize, reopened]\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n pull-requests: write # Allow bot to write diff results to PR comments\n\njobs:\n quality-check:\n name: Code Quality Checks\n runs-on: ubuntu-latest\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff preview\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Run pre-commit hooks\n run: |\n uv run pre-commit run --all-files\n\n - name: Run Unit Tests\n run: |\n uv run pytest tests/ -v\n\n infra-preview:\n needs: quality-check\n name: Infrastructure Changes Preview\n runs-on: ubuntu-latest\n if: github.event.pull_request.head.repo.full_name == github.repository\n\n # Same env contract as CDK deploy (infra/stack.py): secrets for keys, vars for open config.\n env:\n TELEGRAM_BOT_TOKEN: ${{ secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n GEMINI_API_KEY: ${{ secrets.DEV_GEMINI_API_KEY }}\n GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}\n DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}\n LLAMA_API_KEY: ${{ secrets.LLAMA_API_KEY }}\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG || 'kk' }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE || 'https://api.telegram.org/bot' }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER || 'gemini' }}\n GEMINI_MODEL: ${{ vars.GEMINI_MODEL || 'gemini-3-flash-preview' }}\n WTF_GEMINI_MODEL: ${{ vars.WTF_GEMINI_MODEL || 'gemini-3.1-flash-lite-preview' }}\n GEMINI_RPD_LIMIT: ${{ vars.GEMINI_RPD_LIMIT || '500' }}\n GEMINI_API_BASE: ${{ vars.GEMINI_API_BASE || 'https://generativelanguage.googleapis.com/v1beta/models' }}\n FALLBACK_MODEL: ${{ vars.FALLBACK_MODEL || 'gemini-2.5-flash' }}\n WTF_FALLBACK_PROVIDER: ${{ vars.WTF_FALLBACK_PROVIDER || 'deepseek' }}\n GROQ_MODEL: ${{ vars.GROQ_MODEL || 'llama-3.3-70b-versatile' }}\n GROQ_API_BASE: ${{ vars.GROQ_API_BASE || 'https://api.groq.com/openai/v1' }}\n LLAMA_MODEL: ${{ vars.LLAMA_MODEL || 'Llama-4-Scout-17B-16E-Instruct-FP8' }}\n LLAMA_API_BASE: ${{ vars.LLAMA_API_BASE || 'https://api.llama.com/v1' }}\n DEEPSEEK_MODEL: ${{ vars.DEEPSEEK_MODEL || 'deepseek-chat' }}\n DEEPSEEK_API_BASE: ${{ vars.DEEPSEEK_API_BASE || 'https://api.deepseek.com' }}\n ADMIN_USER_ID: ${{ secrets.ADMIN_USER_ID }}\n CHATS_KK: ${{ vars.CHATS_KK }}\n CHATS_ZH: ${{ vars.CHATS_ZH }}\n CHATS_RU: ${{ vars.CHATS_RU }}\n CAPTCHA_TIMEOUT_SECONDS: ${{ vars.CAPTCHA_TIMEOUT_SECONDS || '120' }}\n KICK_BAN_DURATION_SECONDS: ${{ vars.KICK_BAN_DURATION_SECONDS || '31' }}\n VOTEBAN_THRESHOLD: ${{ vars.VOTEBAN_THRESHOLD || '7' }}\n VOTEBAN_FORGIVE_THRESHOLD: ${{ vars.VOTEBAN_FORGIVE_THRESHOLD || '7' }}\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: CDK Synth (Verify Compilation)\n working-directory: ./infra\n run: |\n uv run cdk synth -c env=dev\n\n - name: CDK Diff (Preview Changes)\n id: cdk-diff\n working-directory: ./infra\n run: |\n uv run cdk diff -c env=dev > /tmp/cdk-diff.txt 2>&1 || true\n\n echo \"## ๐ Infrastructure Changes Preview (Zerde Telegram Bot)\" > /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR will modify the following AWS resources:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n if ! grep -q \"Stack ZerdeTelegramBotStack-dev\" /tmp/cdk-diff.txt && ! grep -q \"There were no differences\" /tmp/cdk-diff.txt; then\n echo \"### โน๏ธ No infrastructure changes detected\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR only contains code changes (Lambda functions, etc.)\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n else\n echo \"### โ
Resources to be Created:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\+.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*+/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n echo \"### โ Resources to be Deleted:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\-.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*-/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n echo \"### โ ๏ธ Resources to be Modified:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*~.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*~/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n echo \"### ๐ง Property Changes:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*[+\\-~].*:\" /tmp/cdk-diff.txt | grep -v \"AWS::\" | head -30 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n fi\n\n echo \"\" >> /tmp/diff-report.md\n echo \"๐ Full CDK Diff Output
\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo '```diff' >> /tmp/diff-report.md\n cat /tmp/cdk-diff.txt >> /tmp/diff-report.md\n echo '```' >> /tmp/diff-report.md\n echo \" \" >> /tmp/diff-report.md\n\n cat /tmp/diff-report.md\n\n - name: Comment PR with Infrastructure Diff\n uses: actions/github-script@v7\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n script: |\n const fs = require('fs');\n const report = fs.readFileSync('/tmp/diff-report.md', 'utf8');\n\n const { data: comments } = await github.rest.issues.listComments({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n });\n\n const botComment = comments.find(comment =>\n comment.user.type === 'Bot' &&\n comment.body.includes('Infrastructure Changes Preview')\n );\n\n if (botComment) {\n await github.rest.issues.updateComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n comment_id: botComment.id,\n body: report\n });\n } else {\n await github.rest.issues.createComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n body: report\n });\n }\n"}, "f3bb730a668c177fbcc7662a59dc6632032e7ab0": {"t": 1785762165.8007545, "n": 8077, "h": "f79b707553921bdc", "c": "name: PR Check\n\non:\n pull_request:\n branches:\n - main\n types: [opened, synchronize, reopened]\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n pull-requests: write # Allow bot to write diff results to PR comments\n\njobs:\n quality-check:\n name: Code Quality Checks\n runs-on: ubuntu-latest\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff preview\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Run pre-commit hooks\n run: |\n uv run pre-commit run --all-files\n\n - name: Run Unit Tests\n run: |\n uv run pytest tests/ -v\n\n infra-preview:\n needs: quality-check\n name: Infrastructure Changes Preview\n runs-on: ubuntu-latest\n if: github.event.pull_request.head.repo.full_name == github.repository\n\n # Same env contract as CDK deploy (infra/stack.py): secrets for keys, vars for open config.\n env:\n TELEGRAM_BOT_TOKEN: ${{ secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n GEMINI_API_KEY: ${{ secrets.DEV_GEMINI_API_KEY }}\n GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}\n DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}\n LLAMA_API_KEY: ${{ secrets.LLAMA_API_KEY }}\n DEFAULT_LANG: ${{ vars.DEFAULT_LANG || 'kk' }}\n TELEGRAM_API_BASE: ${{ vars.TELEGRAM_API_BASE || 'https://api.telegram.org/bot' }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER || 'gemini' }}\n GEMINI_MODEL: ${{ vars.GEMINI_MODEL || 'gemini-3-flash-preview' }}\n WTF_GEMINI_MODEL: ${{ vars.WTF_GEMINI_MODEL || 'gemini-3.1-flash-lite-preview' }}\n GEMINI_RPD_LIMIT: ${{ vars.GEMINI_RPD_LIMIT || '500' }}\n GEMINI_API_BASE: ${{ vars.GEMINI_API_BASE || 'https://generativelanguage.googleapis.com/v1beta/models' }}\n FALLBACK_MODEL: ${{ vars.FALLBACK_MODEL || 'gemini-2.5-flash' }}\n WTF_FALLBACK_PROVIDER: ${{ vars.WTF_FALLBACK_PROVIDER || 'deepseek' }}\n GROQ_MODEL: ${{ vars.GROQ_MODEL || 'llama-3.3-70b-versatile' }}\n GROQ_API_BASE: ${{ vars.GROQ_API_BASE || 'https://api.groq.com/openai/v1' }}\n LLAMA_MODEL: ${{ vars.LLAMA_MODEL || 'Llama-4-Scout-17B-16E-Instruct-FP8' }}\n LLAMA_API_BASE: ${{ vars.LLAMA_API_BASE || 'https://api.llama.com/v1' }}\n DEEPSEEK_MODEL: ${{ vars.DEEPSEEK_MODEL || 'deepseek-chat' }}\n DEEPSEEK_API_BASE: ${{ vars.DEEPSEEK_API_BASE || 'https://api.deepseek.com' }}\n ADMIN_USER_ID: ${{ secrets.ADMIN_USER_ID }}\n CHATS_KK: ${{ vars.CHATS_KK }}\n CHATS_ZH: ${{ vars.CHATS_ZH }}\n CHATS_RU: ${{ vars.CHATS_RU }}\n CAPTCHA_TIMEOUT_SECONDS: ${{ vars.CAPTCHA_TIMEOUT_SECONDS || '60' }}\n KICK_BAN_DURATION_SECONDS: ${{ vars.KICK_BAN_DURATION_SECONDS || '31' }}\n VOTEBAN_THRESHOLD: ${{ vars.VOTEBAN_THRESHOLD || '7' }}\n VOTEBAN_FORGIVE_THRESHOLD: ${{ vars.VOTEBAN_FORGIVE_THRESHOLD || '7' }}\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: CDK Synth (Verify Compilation)\n working-directory: ./infra\n run: |\n uv run cdk synth -c env=dev\n\n - name: CDK Diff (Preview Changes)\n id: cdk-diff\n working-directory: ./infra\n run: |\n uv run cdk diff -c env=dev > /tmp/cdk-diff.txt 2>&1 || true\n\n echo \"## ๐ Infrastructure Changes Preview (Zerde Telegram Bot)\" > /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR will modify the following AWS resources:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n if ! grep -q \"Stack ZerdeTelegramBotStack-dev\" /tmp/cdk-diff.txt && ! grep -q \"There were no differences\" /tmp/cdk-diff.txt; then\n echo \"### โน๏ธ No infrastructure changes detected\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR only contains code changes (Lambda functions, etc.)\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n else\n echo \"### โ
Resources to be Created:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\+.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*+/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n echo \"### โ Resources to be Deleted:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\-.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*-/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n echo \"### โ ๏ธ Resources to be Modified:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*~.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*~/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n echo \"### ๐ง Property Changes:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*[+\\-~].*:\" /tmp/cdk-diff.txt | grep -v \"AWS::\" | head -30 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n fi\n\n echo \"\" >> /tmp/diff-report.md\n echo \"๐ Full CDK Diff Output
\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo '```diff' >> /tmp/diff-report.md\n cat /tmp/cdk-diff.txt >> /tmp/diff-report.md\n echo '```' >> /tmp/diff-report.md\n echo \" \" >> /tmp/diff-report.md\n\n cat /tmp/diff-report.md\n\n - name: Comment PR with Infrastructure Diff\n uses: actions/github-script@v7\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n script: |\n const fs = require('fs');\n const report = fs.readFileSync('/tmp/diff-report.md', 'utf8');\n\n const { data: comments } = await github.rest.issues.listComments({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n });\n\n const botComment = comments.find(comment =>\n comment.user.type === 'Bot' &&\n comment.body.includes('Infrastructure Changes Preview')\n );\n\n if (botComment) {\n await github.rest.issues.updateComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n comment_id: botComment.id,\n body: report\n });\n } else {\n await github.rest.issues.createComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n body: report\n });\n }\n"}, "8cefb0936bead74357960f11d0da536263a3189d": {"t": 1785762168.7512975, "n": 7841, "h": "fc514c75c7a3af84", "c": "name: PR Check\n\non:\n pull_request:\n branches:\n - main\n types: [opened, synchronize, reopened]\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n pull-requests: write # Allow bot to write diff results to PR comments\n\njobs:\n quality-check:\n name: Code Quality Checks\n runs-on: ubuntu-latest\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff preview\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Run pre-commit hooks\n run: |\n uv run pre-commit run --all-files\n\n - name: Run Unit Tests\n run: |\n uv run pytest tests/ -v\n\n infra-preview:\n needs: quality-check\n name: Infrastructure Changes Preview\n runs-on: ubuntu-latest\n if: github.event.pull_request.head.repo.full_name == github.repository\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: CDK Synth (Verify Compilation)\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n GEMINI_API_KEY: ${{ secrets.DEV_GEMINI_API_KEY }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER }}\n LLM_MODEL: ${{ vars.LLM_MODEL }}\n QUIZ_CHATS_KK: ${{ vars.QUIZ_CHATS_KK }}\n QUIZ_CHATS_ZH: ${{ vars.QUIZ_CHATS_ZH }}\n QUIZ_CHATS_RU: ${{ vars.QUIZ_CHATS_RU }}\n run: |\n uv run cdk synth -c env=dev\n\n - name: CDK Diff (Preview Changes)\n id: cdk-diff\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n GEMINI_API_KEY: ${{ secrets.DEV_GEMINI_API_KEY }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER }}\n LLM_MODEL: ${{ vars.LLM_MODEL }}\n QUIZ_CHATS_KK: ${{ vars.QUIZ_CHATS_KK }}\n QUIZ_CHATS_ZH: ${{ vars.QUIZ_CHATS_ZH }}\n QUIZ_CHATS_RU: ${{ vars.QUIZ_CHATS_RU }}\n run: |\n # Run cdk diff and capture output\n uv run cdk diff -c env=dev > /tmp/cdk-diff.txt 2>&1 || true\n\n # Parse diff and generate report\n echo \"## ๐ Infrastructure Changes Preview (Zerde Telegram Bot)\" > /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR will modify the following AWS resources:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Check if there are any changes\n if ! grep -q \"Stack ZerdeTelegramBotStack-dev\" /tmp/cdk-diff.txt && ! grep -q \"There were no differences\" /tmp/cdk-diff.txt; then\n echo \"### โน๏ธ No infrastructure changes detected\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR only contains code changes (Lambda functions, etc.)\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n else\n # Extract resources to be created (green +)\n echo \"### โ
Resources to be Created:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\+.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*+/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract resources to be deleted (red -)\n echo \"### โ Resources to be Deleted:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\-.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*-/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract resources to be modified (yellow ~)\n echo \"### โ ๏ธ Resources to be Modified:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*~.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*~/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract property changes\n echo \"### ๐ง Property Changes:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*[+\\-~].*:\" /tmp/cdk-diff.txt | grep -v \"AWS::\" | head -30 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n fi\n\n # Add full diff as collapsible section\n echo \"\" >> /tmp/diff-report.md\n echo \"๐ Full CDK Diff Output
\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo '```diff' >> /tmp/diff-report.md\n cat /tmp/cdk-diff.txt >> /tmp/diff-report.md\n echo '```' >> /tmp/diff-report.md\n echo \" \" >> /tmp/diff-report.md\n\n # Save report for next step\n cat /tmp/diff-report.md\n\n - name: Comment PR with Infrastructure Diff\n uses: actions/github-script@v7\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n script: |\n const fs = require('fs');\n const report = fs.readFileSync('/tmp/diff-report.md', 'utf8');\n\n // Find existing comment\n const { data: comments } = await github.rest.issues.listComments({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n });\n\n const botComment = comments.find(comment =>\n comment.user.type === 'Bot' &&\n comment.body.includes('Infrastructure Changes Preview')\n );\n\n if (botComment) {\n // Update existing comment\n await github.rest.issues.updateComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n comment_id: botComment.id,\n body: report\n });\n } else {\n // Create new comment\n await github.rest.issues.createComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n body: report\n });\n }\n"}, "15173cad5f72cc6bdb1a3f5fdafce474129bfbfc": {"t": 1785762173.2834506, "n": 7733, "h": "aa730f82bce19e76", "c": "name: PR Check\n\non:\n pull_request:\n branches:\n - main\n types: [opened, synchronize, reopened]\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n pull-requests: write # Allow bot to write diff results to PR comments\n\njobs:\n quality-check:\n name: Code Quality Checks\n runs-on: ubuntu-latest\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff preview\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Run pre-commit hooks\n run: |\n uv run pre-commit run --all-files\n\n - name: Run Unit Tests\n run: |\n uv run pytest tests/ -v\n\n infra-preview:\n needs: quality-check\n name: Infrastructure Changes Preview\n runs-on: ubuntu-latest\n if: github.event.pull_request.head.repo.full_name == github.repository\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: CDK Synth (Verify Compilation)\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n GEMINI_API_KEY: ${{ secrets.DEV_GEMINI_API_KEY }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER }}\n LLM_MODEL: ${{ vars.LLM_MODEL }}\n QUIZAPI_KEY: ${{ secrets.QUIZAPI_KEY }}\n QUIZ_CHATS: ${{ vars.DEV_QUIZ_CHATS }}\n run: |\n uv run cdk synth -c env=dev\n\n - name: CDK Diff (Preview Changes)\n id: cdk-diff\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n GEMINI_API_KEY: ${{ secrets.DEV_GEMINI_API_KEY }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER }}\n LLM_MODEL: ${{ vars.LLM_MODEL }}\n QUIZAPI_KEY: ${{ secrets.QUIZAPI_KEY }}\n QUIZ_CHATS: ${{ vars.DEV_QUIZ_CHATS }}\n run: |\n # Run cdk diff and capture output\n uv run cdk diff -c env=dev > /tmp/cdk-diff.txt 2>&1 || true\n\n # Parse diff and generate report\n echo \"## ๐ Infrastructure Changes Preview (Zerde Telegram Bot)\" > /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR will modify the following AWS resources:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Check if there are any changes\n if ! grep -q \"Stack ZerdeTelegramBotStack-dev\" /tmp/cdk-diff.txt && ! grep -q \"There were no differences\" /tmp/cdk-diff.txt; then\n echo \"### โน๏ธ No infrastructure changes detected\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR only contains code changes (Lambda functions, etc.)\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n else\n # Extract resources to be created (green +)\n echo \"### โ
Resources to be Created:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\+.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*+/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract resources to be deleted (red -)\n echo \"### โ Resources to be Deleted:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\-.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*-/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract resources to be modified (yellow ~)\n echo \"### โ ๏ธ Resources to be Modified:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*~.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*~/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract property changes\n echo \"### ๐ง Property Changes:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*[+\\-~].*:\" /tmp/cdk-diff.txt | grep -v \"AWS::\" | head -30 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n fi\n\n # Add full diff as collapsible section\n echo \"\" >> /tmp/diff-report.md\n echo \"๐ Full CDK Diff Output
\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo '```diff' >> /tmp/diff-report.md\n cat /tmp/cdk-diff.txt >> /tmp/diff-report.md\n echo '```' >> /tmp/diff-report.md\n echo \" \" >> /tmp/diff-report.md\n\n # Save report for next step\n cat /tmp/diff-report.md\n\n - name: Comment PR with Infrastructure Diff\n uses: actions/github-script@v7\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n script: |\n const fs = require('fs');\n const report = fs.readFileSync('/tmp/diff-report.md', 'utf8');\n\n // Find existing comment\n const { data: comments } = await github.rest.issues.listComments({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n });\n\n const botComment = comments.find(comment =>\n comment.user.type === 'Bot' &&\n comment.body.includes('Infrastructure Changes Preview')\n );\n\n if (botComment) {\n // Update existing comment\n await github.rest.issues.updateComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n comment_id: botComment.id,\n body: report\n });\n } else {\n // Create new comment\n await github.rest.issues.createComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n body: report\n });\n }\n"}, "c333f1811ab3ca5d0e79970c2ad8ba105bf6ce11": {"t": 1785762177.539737, "n": 7535, "h": "825d2a4ae30ed2f9", "c": "name: PR Check\n\non:\n pull_request:\n branches:\n - main\n types: [opened, synchronize, reopened]\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n pull-requests: write # Allow bot to write diff results to PR comments\n\njobs:\n quality-check:\n name: Code Quality Checks\n runs-on: ubuntu-latest\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff preview\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Run pre-commit hooks\n run: |\n uv run pre-commit run --all-files\n\n - name: Run Unit Tests\n run: |\n uv run pytest tests/ -v\n\n infra-preview:\n needs: quality-check\n name: Infrastructure Changes Preview\n runs-on: ubuntu-latest\n if: github.event.pull_request.head.repo.full_name == github.repository\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: CDK Synth (Verify Compilation)\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n GEMINI_API_KEY: ${{ secrets.DEV_GEMINI_API_KEY }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER }}\n LLM_MODEL: ${{ vars.LLM_MODEL }}\n run: |\n uv run cdk synth -c env=dev\n\n - name: CDK Diff (Preview Changes)\n id: cdk-diff\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n GEMINI_API_KEY: ${{ secrets.DEV_GEMINI_API_KEY }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER }}\n LLM_MODEL: ${{ vars.LLM_MODEL }}\n run: |\n # Run cdk diff and capture output\n uv run cdk diff -c env=dev > /tmp/cdk-diff.txt 2>&1 || true\n\n # Parse diff and generate report\n echo \"## ๐ Infrastructure Changes Preview (Zerde Telegram Bot)\" > /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR will modify the following AWS resources:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Check if there are any changes\n if ! grep -q \"Stack ZerdeTelegramBotStack-dev\" /tmp/cdk-diff.txt && ! grep -q \"There were no differences\" /tmp/cdk-diff.txt; then\n echo \"### โน๏ธ No infrastructure changes detected\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR only contains code changes (Lambda functions, etc.)\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n else\n # Extract resources to be created (green +)\n echo \"### โ
Resources to be Created:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\+.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*+/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract resources to be deleted (red -)\n echo \"### โ Resources to be Deleted:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\-.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*-/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract resources to be modified (yellow ~)\n echo \"### โ ๏ธ Resources to be Modified:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*~.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*~/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract property changes\n echo \"### ๐ง Property Changes:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*[+\\-~].*:\" /tmp/cdk-diff.txt | grep -v \"AWS::\" | head -30 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n fi\n\n # Add full diff as collapsible section\n echo \"\" >> /tmp/diff-report.md\n echo \"๐ Full CDK Diff Output
\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo '```diff' >> /tmp/diff-report.md\n cat /tmp/cdk-diff.txt >> /tmp/diff-report.md\n echo '```' >> /tmp/diff-report.md\n echo \" \" >> /tmp/diff-report.md\n\n # Save report for next step\n cat /tmp/diff-report.md\n\n - name: Comment PR with Infrastructure Diff\n uses: actions/github-script@v7\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n script: |\n const fs = require('fs');\n const report = fs.readFileSync('/tmp/diff-report.md', 'utf8');\n\n // Find existing comment\n const { data: comments } = await github.rest.issues.listComments({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n });\n\n const botComment = comments.find(comment =>\n comment.user.type === 'Bot' &&\n comment.body.includes('Infrastructure Changes Preview')\n );\n\n if (botComment) {\n // Update existing comment\n await github.rest.issues.updateComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n comment_id: botComment.id,\n body: report\n });\n } else {\n // Create new comment\n await github.rest.issues.createComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n body: report\n });\n }\n"}, "0eef8c261ddc38e968237ba55d610d96fd28007e": {"t": 1785762179.3593771, "n": 7632, "h": "dc6fa675fe067d84", "c": "name: PR Check\n\non:\n pull_request:\n branches:\n - main\n types: [opened, synchronize, reopened]\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n pull-requests: write # Allow bot to write diff results to PR comments\n\njobs:\n quality-check:\n name: Code Quality Checks\n runs-on: ubuntu-latest\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff preview\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Run pre-commit hooks\n run: |\n uv run pre-commit run --all-files\n\n # - name: Run Unit Tests\n # run: |\n # Run tests (when tests are added)\n # uv run pytest\n # echo \"Tests will run here when implemented\"\n\n infra-preview:\n needs: quality-check\n name: Infrastructure Changes Preview\n runs-on: ubuntu-latest\n if: github.event.pull_request.head.repo.full_name == github.repository\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen --no-dev\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: CDK Synth (Verify Compilation)\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n GEMINI_API_KEY: ${{ secrets.DEV_GEMINI_API_KEY }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER }}\n LLM_MODEL: ${{ vars.LLM_MODEL }}\n run: |\n uv run cdk synth -c env=dev\n\n - name: CDK Diff (Preview Changes)\n id: cdk-diff\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n GEMINI_API_KEY: ${{ secrets.DEV_GEMINI_API_KEY }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER }}\n LLM_MODEL: ${{ vars.LLM_MODEL }}\n run: |\n # Run cdk diff and capture output\n uv run cdk diff -c env=dev > /tmp/cdk-diff.txt 2>&1 || true\n\n # Parse diff and generate report\n echo \"## ๐ Infrastructure Changes Preview (Zerde Telegram Bot)\" > /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR will modify the following AWS resources:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Check if there are any changes\n if ! grep -q \"Stack ZerdeTelegramBotStack-dev\" /tmp/cdk-diff.txt && ! grep -q \"There were no differences\" /tmp/cdk-diff.txt; then\n echo \"### โน๏ธ No infrastructure changes detected\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR only contains code changes (Lambda functions, etc.)\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n else\n # Extract resources to be created (green +)\n echo \"### โ
Resources to be Created:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\+.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*+/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract resources to be deleted (red -)\n echo \"### โ Resources to be Deleted:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\-.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*-/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract resources to be modified (yellow ~)\n echo \"### โ ๏ธ Resources to be Modified:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*~.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*~/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract property changes\n echo \"### ๐ง Property Changes:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*[+\\-~].*:\" /tmp/cdk-diff.txt | grep -v \"AWS::\" | head -30 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n fi\n\n # Add full diff as collapsible section\n echo \"\" >> /tmp/diff-report.md\n echo \"๐ Full CDK Diff Output
\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo '```diff' >> /tmp/diff-report.md\n cat /tmp/cdk-diff.txt >> /tmp/diff-report.md\n echo '```' >> /tmp/diff-report.md\n echo \" \" >> /tmp/diff-report.md\n\n # Save report for next step\n cat /tmp/diff-report.md\n\n - name: Comment PR with Infrastructure Diff\n uses: actions/github-script@v7\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n script: |\n const fs = require('fs');\n const report = fs.readFileSync('/tmp/diff-report.md', 'utf8');\n\n // Find existing comment\n const { data: comments } = await github.rest.issues.listComments({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n });\n\n const botComment = comments.find(comment =>\n comment.user.type === 'Bot' &&\n comment.body.includes('Infrastructure Changes Preview')\n );\n\n if (botComment) {\n // Update existing comment\n await github.rest.issues.updateComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n comment_id: botComment.id,\n body: report\n });\n } else {\n // Create new comment\n await github.rest.issues.createComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n body: report\n });\n }\n"}, "2dd04c7335e3ab605bf560817c5252867c5ab837": {"t": 1785762181.7100432, "n": 7623, "h": "86aafafa030b2006", "c": "name: PR Check\n\non:\n pull_request:\n branches:\n - main\n types: [opened, synchronize, reopened]\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n pull-requests: write # Allow bot to write diff results to PR comments\n\njobs:\n quality-check:\n name: Code Quality Checks\n runs-on: ubuntu-latest\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff preview\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Run pre-commit hooks\n run: |\n uv run pre-commit run --all-files\n\n # - name: Run Unit Tests\n # run: |\n # Run tests (when tests are added)\n # uv run pytest\n # echo \"Tests will run here when implemented\"\n\n infra-preview:\n needs: quality-check\n name: Infrastructure Changes Preview\n runs-on: ubuntu-latest\n if: github.event.pull_request.head.repo.full_name == github.repository\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: CDK Synth (Verify Compilation)\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n GEMINI_API_KEY: ${{ secrets.DEV_GEMINI_API_KEY }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER }}\n LLM_MODEL: ${{ vars.LLM_MODEL }}\n run: |\n uv run cdk synth -c env=dev\n\n - name: CDK Diff (Preview Changes)\n id: cdk-diff\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n GEMINI_API_KEY: ${{ secrets.DEV_GEMINI_API_KEY }}\n NEWS_CHATS_KK: ${{ vars.NEWS_CHATS_KK }}\n NEWS_CHATS_ZH: ${{ vars.NEWS_CHATS_ZH }}\n NEWS_CHATS_RU: ${{ vars.NEWS_CHATS_RU }}\n AI_PROVIDER: ${{ vars.AI_PROVIDER }}\n LLM_MODEL: ${{ vars.LLM_MODEL }}\n run: |\n # Run cdk diff and capture output\n uv run cdk diff -c env=dev > /tmp/cdk-diff.txt 2>&1 || true\n\n # Parse diff and generate report\n echo \"## ๐ Infrastructure Changes Preview (Zerde Telegram Bot)\" > /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR will modify the following AWS resources:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Check if there are any changes\n if ! grep -q \"Stack ZerdeTelegramBotStack-dev\" /tmp/cdk-diff.txt && ! grep -q \"There were no differences\" /tmp/cdk-diff.txt; then\n echo \"### โน๏ธ No infrastructure changes detected\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR only contains code changes (Lambda functions, etc.)\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n else\n # Extract resources to be created (green +)\n echo \"### โ
Resources to be Created:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\+.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*+/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract resources to be deleted (red -)\n echo \"### โ Resources to be Deleted:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\-.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*-/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract resources to be modified (yellow ~)\n echo \"### โ ๏ธ Resources to be Modified:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*~.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*~/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract property changes\n echo \"### ๐ง Property Changes:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*[+\\-~].*:\" /tmp/cdk-diff.txt | grep -v \"AWS::\" | head -30 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n fi\n\n # Add full diff as collapsible section\n echo \"\" >> /tmp/diff-report.md\n echo \"๐ Full CDK Diff Output
\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo '```diff' >> /tmp/diff-report.md\n cat /tmp/cdk-diff.txt >> /tmp/diff-report.md\n echo '```' >> /tmp/diff-report.md\n echo \" \" >> /tmp/diff-report.md\n\n # Save report for next step\n cat /tmp/diff-report.md\n\n - name: Comment PR with Infrastructure Diff\n uses: actions/github-script@v7\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n script: |\n const fs = require('fs');\n const report = fs.readFileSync('/tmp/diff-report.md', 'utf8');\n\n // Find existing comment\n const { data: comments } = await github.rest.issues.listComments({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n });\n\n const botComment = comments.find(comment =>\n comment.user.type === 'Bot' &&\n comment.body.includes('Infrastructure Changes Preview')\n );\n\n if (botComment) {\n // Update existing comment\n await github.rest.issues.updateComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n comment_id: botComment.id,\n body: report\n });\n } else {\n // Create new comment\n await github.rest.issues.createComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n body: report\n });\n }\n"}, "db36311c3938430e293b92f17c14633d4e2856a9": {"t": 1785762207.2512474, "n": 7313, "h": "957ffd9b26952fa2", "c": "name: PR Check\n\non:\n pull_request:\n branches:\n - main\n types: [opened, synchronize, reopened]\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n pull-requests: write # Allow bot to write diff results to PR comments\n\njobs:\n quality-check:\n name: Code Quality Checks\n runs-on: ubuntu-latest\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff preview\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Run pre-commit hooks\n run: |\n uv run pre-commit run --all-files\n\n # - name: Run Unit Tests\n # run: |\n # Run tests (when tests are added)\n # uv run pytest\n # echo \"Tests will run here when implemented\"\n\n infra-preview:\n needs: quality-check\n name: Infrastructure Changes Preview\n runs-on: ubuntu-latest\n if: github.event.pull_request.head.repo.full_name == github.repository\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: CDK Synth (Verify Compilation)\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n NEWS_CHAT_IDS: ${{ secrets.DEV_NEWS_CHAT_IDS }}\n AI_PROVIDER: gemini\n GEMINI_API_KEY: ${{ secrets.DEV_GEMINI_API_KEY }}\n run: |\n uv run cdk synth -c env=dev\n\n - name: CDK Diff (Preview Changes)\n id: cdk-diff\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n NEWS_CHAT_IDS: ${{ secrets.DEV_NEWS_CHAT_IDS }}\n AI_PROVIDER: gemini\n GEMINI_API_KEY: ${{ secrets.DEV_GEMINI_API_KEY }}\n run: |\n # Run cdk diff and capture output\n uv run cdk diff -c env=dev > /tmp/cdk-diff.txt 2>&1 || true\n\n # Parse diff and generate report\n echo \"## ๐ Infrastructure Changes Preview (Zerde Telegram Bot)\" > /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR will modify the following AWS resources:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Check if there are any changes\n if ! grep -q \"Stack ZerdeTelegramBotStack-dev\" /tmp/cdk-diff.txt && ! grep -q \"There were no differences\" /tmp/cdk-diff.txt; then\n echo \"### โน๏ธ No infrastructure changes detected\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR only contains code changes (Lambda functions, etc.)\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n else\n # Extract resources to be created (green +)\n echo \"### โ
Resources to be Created:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\+.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*+/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract resources to be deleted (red -)\n echo \"### โ Resources to be Deleted:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\-.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*-/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract resources to be modified (yellow ~)\n echo \"### โ ๏ธ Resources to be Modified:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*~.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*~/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract property changes\n echo \"### ๐ง Property Changes:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*[+\\-~].*:\" /tmp/cdk-diff.txt | grep -v \"AWS::\" | head -30 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n fi\n\n # Add full diff as collapsible section\n echo \"\" >> /tmp/diff-report.md\n echo \"๐ Full CDK Diff Output
\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo '```diff' >> /tmp/diff-report.md\n cat /tmp/cdk-diff.txt >> /tmp/diff-report.md\n echo '```' >> /tmp/diff-report.md\n echo \" \" >> /tmp/diff-report.md\n\n # Save report for next step\n cat /tmp/diff-report.md\n\n - name: Comment PR with Infrastructure Diff\n uses: actions/github-script@v7\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n script: |\n const fs = require('fs');\n const report = fs.readFileSync('/tmp/diff-report.md', 'utf8');\n\n // Find existing comment\n const { data: comments } = await github.rest.issues.listComments({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n });\n\n const botComment = comments.find(comment =>\n comment.user.type === 'Bot' &&\n comment.body.includes('Infrastructure Changes Preview')\n );\n\n if (botComment) {\n // Update existing comment\n await github.rest.issues.updateComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n comment_id: botComment.id,\n body: report\n });\n } else {\n // Create new comment\n await github.rest.issues.createComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n body: report\n });\n }\n"}, "18b4ae36fcd36a8127118bd9dea193ae13ae4096": {"t": 1785762209.7415247, "n": 7301, "h": "c76cf462096df4bc", "c": "name: PR Check\n\non:\n pull_request:\n branches:\n - main\n types: [opened, synchronize, reopened]\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n pull-requests: write # Allow bot to write diff results to PR comments\n\njobs:\n quality-check:\n name: Code Quality Checks\n runs-on: ubuntu-latest\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff preview\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Run pre-commit hooks\n run: |\n uv run pre-commit run --all-files\n\n # - name: Run Unit Tests\n # run: |\n # Run tests (when tests are added)\n # uv run pytest\n # echo \"Tests will run here when implemented\"\n\n infra-preview:\n needs: quality-check\n name: Infrastructure Changes Preview\n runs-on: ubuntu-latest\n if: github.event.pull_request.head.repo.full_name == github.repository\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: CDK Synth (Verify Compilation)\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n NEWS_CHAT_IDS: ${{ secrets.DEV_NEWS_CHAT_IDS }}\n AI_PROVIDER: groq\n GROQ_API_KEY: ${{ secrets.DEV_GROQ_API_KEY }}\n run: |\n uv run cdk synth -c env=dev\n\n - name: CDK Diff (Preview Changes)\n id: cdk-diff\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n NEWS_CHAT_IDS: ${{ secrets.DEV_NEWS_CHAT_IDS }}\n AI_PROVIDER: groq\n GROQ_API_KEY: ${{ secrets.DEV_GROQ_API_KEY }}\n run: |\n # Run cdk diff and capture output\n uv run cdk diff -c env=dev > /tmp/cdk-diff.txt 2>&1 || true\n\n # Parse diff and generate report\n echo \"## ๐ Infrastructure Changes Preview (Zerde Telegram Bot)\" > /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR will modify the following AWS resources:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Check if there are any changes\n if ! grep -q \"Stack ZerdeTelegramBotStack-dev\" /tmp/cdk-diff.txt && ! grep -q \"There were no differences\" /tmp/cdk-diff.txt; then\n echo \"### โน๏ธ No infrastructure changes detected\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR only contains code changes (Lambda functions, etc.)\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n else\n # Extract resources to be created (green +)\n echo \"### โ
Resources to be Created:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\+.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*+/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract resources to be deleted (red -)\n echo \"### โ Resources to be Deleted:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\-.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*-/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract resources to be modified (yellow ~)\n echo \"### โ ๏ธ Resources to be Modified:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*~.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*~/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract property changes\n echo \"### ๐ง Property Changes:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*[+\\-~].*:\" /tmp/cdk-diff.txt | grep -v \"AWS::\" | head -30 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n fi\n\n # Add full diff as collapsible section\n echo \"\" >> /tmp/diff-report.md\n echo \"๐ Full CDK Diff Output
\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo '```diff' >> /tmp/diff-report.md\n cat /tmp/cdk-diff.txt >> /tmp/diff-report.md\n echo '```' >> /tmp/diff-report.md\n echo \" \" >> /tmp/diff-report.md\n\n # Save report for next step\n cat /tmp/diff-report.md\n\n - name: Comment PR with Infrastructure Diff\n uses: actions/github-script@v7\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n script: |\n const fs = require('fs');\n const report = fs.readFileSync('/tmp/diff-report.md', 'utf8');\n\n // Find existing comment\n const { data: comments } = await github.rest.issues.listComments({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n });\n\n const botComment = comments.find(comment =>\n comment.user.type === 'Bot' &&\n comment.body.includes('Infrastructure Changes Preview')\n );\n\n if (botComment) {\n // Update existing comment\n await github.rest.issues.updateComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n comment_id: botComment.id,\n body: report\n });\n } else {\n // Create new comment\n await github.rest.issues.createComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n body: report\n });\n }\n"}, "d590e63e63a5b6839b698a918d05875de6ae088b": {"t": 1785762211.8116736, "n": 7017, "h": "27cb3a4fc700dc2d", "c": "name: PR Check\n\non:\n pull_request:\n branches:\n - main\n types: [opened, synchronize, reopened]\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n pull-requests: write # Allow bot to write diff results to PR comments\n\njobs:\n quality-check:\n name: Code Quality Checks\n runs-on: ubuntu-latest\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff preview\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Run pre-commit hooks\n run: |\n uv run pre-commit run --all-files\n\n # - name: Run Unit Tests\n # run: |\n # Run tests (when tests are added)\n # uv run pytest\n # echo \"Tests will run here when implemented\"\n\n infra-preview:\n needs: quality-check\n name: Infrastructure Changes Preview\n runs-on: ubuntu-latest\n if: github.event.pull_request.head.repo.full_name == github.repository\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: CDK Synth (Verify Compilation)\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n run: |\n uv run cdk synth -c env=dev\n\n - name: CDK Diff (Preview Changes)\n id: cdk-diff\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n run: |\n # Run cdk diff and capture output\n uv run cdk diff -c env=dev > /tmp/cdk-diff.txt 2>&1 || true\n\n # Parse diff and generate report\n echo \"## ๐ Infrastructure Changes Preview (Zerde Telegram Bot)\" > /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR will modify the following AWS resources:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Check if there are any changes\n if ! grep -q \"Stack ZerdeTelegramBotStack-dev\" /tmp/cdk-diff.txt && ! grep -q \"There were no differences\" /tmp/cdk-diff.txt; then\n echo \"### โน๏ธ No infrastructure changes detected\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR only contains code changes (Lambda functions, etc.)\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n else\n # Extract resources to be created (green +)\n echo \"### โ
Resources to be Created:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\+.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*+/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract resources to be deleted (red -)\n echo \"### โ Resources to be Deleted:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\-.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*-/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract resources to be modified (yellow ~)\n echo \"### โ ๏ธ Resources to be Modified:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*~.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*~/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract property changes\n echo \"### ๐ง Property Changes:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*[+\\-~].*:\" /tmp/cdk-diff.txt | grep -v \"AWS::\" | head -30 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n fi\n\n # Add full diff as collapsible section\n echo \"\" >> /tmp/diff-report.md\n echo \"๐ Full CDK Diff Output
\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo '```diff' >> /tmp/diff-report.md\n cat /tmp/cdk-diff.txt >> /tmp/diff-report.md\n echo '```' >> /tmp/diff-report.md\n echo \" \" >> /tmp/diff-report.md\n\n # Save report for next step\n cat /tmp/diff-report.md\n\n - name: Comment PR with Infrastructure Diff\n uses: actions/github-script@v7\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n script: |\n const fs = require('fs');\n const report = fs.readFileSync('/tmp/diff-report.md', 'utf8');\n\n // Find existing comment\n const { data: comments } = await github.rest.issues.listComments({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n });\n\n const botComment = comments.find(comment =>\n comment.user.type === 'Bot' &&\n comment.body.includes('Infrastructure Changes Preview')\n );\n\n if (botComment) {\n // Update existing comment\n await github.rest.issues.updateComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n comment_id: botComment.id,\n body: report\n });\n } else {\n // Create new comment\n await github.rest.issues.createComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n body: report\n });\n }\n"}, "5d5bde3707bc97d44e9e838bfd826743107f5d54": {"t": 1785762214.140925, "n": 6942, "h": "4aaa159876cb94d9", "c": "name: PR Check\n\non:\n pull_request:\n branches:\n - main\n types: [opened, synchronize, reopened]\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n pull-requests: write # Allow bot to write diff results to PR comments\n\njobs:\n quality-check:\n name: Code Quality Checks\n runs-on: ubuntu-latest\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff preview\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Run pre-commit hooks\n run: |\n uv run pre-commit run --all-files\n\n # - name: Run Unit Tests\n # run: |\n # Run tests (when tests are added)\n # uv run pytest\n # echo \"Tests will run here when implemented\"\n\n infra-preview:\n needs: quality-check\n name: Infrastructure Changes Preview\n runs-on: ubuntu-latest\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: CDK Synth (Verify Compilation)\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n run: |\n uv run cdk synth -c env=dev\n\n - name: CDK Diff (Preview Changes)\n id: cdk-diff\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n run: |\n # Run cdk diff and capture output\n uv run cdk diff -c env=dev > /tmp/cdk-diff.txt 2>&1 || true\n\n # Parse diff and generate report\n echo \"## ๐ Infrastructure Changes Preview (Zerde Telegram Bot)\" > /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR will modify the following AWS resources:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Check if there are any changes\n if ! grep -q \"Stack ZerdeTelegramBotStack-dev\" /tmp/cdk-diff.txt && ! grep -q \"There were no differences\" /tmp/cdk-diff.txt; then\n echo \"### โน๏ธ No infrastructure changes detected\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR only contains code changes (Lambda functions, etc.)\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n else\n # Extract resources to be created (green +)\n echo \"### โ
Resources to be Created:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\+.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*+/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract resources to be deleted (red -)\n echo \"### โ Resources to be Deleted:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\-.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*-/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract resources to be modified (yellow ~)\n echo \"### โ ๏ธ Resources to be Modified:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*~.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*~/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract property changes\n echo \"### ๐ง Property Changes:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*[+\\-~].*:\" /tmp/cdk-diff.txt | grep -v \"AWS::\" | head -30 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n fi\n\n # Add full diff as collapsible section\n echo \"\" >> /tmp/diff-report.md\n echo \"๐ Full CDK Diff Output
\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo '```diff' >> /tmp/diff-report.md\n cat /tmp/cdk-diff.txt >> /tmp/diff-report.md\n echo '```' >> /tmp/diff-report.md\n echo \" \" >> /tmp/diff-report.md\n\n # Save report for next step\n cat /tmp/diff-report.md\n\n - name: Comment PR with Infrastructure Diff\n uses: actions/github-script@v7\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n script: |\n const fs = require('fs');\n const report = fs.readFileSync('/tmp/diff-report.md', 'utf8');\n\n // Find existing comment\n const { data: comments } = await github.rest.issues.listComments({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n });\n\n const botComment = comments.find(comment =>\n comment.user.type === 'Bot' &&\n comment.body.includes('Infrastructure Changes Preview')\n );\n\n if (botComment) {\n // Update existing comment\n await github.rest.issues.updateComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n comment_id: botComment.id,\n body: report\n });\n } else {\n // Create new comment\n await github.rest.issues.createComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n body: report\n });\n }\n"}, "f2e74a5ea5a501add4f2e327c543349350150671": {"t": 1785762216.8247461, "n": 6944, "h": "722f31022f92f8e4", "c": "name: PR Check\n\non:\n pull_request:\n branches:\n - main\n types: [opened, synchronize, reopened]\n\npermissions:\n id-token: write # OIDC authentication required\n contents: read\n pull-requests: write # Allow robot to write diff results to PR comments\n\njobs:\n quality-check:\n name: Code Quality Checks\n runs-on: ubuntu-latest\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff preview\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Run pre-commit hooks\n run: |\n uv run pre-commit run --all-files\n\n # - name: Run Unit Tests\n # run: |\n # Run tests (when tests are added)\n # uv run pytest\n # echo \"Tests will run here when implemented\"\n\n infra-preview:\n needs: quality-check\n name: Infrastructure Changes Preview\n runs-on: ubuntu-latest\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n enable-cache: true\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: CDK Synth (Verify Compilation)\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n run: |\n uv run cdk synth -c env=dev\n\n - name: CDK Diff (Preview Changes)\n id: cdk-diff\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n run: |\n # Run cdk diff and capture output\n uv run cdk diff -c env=dev > /tmp/cdk-diff.txt 2>&1 || true\n\n # Parse diff and generate report\n echo \"## ๐ Infrastructure Changes Preview (Zerde Telegram Bot)\" > /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR will modify the following AWS resources:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Check if there are any changes\n if ! grep -q \"Stack ZerdeTelegramBotStack-dev\" /tmp/cdk-diff.txt && ! grep -q \"There were no differences\" /tmp/cdk-diff.txt; then\n echo \"### โน๏ธ No infrastructure changes detected\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR only contains code changes (Lambda functions, etc.)\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n else\n # Extract resources to be created (green +)\n echo \"### โ
Resources to be Created:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\+.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*+/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract resources to be deleted (red -)\n echo \"### โ Resources to be Deleted:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\-.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*-/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract resources to be modified (yellow ~)\n echo \"### โ ๏ธ Resources to be Modified:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*~.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*~/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract property changes\n echo \"### ๐ง Property Changes:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*[+\\-~].*:\" /tmp/cdk-diff.txt | grep -v \"AWS::\" | head -30 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n fi\n\n # Add full diff as collapsible section\n echo \"\" >> /tmp/diff-report.md\n echo \"๐ Full CDK Diff Output
\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo '```diff' >> /tmp/diff-report.md\n cat /tmp/cdk-diff.txt >> /tmp/diff-report.md\n echo '```' >> /tmp/diff-report.md\n echo \" \" >> /tmp/diff-report.md\n\n # Save report for next step\n cat /tmp/diff-report.md\n\n - name: Comment PR with Infrastructure Diff\n uses: actions/github-script@v7\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n script: |\n const fs = require('fs');\n const report = fs.readFileSync('/tmp/diff-report.md', 'utf8');\n\n // Find existing comment\n const { data: comments } = await github.rest.issues.listComments({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n });\n\n const botComment = comments.find(comment =>\n comment.user.type === 'Bot' &&\n comment.body.includes('Infrastructure Changes Preview')\n );\n\n if (botComment) {\n // Update existing comment\n await github.rest.issues.updateComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n comment_id: botComment.id,\n body: report\n });\n } else {\n // Create new comment\n await github.rest.issues.createComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n body: report\n });\n }\n"}, "ce3bf0b164aab5027b3d1250d7ad8606042dbc4b": {"t": 1785762218.58532, "n": 6852, "h": "e01021c21f27d20e", "c": "name: PR Check\n\non:\n pull_request:\n branches:\n - main\n types: [opened, synchronize, reopened]\n\npermissions:\n id-token: write # ็จไบ AWS OIDC ่ฎค่ฏ (ๆจ่)\n contents: read\n pull-requests: write # ๅ
่ฎธๆบๅจไบบๆ diff ็ปๆๅๅฐ PR ่ฏ่ฎบ้\n\njobs:\n quality-check:\n name: Code Quality Checks\n runs-on: ubuntu-latest\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Run pre-commit hooks\n run: |\n uv run pre-commit run --all-files\n\n # - name: Run Unit Tests\n # run: |\n # Run tests (when tests are added)\n # uv run pytest\n # echo \"Tests will run here when implemented\"\n\n infra-preview:\n needs: quality-check\n name: Infrastructure Changes Preview\n runs-on: ubuntu-latest\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v4\n with:\n fetch-depth: 0 # Fetch full history for better diff\n\n - name: Set up Python 3.13\n uses: actions/setup-python@v5\n with:\n python-version: \"3.13\"\n\n - name: Install uv\n uses: astral-sh/setup-uv@v5\n with:\n version: \"latest\"\n\n - name: Install AWS CDK CLI\n run: |\n npm install -g aws-cdk\n\n - name: Install project dependencies with uv\n run: |\n uv sync --frozen\n\n - name: Configure AWS credentials (OIDC)\n uses: aws-actions/configure-aws-credentials@v4\n with:\n role-to-assume: ${{ secrets.AWS_ROLE_ARN }}\n aws-region: eu-central-1\n\n - name: CDK Synth (Verify Compilation)\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n run: |\n uv run cdk synth -c env=dev\n\n - name: CDK Diff (Preview Changes)\n id: cdk-diff\n working-directory: ./infra\n env:\n TELEGRAM_BOT_TOKEN: ${{ secrets.DEV_TELEGRAM_BOT_TOKEN }}\n TELEGRAM_WEBHOOK_SECRET_TOKEN: ${{ secrets.DEV_TELEGRAM_WEBHOOK_SECRET_TOKEN }}\n run: |\n # Run cdk diff and capture output\n uv run cdk diff -c env=dev > /tmp/cdk-diff.txt 2>&1 || true\n\n # Parse diff and generate report\n echo \"## ๐ Infrastructure Changes Preview (Serverless Telegram Bot Starter)\" > /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR will modify the following AWS resources:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Check if there are any changes\n if ! grep -q \"Stack TelegramBotStack-dev\" /tmp/cdk-diff.txt && ! grep -q \"There were no differences\" /tmp/cdk-diff.txt; then\n echo \"### โน๏ธ No infrastructure changes detected\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo \"This PR only contains code changes (Lambda functions, etc.)\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n else\n # Extract resources to be created (green +)\n echo \"### โ
Resources to be Created:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\+.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*+/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract resources to be deleted (red -)\n echo \"### โ Resources to be Deleted:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*\\-.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*-/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract resources to be modified (yellow ~)\n echo \"### โ ๏ธ Resources to be Modified:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*~.*AWS::\" /tmp/cdk-diff.txt | sed 's/^[[:space:]]*~/ - /' | sed 's/AWS::/`AWS::/' | sed 's/$/`/' | head -20 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n\n # Extract property changes\n echo \"### ๐ง Property Changes:\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n grep -E \"^\\s*[+\\-~].*:\" /tmp/cdk-diff.txt | grep -v \"AWS::\" | head -30 >> /tmp/diff-report.md || echo \" - None\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n fi\n\n # Add full diff as collapsible section\n echo \"\" >> /tmp/diff-report.md\n echo \"๐ Full CDK Diff Output
\" >> /tmp/diff-report.md\n echo \"\" >> /tmp/diff-report.md\n echo '```diff' >> /tmp/diff-report.md\n cat /tmp/cdk-diff.txt >> /tmp/diff-report.md\n echo '```' >> /tmp/diff-report.md\n echo \" \" >> /tmp/diff-report.md\n\n # Save report for next step\n cat /tmp/diff-report.md\n\n - name: Comment PR with Infrastructure Diff\n uses: actions/github-script@v7\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n script: |\n const fs = require('fs');\n const report = fs.readFileSync('/tmp/diff-report.md', 'utf8');\n\n // Find existing comment\n const { data: comments } = await github.rest.issues.listComments({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n });\n\n const botComment = comments.find(comment =>\n comment.user.type === 'Bot' &&\n comment.body.includes('Infrastructure Changes Preview')\n );\n\n if (botComment) {\n // Update existing comment\n await github.rest.issues.updateComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n comment_id: botComment.id,\n body: report\n });\n } else {\n // Create new comment\n await github.rest.issues.createComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: context.issue.number,\n body: report\n });\n }\n"}}}}