doc(regles-metier): neutraliser pénalités skip pour abonnés + tracking source
Modifie les règles de skip et engagement pour distinguer abonnés/non-abonnés : Jauges d'intérêt (03-centres-interet-jauges.md) : - Skip <10s NON abonné : -0.5% (signal négatif) - Skip <10s ABONNÉ : 0% neutre (affinité globale, skip contextuel) Score d'engagement créateur (04-algorithme-recommandation.md) : - Ajout colonne "source" pour tracking origine écoute - Ajout colonne "is_subscribed" pour état abonnement au moment écoute - Skips d'abonnés ne pénalisent PAS les métriques créateur - Skips via search/direct_link/profile/history ne comptent PAS - Seules sources pertinentes (recommendation, live_notification) comptent Reproposition (04-algorithme-recommandation.md) : - Skip <10s non-abonné : ne pas reproposer - Skip <10s abonné : peut reproposer (skip contextuel acceptable) Avantages : - Cohérence UX : abonnement = signal affinité fort - Protection créateur : abonnés fidèles ne nuisent pas aux stats - Anti-raid naturel : skips malveillants via liens directs inefficaces - Encourage créateurs à diversifier contenus sans peur de perdre abonnés Référence: CLARIFICATIONS-REGLES-METIER.md section 4
This commit is contained in:
@@ -111,12 +111,41 @@ score_final = (score_geo * 0.5) + (score_interets * 0.3) + (score_engagement * 0
|
||||
**Décision** : Intégration popularité avec poids 0.2
|
||||
|
||||
**Métriques** :
|
||||
- **Taux de complétion** : écoutes >80% / total écoutes (poids 0.5)
|
||||
- **Taux de complétion** : écoutes >80% / total écoutes pertinentes (poids 0.5)
|
||||
- **Ratio likes** : likes / écoutes (poids 0.3)
|
||||
- **Ratio abonnements** : nouveaux abonnés après écoute / écoutes (poids 0.2)
|
||||
|
||||
**Distinction sources et abonnements** (neutralisation pénalités) :
|
||||
|
||||
Les métriques d'engagement **ne comptent que les écoutes pertinentes** pour éviter de pénaliser injustement les créateurs :
|
||||
|
||||
| Source écoute | Abonné au créateur ? | Skip <10s pénalise ? | Compte dans "total écoutes" ? | Justification |
|
||||
|---------------|---------------------|---------------------|------------------------------|---------------|
|
||||
| **`recommendation`** | ❌ Non | ✅ Oui | ✅ Oui | Skip = mauvaise recommandation OU mauvais contenu |
|
||||
| **`recommendation`** | ✅ Oui | ❌ **Non** | ❌ **Non** | Abonné intéressé globalement, skip contextuel |
|
||||
| **`search`** | Peu importe | ❌ Non | ❌ Non | User cherchait quelque chose de précis, skip = "pas maintenant" |
|
||||
| **`direct_link`** | Peu importe | ❌ Non | ❌ Non | User curieux, peut skip sans jugement qualité |
|
||||
| **`profile`** | Peu importe | ❌ Non | ❌ Non | User explore catalogue créateur |
|
||||
| **`history`** | Peu importe | ❌ Non | ❌ Non | Pas une première écoute |
|
||||
| **`live_notification`** | ❌ Non | ✅ Oui | ✅ Oui | Abonné normalement intéressé |
|
||||
| **`live_notification`** | ✅ Oui | ❌ **Non** | ❌ **Non** | Abonné = affinité, skip contextuel |
|
||||
| **`audio_guide`** | Peu importe | ❌ Non | ❌ Non | Navigation guidée, pas jugement qualité |
|
||||
|
||||
**Calcul engagement créateur** (exemple SQL) :
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
content_id,
|
||||
AVG(completion_rate) as avg_completion,
|
||||
COUNT(*) FILTER (WHERE completion_rate > 0.8) as complete_listens,
|
||||
COUNT(*) FILTER (WHERE completion_rate < 0.1 AND NOT is_subscribed) as penalizing_skips
|
||||
FROM user_listening_history
|
||||
WHERE source IN ('recommendation', 'live_notification') -- Sources pertinentes
|
||||
GROUP BY content_id;
|
||||
```
|
||||
|
||||
**Seuil minimum** :
|
||||
- Minimum **50 écoutes** avant de considérer l'engagement
|
||||
- Minimum **50 écoutes pertinentes** avant de considérer l'engagement
|
||||
- Contenu <50 écoutes : score engagement = 0.5 (neutre)
|
||||
|
||||
**Contenu viral** :
|
||||
@@ -130,8 +159,11 @@ score_final = (score_geo * 0.5) + (score_interets * 0.3) + (score_engagement * 0
|
||||
|
||||
**Justification** :
|
||||
- Équilibre découverte / qualité
|
||||
- **Protection créateur** : abonnés fidèles ne pénalisent pas les métriques
|
||||
- **Anti-raid naturel** : skips via search/direct_link ne comptent pas (raid inefficace)
|
||||
- **Cohérence UX** : abonnement = signal d'affinité fort, skip ponctuel ≠ rejet créateur
|
||||
- Pas de pénalisation arbitraire des contenus anciens
|
||||
- Coût : calculs sur métriques existantes
|
||||
- Coût : calculs sur métriques existantes + colonne `source` + colonne `is_subscribed`
|
||||
|
||||
---
|
||||
|
||||
@@ -251,24 +283,31 @@ score_final = (score_geo * 0.5) + (score_interets * 0.3) + (score_engagement * 0
|
||||
|
||||
### 2.8 Historique et repropositon
|
||||
|
||||
**Décision** : Pas de reproposition sauf contenu partiel
|
||||
**Décision** : Pas de reproposition sauf contenu partiel ou skip d'abonné
|
||||
|
||||
**Règles** :
|
||||
|
||||
| État écoute | Completion | Action |
|
||||
|-------------|------------|--------|
|
||||
| **Écouté complètement** | >80% | ❌ Ne jamais reproposer (sauf flag `replayable = true` pour audio-guides) |
|
||||
| **Skippé rapidement** | <10s | ❌ Ne pas reproposer |
|
||||
| **Partiellement écouté** | 10-80% | ✅ Reproposer avec reprise position (`last_position_seconds`) |
|
||||
| État écoute | Completion | Abonné au créateur ? | Action |
|
||||
|-------------|------------|---------------------|--------|
|
||||
| **Écouté complètement** | >80% | Peu importe | ❌ Ne jamais reproposer (sauf flag `replayable = true` pour audio-guides) |
|
||||
| **Skippé rapidement** | <10s | ❌ Non | ❌ Ne pas reproposer (signal négatif clair) |
|
||||
| **Skippé rapidement** | <10s | ✅ **Oui** | ✅ **Peut reproposer** (abonnement = affinité, skip contextuel) |
|
||||
| **Partiellement écouté** | 10-80% | Peu importe | ✅ Reproposer avec reprise position (`last_position_seconds`) |
|
||||
|
||||
**Stockage historique** :
|
||||
- Table `user_content_history` (user_id, content_id, completion_rate, last_position, listened_at)
|
||||
- Table `user_content_history` (user_id, content_id, creator_id, **is_subscribed**, completion_rate, last_position, listened_at)
|
||||
- Historique **illimité** (PostgreSQL)
|
||||
- Algorithme considère les **100 derniers** pour optimisation requêtes
|
||||
- Export complet disponible (RGPD)
|
||||
|
||||
**Colonne `is_subscribed`** :
|
||||
- Booléen stockant si l'utilisateur était abonné au créateur **au moment de l'écoute**
|
||||
- Permet de distinguer les skips d'abonnés (contextuels) des skips de non-abonnés (désintérêt)
|
||||
- Utilisé pour décisions de reproposition et calculs d'engagement
|
||||
|
||||
**Justification** :
|
||||
- Découverte maximale (pas de redites)
|
||||
- **Cohérence abonnement** : un skip ponctuel d'un abonné ≠ rejet du créateur (peut être contextuel : "pas maintenant", "pas ce sujet", "mauvais timing")
|
||||
- Respect erreurs de clic (contenu partiel = 2nde chance)
|
||||
- Coût stockage négligeable (PostgreSQL scalable)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user