Skip to content

curriculum(#13844): garde fail-closed du générateur parcours — refuser d'écraser un fichier sans header FICHIER GENERE #15882

Description

@jsboige

Part of #13844 (issue fille, suggérée par l'arbitrage #15821 — cf. commentaire myia-ai-01 « Le défaut de classe, qui survit à cet arbitrage »)

Le défaut de classe

docs/curriculum/ mélange deux régimes de propriété indiscernables : cinq pages générées (ids du dict PARCOURS de scripts/notebook_tools/generate_parcours.py, réécrites chaque jour par catalog-cron.yml) et des pages manuelles (_inventory.md, stage5_mamba_ssm.md, et bientôt les pages narratives des pilotes Phase 2). Rien dans le nom ni l'arborescence ne les distingue.

#15821 a traité le symptôme (le pilote 4 visait trading.md, un id généré — cible renommée trading-narratif.md). Le risque de classe survit : toute page manuelle créée sous un nom d'id du dict est écrasée silencieusement au passage du cron suivant — sans PR, sans diff, sans rouge.

Correctif proposé (voie 1 de l'arbitrage, la moins invasive)

Le générateur refuse d'écrire un fichier cible qui ne porte pas déjà son header FICHIER GENERE (fail-closed) : il ne peut plus écraser une page manuelle, quel que soit son nom.

Alternative (voie 2) : descendre les pages générées dans docs/curriculum/_generated/ — frontière visible dans le chemin, mais casse les liens existants (PARCOURS.md, docs/README.md, MyIA.AI.Notebooks/README.md).

Acceptance

  1. generate_parcours.py (ou le chemin d'écriture du cron catalogue) échoue explicitement si le fichier cible existe ET ne porte pas le header FICHIER GENERE.
  2. Test : un fichier stub sans header sous un id du dict → écriture refusée avec message nommant le fichier ; un fichier absent ou portant le header → régénération normale.
  3. Le cron catalog-cron.yml propage l'échec (rouge visible), pas de contournement silencieux.

Genre : MED/guard-tooling.

Activity

  1. jsboige commented on Sep 13, 2026

    @jsboige
    OwnerAuthor

    [CLAIMED] #15882 — myia-po-2026:CoursIA — 2026-09-13T01:29Z — garde fail-closed du generateur parcours : voie 1 (refus d'ecraser un fichier cible sans header FICHIER GENERE), les 3 acceptance (refus explicite nommant le fichier / header ou absent = regen normale / propagation de l'echec au cron, pas de contournement silencieux) -- paths: scripts/notebook_tools/generate_parcours.py, scripts/tests/test_generate_parcours_failclosed.py (nom a confirmer contre l'arborescence de tests existante a l'execution)

    Grain: MED/guard-tooling — lane myia-po-2026:CoursIA — prev: a verifier a la creation (derniere PR mergee de la lane)

    Preflight 3 axes fait : 0 commentaire, timeline croisee uniquement par #15821/#15883 (contexte generateur, pas de livraison), gh pr list --search 15882 vide.

  2. jsboige commented on Sep 13, 2026

    @jsboige
    OwnerAuthor

    [DELIVERED] myia-po-2026:CoursIA — 2026-09-13T01:52Z — PR #15889

    Les 3 acceptance couvertes et prouvées :

    1. Refus explicite : la garde refuse par cible d'écrire un fichier existant sans l'en-tête FICHIER GENERE (fenêtre de scan = 15 premières lignes, pour qu'une page manuelle citant la phrase en milieu de corps n'opte pas par accident). Contrôle positif sur l'arbre réel : trading.md manuel → REFUS (fail-closed, #15882): …trading.md + exit 2, contenu intact, restauration vérifiée.
    2. Tests : 5 nouveaux (TestFailClosedWrite) — refus+préservation / page marquée régénérée / fichier absent créé / marqueur hors fenêtre ≠ opt-in / cible propre régénérée malgré cible sale. 27/27 sur le fichier, 264/264 voisins catalogue.
    3. Propagation cron : structurelle — catalog-cron.yml step set -euo pipefail (:123) invoque le générateur (:135) ; exit 2 ⇒ step rouge ⇒ job rouge. Zéro changement workflow, zéro contournement.

    Non-régression mesurée : regen complète sur l'arbre réel EXIT=0, 5/5 pages réécrites, git status docs/curriculum/ vide (byte-clean). Aucun artefact généré committé.

    Je ne ferme pas l'issue (règle worker) — la clôture automatique viendra du Closes #15882 au merge.

  3. added 2 commits that reference this issue on Sep 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions