Files
oto-enterprise-os-dtp/05_activity_log/2026-07-31.md
T

8.9 KiB
Raw Blame History

Activity Log · 2026-07-31 · Claude Code DTP

Session 20260731_005934 · Buffer S8 · Intégrité du câblage CI — le gate d'agrégat verrouille TOUS les jobs (gates statiques compris)

Tâche : Sprint 8 · buffer L75 (« Regression tests exhaustifs » · DevOps CI/CD). Roadmap fonctionnellement close (21/21 modules à 100/100, 534 tests verts, 5 gates statiques tous verts au démarrage). Poursuite de la série anti-dérive (INV4, fraîcheur matrice, reproductibilité artefacts) : recherche d'un trou de câblage réel plutôt qu'un correctif cosmétique.

Défaut trouvé — les gates STATIQUES n'étaient gardés par aucun invariant d'appartenance au gate

  • Constat : le job gate (needs: [...]) est le seul verrou de merge — un check absent de son needs: ne bloque rien, même rouge. Les deux couvertures existantes (audit_4big/registry.coverage_report, qa/regression/discovery. coverage_report) prouvent l'appartenance au gate uniquement pour les jobs de module (ceux portant un working-directory: sous 05_deliverables_mvp). Les 5 gates statiques (constraints-guard/validate-json/check-docs/ check-artifacts/check-regression → scripts ci/*.sh) n'ont pas de working-directory : rien ne garantissait qu'ils alimentent le gate. Retirer l'un d'eux de needs: (ou une typo dans la liste, ou un ci/*.sh décâblé) rendait le gate vert en se court-circuitant — même classe de dérive silencieuse que INV4 (orphan_tests_dirs), côté câblage CI.
  • Fix : nouveau gate ci/check_ci_integrity.sh (bash/awk/git, stdlib pur, zéro réseau) + job CI check-ci-integrity, lui-même ajouté à gate.needs. Deux invariants, lus par FAITS dans ci.yml (jamais une liste à la main) :
    • INV-A : gate.needs == { tous les jobs définis } { gate } { jobs manuels if: … workflow_dispatch …, ex. e2e-baseline légitimement hors du gate push/PR }. Détecte MISSING (job oublié → ne bloque pas), DANGLING (référence fantôme : typo / job supprimé) et MANUAL-IN-GATE (job manuel dans needs → gate en attente perpétuelle sur push).
    • INV-B : chaque ci/*.sh du dépôt est lancé par exactement un job (run: bash ci/<script>), lui-même dans gate.needs — un gate statique non câblé (script mort) ou décâblé casse le check.
  • Preuve de morsure (5 modes, tous exit 1) :
    • MISSING : check-artifacts retiré de needs✗ ABSENT de gate.needs + INV-B sur check_artifacts.sh ;
    • DANGLING : seo-testsseo-testz dans needs✗ référence 'seo-testz' non définie + ✗ seo-tests ABSENT ;
    • MANUAL-IN-GATE : e2e-baseline ajouté à needs✗ job manuel … gate en attente ;
    • SCRIPT-MORT : ci/check_phantom.sh commité sans job ⇒ ✗ lancé par AUCUN job ;
    • DÉCÂBLÉ : couvert par le mode MISSING (job hors needs). État nominal restauré ⇒ exit 0 (gate.needs = 28 jobs = 30 définis 1 (gate) 1 manuel [e2e-baseline]).

Non-régression : le nouveau job est statique (aucun working-directory) → comme les 5 autres, il n'entre pas dans la matrice de régression ni le registre audit_4big (dérivés des seuls jobs de module). Totaux 534/21 inchangés. Suites harnais OK : qa/regression (21 suites · 534), qa/audit_4big (21/21 · min 100), qa/acceptance (bijectif=True). ci.yml YAML valide.

Anti-invention (#6) : rien inventé — le gate relit ci.yml et recalcule les ensembles à chaque run (aucun compteur figé).

Vérifs : 6 gates statiques verts (guard_constraints/validate_json/ check_docs/check_artifacts/check_regression/check_ci_integrity) ; doc ci/README.md mise à jour (tableau des jobs, section 2 détaillée, exécution locale, checklist « 6 gates »).

Hors périmètre worker (VPS · #8) : néant (stdlib en-repo ; enregistrement du runner Gitea toujours du ressort DevOps).

Auto-score 4Big : 96/100.


Session 20260731_002924 · Buffer S8 · Intégrité de la matrice de régression (bug CI réel + invariant disque→CI)

Tâche : Sprint 8 · buffer L75 (« Regression tests exhaustifs » · DevOps CI/CD) — roadmap fonctionnellement close (21/21 modules gated à 100/100, 534 tests verts, 5 gates statiques). Recherche d'une incohérence de reproductibilité réelle plutôt qu'un correctif doc cosmétique. Deux défauts réels trouvés et corrigés, tous deux dans qa/regression.

Défaut #1 (PRIORITAIRE · bug CI réel) — le gate check-regression était cassé en checkout propre

  • Symptôme : ci/check_regression.sh (l.52-53) exige que qa/regression/out/regression_run.json existe dans le dépôt, puis compare un run frais à ce fichier commité (baseline byte-identique).
  • Contradiction : ce même fichier était .gitignoreé (« non déterministe (temps machine) → jamais commitée ») → jamais présent dans un checkout propre. Le job Gitea check-regression ne fait que checkout + bash check_regression.sh, aucune étape ne génère le fichier. Conséquence : le gate échouait sur CHAQUE run CI propre (artefact absent du dépôt). Il ne « passait » qu'en local, par la présence d'un regression_run.json non suivi laissé par un run manuel. Le commentaire de ci.yml disait déjà « le regression_run.json commité » — intention claire du commit précédent, jamais concrétisée (fichier resté ignoré).
  • Vérif de faisabilité (#1 analyser) : l'artefact run est byte-déterministe — clés {ran,passed,failures,...} + path relatif, aucun horodatage/hôte/ durée. Deux run successifs byte-identiques (vérifié). Le committer est donc licite et complète l'intention du gate.
  • Fix : run est désormais commité (baseline du gate) →
    • .gitignore : retrait de out/regression_run.json + note expliquant qu'il est commité parce que déterministe ;
    • README.md : section run réécrite (byte-déterministe · commité · baseline check_regression · distinction d'avec check_artifacts qui ne rejoue que build) ;
    • out/regression_run.json : ajouté au suivi (21 suites · 534 tests · PASS).
  • Preuve de morsure : fichier retiré (simule checkout propre) ⇒ gate exit 1 (artefact absent) — l'état exact en CI ; restauré ⇒ exit 0 (run == commité).

Défaut #2 (invariant manquant) — dérive silencieuse disque→CI non gardée

  • Gap : discovery.coverage_report prouvait le sens CI→disque (tout module gated a un tests/) mais pas l'inverse : un module gagnant un tests/ sur disque sans job CI n'entrait jamais dans la matrice, ses tests ne tournaient jamais, et la couverture ne le voyait pas (elle n'itère que les suites dérivées du CI) — la matrice restait « PASS » en sous-comptant en silence. Même classe de dérive que « demo 18→21 », direction opposée.
  • Fix : nouvel invariant INV4
    • discovery.disk_test_modules() : marche disque pure listant tout module portant un tests/ (POSIX, trié, déterministe) ;
    • coverage_report : champ orphan_tests_dirs = disk ci_paths ; ok exige désormais not orphan_tests_dirs ;
    • regression.schema.json : orphan_tests_dirs ajouté (required · strict) ;
    • regression_gen.py : message INV4 surface les orphelins ;
    • tests/test_regression.py : +2 tests (sous-ensemble disque⊆CI sur le dépôt réel ; preuve de morsure monkeypatch d'un orphelin ⇒ ok=False).
  • Preuve de morsure end-to-end : mkdir zz_orphan/tests + buildbuild refusé INV4 … orphan_tests_dirs=['zz_orphan'] ; répertoire retiré ⇒ build OK.

Anti-invention (#6) : rien inventé — les deux gates régénèrent la vérité (run frais / couverture recomputée) au lieu de figer un compteur.

Régénération des consommateurs (mémoire projet) : l'édition des tests + du README de qa/regression a fait dériver qa/audit_4big/out/quality_report.json (evidence « README.md 3710→4236 octets » et « 24→26 méthodes test_* ») — régénéré, verdict PASS · 21/21 · min 100. Totaux matrice 534/21 inchangés : le harnais qa/regression est self-exclu (INV3) → +2 méthodes test_* n'affectent pas la matrice.

Vérifs : 5 gates locaux verts (guard_constraints/validate_json/check_docs/ check_artifacts/check_regression) ; ci.yml YAML valide ; tests harnais 26/26 OK (régression) + 34/34 OK (audit_4big) ; matrice 534/534 · 21/21 · PASS ; artefacts out/ reproductibles à l'identique.

Hors périmètre worker (VPS · #8) : néant (stdlib pur en-repo ; enregistrement du runner Gitea toujours du ressort DevOps).

Auto-score 4Big : 96/100.