Python json.load (validate_json.sh) ACCEPTE NaN/Infinity/-Infinity par défaut ;
le JS JSON.parse de la Console Helios lève SyntaxError dessus → un artefact NaN
(dérivé div-par-zéro sérialisé allow_nan=True) passerait tous les gates + byte-repro
tout en cassant le rendu navigateur = faux-vert invisible à la chaîne Python.
Détecteur stdlib json.loads(parse_constant=raise), teeth 5/5 (NaN/Infinity/-Infinity
MORDENT, float+chaîne 'NaN' épargnés) + e2e mutant sur fichier réel flagué.
CLEAN 114/114 out/*.json. run_ci 33 PASS 0 FAIL 0 SKIP inchangé, rejouable, pas de gate (#5).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Axe FRAGMENT jamais balayé : check_docs valide la cible-FICHIER d'un lien mais RETIRE le #slug (link=${link%%#*}) et ignore les ancres pures → un [label](#titre) dont le titre est renommé/typo passe au vert (fichier existe, saut d'ancre mort, silencieux). Détecteur stdlib (slug GitHub/Gitea, accents conservés, code-spans neutralisés) sur 379 .md → 1 seul lien-ancre réel (README:20 → ## Directives Michel...) résout, 0 pendante ; 2 ](#frag) en code-span écartés. Teeth-prouvé (valide True, mutant-typo False). run_ci 33 PASS 0 FAIL 0 SKIP inchangé, 0 édition prod, rejouable, pas de gate (#5).
Axe NEUF absent mémoire : tous les axes numériques testent la VALEUR (accord inter/intra, re-dérivation, arithmétique) ou la forme-date ; aucun ne teste la FORME scalaire JSON. Un compte '3.0'/'"3"' au lieu de 3 se lit pareil mais casse type:integer / == strict / colonne typée = aveugle au byte-repro ET aux oracles (tous type:number accepte int+float, un sequence_id float passe). 3 sous-checks teeth-prouvés (/tmp stdlib) : (A) cohérence type intra-fichier par chemin structurel, (B) clés-compte nb_*/…_total/passed = int obligatoire, (C) 0 NaN/Infinity. Dents : un sequence_id int-parmi-floats MORD, nb=5.0/"44" MORD, comptes réels épargnés. Résultat CLEAN : B=0 C=0 ; A flague seulement run_sheet valeur (colonne clé-valeur hétérogène by-design) ; divergences inter-fichiers = collisions de nom per-module. 2 formes délibérées NON-défauts (sequence_id float = cast wslib/frappe.py:162 fidélité Frappe Float ; is_submittable 0/1 int = convention DocType Frappe). run_ci 33 PASS 0 FAIL 0 SKIP inchangé, rejouable, pas de gate (#5)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Question neuve : quand un même concept-singleton plateforme apparaît comme scalaire dans deux out/*.json indépendants, les valeurs s'accordent-elles ? Une divergence silencieuse ship verte car aucun gate ne compare deux artefacts entre eux. Détecteur teeth-prouvé (57 fichiers ; position GLOBALE sans indice [i] = singleton vs PER-ROW = compte-de-ligne) : mutation cible_rbac_roles 50→49 dans un manifest → MORD. Résultat CLEAN : tous les singletons plateforme s'accordent (cible_rbac_roles=50, ci_modules_count/modules/suites=24, portails=5, doctypes_uniques=45, custom_docperm=116, role_profiles=6, min_score=100, pass_score=95).
TRAP documenté : « même nom = même concept » sur-signale — fields/data_fields/permissions/roles/sections/pass divergent car chacun décrit SON propre DocType/suite (per-module-local, pas un singleton). Seul nom SURCHARGÉ divergent = roles_couverts 50 (tous les role-profiles) vs 44 (rôles des 5 portails business = 50 − 6 plateforme) = by-design, les deux re-dérivés de rbac_50_roles.json.
0 gate ajouté (#5, occurrence-zéro rejouable), 0 commande VPS (#8), run_ci 33 PASS 0 FAIL 0 SKIP. Canal stakeholder daily_reports porté 3710253→HEAD.
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>
Nouvel axe absent de la mémoire, distinct de module-suite-teeth-mutation (mute la LOGIQUE) et
schema-oracle-teeth-audit (audite l'ORACLE) : cible le HARNAIS de test lui-même. 3 cas où une
méthode est définie mais unittest discover ne l'exécute jamais, sans qu'aucun gate ne le voie —
(a) def test_x dupliqué dans une classe (Python garde la dernière liaison), (b) class TestFoo
dupliqué dans un fichier (2ᵉ masque 1ʳᵉ), (c) def test_* niveau-module (discover ne le lance pas).
Trou réel : un shadow passe par absence ET ferait SUR-compter check_readme_claims (compte textuel
des def test_). Détecteur AST teeth-prouvé sur sonde synthétique (3/3 mordent). Balayage réel
CLEAN 25/25 fichiers (0 méthode-dup, 0 classe-dup, 0 test niveau-module). Sweep rejouable, NOT a
gate (occurrence-zéro, #5). run_ci 33 PASS 0 FAIL 0 SKIP · 0 prod édité · 0 artefact reconstruit.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Nouvel axe: la FORCE de la couche oracle elle-même (distinct des dents de logique-générateur). ~20 modules ont un test_schema_oracle qui valide le build-mémoire contre un *.schema.json commité; un schéma vide ({} / type:object sans required) ou malformé rendrait cet oracle faux-vert (accepte tout) — classe ungatée, byte-repro & suites aveugles à la force du schéma. Audit 26/26: tous valides Draft-N + non-vides (required+properties, kw 3..103). Détecteurs de l'audit prouvés: validité mord un schéma malformé, dents mord {} et {type:object}, 0 faux positif sur rbac.schema. Connexes CLEAN: role_id→erpnext_role_name = fonction sur 57 artefacts (0 conflit); oracle exécuté non-skippé sous run_ci (python3 nu, jsonschema 3.2.0); 0 TODO/stub prod. Lecture-seule, occurrence-zéro, rejouable → PAS un gate (#5). run_ci 33 PASS 0 FAIL 0 SKIP · 0 prod édité · 0 artefact reconstruit · 0 gate ajouté (#5)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Un Explore adversarial a re-flagué (2e fois) la cellule « Sortie » du chat_otoia
comme « manque MANIFEST.json » — faux positif connu (fiche-sortie-cell-omits-manifest-
by-design) : les DEUX rangs (portails+chat) listent le payload seul, MANIFEST omis par
convention, docstrings/READMEs énumèrent les 3 (byte-gatés). La récurrence prouve un
footgun non documenté (brûle des cycles d'audit, risque un fix #5/#6 cassant le gate
regex-parsé). Mitigation : blockquote « Note de lecture » après la table, rédigé pour
éviter les regex ancrées du gate (aucun compteur cartes/liens/rôles ni **N tests**).
check_readme_claims PASS · check_docs PASS · run_ci 33 PASS 0 FAIL 0 SKIP · 0 artefact
reconstruit · 0 gate ajouté (#5) · 0 chiffre inventé (#6) · 0 commande VPS (#8)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Investigation: les 6 marqueurs canoniques #9/#10 existent en ≥4 endroits. Hypothèse
« (c) renderer._CANONICAL_MARKERS + (d) l'oracle du test sont des copies non gatées
→ dériver de model.CANONICAL (source unique) ». RÉFUTÉE par ./run_ci.sh (check-readme-claims
RED): la 2e moitié du gate ast.literal_eval STATIQUEMENT ces 2 listes et les set-diffe vs
CLAUDE.md → déjà gatées. Et surtout: check_canonical() PROUVE que le rendu (bâti DEPUIS
model.CANONICAL) émet chaque valeur; le dériver de CANONICAL rend le contrôle tautologique
(vert vacux). EXCEPTION à fix-vs-gate-transitively-protected-constant (qui vise les copies
PASSIVES; un oracle d'enforcement est ACTIF, sa duplication EST le test). Revert intégral
des 2 éditions (test byte-identique). Seul survivant: +5 lignes de commentaire remontant la
raison (indépendance de l'oracle) au site de code, autrement enfouie dans le script CI.
Sortie inchangée (commentaire pur), check_artifacts byte-identique.
run_ci 33 PASS 0 FAIL 0 SKIP · 0 artefact reconstruit · 0 gate ajouté (#5) · 0 chiffre inventé (#6)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Axe NEUF (absent mémoire): liens `[`label`](cible)` où le label code-span est un
chemin de fichier EXISTANT dont le basename diffère de la cible href. check_docs
prouve que la cible résout, jamais que le label la désigne — un Cmd-clic sur
`ci/guard_constraints.sh` atterrissait sur `ci/README.md` (mauvais fichier).
Balayage git ls-files '*.md' → 3 occurrences, toutes README.md (L54 x2 + L75).
Les scripts nommés existent + sont git-trackés (gates) ⇒ FIX = pointer chaque
label vers le fichier qu'il nomme. label==cible, navigation véridique, check_docs
toujours vert. Re-balayage mismatch → 0.
Axe éliminé au passage (CLEAN, non re-flaggé): chemins-fantômes backtick — 2
survivants = faux positifs (label de lien à vraie cible · résolution sous-arbre
confotur/cflib). run_ci = 33 PASS · 0 FAIL · 0 SKIP. 0 gate (#5, origine isolée),
0 artefact rebuild, 0 chiffre inventé (#6), 0 VPS (#8).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sweep rejouable de tous les out/*.json: 0 slug de rôle non résolu vs les 50 ids canoniques;
6 tokens portail hors portails_business = non-défauts vérifiés (5 valeurs icon ERPNext du champ
mobile + le 6e portail technique legitime plateforme). Axe jamais balayé, distinct de
docstring/currency. 0 prod, 0 artefact rebuild, 0 gate (#5), 0 chiffre inventé (#6), 0 VPS (#8).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Défaut réel/reproductible (pas stale, byte-repro vert) : finlib/builder.py:89
faisait [roles_resolved[k] for k in sorted(roles_resolved)], itérant les 4 SLOTS
logiques de spec["roles"] — 2 slots (conseiller_wag ET validation_dossier) pointent
le même rôle ventes-conseiller → 4 entrées pour 3 rôles distincts. Preuve bug (pas
per-slot voulu) : la sortie drope la clé de slot (cle), donc le doublon ne porte
aucune info distinctive ; sémantique documentée README.md:54 « rôles RBAC utilisés »
+ ci/README.md:1100 « ensemble distinct » ; les 3 modules frères produisent tous un
ensemble distinct (confotur 3/3, commissions 4/4, workflow_vente 7/7) — financement
seul outlier 4/3.
Fix (aligné idiome commissions) : ensemble distinct trié par role_id via
sorted({rr["role_id"] for rr in roles_resolved.values()}). Artefact régénéré → 3/3
distinct. 0 gate ajouté (#5 — champ lu par AUCUN gate financement ni consommateur
externe ; convention distinctness déjà tenue par les frères). 0 chiffre inventé (#6).
run_ci 33 PASS · 0 FAIL · 0 SKIP (byte-repro vert avec nouvel artefact, 35 tests verts).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Poursuite de la sous-classe help-text du fix a8342e9 (session 004414). Audit exhaustif
des 22 générateurs `*_gen.py` (help d'une sous-commande énumérant ses fichiers de sortie
↔ fichiers réellement écrits) → 21/22 CLEAN, 1 vrai défaut : seo_gen.py:293.
Le help `build` disait « genere seo_keywords/schema_org/hreflang + MANIFEST » alors que
le code (l.259-262) écrit seo_keywords.json, seo_schema_org.json, seo_hreflang.json,
MANIFEST.json : le help droppait le préfixe seo_ sur 2 des 3 fichiers (schema_org,
hreflang) + l'extension .json sur tous → nommait des fichiers INEXISTANTS
(schema_org ≠ seo_schema_org.json). Même classe que a8342e9.
Preuve fix-en-une-passe : docstring module (l.6-9) ET README (l.15-18) nommaient déjà
correctement les 4 fichiers exacts ; le help était le seul outlier, aligné maintenant
sur eux + la convention des frères (commissions/audit_5d/app_config = noms complets).
Style ASCII sans-accent du fichier respecté (genere).
0 gate (#5 — help ni sérialisé ni AST-parsé ; parseur de help fragile : pas de
convention commune aux 22, classe couverte par audit périodique). Sortie build
byte-identical aux 4 out/ commités (0 rebuild). 0 prod (#8), 0 chiffre inventé (#6).
run_ci 33 PASS · 0 FAIL · 0 SKIP.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Défaut réel (classe prose-facts-vs-numeric-drift) présent dans DEUX surfaces —
daily_reports/2026-08-06.md (l.48-54, canal stakeholder) ET 05_activity_log/2026-08-06.md
(entrée 011419) : l'« axe de vérification objectif » annonçait « concordance totale sur les
14 READMEs annonceurs » mais son énumération omettait 2 modules qui annoncent pourtant un
compte de tests dans leur README, tous deux concordants avec le réel — frontend/portails 19
(19 def test_) et demo/scenarios 39 (39 def test_). Le vrai total est 16 annonceurs / 9 sans
annonce, corroboré par l'en-tête faisant autorité de ci/check_readme_claims.sh (l.96 :
« 27 claims sur 16 modules »). Le « 11 sans annonce » était le complément erroné 25−14 → 9.
Fix (sweep des 2 surfaces en une passe, cf. prose-facts-vs-numeric-drift : un twin fix balaie
TOUTES les surfaces) : daily_reports 14→16 + ajout des 2 entrées manquantes + 11→9 + ancrage
explicite au gate ; journal 14→16 dans l'entrée 011419 (fait courant) avec commentaire de
traçabilité + nouvelle entrée documentant la correction. Chiffres recomputés, non saisis
(grep READMEs annonceurs=16 · def test_ concordance 16/16 · find tests=25 → complément 9).
Écarté au préalable : candidat comment↔code check_regression.sh:17 (« ran/passed/failures »)
= FAUX POSITIF — le commentaire décrit ce que l'ARTEFACT porte (le JSON a bien failures:0),
pas la ligne d'affichage l.79 ; le contrat réel = diff -q byte-à-byte du fichier entier l.71.
0 prod édité, 0 artefact rebuild, 0 gate ajouté (#5 — la surface README-count est déjà gatée),
0 chiffre inventé (#6), 0 VPS (#8). run_ci 33 PASS · 0 FAIL · 0 SKIP avant/après.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Chasse adversariale ciblée (classe RECURRING docstring↔code, scopée aux modules non balayés
la veille) → 1 vrai défaut ungaté. Le help= de sub.add_parser("build") énumérait 4 sorties
(app_config/eas_build/role_navigation/MANIFEST) alors que cmd_build() en écrit 5 : store_listing.json
(l.243) était omis. Docstring (l.15 « les 5 fichiers ci-dessus ») + README (l.56/68) listent bien
les 5. Nouvelle sous-classe help-text argparse du motif docstring↔code (2e surface prose dans le code,
distincte des open('w') vs docstring déjà balayés). Fix = ajout store_listing.json à sa position
canonique. Aucun gate/test ne fige la chaîne (grep -rn = 0 hit externe) → pas d'oracle à réaligner,
pas de gate ajouté (#5). Non-régression : help n'affecte aucune sortie, artefacts byte-identiques,
run_ci 33 PASS·0 FAIL·0 SKIP avant/après. Reste de l'audit (audit_5d/acceptance/regression/
deploy_runbook/commissions/dossier_vente/ecf/portails/faisabilite) CLEAN. 0 artefact rebuild, 0 VPS (#8).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Chasse à un vrai défaut ungaté (agent Explore skeptique) plutôt que répéter le motif de currency (churn). Candidat remonté puis RÉFUTÉ par vérif indépendante : la cellule « Sortie » de 03_agents/frontend_console/AGENT.md omet MANIFEST.json dans les DEUX lignes (portails:28 `out/workspace.json` alors que workspaces_gen.py:219 l'écrit ; chat_otoia:29 `{custom_block,chat_mount}` alors que chat_otoia_gen.py:229 l'écrit) → convention éditoriale (payload listé, manifeste de traçabilité omis), PAS une dérive. L'énumération complète des 3 fichiers est correcte là où elle compte (docstring chat_otoia_gen.py:12/15/18 + README module). Corriger la seule ligne chat = asymétrie ; éditer les deux = churn d'une cellule parsée par ci/check_readme_claims.sh (CO_FI ~L3506/L3576). CLEAN, laissé tel quel (#5/#6, « X not drift, don't fix »).
0 fichier de production édité, 0 artefact reconstruit, 0 gate ajouté (#5), 0 chiffre saisi (#6, 33 recompté de run_ci.sh), 0 VPS (#8). Seule édition in-repo : le journal. Mémoire projet : fiche-sortie-cell-omits-manifest-by-design.md. run_ci 33 PASS·0 FAIL·0 SKIP.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Le gate valide la bonne-formation JSON SEULEMENT (parse strict), mais l.27 portait un
commentaire orphelin annonçant un contrôle de conformité $schema/draft que le code
n'implemente jamais (branche then imprime juste le check). Nouvelle sous-classe
comment-vs-code : les scripts de GATE eux-memes, jamais couverts par les sweeps
docstring-vs-code (scopes aux generateurs de prod + helpers *lib/).
Isolement verifie : sweep des 8 scripts ci/*.sh + lib.sh = 0 autre derive.
Fix 2 volets : (1) suppression de la ligne fantome ; (2) en-tete PERIMETRE explicite
(bonne-formation seule ; conformite $schema = oracle jsonschema optionnel de
check_regression.sh, 17 skips par design) -> le commentaire retire devient une
affirmation positive et vraie du perimetre.
0 changement de logique executable, 0 artefact rebuild, 0 gate ajoute (#5, FIX pas
controle neuf), 0 chiffre saisi (#6), 0 VPS (#8). run_ci 33 PASS / 0 FAIL / 0 SKIP.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
La table §1 « Ce que fait le pipeline » de ci/README.md est LA doc canonique des jobs
statiques (une ligne par gate ci/*.sh). Sa complétude était le jumeau exact de la fiche QA
fermée par afa6165, mais NON gaté : check_ci_integrity verrouille le câblage (ci/*.sh ↔
gate.needs), le bloc fiche-QA ne lit que 03_agents/qa/AGENT.md — rien n'exigeait que chaque
gate figure dans la table §1. Un 9ᵉ gate y serait omis EN SILENCE. Prouvé ungate par mutation
(retrait de la ligne de table check_mobile_workflow → run_ci --static 8 PASS, aucun gate ne mord).
Fix = extension du gate existant (PAS un nouveau job · #5) : bloc Python dans check_readme_claims.sh
(avant sys.exit) réutilisant _gate_names re-dérivé de git ls-files 'ci/*.sh' (hors lib.sh · #6).
Exige chaque basename cité dans une LIGNE DE TABLE (|…) de la section §1 — délibérément PAS la
prose §1 (qui ne cite que certains gates pour l'explication mobile-build.yml : un contrôle
whole-section serait édenté sur un retrait de ligne de table). 0 nouveau ci/*.sh, 33 jobs inchangés.
Teeth 2 axes : MUT1 suppression de la vraie ligne de table (l.24) → RED nommant check_mobile_workflow.sh ;
MUT2 9ᵉ ci/*.sh factice tracké → RED sur les DEUX surfaces (fiche QA + table §1 : forward-protection)
puis git rm --cached + rm, arbre byte-restauré (JAMAIS git clean). Piège inerte écarté : sed 15d
visait l'en-tête de table (grep -n renumérotait relatif au pipe), re-ciblé sur la ligne 24 réelle.
Doc sous-section « COMPLÉTUDE de l'énumération dans la TABLE §1 » ajoutée en §2 de ci/README
(discipline ci-readme-table-detail-in-section2). Sweep préalable repo-wide 7-gates/32-jobs : 0
dérive réelle (toutes occurrences historiques datées ou pédagogiques, classées KEEP).
0 édition de production, 0 artefact rebuild, 0 chiffre saisi (#6 — 8/9 recomputés), 0 VPS (#8).
run_ci 33 PASS · 0 FAIL · 0 SKIP.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>