Le registre des voix de Shorts passe dans la base du service d'état (voix-des-shorts, t_38768ade) #1701

Merged
hermes-fusion merged 1 commit from hermes/migration-voix-shorts-sqlite into main 2026-10-15 02:25:03 +02:00
Collaborator

Carte t_38768ade — la migration de _reseaux/voix-des-shorts.json (série de STUD-1107).

Cause. Le registre qui relie un Short YouTube à sa trace de voix n'avait qu'un foyer, un fichier du dépôt, et enregistrer le relisait puis le réécrivait en entier pour ajouter une ligne : la règle « un lien qui existe ne se réécrit pas » n'était tenue que par ce lire-modifier-réécrire, deux publieurs sortis en même temps (Crayon et Minute Chat en écrivent le même jour) pouvaient poser deux noms pour le même Short.

Remède.

  • etat_partage.sql : table voix_des_shorts, une ligne par lien, clé (compte, vid), un champ par valeur — pas de colonne fourre-tout JSON ; vid vérifié comme un identifiant YouTube, compte sans liste fermée (c'est garde_voix_short.CHAINES qui juge).
  • etat_partage.py : voix_des_shorts_lire / voix_des_shorts_remplacer / voix_des_shorts_poser (le refus de réécriture est fait en base, dans la même transaction que la lecture).
  • _infra/etat-service.py : GET /voix-des-shorts, POST /voix-des-shorts/poser, POST /voix-des-shorts/remplacer. Aucune route existante ne change et le front Svelte ne consomme aucune de ces routes : rien à prévenir côté svelte.
  • etat_client.py : client du registre, basculer voix-des-shorts [--essai] et revenir voix-des-shorts (essai sur une base jetable, .bak-sqlite-<date>, copie réécrite depuis la base, pas de verrou de montage).
  • _reseaux/garde_voix_short.py : enregistrer écrit le fichier toujours puis la base quand la bascule est posée ; nom_de_trace lit la base quand elle fait foi et retombe sur le fichier (tenu à jour) quand le service est muet, en le disant. Un service muet ne refuse jamais un Short dont la voix est prouvée ; STUDIO_ETAT_URL=local coupe tout appel, et les bancs du garde le posent.

Preuves.

  • python3 controle/test_etat_partage.py → ok 8 : voix-des-shorts — … puis TOUT PASSE.
  • python3 controle/test_voix_des_shorts.py → tout est conforme (24 points, dont 13 sur la migration).
  • python3 _infra/test_etat_service.py → OK : le service d'état répond sur chaque route….
  • Les 22 bancs concernés (controle/bancs_concernes.py) : verts, sauf controle/test_lui_epoques.py et controle/test_provenance.py, déjà rouges sur origin/main pour la même cause (cette machine voit /studio en NFS, un montage local y est refusé) — sorties comparées, identiques.
  • cargo test --release --locked : test result: ok partout, 77 tests passés, 0 échec ; cargo build --release --locked sans avertissement.

Non fait, volontairement. Aucune bascule n'a été posée sur le service de production : il est injoignable depuis le PC aujourd'hui (curl http://192.168.1.142:8799/bascules → Failed to connect), et ce n'est pas le rôle de la carte. Le comportement d'avant la bascule est celui de main : le fichier fait foi.

Carte `t_38768ade` — la migration de `_reseaux/voix-des-shorts.json` (série de STUD-1107). **Cause.** Le registre qui relie un Short YouTube à sa trace de voix n'avait qu'un foyer, un fichier du dépôt, et `enregistrer` le relisait puis le réécrivait en entier pour ajouter une ligne : la règle « un lien qui existe ne se réécrit pas » n'était tenue que par ce lire-modifier-réécrire, deux publieurs sortis en même temps (Crayon et Minute Chat en écrivent le même jour) pouvaient poser deux noms pour le même Short. **Remède.** - `etat_partage.sql` : table `voix_des_shorts`, une ligne par lien, clé `(compte, vid)`, un champ par valeur — pas de colonne fourre-tout JSON ; `vid` vérifié comme un identifiant YouTube, `compte` sans liste fermée (c'est `garde_voix_short.CHAINES` qui juge). - `etat_partage.py` : `voix_des_shorts_lire` / `voix_des_shorts_remplacer` / `voix_des_shorts_poser` (le refus de réécriture est fait en base, dans la même transaction que la lecture). - `_infra/etat-service.py` : `GET /voix-des-shorts`, `POST /voix-des-shorts/poser`, `POST /voix-des-shorts/remplacer`. **Aucune route existante ne change** et le front Svelte ne consomme aucune de ces routes : rien à prévenir côté `svelte`. - `etat_client.py` : client du registre, `basculer voix-des-shorts [--essai]` et `revenir voix-des-shorts` (essai sur une base jetable, `.bak-sqlite-<date>`, copie réécrite depuis la base, pas de verrou de montage). - `_reseaux/garde_voix_short.py` : `enregistrer` écrit le fichier **toujours** puis la base quand la bascule est posée ; `nom_de_trace` lit la base quand elle fait foi et retombe sur le fichier (tenu à jour) quand le service est muet, en le disant. Un service muet ne refuse jamais un Short dont la voix est prouvée ; `STUDIO_ETAT_URL=local` coupe tout appel, et les bancs du garde le posent. **Preuves.** - `python3 controle/test_etat_partage.py` → `ok 8 : voix-des-shorts — …` puis `TOUT PASSE`. - `python3 controle/test_voix_des_shorts.py` → `tout est conforme` (24 points, dont 13 sur la migration). - `python3 _infra/test_etat_service.py` → `OK : le service d'état répond sur chaque route…`. - Les 22 bancs concernés (`controle/bancs_concernes.py`) : verts, sauf `controle/test_lui_epoques.py` et `controle/test_provenance.py`, **déjà rouges sur `origin/main`** pour la même cause (cette machine voit `/studio` en NFS, un montage local y est refusé) — sorties comparées, identiques. - `cargo test --release --locked` : `test result: ok` partout, 77 tests passés, 0 échec ; `cargo build --release --locked` sans avertissement. **Non fait, volontairement.** Aucune bascule n'a été posée sur le service de production : il est injoignable depuis le PC aujourd'hui (`curl http://192.168.1.142:8799/bascules` → `Failed to connect`), et ce n'est pas le rôle de la carte. Le comportement d'avant la bascule est celui de `main` : le fichier fait foi.
Le registre des voix de Shorts passe dans la base du service d'état (voix-des-shorts)
All checks were successful
Tests du tableau (Rust + Svelte) / Rust (_tableau/rust) (push) Successful in 18s
Tests du tableau (Rust + Svelte) / Front Svelte (_tableau/front) (push) Successful in 13s
Tests du tableau (Rust + Svelte) / Rust (_tableau/rust) (pull_request) Successful in 21s
Tests du tableau (Rust + Svelte) / Front Svelte (_tableau/front) (pull_request) Successful in 12s
dfe2971fc6
Cause : `_reseaux/voix-des-shorts.json` — quel Short YouTube a été fabriqué avec quelle trace de
voix — n'avait qu'un foyer : un fichier du dépôt. `enregistrer` le relisait en entier puis le
réécrivait pour ajouter une ligne, et la règle « un lien qui existe ne se réécrit pas » n'était
tenue que par ce lire-modifier-réécrire : deux publieurs sortis en même temps (Crayon et Minute
Chat en écrivent le même jour) pouvaient poser deux noms pour le même Short. Le registre était le
dernier lien que le garde de voix lit avant chaque envoi TikTok, et il ne se lisait que par ce
fichier. C'est la migration « voix-des-shorts » de la série de STUD-1107.

Remède :

- `etat_partage.sql` : table `voix_des_shorts` — une ligne par lien, clé `(compte, vid)`, un champ
  par valeur, jamais de colonne fourre-tout JSON : le garde demande UN lien, et « un lien ne se
  réécrit pas » doit être vérifiable par la base. `vid` est vérifié comme un identifiant YouTube
  (onze caractères, alphabet de YouTube), `compte` comme la clé écrite par `_compte` (sans liste
  fermée : c'est `garde_voix_short.CHAINES` qui juge quel compte publie).
- `etat_partage.py` : `voix_des_shorts_lire` (la forme exacte du fichier), `voix_des_shorts_remplacer`
  (tout le registre, en une transaction) et `voix_des_shorts_poser` (un lien ; refuse un Short déjà
  relié à un autre nom, lecture et écriture dans la même transaction — ce que le fichier ne
  garantissait pas).
- `_infra/etat-service.py` : `GET /voix-des-shorts`, `POST /voix-des-shorts/poser` et
  `POST /voix-des-shorts/remplacer`. Aucune route existante ne change, et le front Svelte ne
  consomme aucune de ces routes.
- `etat_client.py` : `voix_des_shorts()`, `voix_des_shorts_poser()`, `voix_des_shorts_remplacer()`,
  puis `basculer voix-des-shorts [--essai]` et `revenir voix-des-shorts` — sans le verrou de
  montage (les voix n'ont rien à voir avec le montage, qui tourne en continu). Le chemin est celui
  du dépôt, à côté du client ; `$VOIX_DES_SHORTS` le remplace dans un banc. L'essai compare sur une
  base jetable, la bascule garde l'ancien en `.bak-sqlite-<date>`, réécrit la copie depuis la base
  et ne renomme rien tant que la comparaison n'est pas IDENTIQUE.
- `_reseaux/garde_voix_short.py` (l'écrivain, sur le PC comme dans le conteneur des agents) :
  `enregistrer` écrit le lien dans le fichier TOUJOURS, puis dans la base quand la bascule est
  posée ; `nom_de_trace` LIT la base quand elle fait foi, et retombe sur le fichier — tenu à jour
  par le même `enregistrer` — quand le service est muet, en le disant. Un Short dont la voix est
  prouvée n'est jamais refusé pour un réseau : la question au service est posée une fois par
  processus, avec un délai court, et le pire cas d'un service muet est un lien non partagé, jamais
  un lien perdu. Un banc ne parle pas au service de production : `STUDIO_ETAT_URL=local` coupe
  l'appel, et les bancs du garde le posent.

Tests : `controle/test_etat_partage.py` section 8 (essai IDENTIQUES, cinq formes refusées sans rien
toucher, bascule avec `.bak-sqlite` et copie réécrite, écriture et refus de réécriture dans la base,
retour arrière qui rend l'état en vigueur dans la forme du producteur, re-bascule) ;
`controle/test_voix_des_shorts.py` section 8 (sans bascule la base n'est ni lue ni écrite, basculée
le garde lit la base et `enregistrer` écrit les deux foyers, refus de la base dit, service muet qui
fait relire le fichier, service muet ET fichier absent qui refusent en le disant, `local` qui
n'appelle rien) ; `_infra/test_etat_service.py` (les trois routes, le refus d'une réécriture et des
formes fausses). Les 22 bancs concernés passent, sauf `controle/test_lui_epoques.py` et
`controle/test_provenance.py`, rouges sur `origin/main` avant ce correctif pour la même raison (cette
machine voit `/studio` en NFS, un montage local y est refusé) : sorties comparées, identiques.
`cargo test --release --locked` : 77 tests passés, 0 échec ; `cargo build --release --locked` sans
avertissement. Doc : `OUTILS.md`, `_tableau/LXC-132.md`.
hermes-fusion deleted branch hermes/migration-voix-shorts-sqlite 2026-10-15 02:25:03 +02:00
Collaborator

Fusionnée automatiquement par fusion-auto (forge) : CI verte (Rust et Front Svelte), PR relue (étiquette relu), sans conflit.

Fusionnée automatiquement par `fusion-auto` (forge) : CI verte (Rust et Front Svelte), PR relue (étiquette `relu`), sans conflit.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
foXaCe/studio!1701
No description provided.