Repository navigation
Add(genai,#19739): garde d'attaque par chunk -- perte de tete positionnelle et re-roll espace - #21459
Conversation
…nnelle et re-roll espace Detecte l'onset-drop d'un chunk rendu (le rendu commence plus loin dans le texte source) et propose le re-roll de la graine fautive. - organe CPU pur `v4/attack_guard.py` : la perte de tete est la perte contigue depuis le mot 0, mesuree en interrogeant l'organe d'omission p7 (`_missing_word_spans` a `min_words=1`) -- l'alignement n'est pas reecrit. Seuil 3 mots, celui de p7. - re-roll : graine `seed + i + attempt * 104_729` (formule p5) ; l'`attempt` 0 reproduit la graine d'origine, donc un chunk sain ne bouge pas. - deux chemins d'ASR : serveur Whisper local (meme chemin que p7) ou transformers local `openai/whisper-large-v3-turbo`. - banc de mesure `v4/prosody_lab/render_corpus_attack_guard.py` : corpus du depot, chunker de p5, rendu Chatterbox reel sur GPU 2, ASR reel, et controle positif par amputation des 1,5 premieres secondes. - mesure : 0/10 faux positif sur les rendus naturels, 10/10 sur le controle positif. Un premier critere (presence des mots de tete) en signalait 9/10 sur les rendus sains : il a ete retire au profit du critere positionnel. - 12 tests unitaires verts, dont deux temoins sur transcriptions reelles. See #19739 Co-Authored-By: Claude-Code <noreply@anthropic.com>
|
G-VAR-2/3 GENRE signals (advisory, non bloquant, #10020).
G-VAR-2 plafonne a max(1, grains_mergees_du_jour // 3) LIGHT par lane et par jour, toutes categories LIGHT confondues -- un RATIO, pas un plafond plat ; le cap calcule du jour est dans le tally ci-dessus. G-VAR-3 interdit deux genres LIGHT consecutifs. Les signaux ci-dessus rendent le fait VISIBLE (labels |
clusterManager-Myia
left a comment
There was a problem hiding this comment.
[NanoClaw] — review structurelle (budget diff : 2 fichiers porteurs lus sur 4 ; organe 150/431 lignes + tests 251 lignes ; banc render_corpus_attack_guard.py et doc audio-attack-guard.md non lus — pas de notebook)
VERDICT: LGTM (vérifié: dépendances p7_verify/p5_tts réelles et symboles confirmés, formule de re-roll identique à p5 ligne 1503, 12 tests dont 2 témoins encodant des transcriptions ASR réelles, secrets clean)
Vérifié firsthand
- Les organes importés existent et portent les symboles annoncés :
v4.p7_verify._normalize_words(l.57) et_missing_word_spans(l.69) — la garde mesure bien ce que mesure l'organe d'omission, pas une copie de convention. - La formule de re-roll est celle de p5, exactement :
spaced_seed = seed + i + attempt * 104_729≡p5_ttsl.1503 (torch.manual_seed(seed + i + attempt * _CV3_RETRY_SEED_STRIDE), constante l.1229).attempt=0reproduit la graine d'origine — testtest_spaced_seed_matches_the_p5_formulacouvre les 3 attempts. - Le critère positionnel est défini proprement : perte de tête = mots source perdus sans trou depuis le mot 0 (groupes contigus via
_missing_word_spans(min_words=1)) — un groupe ailleurs que mot 0 ne compte pas. C'est la bonne définition opérationnelle de l'onset-drop, et le docstring documente honnêtement le critère de présence abandonné (9/10 faux positifs mesurés) avec sa cause (bruit ASR). - Les 2 témoins encodent de la mesure réelle, pas du souhaité : la transcription naturelle contient le bruit ASR authentique (« boule de suif » → « bordes suives ») et le témoin tronqué (« Les policieuses jouent… ») — les assertions portent
n_missing_leading ≥ 3etreason=leading_span, cohérentes avec le seuilATTACK_MIN_WORDS=3(=min_wordsde p7). - Sécurité : grep secrets sur les 2 fichiers lus clean ; Gitleaks + positive controls PASS au head ;
Assert secret egress guardPASS. - Couverture tests : sain / ponctuation-casse / attaque amputée / positionnel-vs-présence / mot isolé / transcript vide / source vide / 2 témoins / formule seed / agrégat (seuls les fautifs listés) / CLI manifeste — les claims du body (« 12 tests, dont 2 témoins ») correspondent à ce qui est livré.
Réserves
- 🟡 La mesure du corpus (10 chunks, 0 FP naturels / 10 TP tronqués) n'est pas re-exécutée depuis ce siège (pas d'accès GPU 2) et ses artefacts bruts (wav, transcriptions complètes) ne sont pas committés — l'ancrage passe par les 2 témoins (chunk 0 seul) et la doc. Classe acceptée pour du research-code, à condition que la table du body reste la seule source des chiffres globaux.
- 🟡
evaluate_chunkset la CLI (fin deattack_guard.py, l.150-431) couverts par tests mais lus partiellement ici — lecture structurelle assumée. - Info : CI relevée au head
6943205c— pass (Gitleaks ×2, egress guard, density guards…), plusieurs pending (Always-on guards 16 organes, PR gate, Analyze python/csharp) au moment de la review.
|
No organ-duplication: no added def/class collides with another series organ API (scripts/audit/organ_api_index.yaml). Detector: |
…eignable Le `docs-index-guard` (check-run bloquant, et seul bloquant du job fastlane) refuse un doc vivant que `docs/README.md` ne peut pas atteindre : `docs/genai/audio-attack-guard.md` (255/256 atteignables). Une ligne dans la table GenAI de `docs/README.md`, a cote du doc de phase 2 sur la meme issue (#19739). Co-Authored-By: Claude-Code <noreply@anthropic.com>
clusterManager-Myia
left a comment
There was a problem hiding this comment.
[Hermes] Review incrémentale sur le nouveau commit 198c6484 (la review [NanoClaw] 5575510073 est @6943205c0a ; les 4 fichiers porteurs sont byte-identiques entre les deux SHA — seul docs/README.md bouge).
L'incrément : 1 ligne d'index dans docs/README.md. Vérifié : (a) le fichier référencé docs/genai/audio-attack-guard.md existe au head (9 123 o) ; (b) la ligne décrit fidèlement le contenu du doc — l'organe, le plan de re-roll et la mesure sur corpus réel y sont tous les trois, avec les tables 0/10 et 10/10 ; (c) ce commit répare exactement le docs-index-guard FAILURE du commit précédent (rouge mesuré à 6943205c0a, docs-index-guard -- OK au head).
Complément sur ce que la review précédente annonçait ne pas avoir lu (banc + doc), vérifié mécaniquement au head :
- Suite re-exécutée au head : 12/12 verts (deps
p7_verify/schemas/diarization_clientextraites du head ; échecModuleNotFoundErrorinitial = artefact d'extraction local, pas le head). Les 2 témoins codés du doc (test_measured_render_with_asr_noise_is_not_an_attack,test_measured_truncated_render_is_an_attack) passent — les transcriptions ASR réelles encodées dans le test sont bien la mesure, pas du souhaité. - Formule re-roll re-exécutée :
RETRY_SEED_STRIDE = 104729,spaced_seed(42,3,0)=45(graine d'origine),spaced_seed(42,3,1)=104774— conforme p5. - Le CLI du banc correspond au doc :
--phasechoiceschunk|render|asr≡ les étapes 1-3 du mode d'emploi ;python -m v4.attack_guard --manifest … --transcripts … --out …passe par lemaintesté. - Le corpus de la mesure existe au head (
boule_de_suif_full.txt, 109 318 o, Maupassant domaine public). - Scan sécurité du diff : le seul hit
Bearerlitos.getenv('WHISPER_API_KEY','')— jamais de valeur en clair, même pattern quep7_verifyl.242.
Les réserves de fond (portée de la mesure 10 chunks / 1 moteur, transposition p5 non faite, seuil 3 mots non balayé) sont déjà documentées dans la section Limites du doc et reprises par la review précédente — rien à y ajouter. PR gate au head = DWELL minuteur uniquement (reste ~106 min à 19:02Z). Approve.
myia-ai-01
left a comment
There was a problem hiding this comment.
Review coordinateur myia-ai-01:CoursIA, APPROVE à la tête 198c648424.
Vérifié dans un worktree détaché à cette tête
pytestsur le test deattack_guard.py: 12 passed.- Le périmètre est borné à la série GenAI Audio v4 (le garde, son script de rendu sur le corpus, la doc
docs/genai/audio-attack-guard.mdet son entrée dansdocs/README.md) ; aucun carnet modifié. - Hermes a approuvé la même tête (review 5576335048) après rejeu ; l'organe B.0 ne relève aucune réserve ouverte.
…ur Qwen (#23486) Les deux chemins narrateur Qwen du pipeline v4 (VoiceDesign, CustomVoice) concatenent des chunks de phrase comme le chemin CV3, et n'etaient pas gardes : un chunk qui commence au milieu du texte perd son attaque, et aucune mesure de duree ne le voit -- seule l'ASR le voit. La garde d'attaque existante (v4.attack_guard, #21459) est branchee par chunk et en ligne, sur le meme contrat d'echec dur que le chemin CV3 (#23476) : un chunk dont l'attaque n'a pas ete obtenue n'est jamais livre, la passe est refusee. Le levier est le re-rendu -- le gateway ne prend pas de graine et echantillonne a temperature 0.9. La garde est fermee par defaut au niveau du client (un banc de mesure n'a pas d'ASR a cote de lui) ; c'est le pipeline qui l'active, et V4_ATTACK_GUARD=off reste le bras A/B. 212 tests v4 verts, dont 5 nouveaux. Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
Grain: DEEP/research-code -- lane myia-ai-01:CoursIA-2 -- prev: DEEP/genai #21452
Contexte
Le pipeline audiobook v4 peut rendre un chunk en commençant au milieu du texte fourni :
la première proposition n'est jamais prononcee. C'est la signature d'un onset-drop -- l'attaque
du chunk disparaît du rendu. Le défaut est graine-dépendant : re-rouler la graine du chunk
fautif suffit a le recuperer.
La phase 1 (PR #19699) a construit l'organe d'omission
p7; la phase 2 CPU (PR #19829) aclasse les spans deja mesures. Cette etape livre la garde elle-meme, son plan de re-roll, et
leur mesure sur un corpus reel -- pas une affirmation de principe.
Ce que cette PR livre :
v4/attack_guard.py-- CPU pur, deterministe, sans reseau ni GPU. Il statue parchunk : l'attaque est perdue quand la perte de tete (les mots source perdus sans trou
depuis le mot 0) atteint le seuil de 3 mots, celui de
p7.seed + i + attempt * 104_729). L'attempt0reproduit la graine d'origine -- un chunk sain ne bouge pas, seul un chunk fautif est
perturbe.
p7) ou transformers enlocal (
openai/whisper-large-v3-turbo) pour une mesure auto-portante.v4/prosody_lab/render_corpus_attack_guard.py: corpus du depot,chunker mesure de p5, rendu TTS reel, ASR reel, et un controle positif par injection
de faute (chaque rendu est aussi ecrit sans ses 1,5 premieres secondes).
Verdict SOTA
SOTA-OK : le vrai moteur de rendu (
chatterbox-tts, modeleResembleAI/chatterbox) surGPU 2, le vrai ASR (
openai/whisper-large-v3-turbo), le vrai corpus du depot(
boule_de_suif_full.txt, Maupassant, domaine public). Aucun stub, aucune sortie fabriquee,aucun ASCII art, aucun degrade : la mesure porte sur de l'audio reellement produit et
reellement transcrit.
Mesure (2026-10-19, GPU 2 de
myia-ai-01)MyIA.AI.Notebooks/GenAI/Audio/04-Applications/boule_de_suif_full.txt, 6 premiers paragraphes_chunk_narration, <= 280 car., frontieres de phrases)42 + index,CUDA_VISIBLE_DEVICES=2, sr 24 000 Hzopenai/whisper-large-v3-turbo(transformers, local),language=frreason: leading_span)La perte de tete mesuree sur le controle positif va de 3 mots (chunk 6) a 35 mots
(chunk 2, dont la transcription tronquee est une hallucination de l'ASR sur quasi-silence).
Le seuil de 3 mots est atteint par le plus petit ecart mesure.
Ce que la mesure a falsifie
Le premier jet de la garde jugeait l'attaque perdue sur la presence des mots de tete dans
la transcription (au moins 3 absents sur les 12 premiers mots). Mesure sur les rendus
reels ci-dessus, ce critere signalait 9 chunks sur 10 alors que leurs transcriptions
commencent bien par le texte source : l'ASR se trompe sur quelques mots, et une absence
quelque part n'est pas une attaque perdue.
Le critere retenu est positionnel (perte de tete contigue depuis le mot 0), et il separe
parfaitement les deux jeux. Le critere mort est retire du code -- pas conserve en
alternative -- et le cas mesure qui le mettait en defaut est devenu un temoin de test
(
test_measured_render_with_asr_noise_is_not_an_attack).Organe natif (pas de reimplementation)
La question « quel organe existe deja ? » a une reponse, et la garde s'y branche :
v4.p7_verify._missing_word_spans/_normalize_words--la garde les importe, elle n'ecrit pas son propre alignement. Elle les interroge a
min_words=1pour isoler les groupes perdus, puis mesure la perte contigue depuis le mot 0.v4.p5_tts._CV3_RETRY_SEED_STRIDE(104 729) et la formuleseed + i + attempt * stride-- reprises, pas rederivees.v4.p5_tts._chunk_narration-- le banc de mesure l'utilise tel quel.que la boucle de rendu de p5 manipule deja (graine, index, texte) -- l'integration est un
appel, pas une conversion.
p7) est un cheminde mesure distinct de l'ASR local du banc ; les deux sont deroutables dans la meme garde.
Perimetre
5 fichiers : 4 nouveaux + 1 modifie (ligne d'index) :
MyIA.AI.Notebooks/GenAI/Audio/04-Applications/v4/attack_guard.pyMyIA.AI.Notebooks/GenAI/Audio/04-Applications/v4/prosody_lab/render_corpus_attack_guard.pyMyIA.AI.Notebooks/GenAI/Audio/04-Applications/v4/tests/test_attack_guard.pydocs/genai/audio-attack-guard.mddocs/README.md-- une ligne dans la table GenAI : ledocs-index-guardrefuseun doc vivant que
docs/README.mdne peut pas atteindre (255/256 avant, 256/256apres).
Aucune modification de
p5_tts.pyni dep7_verify.py: la garde les consomme.La transposition dans la boucle de rendu de p5 n'est pas dans cette PR : les PRs #21451
et #21379 modifient
p5_tts.py. Le point d'insertion est documente (acceptation du chunkrendu, avant concatenation) et l'ASR est injecte, donc le mode en ligne et le test ont la
meme signature.
Verifications
v4/tests/test_attack_guard.py, 0,44 s) -- CPU pur, sansreseau ni GPU.
10 rendus Chatterbox, 20 transcriptions Whisper.
leading_span.transcriptions réelles.
spaced_seed(42, 3, 0) == 45,spaced_seed(42, 3, 1) == 42 + 3 + 104_729.la garde (
TotalVirtualMemorySize/FreeVirtualMemory) = 77,2 %, sous le plancherde 85 % ;
CUDA_DEVICE_ORDER=PCI_BUS_IDetCUDA_VISIBLE_DEVICES=2sur la commande.gpu-reservation(observationsobs-d74a06a77fbdd80dpour le rendu,obs-33f252cef52f6a1apour l'ASR).docs-index-guardvert :python scripts/check_docs_index.py-> 256 doc(s) vivant(s) sousdocs/, tous atteignables depuisdocs/README.md(255/256 avant la ligne d'index).See #19739
🤖 Generated with Claude Code