Skip to content

VoucherBot v1.0.4

Choose a tag to compare

@Devathmaj Devathmaj released this 14 Aug 07:28
· 27 commits to main since this release
f2cee16

v1.0.4 — Reliability, Test Coverage & New Source

Patch release: transactional (idempotency-safe) email delivery for voucher alerts, a large offline unit-test suite, scheduling/readiness hardening, dependency cleanup, and a new community-wiki source for AWS voucher discounts.


What changed since v1.0.3

Three pull requests landed since v1.0.3:


New Features

  • AWSCertifications wiki vouchers source (PR #14) — the r/AWSCertifications community wiki's Vouchers & Discounts page is now ingested as a WEBSITE source. The page is a single MkDocs document (no per-card wrappers), so it is parsed as one post per crawl (article.md-content__inner / h1 / link_selector=self) to preserve all promo codes, links, tables, and notes. Added a VENDOR_MAPPINGS URL-pattern entry so posts from this source are tagged with the canonical aws vendor.
  • Community wiki are enabled by default — no schema migration required (config-driven catalog).

Reliability

  • Transactional outbox for voucher email delivery (PR #12) — notification delivery intent is persisted to a new notification_outbox table in the same transaction as the pipeline run, so delivery state survives commit failures and is retried until delivered. Every send carries a stable idempotency key (voucher:{post_id}:{content_hash}) passed to Resend as the Idempotency-Key header, so replaying a pending row can never deliver a duplicate email. A successful send marks the row SENT and sets posts.is_notified in one commit; the scheduler sweeps remaining PENDING rows every 60s and marks them FAILED after 5 attempts. (New migration: k2l3m4n5o6p7_add_notification_outbox.)
  • Clamped poll_interval_minutes (PR #12) — config intervals are clamped to [1, 43200] minutes, preventing scheduler busy-loops (0/negative) and timedelta overflow (huge values).
  • Process boot time set at application startup (PR #12) — PROCESS_BOOT_AT was captured at module import (stale under uvicorn --preload); it is now set in the app lifespan so lease-staleness checks reflect the real process start.
  • DB-backed readiness check (PR #12) — /health now executes SELECT count(*) FROM sources via the session dependency instead of returning a static "ok", so it reports unhealthy when critical tables are missing.
  • Collector error-propagation fixes (PR #12) — broad except Exception → return [] was replaced with specific httpx handling across website/pearsonvue/rss/training-provider collectors. Auth-blocked (401/403) and transient errors return []; unexpected errors re-raise so the dispatcher applies backoff/unrecoverable handling instead of silently marking the source successful.
  • Email DB-failure state fix — delivery failure state handling corrected in the ingestion pipeline.

Code Quality / Housekeeping

  • Lazy imports moved to module level (PR #12) — groq, google.genai, resend, urllib.request, soupsieve, asyncpg exceptions, and startup imports in main.py now import at module scope, giving clear early errors for missing dependencies and enabling full static dependency tracking.
  • Dependency cleanup (PR #12) — removed unused apscheduler and pgvector from pyproject.toml.
  • mypy strict compliance in the test suite — tests updated to satisfy strict type-checking.

Testing

  • Unit test suite (PR #13) — new offline, fully-mocked tests for the ingestion pipeline, AI analyzer, bootstrap, Pearson VUE and training-provider collectors, settings, and init_db. Suite grew from 198 passed to 341 passed (15 intentional skips). No live DB, network, or third-party APIs are touched.
  • Transactional outbox tests — new tests/test_notification_outbox.py covers idempotency-key stability, staging, delivery success/failure/retry, and the scheduler sweep; extended tests/test_email_sender.py for Idempotency-Key passthrough; added coverage for poll_interval_minutes clamping, set_process_boot_at, and the DB-backed /health check.
  • All CI quality gates pass: ruff format --check, ruff check, mypy voucherbot tests, and the full pytest suite.

Full Changelog: v1.0.3...v1.0.4