132 lines
5.9 KiB
Markdown
132 lines
5.9 KiB
Markdown
|
|
# Algorithme de Découverte Veza
|
||
|
|
|
||
|
|
> **Version** : v0.12.9
|
||
|
|
> **Dernière mise à jour** : 2026-03-12
|
||
|
|
> **Référence** : ORIGIN_BUSINESS_LOGIC.md §11, ORIGIN_FEATURES_REGISTRY.md F351-F375, ORIGIN_UI_UX_SYSTEM.md §13-14
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Principes fondamentaux
|
||
|
|
|
||
|
|
L'algorithme de découverte de Veza est conçu selon des principes éthiques stricts :
|
||
|
|
|
||
|
|
1. **Chronologique, pas algorithmique** — Le feed et la découverte sont ordonnés par date de création (du plus récent au plus ancien). Aucun critère d'engagement (play count, likes, partages) n'influence l'ordre d'affichage.
|
||
|
|
|
||
|
|
2. **Pas de ML/IA** — Aucun algorithme de machine learning (collaborative filtering, content-based filtering, analyse prédictive) n'est utilisé. La découverte repose exclusivement sur des mécanismes déclaratifs et humains.
|
||
|
|
|
||
|
|
3. **Visibilité égale** — Un artiste émergent avec 0 écoutes a exactement la même chance d'apparaître qu'un artiste établi avec des millions d'écoutes, à condition qu'il soit dans le même genre/tag et que son contenu soit plus récent.
|
||
|
|
|
||
|
|
4. **Métriques privées** — Les compteurs d'écoutes, likes et followers ne sont JAMAIS visibles publiquement. Ils sont réservés exclusivement au créateur dans son tableau de bord analytics.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Mécanismes de découverte
|
||
|
|
|
||
|
|
### 1. Feed personnel (chronologique)
|
||
|
|
|
||
|
|
**Implémentation** : `internal/core/feed/service.go`
|
||
|
|
|
||
|
|
Le feed d'un utilisateur affiche les tracks des artistes qu'il suit, triées par `created_at DESC`.
|
||
|
|
|
||
|
|
```
|
||
|
|
Requête : SELECT tracks.*
|
||
|
|
FROM tracks
|
||
|
|
INNER JOIN follows ON follows.followed_id = tracks.creator_id
|
||
|
|
WHERE follows.follower_id = :user_id
|
||
|
|
ORDER BY tracks.created_at DESC, tracks.id DESC
|
||
|
|
```
|
||
|
|
|
||
|
|
Aucun facteur de popularité n'intervient. L'ordre est strictement chronologique.
|
||
|
|
|
||
|
|
### 2. Découverte par genre (F353)
|
||
|
|
|
||
|
|
**Implémentation** : `internal/core/discover/service.go` — `GetTracksByGenre()`
|
||
|
|
|
||
|
|
Browse par genre avec pagination curseur. Tri : `created_at DESC, id DESC`.
|
||
|
|
|
||
|
|
```
|
||
|
|
Requête : SELECT tracks.*
|
||
|
|
FROM tracks
|
||
|
|
INNER JOIN track_genres ON track_genres.track_id = tracks.id
|
||
|
|
WHERE track_genres.genre_slug = :slug
|
||
|
|
AND tracks.status = 'completed'
|
||
|
|
AND tracks.is_public = true
|
||
|
|
ORDER BY tracks.created_at DESC, tracks.id DESC
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. Découverte par tag (F353)
|
||
|
|
|
||
|
|
**Implémentation** : `internal/core/discover/service.go` — `GetTracksByTag()`
|
||
|
|
|
||
|
|
Même principe que par genre, avec les tags déclarés par l'artiste.
|
||
|
|
|
||
|
|
### 4. Nouveautés des genres suivis (F355)
|
||
|
|
|
||
|
|
**Implémentation** : `internal/core/discover/service.go` — `GetTracksFromFollowedGenres()`
|
||
|
|
|
||
|
|
Affiche les tracks récentes dans les genres que l'utilisateur suit. Tri chronologique.
|
||
|
|
|
||
|
|
### 5. Playlists éditoriales (F141)
|
||
|
|
|
||
|
|
**Implémentation** : `internal/core/discover/service.go` — `GetEditorialPlaylists()`
|
||
|
|
|
||
|
|
Playlists créées manuellement par l'équipe de curation. Aucune génération automatique.
|
||
|
|
|
||
|
|
### 6. Recherche textuelle (F375)
|
||
|
|
|
||
|
|
**Implémentation** :
|
||
|
|
- PostgreSQL : `internal/services/search_service.go` (ILIKE pattern matching)
|
||
|
|
- Elasticsearch : `internal/elasticsearch/search_service.go` (BM25 + fuzziness)
|
||
|
|
|
||
|
|
La recherche utilise la pertinence textuelle (BM25 sur Elasticsearch, ILIKE sur PostgreSQL). Le commentaire dans le code est explicite :
|
||
|
|
|
||
|
|
```go
|
||
|
|
// F364: fuzziness for typo tolerance; no boost by popularity (ethical)
|
||
|
|
```
|
||
|
|
|
||
|
|
Les champs boostés sont `title^2` et `artist^2` — c'est un boost de pertinence textuelle, PAS de popularité.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Ce qui est explicitement INTERDIT
|
||
|
|
|
||
|
|
| Mécanisme | Raison de l'interdiction | Référence |
|
||
|
|
|-----------|-------------------------|-----------|
|
||
|
|
| Collaborative filtering | Optimise la rétention, pas la découverte authentique | ORIGIN_BUSINESS_LOGIC.md §11 |
|
||
|
|
| Content-based filtering ML | Crée des bulles de filtrage | ORIGIN_BUSINESS_LOGIC.md §11 |
|
||
|
|
| Analyse prédictive du comportement | Manipulation de l'engagement | ORIGIN_BUSINESS_LOGIC.md §11 |
|
||
|
|
| Trending basé sur play counts | Favorise les artistes établis | ORIGIN_UI_UX_SYSTEM.md §13 |
|
||
|
|
| "X personnes écoutent maintenant" | Dark pattern FOMO | ORIGIN_UI_UX_SYSTEM.md §13 |
|
||
|
|
| Compteurs publics de followers | Biais de preuve sociale | ORIGIN_UI_UX_SYSTEM.md §13 |
|
||
|
|
| Leaderboards/classements | Gamification interdite | CLAUDE.md règle #3 |
|
||
|
|
| Badges de performance | XP/streaks interdits | CLAUDE.md règle #3 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Garanties éthiques testées
|
||
|
|
|
||
|
|
Les tests suivants vérifient en continu le respect de ces principes :
|
||
|
|
|
||
|
|
| Test | Fichier | Ce qu'il vérifie |
|
||
|
|
|------|---------|-----------------|
|
||
|
|
| `TestDiscovery_NoPlayCountBias_GenreBrowse` | `discover/ethical_bias_test.go` | Genre browse : ordre chronologique, pas par play count |
|
||
|
|
| `TestDiscovery_NoPlayCountBias_TagBrowse` | `discover/ethical_bias_test.go` | Tag browse : même vérification |
|
||
|
|
| `TestDiscovery_EmergingArtistVisibility` | `discover/ethical_bias_test.go` | Artiste 0 plays non défavorisé |
|
||
|
|
| `TestDiscovery_MetricsNotExposedInJSON` | `discover/ethical_bias_test.go` | play_count/like_count absents du JSON |
|
||
|
|
| `TestSearch_ArtistZeroPlays_Discoverable` | `services/ethical_search_test.go` | Artiste 0 plays trouvable par nom |
|
||
|
|
| `TestSearch_ZeroPlaysTrack_NotFilteredOut` | `services/ethical_search_test.go` | Track 0 plays non filtré |
|
||
|
|
| `TestSearch_DefaultSortIsChronological` | `services/ethical_search_test.go` | Tri par défaut = chronologique |
|
||
|
|
| `TestSearch_NoPopularityBias_InDefaultRanking` | `services/ethical_search_test.go` | Pas de biais popularité dans le ranking par défaut |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Audit et transparence
|
||
|
|
|
||
|
|
Cet algorithme est :
|
||
|
|
- **Documenté** : ce fichier constitue la documentation publique
|
||
|
|
- **Auditable** : le code source est lisible et les requêtes SQL sont explicites
|
||
|
|
- **Testé** : les tests éthiques ci-dessus sont exécutés en CI
|
||
|
|
- **Déterministe** : pas de composante aléatoire ou opaque
|
||
|
|
|
||
|
|
Toute modification de l'algorithme de découverte doit passer les tests éthiques existants et être documentée ici.
|