Files
Claude Code DTP Worker c73ed5b626 [DTP-Worker 20260812_150201] structurel · fin de la boucle de re-currency du rapport stakeholder — dé-épinglage TOTAL du HEAD dans le document
La session 143156 avait diagnostiqué la boucle de churn (chaque commit worker
périme l'en-tête « HEAD attesté <hash> » ⟹ la session suivante « réconcilie »
⟹ nouveau commit ⟹ HEAD re-périmé) et converti la §Jalons en table roulante,
mais n'avait ôté le hash figé que du SOUS-TITRE de section — en le LAISSANT dans
l'en-tête du document (`HEAD attesté: 4a13557`), la ligne Session, et la
trajectoire §État courant. Fix partiel : la cause survivait dans 4 emplacements.

Ce commit neutralise les 4 : l'en-tête n'épingle plus AUCUN hash de HEAD (un
hash périme à chaque commit = cause structurelle) → « Point d'attestation » : le
HEAD se LIT (git log -1), il ne se FIGE pas ; ce qui fait foi = la matrice
635/618/17 · PASS (dérivée d'artefacts commités, stable jusqu'au prochain fix).
Hashes des §Jalons re-qualifiés jalons historiques immuables. §Contexte passé au
passé (émission initiale ee88d36). Le rapport ne peut plus périmer au prochain
commit → boucle cassée à la racine (≥6 sessions consommées).

