[DTP-Worker] Sprint 8 · buffer L75 · Domaine QA/Audit 4Big : le BARÈME de notation de l'auditeur (« 5 critères 4Big déterministes » + la table Critère|Poids DOC 20/CONTRAT 20/TESTS 25/CLI 15/HANDOFF 20 + l'archétype « generator (5 critères) ») était transcrit À LA MAIN dans le README du module sans AUCUN gate — ironie du module qui NOTE les autres retranscrivant son propre référentiel de scoring. Le bloc racine de check_readme_claims ne gatait que la ligne « Résultat courant » (verdict/modules/min_score), jamais le barème lui-même, alors que qa/audit_4big/out/quality_report.json (byte-gaté par check_artifacts, criteria[] recomputé du référentiel à chaque build) fait autorité. Ajouter/retirer un critère OU changer un poids ferait dériver le README en silence pendant que l'artefact dit autre chose — « vert trompeur » qu'aucune suite tests/ (qui teste des FONCTIONS, pas la prose) n'attrape → nouveau bloc recomputant le nombre de critères (prose « N critères 4Big déterministes » + archétype « generator (N critères) », generator appliquant TOUS les critères) et CHAQUE poids depuis criteria[].weight (zéro duplication du barème du générateur #6), exigeant l'égalité avec le README. Contrôle PAR CRITÈRE et pas seulement de la somme : une compensation de poids (+5/−5) laisserait Σ==100 juste et deux lignes fausses. Cohérences croisées en bonus : Σ poids == 100 (base de renormalisation documentée) ET tout module d'archétype generator porte EXACTEMENT len(criteria) checks (« generator = tous les critères » — 18 modules generator × 5 checks vérifiés). Un claim absent échoue AUSSI (4 morsures vérifiées : prose 5→6 captée là où les poids restent justes · poids TESTS 25→30 capté là où le compte reste 5 · generator 5→4 · claim prose disparu = red ; restauré = green). ci/README.md (table + détail) mis à jour · 7 gates re-verts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Code DTP Worker
2026-07-31 13:37:10 +00:00
parent 0d1df7a8dc
commit 327aa298a2
3 changed files with 151 additions and 1 deletions
+78
View File
@@ -301,6 +301,84 @@ else:
bad(f"README audit_4big · {A4} dit {'/'.join(ma4.groups())} MAIS quality_report "
f"dit {'/'.join(a4_exp)} ({a4_src}) → régénérer le README")
# ============================================================================
# README de l'auditeur 4Big · BARÈME de notation (N critères + poids par critère)
# — même classe de « vert trompeur », au grain du référentiel de scoring.
# ----------------------------------------------------------------------------
# Le barème 4Big est DATA-DERIVED : quality_report.json.criteria (byte-gaté par
# check_artifacts, RECOMPUTÉ du référentiel à chaque build) porte la liste des
# critères et leur poids. Le README les RETRANSCRIT À LA MAIN à trois endroits :
# • la prose « Note chaque module sur N critères 4Big déterministes »,
# • la table « Critère | Poids | Fait vérifié » (une ligne id→poids par critère),
# • l'archétype « generator (N critères) » (generator applique TOUS les critères).
# Ajouter/retirer un critère ou changer un poids ferait dériver ces trois surfaces
# en silence pendant que l'artefact dit autre chose — aucune suite tests/ (qui teste
# des FONCTIONS, pas la prose du README) ne l'attrape. On RECOMPUTE ici chaque nombre
# depuis `criteria` (zéro duplication du barème du générateur · #6) et on exige
# l'égalité avec ce que la doc ÉCRIT. Cohérences croisées : Σ poids == 100 (base de
# renormalisation) ET tout module d'archétype `generator` porte EXACTEMENT
# len(criteria) checks — c.-à-d. « generator = tous les critères » (mord une dérive
# du modèle qui rendrait le « generator (N critères) » du README faux). Un claim
# absent échoue AUSSI (disparition = régression de traçabilité).
# ============================================================================
try:
qr_crit = load("qa/audit_4big/out/quality_report.json")
criteria = qr_crit["criteria"]
except (OSError, KeyError, ValueError) as e:
bad(f"README audit_4big · quality_report illisible : {e}"); criteria = None
if criteria is not None and a4_txt:
n_crit = len(criteria)
# 1) prose « N critères 4Big déterministes »
mc = re.search(r"sur (\d+) critères 4Big déterministes", a4_txt)
if mc is None:
bad(f"README audit_4big · prose « N critères 4Big » — claim INTROUVABLE dans "
f"{A4} (attendu {n_crit})")
elif mc.group(1) == str(n_crit):
good(f"README audit_4big · prose critères — {mc.group(1)} == criteria ({n_crit})")
else:
bad(f"README audit_4big · prose critères — {A4} dit {mc.group(1)} MAIS criteria "
f"en compte {n_crit} → régénérer le README")
# 2) table « Critère | Poids | … » — une ligne id→poids par critère
for c in criteria:
cid, w = c["id"], str(c["weight"])
mw = re.search(rf"\| `{re.escape(cid)}` \| (\d+) \|", a4_txt)
if mw is None:
bad(f"README audit_4big · critère {cid} — ligne INTROUVABLE dans {A4} "
f"(attendu poids={w})")
elif mw.group(1) == w:
good(f"README audit_4big · critère {cid} — poids {mw.group(1)} == criteria ({w})")
else:
bad(f"README audit_4big · critère {cid} — {A4} dit poids {mw.group(1)} MAIS "
f"criteria dit {w} → régénérer le README")
# 3) archétype « generator (N critères) » — generator applique TOUS les critères
mg = re.search(r"`generator` \((\d+) critères\)", a4_txt)
if mg is None:
bad(f"README audit_4big · archétype « generator (N critères) » — claim "
f"INTROUVABLE dans {A4} (attendu {n_crit})")
elif mg.group(1) == str(n_crit):
good(f"README audit_4big · generator — {mg.group(1)} critères == criteria ({n_crit})")
else:
bad(f"README audit_4big · generator — {A4} dit {mg.group(1)} MAIS l'archétype "
f"generator applique les {n_crit} critères → régénérer le README")
# 4) cohérence croisée : Σ poids == 100 (base de renormalisation)
w_sum = sum(c["weight"] for c in criteria)
if w_sum == 100:
good(f"README audit_4big · Σ poids critères == {w_sum} (base 100 cohérente)")
else:
bad(f"README audit_4big · Σ poids critères == {w_sum} ≠ 100 — barème incohérent "
f"avec la renormalisation documentée")
# 5) cohérence croisée : tout module `generator` porte len(criteria) checks
gen = [m for m in qr_crit["modules"] if m.get("archetype") == "generator"]
gen_bad = [m["id"] for m in gen if len(m.get("checks", [])) != n_crit]
if not gen:
good("README audit_4big · aucun module d'archétype generator (rien à recouper)")
elif gen_bad:
bad(f"README audit_4big · modules generator avec ≠ {n_crit} checks : {gen_bad} "
f"→ « generator = tous les critères » violé")
else:
good(f"README audit_4big · {len(gen)} module(s) generator portent {n_crit} "
f"checks (« generator = tous les critères » vérifié)")
# ============================================================================
# Fiches agents · comptes de tests PAR SUITE (colonne « Tests » des tables) —
# même classe de « vert trompeur », au grain le PLUS FIN.