Régression neuve depuis commit 9c062ef : OTO_DESIGN_SYSTEM_v1.md §15
« Fichiers canoniques sur VPS » liste /var/www/html/static/ en inventaire
descriptif (chemin servi = symlink de /opt/oto/sites/static). Faux-positif de
la classe que le garde ignore (USAGE, pas mention) ; doc root-owned non éditable
+ non créé par le worker → fix au niveau du garde (précédent session 010630).
- ci/guard_constraints.sh : OTO_DESIGN_SYSTEM_*.md (glob) ajouté aux exclusions
tracked_files(), même catégorie qu'AUTORISATIONS_*/DIRECTIVE_* ; en-tête documenté.
- ci/README.md : §exclusions + NB inconsistance chemin-servi-vs-source mis à jour.
- Mutation-test : garde mord toujours les 3 usages code réels (static VPS/GitHub/Stripe).
- Inconsistance chemin servi (/var/www/html/static) vs source (/opt/oto/sites/static)
du §15 re-signalée à Michel (non tranchée par le garde).
run_ci.sh : 30 PASS · 0 FAIL · 0 SKIP (rétabli). Zéro nouveau module, zéro gate ajouté (#5).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Régression NEUVE du gate depuis les commits Michel de ce soir (7e4456e/94ae143/9067313 →
4 fichiers root-owned racine). constraints-guard mordait AUTORISATIONS_MICHEL_20260803.md:35
« Écriture dans /var/www/html/static/ » — autorisation POSITIVE en prose de mandat, sans
marqueur de prohibition. Fichier root:root 644 NON éditable par otoclaude + doc signé que je
n'ai pas créé → ni ci-allow par ligne ni réécriture possibles.
Correctif au niveau du garde (ci/, que je possède) : AUTORISATIONS_*.md + DIRECTIVE_*.md
ajoutés aux exclusions tracked_files(), MÊME classe que les exclusions préexistantes
(ci/guard_constraints.sh + .gitea/workflows/*.yml) — docs contenant NÉCESSAIREMENT les
termes en texte de politique. Détection vraie-positive PRÉSERVÉE (mutation-test : un .sh
commité avec les 3 usages interdits → garde mord 3/3). CLAUDE.md RESTE scanné.
⚠️ CONTRADICTION INTER-MANDATS signalée à Michel (NON masquée, activity log + ci/README) :
AUTORISATIONS l.35 contredit l'interdit absolu CLAUDE.md — le chemin correct est le SYMLINK
source /opt/oto/sites/static/. Recommandation : corriger l.35. Décision → Michel.
ci/README §guard mis en cohérence. Zéro nouveau module · garde NON affaibli (faux-positif
corrigé conforme à sa philosophie USAGE-not-mention). run_ci.sh 30 PASS 0 FAIL.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Audit doc-vs-réalité (fan-out exploration) sur les *.md de tête, 03_agents/*/AGENT.md,
05_deliverables_mvp/*/README.md, ci/README.md, roadmap → UNE candidate : CLAUDE.md#2
« michel/otov7-platform » vs section Git « oto-enterprise-os-dtp ». FAUX POSITIF connu
(mémoire otov7-platform-not-drift) : deux dépôts Gitea distincts, tous deux corrects —
otov7-platform = dépôt PRODUIT (plateforme OTOV7 cible du refactoring), oto-enterprise-os-dtp
= dépôt MANDAT (ce worker). L'agent d'exploration (sans accès mémoire) l'a re-remonté →
preuve que le garde-fou méritait d'être in-repo, pas seulement en mémoire privée.
Action : paragraphe « Non-dérive documentée » ajouté à la section guard_constraints.sh de
ci/README.md (propriétaire de #2), calqué sur la note roles_couverts « 44 » — explicite que
produit ≠ mandat, qu'il ne faut PAS « aligner » CLAUDE.md#2, et qu'il n'y a rien à gater
(le garde ne vérifie que l'ABSENCE de github/gitlab/bitbucket, pas l'identité d'un repo
Gitea autorisé).
Discipline : zéro module · zéro gate ajouté (#5) · CLAUDE.md intact (on ne « corrige » pas
la constitution · #6). Recompute README concordant (22/22 scores={100} · 564/564 · 15/15
in_repo · 13 agents · gate.needs=30) = zéro dérive numérique. run_ci.sh --static 7 PASS ·
guard_constraints/check_docs/check_readme_claims verts (nouveau texte cite les plateformes
interdites mais chaque ligne porte « interdites » → ignorée par le garde). Aucune commande
touchant au VPS (#8).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Même fix que dcb463e, un cran plus haut. dcb463e avait dérivé le décompte 30/23/7
du COMMENTAIRE de run_ci.sh (il se périme à chaque module ajouté/retiré de ci.yml) ;
mais la DOC du lanceur (ci/README.md §« Rejouer le gate EN LOCAL ») re-transcrivait
encore les mêmes nombres à la main : bloc d'usage L34-35 (« 7 gates statiques + 23
suites de module » / « 7 gates ci/*.sh ») + checklist L1601 (« 7 gates statiques »).
Vérif d'exposition (verify-uncovered-before-gating) : mutation 23→24 / 7→8 →
check_readme_claims ET check_docs restent VERTS → surface réellement NON gatée.
Décision FIXER pas gater (fix-vs-gate + local-ci-runner) : ci/README.md:51-54 déclare
lui-même que run_ci.sh « n'a pas à être re-gaté (#5) » (exactitude structurelle) —
gater la prose qui le décrit trahirait cette posture. On retire donc les nombres
figés et on laisse run_ci.sh seul propriétaire du décompte (dérivé de gate.needs,
imprimé à l'exécution + --list). Ajout d'un paragraphe l'explicitant (même raison #6).
Intactes : les « 7 gates re-verts » du CHANGELOG (narratif historique d'états passés
VRAIS, pas une composition vive). Zéro module · zéro gate (#5) · zéro chiffre inventé
(#6) · run_ci.sh 30 PASS · guards verts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Balayage de complétude après cb8d931 (qui a ancré « 13 agents » aux 2 docs de
mandat de tête) : 3ᵉ surface HORS gate = le livrable Sprint 1 GAP_ANALYSIS_SPRINT1.md
(Definition of Done). Retranscrit le compte à 3 endroits vifs — périmètre d'audit
(l.12) · constat global total (l.53, le « 12 » analytique EXCLU) · coche de
couverture DoD (l.214). Prouvé ungate (grep ci/=0 ; mutation 13→14 laissait exit 0)
et à dérive prouvée (publiciste 12→13). Extension de la boucle head-docs existante
(3 tuples réutilisant n_agents = git ls-files 03_agents/*/AGENT.md · zéro nouvelle
machinerie · #5) ; on n'ancre que le total ; INTROUVABLE = échec (#6). ci/README.md
documente désormais 7 surfaces vives. 6 morsures (M5 no-false-positive sur le « 12 » ·
M6 SILENT-GREEN via git rm --cached prouvant l'autorité git-index). 7 gates exit 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
La SPEC RBAC a déjà 3 gates (§3 ventilation par portail · §4 colonne Entité · §7
run-book) mais son §5 « Les N rôles (résumé) » restait AVEUGLE. Ce §5 restitue le
total de rôles sur 3 surfaces prose : le compte-titre « ## 5. Les 50 rôles », NEUF
comptes parenthétiques de regroupement (`**Ventes (8)**` …) et une ligne
d'auto-contrôle arithmétique `_(6+8+4+7+5+8+4+2+6 = 50.)_`. AJOUTER un rôle au
contrat (|rôles| 50→51) laisse titre/somme/`= 50` périmés en silence ; ÉDITER
`Ventes (8)→(7)` sans toucher la ligne casse la cohérence titre↔somme — ni les
suites tests/ (FONCTIONS RBAC, jamais la prose) ni le byte-gate d'artefact ne
l'attrapent.
Subtilité (memory rbac-spec-portail-count-gate : « §5 by-family is editorial ») :
les 9 regroupements sont ÉDITORIAUX (« Direction / Gouvernance » agrège des rôles
de familles direction+finance ≠ colonne `famille`) ⇒ AUCUN mapping groupe↔famille
(dérive fausse). On gate UNIQUEMENT ce qui est data-derived sans ce mapping.
Nouveau bloc « 1septies) §5 » : on recompute N = |rôles| du contrat
(rbac_50_roles.json, byte-gaté) et on exige (a) compte-titre == N ; (b) les 9
comptes de regroupement == EXACTEMENT dans l'ordre les termes de la ligne
(comparaison de LISTES ⇒ mord valeur ET position) ; (c) Σ termes == membre droit ;
(d) membre droit == N. Section/titre/ligne/comptes absents = échec (#6).
5 morsures vérifiées (working tree byte-restauré via git checkout -- <fichier>,
gate rc=1 sous mutation · rc=0 restauré) : titre 50→51 (a) · Ventes (8)→(9) (b) ·
= 50.→= 49. (c+d double) · terme 6+→7+ (b+c double) · suppression ligne (absence).
ci/README.md : row check-readme-claims étendue de la clause §5. 7 gates re-verts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Surface ungatée fermée : `03_agents/onapi_legal/AGENT.md:54` décrit le champ Select
`entite_porteuse` du DocType CONFOTUR par « les 7 entités de CLAUDE.md #Entités (WAF ·
WA SRL · AC Arias Cuevas · Consortium ECR DR · Helios RD · Ploutos · 9060 QC) » — un
COMPTE littéral + l'énumération complète du même menu. Le bloc « Confotur entités »
déjà en place ancre le champ mais gate la ligne du README `legal/confotur` (surface e,
ancrée sur legal/confotur/README.md) ; le motif ne vise PAS 03_agents/ ⇒ la fiche
restait hors de tout gate. Dérive #6 : ajouter/retirer/renommer une entité dans
CLAUDE.md §Entités puis régénérer propage le menu de l'artefact ET la ligne README
confotur, MAIS la fiche se périme en silence (l'agent ERPNext Backend seederait un
déroulant de périmètre faux). Aucune suite tests/ (FONCTIONS de build, pas la prose)
ne l'attrape.
Gate ajouté (ci/check_readme_claims.sh) : re-dérive la liste depuis les tokens gras de
« ## Entités » de CLAUDE.md (source ancre · zéro duplication) et exige de la fiche —
(a) COMPTE littéral == |§Entités| ; (b) énumération == §Entités ORDRE EXACT (absent ET
fantôme mordus par set-diff + comparaison ordonnée) ; (c) ancre « CLAUDE.md #Entités »
citée ; (d) cross-check bonus — énumération == options entite_porteuse de l'artefact
byte-gaté (la fiche décrit EXACTEMENT le menu du DocType). Ligne absente = échec (#6).
6 morsures vérifiées (5 fiche · 1 artefact) : 7→8 → ✗(a) ; Ploutos retiré → ✗(b)
absent ; fantôme Fantom SA → ✗(b) fantôme ; réordre WAF↔WA SRL → ✗(b) ordre ; ancre
#Entités retirée → ✗(c) ; option artefact Ploutos→Ploutos SRL → ✗(d) menu divergent.
Restauré = green (a/b/c/d ✓ · exit 0). Working tree byte-restauré via
git checkout -- <fichier précis> (JAMAIS git checkout . / git clean). 7 gates re-verts.
ci/README.md étendu (clause « 2ᵉ surface prose (fiche ONAPI/Legal) »).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Le triplet persona/qualif/voix (Amélie · QC · multilingual_v2) recopié à la main
dans chaque pied de page était HORS de tout gate : le bloc persona Chat OTOIA
(063234) ne confronte que le module chat_otoia, aveugle aux 11 fiches ; le bloc
configs runtime note même que le « QC » est « gardé en littéral — non gaté ici ».
Bloc ajouté (check_readme_claims.sh) : RE-DÉRIVATION INDÉPENDANTE du triplet de
§Architecture cible (regex qui ne fige PAS le qualificatif en dur ⇒ QC→… mord ici,
pas seulement via l'INTROUVABLE du bloc persona) · 3 tokens == CLAUDE.md exigés sur
chaque fiche portant le pied de page · pied de page malformé & évaporation totale du
recensement échouent AUSSI (#6). 6 morsures vérifiées (CLAUDE.md voix v2→v3 : 11
fiches + cascade persona · CLAUDE.md qualif QC→BC : 11 fiches, bloc indépendant ·
seo voix · crm persona · bim malformé · surface évaporée) · restauré green · 7 gates
re-verts. ci/README.md (récap + paragraphe détaillé) mis à jour.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3e surface du MÊME README audit_4big, jamais gatée : les deux seuils que le
scorer applique (DOC « ≥ 400 octets » · TESTS « ≥ 8 méthodes def test_* »),
transcrits à la main. Le bloc BARÈME ne capture que le POIDS voisin (regex
`| `DOC` | 20 |`), aveugle à la 3e cellule. Ces nombres sont DATA-DERIVED de
quality_spec.json[thresholds] (min_doc_bytes/min_test_methods) — l'INPUT
byte-gaté par check_artifacts (report rebuild depuis lui).
Gate ajouté (check_readme_claims.sh) : (1) cross-check d'ANCRAGE — le seuil
TESTS APPLIQUÉ, lu de l'evidence « (seuil N) » de CHAQUE module du report ==
spec.min_test_methods pour tous (mord une divergence spec↔report) ; (2) prose
DOC « ≥ N octets » == spec ; (3) prose TESTS « ≥ N méthodes » == spec ; claim
absent échoue AUSSI (traçabilité #6). Élever min_test_methods (8→12 : module de
8-11 tests sous FAIL) ou changer min_doc_bytes rebuild le report SANS toucher au
README → prose périmée en silence, désormais interdite.
5 morsures vérifiées (README 400→450 · README 8→10 · ligne DOC vidée · spec
min_test_methods 8→12 rebuild : README+cross-check · spec min_doc_bytes 400→500
rebuild) ; restauré = green · 7 gates re-verts. ci/README.md (récap + paragraphe
détaillé) mis à jour. Hors périmètre VPS : néant.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3e surface du MÊME README `qa/audit_5d` : la table « ## Les 5 dimensions »
(README:15-19) transcrit par ligne le triplet (id · titre · reference) de chaque
dimension. Jusqu'ici gatée seulement sur son COMPTE agrégé (« 5 dimensions ») — un
WILDCARD aveugle à QUELLE dimension. Une norme de référence permutée (D3 fiscal
`Ley 32-23`, D1 probatoire `ISA 500`) est une affirmation de conformité fausse
(l'invention même que #6 interdit) sur l'audit de second niveau que le banquier lit.
Gate ajouté (`ci/check_readme_claims.sh`) : liste ORDONNÉE {id:(titre,reference)}
recomputée de `qa/audit_5d/out/audit_report.json[dimensions]` (byte-gaté) — identité
par ensemble d'id (absent/en trop), ordre préservé (D1→D5), (titre,reference) par
ligne. Cohérence croisée bonus : rapport == audit_spec.json[dimensions] (l'INPUT dont
il dérive). Table disparue = échec (traçabilité #6).
8 morsures vérifiées (README rename titre/permute norme ISA/Ley/supprime ligne/
réordonne · artefact & spec renommés · table supprimée) ; restauré green · 7 gates
re-verts. Édition hors `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact.
ci/README.md (recap + paragraphe détaillé) mis à jour.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Le bloc « paramètres canoniques » n'ancrait que model.py::CANONICAL + le README ;
son propre commentaire nommait pourtant le défaut (« marqueurs hardcodés dans le
test, une copie de plus jamais comparée à CLAUDE.md ») sans le fermer. Nouveau bloc :
helper _list_vs_want6 (set-diff EXACT absent/en-trop) pour les copies-LISTES
renderer._CANONICAL_MARKERS + oracle du test ; substring normalisé (USD+DOP==USD + DOP)
pour les 2 docstrings scorer. 4 morsures vérifiées dont CLAUDE.md #10 Cardnet→Azul
mordant SIMULTANÉMENT model+renderer+test+2 docstrings (valeur de l'ancrage) ;
restauré vert · 7 gates re-verts. ci/README.md + activity log mis à jour.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Aucun taux de commission n'étant documenté dans CLAUDE.md, le README §« Anti-invention » promet (README:22-23) « taux_pct: null + source: null + a_confirmer: true pour CHAQUE évènement » et l'invariant CLI #7 REFUSE tout taux_pct fourni SANS source. Le bloc cross-cohérence commissions ne gate QUE brouillons/champs de base ; le bloc racine QUE le compte de tests (« 25 »). RIEN ne confrontait cette promesse à l'artefact byte-gaté out/commission_plan.json.
Dérive la plus dommageable possible du module : qu'un taux_pct DEVIENNE non-null (taux INVENTÉ, ou valeur remplie sans source) pendant que le README affirme encore « tout null » → le calcul base × taux (commlib/finance.py) émettrait une commission fondée sur un chiffre inventé — l'invention EXACTE que le module promet d'écarter. Aucune suite tests/ (FONCTIONS de calcul, jamais la promesse README vs artefact) ne l'attrape.
Gate ajouté (bloc « CRM/Commissions · ANTI-INVENTION (#6) ») : recompute de l'état null/confirmé depuis l'artefact + (a) invariant #7 permanent (aucun taux_pct sans source) · (b) a_confirmer ⟺ taux_pct is null · (c) MANIFEST.counts recoupe le plan (taux_a_confirmer / evenements) · (d) la promesse #6 du README REFLÈTE l'artefact dans les DEUX SENS (tout-null ⇒ promesse présente ; taux confirmé ⇒ promesse retirée) — zéro faux négatif quand la Direction remplira les taux · (e) note_taux du MANIFEST cohérente.
5 morsures vérifiées (taux sans source · taux avec source mais a_confirmer stale + README périmé · a_confirmer=false sur null · counts périmé 5→4 · promesse retirée INTROUVABLE), restauré vert, 7 gates re-verts. Working tree byte-restauré via git checkout -- (JAMAIS git clean). Édition hors 05_deliverables_mvp/*/out ⇒ 0 dérive d'artefact. ci/README.md (récap + paragraphe détaillé) mis à jour. Auto-score 4Big 96/100.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Surface data-derived jusqu'ici hors de tout gate : l'ID du pod RunPod ComfyUI
et le tag modèle Flux, recopiés à la main en 6 endroits, dont la source de
vérité in-repo est le fichier maître AGENTS_EXISTING_ASSETS.md (que les fiches
citent explicitement). Un pod re-créé (nouvel id) ou un modèle bumpé péримait
les citations en silence → batch Flux câblé vers un endpoint GPU mort (#6).
Gate « RunPod endpoint » (ci/check_readme_claims.sh, avant sys.exit) : id+tag
recomputés du bullet §1 (garde : bullet unique) ; direction fiche→inventaire —
toute fiche/master prompt mentionnant RunPod doit citer l'id EXACT (token
backtické de forme pod == canonique) + le tag EXACT ; disparition totale échoue.
6 morsures vérifiées (id change → 3 fiches cascade · tag bump → 3 · mistype → 1
· tag drop → 1 · id drop → incomplet · bullet supprimé → ancre morte) ; restauré
green · 7 gates re-verts.
ci/README.md (clause récap + paragraphe détaillé) + 05_activity_log mis à jour.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Classe fermée `agent-fiche-role-attrs-ungated` (sous-classe colonne CLI). La colonne
« Entrée CLI » des tables de livrables cite à la main le jeu de verbes de chaque module
(`publiciste.py parse|validate|generate|run`, `faisabilite_gen.py
score|scaffold|generate|batch`, …). Les blocs amont gatent déjà génériquement — pour
TOUTES les fiches — les colonnes « Tests » (vs regression_plan) et « Job CI » (vs
ci.yml), mais RIEN ne liait les VERBES écrits aux sous-commandes que le CLI EXPOSE.
Piège #6 : renommer/ajouter/retirer/réordonner un add_parser dans le .py (ou le mal
recopier dans la fiche) laisse la fiche documenter une surface d'invocation FANTÔME —
la doc d'identité qui dit à l'agent COMMENT lancer son livrable ment en silence, le CI
reste vert (le module tourne sous le vrai verbe), aucune suite tests/ ne l'attrape.
Gate ajoutée (ci/check_readme_claims.sh, bloc « colonne Entrée CLI ») : _cli_subcommands()
recompute via AST l'ensemble ORDONNÉ des subparsers.add_parser("<verbe>") ; script résolu
par le chemin de module de la MÊME ligne de table (lien …/<path>/README.md) + basename ;
égalité EXACTE ensemble ET ordre exigée ; `|` markdown échappés `\|` dé-échappés avant
découpe. 16 cellules gatées (6 fiches ; regex [a-z0-9_] capte audit_5d/4big_gen.py).
7 morsures vérifiées, restaurées vert : fiche renomme/ajoute/retire/réordonne un verbe
(4) · le vrai « vert trompeur » add_parser renommé dans le .py fiche inchangée (5) ·
nouveau add_parser non documenté (6) · script déplacé => INTROUVABLE (7). 6 gates
re-verts. ci/README.md catalogue mis à jour. Incident : un git checkout large a reverté
l'edit non-commité du gate ; ré-appliqué (git clean JAMAIS utilisé · ci-allow sur le log).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Les blocs SEO schema.org/hreflang ne gataient que seo/README.md ; la fiche
restituait N nœuds (Organization + M Residence) et N pages × langues sans gate.
Recompute des memes artefacts byte-gates + coherence arithmetique total==1+M.
8 morsures verifiees, working tree byte-restaure, 7 gates re-verts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bloc anti-dérive #6 dans ci/check_readme_claims.sh : la cellule « Métrique
vérifiée » de 03_agents/frontend_console/AGENT.md:29 restituait 3 attributs
data-derived du montage OTOIA (persona Amélie · langues FR/EN/ES ·
`endpoint: null`) ; le bloc chat_otoia amont ne gate que le COMPTE
blocks/mounts/portails, et le gate persona/capabilities ancré sur CLAUDE.md
vise spec/mounts/MANIFEST/README/oracle, jamais cette fiche. Le nouveau bloc
recompute les 3 depuis out/chat_mount.json (5 configs) + out/MANIFEST.json
byte-gatés : persona==MANIFEST.persona.nom, langues==MANIFEST.langues majuscule,
endpoint:null == affirmation d'honnêteté exigeant all(mount.endpoint is None)
— un endpoint fabriqué mord. Cohérences croisées MANIFEST⇔chaque mount +
endpoint_statut=='a_confirmer'⇔endpoints tous null. 6 morsures vérifiées ·
7 gates verts · aucune écriture out/ (0 dérive artefact).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
La ligne « Confirmations préalables VPS » du README `devops/deploy_runbook` annote
CHAQUE confirmation réglementaire d'un COUPLE data-derived `nom` (OWNER · RÉF-CONTRÔLE)
— ex. `taux_commission` (Direction · audit_5d D1.1) : QUI doit confirmer le paramètre
avant déploiement + QUEL contrôle qa/audit_5d le trace. Sources faisant autorité
(double, byte-gatées) : les `confirmations` de out/deploy_runbook.json (owner + source)
CROISÉES avec qa/audit_5d/out/audit_report.json (chaque control D#.# porte son propre
owner). Les blocs DevOps amont ne gataient que le COMPTE (2) et l'ENSEMBLE des noms —
AVEUGLES à QUI porte chaque confirmation et à QUEL contrôle la trace. Piège #6 :
réaffecter `taux_commission` de Direction à Ventes (mauvais responsable escaladé),
misattribuer le contrôle (D1.1→D2.1) ou citer un contrôle FANTÔME (D9.9) laisse la
prose périmée en silence pendant que l'artefact/l'audit disent autre chose → l'agent
DevOps escaladerait le mauvais owner / contrôle ; aucune suite tests/ (FONCTIONS de
graphe) n'attrape ce « vert trompeur ». État courant : aucune annotation périmée
(anti-invention #6), le défaut est la surface ungated.
Gate ajouté (ci/check_readme_claims.sh, bloc « 2ter ») : cross-anchor à trois — owner
run-book ⊆ owner du contrôle audit_5d cité (tolère le suffixe « / UAF ») · owner
README ⊆ owner run-book (tolère l'abréviation « Fiscaliste eCF » ⊂ « Compta Fiscaliste
eCF ») · réf README == contrôle réel présent DANS audit_5d ET dans la source. Une
confirmation tracée DOIT rester annotée (traçabilité #6) ; une annotation d'un nom
fantôme échoue AUSSI.
9 morsures vérifiées (README réaffecte owner · misattribue D1.1→D2.1 · contrôle
fantôme D9.9 · annotation retirée · artefact réaffecte owner = silent green · audit_5d
owner divergent · source cite contrôle fantôme · annotation nom fantôme · réf textuelle
absente de la source), restauré vert, 7 gates re-verts. ci/README.md (récap + paragraphe
« 3ᵉ surface deploy_runbook — imputabilité des confirmations ») mis à jour.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Le champ que `Encabezado.TipoMoneda` porte dans chaque e-CF DGII —
`moneda.options = ["USD","DOP"]` — vit dans `ecf_spec.json` ET, byte-gaté par
check_artifacts, dans `out/ecf_plan.json`. C'est une valeur CANONIQUE de CLAUDE.md
#10 (« **USD + DOP** devises ») dont le README se réclame « #10 » (README:37/57/77).
Or byte-gater une constante prouve la REPRODUCTIBILITÉ, PAS l'ANCRAGE :
check_artifacts prouve ecf_plan==build depuis le spec, JAMAIS que spec[moneda]==#10.
Les blocs fiscaux amont gatent le FormaPago (Cardnet · #10) + états/champs
émetteurs, AVEUGLES au jeu de devises ; le bloc « Fiches #10 » ancre les fiches
ERPNext/CRM, AVEUGLE au module fiscal.
Piège #6 : RENOMMER/ÉTENDRE les devises dans CLAUDE.md #10 (`USD + DOP`→`USD + EUR`,
ou +`EUR`) ET dans le spec de façon cohérente reste byte-VERT tout en faisant
émettre à l'e-CF un `TipoMoneda` d'une devise qui CONTREDIT le mandat — « vert
trompeur » de la classe de la marque SEO §Entités, la persona Chat OTOIA ou les
tokens branding #4, qu'aucune suite tests/ (FONCTIONS de génération, jamais l'ancre
à CLAUDE.md) n'attrape. L'agent ERPNext Backend câblerait TipoMoneda hors mandat.
Correctif de déclaration : nouveau champ `moneda.options_source` (ecf_spec.json +
requis dans ecf.schema.json) citant « CLAUDE.md #10 — devises **USD + DOP** »,
DISTINCT de `source` (taux TipoCambio, reste null/a_confirmer côté VPS · #8).
Artefact régénéré (byte-gate re-verte · 39 tests module verts).
Gate ajouté (ci/check_readme_claims.sh, bloc « Fiscal · ecf_dgii — le JEU DE
DEVISES `moneda` … ANCRÉ sur CLAUDE.md #10 ») : RÉUTILISE exp["devises"] déjà
recomputé depuis #10 (zéro duplication) ; (a) spec[moneda].options == devises #10
ORDRE exact ; (b) artefact byte-gaté idem ; (c) options_source cite CLAUDE.md #10 +
chaque devise ; (d) prose README qui se réclame de #10 == jeu exact + toute mention
moneda/devise d'une paire concordante (scan ancré sur contexte, évite le faux
positif `RNC / ITBIS`). 7 morsures vérifiées (CLAUDE.md #10 rename = 4 bites en
cascade · spec options régénéré = le vrai silent green · artefact seul · reorder ·
options_source sans ancre · README ligne #10 · README table), restauré vert, 7
gates re-verts.
ci/README.md (clause récap + paragraphe « 4e surface du MÊME README ») mis à jour.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
La version MAJEURE du SDK Expo que l'app compagnon cible (`expoSdkMajor`) est data-derived : `out/app_config.json.expo.extra.expoSdkMajor = 54` (byte-gaté par check_artifacts ⇒ faisant autorité), recopié dans `out/MANIFEST.json.app.expo_sdk_major`, dérivé de `mobile_spec.json[app].expo_sdk_major` dont la SOURCE FAISANT AUTORITÉ est la roadmap Sprint 5 l.56 « Rebuild Expo 54 » (le spec le DÉCLARE via `expo_sdk_source`). Le README:4/19/35/72 recopie « Expo 54 » CINQ fois À LA MAIN — dont la ligne de source « Expo SDK **54** | roadmap Sprint 5 l.56 ». Le bloc « Mobile · récap de l'app Expo » amont ne gate QUE le quadruplet onglets/rôles/langues/identifiants a_confirmer (comptes de MANIFEST.counts), AVEUGLE au majeur du SDK. Piège #6 : BUMPER le SDK (Expo 55 sort · eas build cible 55) dans le spec/artefact SANS toucher au README (ou l'inverse), ou DÉRIVER la roadmap de l'artefact, laisse la prose PÉRIMÉE en silence pendant que le graphe byte-gaté dit autre chose → l'agent Mobile lancerait `eas build` sur le MAUVAIS SDK (le rebuild même que la ligne roadmap prescrit) — « vert trompeur » qu'aucune suite tests/ (FONCTIONS de génération, jamais la prose ni l'ancre à la roadmap) n'attrape. Même patron d'ANCRAGE que la marque SEO §Entités (Helios RD ancrée sur CLAUDE.md) ou les roadmap_line de la recette, mais sur une valeur dont la roadmap — non CLAUDE.md — est l'INPUT faisant autorité.
Gate ajouté (bloc « Mobile · le SDK MAJEUR Expo … ANCRÉ sur la roadmap Sprint 5 l.56 ») : le majeur re-dérivé de app_config.json byte-gaté, puis (a) cohérence interne artefact ⇔ MANIFEST ⇔ spec ; (b) ancrage roadmap `Rebuild Expo <N>` == artefact (ancre vive) ; (c) le spec DÉCLARE l'ancrage (expo_sdk_source cite roadmap + Expo N) ; (d) TOUTE mention prose « Expo [SDK] N » == artefact (aucune périmée) ; (e) la ligne de source du tableau cite l'ancre roadmap. Un claim absent échoue AUSSI.
7 morsures vérifiées (README 54→55 prose périmée · artefact 54→55 README+roadmap périmés = le vrai silent green · roadmap Rebuild Expo 54→55 artefact périmé · MANIFEST 54→55 chaîne incohérente · spec expo_sdk_source sans roadmap · README ligne source sans roadmap · README retire toute mention Expo N), restauré vert (git checkout --, JAMAIS git clean), 7 gates re-verts. ci/README.md (table récap + paragraphe détaillé) mis à jour.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Les artefacts `out/chat_mount.json` (5 configs runtime, une par portail) +
`out/MANIFEST.json` portent la persona + les capabilities, BYTE-GATÉS pour la
REPRODUCTIBILITÉ par check_artifacts (reconstruction depuis `chat_spec.json`) mais
JAMAIS ANCRÉS à CLAUDE.md §Architecture cible (l.30 « Voix Amélie QC (multilingual_v2) »
· l.28 « OTOIA capabilities : aec.py + knowledge.py + prompt_engine.py + chat.py »),
leur source faisant autorité. Le bloc chat_otoia amont ne gate que la COMPOSITION
(portails métier · 1 block⇔1 mount) ; le SEUL contrôle d'identité vit dans tests/
(`test_persona_amelie_sourcee`/`test_capabilities_sourcees_sans_ajout`) mais son ORACLE
est HARDCODÉ (`"Amélie"`, `["aec.py",…]`) — une copie de plus, jamais comparée à
CLAUDE.md. Piège #6 : renommer la persona (`Amélie`→`Sophie`), changer la voix, ou
renommer/RETIRER une capability dans `chat_spec.json` (ou dans CLAUDE.md) reconstruit
l'artefact fidèlement (byte-gate VERTE) sans toucher l'oracle (tests VERTS) → le chat
monté dans CHAQUE portail annoncerait une persona/voix/capabilities CONTREDISANT le
mandat — « vert trompeur » de la classe des tokens branding ancrés sur #4 et de la
marque SEO §Entités. Aucune suite tests/ (FONCTIONS de génération, jamais l'ancre à
CLAUDE.md) ne l'attrape.
Gate ajouté (bloc « Chat OTOIA · persona + capabilities ancrées CLAUDE.md ») :
persona+capabilities re-dérivées de §Architecture cible (regex `Voix … QC (…)` +
`OTOIA capabilities : …` split `+`, NFC), puis (a) `chat_spec.json`
persona/capabilities == CLAUDE.md (ordre exact) · (b) le spec DÉCLARE l'ancrage
(`persona.source` + chaque `capability.source` citent CLAUDE.md) · (c) CHACUN des 5
mounts + le MANIFEST == CLAUDE.md · (d) README cite l'ancre §Architecture cible + nomme
persona + chaque capability (notation compacte matchée par radical) · (e) l'ORACLE du
test == CLAUDE.md (set-diff). Un claim absent échoue AUSSI.
8 morsures vérifiées : CLAUDE.md `Amélie→Sophie` (mord SIMULTANÉMENT
spec/mount/README/oracle — l'ancre est vive) · CLAUDE.md retire `chat.py` · spec
`aec.py→exfil.py` (capability injectée) · spec `persona.source` sans CLAUDE.md · UN
SEUL mount à voix altérée (byte-gate aveugle) · README retire le radical
`prompt_engine` · oracle du test persona `Amélie→Bob` · oracle du test capabilities
réordonné/tronqué ; restauré = green, exit 0. Working tree byte-restauré
(`git checkout --`, JAMAIS `git clean`) · 7 gates re-verts · unittest module re-vert.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Gate ajouté (bloc « Fiches agents · colonne Job CI ») : on RECOMPUTE l'ensemble des jobs depuis la clé `jobs:` de ci.yml (la section `on:` push/pull_request/workflow_dispatch est AVANT `jobs:` et donc exclue ; jamais une liste à la main) et on exige que chaque token `*-tests` cité dans une fiche y figure. Direction fiche→ci.yml (le consommateur) : ci.yml peut définir des jobs non cités (légitime), une fiche ne peut pas citer un job absent ; la disparition totale de la colonne échoue AUSSI. 33 références vérifiées == jobs ci.yml ; 2 morsures (token de fiche `seo-tests`→`seo-suite-tests` fantôme · job ci.yml `rbac-tests` renommé → mord SIMULTANÉMENT les 4 fiches qui le citent : erpnext_backend/ifc_speckle/mobile/rendu), restauré vert, 7 gates re-verts. ci/README.md + activity log MAJ.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Le bloc e-NCF gate le FORMAT de l'identifiant ; le bloc cross-cohérence (2e surface) gate états émetteurs/champs de base/FormaPago ; mais AUCUN ne comparait l'IDENTITÉ de ce rôle à ses DEUX sources faisant autorité : (a) out/ecf_plan.json (byte-gaté) — chaque emission_events[] porte role_id + erpnext_role_name ; (b) rbac_50_roles.json (contrat) — le rôle porte portail:"compta". Le `portail` n'est PAS dans l'artefact ; il n'est vérifiable QUE contre le contrat.
Même classe d'IDENTITÉ que la Fiche Mobile / les Fiches Faisabilité ou les gardes CRM/workflow_vente, appliquée à une 3e surface distincte du MÊME README fiscal. Piège : la seule vérification existante (tests/) teste des FONCTIONS (ncf/résolution), jamais la prose. RÉAFFECTER l'émission à un autre rôle, le RENOMMER, ou DÉPLACER le rôle hors du portail compta (e-CF émis HORS Compta — séparation cassée) laisse la prose périmée pendant que l'artefact/contrat disent autre chose → l'agent ERPNext Backend câblerait le mauvais rôle émetteur.
Gate ajouté (ci/check_readme_claims.sh, bloc « Fiscal rôle émetteur ») : role_id/erpnext_role_name recomputés de emission_events + portail/nom Frappe du contrat, prose EXACTE ; cohérences croisées : tous les emission_events pointent UN SEUL rôle (fonction · non vide) · role_id unique au contrat · nom artefact == contrat (zéro-dup) · portail == compta. Un claim absent échoue AUSSI. 6 morsures vérifiées (README renomme role_id/nom/portail · artefact réaffecte les 2 events à ventes-directeur (5 mords cascade) · contrat déplace le rôle vers ventes · artefact diverge du contrat sur le nom), restauré vert, 7 gates re-verts. ci/README.md mis à jour.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>