Livrable documentaire uniquement — Plan complet du pipeline vidéo NEXORA
1. Livrable de cette tâche
Créer uniquement :
docs/docs/architecture/video-pipeline-implementation-plan.md
Aucun code, schéma, dépendance, configuration ou test ne sera modifié à ce stade. Le document contiendra la spécification ci-dessous, suffisamment précise pour être confiée directement à un développeur.
Le document suivra une discipline d’ingénierie stricte :
- Flux simples, explicites et déterministes.
- Une seule source de vérité par donnée.
- Aucun fallback silencieux vers des données fictives.
- Aucune vidéo chargée intégralement en mémoire.
- Transitions d’état atomiques et idempotentes.
- Erreurs structurées, observables et récupérables.
- SQL paramétré, types stricts, aucun nouveau
any. - Aucun secret, chemin public ou détail biométrique dans les logs.
- Pas d’abstraction sans au moins deux implémentations réelles.
- Couverture lignes et branches de 100 % pour tout nouveau code testable.
2. Architecture d’implémentation documentée
Flux cible
Panel admin
→ session existante ou nouvel événement planifié
→ multipart upload direct vers R2
→ validation et création atomique du job PostgreSQL
→ orchestrateur CPU
→ Runpod Serverless GPU ou worker GPU local
→ proxy vidéo + détections + états + annotations dans R2
→ publication atomique dans Gold
→ activation du résultat
→ lecture privée avec overlays temporels
Invariants obligatoires
sessions.video_namereste l’identité logique utilisée par Gold.video_assets.iddevient l’identité physique du média.- Une session possède au maximum un asset vidéo actif.
- Un asset possède au maximum un job actif.
- Un retry crée une nouvelle tentative ; il ne réutilise pas les sorties d’une tentative échouée.
- Le résultat précédent reste actif jusqu’à la publication complète du nouveau résultat.
completedsignifie que proxy, overlays, annotations et Gold sont tous publiés.- Une requête
complete uploadrépétée retourne le même résultat sans créer un second job. - La suppression ne peut commencer qu’après annulation ou terminaison du job actif.
- Tous les timestamps sont absolus depuis le début de la vidéo.
- Les coordonnées de bbox sont normalisées entre 0 et 1.
- Un track insuffisamment identifié reste
unknown. - Un modèle absent en production fait échouer le job ; il ne déclenche jamais le mock.
- Le mock reste disponible uniquement avec
NEXORA_MODEL_BACKEND=mockexplicite.
Runpod
Configuration initiale documentée :
- Endpoint Queue asynchrone
/run. - Worker Flex,
workersMin=0,workersMax=1. - GPU prioritaire A4000 16 Go, fallback A5000/L4 24 Go.
- Timeout d’exécution : 6 heures.
- TTL du job : 12 heures.
- Un job par worker.
- Image Docker taggée par SHA, jamais
latest. - Modèles préentraînés intégrés ou mis en cache dans l’image.
- Surveillance par polling toutes les 15 secondes ; webhook seulement comme optimisation.
- Provider sélectionné par
NEXORA_INFERENCE_PROVIDER=runpod|local.
Runpod permet les jobs async, le polling de progression et le scale-to-zero ; le tarif Flex 16 Go est actuellement annoncé autour de 0,58 $/h, à revérifier au déploiement. Endpoints Runpod, requêtes async, tarification.
3. Inventaire exact des fichiers de la future implémentation
Base de données et types
| Fichier | Action future |
|---|---|
web/src/lib/server/db/schema.ts |
Ajouter videoAssets, processingJobs et les colonnes de stockage privé des photos. |
web/drizzle/0001_video_pipeline.sql |
Migration versionnée, contraintes, index et backfill non destructif. |
web/drizzle/meta/_journal.json |
Mise à jour générée par Drizzle, jamais éditée manuellement. |
web/drizzle/meta/0001_snapshot.json |
Snapshot généré correspondant à la migration. |
web/src/lib/video/types.ts |
Nouveaux types partagés et unions discriminées des états. |
web/src/lib/server/video/service.ts |
Service transactionnel unique pour assets, jobs, transitions et retries. |
web/src/lib/server/video/access.ts |
Autorisation par session : admin/director ou enseignant propriétaire. |
Tables prévues :
video_assets- ID UUID, session unique,
video_nameunique. - Nom original, MIME, taille
bigint, checksum SHA-256. - Clés R2 original/playback/analyse.
- Durée, dimensions, audio, statut et
active_job_id. processing_jobs- UUID, asset/session, tentative, provider et ID externe.
- Statut, étape, progression, version de modèles.
- Préfixe de sortie, erreurs structurées, couverture et timestamps.
student_photos- Ajouter
object_key, checksum, MIME, taille et statut de validation. - Conserver temporairement
filenamepour le backfill legacy.
Contraintes :
- Index unique partiel empêchant deux jobs actifs par asset.
active_job_idne référence qu’un jobcompleted.- Foreign keys avec stratégie explicite pour suppression.
- Toutes les transitions utilisent
UPDATE … WHERE status IN (…), puis vérifient le nombre de lignes modifiées.
Stockage et upload R2
| Fichier | Action future |
|---|---|
web/src/lib/server/storage/index.ts |
Supprimer les lectures distantes intégrales et exposer les primitives nécessaires. |
web/src/lib/server/storage/multipart.ts |
Nouveau service multipart R2 : initiate, sign, complete et abort. |
web/src/lib/server/storage/presign.ts |
Nouveau service de présignature GET/PUT avec durées bornées. |
web/package.json |
Ajouter @aws-sdk/s3-request-presigner et les scripts de couverture. |
web/pnpm-lock.yaml |
Mise à jour générée. |
web/src/routes/api/admin/videos/+server.ts |
Conserver GET comme liste agrégée ; retirer l’ancien upload en mémoire. |
web/src/routes/api/admin/videos/uploads/+server.ts |
Initier un multipart pour une session existante. |
web/src/routes/api/admin/videos/uploads/[assetId]/parts/+server.ts |
Signer un lot borné de numéros de parties. |
web/src/routes/api/admin/videos/uploads/[assetId]/complete/+server.ts |
Compléter, vérifier et créer le job atomiquement. |
web/src/routes/api/admin/videos/uploads/[assetId]/+server.ts |
DELETE pour abort idempotent. |
web/src/routes/api/admin/videos/[assetId]/+server.ts |
GET détail et DELETE contrôlé. |
web/src/routes/api/admin/videos/[assetId]/retry/+server.ts |
Créer une nouvelle tentative. |
web/src/routes/api/admin/videos/[assetId]/cancel/+server.ts |
Annuler le job actif. |
web/src/routes/api/admin/sessions/[sessionId]/video/+server.ts |
Déléguer lecture/suppression au nouveau service ; supprimer l’upload form-data. |
web/src/routes/api/admin/photos/+server.ts |
Enregistrer une clé R2 privée au lieu d’une URL. |
Contrat multipart :
- Parties de 64 Mio.
- Trois uploads parallèles.
- Trois retries avec backoff exponentiel et jitter.
- URLs PUT valables 15 minutes.
- Vérification taille et
HeadObjectavant création du job. - Taille maximale configurable, valeur initiale 20 Gio.
- Types acceptés : MP4, MOV, WebM et MKV, mais la validation réelle se fait par
ffprobe. - Les multipart incomplets sont supprimés après 24 heures.
Lecture et overlays
| Fichier | Action future |
|---|---|
web/src/routes/videos/[name]/+server.ts |
Maintenir uniquement le fallback des anciennes vidéos locales. |
web/src/routes/api/media/videos/[assetId]/playback/+server.ts |
Contrôle d’accès puis redirection vers une URL GET présignée. |
web/src/routes/api/media/videos/[assetId]/overlay/manifest/+server.ts |
Servir le manifeste actif. |
web/src/routes/api/media/videos/[assetId]/overlay/states/+server.ts |
Servir les états temporels. |
web/src/routes/api/media/videos/[assetId]/overlay/chunks/[index]/+server.ts |
Servir les bboxes compressées par tranche. |
web/src/lib/video/overlay.ts |
Recherche temporelle, interpolation et validation pure des artefacts. |
web/src/lib/components/video/OverlayCanvas.svelte |
Canvas superposé au <video>. |
web/src/lib/components/video/StudentVideoFilter.svelte |
Recherche et multi-sélection. |
web/src/lib/components/modals/VideoPlayerModal.svelte |
Intégrer player, canvas, filtres, états et erreurs. |
web/src/routes/dashboard/+page.svelte |
Passer assetId, permissions et données de session à la modale. |
Formats :
type StudentWindowStateV1 = {
studentRef: string;
windowStartMs: number;
windowEndMs: number;
state: 'deep' | 'active' | 'passive' | 'disengaged' | 'withdrawal' | 'unobserved';
score: number | null;
signalCode: string | null;
confidence: number;
visibilityRatio: number;
observedCategories: string[];
imputedCategories: string[];
};
type OverlayTrackSampleV1 = {
tMs: number;
studentRef: string | null;
trackId: number;
box: [number, number, number, number];
detectionConfidence: number;
identityConfidence: number | null;
};
Comportement UI :
- Tous les élèves sont sélectionnés à chaque ouverture.
- Recherche, sélectionner tout et désélectionner tout.
- Cadre coloré par état.
- Label
Nom · état · signal lisible. - Élève absent plus de 50 % de la fenêtre :
Non observé. - Inconnus masqués dans l’interface standard.
- Interpolation maximale 500 ms ; bbox masquée après une seconde sans observation.
requestVideoFrameCallbackutilisé quand disponible, fallbacktimeupdate.- Chunk courant et suivant préchargés.
- Si exactement un élève est sélectionné, afficher sa timeline ; sinon moyenne de classe.
- La vidéo reste lisible sans overlay avec un message d’indisponibilité.
Pipeline IA
| Fichier | Action future |
|---|---|
ai/pipeline/config.py |
Configuration typée, validation des providers, modèles et seuils. |
ai/pipeline/storage.py |
Téléchargement/upload en streaming et clés R2 canoniques. |
ai/pipeline/db.py |
Remplacer les interpolations SQL par un driver PostgreSQL paramétré. |
ai/pipeline/runner.py |
Pipeline déterministe, reprise idempotente et publication des artefacts. |
ai/pipeline/artifacts.py |
Nouveau writer/validator des manifestes, états et chunks overlay. |
ai/pipeline/timeline.py |
Nouveau calcul centralisé des timestamps absolus. |
ai/pipeline/steps/ingest.py |
Validation ffprobe et création des proxies lecture/analyse. |
ai/pipeline/steps/detect.py |
YOLO11m préentraîné, sortie bornée et normalisée. |
ai/pipeline/steps/track.py |
ByteTrack continu sur toute la vidéo. |
ai/pipeline/steps/identify.py |
InsightFace, votes, seuil et marge explicites. |
ai/pipeline/steps/pose.py |
YOLO11n-pose avec échantillonnage configuré. |
ai/pipeline/steps/classify.py |
Retirer l’aléatoire ; baseline déterministe et catégories imputées. |
ai/pipeline/steps/score.py |
Conserver le moteur canonique et ajouter confiance/provenance. |
ai/orchestrator.py |
Nouveau poller CPU pour dispatch, statut, finalisation et récupération. |
ai/runpod_handler.py |
Nouveau wrapper minimal runpod.serverless.start. |
ai/providers/base.py |
Contrat provider limité à submit/status/cancel. |
ai/providers/runpod.py |
Adaptateur Runpod avec timeouts, backoff et erreurs typées. |
ai/worker.py |
Mode worker GPU local utilisant le même handler métier. |
ai/Dockerfile |
Targets séparées orchestrateur léger et inference CUDA. |
ai/requirements.txt |
Dépendances CPU et tests épinglées. |
ai/requirements-ml.txt |
Versions compatibles CUDA, Ultralytics et InsightFace épinglées. |
ai/pyproject.toml |
Ruff, pytest, coverage et règles statiques. |
Modèles baseline :
- YOLO11m : détection des personnes.
- ByteTrack : continuité des tracks.
- YOLO11n-pose : posture et gestes.
- InsightFace
buffalo_l: correspondance à la galerie. - Seuil identité initial : cosine ≥ 0,45.
- Marge premier/deuxième candidat ≥ 0,05.
- Minimum trois observations concordantes.
- Les embeddings de référence sont temporaires et ne sont pas publiés.
Publication Gold
| Fichier | Action future |
|---|---|
processing/pipelines/polars_pipeline.py |
Publication vidéo par vidéo dans un staging puis remplacement atomique. |
processing/pipelines/scoring.py |
Inchangé sauf si un type explicite de provenance est nécessaire ; aucune duplication des règles. |
processing/pipelines/video_publish.py |
Nouveau verrou, validation, commit et rollback des partitions. |
web/src/lib/server/gold.ts |
Lire uniquement les partitions activées et exposer les états nécessaires. |
Ordre de publication :
- Valider
result.json, checksums et versions. - Importer annotations vers bronze staging.
- Construire silver et gold staging.
- Prendre un verrou PostgreSQL unique.
- Remplacer atomiquement les partitions de la vidéo.
- Recalculer les agrégats globaux.
- Définir
active_job_id. - Passer job et asset à
completed/ready. - Libérer le verrou.
Interface admin
| Fichier | Action future |
|---|---|
web/src/lib/components/views/AdminView.svelte |
Remplacer l’ancien champ file par l’uploader multipart et le suivi des jobs. |
web/src/lib/components/modals/PlanningModal.svelte |
Créer d’abord la session, puis lancer le même uploader. |
web/src/lib/components/video/VideoUpload.svelte |
Nouveau composant unique d’upload, progression et reprise. |
web/src/lib/components/video/ProcessingStatus.svelte |
Nouveau composant des étapes, couverture, retry et cancel. |
web/src/lib/components/layout/Controls.svelte |
Utiliser le statut du job actif. |
États affichés :
- Upload.
- Validation.
- Transcodage.
- Détection.
- Tracking.
- Identification.
- Classification.
- Publication.
- Terminé ou échec.
Infrastructure et documentation future
| Fichier | Action future |
|---|---|
docker-compose.yml |
Remplacer le worker ambigu par orchestrateur CPU et profil GPU local. |
docker-compose.prod.yml |
Configurer runpod au lieu du backend invalide openrouter. |
docker-compose.test.yml |
Ajouter MinIO, fake Runpod et tests d’intégration. |
.env.example |
Variables R2, Runpod, limites et modèles. |
web/.env.example |
Variables utilisées par SvelteKit. |
web/docs/storage-r2.md |
Multipart, CORS, lifecycle et bucket privé. |
ai/README.md |
Exécution locale/Runpod, modèles, statuts et diagnostic. |
DEPLOY.md |
Création endpoint, secrets, rollback et smoke tests. |
4. Plan de tests avec couverture complète
Politique de couverture
- 100 % lignes, fonctions, statements et branches sur tout nouveau code TypeScript testable.
- 100 % lignes et branches sur tout nouveau code Python testable.
- Aucun
c8 ignore,pragma: no coverou exclusion sans justification documentée et revue. - Les migrations générées, fichiers Drizzle
metaet markup CSS ne comptent pas dans le seuil. - Les appels réseau, R2, Runpod, ffmpeg et PostgreSQL sont testés via ports/adapters injectables.
- Le smoke GPU réel complète la couverture mais ne fait pas partie du CI obligatoire.
Fichiers de tests web
| Fichier | Couverture |
|---|---|
web/src/lib/server/storage/multipart.test.ts |
Initiate, signatures, parties invalides, complete, abort, répétitions et erreurs R2. |
web/src/lib/server/storage/presign.test.ts |
Clés autorisées, expirations et refus des traversées. |
web/src/lib/server/video/service.test.ts |
Toutes les transitions, concurrence, retries, suppression et activation atomique. |
web/src/lib/server/video/access.test.ts |
Admin, director, propriétaire, autre enseignant, parent et non authentifié. |
web/src/lib/video/overlay.test.ts |
Validation schéma, chunk lookup, seek, interpolation, données périmées et bboxes invalides. |
web/tests/unit/components/VideoUpload.test.ts |
Progression, retry, abort, erreurs, tailles et ETags. |
web/tests/unit/components/ProcessingStatus.test.ts |
Chaque statut et action autorisée. |
web/tests/unit/components/OverlayCanvas.test.ts |
Redimensionnement, letterboxing, sélection et masquage. |
web/tests/unit/components/StudentVideoFilter.test.ts |
Tous sélectionnés, recherche, tout/aucun et clavier. |
web/tests/unit/components/VideoPlayerModal.test.ts |
Chargement, seek, état courant, fermeture, fallback et erreurs. |
web/e2e/admin-video.spec.ts |
Remplacer les tests legacy par le flux multipart complet. |
web/e2e/video-player.spec.ts |
Lecture, multi-sélection, cadres, signaux, seek et accès. |
web/e2e/video-security.spec.ts |
Matrice complète des rôles et absence d’URL publique persistante. |
Cas API obligatoires :
- Fichier valide et invalide.
- Taille 0, limite exacte et dépassement.
- Mauvais numéro de partie, doublon, ETag manquant.
- Appel
completeconcurrent. - Session inexistante ou déjà équipée.
- Upload abandonné ou expiré.
- R2 indisponible avant et après création DB.
- Job créé une seule fois.
- Retry pendant job actif refusé.
- Cancel répété idempotent.
- Delete pendant upload, processing, completed et failed.
- Enseignant propriétaire accepté, autre enseignant refusé.
- URL signée expirée régénérée.
- Range et seek fonctionnels.
Fichiers de tests Python IA
| Fichier | Couverture |
|---|---|
ai/tests/test_config.py |
Validation exhaustive des variables et providers. |
ai/tests/test_storage.py |
Streaming, erreurs partielles, checksum et nettoyage. |
ai/tests/test_database.py |
Requêtes paramétrées, claims concurrents et transitions. |
ai/tests/test_timeline.py |
Timestamps absolus, frontières et vidéos à FPS variable. |
ai/tests/test_ingest.py |
ffprobe, codecs, proxies, audio et corruption. |
ai/tests/test_detect.py |
Filtrage personne, coordonnées, limites et lot vide. |
ai/tests/test_track.py |
Continuité, occlusion, disparition et changement de chunk. |
ai/tests/test_identify.py |
Match, seuil, marge, égalité, galerie absente et inconnus. |
ai/tests/test_pose.py |
Keypoints valides, partiels et absents. |
ai/tests/test_classify.py |
Chaque signal, imputation, visibilité et déterminisme. |
ai/tests/test_score.py |
Compatibilité exacte avec le scoring canonique. |
ai/tests/test_artifacts.py |
Schémas, compression, chunks, checksums et manifestes. |
ai/tests/test_runner.py |
Succès, échec à chaque étape, retry, cleanup et idempotence. |
ai/tests/test_runpod_handler.py |
Input invalide, progression, résultat et exception sérialisée. |
ai/tests/test_runpod_provider.py |
Submit/status/cancel, 401, 429, 5xx, timeout et backoff. |
ai/tests/test_orchestrator.py |
Claim, polling, résultat expiré, publication et récupération après crash. |
Cas essentiels :
- Deux chunks ne remettent jamais le temps à zéro.
- Deux tracks ne peuvent pas publier simultanément le même élève au même instant sans résolution explicite.
- Galerie vide ou partielle n’échoue pas.
- Un modèle manquant en mode réel échoue.
- Un modèle manquant en mock reste déterministe.
- Aucun caractère du nom de fichier ne peut influencer un chemin local ou R2.
- Un job relancé n’écrase pas la tentative active.
- Un crash après upload des artefacts mais avant mise à jour DB est récupérable.
Tests processing
| Fichier | Couverture |
|---|---|
processing/tests/test_video_publish.py |
Staging, commit, rollback, verrou et remplacement atomique. |
processing/tests/test_pipeline.py |
Ajouter import d’une vidéo unique et recomposition des agrégats. |
processing/tests/test_scoring.py |
Conserver la couverture canonique existante et ajouter provenance/imputation si nécessaire. |
Scénarios :
- Publication réussie.
- Annotation invalide.
- Partition existante remplacée.
- Échec avant commit.
- Échec pendant recomposition globale.
- Deux publications concurrentes.
- Ancien résultat conservé après rollback.
- Réexécution idempotente du même job.
Intégration et E2E
Le stack de test contiendra :
- PostgreSQL.
- MinIO comme implémentation S3/R2.
- Fake Runpod HTTP programmable.
- ffmpeg réel.
- Worker CPU/mock déterministe.
- Vidéo synthétique avec audio.
- Galerie complète et galerie partielle.
Parcours E2E :
- Admin crée une session.
- Upload multipart direct.
- Progression upload visible.
- Job créé automatiquement.
- Fake Runpod publie les artefacts.
- Finalizer publie Gold.
- Asset passe
ready. - Modale ouverte avec tous les élèves sélectionnés.
- Désélection d’un élève masque uniquement sa bbox.
- Seek change bbox, niveau et signal.
- Élève sans référence apparaît
Non observé. - Parent reçoit 403.
- Enseignant non propriétaire reçoit 403.
- Suppression retire asset et objets sans affecter la session avant confirmation.
Smoke test GPU réel
Non exécuté à chaque CI, mais obligatoire avant production :
- Endpoint Runpod réel.
- Vidéo de deux minutes, dix élèves, deux sans référence.
- YOLO, ByteTrack, pose et InsightFace réellement chargés.
- Vérifier proxy H.264/AAC et lecture Range.
- Vérifier timestamps, manifestes et Gold.
- Mesurer temps GPU, délai de queue, cold start, mémoire et coût.
- Répéter après extinction complète du worker pour tester le cold start.
- Tester cancel puis retry.
- Tester indisponibilité R2 temporaire.
Commandes de validation futures
cd web
pnpm check
pnpm lint
pnpm test
pnpm test:e2e
pnpm build
pnpm vitest run --coverage
cd ai
ruff check .
pytest --cov=pipeline --cov=providers --cov-branch --cov-fail-under=100
cd processing
uv run pytest --cov=pipelines --cov-branch --cov-fail-under=100
docker compose -f docker-compose.test.yml up --build --abort-on-container-exit
5. Critères d’acceptation du futur développement
- Aucun upload de production ne traverse le serveur web.
- Aucune lecture distante ne charge une vidéo entière en mémoire.
Rangeet seek fonctionnent sur R2.- Le pipeline démarre automatiquement après finalisation.
- Tous les statuts sont persistés et récupérables après crash.
- Aucun fallback mock/aléatoire en production.
- Les timestamps restent corrects sur toute la vidéo.
- Les bboxes publiées correspondent à la timeline de lecture.
- Tous les élèves sont sélectionnés par défaut.
- Chaque bbox affiche engagement et un signal lisible.
- Un élève incertain n’est jamais identifié arbitrairement.
- Les galeries partielles génèrent un avertissement sans bloquer.
- Les parents et enseignants non propriétaires ne peuvent lire ni vidéo ni overlays.
- Un retraitement échoué conserve le dernier résultat valide.
- Toutes les nouvelles branches testables atteignent 100 % de couverture.
- Le dépôt reste vert sur type-check, lint, tests, build et intégration.
- La seule modification de la tâche actuelle demeure la création du document de plan ; aucune implémentation n’est incluse.
20. Statut d'implémentation (livraison réelle)
Cette section reflète ce qui a été effectivement implémenté et vérifié sur
master, couche par couche. Le reste (migration Drizzle appliquée en base, Runpod réel, smoke GPU) est documenté comme étant à valider sur l'environnement de production.
20.1 Socle web — implémenté et vérifié ✅
| Brique | Fichiers | Tests |
|---|---|---|
| Types partagés | web/src/lib/video/types.ts |
— |
| Overlay (seek/interpélation/validators) | web/src/lib/video/overlay.ts |
overlay.test.ts |
| Tables | video_assets, processing_jobs + colonnes photos privées (schema.ts) |
migration 0001_video_pipeline.sql |
| Service transactionnel | web/src/lib/server/video/service.ts (transitions atomiques via returning()) |
— |
| Autorisation par session | web/src/lib/server/video/access.ts |
— |
| Storage multipart/presign | multipart.ts, presign.ts, client.ts, read.ts |
storage.test.ts |
| Routes admin uploads | /uploads, /uploads/[assetId]/parts, /complete, DELETE + asset/retry/cancel |
— |
| Routes media | /playback (présigné), /overlay/manifest|states|chunks |
— |
| Composants UI | OverlayCanvas, StudentVideoFilter, VideoUpload, ProcessingStatus |
— |
| Intégration | VideoPlayerModal (asset+overlay), dashboard (assetId), AdminView, PlanningModal |
— |
Vérifications : svelte-check 0 erreur · vitest 75 tests ✅.
20.2 Moteur IA — implémenté et vérifié ✅
| Brique | Fichiers | Tests |
|---|---|---|
| Providers | providers/base.py, runpod.py, local.py |
tests/test_providers.py |
| Timestamps absolus | pipeline/timeline.py |
tests/test_timeline.py |
| Artefacts overlay | pipeline/artifacts.py |
tests/test_artifacts.py |
| DB paramétré | pipeline/db.py (psycopg, claims atomiques) |
— |
| Orchestrateur | orchestrator.py |
tests/test_orchestrator.py |
| Handler Runpod | runpod_handler.py |
— |
| classify déterministe | pipeline/steps/classify.py (plus de random) |
tests/test_classify.py |
| identify seuils | pipeline/steps/identify.py (0.45 / marge 0.05 / min 3 obs) |
tests/test_identify.py |
Vérifications : pytest 25 tests ✅ · ruff clean ✅.
20.3 À valider en environnement réel (non exécuté ici)
- Appliquer
web/drizzle/0001_video_pipeline.sqlsur la base (oudrizzle-kit push). - Configurer R2 (
NEXORA_S3_*) + bucket privé + lifecycle. - Configurer Runpod (
NEXORA_RUNPOD_ENDPOINT,NEXORA_RUNPOD_API_KEY,NEXORA_INFERENCE_PROVIDER=runpod). - Smoke GPU : vidéo 2 min, YOLO/ByteTrack/pose/InsightFace réels, lectures Range.
pnpm check && pnpm test && pnpm test:e2e && pnpm buildsur web ;pytest --cov-fail-under=100sur ai (nécessite pytest-cov en CI).- E2E
admin-video.spec.ts/video-player.spec.tsréécrits autour du multipart.
20.4 Commandes de validation actuellement vertes
cd web && npx svelte-check --threshold error # 0 erreur
cd web && npx vitest run --config vitest.config.ts # 75 tests
cd ai && .venv/bin/python -m pytest tests/ -q # 25 tests
cd ai && .venv/bin/ruff check providers pipeline/... orchestrator.py # clean