Files
oto-enterprise-os-dtp/05_activity_log/2026-08-02.md
T
Claude Code DTP Worker 40ee6f6a46 [DTP-Worker 20260802_013501] Sprint 8 · buffer · CRM Dossier Vente : gate d'IDENTITÉ du COMPTE D'INVARIANTS de _validate (5ᵉ instance du ledger)
5ᵉ instance de la classe « ledger d'invariants » (après Chat OTOIA · SEO ·
Fiscal e-CF · Legal CONFOTUR). Le compte « 12 invariants » de
crm/dossier_vente/doctype_dossier_vente_gen.py était transcrit à la main à
7 endroits (4 chaînes du .py + 3 du README : commande, titre « ## Les 12
invariants », prose de score), aucun gaté — invisibles à check_artifacts
(le .py n'est pas un out/*.json) et aux suites tests/ (qui testent des
fonctions, pas la prose). Ajouter un contrôle # 13 · sans toucher les 7
chaînes ⇒ CI applique 13 contrôles pendant que docs+self-reports disent 12
en silence (vert trompeur · #6).

Ledger PROPRE 1..12 (≈ CONFOTUR) : schéma compté à part (« schéma + N
invariants »), pas de schéma-#1 non marqué, pas de split a/b ; détection de
doublon nu conservée en filet. Le gate RECOMPUTE le ledger depuis le seul
registre-source (# N · de _validate) et exige (a) ledger contigu 1..N ;
(b) toute mention « N invariants » du .py == |ledger| ; (c) annonce du titre
README == |ledger| ; (d) toute mention README == |ledger| ; (e) énumération
numérotée de la section contiguë 1..N.

5 checks verts sur l'arbre propre. 7 morsures adversariales (M1 self-report
.py · M2 titre README · M3 prose README · M4 ajout # 13 · = ledger 13 vs
prose 12, mord .py+README+énumération = autorité au CODE · M5 gap # 7 · ·
M6 doublon nu # 5 · · M7 énumération 7→8). 6 gates re-verts exit 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-02 01:40:40 +00:00

206 lines
12 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-02 · Claude Code DTP Worker
## Sprint 8 · buffer · CRM Dossier Vente — gate d'IDENTITÉ du COMPTE D'INVARIANTS de `_validate` (5ᵉ instance du ledger)
**Contexte** — Série anti-dérive Sprint 8 (CLAUDE.md #6 « zéro invention de
chiffres »). Le pattern « ledger d'invariants » (recompute le nombre de contrôles
CI depuis le registre-source `# N ·` de `_validate`, jamais une liste à la main)
a déjà couvert **Chat OTOIA**, **SEO**, **Fiscal e-CF** et **Legal CONFOTUR**. Le
**5ᵉ générateur** portant le même nombre magique restait NON gaté :
`crm/dossier_vente/doctype_dossier_vente_gen.py` (candidats restants recensés :
`qa/audit_5d` ·15, `crm/commissions` ·10, tous ledgers propres non gatés).
Le compte **« 12 invariants »** y est transcrit **à la main à SEPT endroits**,
aucun gaté, tous invisibles à `check_artifacts` (le `.py` source n'est pas un
`out/*.json`) :
1. docstring module (l.14 « schéma + 12 invariants de ») ;
2. docstring `_validate` (l.77 « 12 invariants de cross-cohérence ») ;
3. message de succès CLI `validate` « … schéma + 12 invariants verts. » (l.218) ;
4. aide du sous-parseur `validate` (l.230) ;
5. README bloc de commande « schéma + 12 invariants » (l.56) ;
6. README titre de section « ## Les 12 invariants » (l.60) ;
7. README prose de score « 12 invariants de cross-cohérence » (l.83).
Ajouter un contrôle `# 13 ·` à `_validate` sans toucher les 7 chaînes ⇒ le README
ET les self-reports du `.py` mentent en silence pendant que la CI applique 13
contrôles. Aucune suite `tests/` (qui teste des FONCTIONS de validation, pas la
prose) n'attrape ce « vert trompeur ».
**Particularité du registre Dossier Vente** (≈ CONFOTUR, ≠ Fiscal) : le ledger est
**PROPRE 1..12** — le **schéma est compté À PART** (phrasé « schéma + N invariants »),
donc **pas de schéma-#1 non marqué** et **pas de split a/b**. On garde néanmoins la
détection de doublon nu comme filet. Le README porte AUSSI une **énumération
numérotée** sous le titre de section (item 1 = conformité au schéma, puis les
contrôles), gatée en contiguïté 1..N.
**Gate ajouté** (`ci/check_readme_claims.sh`, bloc « CRM · Dossier Vente · IDENTITÉ
du COMPTE D'INVARIANTS ») — RECOMPUTE le ledger depuis le SEUL registre-source
(`# N ·` de `_validate`) et exige :
- **(a)** ledger CONTIGU 1..N (lacune OU doublon nu = vrai défaut de registre) ;
- **(b)** toute mention « N invariants » du `.py` == |ledger| ;
- **(c)** l'annonce du titre README « ## Les N invariants » == |ledger| ;
- **(d)** toute mention « N invariants » du README == |ledger| ;
- **(e)** l'ÉNUMÉRATION numérotée de la section (« 1. … 2. … N. ») contiguë 1..N.
Une mention ou le registre absent échoue AUSSI (traçabilité #6).
**Vérif** — 5 checks verts sur l'arbre propre (ledger 1..12 = 12 marqueurs `# N ·`,
schéma compté à part). **7 morsures** adversariales : M1 self-report `.py` 12→13
(b) · M2 titre README 12→13 (c+d) · M3 prose README 12→13 (d) · **M4 ajout marqueur
`# 13 ·` ⇒ ledger→13 pendant que la prose reste 12 (mord `.py` ET README ET
l'énumération, preuve que l'autorité est le CODE)** · M5 suppression `# 7 ·` ⇒ gap
non-contigu (a) · M6 doublon nu `# 5 ·` ⇒ détection de vrai doublon (a) · M7
énumération README 7.→8. ⇒ deux 8/pas de 7 (e). Gates re-verts : `check_artifacts`
· `check_docs` · `guard_constraints` · `check_ci_integrity` · `check_regression` ·
`check_readme_claims` tous exit 0.
---
## Sprint 8 · buffer · Legal CONFOTUR — gate d'IDENTITÉ du COMPTE D'INVARIANTS de `_validate` (4ᵉ instance du ledger)
**Contexte** — Série anti-dérive Sprint 8 (CLAUDE.md #6 « zéro invention de
chiffres »). Le pattern « ledger d'invariants » (recompute le nombre de contrôles
CI depuis le registre-source `# N ·` de `_validate`, jamais une liste à la main)
a déjà couvert **Chat OTOIA**, **SEO** et **Fiscal e-CF**. Le **4ᵉ générateur**
portant le même nombre magique restait NON gaté :
`legal/confotur/confotur_application_gen.py`.
Le compte **« 14 invariants »** y est transcrit **à la main à SIX endroits**,
aucun gaté, tous invisibles à `check_artifacts` (le `.py` source n'est pas un
`out/*.json`) :
1. docstring module (l.24 « schéma + 14 invariants de ») ;
2. docstring `_validate` (l.87 « 14 invariants de cross-coherence ») ;
3. message de succès CLI `validate` « … schéma + 14 invariants verts. » (l.283) ;
4. aide du sous-parseur `validate` (l.295) ;
5. README bloc de commande « schéma + 14 invariants » (l.56) ;
6. README commentaire d'arborescence « CLI build/validate · 14 invariants » (l.82).
Ajouter un contrôle `# 15 ·` à `_validate` sans toucher les 6 chaînes ⇒ le README
ET les self-reports du `.py` mentent en silence pendant que la CI applique 15
contrôles. Aucune suite `tests/` (qui teste des FONCTIONS de validation, pas la
prose) n'attrape ce « vert trompeur ».
**Particularité du registre CONFOTUR** (≠ Fiscal) : le ledger est **PROPRE 1..14**
(pas de schéma-#1 non marqué, pas de split a/b). MAIS le README porte AUSSI un
compte de **SOUS-ENSEMBLE éditorial** — « **2 invariants** refusent tout champ
monétaire » (l.92) — à NE PAS confondre avec le total. Un `\d+ invariants` naïf
mordrait donc l'arbre PROPRE (il verrait `{2, 14}`). Le gate exclut le
sous-ensemble par **lookahead négatif** `(\d+)\s+invariants(?!\s+refusent)`,
appliqué au `.py` comme au README.
**Gate ajouté** (`ci/check_readme_claims.sh`, bloc « Legal · CONFOTUR · IDENTITÉ
du COMPTE D'INVARIANTS ») — RECOMPUTE le ledger depuis le SEUL registre-source
(`# N ·` de `_validate`) et exige :
- **(a)** ledger CONTIGU 1..N (lacune OU doublon nu = vrai défaut de registre) ;
- **(b)** toute mention-total « N invariants » du `.py` (hors « refusent ») == |ledger| ;
- **(c)** toute mention-total du README (hors « refusent ») == |ledger|.
Une mention ou le registre absent échoue AUSSI (disparition d'un chiffre =
régression de traçabilité #6).
**Vérif** — 3 checks verts sur l'arbre propre (ledger 1..14 = 14 marqueurs `# N ·`).
**6 morsures** adversariales : M1 self-report `.py` 14→15 (b) · M2 README commande
14→15 (c) · M3 README arborescence 14→13 (c) · **M4 ajout marqueur `# 15 ·`
ledger→15 pendant que la prose reste 14 (mord `.py` ET README, preuve que
l'autorité est le CODE)** · M5 suppression `# 7 ·` ⇒ gap non-contigu (a) · M6
doublon nu `# 5 ·` ⇒ détection de vrai doublon (a). **M7 no-false-positive** :
sous-ensemble « 2 → 3 invariants refusent » reste VERT (le lookahead exclut bien
le sous-ensemble). Gates re-verts : `check_artifacts` · `check_docs` ·
`guard_constraints` · `check_ci_integrity` · `check_regression` ·
`check_readme_claims` tous exit 0.
---
## Sprint 8 · buffer · Publiciste — gate d'ANCRAGE des DEVISES du site public sur CLAUDE.md #10
**Contexte** — Série anti-dérive Sprint 8 (CLAUDE.md #6 « zéro invention de
chiffres »). Le bloc `Publiciste/branding` existant ancre les **4 tokens DESIGN**
de CLAUDE.md #4 (2 couleurs + 2 typographies) sur leurs 4 copies. Mais le MÊME
module publiciste porte une **2ᵉ constante constitutionnelle** — les **devises
CLAUDE.md #10 (« USD + DOP »)** — recopiée à 4 endroits data-derived, **aucun
gaté**, tous invisibles à `check_artifacts` (pas un `out/*.json`) :
1. `lib/branding.py` `DEVISE_PRIMAIRE`/`DEVISE_SECONDAIRE` — constantes auto-
étiquetées « contrainte #10 · USD + DOP », sans gate ;
2. `lib/generator.py` `_fmt_usd`/`_fmt_dop` — les **formateurs qui IMPRIMENT le
code devise sur la grille de prix du site public** `vente.otov7.com` (sortie
face-public : une devise hors #10 = mandat trahi en silence) ;
3. `lib/generator.py` footer HTML « Prix … en USD + DOP (Cardnet) » ;
4. `tests/test_publiciste.py` — l'oracle hardcodé `assertIn("USD 150 000", …)`,
une copie de plus jamais comparée à CLAUDE.md.
Aucune suite `tests/` (qui teste des **fonctions** de rendu, pas l'ancre à
CLAUDE.md) n'attrape la dérive : renommer la devise #10 et aligner le module
reste vert alors que le site émettrait la mauvaise devise ; ne rien bouger reste
vert alors que `branding.py` se dit « #10 » en mentant.
**Gate ajouté** (`ci/check_readme_claims.sh`, bloc « Publiciste/generator+branding
· DEVISES CANONIQUES ») — RE-PARSE les 2 devises depuis la ligne #10 de CLAUDE.md
(indépendamment de `exp` amont · aucun skip hérité) puis exige :
- **(a)** `branding.py` DEVISE_PRIMAIRE/SECONDAIRE == #10 (ordre inclus) ;
- **(b)** l'ensemble des codes émis par les formateurs `generator.py` == #10 ;
- **(c)** le footer HTML cite les 2 devises dans l'ordre + `(Cardnet)` ;
- **(d)** l'oracle du test == devise primaire #10.
Un claim absent échoue AUSSI (traçabilité #6 · anti-évaporation).
**Vérif** — 5 checks verts sur l'arbre propre. **6 morsures** adversariales :
M1 branding primaire USD→EUR · M2 formateur `_fmt_usd`→EUR (hors #10) · M3 footer
USD+DOP→USD+EUR · M4 oracle test → EUR · **M5 CLAUDE.md #10 USD→EUR = cascade sur
les 4 copies simultanément** (preuve que l'ancre est CLAUDE.md, pas la cohérence
interne) · M6 footer supprimé → INTROUVABLE. Gates re-verts :
`check_readme_claims` · `check_docs` · `guard_constraints` · `check_ci_integrity`
tous exit 0.
---
## Sprint 8 · buffer · Fiscal e-CF DGII : gate d'IDENTITÉ du COMPTE D'INVARIANTS de `_validate`
**Contexte** — Série anti-dérive Sprint 8 (CLAUDE.md #6 « zéro invention de
chiffres »). Le pattern « ledger d'invariants » a déjà été appliqué à **Chat
OTOIA** et **SEO** (recompute le nombre d'invariants CI depuis le registre-source
`# N ·` de `_validate`, jamais une liste à la main). Le **3ᵉ générateur** portant
le même nombre magique restait NON couvert : `fiscal/ecf_dgii/ecf_dgii_gen.py`.
Le compte **« 12 invariants »** y est transcrit **à la main à SEPT endroits**,
aucun gaté, tous invisibles à `check_artifacts` (le `.py` source n'est pas un
`out/*.json`) :
1. `ecf_dgii_gen.py` docstring module (l.24) ;
2. docstring `_validate` (l.110) ;
3. message de succès CLI `validate` « … schéma + 12 invariants verts. » (l.277) ;
4. aide du sous-parseur `validate` (l.289) ;
5. README bloc de commande « schéma + 12 invariants » (l.65) ;
6. README titre de section « ## Les 12 invariants » (l.69) ;
7. README prose de score « 12 invariants de cross-cohérence » (l.105).
Ajouter un contrôle `# 13 ·` à `_validate` sans toucher les 7 chaînes ⇒ le README
ET les self-reports du `.py` mentent en silence pendant que la CI applique 13
contrôles. Aucune suite `tests/` (qui teste des FONCTIONS de validation, pas la
prose) n'attrape ce « vert trompeur ».
**Particularité du registre fiscal** (≠ SEO/Chat OTOIA au ledger propre 1..N) :
l'**invariant 1 est la validation de SCHÉMA** (`validate(bundle, schema)`, **non
marquée** `# 1 ·`), les marqueurs couvrent **2..N**, et l'invariant **12 est
splitté** en `# 12a ·` (unicité évènements) / `# 12b ·` (comptes du manifeste) —
deux volets d'un même invariant. Le gate reconstruit donc le ledger = `{1:schéma}`
marqueurs-top-level, en collapsant 12a/12b, tout en **mordant un vrai doublon**
d'un numéro NON suffixé.
**Gate ajouté** (`ci/check_readme_claims.sh`, bloc « Fiscal · e-CF DGII · IDENTITÉ
du COMPTE D'INVARIANTS ») — RECOMPUTE le ledger depuis le SEUL registre-source
(`# N ·` de `_validate`) et exige :
- **(a)** ledger CONTIGU 1..N (schéma #1 présent + marqueurs 2..N sans lacune ;
doublon nu = défaut mordu ; 12a/12b comptés 1×) ;
- **(b)** toute mention « N invariants » du `.py` == |ledger| ;
- **(c)** l'annonce du titre README == |ledger| ;
- **(d)** toute mention « N invariants » du README == |ledger| ;
- **(e)** l'ÉNUMÉRATION numérotée du README (« 1. … 2. … N. ») elle-même contiguë
1..N (item ni sauté ni dupliqué).
**Vérif** — 5 checks verts sur l'arbre propre (ledger 1..12 = schéma #1 + 11
marqueurs). **8 morsures** adversariales : M1 self-report `.py` 12→13 (b) · M2
titre README 12→13 (c+d) · M3 mention README 12→13 (d) · M4 ajout marqueur `# 13 ·`
⇒ ledger→13 pendant que la prose reste 12 (b+c+d, preuve que l'autorité est le
CODE, pas la prose) · M5 suppression `# 7 ·` ⇒ gap non-contigu (a) · M6 doublon nu
`# 5 ·` ⇒ détection de vrai doublon · M7 énumération README 7.→8. ⇒ deux 8/pas de
7 (e) · M8 suppression `validate(bundle, schema)` ⇒ invariant 1 introuvable. Gates
re-verts : `check_artifacts` · `check_docs` · `guard_constraints` ·
`check_ci_integrity` · `check_readme_claims` · `check_regression` tous exit 0.