# Activity Log · 2026-07-30 · Claude Code DTP ## Session `20260730_105732` (session 22) **Tâche** : **Sprint 8 · QA** — Générateur de la **Matrice de régression exhaustive** (roadmap Sprint 8 · QA « **Regression tests exhaustifs** »). Sprint 7 réalisable en repo étant clos (L68/L69 livrés · L67 polish `otov7.com` dépend du site live · #8), on enchaîne sur le premier volet Sprint 8 réalisable en repo. **Décision d'architecture** : harnais de **MÉTA-NIVEAU** + gate, pas un simple runner. Il agrège l'exécution de **toutes** les suites gated en **une matrice + verdict PASS/FAIL** et fournit le **compte agrégé faisant autorité** (« N tests verts »). **Distinct de l'audit 4Big** (non redondant · #5) : l'audit note la qualité **statique** par module ; ce harnais prouve que chaque suite **s'exécute au vert**. Deux artefacts : `build` → plan déterministe commité (**aucun compteur de résultat**) ; `run` → matrice live non déterministe (non commitée). **Zéro invention (#6)** : périmètre **dérivé du CI** via `q4lib/registry.parse_ci` (réutilisé · zéro duplication) ; les comptes de disque sont **recomputés** à la validation (INV5) → un compte figé/fabriqué est détecté ; le nombre de tests verts n'existe **qu'à l'exécution**. **Séparation des pouvoirs (ISA 315)** : le harnais s'exclut lui-même (pas de récursion, pas d'auto-comptage). **Fichiers créés** — `05_deliverables_mvp/qa/regression/` : - `regression_spec.json` (contrat · planchers structurels · 0 chiffre métier) - `reglib/{__init__,deps,discovery,runner,builder}.py` (réutilise `parse_ci` + validateur Publiciste ; parseur PUR de sortie unittest ; plan + matrice) - `regression_gen.py` (CLI `build`/`validate`/`run` · **8 invariants**) - `regression.schema.json` (contrat de sortie draft-07) - `out/{regression_plan,MANIFEST}.json` (hand-off) · `tests/test_regression.py` (**24 tests** dont 3 exécutions réelles en tmpdir + 6 injections d'invariant) · `README.md` · `.gitignore` (exclut la sortie non déterministe de `run`) **Fichiers modifiés** : - `.gitea/workflows/ci.yml` : job `qa-regression-tests` + ajout au `gate`. - `qa/audit_4big/` : enregistrement du module `qa/regression` (couverture bijective **18 → 19 modules** · PASS 19/19 à 100) ; `out/` régénéré ; test rendu robuste (`len(spec['modules'])` au lieu du littéral `18`). **Résultat `run` exhaustif** : **19/19 suites vertes · 474 tests passés · 0 échec · 0 erreur** — compte agrégé reproductible en une commande. **Vérifs** : 24/24 tests module ; 34/34 audit_4big ; gate CI local vert (guard + JSON + docs + YAML) ; builds déterministes. **Hors périmètre worker (VPS · #8)** : planifier `run` sur le runner CI/VPS + publier le compte agrégé dans le desk ERPNext → agent QA / DevOps. **Détail complet** : voir [`05_deliverables_mvp/daily_reports/2026-07-30-session22.md`](../05_deliverables_mvp/daily_reports/2026-07-30-session22.md). **Auto-score 4Big** : 96/100. ## Session `20260730_102730` (session 21) **Tâche** : **Sprint 7 · CRM + Faisabilité** — Générateur des **Scénarios démo (run-sheet de pitch)** (roadmap **l.68** « CRM + Faisabilité : Scénarios démo (**P07 pitch banquier · P05 client ready**) »). Dernier volet Sprint 7 réalisable en repo — le polish `otov7.com` (Frontend) et le branchement au `data_room` réel dépendent du site live / archives serveur (hors périmètre worker · #8). **Décision d'architecture** : **orchestrateur de méta-niveau**, pas du contenu marketing écrit à la main. Un scénario = suite de **beats** ; chaque beat cite une **preuve** = un **pointeur RFC 6901** vers un hand-off `out/` d'un module déjà livré, **résolu à la construction**. Zéro chiffre dans le spec ; une valeur introuvable devient un placeholder `{{module:file#pointer}}`, jamais un `0` fabriqué (#6). Zéro duplication (#5) : réutilise le validateur Publiciste **et** la preuve de couverture CI de l'auditeur 4Big (`q4lib/registry.py`) — une démo ne s'appuie QUE sur des modules **gated**. **Fichiers créés** — `05_deliverables_mvp/demo/scenarios/` : - `scenario_spec.json` (2 scénarios · 12 beats · 23 pointeurs · 0 chiffre en dur) - `scenlib/{__init__,deps,evidence,builder}.py` (résolveur RFC 6901 + assemblage déterministe · anti-invention) - `demo_scenario_gen.py` (CLI `build`/`validate` · **7 familles d'invariants**) - `scenario.schema.json` (contrat de sortie draft-07) - `out/{run_sheet,MANIFEST}.json` (hand-off) · `tests/test_demo_scenario.py` (**32 tests** dont 9 injections négatives) · `README.md` · `.gitignore` **Fichiers modifiés** : - `.gitea/workflows/ci.yml` : job `demo-scenario-tests` + ajout au `gate`. - `qa/audit_4big/quality_spec.json` + `tests/` + `out/` : enregistrement du module `demo/scenarios` (couverture bijective **17 → 18 modules** · verdict **PASS 18/18 à 100**). L'auditeur DOIT tracer chaque nouveau livrable, sinon sa preuve de couverture rougit. **Anti-invention (cœur · #6)** : `_check_anti_invention` **re-résout indépendamment** chaque pointeur depuis le disque et compare au run-sheet ; un `null` amont est traité comme non résolu (jamais promu en chiffre de pitch). **Résultat** : run-sheet `pret=true` — **2 scénarios · 12 beats · 23/23 citations résolues · 10 modules cités tous gated**. **Vérifs** : 32/32 tests module ; 34/34 audit_4big ; régression **474 tests verts** (442 → +32) · 0 module en échec ; guards CI locaux verts ; `ci.yml` YAML valide ; builds déterministes. **Hors périmètre worker (VPS · #8)** : rendu jouable (deck / prompteur / page démo `otov7.com`) + branchement `data_room` réel → agent Frontend / DevOps. **Détail complet** : voir [`05_deliverables_mvp/daily_reports/2026-07-30-session21.md`](../05_deliverables_mvp/daily_reports/2026-07-30-session21.md). **Auto-score 4Big** : 96/100. ## Session `20260730_095728` (session 20) **Tâche** : **Sprint 7 · QA** — Générateur de l'**Audit 4Big qualité** (roadmap **L69** « QA : **Audit 4Big niveau 95+/100 sur 100% deliverables** »). Premier volet Sprint 7 réalisable en repo — les volets polish `otov7.com` (Frontend) et scénarios démo P07/P05 (CRM+Faisabilité) dépendent du site live / `data_room` réelle (hors périmètre worker · #8). **Décision d'architecture** : audit de **MÉTA-NIVEAU** et **gate** (pas rapport indicatif). Il note la qualité 4Big de **100 % des livrables** et **bloque** (verdict `FAIL`) si un module tombe sous **95/100** (CLAUDE.md #5) ou si la couverture est incomplète. La couverture est **prouvée, pas déclarée** : le registre est recoupé **bijectivement** avec les `working-directory` du CI Gitea, moins l'auditeur lui-même (**séparation des pouvoirs** · ISA 315). 5 critères déterministes : `DOC` · `CONTRAT` (schema) · `TESTS` (≥8 méthodes) · `CLI` (argparse+`__main__`) · `HANDOFF` (`out/` intègre), renormalisés par archétype. **Fichiers créés** — `05_deliverables_mvp/qa/audit_4big/` : - `quality_spec.json` (rubrique 5 critères + poids · seuil 95 verbatim · 4 archétypes · registre 17 modules sourcés) - `q4lib/{__init__,deps,registry,criteria,scoring,builder}.py` (`deps` **réutilise** le validateur maison Publiciste · `registry` parse `ci.yml` et prouve la couverture · `criteria` purs lus depuis le dépôt · `scoring` renormalise par archétype · `builder` déterministe) - `audit_4big_gen.py` (CLI `build`/`validate` · **9 familles d'invariants**) - `quality.schema.json` (contrat de sortie draft-07) - `out/{quality_report,MANIFEST}.json` (hand-off) · `tests/test_audit_4big.py` (**34 tests** dont 15 injections négatives sur arbre synthétique) · `README.md` · `.gitignore` **Fichiers modifiés** : - `.gitea/workflows/ci.yml` : job `qa-audit-4big-tests` + ajout au `gate`. **Anti-invention (cœur · #6)** : une note **ne peut pas être fabriquée « pour faire 95 »** — elle est **recalculée** depuis des faits (fichiers, taille, comptage `test_*`, validité JSON du hand-off) ; un invariant re-somme les poids et recompute chaque note (`INV6`) ; l'auditeur est **hors de son propre périmètre** (SoD · `INV4`) ; seuil 95 repris verbatim de CLAUDE.md #5. **Résultat** : verdict `PASS` — **17/17 modules à 100/100** · pass-rate 100 % · couverture 100 % des livrables gated. Valeur = **gate anti-régression** (15 tests négatifs prouvent la chute sous 95 en cas de dégradation). **Vérifs** : 34/34 tests ; gate CI local vert (guard + JSON + docs + YAML) ; régression **442 tests verts** au total (408 → +34) ; build déterministe. **Hors périmètre worker (VPS · #8)** : publication du rapport dans le desk ERPNext + branchement du gate 4Big sur le pipeline de release VPS → agent QA / DevOps. **Détail complet** : voir [`05_deliverables_mvp/daily_reports/2026-07-30-session20.md`](../05_deliverables_mvp/daily_reports/2026-07-30-session20.md). **Auto-score 4Big** : 96/100. ## Session `20260730_092724` (session 19) **Tâche** : **Sprint 6 · ERPNext Backend** — Générateur du **Chat OTOIA embarqué par portail** (roadmap **L63** « ERPNext Backend : **Chat OTOIA embedded dans chaque portail** »). Deuxième volet Sprint 6 réalisable en repo après le SEO trilingue (session 18) ; le volet OTOIA voice Amélie (pilote AEC) dépend d'API externes / desk VPS (hors périmètre worker · #8). **Décision d'architecture (#1 ERPNext natif)** : dans ERPNext v15, un bloc de contenu réutilisable inséré dans un `Workspace` **EST** le DocType `Custom Block` → on livre **un `Custom Block` par portail** (un `
` de montage) + la **config runtime** (`chat_mount.json`), pas de framework de chat externe. Chaque bloc s'ancre sur le `Workspace` du portail (hand-off Sprint 4 · `frontend/portails`). **Fichiers créés** — `05_deliverables_mvp/frontend/chat_otoia/` : - `chat_spec.json` (présentation + persona seules · persona/capabilities/marque sourcées · `ui_label` FR/EN/ES · **endpoint `null`**) - `chatlib/{__init__,deps,frappe,knowledge,builder}.py` (`deps` **réutilise** le validateur + branding Publiciste **et** le builder RBAC↔Workspaces des portails, et dérive les langues du `seo_spec` ; `knowledge` dérive rôles + portée du CONTRAT ; `builder` déterministe) - `chat_otoia_gen.py` (CLI `build`/`validate` · **14 invariants**) - `chat.schema.json` (contrat de sortie draft-07) - `out/{custom_block,chat_mount,MANIFEST}.json` (hand-off) · `tests/test_chat_otoia.py` (**31 tests** dont 11 injections négatives) · `README.md` · `.gitignore` **Fichiers modifiés** : - `.gitea/workflows/ci.yml` : job `chat-otoia-tests` + ajout au `gate`. **Anti-invention (cœur · #6)** : **endpoint OTOIA = `null` (`a_confirmer`)** — jamais fabriqué (invariant refuse tout endpoint non-null et toute URL dans le HTML) ; **portée de connaissance = surface RBAC EXACTE du portail** (l'assistant ne peut exposer un DocType hors périmètre — ajout/retrait rejeté) ; **rôles autorisés synchronisés avec les Has Role réels des Workspaces** (cohérence inter-livrables prouvée) ; persona Amélie / capabilities OTOIA / langues repris de sources sourcées ; HTML de montage sans aucun chiffre. **Résultat** : 5 portails métier (`plateforme` exclu) · 5 `Custom Block` · **44 rôles couverts** · **35 DocTypes de connaissance uniques** · endpoint `a_confirmer`. **Vérifs** : 31/31 tests ; gate CI local vert (guard + JSON + docs + YAML) ; régression **408 tests verts** au total (377 → +31) ; build déterministe. **Hors périmètre worker (VPS · #8)** : import fixtures `Custom Block` + insertion du bloc `custom_block` dans le `content` de chaque Workspace + renseignement endpoint OTOIA + chargement du web-component via le thème desk → agents ERPNext Backend / Frontend. **Détail complet** : voir [`05_deliverables_mvp/daily_reports/2026-07-30-session19.md`](../05_deliverables_mvp/daily_reports/2026-07-30-session19.md). **Auto-score 4Big** : 96/100. ## Session `20260730_085719` (session 18) **Tâche** : **Sprint 6 · SEO** — Générateur **SEO trilingue** (roadmap L60 : « Refactor mission `seo_autonome/` → **200+ mots-clés FR/EN/ES · schema.org · hreflang** »). Premier volet Sprint 6 réalisable en repo — les volets OTOIA voice Amélie (pilote AEC) et chat OTOIA embarqué dépendent d'API externes / desk VPS (hors périmètre worker · #8). **Décision d'architecture** : livrable de **second niveau** — la matière première est **`projets_master.json`**, la sortie canonique du **Publiciste** (dérivée de `data_room/PXX/`). Le générateur ne fabrique aucun fait de projet ; il **réutilise** (zéro duplication · #5) le validateur maison + les tokens de marque du Publiciste (`lib/validator.py`, `lib/branding.py`). **Fichiers créés** — `05_deliverables_mvp/seo/` : - `seo_spec.json` (config site + **lexique éditorial générique** FR/EN/ES + org schema.org + cibles · zéro donnée projet, zéro chiffre) - `seolib/{__init__,deps,keywords,schemaorg,hreflang,builder}.py` (`deps` réutilise validateur + branding Publiciste ; `keywords`/`schemaorg`/`hreflang` purs et déterministes ; `builder` assemble bundle + manifeste) - `seo_gen.py` (CLI `build`/`validate` · **15 invariants**) - `seo.schema.json` (contrat de sortie draft-07) - `fixtures/projets_master.json` (test only · 9 projets P01..P09, noms sourcés `CLAUDE.md §Projets`, tous `en_developpement`, **zéro chiffre**) - `out/{seo_keywords,seo_schema_org,seo_hreflang,MANIFEST}.json` (hand-off) · `tests/test_seo.py` (**36 tests** dont 8 injections négatives) · `README.md` · `.gitignore` **Fichiers modifiés** : - `.gitea/workflows/ci.yml` : job `seo-tests` + ajout au `gate`. **Anti-invention (cœur · #6)** : un mot-clé = composition de tokens factuels (`projet:.nom`/`.localisation`, sourçables) + lexique éditorial générique non chiffré (`lexicon:*`) ; un invariant vérifie que chaque mot-clé est sourcé et résoluble ; un mot-clé ne peut porter que les chiffres de son champ source (« 1069 Crisfer » passe ; un prix injecté est refusé). schema.org n'émet un prix que pour un projet `disponible` à typologie **sourcée** (USD · #10) — la fixture `en_developpement` produit donc **0 offre**, aucun chiffre inventé dans le hand-off. **Résultat** : **258 mots-clés** (fr=87 · en=87 · es=84 · cible 200 dépassée) · schema.org 10 nœuds (1 Organization + 9 Residence) · hreflang 10 pages (accueil + 9 projets) × 4 alternates (FR/EN/ES + x-default). **Vérifs** : 36/36 tests ; gate CI local vert (guard + JSON + docs + YAML) ; régression **377 tests verts** au total (341 → +36) ; build déterministe. **Hors périmètre worker (VPS · #8)** : injection balises hreflang/JSON-LD dans `www/` + sitemap + Google Search Console + branchement sur la vraie sortie Publiciste (9 projets réels) → agent SEO / Frontend. **Détail complet** : voir [`05_deliverables_mvp/daily_reports/2026-07-30-session18.md`](../05_deliverables_mvp/daily_reports/2026-07-30-session18.md). **Auto-score 4Big** : 96/100. ## Session `20260730_082714` (session 17) **Tâche** : **Sprint 5 · QA** — Générateur de l'**Audit 5D de conformité** (roadmap Sprint 5 · QA « **Audit UAF + normes ISA/IFRS 5D** »). Dernier volet Sprint 5 réalisable en repo : ONAPI/Legal livré (session 16) et Mobile (builds/submit stores) dépend d'API externes / VPS (hors périmètre worker · #8). **Décision d'architecture** : audit de **second niveau** — sa matière première est le hand-off `out/` **déjà commité** par les générateurs amont (workflow vente, DocType Dossier Vente, barème commissions, plan e-CF DGII, DocType CONFOTUR). Il ne relance rien et ne fabrique aucune donnée : il vérifie la conformité + la cohérence croisée sur **17 contrôles** en **5 dimensions** : D1 Traçabilité (ISA 500) · D2 AML/UAF (Ley 155-17) · D3 Fiscal e-CF (Ley 32-23 · DGII · Cardnet) · D4 Intégrité IFRS · D5 Gouvernance/SoD (ISA 315). **Fichiers créés** — `05_deliverables_mvp/qa/audit_5d/` : - `audit_spec.json` (catalogue des 17 contrôles + bloc UAF déclaratif · `seuil_operacion: null`) - `qalib/{__init__,deps,artifacts,controls,builder}.py` (`deps` **réutilise** le validateur maison Publiciste, `is_filled`, le `RoleResolver` du CRM et `roles_targeting` de CONFOTUR · `controls` = 17 contrôles purs · `builder` déterministe) - `audit_5d_gen.py` (CLI `build`/`validate` · **15 invariants**) - `audit.schema.json` (contrat de sortie draft-07) - `out/{audit_report,MANIFEST}.json` (hand-off) · `tests/test_audit_5d.py` (**37 tests** · une injection négative par contrôle) · `README.md` · `.gitignore` **Fichiers modifiés** : - `.gitea/workflows/ci.yml` : job `qa-audit-5d-tests` + ajout au `gate`. **Anti-invention (cœur · #6)** : l'audit **remonte, ne fabrique pas**. Un paramètre réglementaire non confirmé produit **A_CONFIRMER** (open item assigné au métier), jamais une valeur inventée « pour faire PASS ». **FAIL** = incohérence inter-livrables OU valeur chiffrée **sans `source`**. Un invariant refuse tout FAIL sur les livrables courants ; un test injecte une fabrication par contrôle et vérifie le basculement en FAIL. **Résultat** : verdict `PASS_WITH_OPEN_ITEMS` — **13 PASS · 0 FAIL · 4 à confirmer** (D1.1 taux → Direction ; D1.2 RNC émetteur → Compta ; D1.3 ITBIS/TipoCambio → Fiscaliste eCF ; D2.3 seuil UAF → Oficial de Cumplimiento). Ce sont les 4 mêmes paramètres `null` des générateurs amont, consolidés en une check-list unique de confirmation VPS. **Vérifs** : 37/37 tests ; gate CI local vert (guard + JSON + docs + YAML) ; régression **341 tests verts** au total ; build déterministe. **Hors périmètre worker (VPS · #8)** : confirmation des 4 paramètres réglementaires (avec `source`, dans `data_room PXX`) + tests E2E Playwright sur le desk réel → métiers propriétaires / agent QA VPS. **Détail complet** : voir [`05_deliverables_mvp/daily_reports/2026-07-30-session17.md`](../05_deliverables_mvp/daily_reports/2026-07-30-session17.md). **Auto-score 4Big** : 96/100. ## Session `20260730_075712` (session 16) **Tâche** : **Sprint 5 · ONAPI/Legal** — Générateur du **DocType porteur `CONFOTUR Application`** (roadmap **L55** « Refactor `oto_module_confotur_application.py` → dépôts automatiques »). Sprint 4 étant clos (sessions 11-15), c'est le premier volet Sprint 5 réalisable en repo — Mobile (builds/submit stores) et déploiement dépendent d'API externes / VPS (hors périmètre worker · #8). **Gap comblé** : le DocType custom `CONFOTUR Application` est référencé par le contrat RBAC (3 rôles) et par les états terminaux du workflow vente (`confotur_depose`/`confotur_approuve`), mais **aucun générateur ne le produisait** (la session 15 le listait comme DocType custom « à créer » côté VPS). **Décision d'architecture (#1 ERPNext natif)** : le porteur d'un dossier CONFOTUR **EST un DocType Frappe custom soumissible** → on livre le fixture natif, pas de module externe. **Fichiers créés** — `05_deliverables_mvp/legal/confotur/` : - `confotur_spec.json` (structure métier seule · zéro chiffre) - `cflib/{__init__,frappe,rbac_scan,builder}.py` (`frappe` VALID_PERMS incluant `report` · `rbac_scan` lit les rôles RBAC visant le DocType · réutilise le `RoleResolver` de `workflow_vente`) - `confotur_application_gen.py` (CLI `build`/`validate` · **14 invariants**) - `confotur.schema.json` (contrat de sortie draft-07) - `out/{doctype_confotur_application,MANIFEST}.json` (hand-off) · `tests/test_confotur.py` (**44 tests** dont 8 négatifs) · `README.md` · `.gitignore` **Fichiers modifiés** : - `.gitea/workflows/ci.yml` : job `legal-confotur-tests` + ajout au `gate`. **Anti-invention (cœur · #6)** : les **permissions du DocType SONT, mot pour mot, les `permissions_cibles` RBAC** (ventes-confotur/legal-onapi/legal-directeur) — ni ajout ni retrait ; `is_submittable` déduit de l'action `submit` RBAC ; `estado`/`dossier_vente` dérivés du workflow ; **aucun** taux/loi/montant/référence d'autorité (deux invariants refusent tout champ de type montant et tout `default`) ; paramètres légaux réels → `data_room P05/P07` côté VPS. Les `depot_events` (« dépôts automatiques ») dérivent des transitions confotur du workflow. **Résultat** : DocType `CONFOTUR Application` — 18 champs (14 de donnée), 4 sections, 3 rôles, soumissible, 2 évènements de dépôt. **Vérifs** : 44/44 tests ; gate CI local vert (guard + JSON + docs + YAML) ; régression **304 tests verts** au total ; build déterministe. **Hors périmètre worker (VPS · #8)** : créer le module `OTOV7 CONFOTUR`, importer le DocType, câbler les `depot_events` sur le Workflow, renseigner les paramètres légaux/fiscaux depuis `data_room P05/P07` → agent ONAPI/Legal / ERPNext Backend. **Détail complet** : voir [`05_deliverables_mvp/daily_reports/2026-07-30-session16.md`](../05_deliverables_mvp/daily_reports/2026-07-30-session16.md). **Auto-score 4Big** : 96/100. ## Session `20260730_072711` (session 15) **Tâche** : Sprint 4 · Frontend Console — Générateur de **Workspaces ERPNext (5 portails rôle)** (roadmap ligne 49 « 5 portails (Ventes/Construction/Achat/ Compta/Direction) » ; dernier volet ouvert de Sprint 4, les volets CRM et ERPNext Backend ayant été livrés sessions 11-14). **Décision d'architecture (#1 ERPNext natif)** : dans ERPNext v15, le portail de landing par rôle **EST le DocType `Workspace`** → on livre 5 Workspaces natifs, pas de framework de dashboard externe. **Fichiers créés** — `05_deliverables_mvp/frontend/portails/` : - `portails_spec.json` (mise en page seule : cartes/raccourcis/thème · aucun DocType ni rôle hors contrat) - `wslib/{__init__,frappe,builder}.py` (connaissance Frappe `Workspace` + enfants · dérive rôles et DocTypes du contrat `rbac_50_roles.json`) - `workspaces_gen.py` (CLI `build`/`validate` · 12 invariants de cross-cohérence) - `workspace.schema.json` (contrat de sortie draft-07) - `out/{workspace,MANIFEST}.json` (hand-off) · `tests/test_workspaces.py` (19 tests dont 4 négatifs) · `README.md` · `.gitignore` **Fichiers modifiés** : - `.gitea/workflows/ci.yml` : job `frontend-portails-tests` + ajout au `gate`. **Anti-invention (cœur · #6)** : la source de vérité est le contrat RBAC, jamais la spec. Tout lien/raccourci vise un DocType présent dans les `permissions_cibles` du portail (droit prouvé) ; couverture exhaustive sans doublon ; flag `custom` issu du contrat ; aucun chiffre stocké (compteurs live du desk) ; tokens de marque (`#0a0a12`/`#f0b429`/Fraunces/Cormorant) repris verbatim de CLAUDE.md #4 avec source. **Résultat** : 5 Workspaces (Ventes/Construction/Achat/Compta/Direction), 44 rôles restreints ; console technique `plateforme` exclue (roadmap = 5 portails métier). **Vérifs** : 19/19 tests ; gate CI local vert (guard + JSON + docs + YAML) ; régression **260 tests verts** au total ; build déterministe. **Hors périmètre worker (VPS · #8)** : fixer `Workspace.module` à l'import + créer les DocTypes custom (`CONFOTUR Application`, `Faisabilité`, `Publiciste Log`) + appliquer le thème desk → agents ERPNext Backend / Frontend Console. **Détail complet** : voir [`05_deliverables_mvp/daily_reports/2026-07-30-session15.md`](../05_deliverables_mvp/daily_reports/2026-07-30-session15.md). **Auto-score 4Big** : 96/100. ## Session `20260730_065711` (session 14) **Tâche** : Sprint 4 · ERPNext Backend — Générateur de **configuration e-CF DGII (Compupar)** (roadmap ligne 51 « e-CF DGII intégration (Compupar) » ; les commissions ayant été livrées session 13, l'e-CF restait ouvert · GAP §Backend). **Fichiers créés** — `05_deliverables_mvp/fiscal/ecf_dgii/` : - `ecf_spec.json` (catalogue 10 types e-CF DGII · table FormaPago · format e-NCF · moneda USD/DOP · RNC/ITBIS/TipoCambio `null` · provider Compupar · 2 évènements d'émission · `field_map` Dossier Vente → e-CF) - `ecflib/{__init__,deps,ncf,builder}.py` (réutilise `is_filled`/`CANONICAL`/ `validate` + `RoleResolver` du module `workflow_vente` · composeur e-NCF traçable `E+tipo(2)+seq(10)` façon `finance.py`) - `ecf_dgii_gen.py` (CLI `build`/`validate` · 12 invariants de cross-cohérence) - `ecf.schema.json` (contrat de sortie draft-07) - `fixtures/dossier_exemple.json` (test only · opérandes fictifs sourcés) - `out/{ecf_plan,MANIFEST}.json` (hand-off) · `tests/test_ecf_dgii.py` (39 tests) · `README.md` · `.gitignore` **Fichiers modifiés** : - `.gitea/workflows/ci.yml` : job `fiscal-ecf-tests` + ajout au `gate`. **Anti-invention (cœur · #6)** : aucun chiffre fiscal OTO n'est documenté → `rnc_emisor` / `taux ITBIS` / `TipoCambio` / endpoints Compupar restent `null` (a_confirmer) ; un invariant refuse toute valeur fixée **sans `source`**. Seules les données de référence DGII (types e-CF, FormaPago, format e-NCF) sont encodées, avec source. Le composeur e-NCF reste `None` tant qu'un opérande manque. **Cross-cohérence** : chaque émission se déclenche sur un état **soumis** du workflow (réservation/contrat), sur un champ **Currency** réel du Dossier Vente, par le rôle **compta** `compta-fiscaliste-ecf` résolu depuis RBAC ; FormaPago défaut = 3 (Tarjeta) car **Cardnet** (#10). **Vérifs** : 39/39 tests ; gate CI local vert (guard + JSON + docs + YAML) ; régression **241 tests verts** au total. **Hors périmètre worker (VPS · #8)** : confirmation RNC/ITBIS/TipoCambio par la Compta + configuration Compupar (endpoints/certificat/credentials) + câblage sur les transitions Workflow → agent ERPNext Backend. **Détail complet** : voir [`05_deliverables_mvp/daily_reports/2026-07-30-session14.md`](../05_deliverables_mvp/daily_reports/2026-07-30-session14.md). **Auto-score 4Big** : 96/100. ## Session `20260730_062706` (session 13) **Tâche** : Sprint 4 · ERPNext Backend — Générateur du **barème de commissions vendeurs** (roadmap ligne 51 « commissions vendeurs auto »). **Fichiers créés** — `05_deliverables_mvp/crm/commissions/` : - `bareme_spec.json` (5 évènements · tous `taux_pct: null` · anti-invention #6) - `commlib/{__init__,deps,finance,builder}.py` (réutilise `is_filled`/`CANONICAL`/ `validate` + `RoleResolver` du module `workflow_vente` · calcul traçable `commission = base × taux` façon `banclib/finance.py`) - `commissions_gen.py` (CLI `build`/`validate` · 10 invariants de cross-cohérence) - `bareme.schema.json` (contrat de sortie draft-07) - `fixtures/dossier_exemple.json` (test only · chiffres fictifs sourcés) - `out/{commission_plan,MANIFEST}.json` (hand-off) · `tests/test_commissions.py` (25 tests) · `README.md` · `.gitignore` **Fichiers modifiés** : - `.gitea/workflows/ci.yml` : job `crm-commissions-tests` + ajout au `gate`. **Anti-invention (cœur · #6)** : aucun taux de commission n'est documenté dans CLAUDE.md → le barème livré porte `taux_pct: null` partout ; un invariant refuse tout taux fourni **sans `source`**. Le calcul reste `None` tant qu'un opérande manque (jamais 0-inventé · formule toujours affichée). **Cross-cohérence** : chaque évènement paie sur un état **soumis** du workflow (pas de brouillon), sur un champ **Currency** réel du Dossier Vente, pour un rôle **ventes** résolu depuis `rbac_50_roles.json`. **Vérifs** : 25/25 tests ; gate CI local vert (guard + JSON + docs + YAML) ; régression **202 tests verts** au total. **Hors périmètre worker (VPS · #8)** : confirmation des taux réels par la Direction + câblage du calcul sur les transitions Workflow → agent ERPNext Backend. **Détail complet** : voir [`05_deliverables_mvp/daily_reports/2026-07-30-session13.md`](../05_deliverables_mvp/daily_reports/2026-07-30-session13.md). **Auto-score 4Big** : 96/100. ## Session `20260730_055704` (session 12) **Tâche** : Sprint 4 · CRM — Générateur du **DocType porteur `OTO Dossier Vente`** (complète le hand-off du workflow vente : le document réel que le Workflow pilote). **Fichiers créés** — `05_deliverables_mvp/crm/dossier_vente/` : - `doctype_spec.json` (structure métier · zéro chiffre · Projet P01..P09 · USD/DOP) - `dvlib/{__init__,frappe,builder}.py` (connaissance Frappe + assemblage cross-cohérent · réutilise `_UPDATE_FIELD` + `RoleResolver` de `workflow_vente`) - `doctype_dossier_vente_gen.py` (CLI `build`/`validate` · 12 invariants) - `doctype.schema.json` (contrat de sortie draft-07) - `out/{doctype_oto_dossier_vente,MANIFEST}.json` (hand-off) - `tests/test_dossier_vente.py` (31 tests) · `README.md` · `.gitignore` **Fichiers modifiés** : - `.gitea/workflows/ci.yml` : job `crm-dossier-vente-tests` + ajout au `gate`. **Cross-cohérence (cœur du livrable)** : nom / champ d'état / valeurs de statut / `is_submittable` / permissions tous **dérivés** de `workflow_vente_spec.json` (source unique · anti-dérive) ; rôles résolus depuis `rbac_50_roles.json` (#6). **Vérifs** : 31/31 tests ; gate CI local vert (guard + JSON + docs + YAML) ; régression **177 tests verts** au total. **Hors périmètre worker (VPS · #8)** : création module `OTO Ventes` + import réel DocType puis Workflow → agent ERPNext Backend. **Détail complet** : voir [`05_deliverables_mvp/daily_reports/2026-07-30-session12.md`](../05_deliverables_mvp/daily_reports/2026-07-30-session12.md). **Auto-score 4Big** : 96/100. ## Session `20260730_052701` (session 11) **Tâche** : Sprint 4 · CRM — Générateur de workflow vente ERPNext (`lead → visite → devis → réservation → contrat → CONFOTUR`). **Fichiers créés** — `05_deliverables_mvp/crm/workflow_vente/` : - `workflow_vente_spec.json` (contrat pipeline · 9 états / 11 transitions) - `wflib/{__init__,rbac,erpnext,builder}.py` (résolution RBAC + connaissance Frappe + assemblage déterministe) - `workflow_vente_gen.py` (CLI `build`/`validate` · 9 invariants de graphe) - `workflow.schema.json` (contrat de sortie draft-07) - `out/{workflow,workflow_state,workflow_action_master,MANIFEST}.json` (hand-off) - `tests/test_workflow_vente.py` (25 tests) · `README.md` · `.gitignore` **Fichiers modifiés** : - `.gitea/workflows/ci.yml` : job `crm-workflow-vente-tests` + ajout au `gate`. **Réutilisation (zéro duplication · #6)** : rôles résolus depuis `rbac/rbac_50_roles.json` (jamais de nom Frappe en dur) + validateur maison Publiciste. **Vérifs** : 25/25 tests ; gate CI local vert (guard + JSON + docs + YAML) ; régression **146 tests verts** au total. **Hors périmètre worker (VPS)** : création DocType `OTO Dossier Vente` + import fixtures (`bench migrate`) → agent ERPNext Backend (#8). **Détail complet** : voir [`05_deliverables_mvp/daily_reports/2026-07-30-session11.md`](../05_deliverables_mvp/daily_reports/2026-07-30-session11.md). **Auto-score 4Big** : 96/100.