[DTP-Worker] Sprint 8 · buffer L75 · Domaine CRM (2e surface) : la phrase « SÉPARATION DES POUVOIRS » du README workflow_vente ÉNUMÉRAIT À LA MAIN ses transitions quatre-yeux (« confirmer réservation, signer contrat, approuver CONFOTUR, annuler/résilier — allow_self_approval = 0 ») sans AUCUN gate d'IDENTITÉ. Le bloc CRM existant gate le COMPTE états/transitions (9/11 · titre pipeline README workflow + « N états » README dossier_vente) MAIS PAS l'IDENTITÉ des transitions marquées separation_of_duties — surface data-derived distincte du MÊME README. Cet ensemble dérive de crm/workflow_vente/out/workflow.json (byte-gaté par check_artifacts) : chaque transition porte allow_self_approval ; l'ensemble QUATRE-YEUX = {action | allow_self_approval == 0} — précisément ce que le README énumère. Le bloc de COMPTE reste AVEUGLE au contenu : (a) DÉCLASSER une transition sensible (ex. « Signer contrat » repasse à self=1 dans le contrat) laisse le compte à 9/11 pendant que l'artefact retire l'action de l'ensemble — la prose reste à 5 actions FAUSSES ; (b) PROMOUVOIR une transition (« Déposer CONFOTUR » → self=0) l'ajoute sans que le compte bouge et la prose l'OMET ; (c) un ÉCHANGE/RENOMMAGE d'action passe aussi — « vert trompeur » qu'aucune suite tests/ (qui teste des FONCTIONS de graphe, pas la prose) n'attrape → nouveau bloc dans check_readme_claims recomputant l'ENSEMBLE des actions quatre-yeux depuis workflow.json (zéro duplication du flag du générateur) et exigeant que la phrase l'énumère EXACTEMENT. Contrôle par ENSEMBLE (absent ET en trop mordus via set-diff), normalisation casse ignorée + suffixe « (perdu) » élidé (les deux transitions vers l'état Perdu — Annuler/Résilier — que la prose groupe « annuler/résilier »). Même patron que l'énumération des onglets Mobile, des open items de l'audit 5D ou de la carte de renormalisation 4Big. Cohérence croisée en bonus : 0 < |quatre-yeux| < |transitions| (l'ensemble sensible est NON VIDE — sinon la garde est vacante — et STRICT — sinon tout le graphe serait bloqué en quatre-yeux). Un claim absent échoue AUSSI (4 morsures vérifiées : déclassement Signer contrat capté là où le compte reste 9/11 · promotion Déposer CONFOTUR captée · échange prose signer contrat→signer bail capté · énumération supprimée = INTROUVABLE ; restauré = green : {annuler, approuver confotur, confirmer réservation, résilier, signer contrat} == workflow.json). État courant : aucune action périmée (anti-invention #6, rien à réécrire) — le défaut est la surface ungated. ci/README.md (table + détail) mis à jour · 7 gates re-verts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -841,6 +841,76 @@ if wf_states is not None:
|
||||
bad(f"CRM pipeline · {DV_RD} — dit états={m.group(1)} MAIS MANIFEST dit "
|
||||
f"états={wf_states} → régénérer le README")
|
||||
|
||||
# ============================================================================
|
||||
# CRM (2e surface du MÊME README) · ÉNUMÉRATION des transitions à SÉPARATION
|
||||
# DES POUVOIRS — la phrase « engagent de l'argent ou clôturent — confirmer
|
||||
# réservation, signer contrat, approuver CONFOTUR, annuler/résilier ».
|
||||
# ----------------------------------------------------------------------------
|
||||
# Le bloc CRM ci-dessus recompute le COMPTE d'états/transitions mais PAS
|
||||
# l'IDENTITÉ des transitions marquées `separation_of_duties`. Or cette liste est
|
||||
# DATA-DERIVED : le générateur émet out/workflow.json (byte-gaté par
|
||||
# check_artifacts ⇒ artefact faisant autorité) dont chaque transition porte
|
||||
# `allow_self_approval` ; l'ensemble des transitions QUATRE-YEUX = {action |
|
||||
# allow_self_approval == 0} — précisément ce que le README énumère À LA MAIN
|
||||
# comme « interdisent l'auto-approbation (`allow_self_approval = 0`) ». Le bloc de
|
||||
# COMPTE reste AVEUGLE au contenu : (a) DÉCLASSER une transition sensible (ex.
|
||||
# « Signer contrat » repasse à allow_self_approval=1 dans le contrat) laisse le
|
||||
# compte d'états/transitions à 9/11 pendant que l'artefact retire l'action de
|
||||
# l'ensemble QUATRE-YEUX — la prose reste à 5 actions FAUSSES ; (b) PROMOUVOIR une
|
||||
# transition (« Déposer CONFOTUR » → self=0) l'ajoute à l'ensemble sans que le
|
||||
# compte bouge, et la prose l'OMET ; (c) RÉORDRE/RENOMMAGE d'action passe aussi —
|
||||
# « vert trompeur » qu'aucune suite tests/ (qui teste des FONCTIONS de graphe, pas
|
||||
# la prose) n'attrape — même patron que l'énumération des onglets Mobile, des open
|
||||
# items de l'audit 5D ou de la carte de renormalisation 4Big. On RECOMPUTE ici
|
||||
# l'ENSEMBLE des actions QUATRE-YEUX depuis workflow.json (zéro duplication du flag
|
||||
# du générateur) et on exige que la phrase l'énumère EXACTEMENT (absent ET en trop
|
||||
# mordus via set-diff). Normalisation : casse ignorée + suffixe « (perdu) » élidé
|
||||
# (les deux transitions vers l'état Perdu — Annuler/Résilier — que la prose groupe
|
||||
# « annuler/résilier »). Cohérence croisée en bonus : 0 < |quatre-yeux| < |trans|
|
||||
# (l'ensemble sensible est NON VIDE — sinon la garde est vacante — et STRICT — sinon
|
||||
# tout le graphe serait bloqué en quatre-yeux, ni l'un ni l'autre n'étant le
|
||||
# contrat). Un claim absent échoue AUSSI (traçabilité).
|
||||
# ============================================================================
|
||||
try:
|
||||
wf_trans_list = load("crm/workflow_vente/out/workflow.json")[0]["transitions"]
|
||||
# ensemble QUATRE-YEUX = actions dont l'auto-approbation est interdite (self=0),
|
||||
# normalisées (casse ignorée · suffixe « (perdu) » élidé — cf. groupage prose)
|
||||
def _sod_norm(a):
|
||||
return re.sub(r"\s*\(perdu\)\s*", "", a).strip().lower()
|
||||
sod_set = {_sod_norm(t["action"]) for t in wf_trans_list
|
||||
if str(t["allow_self_approval"]) == "0"}
|
||||
n_trans_tot = len(wf_trans_list)
|
||||
except (OSError, KeyError, ValueError, IndexError, TypeError) as e:
|
||||
bad(f"CRM séparation · workflow.json illisible/inattendu : {e}"); sod_set = None
|
||||
if sod_set is not None:
|
||||
# bonus : l'ensemble sensible est non vide ET strictement inclus dans le graphe
|
||||
if not (0 < len(sod_set) < n_trans_tot):
|
||||
bad(f"CRM séparation · ensemble quatre-yeux dégénéré : |sod|={len(sod_set)} "
|
||||
f"vs |transitions|={n_trans_tot} (attendu 0 < sod < total) → vérifier le contrat")
|
||||
else:
|
||||
good(f"CRM séparation · ensemble quatre-yeux non vide et strict : "
|
||||
f"0 < {len(sod_set)} < {n_trans_tot}")
|
||||
# énumération de la phrase : capturer le segment entre « clôturent** — » et « — sont marquées »
|
||||
wf_txt3 = read_norm(WF_RD)
|
||||
if wf_txt3 is not None:
|
||||
ms = re.search(r"engagent de l'argent ou clôturent\*\* — (.+?) — sont marquées",
|
||||
wf_txt3)
|
||||
if ms is None:
|
||||
bad(f"CRM séparation · {WF_RD} — énumération des transitions quatre-yeux "
|
||||
f"INTROUVABLE (attendu {sorted(sod_set)})")
|
||||
else:
|
||||
prose_set = {t.strip().lower() for t in re.split(r"[,/]", ms.group(1)) if t.strip()}
|
||||
if prose_set == sod_set:
|
||||
good(f"CRM séparation · {WF_RD} — énumération quatre-yeux "
|
||||
f"{sorted(prose_set)} == workflow.json (allow_self_approval=0)")
|
||||
else:
|
||||
miss = sorted(sod_set - prose_set)
|
||||
extra = sorted(prose_set - sod_set)
|
||||
detail = (f" · absents={miss}" if miss else "") + \
|
||||
(f" · en trop={extra}" if extra else "")
|
||||
bad(f"CRM séparation · {WF_RD} — énumère {sorted(prose_set)} MAIS "
|
||||
f"workflow.json dit {sorted(sod_set)}{detail} → régénérer le README")
|
||||
|
||||
# ============================================================================
|
||||
# Mobile · récap de l'app Expo (onglets / rôles couverts / langues / identifiants
|
||||
# a_confirmer) — même classe de « vert trompeur », transcrite À LA MAIN.
|
||||
|
||||
Reference in New Issue
Block a user