Files
oto-enterprise-os-dtp/05_activity_log/2026-08-03.md
T

33 KiB
Raw Blame History

Activity Log · 2026-08-03 · Claude Code DTP Worker

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 + tags v* (paths mobile/** + le workflow) + workflow_dispatch (inputs platform all/ios/android, profile).
  • Jobs : preflight (TOUJOURS vert · prouve la présence de la config EAS versionnée mobile/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 variable vars.MOBILE_NATIVE_REPOjamais 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.sh30 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 storesRebuild 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.sh30 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.

  1. 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) ».
  2. 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.sh30 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 644non é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.sh30 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.md existe. Vérifié via acclib/deps.py:109-114 (artifact_exists joint DELIVERABLES_ROOT).
  • Surface doublement protégée · ZÉRO gate ajouté (#5). (a) acceptance_gen.py:198 lève au build si un artefact-preuve cité est absent sous DELIVERABLES_ROOT ; (b) acclib/builder.py:62 recalcule exists à 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ée otov7-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.yml0 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.sh30 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 « etet … » 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.md05_deliverables_mvp/*.md → hors du contrôle auto-score 4Big [SOFT].

Vérifications. ./run_ci.sh30 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.sh30 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.py l.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, dont store_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.jsonstore_listing.json` absent du glob, alors que la § « Sorties » du même README le documente déjà comme sortie produite.

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 » sur 05_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.sh30 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 033642Sprint 5 P1 · workflow CI/CD Mobile mobile-build.yml (commit af84b21) : un vrai livrable fonctionnel de la roadmap, absent du snapshot ;
  • session 040643 — fix dérive doc-vs-CODE Mobile (cmd_build 5 fichiers · commit 953e683). 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 : workflow mobile-build.yml (3 jobs preflight/build-ios/ build-android · gardes if secrets.EAS_TOKEN != '' && vars.MOBILE_NATIVE_REPO != '' → SKIP-safe, CI jamais rouge avant activation Michel · profils EAS de eas_build.json source de vérité · Gitea-only #2) ;
  • addendum 040643 : réalignement docstring/README 4→5 fichiers + consommateur quality_report.json ré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.sh30 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.sh30 PASS · 0 FAIL · 0 SKIP (dont check-docs liens OK · check-readme-claims vert). Aucune commande VPS (#8) · aucun git clean .