d429fccf9a
Le bloc « Fiscal · CONTRAT DE FORMAT » ancrait le format DGII
(E + tipoeCF(2) + secuencia(10) = 13 · Ley 32-23) sur ecf_plan.json[e_ncf]
byte-gaté, mais UNIQUEMENT sur 4 surfaces de PROSE (README x3 + fiche
erpnext_backend). Le composeur d'exécution ecflib/ncf.py — qui VALIDE et
COMPOSE réellement l'e-NCF cote VPS — portait 3 copies INDÉPENDANTES du
format (ENCF_RE regex de validation · FORMULE publiée par compose_encf ·
docstring/commentaire), + un oracle de test hardcodé, tous NON gatés.
Silent-green : un rango DGII a 12 chiffres régénère ecf_spec->ecf_plan (les
4 proses suivent) mais laisse ENCF_RE a {2}{10} => is_valid_encf REJETTE un
e-NCF valide (bug runtime) pendant que tests/ reste VERT (oracle == FORMULE
périmée). check_artifacts (pas un out/*.json) et tests/ (teste les fonctions,
pas leur ancrage) sont aveugles.
Gate : extension du bloc e-NCF (surfaces 5->9) réutilisant prefix/tipo/seq/
total + ecf_check déja dérivés (zéro re-dérivation du format · #6). 7 morsures
adversariales dont M6 SILENT-GREEN (artefact seq 10->12, ncf.py inchangé =>
les 5 surfaces mordent, autorité = artefact). 39 tests unittest verts. 6 gates
CI re-verts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
369 lines
23 KiB
Markdown
369 lines
23 KiB
Markdown
# Activity log · 2026-08-02 · Claude Code DTP Worker
|
||
|
||
## Sprint 8 · buffer · Fiscal e-CF — ancrage du CONTRAT DE FORMAT e-NCF dans le COMPOSEUR `ncf.py` (CODE) + son ORACLE de test
|
||
|
||
**Contexte** — Série anti-dérive Sprint 8 (CLAUDE.md #6 « zéro invention de
|
||
chiffres »). Le bloc « Fiscal · e-CF DGII · CONTRAT DE FORMAT » existant ancre le
|
||
format de l'identifiant fiscal DGII (`E + tipoeCF(2) + secuencia(10)` = 13,
|
||
Ley 32-23) sur le SEUL bloc `e_ncf` byte-gaté de `out/ecf_plan.json` (dérivé de
|
||
`ecf_spec.json`) et couvre **4 surfaces de PROSE** : README ×3 + fiche
|
||
`erpnext_backend`. Mais le **composeur d'exécution lui-même** — `ecflib/ncf.py`,
|
||
le code Frappe qui VALIDE et COMPOSE réellement le numéro e-NCF côté VPS/Compupar
|
||
— porte **TROIS copies INDÉPENDANTES du format, AUCUNE dérivée de l'artefact**, +
|
||
un oracle de test qui les bénit, tous **NON gatés** :
|
||
|
||
1. `ENCF_RE = re.compile(r"^E([0-9]{2})([0-9]{10})$")` (l.26) — la **regex de
|
||
VALIDATION** (cœur de `is_valid_encf`/`parse_encf`) ;
|
||
2. `FORMULE = "E + tipoeCF(2) + secuencia(10)"` (l.27) — la chaîne **publiée par
|
||
`compose_encf`** (renvoyée au caller VPS) ;
|
||
3. docstring l.8 « `"E" + tipoeCF (2 chiffres) + secuencia (10 chiffres) → 13
|
||
caracteres` » + commentaire l.25 « Ley 32-23 : E + tipo(2) + secuencia(10) =
|
||
13 » (deux proses-en-code) ;
|
||
4. `tests/test_ecf_dgii.py:246` — oracle hardcodé `assertEqual(…["formule"],
|
||
"E + tipoeCF(2) + secuencia(10)")`.
|
||
|
||
**Le « vert trompeur »** — un rango DGII à 12 chiffres (évènement ops réel, cité
|
||
dans le commentaire du gate existant) régénère `ecf_spec→ecf_plan`, donc les 4
|
||
proses gatées SUIVENT. Mais `ENCF_RE` reste `{2}{10}` : `compose_encf` zfill à 10
|
||
et `is_valid_encf` **REJETTE** un e-NCF désormais valide → **bug d'exécution du
|
||
composeur fiscal**, pendant que la suite `tests/` reste **VERTE** (son oracle ==
|
||
`FORMULE` périmée, self-consistante). Ni `check_artifacts` (`ncf.py` n'est pas un
|
||
`out/*.json`) ni `tests/` (teste les FONCTIONS, pas leur ANCRAGE à l'artefact) ne
|
||
mordent. Même patron que l'oracle/formateur du Publiciste déjà gaté.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, extension du bloc e-NCF · surfaces
|
||
5→9) — RÉUTILISE `prefix/tipo_len/seq_len/total` déjà dérivés du bloc `e_ncf`
|
||
byte-gaté + le helper `ecf_check` (zéro re-dérivation du format #6). Ancre les 5
|
||
surfaces CODE/test au SEUL artefact : (5) `ENCF_RE`, (6) `FORMULE`, (7) docstring,
|
||
(8) commentaire, (9) oracle de test. Une surface absente échoue AUSSI (INTROUVABLE
|
||
· anti-évaporation #6).
|
||
|
||
**Vérif** — 5 checks verts sur l'arbre propre. **7 morsures** adversariales :
|
||
M1 `ENCF_RE {10}→{12}` · M2 `FORMULE secuencia(10)→(12)` · M3 docstring `10→12
|
||
chiffres` · M4 commentaire `secuencia(10)→(12)` · M5 oracle test `(10)→(12)` ·
|
||
**M6 SILENT-GREEN — l'ARTEFACT passe à seq=12 pendant que `ncf.py` reste à 10 ⇒
|
||
les 5 surfaces mordent TOUTES (preuve que l'autorité est l'artefact byte-gaté, pas
|
||
la cohérence interne du composeur)** · M7 `FORMULE` renommée ⇒ INTROUVABLE. Les
|
||
**39 tests unittest** e-CF restent verts (composeur inchangé). Gates re-verts :
|
||
`check_artifacts` · `check_ci_integrity` · `check_docs` · `check_readme_claims` ·
|
||
`check_regression` · `guard_constraints` tous exit 0.
|
||
|
||
---
|
||
|
||
## Sprint 8 · buffer · CRM Commissions — gate d'IDENTITÉ du COMPTE D'INVARIANTS de `_validate` (7ᵉ 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**, **Legal CONFOTUR**,
|
||
**CRM Dossier Vente** et **QA Audit 5D**. Le **7ᵉ générateur** — dernier candidat
|
||
restant recensé au ledger (`crm/commissions` ·10) — était NON gaté :
|
||
`crm/commissions/commissions_gen.py` (barème de commissions vendeurs · roadmap l.51).
|
||
|
||
Le compte **« 10 invariants »** y est transcrit **à la main à CINQ endroits**,
|
||
aucun gaté, tous invisibles à `check_artifacts` (le `.py` source n'est pas un
|
||
`out/*.json`) :
|
||
1. message de succès CLI `validate` « … schéma + 10 invariants verts. » (l.209) ;
|
||
2. aide du sous-parseur `validate` « schéma + 10 invariants » (l.221) ;
|
||
3. README bloc de commande « schéma + 10 invariants » (l.60) ;
|
||
4. README titre de section « ## Les 10 invariants » (l.64) ;
|
||
5. README prose de score « 10 invariants de cross-cohérence » (l.92).
|
||
|
||
Ajouter un contrôle `# 11 ·` à `_validate` sans toucher les 5 chaînes ⇒ le README
|
||
ET les self-reports du `.py` mentent en silence pendant que la CI applique 11
|
||
contrôles. Aucune suite `tests/` (qui teste des FONCTIONS de validation, pas la
|
||
prose) n'attrape ce « vert trompeur ».
|
||
|
||
**Particularité du registre Commissions** (≈ Dossier Vente) : le ledger est
|
||
**PROPRE 1..10** — 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 la
|
||
détection de doublon nu comme filet. Le module porte AUSSI un **SECOND nombre** —
|
||
« **25 tests** » (la suite unittest, déjà gatée par ailleurs) présent dans le
|
||
README : l'ancre sur le mot « invariants » l'exclut nativement (« 25 tests » ≠
|
||
« invariants ») ⇒ aucun faux positif. Comme Dossier Vente, ce README A un titre
|
||
« ## Les N invariants » ET une énumération numérotée du ledger → on gate (a)(b)(c)(d)(e).
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, bloc « CRM · Commissions · 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 · anti-évaporation).
|
||
|
||
**Vérif** — 5 checks verts sur l'arbre propre (ledger 1..10 = 10 marqueurs
|
||
`# N ·`, schéma compté à part). **7 morsures** adversariales : M1 self-report
|
||
`.py` 10→11 (b) · M2 titre README 10→11 (c+d) · M3 prose README 10→11 (d) · **M4
|
||
ajout marqueur `# 11 ·` ⇒ ledger→11 pendant que la prose reste 10 (mord `.py` ET
|
||
README titre/mention 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). Le distinct
|
||
« 25 tests » reste INVISIBLE au gate (ancre « invariants »). Gates re-verts :
|
||
`check_artifacts` · `check_docs` · `guard_constraints` · `check_ci_integrity` ·
|
||
`check_regression` · `check_readme_claims` tous exit 0. **Série ledger close : les
|
||
7 générateurs portant le nombre magique d'invariants sont désormais tous gatés.**
|
||
|
||
---
|
||
|
||
## Sprint 8 · buffer · QA Audit 5D — gate d'IDENTITÉ du COMPTE D'INVARIANTS de `_validate` (6ᵉ 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**, **Legal CONFOTUR** et
|
||
**CRM Dossier Vente**. Le **6ᵉ générateur** portant le même nombre magique restait
|
||
NON gaté : `qa/audit_5d/audit_5d_gen.py` (candidat restant recensé : `crm/commissions`
|
||
·10, ledger propre non gaté).
|
||
|
||
Le compte **« 15 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 sous-commande module (l.19 « valide schéma + 15 invariants ») ;
|
||
2. docstring `_validate` (l.80 « 15 invariants de cohérence audit/contrôles ») ;
|
||
3. message de succès CLI `validate` « … 15 invariants — verdict … » (l.218) ;
|
||
4. aide du sous-parseur `validate` « valide schéma + 15 invariants » (l.229) ;
|
||
5. README bloc de commande « schéma + 15 invariants » (l.66) ;
|
||
6. README prose d'architecture « CLI build/validate + **15 invariants** » (l.81).
|
||
|
||
Ajouter un contrôle `# 16 ·` à `_validate` sans toucher les 6 chaînes ⇒ le README
|
||
ET les self-reports du `.py` mentent en silence pendant que la CI applique 16
|
||
contrôles. Aucune suite `tests/` (qui teste des FONCTIONS de validation, pas la
|
||
prose) n'attrape ce « vert trompeur ».
|
||
|
||
**Particularité du registre Audit 5D** (≈ Dossier Vente, ≠ Fiscal) : le ledger est
|
||
**PROPRE 1..15** — 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 la détection
|
||
de doublon nu comme filet. MAIS le module porte un **SECOND nombre distinct** —
|
||
« **17 contrôles** » (le compte de fonctions-contrôle de `qalib/controls.py`, déjà
|
||
gaté par ailleurs), présent dans le `.py` ET le README : un `\d+ invariants` ancré
|
||
sur le mot « invariants » l'**exclut nativement** (« 17 contrôles » ≠ mot
|
||
« invariants ») ⇒ **aucun faux positif** sur l'arbre propre. Contrairement à
|
||
Dossier Vente/Fiscal, ce README n'a **NI titre « ## Les N invariants » NI
|
||
énumération numérotée** du ledger → on ne gate que (a)(b)(d).
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, bloc « QA · Audit 5D · 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| ;
|
||
- **(d)** toute mention « N invariants » du README == |ledger|.
|
||
Une mention ou le registre absent échoue AUSSI (traçabilité #6 · anti-évaporation).
|
||
|
||
**Vérif** — 3 checks verts sur l'arbre propre (ledger 1..15 = 15 marqueurs `# N ·`,
|
||
schéma compté à part). **6 morsures** adversariales : M1 self-report `.py` 15→16
|
||
(b) · M2 mention README 15→16 (d) · **M3 ajout marqueur `# 16 ·` ⇒ ledger→16 pendant
|
||
que la prose reste 15 (mord `.py` ET README, preuve que l'autorité est le CODE)** ·
|
||
M4 suppression `# 7 ·` ⇒ gap non-contigu (a) · M5 doublon nu `# 5 ·` ⇒ détection de
|
||
vrai doublon (a) · **M6 no-false-positive** : le distinct « 17 contrôles » reste
|
||
INVISIBLE au gate (l'ancre « invariants » l'exclut, arbre propre VERT). Gates
|
||
re-verts : `check_artifacts` · `check_docs` · `guard_constraints` ·
|
||
`check_ci_integrity` · `check_regression` · `check_readme_claims` tous exit 0.
|
||
|
||
---
|
||
|
||
## 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.
|