[DTP-Worker] Sprint 8 · buffer · Fiscal/ecf_dgii (2e surface) : la CROSS-COHÉRENCE e-CF ↔ workflow ↔ DocType ↔ RBAC — le CŒUR du livrable — énumérait EN PROSE trois données data-derived (états qui ÉMETTENT un e-CF · champs Currency de base · FormaPago défaut ancrée sur CLAUDE.md #10/Cardnet) sans AUCUN gate d'IDENTITÉ. Le bloc e-NCF existant ne gate QUE le FORMAT de l'identifiant (E+tipo(2)+seq(10)=13) — jamais ces trois ensembles/valeur. Ils sont DATA-DERIVED de out/ecf_plan.json (byte-gaté par check_artifacts) : README:48 « seulement réservation et contrat » = {emission_events[].update_value} · README:50 « (montant_reservation, montant_contrat) » = {emission_events[].base_field} · README:59 « FormaPago défaut = 3 (Tarjeta) … via Cardnet (#10) » = forma_pago_defaut (ancré sur CLAUDE.md #10 : Cardnet = carte, pas Stripe). PIÈGE : check_artifacts ne prouve QUE ecf_plan==build (byte-for-byte) et le bloc racine ne gate QUE le compte de tests e-CF (« 39 ») → AJOUTER un évènement d'émission (facturer un devis) · en RETIRER un · RENOMMER un base_field · CHANGER forma_pago_defaut (Cardnet abandonné → code 2 Transfert) laissait la prose périmée pendant que l'artefact dit autre chose → l'agent ERPNext Backend câblerait le mauvais évènement / la mauvaise FormaPago (le risque même que la cross-cohérence veut prévenir) — « vert trompeur » qu'aucune suite tests/ (qui teste des FONCTIONS ncf/résolution, pas la prose) n'attrape. Même patron EXACT que la cross-cohérence CRM/Commissions déjà gatée (base_field + états soumis). Nouveau bloc « Fiscal cross-cohérence » dans ci/check_readme_claims.sh (après le bloc e-NCF) : (1) états émetteurs recomputés de emission_events[].update_value, prose exigée EXACTE (set-diff · accents NFKD) ; (2) champs de base recomputés de emission_events[].base_field, prose EXACTE ; (3) FormaPago défaut = forma_pago_defaut.code + libellé (⊆ catalogue) + ancrage Cardnet à proximité. Cohérences croisées en bonus (mordent un plan INTERNEMENT incohérent) : forma_pago_defaut.code ∈ catalogue formas_pago · libellé prose ⊆ libellé catalogue du code · ensembles NON VIDES. Un claim absent échoue AUSSI. 7 morsures vérifiées : prose retire contrat des émetteurs (absents=[contrat]) · prose renomme montant_contrat→montant_final (absents + en trop) · prose FormaPago 3→2 (drift artefact) · artefact forma_pago_defaut.code 3→2 (prose périmée) · artefact ajoute l'évènement devis (états ET base_field mordus · absents=[devis]) · FormaPago prose supprimée (INTROUVABLE) · artefact code→99 hors catalogue (incohérence interne) ; restauré = green : émetteurs [contrat,reservation] · base [montant_contrat,montant_reservation] · FormaPago 3 (Tarjeta) ancré Cardnet · exit 0. État courant : aucune valeur périmée (anti-invention #6, rien à réécrire) — le défaut est la surface ungated. ci/README.md (table + détail « 2e surface e-CF DGII ») mis à jour · working tree byte-restauré (git clean) · 7 gates re-verts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Code DTP Worker
2026-07-31 20:38:52 +00:00
parent 342b571b29
commit 0790fa7811
3 changed files with 182 additions and 1 deletions
+28 -1
View File
File diff suppressed because one or more lines are too long
+106
View File
@@ -1675,6 +1675,112 @@ if encf is not None:
re.search(r"`([A-Z])\s*\+\s*tipoeCF\((\d+)\)\s*\+\s*"
r"secuencia\((\d+)\)`", ecf_fi), False)
# ============================================================================
# Fiscal · e-CF DGII (2e surface du MÊME README) · la CROSS-COHÉRENCE
# (« le cœur du livrable ») — ENSEMBLES/valeur data-derived transcrits À LA MAIN
# sans AUCUN gate d'IDENTITÉ. Le bloc e-NCF ci-dessus ne gate QUE le FORMAT de
# l'identifiant ; la section « Cross-cohérence e-CF ↔ workflow ↔ DocType ↔ RBAC »
# ÉNUMÈRE trois données dérivées de out/ecf_plan.json (byte-gaté par
# check_artifacts ⇒ faisant autorité) :
# • README:48 « seulement réservation et contrat » — l'ensemble des états qui
# ÉMETTENT un e-CF = {emission_events[].update_value}.
# • README:50 « (`montant_reservation`, `montant_contrat`) » — l'ensemble des
# champs Currency de base = {emission_events[].base_field}.
# • README:59 « FormaPago défaut = 3 (Tarjeta) … via Cardnet (#10) » — le code +
# libellé de forma_pago_defaut, ANCRÉ sur CLAUDE.md #10 (Cardnet = carte).
# Aucun gate ne comparait ces valeurs à l'artefact : AJOUTER un évènement
# d'émission (facturer un devis) · en RETIRER un · RENOMMER un base_field ·
# CHANGER forma_pago_defaut (Cardnet abandonné → code 2 Transfert) ferait dériver
# la prose en silence pendant que l'ecf_plan byte-gaté dit autre chose — l'agent
# ERPNext Backend câblerait le mauvais évènement / la mauvaise FormaPago (le risque
# même que la cross-cohérence veut prévenir) — « vert trompeur » qu'aucune suite
# tests/ (qui teste des FONCTIONS ncf/résolution, pas la prose) n'attrape. Même
# patron EXACT que la cross-cohérence CRM/Commissions (base_field + états soumis).
# On RECOMPUTE chaque ensemble/valeur depuis l'artefact (zéro duplication du
# contrat du générateur #6) et on exige que la prose l'encode EXACTEMENT (absent ET
# en trop via set-diff · accents/casse normalisés). Cohérences croisées en bonus
# (mordent un plan INTERNEMENT incohérent) : forma_pago_defaut.code ∈ catalogue
# formas_pago · libellé prose ⊆ libellé catalogue du code · ensembles NON VIDES.
# Un claim absent échoue AUSSI (traçabilité).
# ============================================================================
ECF_RD2 = f"{D}/fiscal/ecf_dgii/README.md"
def _ecf_acc(s):
return "".join(c for c in unicodedata.normalize("NFKD", s)
if unicodedata.category(c) != "Mn").lower()
try:
ecfp = load("fiscal/ecf_dgii/out/ecf_plan.json")
ecf_ev = ecfp["emission_events"]
ecf_uv = {_ecf_acc(e["update_value"]) for e in ecf_ev}
ecf_bf = {e["base_field"] for e in ecf_ev}
ecf_fpd = ecfp["forma_pago_defaut"]
ecf_fp_code = str(ecf_fpd["code"])
ecf_fp_cat = {str(f["code"]): f["label"] for f in ecfp["formas_pago"]}
except (OSError, KeyError, ValueError, TypeError) as e:
bad(f"Fiscal cross-cohérence · artefact ecf_plan illisible/inattendu : {e}"); ecf_ev = None
if ecf_ev is not None:
# bonus : plan INTERNEMENT cohérent (ensembles non vides · défaut ∈ catalogue)
if not ecf_uv or not ecf_bf:
bad("Fiscal cross-cohérence · aucun évènement d'émission (plan vide) → vérifier le plan")
elif ecf_fp_code not in ecf_fp_cat:
bad(f"Fiscal cross-cohérence · forma_pago_defaut.code={ecf_fp_code} ABSENT du "
f"catalogue formas_pago {sorted(ecf_fp_cat)} → plan incohérent")
else:
good(f"Fiscal cross-cohérence · forma_pago_defaut {ecf_fp_code} "
f"({ecf_fp_cat[ecf_fp_code]}) ∈ catalogue formas_pago · émission {sorted(ecf_uv)} non vide")
ecf_rd2 = read_norm(ECF_RD2)
if ecf_rd2 is not None:
# 1) README:48 — états émetteurs « seulement réservation et contrat »
me = re.search(r"seulement\s+([^.]+)\.", ecf_rd2)
if me is None:
bad(f"Fiscal cross-cohérence · {ECF_RD2} — énumération des états émetteurs "
f"INTROUVABLE (attendu {sorted(ecf_uv)})")
else:
es = {_ecf_acc(t.strip()) for t in re.split(r"\bet\b|[,/]", me.group(1)) if t.strip()}
if es == ecf_uv:
good(f"Fiscal cross-cohérence · {ECF_RD2} — états émetteurs {sorted(es)} == "
f"ecf_plan.emission_events[].update_value")
else:
miss = sorted(ecf_uv - es); extra = sorted(es - ecf_uv)
detail = (f" · absents={miss}" if miss else "") + (f" · en trop={extra}" if extra else "")
bad(f"Fiscal cross-cohérence · {ECF_RD2} — énumère {sorted(es)} MAIS plan "
f"{sorted(ecf_uv)}{detail} → régénérer le README")
# 2) README:50 — champs de base « (`montant_reservation`, `montant_contrat`) »
mf = re.search(r"Currency réel\*\* du DocType Dossier Vente\s*\(([^)]*)\)", ecf_rd2)
if mf is None:
bad(f"Fiscal cross-cohérence · {ECF_RD2} — énumération des champs de base "
f"INTROUVABLE (attendu {sorted(ecf_bf)})")
else:
bs = set(re.findall(r"`([a-z_]+)`", mf.group(1)))
if bs == ecf_bf:
good(f"Fiscal cross-cohérence · {ECF_RD2} — champs de base {sorted(bs)} == "
f"ecf_plan.emission_events[].base_field")
else:
miss = sorted(ecf_bf - bs); extra = sorted(bs - ecf_bf)
detail = (f" · absents={miss}" if miss else "") + (f" · en trop={extra}" if extra else "")
bad(f"Fiscal cross-cohérence · {ECF_RD2} — énumère {sorted(bs)} MAIS plan "
f"{sorted(ecf_bf)}{detail} → régénérer le README")
# 3) README:59 — FormaPago défaut « = 3 (Tarjeta) … via Cardnet (#10) »
mp = re.search(r"FormaPago défaut\s*=\s*(\d+)\s*\(([^)]*)\)", ecf_rd2)
if mp is None:
bad(f"Fiscal cross-cohérence · {ECF_RD2} — FormaPago défaut INTROUVABLE "
f"(attendu code {ecf_fp_code} · {ecf_fp_cat.get(ecf_fp_code,'?')})")
else:
got_code = mp.group(1); got_lbl = _ecf_acc(mp.group(2).strip())
cat_lbl = _ecf_acc(ecf_fp_cat.get(ecf_fp_code, ""))
has_cardnet = "cardnet" in _ecf_acc(ecf_rd2[mp.start():mp.start() + 160])
if got_code == ecf_fp_code and got_lbl and got_lbl in cat_lbl and has_cardnet:
good(f"Fiscal cross-cohérence · {ECF_RD2} — FormaPago défaut {got_code} "
f"({mp.group(2).strip()}) == forma_pago_defaut · ancré Cardnet (#10)")
elif got_code != ecf_fp_code:
bad(f"Fiscal cross-cohérence · {ECF_RD2} — FormaPago défaut = {got_code} MAIS "
f"forma_pago_defaut.code = {ecf_fp_code} → régénérer le README")
elif not (got_lbl and got_lbl in cat_lbl):
bad(f"Fiscal cross-cohérence · {ECF_RD2} — libellé FormaPago {mp.group(2).strip()!r} "
f"≠ catalogue code {ecf_fp_code} ({ecf_fp_cat.get(ecf_fp_code)!r}) → régénérer")
else:
bad(f"Fiscal cross-cohérence · {ECF_RD2} — FormaPago défaut sans ancrage "
f"Cardnet (#10) à proximité → régénérer le README")
# ============================================================================
# CRM/Commissions · barème vendeurs — la CROSS-COHÉRENCE (« cœur du livrable »)
# transcrite À LA MAIN dans le README sans AUCUN gate d'IDENTITÉ.