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

142 lines
8.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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-tests``seo-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` + `build` ⇒ **build
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.