Files
Claude Code DTP Worker 0f7a1d8f6f [DTP-Worker 20260812_160204] surface · D-09 · séparateur de milliers monétaire divergent entre les deux surfaces de rendu stakeholder (publiciste=espace · faisabilité=virgule) — arbitrage produit surfacé, NON un bug/fix worker
Chasse au défaut d'abord (pas un énième sweep stérile) : grep TODO/FIXME/stub =
RIEN ; axe format `:g`/`:,`/`:f` de prod = les 2 `:g` restants bornés+annotés
sûrs (commissions:86 percent 0-100 · bancable/finance:143 nb-unités borné) →
axe `:g` genuinement clos, 0 bug de correctness.

Vrai locus = arbitrage de PRÉSENTATION transverse, non un défaut :
- publiciste/lib/generator.py:34-39 → espace (`.replace(",", " ")`) : USD 8 560 000
- faisabilite/generator/genlib/renderer.py:28-37 + bancable/banclib/report.py:21-32
  → virgule US (`,.0f` sans replace) : USD 8,560,000
- signaux partiels sans règle dure : OTO_DESIGN_SYSTEM_v1.md:89-90 illustre
  l'espace (« dès 145 000 USD ») ↔ fixtures data_room écrivent en virgule
  (architecture.md:11 « USD 150,000 ») ; aucune directive ne tranche.

