Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
81 KiB
Activity Log · 2026-08-03 · Claude Code DTP Worker
Session 083713 · Gate constraints-guard RED réparé — nouveau doc REFERENCE OTO_DESIGN_SYSTEM_v1.md (mention VPS, pas usage) + inconsistance chemin re-signalée à Michel
Contexte. ./run_ci.sh au démarrage : 29 PASS · 1 FAIL — régression NEUVE
(constraints-guard) apparue avec le commit 9c062ef (« REFERENCE · OTO Design System
v1 »), qui a ajouté OTO_DESIGN_SYSTEM_v1.md à la racine. Toutes les autres dimensions
vertes ; arbre propre.
Cause racine (faux-positif · classe identique à la session 010630). Le §15 du doc
« Fichiers canoniques sur VPS » liste, en inventaire descriptif, deux emplacements
/var/www/html/static/ (assets concierge + scripts UI canoniques). Le garde (dont
l'en-tête déclare « détecte l'USAGE… PAS sa simple mention ») a mordu ces deux
lignes — mais ce sont des mentions d'emplacements servis par nginx
(/var/www/html/static = SYMLINK de /opt/oto/sites/static, cf. CLAUDE.md §VPS), pas
une écriture exécutable. L'usage réel vivrait dans un .sh/.py/.yml — toujours
scannés.
Pourquoi PAS d'édition du doc fautif. (1) Root-owned root:root 644 — non éditable
par otoclaude (-w négatif) → l'escape ci-allow par ligne est inapplicable.
(2) Document ajouté par un commit REFERENCE que je n'ai pas créé → principe « surface,
don't overwrite ». Exactement la situation de la session 010630 (fichiers root-owned de
Michel).
Correctif — au niveau du garde que je possède (ci/), 2+ solutions pesées.
- Option retenue : ajout de
OTO_DESIGN_SYSTEM_*.md(glob → survit à un futur_v2) aux exclusions detracked_files(), même catégorie queAUTORISATIONS_*.md/DIRECTIVE_*.md(docs racine énumérant nécessairement des chemins VPS en tant que mention). En-tête du garde +ci/README.md§exclusions mis en cohérence (raison + inventaire-vs-usage documentés). - Option écartée : demander à Michel de rendre le doc éditable pour y poser des
ci-allow— plus lourd, casse à chaque re-push du doc ; le fix dans MONci/est durable.
Détection vraie-positive PRÉSERVÉE (mutation-test, guard-constraints-flags-usage-not-mention).
Un .sh temporaire commité avec les 3 usages littéraux (écriture chemin statique VPS, URL
GitHub, appel Stripe) → le garde mord les 3 (✗). Seule la prose de référence/gouvernance
.md est exclue ; CLAUDE.md (constitution) reste scanné. Aucun trou vers un usage
forbidden dans du code.
⚠️ INCONSISTANCE RE-SIGNALÉE À MICHEL (non tranchée par le garde). Le §15 liste le chemin
servi /var/www/html/static/ alors que le mandat (CLAUDE.md · Interdits absolus + §VPS)
préfère la source /opt/oto/sites/static/ (le premier étant le symlink du second). Même
inconsistance chemin-servi-vs-source que la l.35 d'AUTORISATIONS_*.md déjà signalée le
010630. Documentée ici + ci/README.md, pas masquée, pas tranchée (décision archi → Michel).
Vérifications. ./run_ci.sh → 30 PASS · 0 FAIL · 0 SKIP (rétabli). Mes propres
mentions du chemin dans ci/README.md (description de l'exclusion) marquées ci-allow
(motif l.100 préexistant). Zéro nouveau module · zéro gate ajouté (#5) — le garde n'est
pas affaibli (mutation 3/3 RED sur usage code), corrigé d'un faux-positif conforme à sa
propre philosophie. Aucune commande touchant au VPS (#8) · aucun git clean .
Session 063711 · Sprint 5/8 · Canal 2 daily_reports/ remis à jour (3 sessions manquantes depuis 040643)
Contexte + choix de tâche. ./run_ci.sh au démarrage : 30 PASS · 0 FAIL · 0 SKIP,
arbre propre. Roadmap 1→8 intégralement livrée + gatée verte. Un sweep de dérive dédié
(agent Explore : globs de sortie README-vs-os.path.join, docstrings générateurs, comptes
prose, liens Markdown) a rendu 0 dérive ungated — les gates existants
(check_readme_claims/check_artifacts/check_regression/check_docs) couvrent l'acquis,
et re-scanner serait redondant (#5). La valeur restante réelle in-périmètre : la currency
du canal 2 stakeholder (contrat « Rapports quotidiens »), classe two-logging-channels.
Défaut trouvé (dérive de couverture, réelle). Le snapshot daily_reports/2026-08-03.md
s'arrêtait à l'addendum session 040643. Trois sessions net postérieures manquaient au
snapshot — toutes des correctifs d'intégrité doc (aucun ne bouge les chiffres
launch-readiness, d'où table de clôture inchangée) :
050654—ci/README.mdcomplété (2e workflowmobile-build.yml, commit1af5d01) ;053701— fix prose-factregression_run.jsondoc-vs-réalité (commits89eb8e6+3d8ccb0) ;060704— fix citation roadmap fantôme module bancable (commit88d9955).
Réalisé. Trois addenda concis insérés avant la table « fin de journée » (qui reste la synthèse de clôture), 100 % sourcés : chaque addendum cite son/ses commit(s), sa classe de dérive et le consommateur régénéré le cas échéant. Aucune valeur inventée.
Chiffres re-dérivés d'artefacts (aucun saisi à la main). regression_run.json.totals
= 22 suites · 569 ran / 569 passed · 0/0/0 ; quality_report.json verdict PASS · 22
modules · min 100 (seuil 95) ; acceptance_matrix.json 15/15 status=in_repo
(all_modules_gated + all_artifacts_exist all true) ; README Mobile 4931 octets
(wc -c). Tous concordants → table de clôture laissée inchangée (correcte telle quelle).
Sûreté du changement. daily_reports/ n'est ni un artefact out/ byte-gaté ni une
source de claims de check_readme_claims (surfaces gatées = README/AGENT.md, pas les
rapports quotidiens) → édition gate-neutre. Aucun claim numérique gaté touché · aucun
terme interdit · aucune logique de prod ni de gate modifiée.
Vérifications. ./run_ci.sh → 30 PASS · 0 FAIL · 0 SKIP (inchangé) · git status
= 1 fichier. Zéro nouveau module · zéro gate ajouté (#5). Aucune commande touchant au
VPS (#8) · aucun git clean .
Session 033642 · Sprint 5 P1 · Livrable FONCTIONNEL : workflow CI/CD Mobile .gitea/workflows/mobile-build.yml (build EAS iOS + Android)
Contexte + choix de tâche. ./run_ci.sh au démarrage : 30 PASS · 0 FAIL · 0 SKIP,
arbre propre. Michel : « commits fonctionnels, pas juste docs ». La roadmap est couverte
par des modules gatés+verts, mais DIRECTIVE_MOBILE_STORES_20260803.md (Sprint 5, actif)
liste explicitement en P1 · CI/CD Mobile la création de .gitea/workflows/mobile-build.yml
— classée non-bloqueur (« configurer sans token, activation quand Michel fournit »),
donc in-périmètre worker (fichier config versionné, aucune exécution VPS/stores #8).
Vérifié absent : .gitea/workflows/ ne contenait que ci.yml. Vraie tâche fonctionnelle
non faite → exécutée.
Livrable créé : .gitea/workflows/mobile-build.yml.
- Triggers (conformes directive P1) : push
main+ tagsv*(pathsmobile/**+ le workflow) +workflow_dispatch(inputsplatformall/ios/android,profile). - Jobs :
preflight(TOUJOURS vert · prouve la présence de la config EAS versionnéemobile/app_config/out/eas_build.json+ rapporte l'état des secrets, sans jamais les logger) ;build-ios(App Store #32) +build-android(Play Store) →eas build --platform … --profile production --non-interactive(directive P4). - Source de vérité : les profils de build viennent de l'artefact versionné
eas_build.json(development/preview/production) — pas réinventés. - Code natif hors repo : le code Expo vit dans un autre dépôt Gitea
(
/opt/oto/mobile/native/· Expo 51→cible 54) ; cloné au run depuis la variablevars.MOBILE_NATIVE_REPO— jamais recopié ici.
Sûreté (activation différée · #6 zéro invention · #8). Les jobs de build sont gardés
par if: secrets.EAS_TOKEN != '' && vars.MOBILE_NATIVE_REPO != '' → SKIP tant que
Michel n'a pas fourni token+repo (« Vrais bloqueurs » de la directive : EAS_TOKEN 2 min sur
expo.dev). Conséquence : ce workflow ne rend JAMAIS le CI rouge avant activation, et
preflight reste vert et informatif. Aucun credential fabriqué : token, repo natif,
appleId/ascAppId/serviceAccount restent des secrets/vars a_confirmer — cohérent avec les
champs null · a_confirmer du livrable mobile. Plateforme Gitea Actions uniquement (#2).
Non-régression des gates (vérifié). check_ci_integrity.sh n'inspecte QUE ci.yml
(chemin en dur CI=".gitea/workflows/ci.yml") → le 2e workflow lui est invisible, aucun
job à ajouter à gate.needs. guard_constraints.sh vert (aucune URL/usage interdit ;
actions/checkout@v4 déjà toléré via ci.yml). YAML valide (pyyaml).
Consommateur régénéré (classe artifact-reproducibility-gate). Ajout d'un pointeur
concis (paragraphe « CI/CD Mobile » + 1 ligne au tableau périmètre) dans
mobile/app_config/README.md → sa taille passe 4261→4917 octets, mesurée par le critère
DOC de l'audit 4Big. check-artifacts a viré ROUGE (dérive attendue) →
audit_4big_gen.py build -o out régénéré : seule la ligne evidence "README.md (…octets)"
change ; verdict inchangé PASS · 22/22 modules ≥ 95. Lien Markdown vérifié résolvant
(../../../.gitea/workflows/mobile-build.yml).
Vérifications finales. ./run_ci.sh → 30 PASS · 0 FAIL · 0 SKIP. Zéro nouveau
module · zéro gate ajouté (#5) · aucune commande VPS (#8).
Aucun git clean exécuté .
Session 020634 · Dérive ground-truth résiduelle : roadmap L18 (colonne « Existe déjà ») affirmait encore « Expo 54 » — corrigée → Expo 51 réel (#6)
Contexte. ./run_ci.sh au démarrage : 30 PASS · 0 FAIL · 0 SKIP, arbre propre.
Focus mandat courant = Sprint 5 Mobile (DIRECTIVE_MOBILE_STORES_20260803.md). Le
module in-repo mobile/app_config est complet et vert (schéma + 12 invariants ·
comptes 5 onglets / 44 rôles / 3 langues / 13 a_confirmer vérifiés contre
out/MANIFEST.json · docstring/README cohérents). Les actions P1-P5 de la directive
visent l'app réelle /opt/oto/mobile/native/ (hors repo #8, bloquées sur
EAS_TOKEN/credentials Michel). J'ai donc cherché une dérive réelle in-repo dans le
périmètre worker.
Défaut RÉEL trouvé (prolonge la session 013634). La session 013634 a corrigé la
fausse affirmation « Expo 54 en place » dans AGENTS_EXISTING_ASSETS.md §8 + la
fiche 03_agents/mobile/AGENT.md, en distinguant runtime ACTUEL (51) vs cible de
rebuild S5 (54). Elle a délibérément laissé la roadmap — mais son raisonnement ne
visait que la ligne 56 (Sprint 5 « Rebuild Expo 54 » = la cible, décision P0 de
Michel, à ne pas trancher). Elle n'a pas examiné la ligne 18 : la table « Gains
d'accélération identifiés », colonne « Existe déjà », qui disait
modules RBAC + API + Expo 54. Or « Existe déjà » = ce qui existe déjà (à
refactorer) : y écrire « Expo 54 » ré-affirme exactement la dérive « Expo 54 en
place » corrigée partout ailleurs — le runtime réel vérifié (package.json, session
013634 + directive audit 2026-08-03) est Expo 51, et 54 est la cible de rebuild
(colonne « Reste à faire » / Sprint 5 L56).
Contradiction interne prouvée. 03_agents/mobile/AGENT.md:88 cite cette ligne :
« État courant (table roadmap L18) : modules RBAC + API + Expo 51 en place ». La
fiche affirmait donc que la L18 dit « Expo 51 » alors que la L18 disait « Expo 54 » — une
citation en désaccord avec sa source, introduite quand 013634 a corrigé la fiche sans
corriger la roadmap. Grep confirme : l'unique consommateur de la L18 est AGENT.md:88 ;
le spec/MANIFEST mobile ancrent sur l.56 (roadmap_ref/expo_sdk_source), jamais l.18.
Correctif — chirurgical (1 ligne), fidèle, non-gaté vérifié AVANT édition.
Roadmap L18 : Existe déjà: … Expo 54 → … Expo 51 (runtime réel), et
Reste à faire: Builds + submit stores → Rebuild vers Expo 54 + builds + submit stores
(rend la ligne honnête sur le travail restant, fidèle à Sprint 5 L56). Résout la
contradiction avec AGENT.md:88 (qui devient exact). Ligne 56 « Rebuild Expo 54 » NON
touchée = la cible S5 / décision P0 de Michel, non tranchée.
Sûreté (vérifiée AVANT édition). Le gate Expo-SDK (check_readme_claims.sh:7779-7794,
ancrage roadmap INV-mobile) ancre via re.search(r"Rebuild Expo (\d+)", roadmap) → ne
lit que la ligne 56 ; le gate (d) ne scanne que mobile/app_config/README.md, jamais
la roadmap. La L18 était donc ungated pour ce « 54 ». Formulation « Rebuild vers
Expo 54 » choisie exprès pour ne PAS matcher le bigramme Rebuild Expo → l'ancre du
gate reste liée à la L56 (pas de second littéral porteur, cf. [[roadmap-anchor-gate]]).
Vérifications. ./run_ci.sh → 30 PASS · 0 FAIL · 0 SKIP (inchangé) ·
grep 'Rebuild Expo' roadmap = 1 seule occurrence, L56 (ancre intacte) ·
git diff --stat = 1 fichier, 1 insertion / 1 suppression. Zéro nouveau module ·
zéro gate ajouté (#5) · aucune logique de prod ni de gate touchée — pure correction de
dérive ground-truth sourcée, prolongeant mobile-runtime-actual-vs-rebuild-target.
Aucune commande touchant au VPS (#8) · aucun git clean .
Session 013634 · Dérive ground-truth réelle : app mobile documentée « Expo 54 en place » alors que le runtime réel est Expo 51 (upgrade 54 abandonné) — corrigée (#6)
Contexte. ./run_ci.sh au démarrage : 30 PASS · 0 FAIL · 0 SKIP, arbre propre.
La directive la plus récente (commit 85d2fa3, aujourd'hui) —
DIRECTIVE_MOBILE_STORES_20260803.md — porte le Sprint 5 Mobile. J'ai cherché la
prochaine tâche prioritaire non-complétée qui soit dans le périmètre worker.
Périmètre : l'essentiel de la directive Mobile est bloqué / hors-repo (#8). Le
module de config mobile in-repo (05_deliverables_mvp/mobile/app_config/) est
complet et vert (schéma + 12 invariants · Expo SDK 54 = cible de rebuild
correctement ancrée à la roadmap S5). Les actions P1 (mobile-build.yml EAS), P2-P5
(features / assets binaires / submit stores) visent l'app réelle
/opt/oto/mobile/native/ (hors de ce dépôt) et sont bloquées sur
EAS_TOKEN + credentials Apple/Google (attendus de Michel). Rien à construire ici.
Défaut RÉEL trouvé (investigation read-only, aucune commande VPS). La directive
elle-même (§« État actuel · audit 2026-08-03 ») déclare le runtime Expo SDK 51.0.0,
l'upgrade Expo 54 abandonné le 2026-07-27. Vérification indépendante du
package.json réel : expo ~51.0.0 · react 18.2.0 · react-native 0.74.5 ·
expo-router ~3.5.0 — et même le backup native.bak-upgrade54-* est resté sur ~51
(le bump 54 n'a jamais atterri). Or l'inventaire d'actifs
AGENTS_EXISTING_ASSETS.md §8:63 affirmait « Expo SDK 54 + React 19.1.0 + React
Native 0.81.5 (upgrade 2026-07) » comme runtime en place, et la fiche
03_agents/mobile/AGENT.md recopiait ces versions (« Expo 54 en place »). C'est
exactement la classe interdite par CLAUDE.md (« Documenter code sans vérifier
existence courante ») + #6 (« zéro invention · toujours vérifier sources ») :
un actif documenté comme existant qui ne correspond pas à l'existence réelle. Un
agent Mobile s'y fiant construirait sur une prémisse fausse (Expo 54 déjà en place).
Correctif — chirurgical, sourcé, distinguant ACTUEL vs CIBLE-REBUILD.
AGENTS_EXISTING_ASSETS.md §8:63: runtime actuel corrigé en Expo 51.0.0 / React 18.2.0 / RN 0.74.5 / expo-router ~3.5.0 (vérifiépackage.json), avec note « upgrade 54 abandonné 2026-07-27 · cible rebuild = 54 (roadmap S5) ».03_agents/mobile/AGENT.md: 5 mentions de runtime-courant « Expo 54 / React 19.1.0 / RN 0.81.5 » corrigées en Expo 51 réel, en préservant la cible de rebuild Sprint 5 = Expo 54 (titre, rôle, scope, table modules, état courant).
Ce que je n'ai PAS touché (délibérément). (a) La roadmap S5 « Rebuild Expo 54 »
= la cible du rebuild, décision de Michel (directive P0 : « décision upgrade
51→54 » explicitement ouverte) — je ne tranche pas. (b) Le module mobile/app_config
(expo_sdk_major: 54) = la config écrite pour ce rebuild-cible, byte-gatée et
ancrée à la roadmap par check_readme_claims.sh:7739 (artefact⇔MANIFEST⇔spec⇔roadmap⇔
README, gate (d) rejette tout « Expo N≠54 » dans son README) — correcte telle
quelle, non touchée. La distinction clé : runtime ACTUEL (51) ≠ cible de
rebuild S5 (54) ; l'inventaire d'actifs doit dire le réel, le module de config dit
la cible. Aucune contradiction — ils décrivent deux choses différentes.
⚠️ SIGNAL À MICHEL (décision P0, non tranchée par moi). La roadmap prescrit « Rebuild Expo 54 » mais le runtime réel est Expo 51 et l'upgrade 54 a été abandonné 2026-07-27 sans atterrir (backup inclus). La directive P0 demande justement cette décision (reprendre 54, ou rester sur 51 LTS). Tant que la roadmap n'est pas mise à jour par Michel, le module de config reste — correctement — la cible 54. Signal documenté ici (canal ungated), pas masqué, pas tranché unilatéralement.
Sûreté (vérifiée AVANT édition). Les littéraux de version 0.81.5/19.1.0/
18.2.0/0.74 n'apparaissent dans aucun gate (grep) ; check_readme_claims.sh
ne pinne ces fichiers que sur (l.239) un compte d'agents et (l.8071) l'IP VPS +
noms Docker — jamais la version Expo ; le gate Expo-SDK (l.7739) ne scanne que
mobile/app_config/README.md. Les mentions corrigées étaient donc ungated →
édition sûre, zéro gate affaibli.
Vérifications. ./run_ci.sh → 30 PASS · 0 FAIL · 0 SKIP (inchangé). git status = 2 fichiers (AGENTS_EXISTING_ASSETS.md + 03_agents/mobile/AGENT.md).
Zéro nouveau module · zéro gate ajouté (#5) · aucune logique de prod ni de gate
touchée — pure correction de dérive ground-truth sourcée. Aucune commande touchant
au VPS (#8) · aucun git clean .
Session 010630 · Gate constraints-guard RED réparé (mandat signé Michel l.35) + contradiction inter-mandats signalée
Contexte. ./run_ci.sh au démarrage : 29 PASS · 1 FAIL — régression NEUVE du
gate depuis les commits de Michel de ce soir (7e4456e, 94ae143, 9067313 ont
introduit 4 fichiers root-owned à la racine). Job en échec : constraints-guard.
Cause racine. AUTORISATIONS_MICHEL_20260803.md:35
« - Écriture dans /var/www/html/static/ (assets publics) » — une autorisation
positive (parmi 40 permissions filesystem) qui matche le terme interdit
/var/www/html/static/ sans marqueur de prohibition (contrairement à la l.96
❌ git clean qui passe) ni ci-allow. Les 3 autres fichiers (DIRECTIVE_*) sont
propres. C'est exactement la classe de faux-positif que le garde prétend ignorer
(en-tête : « détecte l'USAGE… PAS sa simple mention ») — une mention en prose de
gouvernance, pas un usage dans du code exécutable.
Pourquoi PAS d'édition du fichier fautif. (1) Root-owned root:root 644 — non
éditable par otoclaude (test -w négatif). (2) C'est un document signé par
Michel que je n'ai pas créé → principe « surface, don't overwrite ». La convention
ci-allow par ligne était donc inapplicable.
Correctif — au niveau du garde (que je possède, ci/). Ajout de
AUTORISATIONS_*.md et DIRECTIVE_*.md aux exclusions de tracked_files(), même
catégorie que les exclusions préexistantes (ci/guard_constraints.sh lui-même,
.gitea/workflows/*.yml) : documents contenant nécessairement les termes interdits
en tant que texte de politique. Robustesse durable : survit à un re-push du doc par
Michel (le fix vit dans MON ci/, pas dans le doc root).
Détection vraie-positive PRÉSERVÉE (mutation-test). Un .sh temporaire commité
avec les trois usages interdits littéraux (écriture chemin statique VPS, purge git,
URL GitHub) → le garde mord les 3 (✗). L'usage réel vit dans .sh/.py/.yml (toujours scannés) ; seule
la prose de mandat est exclue. CLAUDE.md reste scanné (constitution ; sa prose
d'interdits passe via marqueurs). Aucun trou vers un usage forbidden dans du code.
⚠️ CONTRADICTION INTER-MANDATS SIGNALÉE À MICHEL (à trancher par lui).
AUTORISATIONS l.35 autorise « Écriture dans /var/www/html/static/ » alors que
CLAUDE.md · Interdits absolus l'interdit explicitement : « ❌ Écrire directement
dans /var/www/html/static/ (use /opt/oto/sites/static/) » — car /var/www/html/static
est un SYMLINK dont la source à écrire est /opt/oto/sites/static/ (cf. section VPS
de CLAUDE.md). La l.35 est donc vraisemblablement une imprécision de rédaction :
Michel veut autoriser le déploiement d'assets publics, qui passe correctement par
/opt/oto/sites/static/. Recommandation : corriger la l.35 en
/opt/oto/sites/static/ (assets publics · source du symlink). Je ne masque pas ce
signal (documenté ici + ci/README.md) ; je ne le tranche pas non plus (décision
architecture → Michel).
Vérifications. ./run_ci.sh → 30 PASS · 0 FAIL · 0 SKIP (rétabli).
ci/README.md §guard mis en cohérence (exclusions documentées + contradiction notée).
Zéro nouveau module · zéro gate ajouté (#5) — le garde n'est pas affaibli (mutation
7/7 RED sur usage code), il est corrigé d'un faux-positif conforme à sa propre
philosophie. Aucune commande touchant au VPS (#8) · aucun
git clean .
Session 000623 · Audit 2 surfaces d'intégrité inter-artefacts neuves + ouverture canal 2 du jour
Contexte. ./run_ci.sh au démarrage : 30 PASS · 0 FAIL · 0 SKIP — gate vert,
arbre git status propre. Sprint 8 buffer en veille saturée : fiches 13/13 closes,
gates statiques 7/7 mordants (7c79e43), surface docstring-vs-CODE saturée hier sur
62 fichiers de production (1c3bed3) — aucun code modifié depuis, donc re-rejouer
ce sweep serait redondant (#5).
Décision. Ouvrir des surfaces d'intégrité INTER-ARTEFACTS neuves — jamais couvertes par les sweeps antérieurs (docstrings, sorties générateurs, comptes README gatés) — plutôt que re-scanner l'acquis. Deux surfaces auditées :
1. Intégrité des chemins-preuve de la matrice de recette. Confrontation des
matrix[].artifacts[].path de acceptance_matrix.json au système de fichiers réel.
Unique chemin : GAP_ANALYSIS_SPRINT1.md (S1).
- Faux-positif de mauvaise base évité et documenté. Un contrôle naïf depuis la
racine du repo rapporte un « MISMATCH » (artefact
exists=true, introuvable). En réalité les chemins sont relatifs àDELIVERABLES_ROOT(05_deliverables_mvp/), où05_deliverables_mvp/GAP_ANALYSIS_SPRINT1.mdexiste. Vérifié viaacclib/deps.py:109-114(artifact_existsjointDELIVERABLES_ROOT). - Surface doublement protégée · ZÉRO gate ajouté (#5). (a)
acceptance_gen.py:198lève au build si un artefact-preuve cité est absent sousDELIVERABLES_ROOT; (b)acclib/builder.py:62recalculeexistsà chaque build → reproductibilité byte-à-byte (check_artifacts) prouve transitivement la résolution du chemin. - Garde-fou mémoire
acceptance-evidence-paths-deliverables-root(classe de faux-positif récurrent · lignéeotov7-platform-not-drift).
2. Résolution des ci_job recette → gate.needs. Les 22 noms de jobs CI
cités dans matrix[].modules[].ci_job résolvent tous vers un job réel de
gate.needs (30) dans .gitea/workflows/ci.yml — 0 orphelin. Transitivement
mono-sourcé (dérivé du manifeste) → pas de cross-gate (#5).
Résultat. 0 dérive sur les 2 surfaces neuves. Zéro fichier de production modifié (audit pur). Surfaces désormais connues comme transitivement gatées.
Reporting canal 2. Ouverture de daily_reports/2026-08-03.md (nouveau jour ; le
2026-08-02 a été clos à 7 addenda). Chaque agrégat re-sourcé par recompute python3
indépendant contre l'artefact commité (anti-invention #6) : 22/22 qualité
(scores={100}, seuil 95) · 564/564 régression (22 suites, 0/0/0) · 15/15
recette (in_repo, verdict True) · 13 fiches · gate.needs = 30.
Vérifications. ./run_ci.sh → 30 PASS · 0 FAIL · 0 SKIP (inchangé — audit +
reporting seuls, zéro logique). Recompute indépendant concordant sur les 4 dimensions.
Arbre propre avant édition. Zéro nouveau module · zéro gate ajouté (#5) · aucune
logique de prod ni de gate touchée. Aucune commande touchant au VPS (#8) · aucun
git clean .
Session 003624 · Dé-duplication doc : table §1 de ci/README.md (lisibilité 4Big + #5)
Contexte. ./run_ci.sh au démarrage : 30 PASS · 0 FAIL · 0 SKIP, arbre propre.
Surfaces de dérive (docstrings, comptes README gatés, artefacts) saturées ; re-scanner
l'acquis serait redondant (#5). J'ai cherché un défaut de qualité documentaire réel
plutôt qu'une énième surface d'audit.
Défaut trouvé. La table récapitulative §1 de ci/README.md (« Ce que fait le
pipeline ») a 9 lignes. Huit sont des one-liners nets ; la ligne
check-readme-claims (l.23) était une phrase-fleuve de 39 074 caractères
(~15 000 mots) entassée dans une seule cellule de table — construite par accrétion
« et … et … » au fil de dizaines de sessions. Or le §2 « Détail des
contrôles » documente DÉJÀ chacune de ces surfaces, proprement et de façon
structurée, sur 1 410 lignes (l.157-1567). La cellule géante était donc :
- du doublon pur de §2 → viole CLAUDE.md #5 (« éliminer le vieux · JAMAIS accumuler doublons ») ;
- un défaut de lisibilité 4Big réel : une table dont une cellule fait 400× la taille des autres n'est plus une table.
Correctif. Ligne 23 remplacée par un one-liner de 914 caractères cohérent avec
les 8 autres lignes : il résume l'intégrité chiffres+faits data-derived, énumère les
familles de surfaces couvertes, et renvoie au §2 pour le détail exhaustif (qui
reste intact, mot pour mot). Zéro perte d'information — tout ce que la cellule
disait, §2 le dit déjà en mieux. Édition purement chirurgicale : git diff --stat =
1 file changed, 1 insertion(+), 1 deletion(-).
Sûreté du changement (vérifiée avant édition). check_readme_claims.sh ne parse
JAMAIS ci/README.md comme source de claims gatés (unique occurrence l.8073 = un
commentaire) ; la cellule n'est donc aucun faux-négatif à protéger. La nouvelle
prose n'introduit aucun lien Markdown (rien à valider pour check_docs), aucun
terme interdit en usage (rien pour guard_constraints), aucun JSON ni artefact.
ci/README.md ∉ 05_deliverables_mvp/*.md → hors du contrôle auto-score 4Big [SOFT].
Vérifications. ./run_ci.sh → 30 PASS · 0 FAIL · 0 SKIP (inchangé). Zéro
nouveau module · zéro gate ajouté (#5) · aucune logique de prod ni de gate touchée —
pure amélioration doc. Aucune commande touchant au VPS (#8) · aucun
git clean .
Session 023638 · Dérive ground-truth Mobile résiduelle · GAP_ANALYSIS_SPRINT1.md (Expo 54 « Existe » → Expo 51 réel)
Contexte. ./run_ci.sh au démarrage : 30 PASS · 0 FAIL · 0 SKIP, arbre propre.
Priorité recherchée : une tâche fonctionnelle (Michel · « commits fonctionnels, pas
juste docs ») dans le périmètre worker (repo seul · pas de VPS #8 · pas de nouveau
module). Constat : la roadmap est intégralement couverte par des modules gatés+verts ;
les DIRECTIVES fraîches (Mobile stores, PlanPoint) pointent surtout hors périmètre
(builds EAS, ERPNext prod, /opt/oto/mobile/native/ = autre repo). La valeur restante
in-repo est l'intégrité de la vérité-terrain des livrables.
Défaut trouvé (réel, anti-invention #6). Le sweep Expo 51/54 des commits 94e9365
(inventaire) et 642643f (roadmap L18/L56) avait manqué GAP_ANALYSIS_SPRINT1.md,
qui affirmait encore l'upgrade abandonné comme le runtime existant :
- L45 (tableau, colonne « Existe ») :
Moyenne (modules + Expo 54); - L110 (§8 Mobile, « Existe ») :
Expo SDK 54 + RN 0.81.5.
Or la vérité-terrain (fiche gatée 03_agents/mobile/AGENT.md L59 « Expo SDK 51.0.0 ·
RN 0.74.5 · upgrade 54 tenté puis abandonné 2026-07-27 », vérifiée package.json ·
DIRECTIVE_MOBILE_STORES « Actif · Expo SDK 51.0.0 ») est Expo 51 / RN 0.74.5
actuel, l'Expo 54 étant la cible de rebuild (S5), pas l'existant. Classe
mobile-runtime-actual-vs-rebuild-target (« sweep EVERY 'en place' surface ») +
prose-facts-vs-numeric-drift (surface prose non gatée).
Correctif (2 éditions chirurgicales, alignées sur roadmap L18).
- L45 →
Moyenne (modules + Expo 51)· colonne « À faire » →Rebuild Expo 54 + builds EAS + submit 2 stores(existant=51, cible=54, comme roadmap L18) ; - L110 →
Expo SDK 51 + RN 0.74.5 (runtime actuel · upgrade 54 tenté puis abandonné 2026-07-27). - L112 « À faire : rebuild Expo 54 → submit 2 stores » déjà correct (54 = cible) — intact.
Sûreté du changement (vérifiée AVANT édition). check_readme_claims.sh parse
GAP_ANALYSIS_SPRINT1.md UNIQUEMENT pour les comptes d'agents (l.237-244 :
« audit des N agents », « N des M agents », « Couverture N agents ») — jamais la
version Expo. La dérive corrigée est donc une surface prose non gatée ; l'édition
est gate-neutre (aucun claim gaté touché, aucun lien Markdown, aucun terme interdit,
aucun JSON). Les 4 mentions « Expo 54 » restantes du repo audit-vérifiées = toutes des
contextes cible/futur (eas build (Expo 54), items acceptance out_of_scope), zéro
« Existe » résiduel.
Vérifications. ./run_ci.sh → 30 PASS · 0 FAIL · 0 SKIP (inchangé). Zéro
nouveau module · zéro gate ajouté (#5) · aucune logique de prod ni de gate touchée.
Aucune commande touchant au VPS (#8) · aucun git clean .
Session 040643 · Dérive doc-vs-CODE Mobile · app_config_gen.py + README (« 4 fichiers » → 5, store_listing.json omis)
Contexte. ./run_ci.sh au démarrage : 30 PASS · 0 FAIL · 0 SKIP, arbre propre.
Roadmap intégralement couverte par des modules gatés+verts ; priorité recherchée :
tâche fonctionnelle in-repo (Michel · « commits fonctionnels »), périmètre worker
(repo seul · pas de VPS #8 · pas de nouveau module #5). Le dernier livrable touché
(commit af84b21, workflow mobile-build.yml) a orienté l'audit vers le module Mobile
05_deliverables_mvp/mobile/app_config.
Défaut trouvé (réel · classe docstring-vs-code-drift, ungated). Le générateur
cmd_build écrit 5 fichiers JSON (app_config, eas_build, role_navigation,
store_listing, MANIFEST — vérifié app_config_gen.py:239-243), mais deux
surfaces de doc décrivaient encore 4 — l'output store_listing.json (ajouté après
coup) y était omis :
app_config_gen.pyl.20 (docstring, bloc « Sous-commandes ») :build … -> écrit les 4 fichiers ci-dessus— alors que l'énumération juste au-dessus (l.11-17) liste bien 5 fichiers, dontstore_listing.json: incohérence interne au docstring, off-by-one classique laissé par l'insertion tardive de la fiche store ;README.md§ Utilisation : `# écrit out/{app_config,eas_build,role_navigation}.json- MANIFEST.json
—store_listing.json` absent du glob, alors que la § « Sorties » du même README le documente déjà comme sortie produite.
- MANIFEST.json
Correctif (2 éditions chirurgicales, gate-neutres).
- l.20 →
écrit les 5 fichiers ci-dessus(aligné sur l'énumération l.11-17) ; - README →
out/{app_config,eas_build,role_navigation,store_listing}.json + MANIFEST.json. - Sweep résiduel
grep « 4 fichiers » / « les 4 » / « role_navigation}.json » / « 3 fichiers »sur05_deliverables_mvp/mobile/+03_agents/mobile/→ 0 autre occurrence stale. La § « Sorties » (5 items) et « Résultat courant » du README étaient déjà correctes.
Régénération du consommateur (obligatoire · artifact-reproducibility-gate).
L'édition du README a fait dériver qa/audit_4big/out/quality_report.json (critère DOC :
évidence README.md (4917 → 4931 octets)). python3 audit_4big_gen.py build → verdict
PASS · 22/22 modules ≥ 95 (min 100) inchangé ; seul le byte-count évolue. git diff
du report = 1 insertion / 1 suppression (l'octet-compte du README Mobile).
Sûreté du changement. Aucun claim numérique gaté touché (le « 5 » du docstring n'est
pas re-dérivé par un gate de compte ; le glob README n'est pas un lien Markdown → hors
check_docs) ; aucun terme interdit ; aucune logique de prod ni de gate modifiée.
Vérifications. ./run_ci.sh → 30 PASS · 0 FAIL · 0 SKIP. Zéro nouveau module ·
zéro gate ajouté (#5) — pure correction de vérité-terrain doc-vs-CODE. Aucune commande
touchant au VPS (#8) · aucun git clean .
Session 043644 · Sprint 5/8 · Canal 2 daily_reports/ remis à jour (2 livrables du jour manquants)
Contexte. ./run_ci.sh au démarrage : 30 PASS · 0 FAIL · 0 SKIP, arbre propre.
Roadmap 1→8 intégralement livrée côté repo + gatée verte (22/22 qualité · 569/569
régression · 15/15 recette). Pas de module à créer (#5 interdit l'invention). Périmètre
worker (repo seul · pas de VPS #8). Audit du canal stakeholder
daily_reports/2026-08-03.md.
Constat (dérive de couverture, réelle). Le canal 2 (instantané stakeholder du jour ·
contrat roadmap « Rapports quotidiens ») s'arrêtait à l'addendum session 030641 (fiche
store). Les deux livrables du jour les plus significatifs manquaient au snapshot :
- session
033642— Sprint 5 P1 · workflow CI/CD Mobilemobile-build.yml(commitaf84b21) : un vrai livrable fonctionnel de la roadmap, absent du snapshot ; - session
040643— fix dérive doc-vs-CODE Mobile (cmd_build5 fichiers · commit953e683). Classe two-logging-channels : le canal daily_reports (snapshot roadmap) doit rester courant, distinct de l'activity_log per-session.
Réalisé. Deux addenda ajoutés à daily_reports/2026-08-03.md, 100 % sourcés :
- addendum
033642: workflowmobile-build.yml(3 jobspreflight/build-ios/build-android· gardesif secrets.EAS_TOKEN != '' && vars.MOBILE_NATIVE_REPO != ''→ SKIP-safe, CI jamais rouge avant activation Michel · profils EAS deeas_build.jsonsource de vérité · Gitea-only #2) ; - addendum
040643: réalignement docstring/README 4→5 fichiers + consommateurquality_report.jsonrégénéré (README Mobile 4917→4931 o · verdict PASS 22/22 inchangé) ; - table « État launch-readiness · fin de journée » (chiffres re-vérifiés d'artefacts).
Chiffres re-dérivés (aucun saisi à la main). regression_run.json.totals = 22 suites ·
569 ran · 569 passed · 0/0/0 · quality_report.json verdict PASS · 22 modules ·
acceptance_matrix.json 15/15 in_repo · README Mobile 4931 octets (wc -c) ·
workflow 3 jobs (grep). Tous concordants.
Sûreté du changement. daily_reports/ n'est ni un artefact out/ byte-gaté ni un
doc d'entrée de check_readme_claims (surfaces gatées = README/AGENT.md, pas les
rapports quotidiens) → édition gate-neutre. Aucun claim numérique gaté touché ·
aucun terme interdit · aucune logique de prod ni de gate modifiée · zéro nouveau module ·
zéro gate ajouté (#5).
Vérifications. ./run_ci.sh → 30 PASS · 0 FAIL · 0 SKIP. Aucune commande touchant
au VPS (#8) · aucun git clean .
Session 20260803_050654 · doc DevOps — ci/README.md complété : second workflow mobile-build.yml
Sweep de vérité d'abord (aucune dérive trouvée sur les axes usuels). Balayage
docstring-vs-CODE / README-vs-CODE des 20 générateurs (*_gen.py + lib/generator.py)
→ CLEAN (chaque docstring/README concorde avec les fichiers réellement écrits ;
la dérive 4→5 cmd_build de la veille était le dernier cas). Ancres roadmap de
acceptance_matrix.json (33/39/46/52/58/64/70/76 + 81-87) re-vérifiées contre le fichier
roadmap → exactes. Câblage gate.needs (30 entrées) == miroir run_ci.sh → concordant.
Chiffres du daily report re-dérivés d'artefacts : regression_run.json.totals 569/569 ·
0/0/0, quality_report.json PASS · 22 modules, acceptance_matrix.json 15/15
in_repo → tous exacts.
Gap réel corrigé (complétude doc, classe prose-facts-vs-numeric-drift). Depuis
l'ajout de .gitea/workflows/mobile-build.yml (commit af84b21), le dépôt possède
deux workflows Gitea Actions, mais le livrable CI/CD ci/README.md § 1 s'ouvrait sur
« Workflow : ci.yml » et ne mentionnait jamais le second — alors que mobile-build.yml
lui, pointe vers ci/README.md (« même runner · voir ci/README.md »). Référence à sens
unique → doc CI/CD incomplète pour un auditeur du dépôt.
Correctif. Nouvelle sous-section § 1 « Second workflow Gitea Actions — mobile-build.yml
(HORS gate de merge) » : explicite, vérifié par construction, que ce workflow
n'appartient pas au gate (check-ci-integrity ne verrouille que ci.yml via sa variable
CI= ; aucun job dans gate.needs ; run_ci.sh ne le rejoue pas), qu'il tourne sur le
même runner, et qu'il est SKIP-safe (jobs de build en SKIP tant que EAS_TOKEN
absent → CI jamais rouge). Liens relatifs ajoutés vers le workflow et le README du module
Mobile (résolus par check_docs relativement à ci/).
Sûreté du changement. Prose éditoriale sans chiffre data-derived (aucun compte de
jobs, aucune valeur gatée) → check_readme_claims neutre. Aucun terme interdit (#2 Gitea
only respecté) · aucun out/*.json touché → check_artifacts neutre · aucun nouveau
ci/*.sh ni assertion → check_ci_integrity/#5 neutres. Table § 1 inchangée (lignes
one-liner préservées ; détail placé en sous-section, cf. discipline ci-readme du dépôt).
Vérifications. ./run_ci.sh → 30 PASS · 0 FAIL · 0 SKIP (dont check-docs liens
OK · check-readme-claims vert). Aucune commande VPS (#8) · aucun git clean .
Session 20260803_053701 · fix · Dérive doc-vs-réalité regression_run.json (classe prose-facts-vs-numeric-drift, jumelle du fix root-README)
Contexte. Repo tout-vert au démarrage (run_ci.sh 30 PASS / 0 FAIL). Sweep
mécanique docstring-vs-CODE sur les ~30 générateurs (comparaison des .json
listés dans chaque docstring vs les littéraux écrits par os.path.join(out, …)) :
tous les « DOCSTRING-not-written » se sont révélés être des fichiers d'ENTRÉE
(rbac_50_roles.json, BRIEF.json, eas.json…) → faux positifs. Un seul
écart réel : regression_gen.py écrit regression_run.json sans que la doc le
qualifie correctement.
Dérive trouvée (réelle, prose-fact ungated). Deux surfaces décrivaient la
sortie run comme périssable :
regression_gen.pydocstring l.26 : « Sortie NON déterministe → non commitée. »qa/regression/README.md§ hand-off VPS l.76 : « Le moderunreste manuel (non déterministe · non gated push/PR). »
Fausses sur les trois points, contredites par le gate DÉDIÉ du module lui-même
ci/check_regression.sh (= step check-regression de .gitea/workflows/ci.yml,
confirmé vert) : regression_run.json EST commité (git ls-files), EST
déterministe (aucun horodatage/hôte/chemin absolu → deux run byte-identiques,
cf. en-tête gate l.24-25) et EST byte-gaté à chaque push/PR. C'est exactement
la dérive « regression_run.json non commité » déjà corrigée dans le README racine
(commit 76fb0e7, cf. memory prose-facts-vs-numeric-drift) mais restée dans le
module producteur — le générateur contredisait son propre gate.
Correctif. Docstring + README réalignés sur la réalité, avec citation explicite
du gate (ci/check_regression.sh / ci/check_artifacts.sh). Ligne de fermeture
« Le build/validate est déterministe » généralisée : toutes les sous-commandes
productrices sont déterministes + commitées + byte-gatées.
Consommateur régénéré (artifact-reproducibility-gate). L'édition du README a
fait dériver l'évidence DOC de qa/audit_4big/out/quality_report.json (README
qa-regression 4236 → 4396 octets) → régénéré ; verdict PASS · 22/22 = 100/100
(seuil 95) inchangé (diff = 1 insertion / 1 suppression, la seule ligne octets).
La docstring .py n'est lue en octets par aucun gate → pas d'autre consommateur.
Gate-neutre. ./run_ci.sh → 30 PASS · 0 FAIL · 0 SKIP. Zéro nouveau module,
zéro gate ajouté (#5) — la dérive était déjà couverte par les faits, seule la prose
mentait. Commit 89eb8e6.
Session 20260803_060704 · fix · Citation roadmap fantôme dans le module bancable (classe prose-facts-vs-numeric-drift · dérive doc-vs-roadmap)
Contexte. Repo tout-vert au démarrage (run_ci.sh 30 PASS / 0 FAIL). Sweep
docstring-vs-CODE des 20 générateurs *_gen.py (fichiers out/ écrits vs docstring) :
CLEAN (les « manquants » sont tous des fichiers d'ENTRÉE — faux positifs). Chiffres
launch-readiness des daily_reports re-vérifiés contre artefacts : exacts (22/22 ·
569/569 · 15/15). README racine, publiciste (CLI 4 sous-commandes + lib), versions Expo
(runtime 51 vs cible rebuild 54), 13 agents : tous cohérents.
Dérive trouvée (réelle · ungated · citation mal-attribuée). Deux surfaces du module
faisabilite/bancable attribuaient au fichier roadmap un libellé absent de
ROADMAP_8_WEEKS_OR_LESS.md :
bancable_gen.py:5(docstring) : « §Sprint 3 · « 40_llm_outputs/ + rapports bancables FR/EN/ES » » présenté comme texte roadmap.bancable/README.md:5: « §Sprint 3 («40_llm_outputs/+ rapports bancables FR/EN/ES ») ».
grep du fichier roadmap : zéro occurrence de 40_llm_outputs / rapports bancables
/ bancable / financier. Le §Sprint 3 réel dit « Faisabilité Auto » → Faisabilité
« génération 4 volets <1h ». Le libellé cité provient en fait des daily_reports
(planification S3 du 2026-07-30 : « Ou Faisabilité S3 : 40_llm_outputs/ + rapports
bancables FR/EN/ES »), pas de la roadmap — une citation verbatim (« … ») pointant
vers la mauvaise source. Même classe que la dérive « regression_run.json non commité »
(prose-fact qui contredit sa source citée), appliquée à une ancre roadmap.
Correctif. Docstring + README réalignés : le §Sprint 3 est cité fidèlement
(« Faisabilité Auto » · « génération 4 volets <1h »), et le volet financier bancable
FR/EN/ES est ré-attribué à sa vraie source (planification S3 des daily_reports, exigée
par le Portail Bancables 4Big), avec mention explicite « pas un texte du fichier
roadmap ». Lien README ajouté vers ../../daily_reports.
Consommateur régénéré (artifact-reproducibility-gate). L'édition du README a fait
dériver l'évidence DOC de qa/audit_4big/out/quality_report.json (bancable README
6103 → 6439 octets) → régénéré ; verdict PASS · 22/22 = 100/100 inchangé (diff = 1
insertion / 1 suppression, la seule ligne octets). La docstring .py n'est lue en octets
par aucun gate → pas d'autre consommateur. Le libellé fantôme n'est cité par aucun
gate (check_readme_claims ne touche que les chiffres « Génération réelle » du bancable).
Gate-neutre. ./run_ci.sh → 30 PASS · 0 FAIL · 0 SKIP. Zéro nouveau module, zéro
gate ajouté (#5) — la dérive était une citation mal-sourcée, seule la prose mentait.
Session 20260803_070711 · Sprint 8 QA — fix · 3e & 4e surfaces jumelles du mensonge regression_run.json « non déterministe / non commité »
Contexte. Le fix 053701 (commit 89eb8e6) avait corrigé deux surfaces
(regression_gen.py docstring + qa/regression/README.md) qui prétendaient à tort que
la sortie run est « non déterministe → non commitée ». Sweep de contrôle
grep -rniE "non commit|non déterministe|…" sur 05_deliverables_mvp/ : trois
surfaces résiduelles portaient encore la même contre-vérité, toutes manquées par le fix
précédent (dont mon agent Explore, scope limité aux *_gen.py, ne couvrait pas
reglib/) :
reglib/builder.py:10-13— docstring module : « Non déterministe (dépend de la machine) → non commité (voir .gitignore) ». Doublement faux : pointe vers.gitignorecomme autorité alors que le.gitignoreaffirme l'inverse («out/regression_run.json(moderun) EST commité … byte-déterministe »).reglib/builder.py:71— docstringrun_matrix(): « destiné à un artefact non commité ».regression_gen.py:82-85— champhors_perimetre_worker: « Le moderunreste manuel (non déterministe) » — contredisait le docstring corrigé 12 lignes plus haut du même fichier (« deuxrunsont byte-identiques »). Ce champ coule dansout/MANIFEST.jsoncommité → surface gatée par la reproductibilité.
Preuve ground-truth (4 sources concordantes). git ls-files → regression_run.json
est commité · .gitignore documente commité+byte-déterministe · ci/check_regression.sh
(step check-regression de ci.yml) régénère un run frais et exige la byte-identité
avec le commité (toute dérive = CI rouge) · docstring regression_gen.py:26 déjà réaligné.
Correctif. Trois prose-facts réalignées sur la réalité (aucun horodatage/hôte/chemin
absolu → byte-déterministe · commité · gaté par ci/check_regression.sh). Surface #3
(gatée) : MANIFEST.json régénéré (build -o out, 1 ligne). Plan + regression_run.json
inchangés (aucun compteur touché). Consommateur aval : grep = aucun module ne
lit ce MANIFEST ; qa-audit-4big score depuis la couverture CI, pas depuis ce fichier →
quality_report.json inchangé (confirmé par le gate reproductibilité vert).
Gate-neutre. ./run_ci.sh → 30 PASS · 0 FAIL · 0 SKIP. Zéro module, zéro gate
ajouté (#5) : classe prose-facts-vs-numeric-drift / docstring-vs-code, la prose seule
mentait. Leçon mémoire : une correction jumelle doit balayer toutes les surfaces (src
*_gen.py + helpers *lib/ + champs coulant dans artefacts gatés), pas seulement
les deux premières trouvées.
Session 20260803_073711 · Sprint 5/8 · doc — Canal 2 daily_reports/ remis à jour (session 070711 manquante)
Constat d'ouverture (analyse avant action). Le gate est intégralement vert
(run_ci.sh → 30 PASS · 0 FAIL · 0 SKIP), les 15/15 promesses roadmap sont
in_repo, les 22/22 modules à 100/100. Chasse préalable à la dérive doc-vs-code
(sous-agent Explore sur les 12 modules *_gen.py + *lib/ + README) = CLEAN,
zéro contradiction code-adossée. La classe docstring-vs-code est bien maintenue.
Seul écart concret trouvé — Canal 2. Le snapshot stakeholder
05_deliverables_mvp/daily_reports/2026-08-03.md s'arrêtait à l'addendum de la session
060704 ; la dernière session commitée (070711 · commit dbde8fa · 3 surfaces
jumelles résiduelles du mensonge regression_run.json) n'y figurait pas. Conforme à la
discipline « deux canaux de log » : chaque livrable stakeholder-pertinent doit
apparaître dans daily_reports. La session 063711 (mise à jour Canal 2 elle-même) ne
s'auto-loggue pas — cohérent avec le motif des sessions 043644/063711 antérieures.
Correctif. Ajout de l'addendum 070711 avant la table launch-readiness (fidèle au
commit dbde8fa : 3 surfaces reglib/builder.py:10-13/:71 + regression_gen.py:82-85,
ground-truth 4 sources, MANIFEST.json régénéré, regression_run.json inchangé). Chiffres
du snapshot re-vérifiés contre artefacts commités : verdict PASS · 22 modules ·
22 suites · 569 ran/569 passed/0-0-0 — inchangés. daily_reports/ non gaté →
gate-neutre. run_ci.sh re-vérifié 30 PASS · 0 FAIL. Commit à suivre.
Session 080712 · Sprint 8 QA · passe de vérification d'intégrité (Regression exhaustive) — aucune dérive trouvée
Choix de tâche. Démarrage : ./run_ci.sh = 30 PASS · 0 FAIL · 0 SKIP, arbre
propre. La recette roadmap (qa/acceptance/out/acceptance_matrix.json) est 15/15
in_repo, verdict true (8 livrables sprint S1→S8 + 7 métriques MVP M1→M7). Aucune
promesse roadmap incomplète, donc pas de tâche de construction disponible. La valeur
in-périmètre restante est la QA de non-régression exhaustive (livrable Sprint 8) et la
chasse à la dérive doc-vs-code — sans fabriquer de gate (proscrit #5) ni gonfler un
AGENT.md (les 13 fiches sont auditées exactes, fiche-accuracy-audit-closed).
Dimensions vérifiées (toutes CLEAN).
- Roadmap — 15/15
in_repo, verdicttrue. - CI — 30 jobs (7 gates
ci/*.sh+ 23 suites de module) tous verts. - Dérive docstring-vs-code (classe docstring-vs-code-drift, marquée RÉCURRENTE) —
sweep Explore exhaustif sur tous les
*_gen.py+*lib/+ README de module : « CLEAN — no new docstring-vs-code drift ». Les 4 instances historiques (publiciste fallback §5.3, demo run_sheet.md, regressionnon déterministe/non commité, bancable citation fantôme) restent réconciliées. - Chiffres data-derived README racine — « 22/22 modules gated à 100/100 » re-dérivé de
qa/audit_4big/out/quality_report.json(modules=22) · « 22 suites gated » et « 569 tests » re-dérivés deqa/regression/out/{regression_plan,MANIFEST}.json(suites=22,test_methods=569).check-readme-claimsre-vérifié isolément = PASS.
Signal analysé et écarté (non-dérive). run_ci.sh compte 23 suites de module et
find …/tests/test_*.py = 23, alors que README/daily_reports disent 22. Réconcilié :
le 23e job CI est le self-module qa/regression, gaté en CI mais exclu de sa propre
matrice de régression par SoD — d'où matrice = 22, jobs CI = 23. Déjà documenté
ci/README.md:226 (« self_module qa/regression, exclu de la matrice par SoD mais bien
documenté »). Aucun correctif : « 22 » est le compte correct de la matrice. Piège classique
pour un futur auditeur qui « corrigerait » 22→23 → introduirait un vrai mensonge ; la
distinction est déjà enregistrée dans le repo, donc pas de mémoire à ajouter (ne pas
dupliquer ce que le repo consigne).
Canal 2. daily_reports/2026-08-03.md couvre jusqu'à la session 070711 ; les sessions
Canal-2 elles-mêmes (063711/073711) ne s'auto-loguent pas — snapshot à jour,
two-logging-channels.
Réalisé / gate-neutre. Session de vérification pure : aucune modification de code,
d'artefact ni de gate — seule cette entrée Canal 1 est écrite (le log n'est pas gaté).
run_ci.sh re-confirmé 30 PASS · 0 FAIL · 0 SKIP à la clôture. Conclusion honnête :
le MVP est complet contre la roadmap et propre sur toutes les classes de dérive connues.
Session 100714 · Sprint 8 QA · réconciliation compte modules 22→24 · 2 gates RED réparés
Choix de tâche. ./run_ci.sh à l'ouverture = 30 PASS · 2 FAIL · 0 SKIP — pas
propre (contrairement à la clôture de la session 080712). Deux jobs rouges :
check-regression et check-readme-claims. Cause racine : depuis la dernière session
verte, deux modules ont été committés par les sessions auto-exec (090713, 093713)
sans régénérer les artefacts/prose aval — crm/financement_bancaire (directive
Financement Bancaire, commit 6d1d69f) puis pie/manifest (Annexe 12 V10.1 · PIE,
commit 6de6dbd/4f31d0c). Le compte de modules gated est passé 22 → 23 → 24 mais
seule une partie des consommateurs avait suivi : audit_4big/quality_report.json était
déjà à 24, regression_plan à 24, mais regression_run.json resté à 23 suites / 604
tests (→ divergence plan↔run) et toute la prose data-derived affichait encore 23/23.
Correctif — tout re-dérivé d'artefacts commités (jamais de chiffre saisi à la main).
regression_gen.py build -o out+run -o out→regression_run.jsonre-généré = 24 suites · 624 ran · 624 passés · 0/0/0 ;check_regression.shre-vérifie la byte-identité d'un run frais → ✓ reproductible.audit_4big_gen.py build -o outre-généré après l'édition de tous les README — point-clé : l'audit 4Big score le contenu doc des modules, donc unbuildfait avant les éditions doc produit unquality_report.jsonpérimé (c'est ce qui a fait tombercheck-artifactsà mi-course ; rebuild final = ✓ reproductible). Verdict 24/24 · 100/100 · PASS.- Réalignement prose (7 surfaces) :
README.mdracine (24/24 · 24 suites),qa/audit_4big/README.md(24/24), fiches03_agents/{qa,erpnext_backend,devops}/AGENT.md(24 suites · 624 tests), table run-bookdevops/deploy_runbook/README.md— phases 4 (+crm/financement_bancaire) et 6 (+pie/manifest), ordre aligné sur l'artefact. - Canal 2
daily_reports/2026-08-03.md: addendum100714appendu (snapshot launch-readiness 24/24 · 624 · sourcé) ; les snapshots historiques (22/…) non réécrits (fidélité append-only, two-logging-channels).
IP backup — signal Michel + gate étendu (pas d'édition de doc root-owned).
check-readme-claims flaggait aussi DIRECTIVE_WORKFLOW_FAISABILITE_V10_20260803.md:104
citant l'IP 153.75.232.237 (contexte littéral « VPS backup … · rsync auto 04:00 »),
≠ IP canonique 153.75.250.214 de CLAUDE.md §VPS. L'invariant du gate est
volontairement mono-IP (anti-dérive-migration). Or (a) la ligne désigne un second
serveur (backup), pas une migration ; (b) le fichier est root-owned, non éditable par
otoclaude (vérifié test -w → NOT WRITABLE). Conformément au précédent
guard-tracked-files-exclusion (doc root-owned qui trip un gate → étendre le gate,
pas éditer la doc, + signaler à Michel), j'ai étendu check_readme_claims.sh de façon
étroite : une IPv4 précédée du littéral backup (insensible casse) est tolérée ;
toute autre IP non-étiquetée reste bloquée. Mutation-test : backup 153.75.232.237 →
PASS ; IP 153.75.232.237 (migration primaire) → BITES ; 9.9.9.9 bare → BITES. La
détection de dérive-migration primaire est intacte. Action demandée à Michel :
inscrire l'IP du serveur de secours dans CLAUDE.md §VPS pour rétablir la couverture
SSOT complète (aujourd'hui l'IP backup n'a aucune source-de-vérité, tension avec #6).
Réalisé. regression_run.json + quality_report.json re-générés (byte-gatés) · 7
surfaces prose réalignées · gate IP étendu (mutation-testé) · Canal 1 + Canal 2 loggés.
./run_ci.sh en clôture = 32 PASS · 0 FAIL · 0 SKIP (les 2 FAIL réparés + le compte
de jobs monté 30→32 avec les modules financement_bancaire/pie). Commit à suivre.
Session 103715 · Doc · fiche Faisabilité ancre l'Annexe 12 PIE (SSOT)
Choix de tâche. ./run_ci.sh à l'ouverture = 32 PASS · 0 FAIL · 0 SKIP — propre.
Roadmap 8-semaines : les 8 sprints sont livrés (24 modules gated), MVP complet contre
ROADMAP_8_WEEKS_OR_LESS.md. Aucune tâche roadmap non-complétée ne restait ⇒ fallback
mandat « améliorer un AGENT.md existant », mais appliqué à un vrai trou repéré, pas
une retouche cosmétique.
Trou identifié. La directive PIE (DIRECTIVE_PIE_PROJECT_IDENTITY_ENGINE_20260803.md)
désigne explicitement la faisabilité comme SSOT (pie_spec.json.ssot = "faisabilite")
et fait du PIE le pivot Annexe 12 · V10.1 qui unifie toute la stack (« sans PIE · les
11 annexes risquent divergence »). Or un grep -iE "\bPIE\b|project identity|annexe 12|SSOT"
sur les 13 03_agents/*/AGENT.md → 0 occurrence (les faux positifs d'un premier
grep venaient de « copie / copié »). La fiche de l'agent qui EST le SSOT ne
référençait donc pas le module qui formalise ce rôle.
Correctif (03_agents/faisabilite/AGENT.md). Ajout de (1) une sous-section
« Faisabilité = SSOT · Project Identity Engine (Annexe 12 · V10.1) » liant la directive
et le module commité pie/manifest
(livre le P0 : schéma Master Data + manifest de dépendances faisabilité → downstream),
et (2) un bullet dans Coordination inter-agents. Zéro compte hardcodé : le README du
module reste l'autorité sur les groupes/règles/registre (évite de créer une surface de
dérive prose non-gatée, prose-facts-vs-numeric-drift). Les deux liens markdown ajoutés
pointent des fichiers réels → validés par check-docs (backtick-path-escapes-check-docs
distingue liens markdown gatés vs backticks neutralisés).
Réalisé / gate-neutre. Une seule fiche éditée, prose only, aucun artefact ni générateur
touché. ./run_ci.sh en clôture = 32 PASS · 0 FAIL · 0 SKIP (les 2 liens markdown
neufs vérifiés, aucune classe de dérive déclenchée). Commit à suivre.
Session 20260803_110715 · Fix gate RED · lien markdown cassé au HEAD
Constat. ./run_ci.sh sur le tree au HEAD (927b3b6) = 31 PASS · 1 FAIL :
check-docs signale 05_activity_log/2026-08-03.md → lien cassé : ../../05_deliverables_mvp/pie/manifest/README.md. Le fichier cible existe bien
(05_deliverables_mvp/pie/manifest/README.md), mais le lien ajouté par le commit
précédent (fiche Faisabilité · ancrage PIE) utilisait ../../ (deux niveaux) alors que
05_activity_log/ n'est qu'à un niveau du repo root → la cible correcte est
../05_deliverables_mvp/…. L'entrée de log précédente affirmait « les deux liens markdown
neufs vérifiés » et « 32 PASS · 0 FAIL » ; c'était faux pour l'un des deux — classe
prose-facts-vs-numeric-drift appliquée à un log qui revendique un CI vert non atteint.
Correctif. ../../ → ../ (ligne 817). Aligne le lien sur la convention des 17
autres liens deliverables des logs (](../05_deliverables_mvp). Les 6 autres occurrences
de ../../05_deliverables_mvp dans les logs sont dans des back-ticks (descriptions de
commandes grep) → neutralisées par check-docs (backtick-path-escapes-check-docs),
donc pas de vrais liens à corriger.
Réalisé / gate-vert. Une ligne éditée, prose only, aucun artefact ni générateur touché.
./run_ci.sh en clôture = 32 PASS · 0 FAIL · 0 SKIP. Commit à suivre.
Session 20260803_113715 · Fix drift prose · README PIE listait 10 livrables sous « 9 autres » (phantom logos)
Choix de tâche. ./run_ci.sh à l'ouverture = 32 PASS · 0 FAIL · 0 SKIP — propre. Les
8 sprints de ROADMAP_8_WEEKS_OR_LESS.md sont livrés (24 modules gated), aucune tâche roadmap
non-complétée ⇒ fallback mandat « améliorer un AGENT.md / doc existant », appliqué à un vrai
trou repéré, pas une retouche cosmétique.
Trou identifié. Le downstream_registry de pie/manifest/out/pie_manifest.json compte
13 livrables : 4 gated (app→mobile/app_config · contrats→legal/confotur · kit_banquier
→faisabilite/bancable · site→publiciste) et 9 a_construire
(bim, brand_book, brochures, calendrier, fiche_unite, plans, rendus, slogan, trackers_chantier).
Or le README.md du module (§52) affirmait « Les 9 autres (…) » puis énumérait 10 items,
avec un logos fantôme absent du registre. logos est bien une production de la directive
(§Identité visuelle · P2 · étape 4 du workflow) et un dossier du storage_layout (logos/),
mais n'est PAS l'un des 13 livrables downstream du manifest. Classe
prose-facts-vs-numeric-drift : énumération free-text divergente de l'artefact (compte « 9 »
correct = 13−4, mais la liste en contenait 10).
Correctif. Retrait de logos, dans la parenthèse (§52) → 9 items alignés 1-pour-1 sur les
9 cle a_construire du registre. Aucun autre logos à corriger : les 2 occurrences restantes
sont légitimes (prose « ce que le worker ne fait pas · Brand Books / logos » + storage_layout
logos/), pas des libellés de livrable downstream. Zéro touche au générateur / à
pie_manifest.json — la prose s'aligne sur l'artefact (SSOT), jamais l'inverse.
Rebuild audit_4big. check_artifacts a viré RED après l'édit README : audit_4big score le
contenu DOC des modules (audit4big-rebuild-after-doc-edits), donc quality_report.json
dérivait sur le seul champ evidence du module pie (README.md 4022→4015 octets, les 7 octets
de logos, retirés). Régénéré en dernier via audit_4big_gen.py build → verdict PASS · 24/24
modules ≥ 95 inchangé, diff confiné à cette unique ligne (score pie inchangé).
Réalisé / gate-vert. 1 ligne prose éditée + quality_report.json re-généré byte-gaté.
./run_ci.sh en clôture = 32 PASS · 0 FAIL · 0 SKIP. Commit à suivre.
Session 120715 · Fix drift résiduel 22→24 · surfaces sœurs laissées par la réconciliation 100714 dans la prose des gate-docs (ci/)
Choix de tâche. ./run_ci.sh à l'ouverture = 32 PASS · 0 FAIL · 0 SKIP — propre.
Les 8 sprints de ROADMAP_8_WEEKS_OR_LESS.md sont livrés (24 modules gated), la matrice
de recette couvre bijectivement les 15 promesses (8 sprint-deliverables + 7 métriques MVP,
ancrées aux roadmap_line). Aucune tâche roadmap non-complétée ⇒ fallback mandat « auditer /
améliorer une doc » appliqué à un vrai trou de dérive, pas une retouche cosmétique.
Audits à blanc (0 dérive). (a) Sweep docstring-vs-CODE des 2 modules les plus neufs
(pie/manifest, crm/financement_bancaire) via sous-agent Explore → sorties/entrées/invariants/
comptes tous fidèles au code, propres (docstring-vs-code-drift saturé, confirmé). (b) Le
canal daily_reports/2026-08-03.md n'est PAS périmé : l'instantané 000623 (22 modules) était
exact à l'écriture — pie + financement_bancaire ont été ajoutés à 100714 — et l'addendum
100714 du même fichier réconcilie déjà 22→24 (24/24 · 624 tests · 15/15). Ne pas ré-écrire un
instantané historiquement exact.
Trou identifié — surfaces sœurs 22→24 non balayées. La réconciliation 100714 (commit
e24f2c9) a mis à jour les surfaces gatées (fiches QA/DevOps/ERPNext, README racine → tous
« 24 suites · 624 tests ») mais a laissé 6 mentions résiduelles dans la prose explicative des
gate-docs (ci/README.md + commentaires ci/check_readme_claims.sh — surfaces non gatées,
d'où silence). Classe prose-facts-vs-numeric-drift : claims free-text au présent divergeant
de l'artefact. Distinguées avec soin des voisins à conserver :
- Reproductions historiques (numéros d'époque, exacts) : « 20 modules listés sur 22 », « bijective 22/22 vs CI » (défaut réel reproduit quand il y avait 22 modules) → intactes.
- Hypothétiques pédagogiques : « ex. 21→22 modules », « 17→22 », les exemples de compensation
« 534/560/564 tests » (le
ci/README.mdréserve les placeholdersN/Maux valeurs vives et les entiers concrets aux exemples de dérive passée) → intacts. - Citations de n° de ligne : « README:22-23 » (pas un compte) → intactes.
Correctif (6 éditions chirurgicales, 2 fichiers).
- De-hardcode de l'invariant général (×2 ·
ci/README.mdL733 + commentaire miroircheck_readme_claims.shL3168) : « l'union des cellules Modules == les 22 modules de l'artefact » → « == l'ensemble des modules de l'artefact ». Cette clause décrit au présent ce que le gatedeploy_runbookexige NOW (artefact = 24 modules, union vérifiée) ; y figer un compte est une dérive-en-puissance qui vient justement de dériver. Phrasing agnostique = anti-récidive (ne re-dérivera plus à l'ajout d'un module). - Alignement des citations de contenu de fiche au présent (×4 · bloc « Fiche DevOps · COMPTE de
suites gated » de
check_readme_claims.sh) : « la cellule porte « 22 suites gated » », « l'agrégat QA « 22 suites gated · 564 tests » », « la MÊME valeur 22 vit à DEUX endroits », « sans capter la valeur 22 de la fiche QA » → 24 / 624. Ces commentaires citent le contenu courant des fiches DevOps/QA, lesquelles portent désormais « 24 suites · 624 tests » (vérifié :03_agents/{devops,qa}/AGENT.md). Sweep complet du bloc — aucune sœur22/564résiduelle.
Zéro artefact / générateur touché. ci/ n'est pas un module de 05_deliverables_mvp/ → non
scoré par audit_4big (audit4big-rebuild-after-doc-edits) ⇒ pas de rebuild quality_report.
Aucun gate ne dépend du texte de ces commentaires (le code recompute depuis reg["suites"] /
deploy_runbook.json). Vérifié : deploy_runbook.json = 24 modules (union, financement_bancaire
pie/manifestprésents) · fiches gatées = 24/624 ·quality_report= 24/24@100 ·regression_run= 24 suites · 624 tests.
Réalisé / gate-vert. 6 lignes de prose gate-doc éditées, prose only. ./run_ci.sh en clôture =
32 PASS · 0 FAIL · 0 SKIP. Commit à suivre.
Session 20260803_123715 · QA drift-hunt — docstring-vs-CODE (financement_bancaire)
État d'entrée. Tous les sprints livrés ; ./run_ci.sh = 32 PASS · 0 FAIL · 0 SKIP. Mode
maintenance/anti-dérive. La classe count-reconciliation 22→24 a été vérifiée propre à toutes
les surfaces au présent : les seuls hits 22 suites/564 tests résiduels vivent dans les
daily_reports/ (instantanés append-only historiquement exacts au moment d'écriture — le dernier
addendum de 2026-08-03.md porte bien 24 suites · 624), donc KEEP (cf. two-logging-channels,
prose-facts-vs-numeric-drift : historique ≠ dérive). Artefacts vivants confirmés :
regression_run.json = 24 suites / 624 ran · quality_report.json = 24 modules.
Cible retenue — classe ouverte/récurrente docstring-vs-code-drift. Audit read-only (agent
Explore) des docstrings de générateurs *_gen.py (inputs/fallbacks/outputs annoncés vs code réel),
focalisé sur les modules les plus neufs (pie/manifest, financement_bancaire, mobile).
Dérive confirmée (1). crm/financement_bancaire/financement_bancaire_gen.py — le CODE lit deux
contrats d'entrée : financement_spec.json et rbac/rbac_50_roles.json (via
RoleResolver.from_path() L84 → RBAC_CONTRACT_PATH ; l'invariant 4 L145 valide les rôles contre
RBAC). Or la docstring n'énumérait que financement_spec.json en input (L7) et se contentait de
« du contrat RBAC » sans nommer le fichier. Convention des pairs vérifiée : tous les
générateurs consommant RBAC citent explicitement le fichier — commissions L8
(le contrat RBAC (rbac_50_roles.json)), workflow_vente L11-12, mobile/app_config L9.
financement_bancaire était le seul outlier. Le README du module (L71) nommait déjà correctement
rbac_50_roles.json → surface sœur non dérivée (la docstring était l'unique surface fautive).
Correctif (1 édition chirurgicale, docstring only). L22-23 : « du contrat RBAC » →
« du contrat RBAC (rbac_50_roles.json, résolu par RoleResolver.from_path, invariant 4) ». Numéro
d'invariant vérifié exact (L145). Aligne la docstring sur la convention des pairs et sur le README
du module. Zéro artefact / générateur logique touché — ci/ non concerné, aucun gate ne pin le
texte de cette docstring.
Autres modules audités = propres : pie/manifest (inputs/outputs cohérents), mobile/app_config
(4 inputs + 5 outputs documentés fidèlement), reste des générateurs échantillonnés sans dérive
input/output/fallback.
Réalisé / gate-vert. 1 ligne docstring alignée. ./run_ci.sh en clôture = 32 PASS · 0 FAIL ·
0 SKIP. Commit 2e4ff2d.
Session 20260803_130717 · QA drift-hunt — docstring-vs-CODE (balayage des générateurs restants) · CLEAN
État d'entrée. Tous sprints livrés ; ./run_ci.sh = 32 PASS · 0 FAIL · 0 SKIP. Mode
maintenance/anti-dérive. Poursuite de la classe ouverte/récurrente docstring-vs-code-drift : la
session 123715 avait audité pie/manifest + financement_bancaire + mobile ; sessions antérieures
commissions + workflow_vente. Cette session balaie les 12 générateurs restants non encore couverts.
Audit (agent Explore, read-only). Comparaison docstring module-level (inputs/fallbacks/outputs
annoncés) vs code réel (open/Path/read_text/json.load/from_path/PATH-constants ; write_text/json.dump)
pour : faisabilite/generator, fiscal/ecf_dgii, seo, frontend/portails/workspaces,
crm/dossier_vente, legal/confotur, qa/{acceptance,audit_5d,regression},
rbac/{fixtures_gen,roleprofile_gen,userperm_gen}.
Verdict : CLEAN. Deux candidats remontés par l'agent, tous deux faux positifs après vérification manuelle :
ecf_dgii_gen.py« ometecf_spec.jsonde ses inputs ». Non-dérive — convention des pairs. La docstring (L5-9) énumère les 3 contrats de cross-cohérence EXTERNES (workflow_vente_spec.jsonL7,dossier_vente/doctype_spec.jsonL8,rbac_50_roles.jsonL9), pas le spec PROPRE du module. Le jumeau structurel exactcommissions_gen.pyfait à l'identique : il lit son proprebareme_spec.json(L48,_SPEC_PATH) mais sa docstring (L5-8) n'énumère que les 3 mêmes contrats externes, jamais son spec. Ajouterecf_spec.jsonà ecf créerait une asymétrie avec commissions. Par ailleurs la docstring ecf acknowledge déjà son spec comme 4ᵉ contrat : L110 « 12 invariants de cross-coherence (les 4 contrats) » + L24-25 « e-CF↔workflow↔DocType↔RBAC » (4 = e-CF-spec + les 3 externes). Cohérent.confotur_application_gen.py« lit rbac via helperrbac_scan.load_contract()». Non-dérive. La docstring (L8) nomme correctement le fichier-sourcerbac_50_roles.json— que le CODE le lise directement ou via un helper de scan, le fichier nommé est la source. Docstring exacte.
Ledger ecf # 1 · absent = by-design, gaté. Le ledger de _validate porte des marqueurs # 2 ·
… # 12 · (avec split # 12a/# 12b) mais aucun # 1 ·. Ce n'est pas une lacune : le gate
ci/check_readme_claims.sh (bloc « Fiscal · e-CF DGII », L1885-1960) documente et exige cette
convention — L1906-1907 « l'invariant 1 est la validation de SCHÉMA (validate(bundle, schema)), non
marquée # 1 · ; les marqueurs couvrent 2..N » ; le gate calcule ecf_led = sorted(_top | {1}) et
vérifie la contiguïté 1..12. Le README (« ## Les 12 invariants », item 1 = « Conformité au schéma »)
confirme l'énumération 1..12 avec schéma = #1. Ne PAS ajouter de # 1 · (contredirait l'intention
de design gatée). Compte « 12 » aligné à SEPT surfaces (4 chaînes .py + 3 README), toutes gatées.
Portée de la classe. Avec ce balayage, l'ensemble des générateurs *_gen.py du dépôt est
désormais vérifié pour la classe docstring-vs-CODE (12 ici + 5 des sessions antérieures). La classe
reste ouverte (docstring-vs-code-drift) pour tout code NEUF, mais le parc existant est propre.
Réalisé. Zéro fichier de production modifié (aucune dérive réelle). Audit + vérification
manuelle des 2 faux positifs + inspection du gate ecf. ./run_ci.sh = 32 PASS · 0 FAIL · 0 SKIP
(inchangé). Session de vérification → commit log-only (rythme établi, cf. f0827a7).
Session 20260803_133718 · QA drift-hunt — inventaire d'assets vs réalité filesystem (classe NEUVE) · 1 fix
État d'entrée. Tous sprints livrés ; ./run_ci.sh = 32 PASS · 0 FAIL · 0 SKIP. Artefacts vivants
concordants (regression_run.json = 24 suites / 624 ; quality_report.json = 24 modules). La classe
docstring-vs-code-drift a été balayée exhaustivement (parc *_gen.py propre, sessions 123715/130717).
Cette session ouvre une surface plus fraîche, jamais auditée : les documents prose racine
(README, PORTAIL_*, DIRECTIVE_*, AGENTS_EXISTING_ASSETS.md, AUTORISATIONS_*) — leurs claims
factuels présent-de-l'indicatif vs état réel du repo / filesystem.
Méthode. Agent Explore read-only (extraction des claims présent-tense) + vérification manuelle
filesystem de chaque candidat (jamais confiance aveugle à l'agent). Distinctions appliquées
(cf. prose-facts-vs-numeric-drift, mobile-runtime-actual-vs-rebuild-target) : snapshots
historiques append-only ≠ dérive · cibles roadmap ≠ runtime actuel · claims sur API VPS live
non-réfutables par simple absence de source.
Candidats agent écartés (faux positifs après vérif manuelle) :
- README.md, CLAUDE.md,
AUTORISATIONS_*, la plupart desDIRECTIVE_*= propres (24/24, 624, 13 agents, constantes CLAUDE.md tous vérifiés exacts). AGENTS_EXISTING_ASSETS.mdL18-19 « (compilé pyc) » = exact : les.pysources sont absents mais/opt/oto/__pycache__/oto_agent_faisabilite.cpython-310.pyc(+ orchestrateur) existent. L'agent avait raté le__pycache__. Annotation fidèle.DIRECTIVE_RENDUS_EXISTANTSL36 « Rendus totaux par projet » = NON touché. Directive écrite par Michel décrivant ledata_roomexterne ; le recompte de l'agent (60_photos_site/top-level) ≠ la méthodo du doc (agrège plusieurs sous-dossiers +static/renders+portal/img). Réécrire les chiffres de Michel sur une base de comptage ambiguë = invention → exclu (garde-fou « ne pas écraser un doc-source sur base incertaine »).PORTAIL_BANCABLESL12 « 3.4 MB » vs 3.3M réel = arrondi cosmétique, hors périmètre (fichier VPS externe) → non touché.
Dérive RÉELLE confirmée & corrigée (classe neuve : inventaire-vs-filesystem). La convention
propre du doc (L18-19, L68 annotent « (compilé pyc) » les assets dont seul le .pyc subsiste) était
appliquée de façon incohérente : classification filesystem exhaustive des 22 chemins .py du doc →
5 entrées pyc-only NON annotées (source absente au chemin exact indiqué, seul le .pyc présent) :
L20 oto_module_etudes_faisabilite_real, L21 oto_module_execution_faisabilite,
L22 oto_module_faisabilites_pages, L23 oto_module_faisabilites_viewer, L59 oto_module_mobile_api.
Correctif : ajout de « (compilé pyc) » sur ces 5 lignes — alignement sur la convention propre du
doc + la réalité filesystem vérifiée (strictement analogue au fix financement_bancaire/2e4ff2d
qui alignait une docstring sur la convention de ses pairs). Zéro invention. Assets .py avec source
réelle (aec.py, knowledge.py, prompt_engine.py, otoia_batch_projets.py, gen_renders_flux.py,
mobile_download.py, seed_mobile_rbac.py, confotur_application.py, bim_compras.py, ifc_to_glb.py,
worker_tasks_queue.py, executive_hero_flux.py) = laissés sans annotation (correct).
⚠️ Deux items SURFACÉS à Michel (NON édités — contredisent une source d'autorité / non-réfutables) :
otoia/capabilities/chat.py(L102) est ABSENT au chemin indiqué (ni.pyni.pyc), alors que CLAUDE.md le liste comme capability OTOIA canonique (« aec.py + knowledge.py + prompt_engine.py- chat.py »). Incohérence doc-inventaire ↔ constitution → je ne réécris pas l'inventaire pour contredire CLAUDE.md ; à trancher par Michel (chat.py à recréer, ou capability à retirer de la liste canonique ?). Note : le footer L128 du même doc omet déjà chat.py (« aec + knowledge + prompt_engine » seulement) — inventaire déjà auto-incohérent sur ce point.
config/projets_editor.py(L127) « (API GET/POST déjà en place)» — source absente au chemin, mais le claim porte sur une API VPS live, non réfutable par la seule absence de source in-/opt/oto(peut tourner déployée ailleurs) → non touché, signalé pour confirmation.
Gate. AGENTS_EXISTING_ASSETS.md est référencé par ci/check_readme_claims.sh uniquement pour
l'endpoint RunPod (§1) et des titres — aucune annotation (compilé pyc) n'est pinnée. ./run_ci.sh
en clôture = 32 PASS · 0 FAIL · 0 SKIP (inchangé).
Réalisé. 1 fichier prose (5 lignes annotées, convention + réalité). 2 items surfacés à Michel. Classe inventaire-vs-filesystem = nouvelle, distincte de docstring-vs-CODE et README-counts ; reste ouverte pour les claims filesystem des docs racine.
Session 20260803_140718 · Sprint 8 QA · inventaire-vs-filesystem étendu aux assets non-.py d'AGENTS_EXISTING_ASSETS.md — CLEAN (aucune édition) + signal chat.py enrichi
État d'entrée. ./run_ci.sh = 32 PASS · 0 FAIL · 0 SKIP, arbre git status propre.
Roadmap 1→8 intégralement livrée + gatée. Recherche de la prochaine tâche prioritaire
non-complétée in-périmètre : (a) recherche de tâche fonctionnelle (Michel · « commits
fonctionnels ») → grep TODO/FIXME/stub/NotImplemented sur les 12 générateurs +
05_deliverables_mvp/*.py = 0 stub réel (tous les hits « placeholder » sont le vocabulaire
anti-invention légitime — sentinelles {{…}}/USER_PLACEHOLDER, pas du code inachevé) ;
les 12 modules ont leur *_gen.py. Zéro tâche fonctionnelle in-scope ne reste (constat partagé
par les sessions antérieures ; le reste vise le runtime VPS hors périmètre #8). → bascule sur la
seule surface de dérive encore fraîche : la classe inventory-vs-filesystem-drift ouverte
par 133718, qui n'avait classifié que les 22 chemins .py du doc.
Surface neuve auditée (jamais couverte). Les claims d'assets NON-.py locaux
d'AGENTS_EXISTING_ASSETS.md (.md/.json/.sh/.js/.safetensors/.pristine) — 12 chemins
sous /opt/oto, vérifiés un par un au filesystem réel (jamais confiance aveugle) :
- 11 = SRC présents (source réelle au chemin exact) → aucune annotation
(compilé pyc)due (ces formats ne compilent pas en pyc) :faisabilite_4_volets_standard.md,flux1-dev-fp8.safetensors,mission_seo_indexation.md,task_seo_indexation_20260727.json,seo_indexation_20260727_INITIAL.md,deploy_mobile_rbac.sh,seed_mobile_rbac.py,static/oto_mobile.js,oto_module_confotur_application.py(+.pristine),config/projets_config.json. - 1 = MISS :
config/projets_editor.py— déjà surfacé à Michel par133718(item 2 : claim d'API VPS live, non-réfutable par la seule absence de source in-/opt/oto) → non touché.
Résultat : 0 dérive, 0 édition. La classe inventory-vs-filesystem-drift est désormais
close pour les assets LOCAUX (22 .py traités par 133718 + 11 non-.py vérifiés SRC ici) ;
elle ne reste ouverte que sur les claims VPS-externes / non-réfutables (API projets_editor,
tailles de fichiers data-room). Re-scanner les assets locaux serait désormais redondant (#5).
Signal chat.py ENRICHI à Michel (item 1 de 133718, non tranché). Re-confirmé :
otoia/capabilities/chat.py absent (ni .py ni .pyc) alors que CLAUDE.md le liste comme
capability OTOIA canonique. Nuance neuve : un __pycache__/oto_module_chatbot_lead.cpython-310.pyc
existe — mais c'est un module chatbot-lead distinct, PAS la capability capabilities/chat.py.
Donne à Michel le contexte pour trancher (recréer chat.py, ou pointer la capability vers le module
lead existant, ou retirer de la liste canonique). Toujours non édité — décision → Michel (ne pas
réécrire l'inventaire contre la constitution CLAUDE.md).
Sûreté. Session audit + log pur : AGENTS_EXISTING_ASSETS.md non modifié (0 dérive
locale trouvée). Aucun artefact out/ touché, aucun claim gaté, aucune logique de prod/gate.
./run_ci.sh en clôture = 32 PASS · 0 FAIL · 0 SKIP (inchangé). Zéro nouveau module · zéro
gate ajouté (#5). Aucune commande touchant au VPS (#8) · aucun git clean .