[DTP-Worker] Sprint 8 · buffer L75 · Domaine Fiscal/e-CF : le CONTRAT DE FORMAT de l'e-NCF (« E + tipoeCF(2) + secuencia(10) » = 13) était retranscrit À LA MAIN dans QUATRE endroits de prose (README ×3 + fiche agent erpnext_backend) sans AUCUN gate d'IDENTITÉ. Le bloc racine de check_readme_claims ne gate que le COMPTE de tests e-CF (« 39 ») — surface distincte du MÊME module. Ce format — préfixe · longueur du segment tipo · longueur du segment secuencia · longueur TOTALE — est le CŒUR du module (le « composeur traçable ») et dérive du bloc e_ncf de fiscal/ecf_dgii/out/ecf_plan.json (byte-gaté par check_artifacts) : prefix (« E »), longueur (13), regex (^E[0-9]{12}$), structure (« E + tipoeCF (2 chiffres) + secuencia (10 chiffres) »). Format e-NCF standard DGII (Ley 32-23) porté avec source — pas un chiffre inventé (#6). Aucun gate ne comparait la LONGUEUR des segments à l'artefact : allonger la secuencia (rango DGII à 12 chiffres → longueur 15, regex 14 digits) OU changer le préfixe ferait dériver les QUATRE proses en silence pendant que l'ecf_plan byte-gaté dit autre chose — « vert trompeur » qu'aucune suite tests/ (qui teste les FONCTIONS compose_encf/parse_encf, pas la prose) n'attrape → nouveau bloc recomputant (prefix, tipo_len, seq_len, total) depuis le SEUL bloc e_ncf (zéro duplication du format du générateur #6) et exigeant que CHAQUE prose l'encode EXACTEMENT (4 sous-checks numérotés, patron du bloc DevOps). Cohérences croisées en bonus (mordent un artefact INTERNEMENT incohérent) : 1 + tipo_len + seq_len == longueur (1+2+10==13) ET |regex digits| == tipo_len + seq_len (12 == 2+10). Un claim absent échoue AUSSI. 5 morsures vérifiées : drift de l'artefact source (secuencia 10→12, les 4 proses mordues) · résumé README tipo 2→3 · invariant README total 13→14 (aveugle au segment) · fiche erpnext_backend secuencia 10→9 · composition README supprimée (INTROUVABLE) ; plus la morsure d'incohérence d'artefact (regex {11} désaligné du segment tipo+seq=12) ; restauré = green : E + tipo(2) + secuencia(10) = 13 == e_ncf. État courant : aucun segment périmé (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:
@@ -84,6 +84,13 @@
|
||||
# dans DEUX docs de module (le bloc racine ne gate que le README d'entrée)
|
||||
# → recompté depuis la matrice acceptance (kind sprint_deliverable / mvp_metric)
|
||||
# + cohérence croisée == MANIFEST.counts (compteur ⇔ matrice résumée)
|
||||
# fiscal/ecf_dgii/README.md (×3) + 03_agents/erpnext_backend/AGENT.md (format e-NCF) :
|
||||
# • le CONTRAT DE FORMAT de l'e-NCF « E + tipoeCF(2) + secuencia(10) = 13 »
|
||||
# (préfixe · longueur segment tipo · longueur segment secuencia · longueur
|
||||
# totale) transcrit À LA MAIN dans QUATRE endroits de prose → recompté depuis
|
||||
# le SEUL bloc `e_ncf` d'ecf_plan.json (prefix/longueur/regex/structure, byte-
|
||||
# gatés) + cohérences croisées (1+tipo+seq == longueur · |regex digits| ==
|
||||
# tipo+seq — mordent un artefact internement incohérent)
|
||||
# Un claim absent échoue AUSSI (la dérive de formulation qui ferait disparaître
|
||||
# un chiffre est elle-même une régression de traçabilité).
|
||||
#
|
||||
@@ -1518,6 +1525,102 @@ if acc_fi is not None:
|
||||
bad(f"Recette · {ACC_FI} — dit {'/'.join(m.groups())} MAIS matrice dit "
|
||||
f"{'/'.join(acc_exp)} ({acc_src}) → régénérer la fiche")
|
||||
|
||||
# ============================================================================
|
||||
# Fiscal · e-CF DGII — le CONTRAT DE FORMAT de l'e-NCF (« E + tipoeCF(2) +
|
||||
# secuencia(10) » = 13) transcrit À LA MAIN dans QUATRE endroits de prose (README
|
||||
# ×3 + fiche agent erpnext_backend), sans AUCUN gate d'IDENTITÉ.
|
||||
# ----------------------------------------------------------------------------
|
||||
# Le générateur ecf_dgii_gen émet out/ecf_plan.json (byte-gaté par check_artifacts
|
||||
# ⇒ faisant autorité) dont le bloc `e_ncf` PORTE le format de l'identifiant
|
||||
# électronique DGII : `prefix` (« E »), `longueur` (13), `regex`
|
||||
# (« ^E[0-9]{12}$ ») et `structure` (« E + tipoeCF (2 chiffres) + secuencia
|
||||
# (10 chiffres) »). Ce format — préfixe + longueur du segment tipo + longueur du
|
||||
# segment secuencia + longueur totale — est le CŒUR du module (le « composeur
|
||||
# traçable ») et il est recopié À LA MAIN dans QUATRE endroits de prose :
|
||||
# • README:10 « composeur d'e-NCF traçable `E + tipoeCF(2) + secuencia(10)` »
|
||||
# • README:75 (invariant 7) « E+tipo(2)+seq(10)=13 » (porte la longueur TOTALE)
|
||||
# • README:84 (composition) « e_ncf = "E" + tipo(2) + secuencia(10) »
|
||||
# • 03_agents/erpnext_backend/AGENT.md:33 « `E + tipoeCF(2) + secuencia(10)` »
|
||||
# Le bloc racine de check_readme_claims ne gate QUE le COMPTE de tests e-CF
|
||||
# (« 39 »). Aucun gate ne comparait la LONGUEUR des segments à l'artefact : allonger
|
||||
# la secuencia (rango DGII à 12 chiffres → seq=12, longueur=15, regex 14 digits)
|
||||
# OU changer le préfixe ferait dériver les QUATRE proses en silence pendant que
|
||||
# l'ecf_plan byte-gaté dit autre chose — « vert trompeur » qu'aucune suite tests/
|
||||
# (qui teste des FONCTIONS ncf.compose/parse, pas la prose des docs) n'attrape.
|
||||
# Même patron que l'énumération des onglets Mobile, la carte 4Big ou les open items
|
||||
# 5D. On RECOMPUTE (prefix, tipo_len, seq_len, total) depuis le SEUL bloc `e_ncf`
|
||||
# (zéro duplication du format du générateur #6) et on exige que CHAQUE prose
|
||||
# l'encode EXACTEMENT. Cohérences croisées en bonus (mordent un artefact
|
||||
# INTERNEMENT incohérent) : |prefix| + tipo_len + seq_len == longueur (1+2+10==13)
|
||||
# ET le nombre de chiffres du `regex` == tipo_len + seq_len (12 == 2+10). Un claim
|
||||
# absent échoue AUSSI (la disparition d'un format est une régression · traçabilité).
|
||||
# ============================================================================
|
||||
ECF_RD = f"{D}/fiscal/ecf_dgii/README.md"
|
||||
ECF_FI = "03_agents/erpnext_backend/AGENT.md"
|
||||
try:
|
||||
encf = load("fiscal/ecf_dgii/out/ecf_plan.json")["e_ncf"]
|
||||
ecf_prefix = encf["prefix"]
|
||||
ecf_total = int(encf["longueur"])
|
||||
ecf_seglens = [int(x) for x in
|
||||
re.findall(r"\((\d+)\s*chiffres?\)", encf["structure"])]
|
||||
ecf_mdig = re.search(r"\[0-9\]\{(\d+)\}", encf["regex"])
|
||||
except (OSError, KeyError, ValueError) as e:
|
||||
bad(f"Fiscal · artefact ecf_plan illisible/inattendu : {e}"); encf = None
|
||||
if encf is not None:
|
||||
if len(ecf_seglens) != 2:
|
||||
bad(f"Fiscal · e_ncf.structure malformée : {encf['structure']!r} "
|
||||
f"(attendu 2 segments « (N chiffres) », trouvé {ecf_seglens})")
|
||||
else:
|
||||
ecf_tipo, ecf_seq = ecf_seglens
|
||||
# Cohérences croisées : l'artefact doit être INTERNEMENT cohérent.
|
||||
if len(ecf_prefix) != 1:
|
||||
bad(f"Fiscal · incohérence artefact : prefix={ecf_prefix!r} n'est pas "
|
||||
f"1 caractère")
|
||||
if 1 + ecf_tipo + ecf_seq != ecf_total:
|
||||
bad(f"Fiscal · incohérence artefact : 1+{ecf_tipo}+{ecf_seq}="
|
||||
f"{1 + ecf_tipo + ecf_seq} MAIS longueur={ecf_total}")
|
||||
if ecf_mdig is None or int(ecf_mdig.group(1)) != ecf_tipo + ecf_seq:
|
||||
got = ecf_mdig.group(1) if ecf_mdig else "?"
|
||||
bad(f"Fiscal · incohérence artefact : regex porte {got} chiffres MAIS "
|
||||
f"tipo+seq={ecf_tipo + ecf_seq}")
|
||||
exp_ncf = f"{ecf_prefix} + tipo({ecf_tipo}) + secuencia({ecf_seq}) = {ecf_total}"
|
||||
def ecf_check(tag, path, txt, m, with_total):
|
||||
if m is None:
|
||||
bad(f"Fiscal · {path} — {tag} : format e-NCF INTROUVABLE "
|
||||
f"(attendu {exp_ncf})")
|
||||
return
|
||||
g = m.groups()
|
||||
ok = (g[0] == ecf_prefix and int(g[1]) == ecf_tipo
|
||||
and int(g[2]) == ecf_seq
|
||||
and (not with_total or int(g[3]) == ecf_total))
|
||||
if ok:
|
||||
good(f"Fiscal · {path} — {tag} : {exp_ncf} == e_ncf (artefact)")
|
||||
else:
|
||||
shown = "/".join(g)
|
||||
bad(f"Fiscal · {path} — {tag} : dit {shown} MAIS e_ncf dit "
|
||||
f"prefix={ecf_prefix} tipo={ecf_tipo} seq={ecf_seq} "
|
||||
f"total={ecf_total} → régénérer le doc")
|
||||
# 1) README:10 — résumé « composeur d'e-NCF traçable `E + tipoeCF(2) + secuencia(10)` »
|
||||
ecf_rd = read_norm(ECF_RD)
|
||||
if ecf_rd is not None:
|
||||
ecf_check("résumé composeur", ECF_RD, ecf_rd,
|
||||
re.search(r"`([A-Z])\s*\+\s*tipoeCF\((\d+)\)\s*\+\s*"
|
||||
r"secuencia\((\d+)\)`", ecf_rd), False)
|
||||
# 2) README:75 — invariant 7 « E+tipo(2)+seq(10)=13 » (porte la longueur totale)
|
||||
ecf_check("invariant format", ECF_RD, ecf_rd,
|
||||
re.search(r"\(([A-Z])\+tipo\((\d+)\)\+seq\((\d+)\)=(\d+)",
|
||||
ecf_rd), True)
|
||||
# 3) README:84 — composition « e_ncf = "E" + tipo(2) + secuencia(10) »
|
||||
ecf_check("composition ncf.py", ECF_RD, ecf_rd,
|
||||
re.search(r'e_ncf\s*=\s*"([A-Z])"\s*\+\s*tipo\((\d+)\)\s*\+\s*'
|
||||
r"secuencia\((\d+)\)", ecf_rd), False)
|
||||
# 4) Fiche agent erpnext_backend — « `E + tipoeCF(2) + secuencia(10)` »
|
||||
ecf_fi = read_norm(ECF_FI)
|
||||
if ecf_fi is not None:
|
||||
ecf_check("fiche erpnext_backend", ECF_FI, ecf_fi,
|
||||
re.search(r"`([A-Z])\s*\+\s*tipoeCF\((\d+)\)\s*\+\s*"
|
||||
r"secuencia\((\d+)\)`", ecf_fi), False)
|
||||
|
||||
sys.exit(1 if FAIL else 0)
|
||||
PY
|
||||
rc=$?
|
||||
|
||||
Reference in New Issue
Block a user