SURFACE, don't rewrite : ajout D-09 au OPEN_DECISIONS_REGISTER (+ note d'en-tête).
Choisir un séparateur = convention design/audience (arbitrage Michel), pas une
correction worker (#6). Les 2 rendeurs sont internes-cohérents+testés ; aucune
sortie formatée n'est un artefact commité (out/ = nombres bruts ; formatage au
runtime VPS #8) → aucun gate concerné. Pas de gate (#5) : classe D-01…D-08.

Vérif : run_ci 33 PASS · 0 FAIL · 0 SKIP (inchangé, doc éditorial). 0 code V18
(bloqué #6) · 0 module prod · 0 artefact reconstruit · 0 chiffre figé · NFC-clean.
Fichiers : M OPEN_DECISIONS_REGISTER.md · M 05_activity_log/2026-08-12.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-12 16:09:26 +00:00

270 lines
16 KiB
Markdown

# Registre des décisions ouvertes · OTO Enterprise OS DTP
> **But** — Punch-list unique, sourcée, des **décisions produit qui appartiennent à Michel**
> (arbitrages de périmètre / dépendances runtime hors dépôt), consolidée depuis les journaux
> de session où elles ont été *surfacées* au fil de l'eau. Ces items **ne sont pas des bugs
> worker** : les corriger unilatéralement serait soit une invention de périmètre (#6), soit
> une réécriture d'une source d'autorité. Ce registre **regroupe et source**, il ne tranche pas.
>
> **Portée** — CI dépôt **verte** : tous les jobs de `gate.needs` passent · tous les modules 4Big
> au seuil `100/100`, verdict `PASS`. *(Décomptes exacts — dérivés et gatés — dans le README
> `## État courant` et `qa/audit_4big/out/quality_report.json` ; jamais figés ici, ils dérivent
> quand un gate ou un module est ajouté.)* Aucun de ces items
> ne casse un gate ; ils concernent le **périmètre produit** et l'état runtime **hors dépôt**
> (VPS `153.75.250.214` · `CLAUDE.md` #8), non vérifiable/éditable depuis le worker.
>
> **Mise à jour** — 2026-08-11 · session `20260811_025754` (ajout du **bloc V18** D-06→D-08 :
> la séquence V18 moteur est intégralement suspendue à des arbitrages Michel — cf. audit de
> migration). Base 2026-08-05 · session `20260805_014119`. Chaque ligne cite sa source exacte
> et la session qui l'a surfacée en premier. **Ne pas re-surfacer** ces items en doublon (#5) :
> pointer ici.
>
> **Réalignement de citations** — 2026-08-12 · session `20260812_123144` : deux citations `Constat`
> pointaient un mauvais numéro de ligne après les fixes du jour (le décompte de décision reste
> inchangé). D-02 `gate.py:142-145 → :164-167` (les gardes d'affichage `percent`/`overall` des
> commits `85cd625`/`1992ee6` ont décalé `_cond_validation_wag`) ; D-01 `legal/confotur/README.md:8-17
> → :32-33` (bannière de statut V18 préfixée). Sweep des autres citations = résolvent (snapshots
> V18/directives datés = stables).
>
> **Ajout** — 2026-08-12 · session `20260812_160204` : **D-09** (séparateur de milliers divergent
> entre surfaces de rendu monétaire publiciste / faisabilité). Arbitrage de présentation
> stakeholder ; ni un bug worker ni gaté (aucune sortie formatée n'est un artefact commité) —
> **surfacé, pas tranché**.
---
## Légende statut
- 🟠 **OUVERT** — décision produit en attente de Michel (ou d'un agent hors dépôt).
- 🟢 **VÉRIFIÉ-SANS-SUITE** — soupçon investigué → aucun risque réel ; consigné pour ne pas ré-ouvrir.
---
## D-01 · 🟠 PIE : `contrats` attribué à `legal/confotur` qui ne génère pas ces contrats
**Décision attendue** — Soit (a) construire un vrai module `contrats` (Promesa de compraventa ·
Fideicomiso d'adhésion · règlement HOA), soit (b) rebasculer l'attribution à `"module": null`
comme les autres downstreams sans générateur (brochures/plans/rendus/bim).
**Constat** — Le registre downstream PIE mappe `contrats → legal/confotur` :
- `05_deliverables_mvp/pie/manifest/pie_spec.json:24`
`{ "cle": "contrats", "libelle": "Contrats types (Promesa · Fideicomiso · HOA)", "module": "legal/confotur" }`
- Écho dans l'artefact gaté : `05_deliverables_mvp/pie/manifest/out/pie_manifest.json:165-166`,
`out/MANIFEST.json:24`, et la table `README.md:48`.
Or `legal/confotur` produit **uniquement le DocType Frappe de la demande CONFOTUR** (Ley 158-01),
pas de gabarit Promesa/Fideicomiso/HOA :
- `05_deliverables_mvp/legal/confotur/README.md:32-33` (sorties = `doctype_confotur_application.json`
+ `MANIFEST.json`, rien d'autre).
**Incohérence interne** — le même registre utilise déjà `"module": null` pour tout downstream
sans générateur (`pie_spec.json:22,27,28,29,30`). `contrats` est le seul downstream attribué à
un module qui ne le produit pas. **Arbitrage de périmètre, pas une correction worker.**
**Sources / surface** — décrit dans la mémoire projet `directive-vs-implementation` (« PIE SIGNAL »).
Non édité : cf. convention *SURFACE, don't rewrite*.
**Lien V18 (2026-08-11)** — L'audit de migration **remonte cet item au rang d'arbitrage V18** :
`OTO_V18_MIGRATION_ARCHITECTURE_AUDIT_20260810.md` §12.4 (:216) demande à Michel de trancher le
**périmètre de génération juridique (Section 13)** — « CONFOTUR seul (existant) ou aussi
Promesa/Fideicomiso/HOA (aucun code aujourd'hui) » — et **pointe explicitement ici**. Même décision
que D-01, désormais dans le chemin critique V18. Ne pas dédoubler : cet item **est** l'arbitrage
Section 13.
---
## D-02 · 🟠 Financement bancaire : condition #4 encore sur `wag_validated_by` (humain), directive V10 la remplace par un audit IA signé
**Décision attendue** — L'agent **OTO Auditeur Finances** (IA autonome, **hors dépôt**) doit
exister/émettre un `audit.decision == APPROVED` signé pour que la condition #4 soit implémentable.
Tant qu'il n'existe pas, le module ne peut pas migrer sans casser le gate de financement.
**Constat** — La directive porte une couche `## PRÉCISION` (2026-08-03) qui **supersede**
explicitement la validation humaine « conseiller WAG » par une décision d'agent IA :
- `DIRECTIVE_FINANCEMENT_BANCAIRE_COMPLET_20260803.md:206-210` et `:275-279`
`condition_4_ok = audit and audit['decision'] == 'APPROVED' and audit['signature_valid']`.
Le module livré implémente encore l'**ancienne** condition humaine :
- `05_deliverables_mvp/crm/financement_bancaire/finlib/gate.py:164-167`
`_cond_validation_wag` teste `dossier.get("wag_validated_by")` (:165).
- `05_deliverables_mvp/crm/financement_bancaire/financement_spec.json:157` (label « Validation
manuelle WAG confirmée par le conseiller référent »).
**Pourquoi worker n'édite pas** — la nouvelle condition dépend d'un producteur d'`audit` signé
qui n'existe pas dans le dépôt ; migrer le gate maintenant le rendrait toujours-faux. **Arbitrage
séquencement produit + dépendance agent hors dépôt.**
**Sources / surface** — mémoire `directive-vs-implementation` (« V10/173726 SIGNAL »).
---
## D-03 · 🟠 Inventaire : `otoia/capabilities/chat.py` absent au chemin, alors que `CLAUDE.md` le liste comme capability canonique
**Décision attendue** — Soit recréer `chat.py`, soit retirer `chat.py` de la liste des
capabilities OTOIA canoniques dans `CLAUDE.md` §Architecture cible.
**Constat**
- `AGENTS_EXISTING_ASSETS.md:102` le déclare présent (« conversation »).
- `CLAUDE.md:28` le liste (« aec.py + knowledge.py + prompt_engine.py + chat.py »).
- Filesystem : `/opt/oto/otoia/capabilities/chat.py` **absent** (ni `.py` ni `.pyc`).
- Auto-incohérence : le footer du même inventaire (L128) **omet déjà** `chat.py`.
**Pourquoi worker n'édite pas** — corriger l'inventaire contredirait la constitution `CLAUDE.md` ;
l'inverse toucherait la constitution. **À trancher par Michel.** (Distinct du `chatbot-lead`
qui, lui, existe — ne pas confondre.)
**Sources / surface****déjà surfacé** session `20260803_133718`
(`05_activity_log/2026-08-03.md:1245-1250`).
---
## D-04 · 🟠 Inventaire : `config/projets_editor.py` « API GET/POST déjà en place » — source absente (claim runtime non réfutable)
**Décision attendue** — Confirmer si l'API `projets_editor` tourne effectivement (déployée
ailleurs sur le VPS) ou si le claim d'inventaire est obsolète.
**Constat**
- `AGENTS_EXISTING_ASSETS.md:127` : `/opt/oto/config/projets_editor.py (API GET/POST déjà en place)`.
- Filesystem : aucun `projets_editor*` sous `/opt/oto` ; le sibling `projets_config.json` existe.
- Le claim porte sur une **API VPS live****non réfutable** par la seule absence de source
in-`/opt/oto` (peut tourner déployée ailleurs, #8). Non touché.
**Sources / surface****déjà surfacé** session `20260803_133718`
(`05_activity_log/2026-08-03.md:1251-1253`).
---
## D-05 · 🟢 Mobile : identifiant bundle `com.otov7.app` face au renommage OTOV7 → « OTO Enterprise OS » — VÉRIFIÉ, aucun risque
**Verdict** — Le renommage produit **ne menace pas** l'App Store #32. L'`app.name` passe bien à
« OTO Enterprise OS », mais tout identifiant de store est **quarantiné `null · a_confirmer`,
jamais fabriqué**, et **découplé** du nom d'app par conception (#6/#8) :
- `05_deliverables_mvp/mobile/app_config/mobile_spec.json` (`bundleIdentifier`/`package` en
`a_confirmer`, « jamais fabriquée #6/#8 »).
- `out/app_config.json``bundleIdentifier: null`, `package: null`.
- Constante historique figée `com.otov7.app` : `DIRECTIVE_MOBILE_STORES_20260803.md:15-16`.
Aucun chemin de code ne peut auto-muter le bundle id. La mise à jour réelle de #32 (si besoin)
est **manuelle, hors dépôt**. Consigné ici pour éviter de ré-ouvrir le soupçon (mémoire
`directive-vs-implementation` « mobile SIGNAL »).
---
## D-06 · 🟠 V18 : approbation de l'audit de migration — gate d'entrée de TOUTE la séquence moteur V18
**Décision attendue** — Michel doit **approuver l'audit de migration V12→V18** (ou demander
révisions). Tant qu'il n'est pas validé, **aucune** phase de développement V18 ne peut démarrer :
c'est le premier maillon d'une chaîne à validation par étape.
**Constat** — Le GO signal de développement **n'active pas le code direct** ; il active une
**séquence à validation** dont l'audit est l'étape 1 et son approbation l'étape 2 :
- `V18_GO_SIGNAL_DEVELOPMENT_20260810.md:79-84` → « n'active PAS le code direct — il active la
séquence : 1. Audit V12→V18 · 2. **Validation Michel de l'audit** · 3. Phase 1 · 4. Validation
Michel Phase 1 · 5. Phase 2→15 avec validation à chaque phase ».
- `DIRECTIVE_V18_MASTER_FEASIBILITY_ENGINE_20260810.md:90-91` → INTERDICTIONS ABSOLUES : « NE PAS
coder avant l'audit ».
- Livrable produit et en attente : `OTO_V18_MIGRATION_ARCHITECTURE_AUDIT_20260810.md` §12 (:207-218),
recommandation + les 4 arbitrages Michel avant Phase 1.
**Pourquoi worker n'avance pas** — Coder un moteur V18 avant l'approbation violerait la directive
(« NE PAS coder avant l'audit ») et la séquence GO. **Blocage de gouvernance produit, pas un bug.**
**Sources / surface** — surfacé session `20260811_022753` (`05_activity_log/2026-08-11.md`, production
de l'audit) ; consolidé ici session `20260811_025754`.
---
## D-07 · 🟠 V18 : formules financières (DCF · IRR/VAN · DSCR/LTV/LTC) absentes des docs lisibles — moteurs 4/8 bloqués
**Décision attendue** — Michel doit **fournir / rendre lisibles** les conventions financières exactes
(échéancier DCF, actualisation IRR/VAN, ratios bancaires DSCR/LTV/LTC, Cost Plan/WBS) attendues pour
les moteurs **Financial (4)** et **Bankability (8)**. Sans elles, coder ces moteurs = **inventer une
convention financière** — interdit par #6, risque de migration le plus grave (R1 🔴).
**Constat**
- `05_deliverables_mvp/faisabilite/bancable/banclib/finance.py` est un **snapshot** (coût · revenu ·
marge · point d'équilibre en unités) : `grep` confirme **aucun** `DSCR`/`LTV`/`LTC`, aucune
actualisation multi-période.
- Écart détaillé : `OTO_V18_MIGRATION_ARCHITECTURE_AUDIT_20260810.md` §5 (:102-114) et le point de
décision §12.2 (:214) ; risque R1 « inventer des formules » gravité 🔴 (:182), mitigation =
**bloquer moteur 4/8 avant lecture des formules par Michel**.
- Hypothèse déclarée §5 (:112) : les formules figurent **peut-être** dans la directive complète
57 chapitres et/ou les audits deep **root-owned illisibles** par le worker (#8).
**Pourquoi worker n'édite pas** — L'architecture V12 « valeur = {formule + opérandes sourcés/null} »
est le bon patron à **généraliser**, mais les formules elles-mêmes ne sont **pas dérivables** du code
lisible. **Dépendance d'entrée + arbitrage produit.**
**Sources / surface** — audit §5/§10-R1/§12.2 ; consolidé session `20260811_025754`.
---
## D-08 · 🟠 V18 : confirmer que le Master Intake A1-A20 est un sur-ensemble STRICT du `brief.json` V12 (rétro-compat parser)
**Décision attendue** — Michel doit **confirmer** que le futur Master Data Model (A1-A20) **étend**
le schéma d'entrée V12 sans en casser les clés — pour éviter la création d'une **2e base** (R2 🔴)
et préserver le parser Publiciste / `projets_master` (R6).
**Constat**
- Recommandation data model : `OTO_V18_MIGRATION_ARCHITECTURE_AUDIT_20260810.md` §4 (:86-100) —
« One Master Dataset · Multiple Outputs » ; V12 le respecte déjà (bancable consomme le **même**
`brief.json` que le générateur).
- Point de décision §12.3 (:215) : confirmer le **sur-ensemble strict**. Séquence Phase 1 §11 (:197)
= étendre `brief.schema.json``master_intake.schema.json`, **rétro-compat garantie**, canoniques
réimposés.
- Risque R2 « créer une 2e base en dupliquant `brief.json` » gravité 🔴 (:183) ; mitigation = intake
= sur-ensemble strict du `brief.schema.json`.
**Pourquoi worker n'édite pas** — Décision d'architecture de données ; l'étendre présuppose la liste
fine A1-A20, contenue dans la directive complète **non lisible** (§0 · #8). **À valider avant Phase 1.**
**Sources / surface** — audit §4/§10-R2/§11/§12.3 ; consolidé session `20260811_025754`.
---
## D-09 · 🟠 Présentation : séparateur de milliers divergent entre les deux surfaces de rendu monétaire (publiciste = espace · faisabilité = virgule)
**Décision attendue** — Michel (ou le design system) doit **fixer la convention canonique** du
séparateur de milliers pour les montants **face au stakeholder**, puis harmoniser les deux
rendeurs sur ce choix. Options : (a) **espace** partout (`USD 8 560 000`), aligné sur l'exemple
public du design system ; (b) **virgule US** partout (`USD 8,560,000`), aligné sur la graphie des
`data_room` sources ; (c) convention **par audience** (espace pour le marketing public, virgule
pour le dossier technique/banquier) — statu quo assumé et documenté.
**Constat** — deux modules rendent le **même montant** différemment, tous deux face au stakeholder :
- **Publiciste** (HTML marketing public) → **espace** :
`05_deliverables_mvp/publiciste/lib/generator.py:34-39`
(`_fmt_usd`/`_fmt_dop` = `f"{value:,.0f}".replace(",", " ")`) ⟹ `USD 8 560 000`.
- **Faisabilité** (rapport de faisabilité + bancable) → **virgule** :
`05_deliverables_mvp/faisabilite/generator/genlib/renderer.py:28-37` (`_money`, docstring `:29`
« USD 250,000 ») et `05_deliverables_mvp/faisabilite/bancable/banclib/report.py:21-32`
(`_money`/`_int` = `,.0f` / `:,`, **sans** `replace`) ⟹ `USD 8,560,000`.
**Signaux partiels (pas de règle dure)** — le design system illustre le format public avec un
**espace** (`OTO_DESIGN_SYSTEM_v1.md:89-90`, « ### Séparateur privilégié » → ex. « dès 145 000 USD »),
ce que suit le publiciste ; mais les fixtures `data_room` sources écrivent en **virgule US**
(`publiciste/fixtures/data_room/P01/20_architecture/architecture.md:11` → « USD 150,000 »), ce que
suit la faisabilité. À noter aussi : l'exemple du design system place le **montant avant la devise**
(`145 000 USD`), alors que **les deux** modules mettent la devise **en tête** (`USD …`) — donc aucun
des deux ne calque l'exemple à la lettre. Aucune directive datée ne tranche le séparateur.
**Pourquoi worker n'édite pas** — Choisir un séparateur unique impose une **convention de présentation
transverse** (arbitrage design/audience), non une correction ponctuelle ; l'imposer unilatéralement
réécrirait implicitement une règle du design system ou la graphie des sources (#6). Les deux rendeurs
sont **internes-cohérents et testés** ; aucune sortie formatée n'est un **artefact commité** (les
`out/` des deux modules ne stockent que des nombres bruts — le formatage vit dans le HTML/rapport
généré au runtime VPS · #8), donc **aucun gate n'est concerné**.
**Sources / surface** — surfacé session `20260812_160204` (balayage des spécificateurs de format
`:g`/`:,`/`:f` de production, frère de l'arc « `:g` lossy » des commits `e7cc3c4`/`5af86e3`). Les deux
`:g` de production restants sont bornés + annotés sûrs (`crm/commissions/commlib/finance.py:86`
percent 0-100 · `faisabilite/bancable/banclib/finance.py:143` unités bornées) — hors périmètre de D-09.
---
## Rappel de discipline
- Ces items sont **surfacés, pas tranchés** : les éditer côté worker violerait #6 (invention) ou
réécrirait une source d'autorité (`CLAUDE.md`, une directive datée).
- **Ne pas re-signaler** en doublon dans les rapports quotidiens (#5) — **pointer ce registre**.
- Rien ici ne bloque la CI dépôt (verte) ; tout relève du **périmètre produit** ou du **runtime
hors dépôt** (VPS · #8).