[DTP-Worker 20260802_083529] Sprint 8 · buffer · Faisabilité/bancable : élimination du taux 0.52 codé en dur dans l'oracle _check_derived_arithmetic

Le seul survivant en dur du paramètre canonique #9 (point d'équilibre 52 %)
vivait au cœur de l'oracle anti-invention de bancable_gen.py — alors que le
module PRÊCHE la source unique (deps.py « une seule source de vérité » ;
finance._pct « jamais codé en dur »). Transitivement protégé (donc gate
redondant, #5) mais BUG LATENT inverse : #9 52 %→55 % aurait fait rejeter
en silence un dossier bancable VALIDE. Fix = dériver le taux de
CANONICAL (finance._pct), pas un checker de plus.

Vérif : validate byte-identique à 52 % (pe=21) · 22 tests verts · preuve
levée du bug (source→55 % ⇒ pe=22, invariants OK) · 6 gates CI exit 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Code DTP Worker
2026-08-02 08:43:04 +00:00
parent ccb86fe7ca
commit 448c310398
2 changed files with 63 additions and 3 deletions
@@ -114,7 +114,9 @@ def _check_derived_arithmetic(brief: dict, manifest: dict) -> list[str]:
"""Reproduit indépendamment les 4 agrégats et compare au manifeste.
Prouve qu'aucune valeur calculée n'a été « posée » : elle DOIT découler des
typologies sourcées et du taux canonique 52 %.
typologies sourcées et du taux canonique de point d'équilibre. Ce taux est lu
à la SOURCE UNIQUE (`CANONICAL` · CLAUDE.md #9, gaté), jamais recopié en dur
ici — sinon un changement du mandat (#9) casserait cet oracle en silence.
"""
motifs: list[str] = []
rows = finance.typologies(brief)
@@ -128,8 +130,9 @@ def _check_derived_arithmetic(brief: dict, manifest: dict) -> list[str]:
if all_q and all(r["prix_usd"] is not None for r in rows) else None)
exp_dop = (sum(q * r["prix_dop"] for q, r in zip(qtes, rows))
if all_q and all(r["prix_dop"] is not None for r in rows) else None)
exp_pe = (float(math.ceil(0.52 * exp_total))
if exp_total is not None else None)
pe_pct = finance._pct(deps.CANONICAL["point_equilibre_pct"])
exp_pe = (float(math.ceil(pe_pct * exp_total))
if exp_total is not None and pe_pct is not None else None)
for cle, exp in (("total_unites", exp_total),
("valeur_catalogue_usd", exp_usd),