Sujets : le relevé de /opt/studio/sujets.json passe dans la base du service d'état (t_ae236aa9) #1694
Loading…
Reference in a new issue
No description provided.
Delete branch "hermes/migration-sujets-sqlite"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Carte
t_ae236aa9(sujets.json → SQLite). Branchehermes/migration-sujets-sqlite, commitffb882a6, rebasée surmainae760c38.Cause.
/opt/studio/sujets.json— les vidéos des chaînes voisines qui font plusieurs fois la médiane de la leur, ce qui remplace vidIQ ou TubeBuddy (demande de l'opérateur, 2026-09-25) — n'avait qu'un foyer : un fichier sur le LXC 132, réécrit d'un bloc par la collecte (_tableau/sujets.py, appelée partableau-bord.py). Ni requêtable, ni relu ailleurs, et une donnée que l'Agenda lit.Remède. Cinq tables dans
etat_partage.sql(sujets_releve,sujets_ids,sujets_chaines,sujets_videos— une ligne par vidéo,rang= le rang affiché —,sujets_absentes),sujets_lire/detail/remplacerdansetat_partage.py, trois routes dans_infra/etat-service.py,basculer sujets [--essai]/revenir sujetsdansetat_client.py, et l'écriture parsocle.sujets_ecrire(fichier d'abord, base ensuite). Détail complet dans le message du commit.API. Trois routes NOUVELLES (
GET /sujets,GET /sujets/detail,POST /sujets/remplacer) ; aucun champ d'API existant ne change, et le front Svelte ne consomme pas ces routes. Rien à faire côtésvelte.Ce qui est mesuré
La bascule, son aller-retour et son refus, sur le relevé vivant du 132 (102 vidéos, 16 chaînes, relevé du 2026-10-14T07:18), lu par ssh et comparé à une base jetable :
Les bancs, ajoutés et touchés :
Le banc neuf couvre : une base d'avant ce nom de bascule refaite sans perte (le CHECK de
basculesrestauré), le refus d'un relevé sansvideosni avec un champ inconnu (rien n'entre, la bascule n'est pas posée), l'essai sur le relevé réel, la bascule (comptes par table,.bak-sqlite-<date>, copie réécrite depuis la base), le service muet (« fichier-muet », et le fichier quand même écrit), le service injoignable avant l'écriture (« fichier », chemin d'avant la bascule), le retour arrière puis la re-bascule.Suite complète,
python3 _tableau/lancer-tests.py --tout --sans-couverture: 169 bancs verts, 1 rouge —_tableau/test_accueil_parite.py, qui est déjà rouge sur un arbre neuf deorigin/main(vérifié surae760c38, même assertion : « le JSON doré n'est plus la sortie de Python », clésmonetisation,seuil_heures_apres,fin_seuil,courbes). Hors périmètre de cette carte ; à prendre telle quelle.Ce que je n'ai pas pu mesurer. La bascule elle-même (sans
--essai) n'a pas été posée : le service d'état n'est pas joignable aujourd'hui —192.168.1.142ne répond pas (ping 100 % de pertes,curlsort en 7), le LXC 130 étant éteint par décision de l'opérateur. Le fichier fait donc foi comme avant, et la collecte du 132 continue d'écrire le fichier seul (socle.sujets_ecrirerend « fichier »). Le code est prêt et éprouvé sur une base jetable : dès que le service répond,basculer sujetspuis la double écriture prennent le relais sans autre changement. Commande à jouer alors :Point de collision à signaler.
etat_partage.sql,etat_partage.py,_infra/etat-service.py,etat_client.pyet la ligneetat_client.pyd'OUTILS.mdsont touchés par chacune des migrations en cours (hermes/migration-atelier-sqlite,-historique-sqlite,-instagram-sqlite,-reseaux-sqlite,-choix-vignettes-sqlite, toutes non fusionnées). J'ai repris le même motif debascules.nomque la branche historique (motif GLOB +_reparer_bascules) pour que la fusion de l'une ou de l'autre ne laisse qu'une copie : la résolution de conflit attendue est de garder une seule ligne de CHECK et un seul_reparer_bascules.Cause : `/opt/studio/sujets.json` (les vidéos des chaînes voisines qui font plusieurs fois la médiane de la leur — ce qui remplace un abonnement à vidIQ ou TubeBuddy) n'avait qu'un foyer : un fichier sur le LXC 132, réécrit d'un bloc par la collecte (`_tableau/sujets.py`, appelé par `tableau-bord.py`). Ni requêtable, ni relu ailleurs, et une donnée que l'Agenda lit. C'est la migration « sujets.json » de la série de STUD-1107. Remède : - `etat_partage.sql` : cinq tables — `sujets_releve` (l'heure du relevé), `sujets_ids` (pseudo → identifiant de chaîne, résolu une fois et gardé), `sujets_chaines` (une ligne par chaîne suivie, sa médiane par format, NULL quand elle n'a pas cinq vidéos du format), `sujets_videos` (une ligne par vidéo du classement, `rang` = le rang affiché, `video` unique) et `sujets_absentes` (les pseudos introuvables, dans l'ordre du relevé). `t` est vérifié par motif ET par `strftime` ; `bascules.nom` passe d'une liste fermée à un motif GLOB (SQLite ne modifie pas un CHECK, et douze migrations sont en cours), et `_reparer_bascules` refait une base restée sur l'ancienne liste, sans perdre une ligne (idempotent). - `etat_partage.py` : `sujets_lire` / `sujets_detail` / `sujets_remplacer`, en une transaction, et le REFUS d'un relevé qui n'a pas la forme du producteur (une clé manquante, un champ que la table ignore) : un classement vide est indistinguable du calme, le piège de STUD-52. - `_infra/etat-service.py` : `GET /sujets` (`{"releve": …}` — un relevé nu rendrait 404 sur une base vide), `GET /sujets/detail` (des comptes) et `POST /sujets/remplacer`. Aucun champ d'API existant ne change, et le front Svelte ne consomme pas ces routes. - `etat_client.py` : `sujets()`, `sujets_detail()`, `sujets_remplacer()`, puis `basculer sujets [--essai]` et `revenir sujets` — sans le verrou de montage : le montage n'a rien à voir avec ce relevé, et les montages tournent en continu (l'attendre rendrait la bascule impossible). Son écrivain vivant sur le 132, la bascule lit une copie désignée par `$ETAT_SUJETS` (absent, elle le dit et s'arrête, au lieu de basculer du vide). - `_tableau/socle.py` : l'accès au service d'état en `urllib` (une seule fois pour tous les fichiers d'état dont l'écrivain vit sur le 132, où `etat_client.py` n'est pas livré) et `sujets_ecrire`. Le FICHIER d'abord, toujours — c'est lui que la page lit —, la base ensuite quand la bascule est posée ; service muet alors que la bascule est CONNUE : « fichier-muet », et c'est DIT sur la sortie d'erreur. Aucun banc ne parle au service de production : hors du 132, il n'est appelé que si `STUDIO_ETAT_URL` le désigne (leçon du 13/10). - `_tableau/sujets.py` : la collecte écrit par le socle (la règle n'est pas recopiée fichier d'état par fichier d'état). Ce qui est lu ne change pas : `onglet_sujets.py` et `sujets.lire()` lisent toujours le fichier — une page qui interrogerait le service dépendrait d'un service muet à chaque rendu. Passé la bascule, le fichier est la COPIE que la page lit. Tests : `_tableau/test_sujets_bascule.py` (nouveau : base d'avant le nom refaite sans perte, essai sur le relevé réel, bascule, copie réécrite, `.bak-sqlite-<date>`, re-bascule, service muet, retour arrière) ; `_infra/test_etat_service.py` (les trois routes, le refus d'une forme fausse) ; `_tableau/test_sujets.py`, `test_onglet_sujets.py`, `test_serveur_suite.py`, `test_tableau_rendu.py` inchangés et verts. Suite complète (`lancer-tests.py --tout --sans-couverture`) : 169 bancs verts, 1 rouge — `test_accueil_parite.py`, déjà rouge sur `origin/main` avant ce correctif (vérifié sur un arbre neuf de `ae760c38`). Doc : `OUTILS.md`, `_tableau/LXC-132.md`.Fusionnée automatiquement par
fusion-auto(forge) : CI verte (Rust et Front Svelte), PR relue (étiquetterelu), sans conflit.