[DTP-Worker 20260812_120139] vérif · classe « affichage arrondi ⟺ gate booléen » FERMÉE repo-wide : preuve d'immunité structurelle de audit_4big (score-au-seuil 95 = quantité UNIQUE affichage+verdict, ≠ financement à 2 quantités divergentes) + note anti-récurrence in-situ → commentaire pur · rebuild byte-identique · sans fix · sans gate
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -319,3 +319,24 @@ Chaque incrément correspond à un **test de régression à dents** ajouté par
|
||||
**Impact d'artefact : ZÉRO.** Commentaires purs → aucun changement de sortie. `bancable` n'a pas d'`out/` commité (`bancable-out-not-committed`). `_rate_label` est du code **runtime** (`compute_line`), jamais appelé par `commissions_gen.py`, et aucune `formule`/`base` n'est sérialisée dans les artefacts commités. `regression_run.json`/`quality_report.json` **inchangés** (633/616/17 · 24×100). Aucun compteur de fiche/README à réaligner.
|
||||
|
||||
**Vérif.** `./run_ci.sh` = **33 PASS · 0 FAIL · 0 SKIP** (inchangé). 3 fichiers édités **compilent** + **NFC-clean** (vérifié). **0 code moteur V18** (bloqué #6), **0 fix de code** (défauts inexistants), **0 chiffre/fixture inventé** (#6), **0 gate ajouté** (#5), **0 artefact modifié/reconstruit**, **0 commande VPS** (#8), **0 API externe**. Fichiers : `M crm/commissions/commlib/finance.py` · `M faisabilite/bancable/banclib/finance.py` · `M faisabilite/bancable/banclib/report.py` (notes anti-récurrence `:g`) + ce journal.
|
||||
|
||||
## Session `20260812_120139` — VÉRIF · fermeture repo-wide de la classe « affichage arrondi ⟺ gate booléen » : preuve d'immunité structurelle de `audit_4big` (seul autre score-au-seuil), note anti-récurrence in-situ
|
||||
|
||||
**État au démarrage.** `./run_ci.sh` = **33 PASS · 0 FAIL · 0 SKIP** (baseline verte). `regression_run.json` (lu depuis l'artefact commité · #6) = **635 exécutés · 618 passés · 17 skippés · 0 échec** (PASS). `quality_report.json` = **PASS · 24 modules · min 100/100 · bijection couverture 24↔24 (`ok: true`)**. Séquence moteur V18 toujours **bloquée** en gouvernance (D-06 = gate d'entrée · « 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` **déjà à jour au HEAD courant** (matrice **635/618/17** = artefact commité ; le dernier commit `3849375` est une vérif byte-identique sans impact matrice → aucune re-réconciliation due).
|
||||
|
||||
**Chasse au défaut d'abord (Explore very-thorough) sur 6 modules JAMAIS ré-audités ce cycle → DRY (0 défaut réel).** Ciblé : `rbac/` (roleprofile/userperm/fixtures/apply_plan) · `publiciste/lib` + générateur · `legal/confotur` · `devops/deploy_runbook` · `crm/workflow_vente` · `seo/seo_gen`+`seolib`. Axes : formatage numérique domaine non-borné (`,.0f` correct sur montants ; pas de `:g` sur non-borné), gardes de division (toutes présentes), off-by-one de comptage, encodeur selon contexte (`html.escape`/`quote` corrects), agrégats (`min`/set-equality corrects), booléens inertes. **Aucun candidat, même faible.**
|
||||
|
||||
**Vrai axe = fermeture repo-wide de la classe corrigée aux 3ᵉ/4ᵉ vagues du jour (`85cd625`+`1992ee6`).** Le commit `3849375` a prouvé que `financement_bancaire` est le **seul module à champ `percent`** (grep artefacts commités confirmé : `financement.schema.json` + `gate_status_example.json` uniquement). Mais la classe de bug réelle n'est pas « champ nommé percent » — c'est **« une valeur d'AFFICHAGE arrondie qui franchit une frontière de SEUIL en contredisant une décision booléenne »**. Il restait **un** autre porteur non examiné : `qa/audit_4big/q4lib/scoring.py:65` — un **score 0-100 arrondi**, comparé au **seuil PASS 95** (#5). Sibling naturel qu'un futur auditeur re-flaggerait.
|
||||
|
||||
**Preuve d'immunité STRUCTURELLE (mécanisme distinct du fix financement).** Vérifié bout-en-bout :
|
||||
- `scoring.py:65-66` — `score = _round_half_up(100.0 * earned / total)` **PUIS** `verdict = "PASS" if score >= pass_score`. Le verdict dérive du **MÊME entier arrondi** que celui affiché.
|
||||
- `audit_4big_gen.py:136` (INV6) recompute la note via `scoring._round_half_up(...)` (même arrondi) ; `:144` (INV7) attend `"PASS" if m["score"] >= ps` (même `score`).
|
||||
→ Il n'existe **qu'UNE seule quantité** (`score`, arrondie), servant à la fois d'affichage ET de gate. Contrairement à `financement` où `percent` (arrondi, affichage) et `ok` (exact, gate) étaient **DEUX quantités divergentes** en bord de seuil, ici **aucune divergence n'est possible par construction**. La classe « affichage ⟺ gate » est donc **FERMÉE repo-wide** : financement était le seul locus à deux-quantités (corrigé), audit_4big est le seul autre score-au-seuil et il est immun par unicité de quantité.
|
||||
|
||||
**Action = note anti-récurrence in-situ (commentaire pur · sœur de « twin fix must sweep ALL surfaces », `docstring-vs-code-drift`).** Ajout à `scoring.py:66` d'une justification (quantité unique par design → immunité au bug financement → **ne PAS scinder en brut-vs-arrondi**, ce qui ré-introduirait précisément la divergence + renvoi à INV6/INV7). Convertit le sibling « à re-vérifier » en « déjà revu, sûr » pour les audits futurs.
|
||||
|
||||
**Pourquoi PAS un fix ni un gate (#5/#6).** Aucun défaut : le code est correct et interne-cohérent (une quantité, pas de contradiction atteignable) — « corriger » en comparant le verdict à `earned/total` **brut** créerait la divergence, une régression exactement inverse d'un fix (cf. `verify-non-defects`). Rien de nouveau à gater : INV6/INV7 garantissent déjà la cohérence `score`↔`verdict`, et le seuil 95 est déjà ancré (mémoire `threshold-in-guard-prose-gate`). Commentaire sans marqueur `# N ·` d'invariant → aucun déclenchement du gate ledger.
|
||||
|
||||
**Impact d'artefact : ZÉRO.** Commentaire pur → sortie inchangée. `audit_4big_gen.py` ré-exécuté → `quality_report.json` **byte-identique** (`git diff` vide). Matrice **inchangée** (635/618/17 · 24×100). Aucun compteur de fiche/README à réaligner.
|
||||
|
||||
**Vérif.** `./run_ci.sh` = **33 PASS · 0 FAIL · 0 SKIP** (inchangé). `scoring.py` **compile** + **NFC-clean** (vérifié). **0 code moteur V18** (bloqué #6), **0 fix de code** (défaut inexistant), **0 chiffre/fixture inventé** (#6), **0 gate ajouté** (#5), **0 artefact modifié/reconstruit** (byte-repro prouvé), **0 commande VPS** (#8), **0 API externe**. Fichiers : `M 05_deliverables_mvp/qa/audit_4big/q4lib/scoring.py` (note anti-récurrence) + ce journal.
|
||||
|
||||
@@ -63,6 +63,13 @@ def score_module(spec: dict, module: dict) -> dict:
|
||||
f"Archétype {archetype} sans critère applicable — spec incohérent.")
|
||||
|
||||
score = _round_half_up(100.0 * earned / total)
|
||||
# Quantité UNIQUE par design : le verdict dérive du MÊME `score` arrondi que
|
||||
# celui affiché (jamais d'une note brute parallèle). Immunité structurelle au
|
||||
# bug « barre à 100 % ⟺ gate ouvert » corrigé côté financement_bancaire (là,
|
||||
# `percent` arrondi et `ok` exact étaient DEUX quantités divergentes en bord de
|
||||
# seuil). Ici affichage et gate sont le même entier → ne PAS scinder en
|
||||
# brut-vs-arrondi (ré-introduirait précisément la divergence). Idem INV6/INV7
|
||||
# du générateur, qui recomputent verdict sur ce `score` (pas sur earned/total brut).
|
||||
verdict = "PASS" if score >= thresholds["pass_score"] else "FAIL"
|
||||
return {
|
||||
"id": module["id"],
|
||||
|
||||
Reference in New Issue
Block a user