Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/bayashat_zerde-serverless-bot.json

1 line
300 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"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 \"<details>\" >> /tmp/diff-report.md\n echo \"<summary>📋 Full CDK Diff Output</summary>\" >> /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 \"</details>\" >> /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 \"<details>\" >> /tmp/diff-report.md\n echo \"<summary>📋 Full CDK Diff Output</summary>\" >> /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 \"</details>\" >> /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 \"<details>\" >> /tmp/diff-report.md\n echo \"<summary>📋 Full CDK Diff Output</summary>\" >> /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 \"</details>\" >> /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 \"<details>\" >> /tmp/diff-report.md\n echo \"<summary>📋 Full CDK Diff Output</summary>\" >> /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 \"</details>\" >> /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 \"<details>\" >> /tmp/diff-report.md\n echo \"<summary>📋 Full CDK Diff Output</summary>\" >> /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 \"</details>\" >> /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 \"<details>\" >> /tmp/diff-report.md\n echo \"<summary>📋 Full CDK Diff Output</summary>\" >> /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 \"</details>\" >> /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 \"<details>\" >> /tmp/diff-report.md\n echo \"<summary>📋 Full CDK Diff Output</summary>\" >> /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 \"</details>\" >> /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 \"<details>\" >> /tmp/diff-report.md\n echo \"<summary>📋 Full CDK Diff Output</summary>\" >> /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 \"</details>\" >> /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 \"<details>\" >> /tmp/diff-report.md\n echo \"<summary>📋 Full CDK Diff Output</summary>\" >> /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 \"</details>\" >> /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 \"<details>\" >> /tmp/diff-report.md\n echo \"<summary>📋 Full CDK Diff Output</summary>\" >> /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 \"</details>\" >> /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 \"<details>\" >> /tmp/diff-report.md\n echo \"<summary>📋 Full CDK Diff Output</summary>\" >> /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 \"</details>\" >> /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 \"<details>\" >> /tmp/diff-report.md\n echo \"<summary>📋 Full CDK Diff Output</summary>\" >> /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 \"</details>\" >> /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 \"<details>\" >> /tmp/diff-report.md\n echo \"<summary>📋 Full CDK Diff Output</summary>\" >> /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 \"</details>\" >> /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 \"<details>\" >> /tmp/diff-report.md\n echo \"<summary>📋 Full CDK Diff Output</summary>\" >> /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 \"</details>\" >> /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 \"<details>\" >> /tmp/diff-report.md\n echo \"<summary>📋 Full CDK Diff Output</summary>\" >> /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 \"</details>\" >> /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 \"<details>\" >> /tmp/diff-report.md\n echo \"<summary>📋 Full CDK Diff Output</summary>\" >> /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 \"</details>\" >> /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 \"<details>\" >> /tmp/diff-report.md\n echo \"<summary>📋 Full CDK Diff Output</summary>\" >> /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 \"</details>\" >> /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 \"<details>\" >> /tmp/diff-report.md\n echo \"<summary>📋 Full CDK Diff Output</summary>\" >> /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 \"</details>\" >> /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 \"<details>\" >> /tmp/diff-report.md\n echo \"<summary>📋 Full CDK Diff Output</summary>\" >> /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 \"</details>\" >> /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"}}}}