fbe298ffd0
Vérité-terrain : grep -c def test_negative_ = 10 (réparties Keywords/SchemaOrg/Hreflang/Manifest, PAS de classe dédiée) ; git show 0d3b242 = déjà 10 dès la création → jamais un état vrai antérieur (pas historical-repro). Piège confotur écarté : les 2 frères qui affichent un sous-compte négatif en prose sont EXACTS car adossés à une classe nommée countable (confotur « 8 négatifs » = classe TestNegative=8 ; devops « 14 injections négatives » = classe TestNegativeInjections=14) — SEO est le seul faux, ses négatifs ne forment pas de classe. Toute la classe « sous-compte négatif en prose » (seo/devops/confotur) auditée end-to-end.
Surfaces (balayage twin-fix) : seule seo/README.md:67 corrigée (présent-tense, doc vivante) ; les 2 autres occurrences du « 8 » sont dans daily_reports/2026-07-30-session18.md + 05_activity_log/2026-07-30.md = snapshots datés du 2026-07-30 → KEEP.
Effet de bord : audit_4big score le contenu README → quality_report.json régénéré EN DERNIER (seule ligne changée : evidence README.md 3900→3901 octets) · verdict PASS · 24/24 ≥95 (min 100) inchangé.
0 gate ajouté (#5 · erreur d'origine isolée, pas une dérive récurrente ; total déjà gaté ; précédent confotur = ne pas gater ces sous-comptes) · 0 édition d'autorité (le test file n'est pas modifié) · 0 chiffre inventé (#6) · 0 commande VPS (#8). run_ci.sh : 33 PASS
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
967 lines
79 KiB
Markdown
967 lines
79 KiB
Markdown
# Activity Log · 2026-08-05 · Claude Code DTP Worker
|
||
|
||
## Session 094211 · FIX RÉEL — le README module **SEO** annonçait « 36 tests (dont **8** injections négatives) » alors que la suite en compte **10** `test_negative_*` (faux depuis le commit d'origine `0d3b242`, jamais gaté) → corrigé **8→10** ; toute la classe « sous-compte négatif en prose » (seo/devops/confotur) auditée · 0 gate ajouté · 0 chiffre inventé
|
||
|
||
**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 (Sprint 8 · QA). Aucune tâche
|
||
fonctionnelle in-repo restante → chasse à la **dérive documentaire réelle non-gatée** (le mode de valeur
|
||
honnête de cette phase). Recherche fan-out (Explore, read-only) + vérification manuelle : **une** dérive
|
||
présent-tense confirmée, isolée.
|
||
|
||
**Finding (calcul de la vérité-terrain, pas un soupçon · [[prose-facts-vs-numeric-drift]]).**
|
||
`05_deliverables_mvp/seo/README.md:67` écrit `# 36 tests (dont 8 injections négatives)`. Le **total 36**
|
||
est exact ET **gaté** (`ci/check_readme_claims.sh:941` recompute `# (\d+) tests` vs le nombre réel de
|
||
`def test_`). Le **sous-compte « 8 »** n'est capté par **aucun** groupe de capture (le pattern ne prend que
|
||
le total) → **non gaté**. Vérité-terrain : `grep -c "def test_negative_" tests/test_seo.py` = **10** (10
|
||
méthodes réparties dans les classes `Keywords`/`SchemaOrg`/`Hreflang`/`Manifest`, pas de classe dédiée).
|
||
`git show 0d3b242:…/test_seo.py | grep -c def test_negative_` = **10** dès le commit d'origine → le « 8 »
|
||
est **faux depuis la création** (2026-07-30), jamais un état vrai antérieur (donc pas *historical-repro*).
|
||
|
||
**Écarter le piège confotur ([[confotur-8-negatifs-not-drift]]).** Les deux modules-frères qui affichent
|
||
un sous-compte négatif en prose sont **exacts** car adossés à une **classe nommée** (structurellement
|
||
countable) : confotur « 8 négatifs » = classe `TestNegative` (**8** méthodes) ✓ · devops « 14 injections
|
||
négatives » = classe `TestNegativeInjections` (**14** méthodes) ✓. **SEO est le seul faux** : ses négatifs
|
||
ne forment **pas** de classe (préfixe `test_negative_` dispersé), et aucune lecture ne donne 8 → **10** est
|
||
le compte honnête. Fix minimal : `8 → 10`.
|
||
|
||
**Surfaces (balayage twin-fix · [[prose-facts-vs-numeric-drift]]).** Le « 8 » apparaît 3× : (a)
|
||
`seo/README.md:67` = **présent-tense, doc canonique vivante → FIX** ; (b)
|
||
`daily_reports/2026-07-30-session18.md:48` et (c) `05_activity_log/2026-07-30.md:920` = **snapshots datés
|
||
du 2026-07-30 → KEEP** (convention : rapports/logs horodatés immuables, ne pas réécrire l'histoire,
|
||
[[two-logging-channels]]).
|
||
|
||
**Effet de bord attendu et rebuild ([[audit4big-rebuild-after-doc-edits.md]]).** `audit_4big` **score le
|
||
contenu README** ; l'édition a fait diverger l'artefact byte-gaté `qa/audit_4big/out/quality_report.json`
|
||
(`check-artifacts` RED). Rebuild `audit_4big_gen.py build` **en dernier** → seule ligne changée :
|
||
`"evidence": "README.md (3900 → 3901 octets)"` (« 8 »→« 10 » = +1 octet) · verdict **PASS · 24/24 ≥95
|
||
(min 100)** inchangé.
|
||
|
||
**Décision de NON-gatage (#5 · [[verify-uncovered-before-gating]]).** Erreur d'**origine isolée** (une
|
||
faute de frappe unique), **pas** une classe de dérive récurrente : les 2 frères sont exacts et le total est
|
||
déjà gaté. Gater le sous-compte seul exigerait, par cohérence, de gater aussi confotur/devops (classe
|
||
countable, changement rare) — 3 checks pour un événement à très basse fréquence. Conforme au précédent
|
||
[[confotur-8-negatifs-not-drift]] (« ne pas fixer/gater » ces sous-comptes). **Classe désormais auditée
|
||
end-to-end** (consigné pour un futur passage : les 3 sous-comptes négatifs sont vérifiés exacts au
|
||
2026-08-05).
|
||
|
||
**Bilan.** 2 fichiers touchés (`seo/README.md` prose + `quality_report.json` régénéré) · **0 édition
|
||
d'autorité** (le test file, source de vérité, n'est pas modifié) · **0 gate ajouté** (#5) · **0 chiffre
|
||
inventé** (#6 · 10 dérivé de `grep -c`) · **0 commande VPS** (#8) · **aucun `git clean`** <!-- ci-allow : mention de l'interdit, jamais exécuté -->
|
||
· `./run_ci.sh` final : **33 PASS · 0 FAIL · 0 SKIP**.
|
||
|
||
## Session 091204 · FIX de COUVERTURE doc — la fiche **Mobile** omettait son propre **livrable in-repo gaté** (`mobile/app_config`) : elle n'ancrait le rôle que sur RBAC + acceptance, jamais sur le générateur de config app (22 tests · job CI · CLI) → sous-section dédiée + ligne de table **auto-gatée** (3 gates) + 3 énumérations « ancrage in-repo » réconciliées · 0 édition d'autorité · 0 gate ajouté · 0 chiffre inventé
|
||
|
||
**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 (Sprint 8 · launch-readiness). Un Explore read-only sur la
|
||
classe *docstring-vs-code drift* (récurrente, cf. [[docstring-vs-code-drift]]) n'a **rien remonté de
|
||
concret** (le « 14 invariants » de `chat_otoia` est correct : les invariants 8 et 9 sont assertés à la
|
||
fois globalement ET par-mount → 14 numéros distincts, pas une dérive). Classe saturée. Pivot vers la
|
||
**complétude des fiches** — la classe qui a produit le FIX réel de la session 071201 (CRM omettait son
|
||
4e module `financement_bancaire`) : *completeness ≠ accuracy* ([[fiche-accuracy-audit-closed]]).
|
||
|
||
**Le finding — diff `05_deliverables_mvp/*/` vs les 13 fiches.** Un `grep -rl <module> 03_agents/*/AGENT.md`
|
||
sur les 22 modules livrés a remonté **un seul orphelin** : `mobile/app_config` → référencé par **AUCUNE**
|
||
fiche (les 21 autres sont couverts ≥1×). Or `05_deliverables_mvp/mobile/app_config/` est un module
|
||
générateur **réel, commité et gaté** : 5 fichiers `out/*.json` (`app_config.json`/`eas_build.json`/
|
||
`role_navigation.json`/`store_listing.json`/`MANIFEST.json`), suite `mobile-app-config-tests` **dans
|
||
`gate.needs`**, CLI `build|validate`, 22 méthodes de test (`regression_plan.suites[mobile/app_config].
|
||
test_methods`). C'est le **livrable in-repo propre de l'agent Mobile** (docstring : « Livrable Mobile de
|
||
la roadmap Sprint 5 »). La fiche `03_agents/mobile/AGENT.md` ne le mentionnait **nulle part** — elle
|
||
énumérait ses ancrages in-repo comme *uniquement* le **rôle RBAC** + la **row QA acceptance S5**
|
||
(« ancré dans **deux** artefacts in-repo vérifiables »), en omettant son générateur le plus direct.
|
||
Ce n'était pas une inexactitude (les 2 ancres RBAC/QA sont justes) mais une **incomplétude** : le
|
||
livrable in-repo le plus concret de l'agent était absent de sa propre fiche.
|
||
|
||
**Pas de piège des deux cadres de sprint (contrairement à 071201/081202).** `mobile/app_config` est
|
||
Sprint **5** dans les DEUX cadres : `acceptance_spec` le classe en `evidence_modules` de **S5**
|
||
(`roadmap_line 58`) et la roadmap `## SPRINT 5` porte la ligne **Mobile L56** « Rebuild Expo 54 +
|
||
submit App Store #32 + Play Store ». J'ai cité **L56** (ligne Mobile, celle qu'ancre la docstring
|
||
`l.56-57`). Aucun conflit à trancher ([[agent-internal-vs-roadmap-sprint-frames]]).
|
||
|
||
**La correction (mirroir exact du pattern CRM 071201).** (a) Nouvelle sous-section « Générateur de
|
||
config app **in-repo** · `mobile/app_config` » + **1 ligne de table** identique en structure à celle du
|
||
CRM (`Module | Sprint | Rôle | Entrée CLI | Job CI | Tests`). (b) **3 réconciliations minimales** des
|
||
énumérations « ancrage in-repo » qui, sans elles, contrediraient la nouvelle section : le « livrable
|
||
in-repo est [refonte VPS] et [rôle RBAC] » (ajout du générateur), « ancré dans **deux** artefacts »
|
||
(→ « des artefacts … Outre son générateur … **deux cross-références** RBAC/QA »), et la note d'honnêteté
|
||
« l'ancrage réel est RBAC + QA S5 » (ajout du générateur). Toutes sourcées, aucune n'invente.
|
||
|
||
**Auto-gatage confirmé — le finding devient opposable au merge (3 gates indépendants de
|
||
`check_readme_claims.sh`, résolution par cible de lien `mobile/app_config ∈ plan.suites`).** `run_ci`
|
||
final montre les 3 dents mordre sur la nouvelle ligne (`AGENT.md:65`) : (a) cellule Tests `22 == source
|
||
(22)`, (b) job CI `mobile-app-config-tests == ci.yml`, (c) verbes CLI `build|validate == subparsers`.
|
||
Une future dérive du compte/job/CLI **mordra** désormais — comme pour la ligne CRM financement.
|
||
|
||
**Discipline.** Le `build` du module n'est **pas** régénéré (je n'ai touché aucun `out/`) → `git status`
|
||
ne montre **que** `03_agents/mobile/AGENT.md`. **0 gate ajouté** (surface déjà couverte par row_re/job/CLI
|
||
· #5) · **0 édition d'autorité** (roadmap, spec, directive, module intouchés) · **0 chiffre inventé**
|
||
(#6 : 22 lu dans `regression_plan`, 5 fichiers lus dans `out/` + docstring, Sprint 5/L56 lu dans
|
||
`acceptance_spec` + roadmap) · aucune commande VPS (#8) · aucun `git clean`. <!-- ci-allow : mention de l'interdit, jamais exécuté -->
|
||
|
||
**Bilan.** 1 fiche agent complétée (sous-section + 1 ligne auto-gatée + 3 réconciliations) · **CI 33
|
||
PASS · 0 FAIL · 0 SKIP** · le dernier module livré orphelin de fiche est désormais documenté et opposable.
|
||
|
||
## Session 081202 · FIX RÉEL — le module `crm/financement_bancaire` s'auto-étiquetait « **Sprint 5** » dans une **citation roadmap-globale** (`roadmap L52`) alors que L52 ∈ **Sprint 4** : label corrigé S5→S4 sur ses 2 seules surfaces (README + docstring gen) · directive Michel INTACTE · 0 gate · 0 chiffre inventé
|
||
|
||
**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 (Sprint 8 · launch-readiness). Tâche retenue : le **SIGNAL surfacé non
|
||
tranché** par la session 071201 — le README du module `crm/financement_bancaire` écrivait « **Sprint 5** ·
|
||
roadmap L52 » alors que L52 est une ligne **Sprint 4**. Investigué et **résolu comme drift réel** (pas un
|
||
cadre agent-interne).
|
||
|
||
**Le finding — un vrai conflit de cadres, tranché par la structure roadmap + l'autorité byte-gatée.**
|
||
La ligne 3 du README dit « **Sprint 5 · CRM natif ERPNext · roadmap L52 (workflow vente end-to-end · volet
|
||
financement)** ». C'est une **citation roadmap-GLOBALE** (elle cite `roadmap L52` + reprend le texte du
|
||
deliverable S4 « workflow vente end-to-end »), **pas** un cadre agent-interne de build-phase
|
||
([[agent-internal-vs-roadmap-sprint-frames]]). Or :
|
||
- Le **fichier roadmap** lui-même : `## SPRINT 4` = L48, deliverable L52 « 5 portails RBAC live · workflow
|
||
vente end-to-end » ; `## SPRINT 5` = L54 « ONAPI + Compliance + Mobile » (rien à voir avec le financement).
|
||
→ « Sprint 5 · roadmap L52 (workflow vente end-to-end) » est **auto-contradictoire**.
|
||
- L'**autorité byte-gatée** `qa/acceptance/acceptance_spec.json` (partition INV5) classe
|
||
`crm/financement_bancaire` sous **S4 · roadmap_line 52** (`evidence_modules` de S4).
|
||
- Les **3 modules frères** du même bucket S4 s'étiquettent tous « **Sprint 4** » (workflow_vente : « Réalise
|
||
le deliverable roadmap Sprint 4 » · dossier_vente : « Sprint 4 » · commissions : « Sprint 4 · roadmap
|
||
ligne 51 »). `financement_bancaire` était le **seul outlier**.
|
||
- La **fiche CRM** `03_agents/crm/AGENT.md` liste déjà correctement ce module en « **4 (roadmap L52)** »
|
||
(session 071201, sourcé S4). Le module contredisait donc sa propre fiche.
|
||
|
||
**Provenance de l'erreur (surfacée, non éditée).** La **DIRECTIVE de Michel**
|
||
`DIRECTIVE_FINANCEMENT_BANCAIRE_COMPLET_20260803.md:140` cadre le travail en « `[Sprint 5 · Financement]` » —
|
||
c'est **son** cadre d'entrée (snapshot daté, autorité pour son propre contenu · [[directive-vs-implementation]]).
|
||
L'auteur du module a transcrit ce « Sprint 5 » directive **dans un slot de citation roadmap-globale**, où il
|
||
devient faux (L52 ∈ S4). La directive est **laissée INTACTE** (input immuable de Michel, jamais éditée · comme
|
||
`daily_reports`).
|
||
|
||
**La correction (2 surfaces, balayées en un passage · [[prose-facts-vs-numeric-drift]]).** Grep exhaustif :
|
||
exactement **2** surfaces manuscrites portaient le mauvais label — `README.md:3` (prose) et
|
||
`financement_bancaire_gen.py:4` (docstring) ; **aucun** spec/artefact/`out/*.json`/gate ne porte de champ
|
||
sprint (vérifié). S5→S4 sur les deux. Le `build` du module ne régénère **aucun** artefact modifié (docstring
|
||
+ README non émis dans `out/`) → `check_artifacts` reste vert, `git status` ne montre que mes 2 fichiers source.
|
||
|
||
**Pas de gate ajouté (#5).** Le label de sprint des modules est un **piège à deux cadres légitimes**
|
||
(agent-interne vs roadmap-global) : un gate aveugle qui re-dériverait chaque label depuis `acceptance_spec`
|
||
produirait des faux positifs sur les frames agent-internes légitimes. Je **corrige la prose** (drift réel,
|
||
citation roadmap-globale fausse) sans instrumenter la surface. 0 chiffre inventé (#6) · 0 commande VPS (#8).
|
||
|
||
**Bilan.** 2 surfaces source alignées S5→S4 · directive Michel INTACTE · 0 édition d'autorité (l'autorité
|
||
`acceptance_spec` disait déjà S4) · 0 gate · 0 invention · **CI 33 PASS**. SIGNAL 071201 → **clos**.
|
||
|
||
## Session 071201 · FIX de COUVERTURE doc — la fiche CRM omettait son **4e module livré** (`crm/financement_bancaire`) : ajout d'une sous-section dédiée + ligne de table **auto-gatée** (35 tests · job CI · verbes CLI) · 0 édition d'autorité
|
||
|
||
**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 (24/24 modules 4Big à 100/100, matrice
|
||
d'acceptance 15/15 `in_repo`) — **Sprint 8 · launch-readiness**. Les décisions ouvertes restantes sont
|
||
des **arbitrages produit de Michel** ([[open-decisions-register]], ne pas trancher · #5). Tâche retenue :
|
||
le **fallback explicite** de la mission (« améliorer la doc d'un AGENT.md ») appliqué à un **écart réel**,
|
||
pas cosmétique.
|
||
|
||
**Le finding.** La fiche `03_agents/crm/AGENT.md` se présente comme le recensement des « **Livrables CRM
|
||
réellement produits** » mais n'en documentait que **3** (trio pipeline `workflow_vente`/`dossier_vente`/
|
||
`commissions`). Or `05_deliverables_mvp/crm/` héberge un **4e module gaté** — `financement_bancaire`
|
||
(parcours hypothécaire RD · gate check 4 conditions · 35 tests · job `crm-financement-bancaire-tests`) —
|
||
**absent de TOUTES les 13 fiches agents** (grep confirmé), y compris de sa fiche propriétaire naturelle.
|
||
Ce n'était pas une *inexactitude* (les 3 lignes existantes sont justes, cf. [[fiche-accuracy-audit-closed]])
|
||
mais une **incomplétude** : un livrable réel sans surface de doc côté agent.
|
||
|
||
**Pourquoi il était hors du trio (et le reste).** Le trio partage **une source unique**
|
||
(`workflow_vente_spec.json` + `rbac_50_roles.json`) — c'est la propriété « cross-cohérents » que décrit la
|
||
prose du trio, et que le gate `check_readme_claims.sh:725` encode en figeant « Total CRM : 81 tests » aux
|
||
**3** suites du pipeline. `financement_bancaire` **ne partage pas** cette source (piloté par
|
||
`DIRECTIVE_FINANCEMENT_BANCAIRE_COMPLET_20260803.md`), donc l'ajouter comme 4e ligne du trio aurait été
|
||
faux sémantiquement **et** cassé le gate (regex `Total CRM : **N tests**`). D'où une **sous-section
|
||
séparée**, le trio et son agrégat gaté laissés **intacts**.
|
||
|
||
**Sourcing (zéro invention · #6).** Sprint **4 · roadmap L52** lu dans l'autorité roadmap-globale
|
||
`qa/acceptance/acceptance_spec.json:71-84` (byte-gaté ; `evidence_modules` inclut `crm/financement_bancaire`
|
||
sous S4) — **pas** le « Sprint 5 » du README module, qui est le **cadre agent-interne**
|
||
([[agent-internal-vs-roadmap-sprint-frames]]). Nombre de tests **35** lu dans `regression_plan.json`
|
||
(`test_methods`, source faisant autorité). CLI `financement_bancaire_gen.py build|validate` vérifié depuis
|
||
les subparsers.
|
||
|
||
**Auto-gatage confirmé — le finding devient opposable au merge.** La nouvelle ligne de table est captée
|
||
par **trois** gates indépendants de `check_readme_claims.sh` (résolution par **cible de lien**,
|
||
`crm/financement_bancaire ∈ auth`) : (a) cellule Tests `35 == source (35)`, (b) job CI
|
||
`crm-financement-bancaire-tests == ci.yml`, (c) verbes CLI `build|validate == subparsers`. Une future
|
||
dérive du compte/job/CLI **mordra** désormais. `./run_ci.sh` final : **33 PASS**.
|
||
|
||
**SIGNAL (surfacé, non tranché · SURFACE don't rewrite).** Le README du module écrit « **Sprint 5** ·
|
||
roadmap L52 » — pairing interne étrange (L52 est une ligne **Sprint 4**) : soit le cadre agent-interne,
|
||
soit une micro-dérive du label roadmap-global vs l'autorité `acceptance_spec` (S4). **Non édité** (le
|
||
module README n'est pas ma cible ; le piège des deux cadres de sprint exige une édition spec+regen
|
||
coordonnée, cf. [[agent-internal-vs-roadmap-sprint-frames]]) — consigné ici pour un passage ultérieur.
|
||
|
||
**Bilan.** 1 fiche agent enrichie (sous-section + 1 ligne auto-gatée) · **0 édition d'autorité** · 0 gate
|
||
ajouté (surface déjà couverte par `row_re`/job/CLI · #5) · 0 chiffre inventé · CI **33 PASS**.
|
||
|
||
## Session 051154 · Attestation des DENTS des **suites de MODULE** — BATCH 4 (FINAL) : les **7 dernières** suites → **25/25** prouvées · **7 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 — nous sommes au **Sprint 8 · QA :
|
||
regression tests exhaustifs**. Continuation et **clôture** de l'axe des DENTS des suites de MODULE
|
||
([[module-suite-teeth-mutation]]) : les batches 034144/041149/044153 ont prouvé **18/25**, laissant les
|
||
**7 dernières** non-couvertes (rbac-aggregate, portails, audit-4big, demo-scenario, regression,
|
||
deploy-runbook, acceptance) — **non-couvertes ≠ édentées, juste non-prouvées**. Ce batch les couvre
|
||
toutes → **25/25**. Axe distinct des 8 gates STATIQUES (8/8, 031134) : une suite qui rechargerait
|
||
`out/*.json` contre elle-même serait édentée = faux vert Sprint 8 comme un gate édenté.
|
||
|
||
**Méthode.** Reconnaissance (Explore, read-only) pour cartographier, par module, **une ligne de LOGIQUE
|
||
de générateur** reconstruite en mémoire par une assertion. **Vérification critique avant de croire
|
||
l'agent** ([[module-suite-teeth-mutation]] leçon (b)) : deux mutations proposées étaient **INERTES**,
|
||
pas mordantes — `and→or` sur `deploylib/builder.py:61` (`not [] and not []` = True → `or` = True aussi,
|
||
sortie inchangée) et idem `acclib/builder.py:138`. Remplacées par des mutations qui **font basculer** la
|
||
sortie observée : `deploy` → `gated_set - mapped_set` **→ `|`** (union : `missing` non-vide, bijective
|
||
False, asserté par `test_coverage_bijective`) ; `acceptance` → `"exact": want == have` **→ `!=`**
|
||
(chaque `p["exact"]` bascule False, asserté par `test_partition_exact_all_sprints`). Unicité de chaque
|
||
cible re-vérifiée par `grep -Fc == 1` **avant** mutation. Harnais `/tmp` read-only
|
||
(`/tmp/suite_teeth_20260805_batch4.sh`) : **baseline verte** sanity → backup `cp` → `str.replace` (assert
|
||
1 occurrence) → run de **la seule suite du module** (working-directory dérivé de `ci.yml`) → assert
|
||
`exit≠0` → restauration `cp` + `cmp` byte-exact ; `trap EXIT` restaure tout ; jamais `git
|
||
clean`/`checkout` ([[ci-gate-verification-method]]). <!-- ci-allow : mention de l'interdit, jamais exécuté -->
|
||
|
||
**6 BITES — mutations de LOGIQUE de générateur, sortie re-assertée en mémoire :**
|
||
- **portails** · `wslib/builder.py:114` `roles_couverts = sum(m["nb_roles"] …)` **`+ 1`** → `test_roles_restriction` recompte le total vs `manifest.counts.roles_couverts`.
|
||
- **audit-4big** · `q4lib/builder.py:30` `"fail": len(below)` **`+ 1`** → `test_real_build_passes_gate` exige `totals.fail == 0`.
|
||
- **demo-scenario** · `scenlib/builder.py:44` `duree = sum(b["duree_min"] …)` **`+ 1`** → `test_duree_est_somme_des_beats` recompte `sc["duree_min"]` vs somme des beats.
|
||
- **regression** · `reglib/builder.py:44` `"test_methods": sum(s["test_methods"] …)` **`- 1`** → `test_totals_match_suites` recompute la somme vs `totals.test_methods`.
|
||
- **deploy-runbook** · `deploylib/builder.py:59` `gated_set - mapped_set` **`→ |`** → `test_coverage_bijective` exige `bijective` + `missing==[]`.
|
||
- **acceptance** · `acclib/builder.py:136` `"exact": want == have` **`→ !=`** → `test_partition_exact_all_sprints` exige chaque `p["exact"]` + `partition_ok`.
|
||
|
||
**1 BITE — sous-classe distincte (validation-de-CONTRAT, pas générateur).** `rbac-aggregate`
|
||
(`rbac/tests/test_rbac.py`) n'a **pas** de builder/`out/` : il charge directement le **contrat**
|
||
`rbac_50_roles.json` et y asserte des invariants absolus (schéma, ==50, unicité id/nom, couverture des 5
|
||
portails, invariant #6 `set_user_permissions`). Structurellement **non-echo** (il ne compare pas un
|
||
artefact à lui-même — il contraint des constantes dures). Dent prouvée par une dérive du **contrat**
|
||
`"cible_rbac_roles": 50 → 49`, assertée par `test_exactement_50_roles` → **BITE**. Honnêteté de portée :
|
||
axe « contrat » ≠ axe « logique de générateur », signalé comme tel plutôt que forcé dans le même moule.
|
||
|
||
**Verdict : 7 BITES · 0 TOOTHLESS → clôture 25/25 des suites de MODULE mordantes.** Combiné aux 8 gates
|
||
STATIQUES (8/8) et à la reproductibilité des artefacts, le Sprint 8 « regression tests exhaustifs » est
|
||
attesté sur ses **deux axes de DENTS**.
|
||
|
||
**Vérifications.** Arbre **byte-pristine** après harnais (`git status --porcelain` vide, `git diff --stat`
|
||
vide). `./run_ci.sh` → **33 PASS · 0 FAIL · 0 SKIP** (aucun fichier gaté touché — restauration byte-exact).
|
||
**0 chiffre inventé (#6)** · **0 gate ajouté** (prouve les tests existants, n'en crée aucun — #5) · **0
|
||
édition de production** · **aucune commande VPS (#8)** · **aucun `git clean`.** <!-- ci-allow : mention de l'interdit, jamais exécuté -->
|
||
|
||
## Session 044153 · Attestation des DENTS des **suites de MODULE** — BATCH 3 : mutation-test *generator-logic* sur 6 nouvelles suites (→ **18/25** prouvées) · **6 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. Continuation directe de
|
||
l'axe des DENTS des suites de MODULE ([[module-suite-teeth-mutation]]) : les batches 034144 (6) et
|
||
041149 (6) ont prouvé **12/25** suites, laissant **13 non-couvertes (≠ édentées, juste non-prouvées)**.
|
||
Ce batch 3 en couvre 6 de plus → **18/25**. Axe distinct des 8 gates STATIQUES (8/8, 031134) : une
|
||
suite qui rechargerait `out/*.json` contre elle-même serait édentée = faux vert Sprint 8.
|
||
|
||
**Méthode.** Reconnaissance (Explore, read-only) pour cartographier, par module, **une ligne de LOGIQUE
|
||
de générateur** (calcul/règle, jamais un octet d'artefact) qu'une assertion unittest reconstruit **en
|
||
mémoire** depuis le contrat. Unicité de chaque cible re-vérifiée par `grep -Fc == 1` **avant** mutation.
|
||
Harnais `/tmp` read-only (`/tmp/suite_teeth_20260805_3.sh`) : backup `cp -p` → remplacement d'octets
|
||
littéral (`str.replace`, assert 1 occurrence) → run de **la seule suite du module** → assert `exit≠0` →
|
||
restauration `cp` + `cmp` byte-exact ; `trap EXIT` restaure tout ; jamais `git clean`/`checkout`
|
||
([[ci-gate-verification-method]]). <!-- ci-allow : mention de l'interdit, jamais exécuté -->
|
||
|
||
**6 BITES (mutations de LOGIQUE réelles) :**
|
||
- `rbac/fixtures_gen` — `fixturelib/builder.py:43` `if_owner = scope == SCOPE_IF_OWNER` `== → !=` →
|
||
inverse tous les `if_owner`, `test_if_owner_reflete_scope_own` (attend `1 if scope=="own" else 0`) **mord**.
|
||
- `rbac/userperm_gen` — `permlib/builder.py:43` `by_mechanism[mechanism] += 1` `→ += 2` → total 50→100,
|
||
`test_manifeste_fidele` (`assertEqual(sum(by_mechanism.values()), 50)`) **mord**.
|
||
- `rbac/apply_plan` — `applylib/aggregator.py:174` chaîne `roles == cible == up_entries == rp_covered`,
|
||
2ᵉ `== → !=` → `couverture_bijective` bascule False, `test_consistency_bijective` (`assertTrue`) **mord**.
|
||
- `mobile/app_config` — `mobilelib/builder.py:105` `roles = sorted(roles_map.get(key, []))` `+reverse=True` →
|
||
ordre inversé, `test_roles_allowed_egal_surface_rbac` (`==sorted(roles_map[portail])`) **mord**.
|
||
- `qa/audit_5d` — `qalib/builder.py:60` `"fail": all_statuts.count(_FAIL)` `_FAIL → _PASS` → totals
|
||
fail 0→13, `test_verdict_pass_with_open_items` (`totals == {...,"fail":0,...}`) **mord**.
|
||
- `frontend/chat_otoia` — `chatlib/builder.py:114` `"roles_couverts": sum(m["nb_roles"] …)` →
|
||
`sum(1 …)` → 44→~5, `test_44_roles_couverts` (`total(44) == roles_couverts`) **mord**.
|
||
|
||
**LEÇON de méthode réappliquée — désambiguïser TOOTHLESS-test vs mutation INERTE.** L'Explore avait
|
||
d'abord proposé `mobile mobilelib/builder.py:192 "roles_couverts": sum → len` : **édenté pour la suite
|
||
de MODULE** car `roles_couverts` (agrégat manifest) n'est **jamais** ré-asserté en mémoire par la suite
|
||
mobile (seuls `n_roles`/`roles_allowed` par-onglet le sont). Observation honnête, **pas un défaut** — on
|
||
a muté à la place une ligne **réellement contrainte** (`:105` le tri). Idem `fixtures :68 doctypes_uniques`
|
||
(non référencé par la suite) → basculé sur `:43 if_owner`. → Règle confirmée : **vérifier que la ligne
|
||
mutée est bien celle que le test reconstruit avant de croire un verdict.**
|
||
|
||
**Portée honnête.** 18/25 échantillonnées pour la diversité (inversion booléenne, incrément de compteur,
|
||
chaîne d'égalité, tri-déterminisme, count de statut, agrégat de rôles). **7 restantes non-couvertes ≠
|
||
édentées** (rbac agrégé, portails, audit-4big, demo-scenario, regression, deploy-runbook, acceptance) —
|
||
pas de plafond silencieux.
|
||
|
||
**Vérifications.** Après restauration : `git status --porcelain` **vide**, arbre **byte-exact pristine**
|
||
(6/6 fichiers `cmp` OK). `./run_ci.sh` → **33 PASS · 0 FAIL · 0 SKIP** (inchangé). Harnais `/tmp` supprimé.
|
||
**0 gate ajouté (#5 — prouve les tests existants, n'en ajoute aucun) · 0 chiffre inventé (#6) · 0 édition
|
||
de production · 0 commande VPS (#8) · aucun `git clean`.** <!-- ci-allow : mention de l'interdit, jamais exécuté -->
|
||
|
||
## Session 041149 · Attestation des DENTS des **suites de MODULE** — BATCH 2 : mutation-test *generator-logic* sur 6 nouvelles suites (→ **12/25** prouvées) · **6 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. Continuation honnête et directe de l'axe des DENTS des suites de MODULE ([[module-suite-teeth-mutation]]) :
|
||
la session 034144 avait prouvé **6/25** suites, laissant **19 non-couvertes (≠ édentées, juste non-prouvées)**.
|
||
Ce batch 2 en couvre 6 de plus → **12/25**. Axe distinct des DENTS des 8 gates STATIQUES (8/8, 031134) : une
|
||
suite qui rechargerait `out/*.json` contre elle-même serait édentée = faux vert Sprint 8 comme un gate édenté.
|
||
|
||
**Méthode.** Reconnaissance (Explore, read-only) pour cartographier, par module, **une ligne de LOGIQUE de
|
||
générateur** (calcul/règle, jamais un octet d'artefact) qu'une assertion unittest reconstruit **en mémoire**
|
||
depuis le contrat. Unicité de chaque cible vérifiée par `grep -Fc` **avant** mutation. Harnais `/tmp` read-only
|
||
(`/tmp/suite_teeth_20260805_2.sh`) : backup `cp` → mutation de la logique → exécution de **la seule suite du
|
||
module** → assertion `exit≠0` → restauration `cp` + `cmp` byte-exact ; `trap EXIT` restaure tout ; jamais
|
||
`git clean`/`checkout` ([[ci-gate-verification-method]]). <!-- ci-allow : mention de l'interdit, jamais exécuté -->
|
||
|
||
**6 BITES (mutations de LOGIQUE réelles) :**
|
||
- `faisabilite/generator` — `scorer._score_completude` `20 * filled → 20 / filled` (sed adressé L57 car la
|
||
formule récurre L81) → le score `4big` tombe < 95, `test_complete_brief_scores_publiable` **mord** (exit 1).
|
||
- `faisabilite/bancable` — `finance.derived` point d'équilibre `math.ceil(pe_brut) → math.floor` → 21→20,
|
||
`test_derived_arithmetic_traceable` **mord**.
|
||
- `crm/workflow_vente` — `builder` `trans_rows.sort(...)` `+reverse=True` → casse le déterminisme trié,
|
||
`test_transitions_sorted_stable` **mord**.
|
||
- `crm/dossier_vente` — `is_submittable` seuil `>= "1"` (voir ci-dessous) **mord**.
|
||
- `crm/financement_bancaire` — `gate.apport_requis_usd` `/ 100.0 → * 100.0` → apport ×10 000,
|
||
`test_apport_requis_*` **mord**.
|
||
- `publiciste` — `_fmt_usd` suppression du `.replace(",", " ")` (séparateur de milliers = espace) →
|
||
"USD 150,000" ≠ "USD 150 000" attendu (test L201) **mord**.
|
||
|
||
**LEÇON de méthode — un verdict « TOOTHLESS » doit être désambiguïsé : (a) test réellement édenté vs
|
||
(b) mutation comportementalement INERTE pour la donnée du contrat.** Deux mutations de ce batch ont d'abord
|
||
lu TOOTHLESS mais étaient (b), **PAS des défauts** :
|
||
- `dossier_vente` `>= "1" → > "1"` est **inerte** car le max des `doc_status` réels = **"2"** (les deux
|
||
branches donnent 1). Une mutation qui **fait basculer** le résultat (`>= "3"` → `"2">="3"` False → 0)
|
||
**mord** bien : la suite contraint la règle `is_submittable`.
|
||
- `publiciste` `min(prices) → max` est **inerte** car le retour de `_prix_depuis` n'alimente QUE la gate
|
||
`is not None` (L116) ; sa valeur min-vs-max n'est **jamais** affichée (chaque ligne de typologie rend son
|
||
propre prix, L57). Observation honnête, **pas un défaut à corriger** (#5/#6) : la sémantique du minimum
|
||
n'a aucun effet observable en aval → on mute plutôt une logique **observée** (`_fmt_usd`).
|
||
→ Règle : **confirmer que la mutation change la SORTIE pour la fixture avant de croire un TOOTHLESS.**
|
||
|
||
**Portée honnête.** 12/25 échantillonnées pour la diversité (arithmétique, seuil booléen, tri-déterminisme,
|
||
zfill/format, dédup, séparateur) ; **13 restantes non-couvertes ≠ édentées** (rbac-agrégat/fixtures/userperm/
|
||
applyplan, portails, audit-5d, chat-otoia, audit-4big, demo-scenario, regression, deploy-runbook, acceptance,
|
||
mobile-app-config) — pas de plafond silencieux.
|
||
|
||
**Vérifications.** Après restauration : `git status` **propre**, arbre **byte-exact pristine** (6/6 fichiers
|
||
`cmp` OK). `./run_ci.sh` → **33 PASS · 0 FAIL · 0 SKIP** (inchangé — aucun fichier gaté modifié en net).
|
||
**0 gate ajouté (#5 — prouve les tests existants, n'en ajoute aucun) · 0 chiffre inventé (#6) · 0 édition de
|
||
production · 0 commande VPS (#8) · aucun `git clean`.** <!-- ci-allow : mention de l'interdit, jamais exécuté -->
|
||
|
||
## Session 034144 · Attestation des DENTS des **suites de test de MODULE** — mutation-test *generator-logic* (6 suites échantillonnées, chacune doit sortir NONZERO sur une dérive de LOGIQUE de son générateur, pas d'écho d'artefact) → **6 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. Vérifications
|
||
d'entrée : les 3 chiffres launch-readiness rechargent à l'identique depuis les artefacts commités
|
||
(recompute `python3` indépendant, aucune valeur saisie à la main) — `quality_report` **24 modules ·
|
||
tous == 100 · coverage.ok** · `regression_run` **suites 24 · ran 624 · passed 624 · 0/0/0** ·
|
||
`acceptance_matrix` **15/15 `in_repo` · verdict True · 36 `ci_job`** · `run_ci --list` **33 = 8 statiques + 25 suites**.
|
||
Un balayage read-only fan-out (README de module + docstrings des `*_gen.py`/`*lib` + DIRECTIVE↔module)
|
||
n'a **remonté aucune dérive prose** (surfaces contenu saturées, #5). **Axe distinct et jamais
|
||
couvert en suite** : hier (`031134`) a prouvé que les **8 gates STATIQUES** mordent (8/8) ; personne
|
||
n'a jamais prouvé que les **25 suites unittest de MODULE** mordent sur une dérive de **LOGIQUE de
|
||
générateur**. Une suite qui ne ferait que recharger `out/*.json` et l'asserter contre lui-même
|
||
serait **édentée** (faux vert Sprint 8 « regression tests exhaustifs ») exactement comme un gate
|
||
édenté. Constat encourageant préalable : les suites **reconstruisent en mémoire** depuis le contrat
|
||
(`builder.build_bundle(contract)`), donc elles *devraient* contraindre la logique — restait à le **prouver**.
|
||
|
||
**Méthode ([[verify-uncovered-before-gating]] appliquée à l'inverse — prouver que la protection MORD).**
|
||
Harnais unique hors dépôt (`/tmp`, jamais commité), par suite : `backup cp → mutation ciblée de la
|
||
LOGIQUE du générateur → run de la SEULE suite du module → assert exit≠0 → restore byte-exact cp →
|
||
cmp`. Trap `EXIT` restaurant **tout** même en cas d'échec. Chaque mutation = une vraie erreur de
|
||
calcul/structure que le générateur pourrait introduire (cible re-vérifiée unique sur l'arbre courant
|
||
AVANT via `grep -Fc`), **jamais** un octet d'artefact ni un commentaire :
|
||
|
||
| # | Suite (module) | Mutation *generator-logic* injectée | Verdict |
|
||
|---|---|---|---|
|
||
| 1 | `crm-commissions` | `finance.py` : commission `base * taux` → `base + taux` | **BITES** exit=1 |
|
||
| 2 | `pie-manifest` | `pielib/builder.py` : `_statut` inversé (`gated`↔`a_construire`) → compteurs faussés | **BITES** exit=1 |
|
||
| 3 | `fiscal-ecf` | `ecflib/ncf.py` : e-NCF `zfill(10)` → `zfill(9)` (rompt le format 13 car. Ley 32-23) | **BITES** exit=1 |
|
||
| 4 | `rbac-roleprofile` | `profilelib/builder.py` : `nb_roles = len(role_names)` → `+ 1` | **BITES** exit=1 |
|
||
| 5 | `seo` | `seolib/keywords.py` : dédup neutralisée (`if key in seen and False:`) → doublons | **BITES** exit=1 |
|
||
| 6 | `legal/confotur` | `cflib/builder.py` : options `entites` jointes `"\n"` → `"|"` (mauvais séparateur Frappe) | **BITES** exit=1 |
|
||
|
||
**Résultat : 6 BITES · 0 TOOTHLESS.** Chaque suite échantillonnée oppose au merge une dérive réelle
|
||
de la **logique** de son générateur — aucune n'est un simple miroir d'artefact. Combiné à hier,
|
||
l'opposabilité au merge est prouvée sur **8 gates statiques + 6 suites de module**.
|
||
|
||
**Portée honnête (pas de plafond silencieux).** Échantillon de **6 des 25 suites** de module,
|
||
choisi pour la diversité des styles d'assertion (calcul monétaire · compteurs de statut · format
|
||
réglementaire · métadonnée de comptage · dédup · sérialisation d'options). Les **19 suites non
|
||
mutées ce jour** (`publiciste`, `rbac`(agrégée)/`fixtures`/`userperm`/`applyplan`, `faisabilite-gen`,
|
||
`bancable`, `workflow-vente`, `dossier-vente`, `financement-bancaire`, `portails`, `audit-5d`,
|
||
`chat-otoia`, `audit-4big`, `demo-scenario`, `regression`, `deploy-runbook`, `acceptance`, `mobile-app-config`)
|
||
restent à attester en session ultérieure — non couvertes ≠ édentées, juste non prouvées aujourd'hui.
|
||
|
||
**Discipline.** Attestation **read-only par conception** (harnais en `/tmp`, mutations restaurées
|
||
`cp` depuis backup + `cmp` byte-exact · **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). Axe **dents des suites de module**,
|
||
distinct de l'axe **dents des gates** (`031134`) et des attestations de **contenu**.
|
||
|
||
**Vérifications.** `git status --porcelain` **vide** (arbre byte-pristine post-harnais) · `cmp`
|
||
backup↔restauré pour les 6 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 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é -->
|
||
|
||
## Session 054200 · Currency du canal STAKEHOLDER : consigner la clôture des DEUX axes de « dents » dans `daily_reports/2026-08-05.md` · 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 côté repo (Sprint 8 buffer). Les surfaces
|
||
de dérive usuelles sont saturées, donc j'ai d'abord **cherché une vraie régression**, pas une
|
||
attestation redondante (#5) :
|
||
|
||
1. **Chasse docstring↔code drift** (classe documentée RÉCURRENTE/non-close — a déjà trouvé le
|
||
« fallback §5.3 fantôme » publiciste + l'output `run_sheet.md` omis). Balayage des **21
|
||
générateurs** (docstring/commentaires vs fichiers réellement écrits : `open`/`write_text`/
|
||
`json.dump`). **Résultat : 0 contradiction réelle.** Les « écarts » remontés (docstrings
|
||
sans liste-de-sorties en puces) étaient des **faux positifs** : `commissions_gen.py` documente
|
||
bien ses sorties dans le bloc *Sous-commandes* (`build → écrit commission_plan.json +
|
||
MANIFEST.json`), simple placement différent de `financement` (7 sorties → liste séparée).
|
||
Uniformiser serait de la **pure churn** (#5) — écarté.
|
||
|
||
2. **Seule action honnête + non-redondante trouvée : currency du canal stakeholder.** Le
|
||
`daily_reports/2026-08-05.md` (session `004112`, matin) s'arrête au jalon **33 jobs** et
|
||
**précède** toute la série d'attestation *teeth* des **suites de MODULE** (BATCH 1→4,
|
||
commits `034144`→`051154`, clôture **25/25**) jouée plus tard le même jour. Le canal
|
||
stakeholder ([[two-logging-channels]]) ne captait donc **aucun** des deux axes de « dents ».
|
||
|
||
**Fait.** Ajout d'une section « Mise à jour fin de journée » au rapport du jour, consignant la
|
||
**clôture des deux axes** : (A) **8/8** gates statiques (`9fe8bf1`/`031134`) · (B) **25/25**
|
||
suites de module (`6+6+6+7`, `98f3f56`/`d25da28`/`e38dd93`/`986d293`). Chaque chiffre **sourcé
|
||
sur une structure commitée** (`ls ci/*.sh` hors `lib.sh` = 8 · `gate.needs` = 25 · série de
|
||
commits) — **0 saisi à la main** (#6). Message stakeholder explicité : les tables de currency
|
||
prouvent que la CI est **verte** ; les attestations *teeth* prouvent qu'elle **mord** (un gate/
|
||
suite toujours-vert = faux vert invisible aux tables).
|
||
|
||
**Vérifications.** `./run_ci.sh` → **33 PASS · 0 FAIL · 0 SKIP** (seul fichier touché =
|
||
`daily_reports/2026-08-05.md` + ce log ; aucun fichier de code gaté). **0 chiffre inventé
|
||
(#6) · faux findings docstring écartés · 0 édition de production · 0 gate ajouté (#5) · aucune
|
||
commande VPS (#8) · aucun `git clean`.** <!-- ci-allow : mention de l'interdit, jamais exécuté -->
|
||
|
||
## Session 061201 · Sweep REPO-WIDE de la classe « chemin fantôme en code-span backtick » (ungated, documentée récurrente) → 0 fantôme réel · 0 édition de production
|
||
|
||
**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 (Sprint 8 buffer). Plutôt qu'une n-ième attestation
|
||
redondante (#5), j'ai d'abord voulu **fermer un axe encore incomplet**. Deux axes de câblage
|
||
CI vérifiés d'abord et confirmés **structurellement clos** : (a) parité local↔CI —
|
||
`run_ci.sh` **dérive** sa liste de `gate.needs` (aucune liste en dur), et
|
||
`check_ci_integrity.sh` verrouille `ci.yml` comme source de vérité ; (b) **gate orphelin** —
|
||
`check_ci_integrity` INV-B itère `git ls-files 'ci/*.sh'` et exige que chaque script soit
|
||
lancé par un job du gate **ou** sourcé par un gate lancé → un `ci/*.sh` mort/décâblé casse la
|
||
CI. Rien à ajouter (#5).
|
||
|
||
**Axe réellement balayé (nouveau périmètre).** La classe **« chemin in-repo fantôme dans un
|
||
code-span backtick »** est **ungated à dessein** (les backticks sont neutralisés par
|
||
`check_docs` — cf. [[backtick-path-escapes-check-docs]] ; « ne pas gater tous les backticks »).
|
||
L'audit d'exactitude des fiches ([[fiche-accuracy-audit-closed]]) ne couvrait que les **13
|
||
`03_agents/*/AGENT.md`**. Je l'ai **étendu à TOUT le markdown suivi** (~200 fichiers :
|
||
READMEs de modules, `daily_reports/`, `04_roadmap/`, `ci/README.md`, DIRECTIVE_*, GAP_ANALYSIS,
|
||
logs) via un harnais qui extrait chaque token backtické contenant un `/` et le résout contre
|
||
**quatre ancres** : dossier du doc, racine du dépôt, `05_deliverables_mvp/`, et chaque
|
||
sous-module `05_deliverables_mvp/*/`.
|
||
|
||
**Résultat : 0 fantôme réel.** Les ~180 tokens remontés se ventilent en **trois formes
|
||
bénignes**, chacune vérifiée sur échantillon :
|
||
1. **Runtime/VPS hors-dépôt** (`/static/`, `otoia/capabilities/*`, `www/`, `seo_autonome/`,
|
||
`data_room/PXX/`) — non réfutables depuis le dépôt (#8), déjà connues.
|
||
2. **Citations cross-module en prose** — un README/rapport nomme le fichier d'un AUTRE module
|
||
par son nom court. Vérifié : `crm/commissions/README.md` cite `banclib/finance.py` **à
|
||
l'intérieur d'un vrai lien Markdown** dont la **cible existe et EST validée par
|
||
`check_docs`** (le backtick n'est que le libellé) ; `banclib`/`wflib`/`cflib` résolvent tous
|
||
dans le dossier de leur module propre.
|
||
3. **Narratif d'historique + non-chemins pédagogiques** — les `05_activity_log/*` antérieurs
|
||
citent des fichiers par nom court (prose, pas navigation), et certains chemins **n'existent
|
||
pas EXPRÈS** : `./inexistant-xyz-123.md` / `./this/does/not/exist.md` sont les liens cassés
|
||
d'exemple prouvant que `check_docs` **mord**, et `/tmp/suite_teeth_*.sh` sont les harnais de
|
||
mutation-test éphémères (`/tmp` read-only). Correct par conception.
|
||
|
||
**Conclusion honnête.** L'axe fantôme-backtick est **propre repo-wide** (extension du 13→~200
|
||
`.md`), les deux axes de câblage CI sont clos, les axes *teeth* (8/8 statiques · 25/25 suites)
|
||
et free-text/chiffres étaient déjà saturés. **Aucun défaut réel trouvé → 0 édition de
|
||
production** (churner un doc exact serait de la dérive #5) et **0 gate ajouté** (gater les
|
||
backticks est explicitement rejeté, et un gate lisant `/opt/oto` serait non-portable côté
|
||
runner Gitea — cf. [[ci-gate-verification-method]]). Seule sortie : ce log + une note mémoire
|
||
pour que la prochaine session ne rejoue pas ce sweep à froid ni ne re-flague ces formes.
|
||
|
||
**Vérifications.** `./run_ci.sh` → **33 PASS · 0 FAIL · 0 SKIP** (seul fichier touché = ce
|
||
log ; aucun fichier de code gaté). **0 chiffre inventé (#6) · faux positifs backtick écartés
|
||
par résolution multi-ancre + inspection · 0 édition de production · 0 gate ajouté (#5) ·
|
||
aucune commande VPS (#8) · aucun `git clean`.** <!-- ci-allow : mention de l'interdit, jamais exécuté -->
|
||
|
||
---
|
||
|
||
## Session 20260805_064201 · FIX RÉEL — la fenêtre de sprint *roadmap-globale* de `faisabilite/generator` était fausse (S2 → S3)
|
||
|
||
**Défaut trouvé (première vraie édition de production depuis plusieurs sessions de sondes « 0 édition »).**
|
||
Le registre de l'auditeur 4Big attribuait au **générateur de faisabilité 4 volets** une fenêtre
|
||
de sprint **roadmap-globale erronée** :
|
||
|
||
- `05_deliverables_mvp/qa/audit_4big/quality_spec.json:66`
|
||
→ `"sprint": "S2"`, `"source": "roadmap Sprint 2 · Faisabilité générateur 4 volets …"`.
|
||
|
||
Or la roadmap **ne contient AUCUNE faisabilité au Sprint 2** (`04_roadmap/…:35-39` = Console /
|
||
CRM / RBAC). La **« génération 4 volets <1h »** est explicitement au **Sprint 3**
|
||
(`…:43`, livrable `…:46` « P07 Aqua Terra faisabilité complète auto-générée »). La citation
|
||
`source` était donc **falsifiable et fausse** (classe [[prose-facts-vs-numeric-drift]] · sous-classe
|
||
*citation mal-attribuée* + [[roadmap-anchor-gate]]).
|
||
|
||
**Cause racine — confusion de deux cadres de « sprint ».**
|
||
1. **Cadre agent-interne** (phases de construction par agent) : `03_agents/faisabilite/AGENT.md`
|
||
§130-133 définit S1 = template · **S2 = générateur 4 volets** · S3 = version tracking — le tout
|
||
**ancré à la roadmap Sprint 3** (L41-46). Ce cadre est repris tel quel dans les docs de module
|
||
(`generator/README.md` H1 « Sprint 2 », `TEMPLATE_…:216`, `GAP_ANALYSIS_SPRINT1.md:74-75`,
|
||
`publiciste/README.md:26`, `daily_reports/*`). **Cohérent dans son cadre — laissé intact.**
|
||
2. **Cadre roadmap-global** (autorité de la recette) : le champ `sprint` de `quality_spec.json`
|
||
— **toutes** les autres entrées le sourcent « roadmap Sprint N ». C'est le **seul** endroit qui
|
||
doit porter le sprint roadmap-global. Il avait recopié le label agent-interne « S2 ».
|
||
|
||
**Conséquence corrigée.** Le livrable-phare **S3** « P07 faisabilité complète auto-générée »
|
||
était prouvé **sans** le module qui la génère (`faisabilite/generator`), tandis que ce dernier
|
||
était compté comme preuve du **S2** (« 7 dashboards · CRM · RBAC ») — auquel il n'a **aucun**
|
||
rapport. La preuve la plus directe du livrable-phare était mal-classée.
|
||
|
||
**Correctif (édition coordonnée 2-spec + régénération byte-gatée).**
|
||
- `quality_spec.json:66` : `"sprint"` **S2 → S3**, `source` recitée « roadmap Sprint 3 · Faisabilité
|
||
générateur 4 volets → data_room/PXX » (aligné sur le style de son jumeau `bancable`, ligne 71,
|
||
déjà S3).
|
||
- `acceptance_spec.json` : `faisabilite/generator` **retiré** de `evidence_modules` S2, **ajouté**
|
||
à S3 (`["faisabilite/bancable", "faisabilite/generator"]`) — sinon l'**invariant 5 « partition
|
||
exacte »** casse (`want` lu dans `quality_spec` ≠ `have` déclaré). Édition des DEUX specs
|
||
obligatoire et suffisante.
|
||
- Régénération : `audit_4big` (report) **puis** `acceptance` (lit la fenêtre depuis `quality_spec`).
|
||
|
||
**Vérifications.** `partition_ok=True · bijective=True` · S2 = 6 modules (publiciste + 5 rbac,
|
||
exact) · S3 = {bancable, generator} (exact). `./run_ci.sh` → **33 PASS · 0 FAIL · 0 SKIP**.
|
||
Score 4Big du générateur **inchangé 100/100** (le champ `sprint` ne sert qu'au tri + méta du
|
||
report, pas d'oracle de scoring vérifié dans `q4lib/scoring.py`).
|
||
|
||
**Portée honnête / anti-churn.** **5 fichiers** touchés (2 specs + 3 artefacts régénérés) + ce log.
|
||
**Zéro** doc de module éditée : les ~10 « S2 » du générateur ailleurs sont le **cadre agent-interne**
|
||
(ancré Sprint 3), corrects — les churner serait de la dérive #5. `daily_reports/*` = historique,
|
||
non réécrit. **0 gate ajouté** (surface déjà gatée par invariant 5 · [[verify-uncovered-before-gating]]),
|
||
**0 chiffre inventé** (#6, tout dérivé du roadmap), **0 commande VPS** (#8), **aucun `git clean`**. <!-- ci-allow : mention de l'interdit, jamais exécuté -->
|
||
|
||
---
|
||
|
||
## Session 20260805_074202 · FIX de COUVERTURE — le livrable transverse `demo/scenarios` manquait des DEUX fiches co-porteuses
|
||
|
||
**Classe** : complétude ≠ exactitude ([[fiche-accuracy-audit-closed]]) — même classe que
|
||
le FIX précédent (CRM omettait `financement_bancaire`). Méthode : diff
|
||
`05_deliverables_mvp/*/` (modules à générateur + tests + `out/`) vs les tables de
|
||
livrables des 13 fiches `03_agents/*/AGENT.md`.
|
||
|
||
**Défaut réel trouvé.** Le module **`05_deliverables_mvp/demo/scenarios/`** — livrable
|
||
bel et bien produit (générateur `demo_scenario_gen.py` · **39 tests** · `out/{run_sheet,MANIFEST}` ·
|
||
README · déjà gaté par `check_readme_claims` sur son propre README + job CI
|
||
`demo-scenario-tests`) — n'était recensé dans **AUCUNE** des 13 fiches agents (grep
|
||
`demo|scenario` sur `03_agents/*/AGENT.md` = 0 hit). C'est un livrable **transverse
|
||
sans agent propre** : son README le cadre « Sprint 7 (CRM + Faisabilité) » et la roadmap
|
||
L68 l'assigne explicitement à **CRM + Faisabilité**. Les DEUX co-porteurs l'omettaient.
|
||
|
||
**Correctif — 2 fiches, une seule source gatée (anti-duplication #5).**
|
||
- **Fiche CRM** (`03_agents/crm/AGENT.md`) : nouvelle sous-section « Livrable transverse ·
|
||
Sprint 7 — scénarios démo », avec table 1-ligne **auto-gatée** (mirroir du précédent
|
||
`financement_bancaire`). La ligne pointe `…/demo/scenarios/README.md` et finit `| 39 |`
|
||
→ captée par le `row_re` de `check_readme_claims` (label `\w+/` = `scenarios/`, chemin
|
||
résolu `demo/scenarios` ∈ `plan.suites`) → cellule Tests **recomputée** depuis
|
||
`regression_plan.json`. Framée honnêtement : **pas un livrable CRM propre** mais un
|
||
méta-générateur qui **compose** les livrables amont, co-porté, **ne partage aucune
|
||
source** avec le trio ni le financement.
|
||
- **Fiche Faisabilité** (`03_agents/faisabilite/AGENT.md`) : **cross-référence en prose**
|
||
(pas de chiffre redupliqué · #5) vers la fiche CRM + le README du module, mentionnant
|
||
que `bancable` alimente le scénario `S-P07-BANQUIER`.
|
||
|
||
**Auto-gates confirmés (3 axes indépendants, la ligne CRM franchit chacun).**
|
||
1. `Fiche 03_agents/crm/AGENT.md · demo/scenarios — Tests 39 == source (39)` (recompute
|
||
`regression_plan.json`).
|
||
2. `Entrée CLI · demo_scenario_gen.py — verbes build|validate == subparsers`.
|
||
3. `Traçabilité roadmap · demo/scenarios — citation l.68 == roadmap`.
|
||
Job CI `demo-scenario-tests` == ci.yml. `check_docs` : cross-refs `../crm/AGENT.md`
|
||
résolus OK.
|
||
|
||
**Portée honnête / anti-churn.** **2 fichiers** touchés (2 fiches) + ce log. **0 gate
|
||
ajouté** (surface déjà couverte par le `row_re` générique des cellules Tests ·
|
||
[[verify-uncovered-before-gating]] · [[doc-numeric-claims-gate]]) — la nouvelle ligne
|
||
*hérite* du gate existant. **0 chiffre inventé** (#6 · 39 dérivé de la source unique).
|
||
Le trio CRM + « Total CRM 81 tests » + le financement laissés **INTACTS** (demo hors-trio,
|
||
source distincte). **0 production éditée** (#5), **0 commande VPS** (#8), **aucun
|
||
`git clean`**. `./run_ci.sh` → **33 PASS · 0 FAIL · 0 SKIP**. <!-- ci-allow : mention de l'interdit, jamais exécuté -->
|
||
|
||
---
|
||
|
||
## Session 20260805_084202 · FIX RÉEL — « 6 sections » périmé dans les 2 docs d'implémentation du module `financement_bancaire` (le module en livre 7)
|
||
|
||
**Classe** : prose FACT count périmée, ungated ([[prose-facts-vs-numeric-drift]] ·
|
||
[[doc-numeric-claims-gate]]) — distincte des comptes gatés.
|
||
|
||
**Défaut réel trouvé.** Deux surfaces d'implémentation décrivant le module livré
|
||
`crm/financement_bancaire` affirmaient **« 6 sections »** alors que le module en livre
|
||
**7** :
|
||
- `05_deliverables_mvp/crm/financement_bancaire/README.md:9` — « la structure des 6 sections »
|
||
- `03_agents/crm/AGENT.md:47` — « cœur du gate + 6 sections + bannière »
|
||
|
||
**Preuve du bon compte = 7** (triple-sourcé, byte-gaté) :
|
||
- `out/MANIFEST.json` → `counts.sections = 7` (artefact byte-gaté par `check_regression`/`check_artifacts`).
|
||
- `financement_spec.json` → bloc `sections` = 7 (`apport_initial`, `info_achat`,
|
||
`choix_banque`, `formulaires`, `exigences`, `autorisations`, `envoi`).
|
||
- Le README **lui-même** se contredisait : ligne 49 énumère les **7** sections de
|
||
l'accordéon, ligne 57 « **7 sections** » (annotée « source de vérité = MANIFEST.json »).
|
||
Seule la ligne 9 (prose libre) était restée à « 6 ».
|
||
|
||
**Origine du « 6 ».** La `DIRECTIVE_FINANCEMENT_BANCAIRE_COMPLET` originale (L106)
|
||
énumère exactement **6 sections non-gating** (`Info achat / Choix banque / Formulaires /
|
||
Exigences / Autorisations / Envoi`), **puis** a été **amendée** pour ajouter la section
|
||
gating `apport_initial` en position 1 → **7** au total. La spec + le module ont suivi (7),
|
||
mais les 2 phrases de prose d'implémentation avaient gardé le « 6 » d'avant l'amendement.
|
||
|
||
**Correctif — 2 surfaces d'implémentation, 6→7. Directives laissées INTACTES.**
|
||
Les **4** occurrences « 6 sections » restantes vivent dans des **snapshots directive**
|
||
gelés (`DIRECTIVE_FINANCEMENT…` L106/L122/L131 + `DIRECTIVE_WORKFLOW_FAISABILITE_V10`
|
||
L22/L47) — **input-specs datés de Michel**, jamais réécrits ([[directive-vs-implementation]] ·
|
||
`spec = authority, directive = snapshot`). Leur « 6 » est **historiquement exact** au
|
||
cadre pré-amendement (énumération des 6 aval). Seules les 2 surfaces décrivant le
|
||
**livrable** sont corrigées.
|
||
|
||
**Aucun gate ajouté (#5).** Un gate structuré sur la ligne « Comptes courants »
|
||
recomputerait la ligne 57 (déjà correcte, adossée à MANIFEST) mais **ne mordrait pas**
|
||
la prose libre de la ligne 9 — la classe réelle du défaut. Financement reste le seul
|
||
module dont `MANIFEST.counts` n'est pas recompté dans `check_readme_claims` ; **SIGNAL
|
||
surfacé** (couverture prose ungated), pas d'ajout ce tour pour éviter un gate fragile +
|
||
hors-cible. **0 chiffre inventé** (#6 · 7 dérivé de MANIFEST/spec), **0 production éditée**
|
||
(#5), **0 commande VPS** (#8), **aucun `git clean`**. `./run_ci.sh` → **33 PASS · 0 FAIL · 0 SKIP**. <!-- ci-allow : mention de l'interdit, jamais exécuté -->
|