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

342 lines
27 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Activity Log · 2026-08-05 · Claude Code DTP Worker
## Session 031134 · Attestation launch-readiness des DENTS du gate — mutation-test des **8 gates statiques** (chacun doit sortir NONZERO sur sa dérive) → **8 BITES · 0 TOOTHLESS** · arbre byte-pristine · 0 édition de production
**Contexte + choix de tâche.** `./run_ci.sh` au démarrage : **33 PASS · 0 FAIL · 0 SKIP**,
arbre propre, roadmap `ROADMAP_8_WEEKS_OR_LESS.md` intégralement livrée/gatée (8 sprints · 7
critères ✅). Les ~15 dernières sessions ont saturé les axes d'audit *contenu* : cross-artefact,
dérive free-text (docstring↔code, inventaire↔fs), attestation des 4 chiffres stakeholder, des 18
citations `file:line` du registre. **Axe distinct et non couvert en suite depuis le 2026-08-02** :
prouver que les gates ont encore des **DENTS**. `run_ci` prouve qu'ils **PASSENT** sur arbre
propre — il ne prouve **jamais** qu'ils **ÉCHOUENT** sur une vraie dérive. Un gate devenu édenté
(toujours vert) est **pire** qu'absent : un faux vert de launch-readiness. La mémoire
[[guard-constraints-flags-usage-not-mention]] notait la dernière suite-mutation-test à **7/7
ROUGE le 2026-08-02** — or depuis : **+1 gate** (8ᵉ `check-mobile-workflow`, `001109`) et **~3
jours d'éditions**. Aucune session n'a re-prouvé la suite **entière** à 8. Valeur honnête du jour :
**Sprint 8 « regression tests exhaustifs »** — attester les dents des 8, corriger tout édentement.
**Méthode (discipline [[verify-uncovered-before-gating]] appliquée à l'inverse — prouver que la
protection MORD).** Harnais unique hors dépôt (`/tmp`, jamais commité), par gate :
`backup→mutation ciblée→run gate→assert exit≠0→restore byte-exact`, avec trap `EXIT` restaurant
**tout** même en cas d'échec. Une mutation = l'exacte classe de bug que le gate est censé
opposer au merge (aucune liste en dur — chaque cible re-vérifiée sur l'arbre courant AVANT) :
| # | Gate | Mutation injectée | Verdict |
|---|---|---|---|
| 1 | `guard_constraints` | usage chemin interdit `/var/www/html/static/…` (écriture · #4) | **BITES** exit=1 |
| 2 | `validate_json` | JSON malformé (`GARBAGE_NOT_JSON` appendé à un `out/*.json`) | **BITES** exit=1 |
| 3 | `check_docs` | lien Markdown interne cassé (`./inexistant-xyz-123.md`) | **BITES** exit=1 |
| 4 | `check_artifacts` | `out/MANIFEST.json` commité ≠ build frais (1 octet) | **BITES** exit=1 |
| 5 | `check_regression` | `regression_run.json` `passed:25→24` vs run frais | **BITES** exit=1 |
| 6 | `check_ci_integrity` | 1 job (`pie-manifest-tests`) retiré de `gate.needs` | **BITES** exit=1 |
| 7 | `check_readme_claims` | compte d'agents dérivé `13→12` dans README | **BITES** exit=1 |
| 8 | `check_mobile_workflow` | `secrets.` réintroduit dans un `if:` de job (SKIP silencieux) | **BITES** exit=1 |
**Résultat : 8 BITES · 0 TOOTHLESS.** Chaque gate statique oppose encore au merge la classe de
dérive qu'il déclare protéger — **aucun édenté** malgré 3 jours d'éditions. La mutation #8 est
précisément l'anti-pattern `234104` (contexte `secrets` indisponible en `jobs.<id>.if` → build
SKIP silencieux le jour où Michel fournit `EAS_TOKEN`) : opposabilité au merge **confirmée**.
**Discipline.** Attestation **read-only par conception** (harnais en `/tmp`, mutations restaurées
`cp` depuis backup · **jamais `git clean`/`git checkout`** — cf. interdit CLAUDE.md · [[ci-gate-verification-method]]). <!-- ci-allow : mention de l'interdit, jamais exécuté -->
**0 gate ajouté** (#5 — on ne teste pas, on *prouve les tests existants*) · **0 chiffre inventé**
(#6) · **0 édition de production** (seul ce journal change). Distinct des attestations
`234104`/`004112` (contenu) : axe **dents des gates**, jamais couvert en suite complète à 8.
**Vérifications.** `git status --porcelain` **vide** (arbre byte-pristine post-harnais) · `diff`
backup↔restauré pour les 8 fichiers touchés = identiques · `./run_ci.sh` → **33 PASS · 0 FAIL · 0
SKIP** (inchangé). Aucune commande VPS (#8) · aucun `git clean`. <!-- ci-allow : mention de l'interdit, jamais exécuté -->
## Session 024134 · Attestation launch-readiness du `OPEN_DECISIONS_REGISTER` (18 citations `file:line` + 2 numériques d'en-tête re-prouvées) → 1 FIX de dérive latente : dé-figeage des 2 compteurs mobiles gelés dans le doc · 0 gate ajouté · 0 édition d'autorité
**Contexte + choix de tâche.** `./run_ci.sh` au démarrage : **33 PASS · 0 FAIL · 0 SKIP**, arbre
propre, roadmap intégralement livrée/gatée. Le `OPEN_DECISIONS_REGISTER.md` a été **promu
découvrable hier** (session `021124`) mais son contenu — **18 citations `file:line` vers des
sources d'autorité** (`CLAUDE.md`, directives datées, `pie_spec.json`, `gate.py`, journaux) —
n'avait **jamais été re-vérifié indépendamment** contre les numéros de ligne courants. Un
punch-list *launch-readiness* dont les ancres pointent à côté est trompeur. **Valeur honnête
distincte** : attester chaque citation, et corriger toute dérive réelle du doc lui-même (le
registre est **notre** doc worker, pas une source d'autorité — l'éditer pour l'exactitude est
un travail worker légitime, distinct de *SURFACE-don't-rewrite* qui protège les autorités).
**Attestation (read-only d'abord).** Les **18** citations re-prouvées exactes au numéro de ligne :
- D-01 (PIE) : `pie_spec.json:24` (`contrats``legal/confotur`) · siblings `null` `:22,27,28,29,30` ·
`out/MANIFEST.json:24` · `README.md:48` · `out/pie_manifest.json:165-166` · `legal/confotur/README.md:8-17`. **Toutes exactes.**
- D-02 (financement) : `DIRECTIVE_FINANCEMENT…:206-210` + `:275-279` (couche `## PRÉCISION` audit-IA) ·
`finlib/gate.py:142-145` (`_cond_validation_wag` teste encore `wag_validated_by`) · `financement_spec.json:157`. **Toutes exactes.**
- D-03/D-04 (inventaire) : `AGENTS_EXISTING_ASSETS.md:102/127/128` · `CLAUDE.md:28` · `activity_log/2026-08-03.md:1245-1250`/`:1251-1253` · filesystem (`chat.py`, `projets_editor.py` absents). **Toutes exactes.**
- D-05 (mobile) : `mobile_spec.json` (`a_confirmer`) · `out/app_config.json` (`bundleIdentifier`/`package` `null`) · `DIRECTIVE_MOBILE_STORES:15-16` (`com.otov7.app`). **Toutes exactes.**
**FIX — dérive latente réelle (en-tête, ligne 9).** Le `> **Portée**` gelait **deux compteurs
activement mobiles** : `33/33 gates` et `24 modules 4Big 100/100`.
- `33` : le compte de `gate.needs` est passé **32→33 il y a 2 jours** (`b7ffb64`) ; le README
**refuse délibérément** de le figer (« `gate.needs` dérivé de ci.yml, *sans liste en dur* »,
`README.md:28`). Le registre était le **seul** doc à le geler → à contre-courant de la discipline projet.
- `24` : historique `21→22→24` (commentaires de `check_readme_claims.sh`) ; ce chiffre est **déjà
gaté** (recomputé depuis `quality_report.json` totals pour le README + `audit_4big/README.md`).
Le registre en était une **3ᵉ copie ungated** → dérive silencieuse au prochain module ajouté.
- **Correction** (dé-figeage, pas gate #5) : reformulé en qualitatif — « tous les jobs de
`gate.needs` passent · tous les modules 4Big au seuil `100/100`, verdict `PASS` » + **pointeur**
vers les sources dérivées-et-gatées (`README ## État courant` + `quality_report.json`). Aligne le
registre sur la philosophie *no-hardcoded-count* du README ; discipline single-source, **pas** un gate redondant.
**Discipline.** Attestation confirmée AVANT tout edit (33/33 gates · 24 modules `100/100`/`PASS`
re-dérivés : `gate.needs`→33 · `quality_report.json` totals→`{modules:24, pass:24, min/max:100,
verdict:PASS}`). **0 édition d'autorité** (`CLAUDE.md`, directive, `pie_spec.json`, `gate.py`
intouchés) · **0 gate ajouté** (#5) · **0 chiffre inventé** (#6, on **retire** deux chiffres, on
n'en ajoute aucun) · **1 seule ligne** du registre modifiée. Items D-01..D-05 **inchangés** (la
provenance « consolidation » reste `014119` — ce reword ne touche aucun item).
**Vérifications.** `grep` compteurs `N/N`/`N modules` résiduels dans le registre → **aucun (clean)**.
`./run_ci.sh`**33 PASS · 0 FAIL · 0 SKIP**. Aucune commande VPS (#8) · aucun `git clean`. <!-- ci-allow : mention de l'interdit, jamais exécuté -->
## Session 021124 · `OPEN_DECISIONS_REGISTER` rendu découvrable — indexé dans la Navigation README + pointeur « État courant » (le punch-list launch-readiness n'était référencé nulle part) → 2 éditions README, 0 édition d'autorité
**Contexte + choix de tâche.** `./run_ci.sh` au démarrage : **33 PASS · 0 FAIL · 0 SKIP**,
arbre propre, roadmap intégralement livrée/gatée. La session `014119` (juste avant) a créé
`05_deliverables_mvp/OPEN_DECISIONS_REGISTER.md` — une punch-list *launch-readiness* consolidée
« pour que Michel la trouve ». **Mais elle ne la référençait de nulle part** : `grep -rl
OPEN_DECISIONS_REGISTER --include=*.md` ne renvoyait **que** la ligne du journal `014119`.
Le README `## Navigation` indexe pourtant son sibling `GAP_ANALYSIS_SPRINT1.md` ligne 24. Un
punch-list que personne ne peut atteindre est de valeur nulle : **fermer cette boucle de
découvrabilité** est la valeur honnête distincte du jour (ni gate redondant #5, ni
re-surfaçage — le registre consolide déjà).
**Vérification AVANT promotion** (anti-invention #6 · on ne met pas en avant un doc non re-vérifié).
Re-prouvé indépendamment les claims-clés du registre au filesystem/source :
- D-01 : `pie_spec.json:24` attribue bien `contrats` (Promesa · Fideicomiso · HOA) à
`legal/confotur` — RÉEL.
- D-03 : `CLAUDE.md:28` liste `chat.py` ; `/opt/oto/otoia/capabilities/chat.py` **absent** — RÉEL.
- D-04 : `AGENTS_EXISTING_ASSETS.md:127` « projets_editor.py API en place » ; **aucun**
`projets_editor.py` sous `/opt/oto/config` — RÉEL (claim runtime VPS non réfutable, #8).
Registre jugé fidèle → promotion légitime.
**Éditions (2, README seul).**
1. `## Navigation` — nouvelle ligne juste après `GAP_ANALYSIS_SPRINT1.md`, pointant le registre
(description : punch-list décisions produit ouvertes qui appartiennent à Michel · sourcée,
ne tranche pas).
2. `## État courant (sourcé)` — bullet « Décisions produit ouvertes » : *CI verte ≠ zéro décision
en attente* → pointe le registre. **Sans compte chiffré en dur** (le nombre d'items dériverait ·
#6) : pointeur qualitatif uniquement.
**Discipline.** *SURFACE, don't rewrite* : **0 édition** de `CLAUDE.md`, d'une directive datée,
d'un `pie_spec.json`/`gate.py`, ni du registre lui-même. Aucun gate ajouté (#5). Les 2 lignes
README sont de la prose de navigation (pas de claim numérique gaté).
**Vérifications.** `ci/check_readme_claims.sh`**vert** (chiffres README inchangés, fidèles).
`ci/check_docs.sh`**vert** (nouveaux liens internes valides). `./run_ci.sh` → **33 PASS · 0
FAIL · 0 SKIP**. **0 chiffre inventé (#6) · 3 claims re-prouvés avant promotion · 0 édition
d'autorité · aucune commande VPS (#8) · aucun `git clean`.** <!-- ci-allow : mention de l'interdit, jamais exécuté -->
## Session 014119 · Registre des décisions ouvertes — consolidation sourcée des arbitrages produit surfacés au fil de l'eau (Sprint 8 launch-readiness) → 1 livrable-doc neuf · 0 édition d'autorité
**Contexte + choix de tâche.** `./run_ci.sh` au démarrage : **33 PASS · 0 FAIL · 0 SKIP**,
arbre propre. Roadmap intégralement livrée/gatée. Les **6 dernières sessions** (`200738`
08-03 → `011114` 08-05) ont saturé l'audit read-only (inter-artefacts, dérive free-text,
attestation stakeholder, 8ᵉ gate mobile). Reproduire une 7ᵉ passe read-only aurait été à
faible valeur / redondant (#5). **Valeur honnête distincte du jour** : les items *réellement
ouverts* (arbitrages de périmètre produit + dépendances runtime hors dépôt) sont **éparpillés**
dans les journaux de session et n'existaient **nulle part de façon consolidée et découvrable**
pour Michel — un vrai trou de *launch-readiness* Sprint 8. J'ai créé
`05_deliverables_mvp/OPEN_DECISIONS_REGISTER.md` : une punch-list unique, **100 % sourcée**,
qui **regroupe** (ne tranche pas, ne réécrit aucune source d'autorité).
**Vérification indépendante de CHAQUE signal AVANT consolidation** (anti-invention #6 · deux
Explore parallèles + spot-check manuel). Aucun item repris de mémoire sans re-preuve :
- **D-01 PIE `contrats``legal/confotur`** : REAL. `pie/manifest/pie_spec.json:24` attribue
`contrats` (Promesa · Fideicomiso · HOA) à `legal/confotur` ; or ce module ne produit **que**
le DocType demande CONFOTUR (`legal/confotur/README.md:8-17`). Incohérence interne confirmée :
tous les autres downstreams sans générateur portent `"module": null` (`pie_spec.json:22,27-30`),
`contrats` est le seul attribué à un module qui ne le génère pas. Arbitrage de périmètre.
- **D-02 Financement condition #4 WAG→audit IA** : REAL. Directive `## PRÉCISION`
(`DIRECTIVE_FINANCEMENT_..._20260803.md:275-279`) supersede `wag_validated_by` par
`audit.decision=='APPROVED'` signé ; le module ship encore l'ancienne couche
(`finlib/gate.py:142-145` + `financement_spec.json:157`). Dépend d'un agent auditeur hors dépôt.
- **D-03 `chat.py` absent** / **D-04 `projets_editor.py` absent** : REAL, filesystem confirmé
(ni `.py` ni `.pyc` sous `/opt/oto`), **déjà surfacés** session `20260803_133718`
(`2026-08-03.md:1245-1253`) → registre = **pointeur** anti-doublon (#5), pas re-surfaçage.
- **D-05 bundle id mobile** : soupçon INVALIDÉ → 🟢 VÉRIFIÉ-SANS-SUITE. Le renommage
OTOV7→« OTO Enterprise OS » ne touche pas le bundle : `bundleIdentifier`/`package` quarantinés
`null · a_confirmer`, découplés du nom d'app (`mobile_spec.json`, `out/app_config.json`).
Consigné pour ne pas ré-ouvrir. Faux-positif écarté (#6).
**Discipline.** *SURFACE, don't rewrite* respecté : **0 édition** de `CLAUDE.md`, d'une directive
datée, ou d'un `pie_spec.json`/`gate.py` (les toucher serait invention de périmètre ou réécriture
d'autorité). Le registre est un doc-pointeur volontairement non-gaté (chaque ligne cite sa source
file:line, contenu 100 % dérivé — faible surface de dérive), au même titre que `daily_reports`.
**Vérifications.** `./run_ci.sh`**33 PASS · 0 FAIL · 0 SKIP** (inchangé — aucun fichier gaté
touché). **0 chiffre inventé (#6) · 1 faux-positif écarté (bundle id) · 4 signaux re-prouvés
indépendamment avant consolidation · 0 édition d'autorité · aucune commande VPS (#8) · aucun
`git clean`.** <!-- ci-allow : mention de l'interdit, jamais exécuté -->
## Session 001109 · Nouveau gate `check-mobile-workflow` — la structure de `mobile-build.yml` devient opposable au merge (surface mutation-testée UNGATED, 1er contrôle) → 1 gate ajouté + câblé · 32→33 jobs
**Contexte + choix de tâche.** `./run_ci.sh` au démarrage : **32 PASS · 0 FAIL · 0
SKIP**, arbre propre. Roadmap `ROADMAP_8_WEEKS_OR_LESS.md` intégralement livrée/gatée
(8 sprints). Les 4 sessions du 08-04 (`221055`, `224101`, `231101`, `234104`) avaient
saturé les surfaces d'audit read-only (inter-artefacts, dérive non-gatée, attestation
stakeholder) puis **durci `mobile-build.yml`** (pattern preflight-output, portable
GitHub/Gitea). Cette dernière édition a laissé une **queue** : son propre log notait
« Aucun gate ne linte la structure de `mobile-build.yml` (`check-ci-integrity` ne
verrouille QUE `ci.yml`) ». Autrement dit le correctif de portabilité qu'elle venait
de poser **pouvait régresser en silence** — exactement la classe « marche dans ma
tête, casse le jour où on en a besoin » (mémoire [[mobile-build-secrets-if-gating]] :
« workflow HORS `gate.needs``run_ci` won't catch a regression »). La valeur honnête
du jour : **fermer cette queue** en rendant la structure de `mobile-build.yml`
opposable au merge. NON redondant (#5) : c'est le **premier** contrôle de ce fichier.
**Preuve d'absence de couverture AVANT d'ajouter le gate** (discipline
[[verify-uncovered-before-gating]]). Mutation : réintroduire l'exact anti-pattern
corrigé en `234104``secrets.EAS_TOKEN != ''` dans un `if:` au niveau job. Résultat :
**7/7 gates statiques restent VERTS**. Surface confirmée non gatée (ni
`check_ci_integrity` — scope `CI=ci.yml` — ni `validate_json` — scope `.json`). Fichier
byte-restauré aussitôt (`cp` depuis backup tmp · jamais `git clean`). <!-- ci-allow : mention de l'interdit, jamais exécuté -->
**Livrable : `ci/check_mobile_workflow.sh` (8ᵉ gate statique) + câblage.** Le gate lit
des **FAITS dans le fichier** (jamais une liste à la main · #6), 4 invariants :
- **MOB-1 · bien-formé** — existe · `name:`/`on:`/`jobs:` + 3 jobs (`preflight`,
`build-ios`, `build-android`) ; parse YAML strict **exigé si PyYAML dispo**, sinon
awk seul (runner sans pip → best-effort, jamais un faux vert : MOB-2/3/4 en sont
indépendants).
- **MOB-2 · portabilité** — **0** `secrets.` dans un `if:` de **job** (`^ if:`).
Le contexte `secrets` n'est pas exposé dans `jobs.<id>.if` (table d'availability
GitHub Actions) → sur `act`/Gitea il s'évaluerait vide → **SKIP silencieux**. C'est
la régression `234104` verrouillée.
- **MOB-3 · activation différée (#6/#8)** — chaque job de build (`run: eas build`) est
gaté sur `needs.preflight.outputs.has_token` → SKIP tant que le token absent, donc
le workflow ne rend jamais le CI rouge avant activation Michel.
- **MOB-4 · contrat d'outputs** — `preflight` déclare `has_token`/`has_repo`, chaque
`needs.preflight.outputs.<X>` référencé est **déclaré** (0 dangling) et chaque output
déclaré est **alimenté** par un `echo …>>$GITHUB_OUTPUT`.
**Bug corrigé pendant l'écriture (auto-vérification).** 1er jet : `preflight` était
classé « job de build » car un **commentaire** `# … eas build …` (l.108, entre deux
jobs) était attribué au job précédent par le parseur awk. Corrigé en exigeant
`run:[[:space:]]*eas build` (commande réelle, pas une mention). Après correctif : gate
**VERT** sur le fichier propre.
**Mutation-testing du gate lui-même (5 mutations · toutes ROUGES, fichier propre
re-VERT).** (1) YAML cassé (indent) · (2) `secrets.` en `if:` de job · (3) `if:` du
job `build-ios` supprimé · (4) output fantôme référencé (`has_tokenX`) · (5) output
`has_repo` non alimenté. Chaque mutation → `exit 1` ; `cp` backup → gate re-VERT.
**Câblage (garde `check-ci-integrity` INV-A/B vert).** Job `check-mobile-workflow`
ajouté à `ci.yml` (steps `bash ci/check_mobile_workflow.sh`) **et** à `gate.needs`.
`check_ci_integrity` reconnaît le nouveau `ci/*.sh` comme **câblé** (lancé par un job
du gate + il source `lib.sh`) → INV-A (gate.needs == tous jobs non-manuels) et INV-B
(tout `ci/*.sh` câblé) **restent verts**. `run_ci.sh` (dérivé de `gate.needs`, sans
liste en dur) l'inclut **automatiquement** → passage **32→33 jobs (8 gates statiques
+ 25 suites)**, zéro édition de `run_ci.sh` (#6, exactitude structurelle).
**Doc (traçabilité, pas de dérive).** `ci/README.md` : ligne §1 pour
`check-mobile-workflow`, sous-section §2 détaillée (4 invariants + les 5 mutations),
et nuance ajoutée à « Second workflow » (les **jobs** restent hors gate de merge, mais
la **structure du fichier** est désormais gatée). Convention [[ci-readme-table-detail-in-section2]]
respectée : ligne §1 courte, détail en §2. Les mentions historiques « 7 gates
re-verts » (§2, records de mutations passées) restent exactes en **passé** ; le nouveau
record dit **8ᵉ gate**.
**Vérifications.** `bash ci/check_mobile_workflow.sh` → VERT (4 invariants) ; 5
mutations → ROUGE ; `python3 yaml.safe_load` sur `ci.yml` → valide ; `check_ci_integrity`
→ VERT (câblage intègre) ; `./run_ci.sh`**33 PASS · 0 FAIL · 0 SKIP**. **1 gate
ajouté (NON redondant : 1re couverture d'un fichier mutation-testé ungated · pas un
doublon #5) · 1 job CI câblé · 0 nouveau module · 0 chiffre inventé (#6) · 0 édition
de production hors CI · aucune commande VPS (#8) · aucun `git clean`.** <!-- ci-allow : mention de l'interdit, jamais exécuté -->
---
## Session 004112 · Currency du canal stakeholder `daily_reports` au jalon 33 jobs + réattestation indépendante → CLEAN · 0 édition de production
**Contexte + choix de tâche.** `./run_ci.sh` au démarrage : **33 PASS · 0 FAIL · 0
SKIP**, arbre propre. Roadmap intégralement livrée+gatée. La session `001109` (même
jour, plus tôt) a fait franchir au gate de merge le cap **32 → 33 jobs** (8ᵉ gate
statique `check-mobile-workflow`). Or le canal roadmap-facing `daily_reports/` s'arrêtait
au `2026-08-04` en affichant encore « **32 PASS** ». Les surfaces de dérive read-only
étant saturées (re-scan = redondant #5), la valeur honnête du jour est de **rendre le
canal stakeholder fidèle au point courant** — discipline [[two-logging-channels]] :
garder les deux canaux, chaque figure sourcée d'un artefact commité.
**Vérification préalable — pas de dérive présent-tense « 32 » résiduelle.** Balayage des
surfaces present-tense (`README.md`, `ci/README.md`) : **aucun** décompte de jobs figé en
dur (le nombre est **dérivé à l'exécution** par `run_ci.sh --list`, jamais retranscrit).
Les nombreux « 32 » des logs/daily_reports antérieurs sont des **snapshots datés** (vrais
à l'époque) → classe *historical-repro = KEEP* ([[prose-facts-vs-numeric-drift]]), on n'y
touche pas. Le « 7 gates statiques » de `ci/README.md` l.49 décrit l'état **avant** l'ajout
du 8ᵉ gate (narratif du mutation-test préalable) → exact en passé, KEEP.
**Livrable : `05_deliverables_mvp/daily_reports/2026-08-05.md`.** Snapshot stakeholder
consignant le jalon 33 jobs (= **8 gates statiques + 25 suites**) + réattestation. Chaque
chiffre **recomputé `python3` indépendamment** des artefacts commités (aucune valeur saisie
à la main · #6), tous concordants avec la table :
- `quality_report.json` : **24/24 modules == 100** · `coverage.ok=true` · ci==registry==24 · verdict `PASS`.
- `regression_run.json.totals` : **24 suites · 624 ran · 624 passed · 0/0/0** · verdict `PASS`.
- `acceptance_matrix.json` : **15/15 `status=in_repo`** · verdict `True` · **`ci_job` ×36** (niché `matrix[].modules[]`).
- Structure CI : `run_ci.sh --list` = **33 jobs = 8 statiques + 25 suites** · `ls ci/*.sh` (hors `lib.sh`) = **8**.
**Vérifications.** `./run_ci.sh`**33 PASS · 0 FAIL · 0 SKIP** (inchangé — livrable
prose, hors `check_artifacts`/`audit_4big`). Liens Markdown du rapport résolus depuis
`daily_reports/` : `../qa/…` (artefacts), `../../run_ci.sh`, `../../.gitea/…`, `../../ci/…`
`check_docs` VERT. **0 chiffre inventé (#6) · 0 édition de production · aucune commande
VPS (#8) · aucun `git clean`.** <!-- ci-allow : mention de l'interdit, jamais exécuté -->
---
## Session 011114 · Double sweep read-only sur les DEUX classes de dérive free-text ungated (docstring↔code des 22 générateurs · inventaire↔filesystem) → CLEAN · 0 édition de production · faux « nouveau finding » écarté (anti-invention #6)
**Contexte + choix de tâche.** `./run_ci.sh` au démarrage : **33 PASS · 0 FAIL · 0
SKIP**, arbre propre. Roadmap `ROADMAP_8_WEEKS_OR_LESS.md` intégralement livrée+gatée
(8 sprints · 7 critères de succès ✅). Les deux sessions du jour ont déjà (a) ajouté le
8ᵉ gate statique `check-mobile-workflow` (`001109`, 32→33 jobs) et (b) mis le canal
stakeholder `daily_reports` au jalon 33 jobs avec réattestation des 4 chiffres (`004112`).
Les surfaces d'audit inter-artefacts / dérive gatée / attestation sont **saturées**
(re-scan = redondant #5). La valeur honnête restante : re-vérifier les **deux classes de
dérive free-text NON gatées** que la mémoire marque comme récurrentes/non-fermées, avant
d'envisager quoi que ce soit — discipline [[verify-uncovered-before-gating]] (prouver
l'état AVANT d'agir) + anti-invention #6.
**Sweep 1 — docstring↔code des 22 générateurs ([[docstring-vs-code-drift]], classe
RECURRING/not-closed).** Pour chacun des 22 `*_gen.py` de `05_deliverables_mvp/*` :
comparaison du **docstring/en-tête** (inputs annoncés · fichiers `out/` produits ·
fallbacks) au **code réel** (argparse · `open(...,"w")` / `json.dump` / `write_text` ·
branches de fallback). Résultat : **22/22 CLEAN** — chaque docstring décrit exactement les
sous-commandes, les inputs et les artefacts écrits. Spot-check manuel des deux générateurs
multi-sorties les plus risqués (au-delà de la lecture agent) :
- `demo/scenarios/demo_scenario_gen.py` — docstring l.20/l.32 annonce `run_sheet.json` +
`run_sheet.md` + `MANIFEST.json` → code écrit bien les 3 (l.197-199 JSON, l.203-204 `.md`). ✓
- `faisabilite/bancable/bancable_gen.py` — docstring `50_financier_bancable/{fr,en,es}.md`
→ écrits l.171-173. ✓
Aucune régression du type « fallback §5.3 fantôme » (publiciste) ni « output omis »
(demo run_sheet.md) qui avaient été corrigés antérieurement : la classe reste propre.
**Sweep 2 — inventaire `AGENTS_EXISTING_ASSETS.md` ↔ filesystem `/opt/oto`
([[inventory-vs-filesystem-drift]]).** Extraction de tous les chemins `/opt/oto/*` cités
(38 uniques), classification **SRC-OK / PYC-ONLY / MISS** (avec check `__pycache__`) :
- **8 PYC-ONLY** (`oto_agent_faisabilite`, `oto_orchestrateur_faisabilite`,
`oto_module_{etudes_faisabilite_real,execution_faisabilite,faisabilites_pages,faisabilites_viewer,mobile_api,plans_ifc}`)
**tous** déjà annotés « (compilé pyc) » dans le doc : convention interne **cohérente**,
0 dérive.
- **2 MISS** : `otoia/capabilities/chat.py` (absent vs CLAUDE.md §Architecture cible qui le
liste) et `config/projets_editor.py` (§13, « API GET/POST déjà en place » — sibling
`projets_config.json` présent, lui). **Vérification anti-invention #6 AVANT de flaguer :**
`grep -rn` interne → **les deux MISS sont DÉJÀ surfacés à Michel** par la session `133718`
du **2026-08-03** (log l.1245/1284/1289-1295 : claims VPS-externes / non-réfutables laissés
ouverts, chat.py ≠ le module chatbot-lead distinct). Donc **PAS un nouveau finding**
re-signaler serait redondant (#5). Le reste (containers Docker, Speckle, systemd, GSC) est
runtime, non réfutable depuis le dépôt → hors périmètre worker (#8). **SURFACE, don't
rewrite** respecté : 0 édition de l'inventaire (le fichier peut viser un runtime
container-side ; un « fix » unilatéral serait une invention).
**Conclusion honnête.** Les deux seules classes de dérive free-text ungated sont **stables
et propres** à ce jalon ; la dimension chiffres-README est densément gatée (`check_readme_claims`
= 27 claims / 16 modules + fiches). Rien à corriger, **aucun gate à ajouter** (ajouter serait
un doublon #5 ; par ailleurs un gate lisant `/opt/oto` serait non-portable — le runner Gitea
n'a pas ce filesystem, cf. [[ci-gate-verification-method]]). Session **read-only** volontaire,
dans la lignée des attestations `234104`/`004112`, mais sur un **axe distinct** (les 2 classes
free-text, pas les 4 chiffres stakeholder ni le cross-artefact).
**Vérifications.** `./run_ci.sh`**33 PASS · 0 FAIL · 0 SKIP** (inchangé — aucun fichier
gaté touché). **0 chiffre inventé (#6) · faux nouveau-finding écarté par grep interne · 0
édition de production · 0 gate ajouté (anti-redondance #5) · aucune commande VPS (#8) · aucun
`git clean`.** <!-- ci-allow : mention de l'interdit, jamais exécuté -->