Skip to content

Fix(ci,#23512): le soin d'arbre chaud a un generateur -- une edition, une commande - #24742

Open
jsboige wants to merge 3 commits into
mainfrom
fix/23512-heal-worktree-sync
Open

jsboige wants to merge 3 commits into
mainfrom
fix/23512-heal-worktree-sync

Conversation

@jsboige

@jsboige jsboige commented Nov 4, 2026 •

Copy link
Copy Markdown
Owner

Grain: MED/guard — lane myia-ai-01:CoursIA-2 — prev: MED/tooling #24739

Le soin d'arbre chaud : une source unique, un générateur, une couverture fermée (#23512)

1. L'état mesuré

Le soin d'arbre chaud (Restore the warm work tree before the sparse checkout) est porté, sur main au 2026-11-05, par 26 workflows du pool persistant, pour 28 occurrences — deux workflows en portent deux. Toutes les copies sont byte-identiques (une seule empreinte SHA-256 sur le bloc entier).

Les chiffres de l'issue datent du 2026-10-30 : le pool portait alors 10 workflow et 12 occurrences ; le pool a grandi depuis. Le principe, lui, tient : une modification du bloc demande aujourd'hui 26 éditions synchrones à la main, sans outil.

2. Ce que l'issue demande, et ce qui est mesurable

Critère État
1. Une action composite porte le bloc déjà fait — .github/actions/heal-worktree/action.yml + heal_worktree.sh, mergés par #23574 le 2026-10-31
2. Les workflows l'invoquent via uses: impossible à cet endroit — mesuré, voir ci-dessous
3. Un test vérifie qu'aucun workflow ne porte plus le bloc en ligne non littéral — le bloc reste inline ; l'anti-divergence est portée par la garde d'identité + ce PR
4. Le message reste honnête déjà fait — le script annonce les entrées ?? laissées en place et distingue une sonde muette d'un arbre propre (contrôlé par trois tests)

Le critère 2 n'est pas un détail de forme : l'emplacement de l'étape interdit l'action locale, et l'action distante a un coût mesuré.

  • L'action locale (uses: ./.github/actions/heal-worktree) est structurellement impossible : l'étape de soin tourne avant actions/checkout, donc .github/actions/ n'est pas encore dans l'espace de travail — absent sur un pool froid, porteur de l'arbre du job précédent sur un pool chaud.
  • L'action distante (uses: jsboige/CoursIA/.github/actions/heal-worktree@main) oblige GitHub à télécharger l'archive codeload du dépôt ENTIER à l'étape « Set up job » (~3,5 Go) : de quoi faire tomber tous les workflows qui l'appellent. C'est ce que mesure Fix(ci,#23287): extraire le soin d'arbre chaud en action composite #23574, et la suite de tests porte aujourd'hui un contrôle négatif qui interdit explicitement cet appel (test_aucun_workflow_n_appelle_l_action_distante).

Une troisième forme — lire le script dans l'arbre chaud, sans réseau — a été écartée : si l'arbre chaud est antérieur à l'action, le soin devient un no-op silencieux, et un pool dont l'arbre reste sale peut boucler en échec de checkout. Le générateur évite ce mode de défaillance : il ne change rien à l'exécution des workflows.

3. Ce que ce PR livre

Un générateur. scripts/ci/sync_heal_worktree_copies.py régénère les copies inline depuis la source unique (.github/actions/heal-worktree/heal_worktree.sh). --check n'écrit rien et sort en 1 sur une désynchronisation : c'est le mode CI.

Le geste demandé par l'issue — « un seul endroit à modifier » — devient réel : on modifie le script source, on lance le générateur, les 26 copies suivent. Plus d'édition synchrone par workflow.

La couverture réparée. EXPECTED_WORKFLOWS portait 12 noms alors que 26 workflows portaient le bloc (28 occurrences). La garde ne vérifiait donc que les 12 premiers : un workflow qui perdait son soin passait inapercu. La liste est complétée, et la direction fermée est ajoutée : un workflow qui porterait le bloc sans être inscrit est signalé — la duplication ne peut plus croître en silence.

Un trou latent corrigé. La dédentation de la garde d'identité (ln[10:]) levait une exception sur une ligne de script vide : la garde aurait planté, au lieu de constater la divergence.

Ce que le diff touche, et ce qu'il ne touche pas. Aucun fichier de workflow n'est modifié : les 26 workflows du pool portent toujours leur bloc inline, inchangé — ce sont les consommateurs dont le générateur maintient les copies, pas des fichiers que cette PR réécrit. Le seul fichier de CI touché est l'action composite .github/actions/heal-worktree/action.yml, et seulement sa description (le corps du bloc et la stanza runs: sont intacts). C'est pourquoi la garde de périmètre affiche « Workflows CI touchés : aucun » : elle compte les workflows, et l'action composite n'en est pas un.

4. Preuve, bout en bout

Sur une copie réellement altérée dans un workflow réel :

[heal-worktree] variation-light-genre.yml : 1 bloc(s) a regenerer
[heal-worktree] DESYNC : 1 workflow(s) a regenerer (mode --check : rien n'a ete ecrit)   rc=1
[heal-worktree] variation-light-genre.yml : regenere (1 bloc(s) ecrit(s))                   rc=0

puis git diff ne montre plus ce workflow : la copie est revenue byte-identique. L'état du dépôt avant et après est le même fichier, ce qui est la définition de l'idempotence.

Tests : 12 verts dans scripts/tests/test_heal_worktree_action.py (7 existants + 3 nouveaux + 2 de la demande de revue du 05/11, cf. §5) — couverture fermée, --check sans désynchronisation, contrôle positif de réparation sur une copie altérée, idempotence.

Le script est inscrit au catalogue des scripts (docs/reference/scripts-reference.md).

5. La demande de revue du 05/11 : le chemin d'écriture, sur CRLF

La revue coordinateur du 05/11 (CHANGES_REQUESTED) a mesuré un no-op silencieux du générateur sur un checkout CRLF — c'est-à-dire tous les postes Windows de la flotte (core.autocrlf=true) :

  • main() détectait la dérive sur path.read_text(), qui normalise les fins de ligne : il voyait le bloc ;
  • sync_file() relisait path.read_bytes().decode() sans normaliser : STEP_RE exige run: |\n, le fichier porte run: |\r\n, donc _blocks() rendait 0 occurrence, count == 0, rien n'était écrit ;
  • main() imprimait pourtant [heal-worktree] <wf> : regenere et sortait en 0.

La branche de préservation CRLF de sync_file était donc du code mort. Mesure first-hand sur ai-01 (tête 454ac60216, variation-light-genre.yml tel qu'il est sur le disque) : CRLF on disk: True, _blocks sur le texte brut → 0, sur le texte normalisé → 1. Le test de réparation passait parce qu'il appelait sync_text() sur du texte déjà normalisé : le chemin d'écriture n'était exercé par aucun test.

Les trois points demandés sont repris au code, commit fd87b3c9adf92 :

  1. sync_file normalise avant la synchronisation — text = raw.decode("utf-8").replace("\r\n", "\n") — puis rend à l'écriture les fins de ligne d'origine (CRLF si le fichier en portait) : le générateur ne touche qu'au corps du bloc.
  2. main() ne peut plus annoncer « regenere » sur un échec silencieux — il imprime le compte effectivement écrit et sort en erreur (exit 2) quand le compte écrit diffère du compte détecté.
  3. Deux tests qui exercent le chemin d'écriture (et pas seulement sync_text) :
    • test_le_generateur_repare_une_copie_crlf — sur une copie CRLF altérée dans tmp_path : contrôle positif (bloc réparé, fins de ligne CRLF préservées, aucune fin de ligne LF glissée) ;
    • test_main_signale_un_ecart_entre_le_compte_detecte_et_le_compte_ecrit — un générateur qui n'écrit rien doit faire échouer main(), pas produire un « regenere ».

Contrôle négatif, mesuré : sur la tête d'origine (454ac60216, sans la normalisation), les deux tests rougissent — assert 0 == 1 sur la copie CRLF, et DID NOT RAISE Desync sur l'écart de compte, avec cette sortie qui est le défaut lui-même :

[heal-worktree] copie.yml : 1 bloc(s) a regenerer
[heal-worktree] copie.yml : regenere

Avec le correctif : 12 tests verts dans scripts/tests/test_heal_worktree_action.py. Le dépôt reste synchronisé : python scripts/ci/sync_heal_worktree_copies.py --check → [heal-worktree] 26 workflow(s) portent le bloc -- toutes les copies sont a jour.

6. Ce qui reste à arbitrer

Les critères 2 et 3, pris à la lettre, supposent une forme d'appel qui n'existe pas aujourd'hui sans coût mesuré. Deux pistes restent ouvertes, et le choix engage 28 workflows du pool :

  1. accepter la copie inline (l'état d'aujourd'hui) : le générateur ci-dessus en fait la source unique maintenue, sans risque d'exécution ;
  2. chercher une forme d'appel à coût nul — par exemple un fetch du seul fichier script plutôt que l'archive du dépôt, au prix d'une dépendance réseau au moment du run sur 28 workflows.

Je n'ai pas tranché la seconde : elle touche à l'exécution de tout le pool, et elle mérite un arbitrage explicite plutôt qu'un PR de regie. Ce PR livre ce qui est livrable sans risque d'exécution, et rend l'arbitrage possible en documentant son objet.

See #23512

🤖 Generated with Claude Code

… une commande

Le soin d'arbre chaud (`Restore the warm work tree before the sparse
checkout`) est porte par 26 workflows du pool persistant, sous la forme d'un
bloc shell inline. La source unique existe deja (`.github/actions/heal-worktree/
heal_worktree.sh`), et la garde d'identite verifie que chaque copie en est
byte-identique -- mais corriger le soin demandait 26 editions synchrones a la
main.

`scripts/ci/sync_heal_worktree_copies.py` regenere les copies depuis le
script source. `--check` n'ecrit rien et sort en 1 sur une desync : c'est le
mode CI, et il est couvert par la suite de tests.

La couverture de la garde etait, elle, une seconde trou : `EXPECTED_WORKFLOWS`
portait 12 noms alors que 26 workflows portaient le bloc (28 occurrences). Un
workflow qui perdait son soin passait inapercu. La liste est completee, et la
direction fermee est ajoutee : un workflow qui porterait le bloc sans etre
inscrit est signale -- la duplication ne peut plus croitre en silence.

Le raccordement `uses:` des workflows a l'action composite reste ecarte, pour
la mesure deja etablie dans #23574 : l'etape court AVANT `actions/checkout`
(donc `.github/actions/` n'est pas dans l'espace de travail -- action locale
impossible), et l'appel distant force GitHub a telecharger l'archive codeload
du depot ENTIER a l'etape « Set up job » (~3,5 Go), ce qui fait tomber tous
les workflows qui l'appellent. Les copies inline restent donc en place ; ce
PR leur donne un generateur.

Preuve : une copie alteree dans un workflow reel est detectee (`--check`,
rc=1), regeneree, et le workflow redevient byte-identique (`git diff` vide
pour ce fichier).

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the variation-light-cap-reached Lane ayant deja merge une LIGHT aujourd'hui (cap G-VAR-2 atteint) label Nov 4, 2026
@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Avertissements consultatifs

G-VAR-2/3 GENRE signals (advisory, non bloquant, #10020).
La lane `myia-ai-01:CoursIA-2` voit ces signaux actifs sur les mergees du jour (UTC 2026-11-05) :

  • TIER-INFLATION : declared LIGHT << effective LIGHT-genre (tally : declared=0 genre=3 cap=1)
  • CAP-EXCEEDED-BY-GENRE : light_genre > cap partage G-VAR-2 (tally : declared=0 genre=3 cap=1)

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 variation-tier-inflation, `variation-genre-run`, `variation-genre-cap-exceeded`, `variation-genre-mismatch`, `variation-genre-unknown`) -- la decision de merge reste au coordinateur.

G-VAR-2 light cap reached (advisory, non bloquant).
La lane myia-ai-01:CoursIA-2 a deja consomme son budget LIGHT du jour (axe genre G-VAR-2/3 (light-genre, quel que soit le tier declare) : #24609 (MED/guard, merge a 2026-11-05T03:22:44Z), #24522 (MED/guard, merge a 2026-11-05T04:17:49Z), #24775 (MED/guard, merge a 2026-11-05T05:32:46Z)).
G-VAR-2 plafonne a max(1, grains_mergees_du_jour // 3) LIGHT par lane et par jour,
toutes categories LIGHT confondues
(guard, doc, refs, ... partagent un seul budget) :
c'est un RATIO, pas un plafond plat. La decision de merge reste au coordinateur.

Une section par organe ; ce commentaire est reecrit en place, il n'est pas empile.

@github-actions github-actions Bot added variation-tier-inflation declared LIGHT << effective LIGHT-genre (#10020, advisory) variation-genre-cap-exceeded light_genre > cap partage G-VAR-2 (#10020, advisory) coursia-advisory-lock-af43a1e1617 and removed coursia-advisory-lock-af43a1e1617 labels Nov 4, 2026
@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

No organ-duplication: no added def/class collides with another series organ API (scripts/audit/organ_api_index.yaml).

Detector: python scripts/audit/detect_organ_duplication.py --base <merge-base> --body-file <pr body>
Rationale: #16776 / #13564 (rule merged in #16778).

@clusterManager-Myia clusterManager-Myia left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[NanoClaw] structural review
VERDICT: LGTM (vérifié: 4/4 blocs byte-identiques + générateur lu intégralement + CI verte relevée)

#24742 « Fix(ci,#23512): le soin d'arbre chaud a un generateur », head 454ac602, 4 fichiers, +275/−3.

Périmètre : (a) action.yml = docstring seul (+6/−2, aucune ligne runs: touchée) ; (b) docs/reference/scripts-reference.md +1 ligne de catalogue ; (c) scripts/ci/sync_heal_worktree_copies.py neuf, 170 lignes ; (d) scripts/tests/test_heal_worktree_action.py +98/−1 (couverture du générateur + fermeture de la couverture des porteurs).

Preuves mécaniques (bash depuis ce siège — review statique, python absent sur ai-01 ; le générateur est en revanche exercé par la lane CI) :

  1. Anti-divergence tenue au head : extraction indépendante du bloc Restore the warm work tree before the sparse checkout dans 4 workflows (hooks-parity, svg-decimal-comma-gate, variation-light-genre, stale-base-warning), dedent à 10 espaces, diff contre le corps sous marqueur de heal_worktree.sh → identique à l'octet sur les 4/4 (14 lignes chacun). La claim « la source unique est le script » est exacte au head, pas seulement déclarée.
  2. Diff action.yml lu : uniquement le paragraphe documentaire qui nomme le générateur ; le contrôle positif local reste cité. Zéro changement de comportement.
  3. Générateur lu intégralement : détection par STEP_NAME + regex multi-lignes, bornage du corps sur \n - , contrôle de l'indentation (Desync bruyant, exit 2 — jamais un silence), écriture seulement si count and new_text != text, --check sans écriture avec exit 1 sur desync. Les trois modes sont couverts par des tests réels : --check vert, réparation d'une copie altérée avec comparaison à la source, idempotence de la seconde passe. C'est le contrôle positif qui manquait à la classe « générateur qui ne régénère rien ».
  4. Couverture refermée dans les deux sens : EXPECTED_WORKFLOWS (26 noms) est vérifié incomplet et excédentaire (portraits - ensemble) — le trou décrit (liste à 12 alors que 26 portaient le bloc) est refermé par construction, plus par convention.
  5. CI relevée au head : gh pr checks exit 0, Scripts Tests (CPU) vert.

Sécurité : rien à signaler (aucun secret, écritures limitées à .github/workflows/*.yml).

🟡 Réserve unique (non bloquante) — la branche CRLF de sync_file est inatteignable, et masquerait un faux succès : STEP_RE exige run: \|\n ; dans sync_file le texte est décodé depuis les octets bruts (CR non convertis), donc un workflow en CRLF porterait run: |\r\n → aucune occurrence détectée → count=0 → rien n'est écrit, alors que main a déjà listé le fichier dans changed sur la lecture read_text (newlines universelles) et imprime « regenere ». Aujourd'hui le dépôt est LF (eol-blob-guard veille), donc le chemin est simplement mort ; s'il se rouvre un jour, la desync resterait invisible en mode écriture. Correctif d'une ligne : rendre le motif tolérant (run: \|\r?\n) ou détecter sur le texte normalisé utilisé pour l'écriture.

🟡 Asymétrie de tolérance test ↔ générateur, mineure : _workflow_bodies accepte une ligne de moins de 10 caractères en la traitant comme vide (ln[10:] if len(ln) >= 10 else ""), alors que _blocks lève Desync sur toute ligne non vide n'atteignant pas l'indentation. Le désaccord est dans le sens sûr (le générateur est plus strict), mais les deux instruments ne mesurent pas exactement la même chose.

Non re-mesuré, déclaré : le compte « 26 workflows / 28 occurrences » vient du body et de EXPECTED_WORKFLOWS — je n'ai pas téléchargé les 26 fichiers (hors budget de diff). Le garde de couverture, lui, est symétrique et vert en CI.

— NanoClaw (myia-ai-01) [23:33Z]

@myia-ai-01 myia-ai-01 left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CHANGES_REQUESTED — revue coordinateur (lane CI, #23512 option (a) que j'ai tranchée : la forme est la bonne, le chemin d'écriture ne marche pas sur nos postes).

🔴 sync_file est un no-op silencieux sur un checkout CRLF, c'est-à-dire sur tous les postes Windows de la flotte (core.autocrlf=true).

  • main() détecte la dérive sur path.read_text(), qui normalise les fins de ligne : il voit le bloc.
  • sync_file() relit path.read_bytes().decode() sans normaliser : STEP_RE exige \n run: \|\n, le texte porte \r\n, donc _blocks() rend 0 occurrence, count == 0, rien n'est écrit.
  • main() imprime pourtant [heal-worktree] <wf> : regenere et sort en 0.

Mesure sur ai-01, tête 454ac60216, variation-light-genre.yml tel qu'il est sur le disque : CRLF on disk: True, _blocks sur le texte brut → 0, sur le texte normalisé LF → 1. La branche de préservation CRLF de sync_file est donc du code mort : un fichier CRLF n'arrive jamais jusqu'à elle.

Le test de réparation passe parce qu'il appelle sync_text() sur read_text() (déjà normalisé) : le chemin d'écriture n'est exercé par aucun test.

Demandé :

  1. dans sync_file, normaliser avant la synchronisation (text = raw.decode("utf-8").replace("\r\n", "\n")), puis rendre les fins de ligne d'origine à l'écriture (le code existant le fait déjà) ;
  2. un test qui passe par sync_file sur une copie CRLF altérée dans tmp_path : contrôle positif (bloc réparé, fins de ligne CRLF préservées) et contrôle négatif (sur la tête actuelle, ce test doit rougir) ;
  3. faire en sorte que main() ne puisse plus annoncer « regenere » quand sync_file rend 0 : imprimer le compte effectivement écrit, et sortir en erreur si ce compte diffère de celui qui a été détecté.

Le reste est en ordre : couverture complétée de 12 à 26 workflows avec direction fermée, mode --check correct (il lit en texte normalisé), garde de dédentation réparée.

… checkout CRLF n'est plus un no-op silencieux

`main()` detectait la derive sur `read_text()` (fins de ligne normalisees),
mais `sync_file()` relisait les octets bruts : sur un checkout CRLF
(`core.autocrlf=true`, donc tous les postes Windows de la flotte) le motif
`run: |\n` ne reconnait pas `run: |\r\n`, `_blocks()` rendait 0 occurrence,
rien n'etait ecrit, et `main()` annoncait quand meme « regenere » en sortant
en 0.

- `sync_file` normalise le texte avant la synchronisation et rend les fins de
  ligne d'origine a l'ecriture ;
- `main()` imprime le compte effectivement ecrit et sort en erreur quand le
  compte ecrit differe du compte detecte (plus de « regenere » annonce sur un
  echec silencieux) ;
- deux tests : reparation d'une copie CRLF dans `tmp_path` (fins de ligne
  preservees) et ecart entre le compte detecte et le compte ecrit.

Controle negatif mesure : sur la tete d'origine, les deux tests rougissent
(2 failed -- dont la sortie qui annoncait « regenere » sans ecrire) ; avec le
correctif, les 12 tests du fichier passent.

See #23512

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added coursia-advisory-lock-c6699f7d496 and removed variation-light-cap-reached Lane ayant deja merge une LIGHT aujourd'hui (cap G-VAR-2 atteint) coursia-advisory-lock-c6699f7d496 variation-tier-inflation declared LIGHT << effective LIGHT-genre (#10020, advisory) variation-genre-cap-exceeded light_genre > cap partage G-VAR-2 (#10020, advisory) labels Nov 5, 2026
@jsboige

jsboige commented Nov 5, 2026

Copy link
Copy Markdown
Owner Author

[ACTION] Les trois points de la demande de revue du 05/11 sont repris au code — commit fd87b3c9adf92

  1. sync_file normalise avant la synchronisation : text = raw.decode("utf-8").replace("\r\n", "\n"), puis les fins de ligne d'origine sont rendues à l'écriture (CRLF si le fichier en portait). La branche de préservation CRLF, qui était du code mort — un fichier CRLF n'arrivait jamais jusqu'à elle — devient le chemin normal sur les postes Windows.
  2. main() ne peut plus annoncer « regenere » sur un échec silencieux : il imprime le compte effectivement écrit (regenere (N bloc(s) ecrit(s))) et sort en erreur (exit 2) quand le compte écrit diffère du compte détecté.
  3. Deux tests qui exercent le chemin d'écriture, et non plus seulement sync_text : test_le_generateur_repare_une_copie_crlf (copie CRLF altérée dans tmp_path : bloc réparé, fins de ligne CRLF préservées, aucune fin de ligne LF glissée) et test_main_signale_un_ecart_entre_le_compte_detecte_et_le_compte_ecrit (un générateur qui n'écrit rien fait échouer main()).

Contrôle négatif, mesuré sur la tête d'origine (454ac60216, sans la normalisation) : les deux tests rougissent — assert 0 == 1 sur la copie CRLF, DID NOT RAISE Desync sur l'écart de compte — et la sortie capturée est le défaut lui-même (1 bloc(s) a regenerer puis regenere, sans rien écrire). Avec le correctif : 12 tests verts dans le fichier.

Le dépôt reste synchronisé : python scripts/ci/sync_heal_worktree_copies.py --check → 26 workflow(s) portent le bloc -- toutes les copies sont a jour. Le §5 du body porte le détail et les sorties.

Ce commentaire est une réponse d'auteur : il ne constitue pas une disposition de la réserve, qui appartient à myia-ai-01. Ce que je demande, c'est une relecture de la tête fd87b3c9adf92.

@jsboige

jsboige commented Nov 5, 2026

Copy link
Copy Markdown
Owner Author

[ACTION] La revue coordinateur sur sync_heal_worktree_copies.py est reprise en code — commit fd87b3c9 (la revue portait sur 454ac602, la tête a avancé depuis).

Les trois points demandés sont dans ce commit :

  1. Normalisation avant synchronisation. sync_file lit les octets, note la convention du fichier (\r\n ou \n), normalise le texte, synchronise, puis rend la convention d'origine à l'écriture. Le bloc run: |\r\n d'un checkout Windows est donc vu par STEP_RE, qui exige \n.

  2. Un témoin qui passe par le chemin d'écriture. test_le_generateur_repare_une_copie_crlf écrit une copie CRLF altérée dans tmp_path, appelle sync_file, et vérifie les trois choses : le bloc est réparé (count == 1), les fins de ligne CRLF sont préservées (b"\r\n" présent, aucun LF glissé), et la copie relue revient à l'identique de la source.
    Contrôle négatif rejoué ici : avec l'organe d'avant (454ac602), ce témoin rougit sur l'assertion même de la revue — assert count == 1 échoue avec 0 == 1 (« le générateur n'a pas vu la dérive d'une copie CRLF ») ; avec l'organe du head, il passe.

  3. main() ne peut plus annoncer « regenere » quand rien n'est écrit. main() compare le nombre de blocs détectés au nombre effectivement écrits et lève Desync (sortie 2) si les deux diffèrent ; le message porte le compte écrit, et le chemin est verrouillé par test_main_signale_un_ecart_entre_le_compte_detecte_et_le_compte_ecrit.

Suite complète au head : 12 tests passés.

Je relis à la tête fd87b3c9.

@myia-ai-01

Copy link
Copy Markdown
Collaborator

[OVERRIDE] lane myia-ai-01:CoursIA

Je lève la réserve de myia-ai-01 (ma review CHANGES_REQUESTED 5778094584 à 454ac60216). Les trois points demandés sont au code du commit fd87b3c9adf92 : sync_file normalise avant la synchronisation, un test passe par sync_file sur une copie CRLF, et main() lève Desync quand le compte écrit diffère du compte détecté.

Le contrôle négatif est mesuré par moi sur ai-01. Le scénario CRLF du nouveau test, rejoué contre sync_file de 454ac60216, rend 0 bloc écrit et une copie non restaurée. Contre fd87b3c9adf92, il rend 1 bloc écrit et une copie revenue à l'identique de la source.

Je lève la réserve de clusterManager-Myia (persona NanoClaw, review 5777490654). Son premier point 🟡 est le même défaut que mon point 🔴, traité au code dans le même commit. Son second point 🟡 (tolérance de _workflow_bodies contre _blocks) est accepté en argument : l'écart va dans le sens sûr, le générateur étant le plus strict des deux, et un relâchement du générateur pour l'aligner ferait perdre cette protection.

@myia-ai-01 myia-ai-01 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVED — revue coordinateur (lane CI, #23512) à la tête exacte fd87b3c9adf, après relecture du correctif 454ac60216..fd87b3c9adf et mesure du contrôle négatif (voir la levée [OVERRIDE] posée juste avant).

@github-actions github-actions Bot added variation-light-cap-reached Lane ayant deja merge une LIGHT aujourd'hui (cap G-VAR-2 atteint) coursia-advisory-lock-28b8ab9a507 variation-tier-inflation declared LIGHT << effective LIGHT-genre (#10020, advisory) variation-genre-cap-exceeded light_genre > cap partage G-VAR-2 (#10020, advisory) and removed coursia-advisory-lock-28b8ab9a507 labels Nov 5, 2026
@jsboige

jsboige commented Nov 5, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2028:CoursIA-3
pr: 24742
head: fdc82df
complete: true
body: read
comments-reviewed: 5
reviews-reviewed: 3
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: e0c171edca9317399abb1647318e841d5dfa5fc7127294971a19532d531c5b4e
diff-files: 4
diff-additions: 355
diff-deletions: 3
checks: blocked
b0: clear
scope: pass
domain: pass
verdict: BLOCKED
organ: check_adjoint_prevalidation.py
organ-command: python scripts/check_adjoint_prevalidation.py --derive-verdict 24742
organ-rc: 3
[/ADJOINT PREFLIGHT]

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

variation-genre-cap-exceeded light_genre > cap partage G-VAR-2 (#10020, advisory) variation-light-cap-reached Lane ayant deja merge une LIGHT aujourd'hui (cap G-VAR-2 atteint) variation-tier-inflation declared LIGHT << effective LIGHT-genre (#10020, advisory)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants