88d9955f90
Docstring bancable_gen.py:5 + bancable/README.md:5 attribuaient au fichier ROADMAP_8_WEEKS_OR_LESS.md un libellé verbatim « 40_llm_outputs/ + rapports bancables FR/EN/ES » ABSENT de la roadmap (grep = 0 occurrence). Le §Sprint 3 réel dit « Faisabilité Auto » → « génération 4 volets <1h ». Le libellé cité vient des daily_reports (planif S3 du 2026-07-30), pas de la roadmap : citation mal-attribuée (même classe que « regression_run.json non commité »). Fix : §Sprint 3 cité fidèlement + volet financier bancable ré-attribué aux daily_reports / Portail Bancables 4Big, avec mention « pas un texte roadmap ». Consommateur qa/audit_4big/quality_report.json régénéré (README bancable 6103 → 6439 octets · verdict PASS 22/22 = 100/100 inchangé). Libellé fantôme cité par aucun gate. run_ci.sh 30 PASS 0 FAIL. Zéro module, zéro gate (#5). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
119 lines
6.3 KiB
Markdown
119 lines
6.3 KiB
Markdown
# 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).
|
||
|
||
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).
|