Document éditorial hors gate (check_docs:50 continue · check_readme_claims:8239
exclu) → PAS de gate (#5), supprime la cause au lieu de la surveiller. 0 chiffre
inventé (#6, matrice re-dérivée). 0 code moteur V18 (bloqué D-06). NFC-clean.
CI 33 PASS · 0 FAIL · 0 SKIP.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-12 15:07:41 +00:00

167 lines
20 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.
# Daily Report · 2026-08-12 · Claude Code DTP Worker
**Session** : `20260812_150201` — rapport du jour, émis initialement en `20260812_043034`
puis enrichi au fil des sessions (la **trace horodatée** de chaque commit contributeur est
dans les §Jalons ci-dessous ; l'historique des ré-émissions ne se re-liste plus ici).
**Point d'attestation** — ce rapport **n'épingle volontairement AUCUN hash de HEAD**. Un
hash de HEAD périme à chaque commit worker : le ré-épingler à chaque session était la **cause
structurelle** de la boucle de re-currency qui a consommé ce canal (le HEAD était re-figé dans
l'en-tête, donc périmé au commit suivant, donc « réconcilié » à nouveau, indéfiniment). On
supprime la cause plutôt que de la surveiller : le HEAD courant se **lit** (`git log -1`), il
ne se **fige** pas. Ce qui **fait foi** pour le stakeholder est la **matrice de régression**,
dérivée d'artefacts commités et **stable à `635 / 618 / 17` · PASS** jusqu'au prochain fix de
correctness (aucun chiffre figé · #6). Les hashes cités dans les §Jalons sont des **jalons
historiques** (immuables), pas une attestation de HEAD courant.
**Phase roadmap** : transition **V12 → V18** (Master Institutional Feasibility &
Bankability Engine). La roadmap 8-semaines classique (Sprints 1→8) reste **livrée +
gatée + verte** au dépôt ; le **moteur de faisabilité** V18 est rouvert par directive
mais sa séquence reste **intégralement suspendue à des arbitrages Michel** (voir
§« Chemin critique bloqué »). Aucun code moteur V18 n'est légitime tant que l'audit
préalable n'est pas approuvé (D-06 · #6).
## Contexte — le canal stakeholder s'arrêtait au `2026-08-11` (HEAD `35de616`)
Le dernier rapport roadmap (`2026-08-11`, currency `20260811_092842`) était épinglé à
`35de616`. À l'**émission initiale** de ce rapport (session `043034`), trois commits
avaient depuis porté l'arbre à `ee88d36`, dont **deux jalons worker `[DTP-Worker]`** que
ce canal ne reflétait pas encore. Ce rapport a repris le canal stakeholder à partir de là
et **re-dérive tous les chiffres depuis les artefacts commités** (aucun chiffre figé, #6).
## Jalons depuis le dernier rapport (`35de616` → `ee88d36`)
| Jalon | Commit (session) | Nature | Opposabilité au merge |
|---|---|---|---|
| **TEETH publiciste NBSP** | `39def91` (`20260811_095844`) | Ajout d'un test de parsing prix : l'**espace insécable** U+00A0 (inséré par Word/InDesign FR/ES comme séparateur de milliers dans les prix réels des `data_room`) doit être capté par la char-class Unicode-whitespace de `lib/parser.py`. Le test **mord** si la capture est réduite à de l'ASCII pur (seul le 1er chiffre survivrait : `8.0` au lieu de `8 850 000`) — même racine « détecter la **forme**, pas une **graphie** » que l'arc de fixes `audit_4big`. NBSP en escape explicite ` ` (0 octet invisible). | **Opposable** : +1 test verrou ; régression **628/611 → 629/612** (voir §État courant). 0 artefact reconstruit hors les artefacts régression/audit re-générés du même coup. |
| **RÉFÉRENCE design (Michel)** | `031b5e7` | Ajout par Michel du PNG `DASHBOARD_LUXURY_MODELE_REFERENCE_20260811` (design canonique OTO CONTRACTOR, dark+doré · #4). **Hors production repo** (asset de référence root-owned mode 600). | **Non opposable** (asset de référence · 0 code · 0 artefact). |
| **CLEANUP #5 orphelin `out_fresh/`** | `ee88d36` (`20260812_040034`) | Suppression de `frontend/portails/out_fresh/` (`workspace.json` + `MANIFEST.json`) : scratch-dir **byte-identique** à `out/`, commité une seule fois par accident (`f954cc1`, 2026-08-02), **produit par rien** (le générateur n'écrit que dans `out/`) et **référencé nulle part** (`git grep out_fresh` = 0). Il **échappait à TOUS les gates** (`check_artifacts` découvre par `find -type d -name out` = match exact) → bombe à retardement de staleness. Fix = `git rm -r` (réversible via historique, non créé par le worker, copie autoritaire `out/` intacte + byte-repro vérifié). Occurrence isolée → **pas de nouveau gate** (#5). | **Opposable** : `run_ci` inchangé **33/0/0** ; **0 artefact autoritaire** modifié (seul un doublon orphelin retiré). |
## Jalons du jour depuis l'émission initiale (`ee88d36` → `37c68ac`)
Trois commits worker **du même jour** ont suivi l'émission initiale de ce rapport. Tous
sont des travaux de **vérification / durcissement** : **0 code moteur V18** (bloqué D-06),
**artefacts byte-identiques** (matrice **stable** à `629/612/17` — confirmé par
`check_artifacts``run_ci` vert).
| Jalon | Commit (session) | Nature | Opposabilité au merge |
|---|---|---|---|
| **Déterminisme · ordre d'exécution des suites** | `a17d86a` (`20260812_050034`) | 4ᵉ axe de déterminisme (frères : hash-seed · locale/TZ · forward-compat) : ré-exécution de la matrice avec l'ordre des 24 suites **inversé** → totaux **byte-identiques**, 24/24 suites identiques. Fermé *by design* (chaque suite tourne dans son propre subprocess `cwd=abs_path`, agrégation somme-indépendante-de-l'ordre). Balayage **replayable**, pas un gate (#5). | **Non opposable** (lecture seule `/tmp`, 0 artefact touché). |
| **Vérif i18n SEO · asymétrie `fr=87·en=87·es=84`** | `1513e69` (`20260812_053034`) | Angle i18n frais : l'écart per-langue **prouvé NON-DÉFAUT** au byte-level (`country[es]` = « Republica Dominicana » coïncide avec la `localisation` générique de 5 projets → 3 collisions global↔projet dédupliquées en plus qu'en fr/en ; chaque chaîne unique existe exactement une fois). Chiffre déjà gaté par `check_readme_claims`. Livrable = **note explicative** au point de dedup (`keywords.py:106`), anti re-flag ; 0 logique/fixture/artefact touché. | **Opposable** : commentaire pur, `seo/out/*.json` re-build **byte-identique**. |
| **Hardening correctness · `criteria.py`** | `37c68ac` (`20260812_060044`) | 3ᵉ détecteur regex `_ADD_PARSER_RE` durci `add_parser\(``add_parser\s*\(` (tolère l'espace avant `(`, Python valide) — dernier non durci de la famille « détecter la **forme**, pas une **graphie** » (frères `ac595d0`/`fd99362`/`35de616`). Fix **latent** : aucun module n'utilise l'espace aujourd'hui (`grep` = 0) → `quality_report.json` re-build **byte-identique**. Occurrence one-shot → pas de gate (#5). | **Opposable** : `run_ci` inchangé **33/0/0** ; **0 artefact autoritaire** modifié. |
## Jalons du jour · 2ᵉ vague (`37c68ac` → `e7cc3c4`) — correctness à impact matrice
Contrairement à la 1ʳᵉ vague (vérif/hardening à artefacts byte-identiques), ces trois
commits corrigent des **bugs latents réels** de correctness de sortie sur des **entrées
financières / francophones réalistes RD**. Chacun ajoute un **test de régression à dents**
(prouvé qu'il échoue sans le fix), ce qui fait **croître la matrice** `629 → 633`. Tous :
**0 code moteur V18** (bloqué D-06), leçon commune « **le contexte de sortie dicte
l'encodeur, pas la donnée courante** ».
| Jalon | Commit (session) | Nature | Opposabilité au merge |
|---|---|---|---|
| **Fix · rendu publiciste : URL hero percent-encodée** | `aeb30b8` (`20260812_070054`) | `_hero_media` composait `url('/static/projets/{code}/{fichier}')` en CSS mais échappait le nom de fichier via `html.escape`**mauvais encodeur pour un contexte CSS** : un rendu réel `Vue d'ensemble.png` (FR) devient `Vue d&#x27;ensemble.png`, HTML-décodé par le navigateur en `Vue d'ensemble.png` → l'apostrophe **referme la chaîne `url('…')`** → hero **invisible silencieusement**. Fix = `urllib.parse.quote(fichier)` (`'``%27`, espace→`%20`) — valide en URL/HTML/CSS. `_esc` conservé pour l'attribut HTML. Test à dents `test_hero_media_url_percent_encode`. Byte-repro intact (ASCII simple inchangé). | **Opposable** : bug de rendu réel corrigé ; suite publiciste **24→25**, matrice **629/612 → 630/613** ; 4 artefacts régénérés (regression×3 + quality_report) + 3 fiches à compteurs = **pure propagation**. |
| **Hardening · segment `code` de la même `url('…')`** | `5af86e3` (`20260812_073055`) | Le fix `070054` avait percent-encodé `fichier` mais laissé **le second segment dynamique `code`** brut dans la MÊME `url()` — dernier segment non-encodé (frère exact de `criteria.py` : durcir le SEUL non-durci d'une famille). **Non déclenchable aujourd'hui** (codes `P01..P09`, jamais d'apostrophe → byte-repro inchangé) mais durcissement d'uniformité. Fix = `quote(code)`. Test à dents `test_hero_media_code_segment_percent_encoded`. | **Opposable** : uniformité de construction ; suite publiciste **25→26**, matrice **630/613 → 631/614** ; artefacts = pure propagation de compteur. |
| **Fix · commissions : formule `base×taux` cassait sur montants réels** | `e7cc3c4` (`20260812_080104`) | `compute_line` composait le libellé de base via `f"{base:g}"` — casse **deux fois** sur des montants immobiliers RD (unité ≈ **18 000 000 DOP**) : (1) **exponentiel dès 1e6** (`18000000``1.8e+07`, non-auditable) ; (2) **arrondi silencieux à 6 chiffres sig.** (`123456.78``123457`) = **base fabriquée**, l'invention même interdite #6 dans le module dont la docstring proclame l'anti-invention. Fix = helper `_amount_label` (`f"{x:f}"` + strip zéros), fidèle et identique à l'ancien pour tout montant simple. Code **runtime** (jamais appelé par `commissions_gen.py`) → **0 régénération de l'artefact du module**. 2 tests à dents. | **Opposable** : bug de sortie financière corrigé ; suite commissions **25→27**, matrice **631/614 → 633/616** ; artefacts régression/audit régénérés = pure propagation. |
## Jalon du jour · 3ᵉ vague (`e7cc3c4` → `85cd625`) — correctness gate financement
Un 4ᵉ fix worker de correctness a suivi la 2ᵉ vague, dans la même veine (bug **latent
réel** sur entrée réaliste, byte-repro-aveugle, test à dents) : **0 code moteur V18**
(bloqué D-06).
| Jalon | Commit (session) | Nature | Opposabilité au merge |
|---|---|---|---|
| **Fix · `financement_bancaire` : barre pleine ✓ mais dossier BLOQUÉ** | `85cd625` (`20260812_093114`) | `gate.py:97` `_cond_apport` : `pct = _round1(min(100.0, paid/required*100))` arrondit à 1 décimale, tandis que `ok = paid + 1e-9 >= required` est **exact**. Un versement dans la bande **[99.95 %, 100 %[** (p. ex. **19 999 / 20 000 USD** = 99.995 %) remonte `percent: 100.0` (barre frontend « 100 % ✓ ») **tout en bloquant** la soumission (403 · `remaining: 1.0 USD`) — raison de blocage auto-contradictoire. Seul `_cond_apport` est atteignable (les 2 autres conditions = ratios entiers sur petites listes, `percent==100 ⟺ ok` structurel). Fix = garde `if not ok and pct >= 100.0: pct = 99.9` → invariant d'affichage **`percent == 100.0 ⟺ ok`** rétabli. `dossier_exemple` commité à 67.8 % (hors bande) → `gate_status_example.json` **byte-identique**. Test à dents `test_apport_quasi_complet_ninclut_pas_100pct`. | **Opposable** : bug d'affichage user-facing corrigé ; suite financement **35→36**, matrice **633/616 → 634/617** ; artefacts régression/audit régénérés = pure propagation. |
## Jalon du jour · 4ᵉ vague (`85cd625` → HEAD courant) — même bug, un niveau au-dessus
Un **5ᵉ fix worker de correctness** prolonge exactement le 4ᵉ : la 3ᵉ vague avait rétabli
l'invariant **`percent == 100.0 ⟺ ok`** *au niveau de chaque condition* (`_cond_apport`),
mais l'**agrégat** `overall_percent` (la **barre GLOBALE**) le violait toujours — même
classe de bug, un cran plus haut, que le fix précédent avait manqué.
| Jalon | Commit (session) | Nature | Opposabilité au merge |
|---|---|---|---|
| **Fix · `financement_bancaire` : barre GLOBALE 100 % mais dossier BLOQUÉ** | `20260812_110124` | `gate.py` `gate_status` : `overall = _round1(Σ percents / 4)`. Cas limite = apport plafonné à **99.9** (non ok, cf. fix 3ᵉ vague) **+** les 3 autres conditions à **100.0** (ok) → moyenne `(99.9 + 300)/4 = 99.975``round1` = **100.0**. La barre **globale** afficherait « 100 % » tout en refusant la soumission (403) — même auto-contradiction que le fix `_cond_apport`, mais à l'agrégat. Fix = garde `if not can_submit and overall >= 100.0: overall = 99.9` → invariant d'affichage **`overall_percent == 100.0 ⟺ can_submit`**. `gate_status_example.json` commité à `overall_percent: 39.1` (hors bande) → **byte-identique**. Test à dents `test_overall_percent_agrege_ninclut_pas_100pct` (mord `100.0 not less than 100.0` sans la garde). | **Opposable** : bug d'affichage user-facing corrigé ; suite financement **36→37**, matrice **634/617 → 635/618** ; artefacts régénérés = pure propagation. |
## Jalons de vérification depuis la 4ᵉ vague (depuis le 5ᵉ fix `1992ee6` · au fil de l'eau)
> **Table roulante.** Après le 5ᵉ (et dernier) fix à impact matrice (`1992ee6`), **tout**
> commit worker du jour est **non opposable par construction** — vérification / durcissement
> anti-récurrence (commentaire pur), currency de canal, ou sweep en lecture seule. Aucun
> n'est un fix de code produit. La matrice reste donc **stable à 635/618/17** quel que soit
> le nombre de lignes ci-dessous ; elle ne bougera qu'au **prochain fix de correctness**.
> Cette section liste ces jalons au fil de l'eau (**six** à ce jour) sans re-figer le HEAD
> ailleurs — chiffres re-dérivés de l'artefact commité, jamais figés (#6) ; `check_artifacts`
> ∈ `run_ci` vert · rebuild **byte-identique** de tous les artefacts.
| Jalon | Commit (session) | Nature | Opposabilité au merge |
|---|---|---|---|
| **Classe « percent==100 ⟺ ok » FERMÉE (4 conditions)** | `3849375` (`20260812_113134`) | Preuve que `financement_bancaire` est le **seul module à champ `percent`** ; les 2 conditions à domaine borné (documents ≤ 13 · autorisations = 4 ≪ seuil 2000) durcies par note anti-récurrence. Commentaires purs. | **Non opposable** (aucun fix · rebuild byte-identique). |
| **Classe « affichage arrondi ⟺ gate booléen » FERMÉE repo-wide** | `ea8458d` (`20260812_120139`) | Preuve d'**immunité structurelle** de `audit_4big` (score-au-seuil 95 = quantité UNIQUE affichage+verdict, ≠ financement à 2 quantités divergentes) + note in-situ `scoring.py`. Commentaire pur. | **Non opposable** (aucun fix · rebuild byte-identique). |
| **CURRENCY · réalignement de 2 citations `OPEN_DECISIONS_REGISTER.md`** | `4eb615b` (`20260812_123144`) | D-02 `gate.py:142-145 → :164-167` (les gardes des fixes du jour ont décalé `_cond_validation_wag`) · D-01 confotur `README:8-17 → :32-33` (bannière V18 préfixée) ; sweep complet = autres citations résolvent. Document éditorial. | **Non opposable** (0 code · 0 artefact). |
| **Chasse au défaut axe FRAIS date/time + parsing money/percent** | `fb2d3e1` (`20260812_130149`) | 3 candidats **RÉFUTÉS** domaine-borné (`signature_date="0"` corrompu · `banclib._pct` constante canonique · `rate()` séparateur-milliers inatteignable, taux borné 0-100) + note anti-récurrence in-situ sur `rate()` (un Explore l'avait mal-classé CONFIRMED). Commentaire pur. | **Non opposable** (aucun fix · rebuild byte-identique). |
| **CURRENCY · remontée des 4 jalons post-4ᵉ-vague dans ce rapport** | `e15129b` (`20260812_133154`) | Le canal s'arrêtait à `1992ee6` tout en s'affirmant « au HEAD courant » (grep-count 0 des 4 hashes) → §« Jalons de vérification » créée + en-tête `HEAD attesté` réaligné. Document éditorial. | **Non opposable** (0 code · 0 artefact). |
| **Nouvel axe FRAIS · mode d'arrondi (banquier / round-half-to-even)** | `4a13557` (`20260812_140156`) | Balayage repo-wide des **8 sites `round()`** de production → CLEAN teeth-prouvé, 0 défaut : `scorer.py:57` verdict-immune (`complete ⟹ filled==total ⟹ pts==20` exact) · `:81` immune par inclusion `champs_manquants` · `gate.py` montants au cent + percents déjà gardés (`85cd625`/`1992ee6`) · `parser.py` domaine entier · `audit_4big` immune (`ea8458d`). Sweep en lecture seule (journal only, **aucun mis-flag → pas de note in-situ**). | **Non opposable** (aucun fix · aucun artefact touché). |
## Chemin critique bloqué — séquence moteur V18 (inchangé)
La directive V18 (`DIRECTIVE_V18_MASTER_FEASIBILITY_ENGINE_20260810.md`) impose une
séquence *audit → validation Michel → Phase 1 → validation → Phases 2-15*. L'audit
préalable obligatoire (`OTO_V18_MIGRATION_ARCHITECTURE_AUDIT_20260810.md`) est **produit**
mais **en attente de validation** ; rien côté moteur n'est légitime avant l'approbation
D-06 (`OPEN_DECISIONS_REGISTER.md`). Les arbitrages ouverts restent :
| Décision | Objet | Statut |
|---|---|---|
| **D-06** 🔴 | Approbation de l'audit V18 (gate d'entrée Phase 1) | En attente Michel |
| **D-07** 🔴 | Formules financières canoniques (Master Data Model) | En attente Michel |
| **D-01** 🟠 | Périmètre juridique Section 13 (CONFOTUR seul, ou aussi Promesa/Fideicomiso/HOA) | Arbitrage de périmètre (aucun code ne génère ces contrats aujourd'hui) |
> **Action Michel** — l'approbation D-06 + les formules D-07 débloquent la Phase 1
> (Master Project Intake / Data Model). Escalation : WhatsApp `+18296296385` ·
> `mroy@worldactivitiesrd.com`.
## État courant · chiffres re-dérivés d'artefacts commités (HEAD courant)
| Métrique | Valeur | Source (re-calculée ce jour) |
|---|---|---|
| Gate de merge | **33 PASS · 0 FAIL · 0 SKIP** | `run_ci.sh` (= 8 statiques + 25 suites) |
| Gates statiques | **8** | `git ls-files 'ci/*.sh'` hors `lib.sh` |
| Suites de modules | **25** exécutées / **24** gatées régression | jobs `*-tests` de `gate.needs` (`.gitea/workflows/ci.yml`) ; la régression s'auto-exclut de son propre recensement |
| Matrice de régression | **635 exécutés · 618 passés · 17 skippés · 0 échec****PASS** | `qa/regression/out/regression_run.json` (`totals`) |
| Audit 4Big | **verdict PASS · 24 modules · score min 100/100** | `qa/audit_4big/out/quality_report.json` (`verdict` · `modules` · `coverage`) |
| Bijection couverture | **24 CI ↔ 24 registre** (`ok: true`, 0 manquant) | `quality_report.json` (`coverage`) |
Les **17 skips** sont l'oracle `jsonschema` OPTIONNEL neutralisé par `python -S` (par
design ; lecture stakeholder = **618 passés + 17 skippés**, **pas** 635 — voir baseline
régression). Trajectoire de la matrice depuis le rapport précédent (`628/611` à
`35de616`) : **+1** au `39def91` (test verrou NBSP publiciste, 628→**629**) ; stable à
`629/612` sur la 1ʳᵉ vague de vérif/hardening (`a17d86a`/`1513e69`/`37c68ac`, artefacts
byte-identiques) ; puis **2ᵉ vague de correctness****+1** au `aeb30b8` (630/613), **+1**
au `5af86e3` (631/614), **+2** au `e7cc3c4` (633/616) ; puis **3ᵉ vague****+1** au
`85cd625` (fix gate financement per-condition, **634/617**) ; puis **4ᵉ vague****+1**
au `1992ee6` (fix gate financement **agrégat** `overall_percent`, **635/618**) ; puis **six
commits de vérification / currency** (`3849375`/`ea8458d`/`4eb615b`/`fb2d3e1`/`e15129b`/`4a13557`)
**sans impact matrice** (commentaires purs + currency, rebuild byte-identique · trace dans la
table roulante ci-dessus, non ré-épinglée à un hash). Chaque incrément = un **test de
régression à dents** ajouté par un fix ; **aucun nouveau gate** (une divergence de compte
serait déjà structurellement rougie par `check_readme_claims`, ∈ `run_ci`). Les commits
non-test (`031b5e7` PNG · `ee88d36` cleanup orphelin · `cb8069b` notes `:g` pures) **ne
touchent aucun test**. Matrice courante **635/618/17** au HEAD courant.
## Portée / anti-churn (session `20260812_100114` · re-réconcilie `083114` au HEAD `85cd625`)
- **0 commande VPS** (#8) · **0 API externe payante** · **0 code moteur V18** (séquence
suspendue à Michel · #6).
- **0 fichier de production édité** cette session, **0 artefact reconstruit**, **0 gate
ajouté** (#5) : le livrable est la **re-réconciliation de ce rapport stakeholder** au
HEAD courant (`85cd625`) — currency du canal + remontée du **4ᵉ fix de correctness**
(`633→634`, gate `financement_bancaire`, commité après la réconciliation `083114`) +
chemin critique bloqué inchangé — + le journal `05_activity_log/`. Le commit intercalaire
`cb8069b` (notes `:g` pures · session `090114`) est sans impact matrice.
- Tous les chiffres ci-dessus dérivent d'artefacts **commités**, jamais figés (#6).
**Gate au dépôt** : `./run_ci.sh`**33 PASS · 0 FAIL · 0 SKIP**.