[DTP-Worker 20260812_110124] fix correctness · financement_bancaire overall_percent — la barre GLOBALE pouvait afficher 100.0 tout en BLOQUANT (l'invariant per-condition de 093114 ne s'était pas propagé à l'agrégat) → matrice 634→635 · test à dents · exemple byte-identique · sans gate

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Code DTP Worker
2026-08-12 11:09:49 +00:00
parent 626c39d958
commit 1992ee63be
11 changed files with 80 additions and 22 deletions
+1 -1
View File
@@ -41,7 +41,7 @@ de Michel, d'où son suivi séparé (il ne partage pas la source unique du trio)
| Module | Sprint | Rôle | Entrée CLI | Job CI | Tests | | Module | Sprint | Rôle | Entrée CLI | Job CI | Tests |
|---|---|---|---|---|---| |---|---|---|---|---|---|
| [`financement_bancaire/`](../../05_deliverables_mvp/crm/financement_bancaire/README.md) | 4 (roadmap L52) | Parcours **hypothécaire RD** : cœur métier du **gate check 4 conditions** — aucun document n'est transmis à la banque tant que apport initial (20 % résident · 30 % étranger · Ley 189-11) + documents exigés + autorisations signées + validation référente ne sont pas réunis ; fonctions **pures** sans I/O | `financement_bancaire_gen.py build\|validate` | `crm-financement-bancaire-tests` | 36 | | [`financement_bancaire/`](../../05_deliverables_mvp/crm/financement_bancaire/README.md) | 4 (roadmap L52) | Parcours **hypothécaire RD** : cœur métier du **gate check 4 conditions** — aucun document n'est transmis à la banque tant que apport initial (20 % résident · 30 % étranger · Ley 189-11) + documents exigés + autorisations signées + validation référente ne sont pas réunis ; fonctions **pures** sans I/O | `financement_bancaire_gen.py build\|validate` | `crm-financement-bancaire-tests` | 37 |
Matérialise [`DIRECTIVE_FINANCEMENT_BANCAIRE_COMPLET_20260803.md`](../../DIRECTIVE_FINANCEMENT_BANCAIRE_COMPLET_20260803.md) Matérialise [`DIRECTIVE_FINANCEMENT_BANCAIRE_COMPLET_20260803.md`](../../DIRECTIVE_FINANCEMENT_BANCAIRE_COMPLET_20260803.md)
(**Phase 1 · P0 · MVP** : contrat de données + cœur du gate + 7 sections + bannière (**Phase 1 · P0 · MVP** : contrat de données + cœur du gate + 7 sections + bannière
+1 -1
View File
@@ -37,7 +37,7 @@ le VPS reçoit — jamais l'inverse.
vente, le barème commissions, le DocType Dossier Vente et le plan e-CF **résolvent** vente, le barème commissions, le DocType Dossier Vente et le plan e-CF **résolvent**
leurs rôles depuis ce fichier, jamais un nom Frappe en dur. Total backend **RBAC 60 leurs rôles depuis ce fichier, jamais un nom Frappe en dur. Total backend **RBAC 60
tests** (10 + 11 + 12 + 11 + 16) + **e-CF 39 tests**, tous gated dans le CI (matrice tests** (10 + 11 + 12 + 11 + 16) + **e-CF 39 tests**, tous gated dans le CI (matrice
de régression du repo : **634 tests · 24 suites** · verdict `PASS`, source de régression du repo : **635 tests · 24 suites** · verdict `PASS`, source
`qa/regression/out/regression_run.json` — jamais compté à la main · #6). `qa/regression/out/regression_run.json` — jamais compté à la main · #6).
## Hand-off reçus (à appliquer sur le VPS, dans l'ordre) ## Hand-off reçus (à appliquer sur le VPS, dans l'ordre)
+1 -1
View File
@@ -32,7 +32,7 @@ périmètre — un auditeur ne s'audite jamais.
**conformité** normative des hand-off. **conformité** normative des hand-off.
## Verdict agrégé courant (source `qa/regression/out/regression_run.json`) ## Verdict agrégé courant (source `qa/regression/out/regression_run.json`)
**24 suites gated · 634 tests · 617 passés · 0 échec · 0 erreur → verdict `PASS`.** **24 suites gated · 635 tests · 618 passés · 0 échec · 0 erreur → verdict `PASS`.**
Ce compte est **découvert automatiquement depuis le CI** (`q4lib.registry.parse_ci`, Ce compte est **découvert automatiquement depuis le CI** (`q4lib.registry.parse_ci`,
réutilisé sans duplication) — jamais compté à la main. réutilisé sans duplication) — jamais compté à la main.
Les **17 tests restants sont ignorés** (`skipped`) : ce sont les *oracles optionnels* Les **17 tests restants sont ignorés** (`skipped`) : ce sont les *oracles optionnels*
+20
View File
@@ -1,5 +1,25 @@
# Activity Log · 2026-08-12 · Claude Code DTP Worker # Activity Log · 2026-08-12 · Claude Code DTP Worker
## Session `20260812_110124` — FIX correctness · `financement_bancaire` — même bug que `093114`, un niveau au-dessus : la barre GLOBALE `overall_percent` pouvait afficher 100.0 tout en BLOQUANT (l'invariant per-condition ne s'était PAS propagé à l'agrégat)
**État au démarrage.** `./run_ci.sh` = **33 PASS · 0 FAIL · 0 SKIP** (baseline verte). `regression_run.json totals` (lu de l'artefact commité · #6) = **634 exécutés · 617 passés · 17 skippés · 0 échec** (PASS). `quality_report.json` = **PASS · 24 modules · min 100/100 · bijection 24↔24 (`ok: true`)**. Séquence moteur V18 toujours **intégralement bloquée** en gouvernance (D-06 approbation audit = gate d'entrée · directive « NE PAS coder avant l'audit » · #6) → **aucun code moteur légitime**. Arbitrages produit D-01→D-08 en attente Michel (`OPEN_DECISIONS_REGISTER.md`). Canal stakeholder `daily_reports/2026-08-12.md` à jour au HEAD `85cd625` (session `100114`).
**Chasse au défaut d'abord (angle : la robustesse de la classe « affichage percent == 100 ⟺ soumissible » est-elle vraiment fermée après `093114` ?) → 1 candidat CONFIRMÉ au byte-level, latent mais réel.** Le fix `093114` (`gate.py:105`) a rétabli l'invariant **`percent == 100.0 ⟺ ok`** *par condition* (`_cond_apport` plafonné à 99.9 quand non ok). J'ai vérifié si l'**agrégat** `overall_percent` (la **barre GLOBALE** du frontend, `gate_status:171`) héritait de l'invariant — **il ne l'héritait pas**.
**Le défaut (même classe, un cran plus haut).** `overall = _round1(Σ percents / 4)` sur les 4 conditions. Cas limite atteignable : apport plafonné à **99.9** (non ok, exactement l'état laissé par le fix `093114` p. ex. 19 999/20 000 USD) **+** les 3 autres conditions **ok à 100.0** (documents tous validés WAG, autorisations toutes signées, validation WAG faite) → moyenne `(99.9 + 300)/4 = 99.975``round1` = **100.0**. Résultat user-facing : `overall_percent: 100.0` **tout en** `can_submit: False` (403). La **barre de progression GLOBALE** — celle que le client regarde en premier — afficherait « 100 % » sur un dossier refusé. **Exactement** la même auto-contradiction que le fix per-condition `093114`, mais à l'agrégat que ce fix n'a pas couvert. Reproduit **end-to-end** via le vrai `gate_status` (dossier résident RD 100 000 USD, apport 19 999) : `overall_percent=100.0`, `can_submit=False`.
**Pourquoi byte-repro est aveugle (preuve que ça échappe aux gates).** `gate_status_example.json` commité est à `overall_percent: 39.1` (`can_submit: false`) — **hors bande**. `check_artifacts` (rebuild == commité) le reproduit à l'identique éternellement. Bug **latent** : correct sur l'échantillon figé, faux dès qu'un dossier réel atteint la configuration limite. Même veine que `093114` (per-condition), `073055` (`base×taux`), `080104` (commissions).
**Fix (chirurgical, symétrique au fix `093114`, byte-repro préservé).** Après le calcul de `overall`, garde `if not can_submit and overall >= 100.0: overall = 99.9`. Invariant d'affichage rétabli au niveau agrégat : **`overall_percent == 100.0 ⟺ can_submit`**. L'exemple à 39.1 % **inchangé**`financement/out/` rebuild **BYTE-IDENTIQUE** (`diff -rq out/ /tmp` = IDENTICAL).
**Test à dents (prouvé mordant).** Nouveau `test_overall_percent_agrege_ninclut_pas_100pct` (frère de `test_apport_quasi_complet_ninclut_pas_100pct`, mais à l'agrégat) : dossier avec apport 19 999/20 000 + 3 autres conditions ok → assert `can_submit=False`, les 3 autres conditions `ok=True` (isolation du cas limite), `overall_percent < 100.0` (== 99.9). **Sans le fix**`AssertionError: 100.0 not less than 100.0` (mordu, vérifié par mutation) ; **avec** → OK. Suite financement **36 → 37**.
**Cascade artefacts (test count +1).** Régénéré `regression_run.json` (**634→635 / 617→618**), `regression_plan.json` + `MANIFEST.json` (build), `quality_report.json` (audit_4big **en dernier** · mémoire `audit4big-rebuild-after-doc-edits` — PASS 24/24, min 100). Fiches gatées re-dérivées (`check_readme_claims`) : QA `634/617→635/618`, Backend `634→635`, CRM financement `36→37` (le « Total CRM » du trio est source séparée · financement suivi à part ligne 44 · convention `fiche-accuracy-audit-closed`). Canal stakeholder `daily_reports/2026-08-12.md` prolongé (4ᵉ vague · matrice 634→635 · mémoire `two-logging-channels`).
**Pourquoi pas un nouveau gate (#5).** L'invariant `overall_percent == 100 ⟺ can_submit` est désormais **porté par le code + prouvé par un test à dents** ∈ régression gatée — comme son frère per-condition `093114`. Un gate statique dédié serait redondant (`verify-uncovered` : la suite couvre, mutation confirmée). Origine unique, un seul site.
**Vérif.** `./run_ci.sh` = **33 PASS · 0 FAIL · 0 SKIP**. Fichiers édités **compilent** + **NFC-clean** (vérifié). **0 code moteur V18** (bloqué #6), **1 module produit corrigé** (bug latent user-facing), **artefacts autoritaires régénérés déterministes** (échantillon byte-identique), **0 gate ajouté** (#5), **0 commande VPS** (#8), **0 API externe**, **0 invention de chiffre** (#6 — tous re-dérivés des artefacts). Fichiers : `finlib/gate.py`, `tests/test_financement_bancaire.py`, `qa/regression/out/{regression_run,regression_plan,MANIFEST}.json`, `qa/audit_4big/out/quality_report.json`, fiches `03_agents/{qa,erpnext_backend,crm}/AGENT.md`, `daily_reports/2026-08-12.md` + ce journal.
## Session `20260812_103119` — VÉRIF · nouvel axe « bien-formation structurelle du HTML généré » (parseur réel + entrées adverses FR/ES) → CLEAN teeth-prouvé, replayable, sans gate ## Session `20260812_103119` — VÉRIF · nouvel axe « bien-formation structurelle du HTML généré » (parseur réel + entrées adverses FR/ES) → CLEAN teeth-prouvé, replayable, sans gate
**État au démarrage.** `./run_ci.sh` = **33 PASS · 0 FAIL · 0 SKIP** (baseline verte). `regression_run.json totals` (lu depuis l'artefact commité · #6) = **634 exécutés · 617 passés · 17 skippés · 0 échec** (PASS). `quality_report.json` = verdict **PASS · 24 modules · min 100/100 · bijection couverture 24↔24 (`ok: true`)**. Séquence moteur V18 toujours **intégralement bloquée** en gouvernance (D-06 approbation audit = gate d'entrée · directive « NE PAS coder avant l'audit » · #6) → **aucun code moteur légitime**. Arbitrages produit D-01→D-08 en attente Michel (`OPEN_DECISIONS_REGISTER.md`). Canal stakeholder `daily_reports/2026-08-12.md` re-réconcilié au HEAD par la session `100114` (matrice 634) → à jour ; cette session est **vérification-seule à 0 impact matrice**, rien à ré-émettre. **État au démarrage.** `./run_ci.sh` = **33 PASS · 0 FAIL · 0 SKIP** (baseline verte). `regression_run.json totals` (lu depuis l'artefact commité · #6) = **634 exécutés · 617 passés · 17 skippés · 0 échec** (PASS). `quality_report.json` = verdict **PASS · 24 modules · min 100/100 · bijection couverture 24↔24 (`ok: true`)**. Séquence moteur V18 toujours **intégralement bloquée** en gouvernance (D-06 approbation audit = gate d'entrée · directive « NE PAS coder avant l'audit » · #6) → **aucun code moteur légitime**. Arbitrages produit D-01→D-08 en attente Michel (`OPEN_DECISIONS_REGISTER.md`). Canal stakeholder `daily_reports/2026-08-12.md` re-réconcilié au HEAD par la session `100114` (matrice 634) → à jour ; cette session est **vérification-seule à 0 impact matrice**, rien à ré-émettre.
@@ -171,6 +171,14 @@ def gate_status(dossier: dict, cfg: GateConfig) -> dict:
overall = _round1( overall = _round1(
sum(conditions[k]["percent"] for k in CONDITION_KEYS) / len(CONDITION_KEYS) sum(conditions[k]["percent"] for k in CONDITION_KEYS) / len(CONDITION_KEYS)
) )
# Même invariant qu'au niveau condition (cf. _cond_apport) mais à l'AGRÉGAT :
# la moyenne de 4 percents peut arrondir à 100.0 alors qu'une condition reste
# bloquante — p. ex. apport plafonné à 99.9 (non ok) + les 3 autres à 100.0 →
# (99.9 + 300) / 4 = 99.975 → round1 = 100.0. La barre GLOBALE afficherait
# « 100 % » tout en refusant la soumission (403). On plafonne donc à 99.9.
# Invariant d'affichage : overall_percent == 100.0 ⟺ can_submit.
if not can_submit and overall >= 100.0:
overall = 99.9
return { return {
"can_submit": can_submit, "can_submit": can_submit,
"conditions_total": len(CONDITION_KEYS), "conditions_total": len(CONDITION_KEYS),
@@ -133,6 +133,24 @@ class GateCheckTest(unittest.TestCase):
_, reasons = gate.can_submit_dossier(d, self.cfg) _, reasons = gate.can_submit_dossier(d, self.cfg)
self.assertTrue(any("Apport initial incomplet" in r and "100" not in r for r in reasons)) self.assertTrue(any("Apport initial incomplet" in r and "100" not in r for r in reasons))
def test_overall_percent_agrege_ninclut_pas_100pct(self):
# Invariant d'affichage AGRÉGAT (frère du test per-condition ci-dessus,
# mais au niveau de la barre GLOBALE) : overall_percent == 100.0 ⟺
# can_submit. Cas limite = apport plafonné à 99.9 (non ok) + les 3 autres
# conditions ok à 100.0 → moyenne (99.9 + 300) / 4 = 99.975, qui arrondit
# à 100.0 par _round1. Sans la garde, la barre globale afficherait
# « 100 % » tout en bloquant la soumission (403) — auto-contradiction.
d = _dossier_complet(self.cfg, self.spec)
d["paiements"] = [{"montant_verse_usd": 19999}] # 20 000 requis → apport non ok
status = gate.gate_status(d, self.cfg)
self.assertFalse(status["can_submit"])
# les 3 autres conditions sont bien complètes (isolation du cas limite)
self.assertTrue(status["conditions"]["documents_exiges"]["ok"])
self.assertTrue(status["conditions"]["autorisations_signees"]["ok"])
self.assertTrue(status["conditions"]["validation_wag"]["ok"])
self.assertLess(status["overall_percent"], 100.0)
self.assertEqual(status["overall_percent"], 99.9)
def test_apport_manquant_bloque(self): def test_apport_manquant_bloque(self):
d = _dossier_complet(self.cfg, self.spec) d = _dossier_complet(self.cfg, self.spec)
d["paiements"] = [{"montant_verse_usd": 19999}] d["paiements"] = [{"montant_verse_usd": 19999}]
+22 -10
View File
@@ -1,11 +1,11 @@
# Daily Report · 2026-08-12 · Claude Code DTP Worker # Daily Report · 2026-08-12 · Claude Code DTP Worker
**Session** : `20260812_100114` (rapport initialement émis en `20260812_043034` à **Session** : `20260812_110124` (rapport initialement émis en `20260812_043034` à
`ee88d36` · complété en `20260812_063050` à `37c68ac` · réconcilié en `083114` à `e7cc3c4` `ee88d36` · complété en `20260812_063050` à `37c68ac` · réconcilié en `083114` à `e7cc3c4`
· **re-réconcilié en fin de journée** au HEAD courant) · re-réconcilié en `100114` à `85cd625` · **prolongé au HEAD courant**)
**HEAD attesté** : `85cd625` (le rapport précédent était épinglé à `35de616` · puis ce **HEAD attesté** : HEAD courant (le rapport précédent était épinglé à `35de616` · puis ce
rapport à `ee88d36`, puis `37c68ac`, puis `e7cc3c4` · **un 4ᵉ fix worker de correctness a rapport à `ee88d36`, `37c68ac`, `e7cc3c4`, `85cd625` · **un 5ᵉ fix worker de correctness a
suivi** avec un **impact réel sur la matrice** `633→634` — voir §« Jalon du jour · 3ᵉ vague ») suivi** avec un **impact réel sur la matrice** `634→635` — voir §« Jalon du jour · 4ᵉ vague »)
**Phase roadmap** : transition **V12 → V18** (Master Institutional Feasibility & **Phase roadmap** : transition **V12 → V18** (Master Institutional Feasibility &
Bankability Engine). La roadmap 8-semaines classique (Sprints 1→8) reste **livrée + 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 gatée + verte** au dépôt ; le **moteur de faisabilité** V18 est rouvert par directive
@@ -67,6 +67,17 @@ réel** sur entrée réaliste, byte-repro-aveugle, test à dents) : **0 code mot
|---|---|---|---| |---|---|---|---|
| **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. | | **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égression/audit régénérés = pure propagation. |
## Chemin critique bloqué — séquence moteur V18 (inchangé) ## Chemin critique bloqué — séquence moteur V18 (inchangé)
La directive V18 (`DIRECTIVE_V18_MASTER_FEASIBILITY_ENGINE_20260810.md`) impose une La directive V18 (`DIRECTIVE_V18_MASTER_FEASIBILITY_ENGINE_20260810.md`) impose une
@@ -85,29 +96,30 @@ D-06 (`OPEN_DECISIONS_REGISTER.md`). Les arbitrages ouverts restent :
> (Master Project Intake / Data Model). Escalation : WhatsApp `+18296296385` · > (Master Project Intake / Data Model). Escalation : WhatsApp `+18296296385` ·
> `mroy@worldactivitiesrd.com`. > `mroy@worldactivitiesrd.com`.
## État courant · chiffres re-dérivés d'artefacts commités (HEAD `85cd625`) ## État courant · chiffres re-dérivés d'artefacts commités (HEAD courant)
| Métrique | Valeur | Source (re-calculée ce jour) | | 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) | | 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` | | 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 | | 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 | **634 exécutés · 617 passés · 17 skippés · 0 échec****PASS** | `qa/regression/out/regression_run.json` (`totals`) | | 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`) | | 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`) | | 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 Les **17 skips** sont l'oracle `jsonschema` OPTIONNEL neutralisé par `python -S` (par
design ; lecture stakeholder = **617 passés + 17 skippés**, **pas** 634 — voir baseline 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` à 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 à `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 `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** 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 au `5af86e3` (631/614), **+2** au `e7cc3c4` (633/616) ; puis **3ᵉ vague****+1** au
`85cd625` (fix gate financement, **634/617**). Chaque incrément = un **test de `85cd625` (fix gate financement per-condition, **634/617**) ; puis **4ᵉ vague****+1**
au HEAD courant (fix gate financement **agrégat** `overall_percent`, **635/618**). Chaque incrément = un **test de
régression à dents** ajouté par un fix ; **aucun nouveau gate** (une divergence de compte 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 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 non-test (`031b5e7` PNG · `ee88d36` cleanup orphelin · `cb8069b` notes `:g` pures) **ne
touchent aucun test**. Matrice courante **634/617/17** au HEAD `85cd625`. 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`) ## Portée / anti-churn (session `20260812_100114` · re-réconcilie `083114` au HEAD `85cd625`)
@@ -450,7 +450,7 @@
"criterion": "TESTS", "criterion": "TESTS",
"weight": 25, "weight": 25,
"passed": true, "passed": true,
"evidence": "36 méthodes test_* dans 1 fichier(s) (seuil 8)" "evidence": "37 méthodes test_* dans 1 fichier(s) (seuil 8)"
}, },
{ {
"criterion": "CLI", "criterion": "CLI",
@@ -5,7 +5,7 @@
"version": "1.0", "version": "1.0",
"verdict": "PASS", "verdict": "PASS",
"suites": 24, "suites": 24,
"test_methods": 634, "test_methods": 635,
"coverage_ok": true, "coverage_ok": true,
"artifacts": [ "artifacts": [
"regression_plan.json" "regression_plan.json"
@@ -57,7 +57,7 @@
"in_gate": true, "in_gate": true,
"has_tests_dir": true, "has_tests_dir": true,
"test_files": 1, "test_files": 1,
"test_methods": 36 "test_methods": 37
}, },
{ {
"id": "crm.workflow_vente", "id": "crm.workflow_vente",
@@ -295,7 +295,7 @@
"totals": { "totals": {
"suites": 24, "suites": 24,
"test_files": 24, "test_files": 24,
"test_methods": 634, "test_methods": 635,
"min_methods": 10, "min_methods": 10,
"under_threshold": 0 "under_threshold": 0
}, },
@@ -30,9 +30,9 @@
{ {
"id": "crm.financement_bancaire", "id": "crm.financement_bancaire",
"path": "crm/financement_bancaire", "path": "crm/financement_bancaire",
"expected_methods": 36, "expected_methods": 37,
"ran": 36, "ran": 37,
"passed": 36, "passed": 37,
"failures": 0, "failures": 0,
"errors": 0, "errors": 0,
"skipped": 0, "skipped": 0,
@@ -296,8 +296,8 @@
"suites": 24, "suites": 24,
"green": 24, "green": 24,
"red": 0, "red": 0,
"ran": 634, "ran": 635,
"passed": 617, "passed": 618,
"failures": 0, "failures": 0,
"errors": 0, "errors": 0,
"skipped": 17 "skipped": 17