Défaut latent, byte-repro-aveugle : _cond_apport arrondit percent à 1 décimale
(round) tandis que ok est un test exact. Un versement dans la bande [99.95%,100%[
(ex. 19 999/20 000 USD = 99.995%) remonte à percent:100.0 alors que ok=False,
remaining=1 USD → barre frontend « 100% ✓ » qui refuse la soumission + raison
auto-contradictoire « reste 1 USD · 100.0% ». Seul _cond_apport atteignable
(montant continu) ; documents/autorisations = ratios entiers sur listes 13/4,
bande inatteignable.
Fix chirurgical : garde `if not ok and pct>=100.0: pct=99.9` → invariant
d'affichage percent==100.0 ⟺ ok. Échantillon commité à 67.8% (hors bande) →
gate_status_example.json/out rebuild BYTE-IDENTIQUE.
Test à dents test_apport_quasi_complet_ninclut_pas_100pct (mordu sans le fix).
Cascade +1 test : régression 633→634/616→617, plan+MANIFEST+quality_report
régénérés, fiches QA/Backend/CRM re-dérivées. run_ci 33/0/0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bug latent réel (crm/commissions/commlib/finance.py:75) : le libellé de base de
la formule traçable « commission = base × taux » utilisait f"{base:g}", qui casse
deux fois sur des montants immobiliers réels en RD (une unité USD 300k ≈ 18M DOP) :
(1) notation exponentielle dès 1e6 (18000000 → 1.8e+07, illisible/non auditable) ;
(2) arrondi silencieux à 6 chiffres significatifs (123456.78 → 123457) = une base
FABRIQUÉE ≠ de la réelle, l'invention interdite par #6 dans le module même qui
proclame l'anti-invention.
Fix : helper _amount_label (f"{x:f}" jamais exponentiel + strip zéros) → décimal
fidèle, identique à l'ancien pour tous les montants simples (200000 reste 200000) ;
seuls les cas buggés changent. 2 tests à dents (millions non-exponentiel + décimales
préservées) — teeth prouvé : les DEUX échouent sans le fix.
Byte-repro : 0 impact d'artefact du module (compute_line est runtime, jamais appelé
par le générateur). Cascade compteur-de-suite seule : matrice 631/614 → 633/616,
regression×3 + quality_report régénérés, fiches qa/erpnext/crm + README réalignés
(commissions 25→27, Total CRM 81→83). run_ci 33/0/0. 0 code moteur V18 (bloqué D-06).
0 gate ajouté (#5). 0 commande VPS (#8).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Durcissement d'uniformité (pas bug déclenchable aujourd'hui) qui COMPLÈTE le fix
correctness de la session 070054 (aeb30b8). Ce fix-là a percent-encodé
hero['fichier'] dans src=f"/static/projets/{code}/{quote(fichier)}", mais dans la
MÊME url('…') CSS il restait un 2ᵉ segment dynamique — `code` — interpolé brut puis
html-échappé via _esc(src). C'est exactement l'anti-pattern identifié par 070054
(html.escape = mauvais encodeur pour un segment d'URL), appliqué de façon incomplète.
Fix : src = f"/static/projets/{quote(code)}/{quote(hero['fichier'])}" — quote() est
le SEUL encodeur correct pour un segment d'URL ; le CONTEXTE, pas la donnée courante,
dicte l'encodeur. Zéro dérive : codes réels = P01..P09 (§Projets), quote("p01")=="p01"
→ byte-repro inchangé. Cas frère exact de 060044/criteria.py (« durcir le SEUL membre
non-durci d'une famille ») : ici le SEUL segment d'URL non-encodé de la même url().
Test à dents (test_hero_media_code_segment_percent_encoded) : code théorique "P'X" →
prouvé FAIL sans quote(code), PASS avec. Suite publiciste 25→26, matrice 630/613→631/614.
Défaut d'abord : classe encodage-contextuel balayée sur tous les modules HTML/CSS/URL ;
2 candidats Explore réfutés non-défauts (chat mount_html = persona forcée Amélie par
invariant 7 + portail_key enum ; code segment = théorique mais durci par uniformité).
Cascade régénérée dans l'ordre (quality_report en DERNIER) · 3 fiches compteurs réalignées.
run_ci 33/0/0 · NFC-clean · zéro code moteur V18 (bloqué D-06 #6) · zéro gate (#5) · zéro invention (#6).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
_ADD_PARSER_RE exigeait la parenthèse collée (add_parser\(|add_subparsers\() → `add_subparsers ()` / `add_parser ("build")` (espace avant `(`, Python valide, PEP 8 déconseille sans imposer) silencieusement loupés → sous-scorage −20 pts du critère CLI d'un module sain (symptôme fd99362). Durci en add_parser\s*\(|add_subparsers\s*\(, harmonisé aux 2 frères déjà durcis (_TEST_DEF_RE `def\s+`, _MAIN_GUARD_RE `\s*==\s*`) et à la doctrine écrite du fichier (l.18-30 « détecter la forme, pas une graphie »). 4e fix de cette classe dans ce fichier après ac595d0/fd99362/35de616.
Fix latent (aucun module n'utilise l'espace → quality_report.json byte-identique, check_artifacts vert) mais teeth-prouvé (ancien regex False sur les 2 formes espacées, nouveau True + True sur les formes normales). Cores computationnels commissions/bancable audités CLEAN par ailleurs. run_ci 33 PASS 0 FAIL 0 SKIP · 0 gate (#5) · 0 chiffre inventé (#6) · 0 VPS (#8).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Même racine que le fix ASCII ac595d0 : une détection assume une graphie là où le langage admet plusieurs formes. Fix = regex de FORME (_MAIN_GUARD_RE : 2 styles de guillemets · ordre inversé · espacement libre) + teeth test_cli_detects_single_quoted_and_yoda_guards (3 fixtures, prouvé mordant : ancien littéral rend False sur les 3, nouvelle regex True). Robustesse pure : les 50 gardes du dépôt sont double-quotées et toujours matchées → aucun score ne bouge, quality_report.json byte-identique (audit_4big s'auto-exclut de son scoring). Cascade régression uniquement : 626/609 → 627/610 (nouveau test) + fiches qa/audit_4big 35→36 & agrégat & backend 626→627 re-dérivés (RED check_readme_claims). Sweep préalable : classe ASCII-vs-Unicode close au niveau CODE (générateurs+libs+gates shell tous ASCII-par-domaine sauf les 2 compteurs test déjà \w).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
criteria.py:18 comptait les méthodes via char-class ASCII [A-Za-z0-9_] →
loupait le test réel `test_traçabilite_source` (ç · PEP 3131, exécuté par
unittest) → évidence fausse « 22 méthodes » pour publiciste (réel 23), en
violation du cœur anti-invention #6 de l'audit lui-même. La source sœur
qa/regression/reglib/discovery.py:23 comptait déjà correctement (`test_\w+`,
\w Unicode) = 23 → les 2 outils QA divergeaient d'un. Fix aligné sur la sœur
(\w). Teeth ajoutée (test_tests_counts_non_ascii_method_names, mordante :
1 sur l'ancienne regex, 2 sur la nouvelle).
Cascade régénérée : quality_report.json (publiciste 22→23, verdict PASS 24/24
min 100 inchangé) · regression_run/plan/MANIFEST (625→626 exéc · 608→609 passés)
· fiches qa (audit_4big 34→35, agrégat 626/609) + erpnext_backend (625→626).
Blast-radius = 1 seul nom de test non-ASCII dans tout le dépôt (scan AST 24
suites). Pas de nouveau gate (#5) : check_readme_claims mord déjà la divergence.
run_ci = 33 PASS · 0 FAIL · 0 SKIP. 0 code moteur V18 (#6) · 0 VPS (#8).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Constat: faisabilite/generator/brief.schema.json, documenté « Contrat d'entrée »
et sibling de version/projets_master (tous deux test-enforced), n'était validé
par AUCUN test — _validate_brief() ne garde que le code projet, jamais la forme
complète du brief; un brief drifté hors contrat passait inaperçu.
Fix (teeth): test_input_briefs_validate_against_brief_schema valide les 2 fixtures
contre brief.schema.json via le validateur maison Publiciste (zéro-pip, toujours
exécuté, pas de skip sous python -S). Conformité pré-vérifiée sous validateur
maison ET oracle jsonschema. L'« incomplet » est conforme au sens schéma
(null admis) — incomplet seulement au sens sémantique (prix→placeholders #6).
Cascade régénérée (générateurs, jamais à la main #6): regression_plan/run/MANIFEST
16→17 · totaux 624→625 exécutés / 607→608 passés / 17 skippés · quality_report
evidence 16→17. Prose gatée réalignée (le gate check-readme-claims a mordu):
README module + fiches faisabilite/qa/erpnext_backend. Prose ungatée: GAP_ANALYSIS
16→17 + nouveau bloc daily_report (blocs currency antérieurs = snapshots datés,
non réécrits).
0 gate ajouté (#5) · 0 chiffre à la main (#6) · 0 commande VPS (#8).
run_ci.sh = 33 PASS · 0 FAIL · 0 SKIP.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Vérité-terrain : grep -c def test_negative_ = 10 (réparties Keywords/SchemaOrg/Hreflang/Manifest, PAS de classe dédiée) ; git show 0d3b242 = déjà 10 dès la création → jamais un état vrai antérieur (pas historical-repro). Piège confotur écarté : les 2 frères qui affichent un sous-compte négatif en prose sont EXACTS car adossés à une classe nommée countable (confotur « 8 négatifs » = classe TestNegative=8 ; devops « 14 injections négatives » = classe TestNegativeInjections=14) — SEO est le seul faux, ses négatifs ne forment pas de classe. Toute la classe « sous-compte négatif en prose » (seo/devops/confotur) auditée end-to-end.
Surfaces (balayage twin-fix) : seule seo/README.md:67 corrigée (présent-tense, doc vivante) ; les 2 autres occurrences du « 8 » sont dans daily_reports/2026-07-30-session18.md + 05_activity_log/2026-07-30.md = snapshots datés du 2026-07-30 → KEEP.
Effet de bord : audit_4big score le contenu README → quality_report.json régénéré EN DERNIER (seule ligne changée : evidence README.md 3900→3901 octets) · verdict PASS · 24/24 ≥95 (min 100) inchangé.
0 gate ajouté (#5 · erreur d'origine isolée, pas une dérive récurrente ; total déjà gaté ; précédent confotur = ne pas gater ces sous-comptes) · 0 édition d'autorité (le test file n'est pas modifié) · 0 chiffre inventé (#6) · 0 commande VPS (#8). run_ci.sh : 33 PASS
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`regression_gen.py` (docstring l.26) ET `qa/regression/README.md` (§ hand-off VPS
l.76) décrivaient encore la sortie `run` comme « NON déterministe → non commitée »
/ « manuel · non gated push/PR ». Faux sur les trois points, contredit par son
propre gate dédié `ci/check_regression.sh` (step `check-regression` de ci.yml) :
`regression_run.json` EST commité (git ls-files), EST déterministe (aucun
horodatage/hôte → deux `run` byte-identiques, en-tête du gate l.24-25) et EST
byte-gaté à chaque push/PR. Même dérive « regression_run.json non commité » déjà
corrigée dans le README racine (76fb0e7) mais restée dans le module lui-même.
Réalignés sur la réalité + citation du gate. Consommateur `qa/audit_4big/out/
quality_report.json` régénéré (évidence DOC 4236→4396 octets · verdict PASS 22/22
≥95 min 100 inchangé · 1 insertion/1 suppression · artifact-reproducibility-gate).
Docstring .py non byte-gatée (aucun gate n'en lit les octets). run_ci.sh 30 PASS 0 FAIL.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sweep docstring-vs-CODE des sous-paquets lib/ (nouveau périmètre vs les
générateurs de tête déjà balayés). Concordance quasi totale — UNE dérive réelle :
le docstring d'en-tête de qa/audit_4big/q4lib/builder.py annonçait « les 17 modules
atteignent >= 95/100 » alors que l'artefact commité out/quality_report.json porte
totals.modules = 22 (tous PASS). Le compte a grandi 17->22 au fil des livrables gatés.
Preuve d'antériorité : ci/check_readme_claims.sh l.414-417 documente CETTE dérive
exacte — « 17/17 SAISI À LA MAIN … PÉRIMÉ … (17 -> 22) » — et re-calcule le compte
du README de l'auditeur (désormais 22/22), MAIS le gate ne couvre pas le docstring
du module (les docstrings ne sont pas count-checkés · classe docstring-vs-code-drift).
Le même « 17 » gaté dans le README a survécu, non gaté, dans le docstring de prod.
Correction anti-re-dérive : pas de substitution « 22 » (re-dériverait au module #23) ;
reformulé en énonçant la RÈGLE réelle du builder (verdict = coverage.ok AND not below
=> TOUS les modules audités >= 95/100), + note que le compte est DÉRIVÉ (len(modules)
== totals.modules). Aligné fix-vs-gate (décrire depuis l'autorité = le code).
Zéro module · zéro gate (#5) · un seul fichier de prod touché (docstring seul, zéro
logique) · run_ci.sh 30 PASS · README module gaté déjà à 22/22 (concordant).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
La table §3 de RBAC_50_ROLES_SPEC.md avait dérivé du contrat en préservant le total
50 (10+5 vs 9+6) → invisible aux gates agrégés. Correction alignée sur la source +
nouveau bloc check_readme_claims recomptant chaque portail (et le total) depuis
rbac_50_roles.json. quality_report.json régénéré (evidence octets SPEC). 7 gates PASS.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
INV10 ne garantissait que « roadmap_line est un entier positif ». Ajout de
parse_roadmap_anchors (deps) qui DÉRIVE la structure réelle de la roadmap, et
d'INV11 qui exige que chaque roadmap_line pointe RÉELLEMENT son bullet
(DELIVERABLE du sprint SX · k-ième bullet métrique) et que le « 8 + 7 » soit
dérivé du fichier, pas figé. Morsure prouvée sur le spec réel (S1=999, M3=200).
Régénéré consommateurs : regression 558→564 (run/plan/MANIFEST), quality_report
(acceptance 31→37 méthodes, 100/100 inchangé), fiches QA + Backend, README
acceptance (10→11 invariants). 7 gates verts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Défaut réel (même classe que le bug regression_run.json corrigé plus tôt) :
les 4 générateurs RBAC (fixtures_gen/userperm_gen/roleprofile_gen/apply_plan)
.gitignore-aient leur out/, alors qu'ils sont audités en archétype `generator`
(critère HANDOFF). En checkout PROPRE (git archive HEAD = ce que voit le runner
Gitea) leur out/ est absent → qa/audit_4big (dont le build relit le out/ de
CHAQUE module) les note 80<95 ⇒ INV7 ⇒ build refusé ⇒ check-artifacts ET
check-regression ROUGES. Ça ne passait qu'en local via les out/ non suivis
laissés par des build manuels.
Fix : committer le out/ des 4 générateurs (build byte-déterministe prouvé ;
apply_plan lit ses frères en process, pas via out/) → alignement sur les 15
autres générateurs ; audit 100/100 en checkout propre.
Durcissement : check_artifacts.sh exige désormais `git ls-files --error-unmatch`
sur chaque fichier produit → un out/ ignoré/non commité devient une erreur
LOCALE honnête au lieu d'une surprise en CI. Bite-proof : git rm --cached d'un
artefact (laissé sur disque) ⇒ exit 1 ; re-add ⇒ exit 0.
Régénéré : quality_report.json (dérive DOC = taille des 4 README édités).
Vérifs : 6 gates verts sur git archive propre ; 534/21 inchangé ; suites OK.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Défaut #1 (bug CI réel) : ci/check_regression.sh exigeait regression_run.json
commité comme baseline, mais le fichier était .gitignore → absent en checkout
propre → le job Gitea check-regression échouait sur CHAQUE run CI (ne passait
qu'en local via un fichier non suivi). L'artefact run est byte-déterministe
(aucun horodatage/hôte/durée · path relatif) → committer est licite. Fix :
run désormais commité (baseline), .gitignore + README réécrits.
Défaut #2 (invariant manquant) : coverage_report prouvait CI→disque mais pas
l'inverse. Nouveau disk_test_modules() + orphan_tests_dirs dans INV4 : un module
gagnant un tests/ sans job CI fait chuter la couverture (fini la sous-comptée
silencieuse de la matrice). Schéma + 2 tests de morsure.
Consommateur régénéré : qa/audit_4big/quality_report.json (README 3710→4236 o,
24→26 méthodes). Matrice 534/21/PASS inchangée (harnais self-exclu, INV3).
5 gates verts · 26+34 tests OK · YAML valide.
Seule fiche agent (parmi qa/crm/devops qui en ont une) sans aucun lien vers ses
livrables gated : 03_agents/faisabilite/AGENT.md avait 0 lien 05_deliverables_mvp
vs 3 chez ses pairs. Aucun chemin de la mission vers les artefacts commités qui la
réalisent — vrai gap de finition, non un polish cosmétique.
+ section « Livrables Faisabilité réellement produits » (table calquée sur le
pattern des agents pairs) · 3 entrées TOUTES vérifiées par lecture directe :
TEMPLATE_FAISABILITE_CANONIQUE_v1.0.md [S1 · check-docs] · generator/ [S2 ·
faisabilite_gen score/scaffold/generate/batch · faisabilite-gen-tests · 16t] ·
bancable/ [S3 · bancable_gen build/validate · bancable-tests · 22t].
Anti-invention #6 : sprints lus dans en-têtes README/CLI, sous-commandes via --help,
comptes de tests repris du regression run faisant autorité, jobs CI lus dans ci.yml.
Frontière worker/VPS #8 rappelée : générateurs = contrepartie commitée+testable des
composants runtime OTOIA hors périmètre (aucune faisabilité PXX concrète prétendue).
Vérifs : check_docs vert (0 lien cassé · 3 nouveaux liens relatifs résolvent) ·
guard_constraints vert (exit 0). Doc-only, 0 code · régression inchangée 534 verts.
Auto-score 4Big 96/100.
Harnais méta-niveau : agrège l'exécution de toutes les suites gated en une
matrice + verdict PASS/FAIL et fournit le compte agrégé faisant autorité
(N tests verts). Périmètre dérivé du CI (réutilise q4lib/registry.parse_ci ·
zéro duplication) ; anti-invention (#6) : le plan ne contient aucun compteur de
résultat, recomputé à la validation. Enregistré dans l'audit 4Big (18→19
modules · PASS 19/19). run exhaustif : 19/19 suites vertes · 474 tests passés.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Orchestrateur méta-niveau : compose les hand-offs out/ des 10 modules déjà
livrés en un run-sheet de démo jouable, via pointeurs RFC 6901 résolus à la
construction (zéro chiffre en dur · #6). Réutilise le validateur Publiciste et
la preuve de couverture CI de l'auditeur 4Big (#5) — une démo ne s'appuie que
sur des modules gated. Enregistre demo/scenarios dans l'audit 4Big (17→18,
verdict PASS 18/18 à 100). 32 tests (9 injections négatives) · régression 474
tests verts · guards CI verts · builds déterministes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Audit de méta-niveau + gate : note la qualité 4Big de 100% des livrables gated
et bloque (FAIL) si un module < 95/100 (CLAUDE.md #5). Couverture PROUVÉE par
recoupement bijectif registre ↔ working-directory du CI (moins l'auditeur · SoD
ISA 315). 5 critères déterministes (DOC/CONTRAT/TESTS/CLI/HANDOFF) renormalisés
par archétype. Anti-invention (#6) : chaque note est recalculée depuis des faits
du dépôt, jamais saisie ; un invariant recompute chaque note.
Résultat : PASS · 17/17 modules à 100/100. Régression 442 tests verts (+34).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>