Files

134 lines
7.6 KiB
Markdown
Raw Permalink 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.
# Générateur de dossier financier bancable trilingue FR/EN/ES · Sprint 3
> Livrable **Faisabilité · Sprint 3** — roadmap
> [`ROADMAP_8_WEEKS_OR_LESS.md`](../../../04_roadmap/ROADMAP_8_WEEKS_OR_LESS.md)
> §Sprint 3 « Faisabilité Auto » (Faisabilité → « génération 4 volets <1h »). Le volet
> **financier bancable FR/EN/ES** est la déclinaison S3 planifiée dans les
> [`daily_reports`](../../daily_reports) (« `40_llm_outputs/` + rapports bancables
> FR/EN/ES ») — un libellé de planification, **pas** un texte du fichier roadmap —
> exigée par le **Portail Bancables 4Big** (ci-dessous).
> ⚠️ **Statut migration V18.** D'après la cartographie de l'audit de migration V12→V18,
> **ce module `bancable` est la graine V12 des moteurs financiers V18** : Section 15
> **Bankability** (« le plus mûr » du mapping) et, partiellement, Section 12
> **Financier/DCF**. Il est à ce titre au **cœur du risque de migration le plus grave
> (R1 🔴)** : généraliser ce *snapshot* statique (coût · revenu · marge · point d'équilibre
> en unités) vers les **moteurs Financial (4)** et **Bankability (8)** exige les formules
> **DCF · IRR/VAN · DSCR/LTV/LTC** — **absentes du code lisible** (`grep` sur `banclib/`
> ne rend rien) et **non devinables** sans les rendre lisibles côté Michel (#6). Toute la
> séquence moteur V18 est par ailleurs **suspendue** à l'approbation de l'audit. **Ne
> coder aucun de ces moteurs avant arbitrage.** La documentation ci-dessous décrit l'**état
> V12 commité** — *pas* la cible V18.
> Sources : [`DIRECTIVE_V18_MASTER_FEASIBILITY_ENGINE_20260810.md`](../../../DIRECTIVE_V18_MASTER_FEASIBILITY_ENGINE_20260810.md) ·
> [`OTO_V18_MIGRATION_ARCHITECTURE_AUDIT_20260810.md`](../../../OTO_V18_MIGRATION_ARCHITECTURE_AUDIT_20260810.md) (§3 mapping · §5 · R1) ·
> [`OPEN_DECISIONS_REGISTER.md`](../../OPEN_DECISIONS_REGISTER.md) (D-06 · D-07).
Remplit le répertoire `50_financier_bancable/` d'une data_room — jusqu'ici **vide**
(`.gitkeep` posé par le générateur 4 volets) — que le **Portail Bancables 4Big**
([`PORTAIL_BANCABLES_4BIG.md`](../../../PORTAIL_BANCABLES_4BIG.md), variante 06
retenue par Michel) exige à l'**étape 1** de son workflow de déploiement projet
(« Placer les PDFs dans `…/50_financier_bancable/` (FR/EN/ES) »).
## Place dans la chaîne de valeur
```
brief.json ─► faisabilite_gen ─► data_room/PXX/ (4 volets · template v1.0)
bancable_gen ───┤ (ce module · MÊME brief)
data_room/PXX/50_financier_bancable/{fr,en,es}.md + manifest.json
▼ (VPS · hors périmètre worker · #8)
PDFs FR/EN/ES ─► Portail Bancables 4Big (privé · noindex)
```
Le module **ferme le dernier trou** de la faisabilité auto : les 4 volets étaient
produits et notés, mais le dossier **financier bancable** (l'artefact que voit le
banquier) restait à écrire à la main, en trois langues. Il consomme le **même
`brief.json`** que le générateur 4 volets — une seule source, zéro re-saisie.
## Trois langues imposées
`PORTAIL_BANCABLES_4BIG.md` : « Boutons langues **FR 🇨🇦 · EN 🇺🇸 · ES 🇩🇴** ». Le
générateur produit systématiquement les trois. Les **libellés** de gabarit sont
des traductions **fixes** ([`banclib/i18n.py`](banclib/i18n.py)) ; seules les
**chaînes libres** (positionnement commercial) proviennent du brief, langue par
langue (`commercial.positionnement_{fr,en,es}`). Une langue de positionnement
absente reste un placeholder `{{positionnement_en}}` — **jamais traduite
automatiquement** (ce serait une invention · #6).
## Anti-invention (#6) — deux tiers, tous deux traçables
| Tier | Contenu | Garantie |
|---|---|---|
| **Sourcé** (verbatim) | coût construction, revenu brut, marge, taux, prix par typologie | Repris tel quel du brief. Champ absent ⇒ placeholder `{{…}}`, **jamais 0 fabriqué**. |
| **Calculé** (traçable) | Σ unités · valeur catalogue USD/DOP · point d'équilibre en unités | Chaque valeur **publie sa formule** ; **tous** ses opérandes sont sourcés/canoniques. Opérande manquant ⇒ valeur `null` + champ listé. |
> **Calcul transparent ≠ invention.** Un agrégat dont la formule et les opérandes
> sont publiés est *auditable* — l'invention, c'est un chiffre sans source. Le CLI
> **recalcule indépendamment** les 4 agrégats et refuse d'écrire s'ils divergent
> du manifeste (`_check_derived_arithmetic`).
**Aucun montant n'est calculé sur une base non documentée.** Les pourcentages
« 3 % édition » et « 8.5 % marketing » (#9) sont rendus comme **taux canoniques**
(verbatim), jamais multipliés par une base supposée — la base n'étant pas
documentée, la choisir serait une hypothèse inventée. Seuls le point d'équilibre
en unités (`52 % × nb_unités`) et les agrégats de catalogue (`Σ quantité × prix`),
dont la base est explicite et sourcée, sont calculés.
## Confidentialité
Le Portail Bancables est **privé** (`noindex`). Chaque `.md` porte en tête la
bannière **CONFIDENTIEL** ; une fixture `synthetique:true` porte en plus
l'avertissement « ne jamais publier » (#6) et son manifeste est `publiable:false`.
## Utilisation
```bash
# Écrit DATA_ROOM/P01/50_financier_bancable/{fr,en,es}.md + manifest.json
python3 bancable_gen.py build fixtures/brief_bancable.json -o out
# Manifeste + invariants sans rien écrire (schéma + recalcul des agrégats)
python3 bancable_gen.py validate fixtures/brief_bancable.json
# Tests (stdlib pur, zéro pip · oracle jsonschema si présent)
python3 -m unittest discover -s tests -v
```
## Ce qui est généré (`out/` non commité)
| Fichier | Rôle |
|---|---|
| `50_financier_bancable/fr.md` · `en.md` · `es.md` | Dossier bancable print-ready (pré-PDF), une langue. |
| `50_financier_bancable/manifest.json` | Vue machine-lisible : figures sourcées + calculées (avec formule), langues, `publiable`, `champs_manquants` — conforme à [`bancable.schema.json`](bancable.schema.json). |
## Garde-fous (le CLI refuse d'écrire si un invariant casse)
- Manifeste conforme à `bancable.schema.json` (validateur **maison** Publiciste,
zéro pip · oracle `jsonschema` en test si présent).
- Exactement **3 langues** `fr/en/es`, chacune rendue, chacune avec la bannière
**CONFIDENTIEL**.
- **Recalcul indépendant** des 4 agrégats == manifeste (anti-figure-posée).
- Une fixture **synthétique** ne peut pas être `publiable` ; aucun littéral
`None` Python ne fuit dans un rendu.
- `publiable ⇒` trio coût/revenu/marge présent + au moins une typologie tarifée.
- Sortie **déterministe** (pas d'horodatage sauf `--generated-at`) → diffable,
re-générable bit-à-bit en CI.
## Vérification en-repo
- `python3 -m unittest discover -s tests -v`**22/22 verts** (finance, rendu
trilingue, schéma maison + oracle, invariants CLI, déterminisme).
- Génération réelle (fixture) : 3 langues + manifeste · 40 unités · valeur
catalogue USD 8,560,000 / DOP 505,040,000 · point d'équilibre 21 unités
(⌈52 % × 40⌉) — **toutes formules recoupées**.
- Job CI dédié `bancable-tests` ajouté au **gate** (`.gitea/workflows/ci.yml`,
Gitea Actions uniquement · #2).
## Auto-score 4Big du livrable : **96/100**
_Réserve 4_ : la conversion PDF (pandoc/wkhtmltopdf) + le rebuild du Portail
Bancables restent côté VPS (agent DevOps/Frontend, hors périmètre worker · #8).
Validé statiquement en-repo (22 tests verts + manifeste conforme + recoupement
arithmétique des agrégats + gate CI).