[DTP-Worker] Sprint 8 · buffer · CRM/Commissions : gate de la PROMESSE ANTI-INVENTION (#6) — la raison d'être du barème vendeurs
Aucun taux de commission n'étant documenté dans CLAUDE.md, le README §« Anti-invention » promet (README:22-23) « taux_pct: null + source: null + a_confirmer: true pour CHAQUE évènement » et l'invariant CLI #7 REFUSE tout taux_pct fourni SANS source. Le bloc cross-cohérence commissions ne gate QUE brouillons/champs de base ; le bloc racine QUE le compte de tests (« 25 »). RIEN ne confrontait cette promesse à l'artefact byte-gaté out/commission_plan.json. Dérive la plus dommageable possible du module : qu'un taux_pct DEVIENNE non-null (taux INVENTÉ, ou valeur remplie sans source) pendant que le README affirme encore « tout null » → le calcul base × taux (commlib/finance.py) émettrait une commission fondée sur un chiffre inventé — l'invention EXACTE que le module promet d'écarter. Aucune suite tests/ (FONCTIONS de calcul, jamais la promesse README vs artefact) ne l'attrape. Gate ajouté (bloc « CRM/Commissions · ANTI-INVENTION (#6) ») : recompute de l'état null/confirmé depuis l'artefact + (a) invariant #7 permanent (aucun taux_pct sans source) · (b) a_confirmer ⟺ taux_pct is null · (c) MANIFEST.counts recoupe le plan (taux_a_confirmer / evenements) · (d) la promesse #6 du README REFLÈTE l'artefact dans les DEUX SENS (tout-null ⇒ promesse présente ; taux confirmé ⇒ promesse retirée) — zéro faux négatif quand la Direction remplira les taux · (e) note_taux du MANIFEST cohérente. 5 morsures vérifiées (taux sans source · taux avec source mais a_confirmer stale + README périmé · a_confirmer=false sur null · counts périmé 5→4 · promesse retirée INTROUVABLE), restauré vert, 7 gates re-verts. Working tree byte-restauré via git checkout -- (JAMAIS git clean). Édition hors 05_deliverables_mvp/*/out ⇒ 0 dérive d'artefact. ci/README.md (récap + paragraphe détaillé) mis à jour. Auto-score 4Big 96/100. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1453,3 +1453,58 @@ interdit absolu) · **7 gates re-verts** (`check_readme_claims`/`check_docs`/`gu
|
||||
**hors** `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact ; le pod RunPod réel + le
|
||||
batch ComfyUI Flux restent côté VPS/RunPod).
|
||||
- **Auto-score 4Big** : 96/100.
|
||||
|
||||
## Session `20260801_133334` · Buffer S8 · Domaine CRM/Commissions : la **PROMESSE ANTI-INVENTION (#6)** du barème vendeurs — la **RAISON D'ÊTRE** du module — était HORS de tout gate. Aucun taux de commission n'étant documenté dans CLAUDE.md, le README §« Anti-invention » promet (README:22-23) que « le barème livré porte `taux_pct: null` + `source: null` + `a_confirmer: true` pour **chaque** évènement », et l'invariant CLI #7 REFUSE tout `taux_pct` fourni **sans `source`**. Le bloc cross-cohérence commissions existant ne gate QUE brouillons/champs de base ; le bloc racine QUE le compte de tests (« 25 »). RIEN ne confrontait cette promesse à l'artefact byte-gaté.
|
||||
|
||||
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||||
close ; poursuite de la série anti-dérive (CLAUDE.md #6). Même surface `crm/commissions`
|
||||
que le bloc cross-cohérence (états soumis/base_field) mais **axe orthogonal et plus
|
||||
grave** : non plus QUEL état paie, mais la garantie que le module **n'invente aucun
|
||||
chiffre** — la classe même que #6 pose, appliquée au livrable dont c'est la mission.
|
||||
|
||||
**Dérive silencieuse fermée** :
|
||||
- `05_deliverables_mvp/crm/commissions/README.md:22-23` — la promesse « `taux_pct:
|
||||
null` + `source: null` + `a_confirmer: true` pour **chaque** évènement ».
|
||||
- Source faisant autorité : `out/commission_plan.json` (byte-gaté par
|
||||
`check_artifacts`) — chaque `evenements[]` porte `taux_pct`/`source`/`a_confirmer` ;
|
||||
`out/MANIFEST.json[counts]` recompte `taux_a_confirmer`/`evenements`.
|
||||
- Piège #6, la dérive la plus dommageable possible ici : qu'un `taux_pct` DEVIENNE
|
||||
non-null (taux INVENTÉ, ou valeur remplie **sans `source`**) pendant que le README
|
||||
affirme encore « tout `null` » → le calcul `base × taux` (`commlib/finance.py`)
|
||||
émettrait une commission fondée sur un chiffre inventé — l'invention EXACTE que le
|
||||
module promet d'écarter. Aucune suite `tests/` (FONCTIONS de calcul/résolution,
|
||||
jamais la promesse du README vs l'artefact commité) ne l'attrape.
|
||||
- **État courant** : les 5 évènements sont bien tout-`null` (`taux_pct`/`source`
|
||||
null · `a_confirmer` true), `counts.taux_a_confirmer == 5 == |plan|`, `note_taux`
|
||||
cohérente ; rien de périmé (anti-invention #6, rien à réécrire). Le défaut est la
|
||||
**surface ungated**.
|
||||
|
||||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « CRM/Commissions ·
|
||||
ANTI-INVENTION (#6) » après le bloc cross-cohérence commissions) : on RECOMPUTE
|
||||
l'état null/confirmé depuis l'artefact, puis (a) **invariant #7 permanent** — aucun
|
||||
`taux_pct` renseigné **sans `source`** (taux inventé) ; (b) **cohérence** `a_confirmer`
|
||||
⟺ `taux_pct is null` (un taux confirmé n'est plus « à confirmer », et inversement) ;
|
||||
(c) **`MANIFEST.counts`** recoupe le plan (`taux_a_confirmer` == nb à confirmer ·
|
||||
`evenements` == |plan|) ; (d) **la promesse #6 du README REFLÈTE l'artefact dans les
|
||||
DEUX SENS** — si tout-null, la promesse DOIT être présente (sinon la raison d'être
|
||||
disparaît · #6) ; si un taux est un jour confirmé, la promesse « tout null » DOIT
|
||||
avoir été retirée (sinon « vert trompeur ») — **zéro faux négatif** quand la
|
||||
Direction remplira les taux ; (e) `note_taux` du MANIFEST cohérente avec l'état.
|
||||
|
||||
**5 morsures vérifiées** : `taux_pct` rempli SANS source (invariant #7 · invention
|
||||
+ cascade b/d) · `taux_pct` rempli AVEC source (invariant #7 OK mais `a_confirmer`
|
||||
resté true → b, + README périmé → d — prouve que #7 et la cohérence sont distincts) ·
|
||||
`a_confirmer=false` sur taux null (b + counts périmés c + d) · `MANIFEST.counts.
|
||||
taux_a_confirmer` périmé 5→4 (c seul) · promesse anti-invention retirée du README
|
||||
(d · INTROUVABLE) ; restauré = green : invariant #7 · cohérence · counts · promesse
|
||||
== artefact · exit 0. Working tree byte-restauré (`git checkout --`, **JAMAIS**
|
||||
`git clean`, interdit absolu) · **7 gates re-verts** (`check_readme_claims`/
|
||||
`check_ci_integrity`/`check_docs`/`guard_constraints`/`check_artifacts`/
|
||||
`check_regression`/`validate_json`).
|
||||
|
||||
- `ci/README.md` (cellule récap du pipeline + paragraphe détaillé « promesse
|
||||
anti-invention #6 du barème `crm/commissions` ») mis à jour.
|
||||
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo ;
|
||||
édition **hors** `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact ; la
|
||||
confirmation réelle des taux + le câblage du calcul restent côté Direction/VPS).
|
||||
- **Auto-score 4Big** : 96/100.
|
||||
|
||||
+24
-1
File diff suppressed because one or more lines are too long
@@ -2906,6 +2906,109 @@ if cm_ev is not None:
|
||||
bad(f"CRM commissions · {CM_RD} — énumère {sorted(bs)} MAIS plan "
|
||||
f"{sorted(cm_base)}{detail} → régénérer le README")
|
||||
|
||||
# ============================================================================
|
||||
# CRM/Commissions · ANTI-INVENTION (#6) — la promesse « tous les taux sont `null` »
|
||||
# (le CŒUR du livrable · sa RAISON D'ÊTRE) confrontée à l'artefact byte-gaté.
|
||||
# ----------------------------------------------------------------------------
|
||||
# Le module commissions n'existe QUE pour NE PAS inventer de taux (aucun taux de
|
||||
# commission n'est documenté dans CLAUDE.md). Le README §« Anti-invention (#6) »
|
||||
# le promet noir sur blanc (README:22-23) : « Le barème livré porte `taux_pct:
|
||||
# null` + `source: null` + `a_confirmer: true` pour **chaque** évènement », et
|
||||
# l'invariant CLI #7 REFUSE tout `taux_pct` fourni **sans `source`**. La source
|
||||
# faisant autorité est `out/commission_plan.json` (byte-gaté par check_artifacts) :
|
||||
# chaque évènement porte `taux_pct`/`source`/`a_confirmer`, et `MANIFEST.counts.
|
||||
# taux_a_confirmer` recompte les taux à confirmer.
|
||||
# Le bloc commissions ci-dessus ne gate QUE la CROSS-COHÉRENCE (base_field +
|
||||
# brouillons exclus) ; le bloc racine ne gate QUE le COMPTE de tests (« 25 »).
|
||||
# RIEN ne confrontait la promesse #6 à l'artefact. Piège #6, la dérive la plus
|
||||
# grave possible ici : qu'un `taux_pct` DEVIENNE non-null (un taux INVENTÉ, ou une
|
||||
# valeur remplie SANS `source`) pendant que le README continue d'affirmer « tous
|
||||
# `null` pour chaque évènement » → le calcul `base × taux` émettrait une commission
|
||||
# fondée sur un chiffre inventé (l'invention EXACTE que le module promet d'écarter),
|
||||
# « vert trompeur » qu'aucune suite tests/ (FONCTIONS de calcul, jamais la promesse
|
||||
# du README vs l'artefact commité) n'attrape. On RECOMPUTE l'état null/confirmé
|
||||
# depuis l'artefact et on exige que la promesse du README le REFLÈTE — dans les DEUX
|
||||
# sens (si un taux est un jour confirmé par la Direction, la promesse « tous null »
|
||||
# DOIT être mise à jour, sinon ROUGE : le gate suit la vie du module sans faux
|
||||
# négatif). Cohérences croisées (mordent un plan INTERNEMENT incohérent) : invariant
|
||||
# #7 permanent (aucun `taux_pct` sans `source`) · `a_confirmer` ⟺ `taux_pct is null`
|
||||
# (un taux confirmé n'est plus « à confirmer », et inversement) · MANIFEST.counts
|
||||
# recoupe le plan (`taux_a_confirmer` == nb à confirmer · `evenements` == |plan|).
|
||||
# ============================================================================
|
||||
try:
|
||||
cta_ev = load("crm/commissions/out/commission_plan.json")["evenements"]
|
||||
cta_counts = load("crm/commissions/out/MANIFEST.json")["counts"]
|
||||
cta_note = load("crm/commissions/out/MANIFEST.json").get("note_taux", "")
|
||||
except (OSError, KeyError, ValueError, TypeError) as e:
|
||||
bad(f"CRM commissions anti-invention · artefact illisible/inattendu : {e}")
|
||||
cta_ev = None
|
||||
if cta_ev is not None:
|
||||
if not cta_ev:
|
||||
bad("CRM commissions anti-invention · plan VIDE → aucun évènement à couvrir "
|
||||
"(barème suspect)")
|
||||
else:
|
||||
# (a) invariant #7 permanent : aucun taux_pct rempli SANS source (invention)
|
||||
invente = sorted(e["update_value"] for e in cta_ev
|
||||
if e.get("taux_pct") is not None and e.get("source") is None)
|
||||
if invente:
|
||||
bad(f"CRM commissions anti-invention · taux_pct RENSEIGNÉ sans `source` pour "
|
||||
f"{invente} → invariant #7 VIOLÉ (taux INVENTÉ · #6) → fournir la source "
|
||||
f"ou remettre à null")
|
||||
else:
|
||||
good("CRM commissions anti-invention · invariant #7 — aucun `taux_pct` sans "
|
||||
"`source` (nul taux inventé)")
|
||||
# (b) a_confirmer ⟺ taux_pct is null (un taux confirmé n'est plus « à confirmer »)
|
||||
incoh = sorted(e["update_value"] for e in cta_ev
|
||||
if bool(e.get("a_confirmer")) != (e.get("taux_pct") is None))
|
||||
if incoh:
|
||||
bad(f"CRM commissions anti-invention · `a_confirmer` incohérent avec "
|
||||
f"`taux_pct` pour {incoh} (confirmé mais taux null, ou taux rempli mais "
|
||||
f"encore « à confirmer ») → régénérer le plan")
|
||||
else:
|
||||
good("CRM commissions anti-invention · `a_confirmer` ⟺ `taux_pct is null` "
|
||||
"sur les 5 évènements (cohérent)")
|
||||
# (c) MANIFEST.counts recoupe le plan
|
||||
n_conf = sum(1 for e in cta_ev if e.get("a_confirmer"))
|
||||
if cta_counts.get("taux_a_confirmer") != n_conf:
|
||||
bad(f"CRM commissions anti-invention · MANIFEST.counts.taux_a_confirmer="
|
||||
f"{cta_counts.get('taux_a_confirmer')} ≠ {n_conf} (plan) → MANIFEST périmé")
|
||||
elif cta_counts.get("evenements") != len(cta_ev):
|
||||
bad(f"CRM commissions anti-invention · MANIFEST.counts.evenements="
|
||||
f"{cta_counts.get('evenements')} ≠ {len(cta_ev)} (plan) → MANIFEST périmé")
|
||||
else:
|
||||
good(f"CRM commissions anti-invention · MANIFEST.counts recoupe le plan "
|
||||
f"({n_conf} à confirmer / {len(cta_ev)} évènements)")
|
||||
# (d) la PROMESSE #6 du README reflète l'état RÉEL de l'artefact (bidirectionnel)
|
||||
all_null = all(e.get("taux_pct") is None and e.get("source") is None
|
||||
and e.get("a_confirmer") is True for e in cta_ev)
|
||||
cta_rd = read_norm(CM_RD)
|
||||
if cta_rd is not None:
|
||||
promesse = re.search(
|
||||
r"`taux_pct:\s*null`\s*\+\s*`source:\s*null`\s*\+\s*"
|
||||
r"`a_confirmer:\s*true`\s*pour\s*\*\*chaque\*\*", cta_rd, re.IGNORECASE)
|
||||
if all_null:
|
||||
if promesse is None:
|
||||
bad(f"CRM commissions anti-invention · {CM_RD} — la promesse « `taux_pct: "
|
||||
f"null` + `source: null` + `a_confirmer: true` pour **chaque** "
|
||||
f"évènement » INTROUVABLE alors que l'artefact est bien tout-null "
|
||||
f"→ la raison d'être du module ne doit pas disparaître (#6)")
|
||||
else:
|
||||
good(f"CRM commissions anti-invention · {CM_RD} — promesse « tout null "
|
||||
f"pour chaque évènement » == artefact (les 5 évènements tout-null)")
|
||||
else:
|
||||
if promesse is not None:
|
||||
bad(f"CRM commissions anti-invention · {CM_RD} — le README affirme "
|
||||
f"« tout `null` pour **chaque** évènement » MAIS l'artefact porte "
|
||||
f"des taux CONFIRMÉS → mettre à jour la §Anti-invention (promesse "
|
||||
f"périmée · « vert trompeur »)")
|
||||
else:
|
||||
good(f"CRM commissions anti-invention · {CM_RD} — la promesse « tout "
|
||||
f"null » a été retirée, cohérent avec des taux désormais confirmés")
|
||||
# (e) la note d'auto-traçabilité du MANIFEST reste cohérente avec l'état
|
||||
if all_null and "null" not in cta_note.lower():
|
||||
bad(f"CRM commissions anti-invention · MANIFEST.note_taux ne mentionne plus "
|
||||
f"`null` alors que tous les taux le sont → note périmée")
|
||||
|
||||
# ============================================================================
|
||||
# RBAC/fixtures_gen · le CATALOGUE des DocTypes `custom` à créer sur le VPS et la
|
||||
# SÉPARATION DES POUVOIRS (le rôle unique porteur de `set_user_permissions`) —
|
||||
|
||||
Reference in New Issue
Block a user