Sfoglia il codice sorgente

feat(sponsor-prompt): lower print/archive/cost thresholds to fire for typical new installs

    The toast was calibrated for power users — lowest bars were 100 prints,
    50 archives, 100 cost. Most installs never crossed any of them, especially
    with the install base ~doubling since March. Matomo confirms: only 4
    prints-100 and 3 archives-50 deeplink visits to /sponsors.html in a 7-day
    window despite tens of thousands of weekly pulls.

    Adds lower thresholds without changing priority order or cooldown:
      PRINT_MILESTONES   = (10, 25, ...)
      ARCHIVE_MILESTONES = (5, 10, ...)
      COST_MILESTONES    = (25, 50, ...)

    Existing toast copy uses {count}/{total} interpolation in all 11 locales,
    so no i18n changes. Tests rebalanced so "below the floor" still tests
    with the new floor; new test_fires_at_lowest_threshold pins prints-10.
maziggy 2 mesi fa
parent
commit
257b9e2c89

File diff suppressed because it is too large
+ 0 - 0
CHANGELOG.md


+ 3 - 3
backend/app/services/sponsor_prompt.py

@@ -32,9 +32,9 @@ logger = logging.getLogger(__name__)
 
 COOLDOWN_DAYS = 14
 
-PRINT_MILESTONES = (100, 500, 1000, 2500, 5000)
-COST_MILESTONES = (100, 500, 1000)
-ARCHIVE_MILESTONES = (50, 250, 1000)
+PRINT_MILESTONES = (10, 25, 100, 500, 1000, 2500, 5000)
+COST_MILESTONES = (25, 50, 100, 500, 1000)
+ARCHIVE_MILESTONES = (5, 10, 50, 250, 1000)
 ANNIVERSARY_YEARS = 1
 
 

+ 14 - 5
backend/tests/unit/test_sponsor_prompt_service.py

@@ -155,15 +155,24 @@ class TestPrintMilestones:
         assert trigger is not None
         assert trigger.milestone == "prints-100"
 
+    @pytest.mark.asyncio
+    async def test_fires_at_lowest_threshold(self, db_session: AsyncSession):
+        user = await _make_user(db_session)
+        await _add_completed_prints(db_session, user_id=user.id, count=10)
+        trigger = await service.evaluate(db_session, user.id)
+        assert trigger is not None
+        assert trigger.milestone == "prints-10"
+        assert trigger.threshold == 10
+
     @pytest.mark.asyncio
     async def test_failed_prints_dont_count(self, db_session: AsyncSession):
         user = await _make_user(db_session)
-        await _add_completed_prints(db_session, user_id=user.id, count=50)
+        await _add_completed_prints(db_session, user_id=user.id, count=5)
         for _ in range(60):
             db_session.add(PrintLogEntry(status="failed", created_by_id=user.id))
         await db_session.flush()
         trigger = await service.evaluate(db_session, user.id)
-        # Only 50 completed → below 100 threshold → no print trigger.
+        # Only 5 completed → below 10 threshold → no print trigger.
         # Anniversary not reached either; no other counter populated.
         assert trigger is None
 
@@ -181,10 +190,10 @@ class TestArchiveMilestones:
 class TestCostMilestones:
     @pytest.mark.asyncio
     async def test_fires_when_cost_sum_crosses_100(self, db_session: AsyncSession):
-        # Prints with cost = ~3.5 each, 30 prints → 105.
+        # 5 prints, cost ~21 each → 105 total. Below the 10-print threshold so
+        # the prints family stays silent and cost gets a chance.
         user = await _make_user(db_session)
-        await _add_completed_prints(db_session, user_id=user.id, count=30, cost_each=3.5)
-        # 30 < 100 prints, so prints-100 not eligible. cost = 105 ≥ 100 → fires.
+        await _add_completed_prints(db_session, user_id=user.id, count=5, cost_each=21.0)
         trigger = await service.evaluate(db_session, user.id)
         assert trigger is not None
         assert trigger.family == "cost"

Some files were not shown because too many files changed in this diff