Skip to content

P0: Card Type Diversity - Cap Identical Card Types #160

@kevsilk597

Description

@kevsilk597

Problem

Today's feed: 45 cards

  • 44 are "RUNNING ON FUMES" workload cards
  • 1 is a hot_streak card

All 44 workload cards have:

  • Same headline template: "[PLAYER NAME] IS RUNNING ON FUMES"
  • Same structure
  • Same repetitive filler text
  • Same low verification score (60)

This is not intelligence. This is spam.

Root Cause

The workload card generator produces unlimited cards without any cap. If 50 players have minute increases, it generates 50 nearly identical cards.

Requirements

1. Cap Cards Per Type Per Day

CARD_TYPE_LIMITS = {
    "hot_streak": 10,
    "cold_streak": 10,
    "workload": 5,      # Hard cap - these are low value
    "injury_impact": 10,
    "matchup": 15,
    "narrative": 10,
    "crossref": 10,
}

def filter_cards_by_type_limit(cards: list[dict]) -> list[dict]:
    """Keep only top N cards per type, sorted by quality."""
    by_type = defaultdict(list)
    for card in cards:
        by_type[card["cardType"]].append(card)
    
    result = []
    for card_type, type_cards in by_type.items():
        limit = CARD_TYPE_LIMITS.get(card_type, 10)
        # Sort by verification score descending, take top N
        sorted_cards = sorted(type_cards, key=lambda c: c["verificationScore"], reverse=True)
        result.extend(sorted_cards[:limit])
    
    return result

2. Require Card Type Diversity in Feed

MINIMUM_CARD_TYPES = 3  # Feed must have at least 3 different card types

def validate_feed_diversity(cards: list[dict]) -> bool:
    types_present = set(c["cardType"] for c in cards)
    return len(types_present) >= MINIMUM_CARD_TYPES

3. Prioritize High-Value Card Types

When selecting which cards to show, prioritize:

  1. matchup - game-specific intelligence
  2. narrative - story angles for media
  3. crossref - convergence signals (our core value prop)
  4. hot_streak/cold_streak - player performance trends
  5. workload - lowest priority (minutes increase is weak signal)

4. Deduplicate Similar Cards

If two cards are about the same signal (e.g., two "minutes increase" cards for players on the same team), keep only the better one:

def deduplicate_similar_cards(cards: list[dict]) -> list[dict]:
    # Group by (card_type, team, signal_type)
    seen_signals = set()
    result = []
    
    for card in sorted(cards, key=lambda c: c["verificationScore"], reverse=True):
        signal_key = (card["cardType"], card.get("player_team"), card.get("signal_type"))
        if signal_key in seen_signals:
            continue
        seen_signals.add(signal_key)
        result.append(card)
    
    return result

Validation

After deploy:

  • Generate cards for a day
  • Verify no more than 5 workload cards appear
  • Verify at least 3 different card types are present
  • Verify no two cards have identical headlines

Definition of Done

  • Card type limits implemented (workload capped at 5)
  • Cards sorted by quality before capping
  • Feed has minimum 3 card types
  • Similar cards deduplicated
  • Workload cards are lowest priority in selection

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions