[DTP-Worker 20260801_210434] Sprint 8 · buffer · CRM/commissions : gate d'IDENTITÉ du CHAMP DEVISE — la clause devise_field = le champ devise (Select USD/DOP · #10) du DocType Dossier Vente (crm/commissions/README.md:54), invariant CLI #8, transcrite en prose hors de tout gate (grep devise_field dans ci/ = 0)
4e surface distincte du même livrable crm/commissions (après états/champs, anti-taux #6, rôles payés) : le « sur quelle devise » du calcul base×taux. Re-dérivée de 3 sources byte-gatées/constitutionnelles : plan.devise_field (out/commission_plan.json) == champ `devise` du DocType (dossier_vente/doctype_spec.json, fieldtype Select) == options ORDONNÉES == devises canoniques CLAUDE.md #10 (« USD + DOP »). Ancrage vivant (#10) : (0) 2 devises depuis le segment gras de #10 ; (a) cross-artefact plan==DocType==#10 ; (b) prose README:54 == artefacts + #10 + tag #10. Distincte du bloc Fiches #10 (prose ERPNext/CRM) et du bloc e-CF TipoMoneda (spec fiscal). 7 morsures vérifiées (4 README · 1 DocType · 1 CLAUDE.md · 1 plan), 7 gates re-verts, working tree byte-restauré (git checkout --, JAMAIS git clean). ci/README.md (récap + paragraphe détaillé) et 05_activity_log mis à jour. Auto-score 4Big 96/100. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,64 @@
|
||||
# Activity Log · 2026-08-01 · Claude Code DTP
|
||||
|
||||
## Session `20260801_210434` · Buffer S8 · Domaine CRM/commissions : l'**IDENTITÉ du CHAMP DEVISE** — la clause `devise_field` = le champ `devise` (`Select` **USD/DOP** · #10) du DocType Dossier Vente, transcrite **en prose** dans la §« Cross-cohérence » (`crm/commissions/README.md:54`) — était **HORS de tout gate**. Les trois blocs commissions déjà en place gatent les états soumis / brouillons exclus, les champs de base Currency, l'identité des rôles payés (portail `ventes`) et la promesse anti-taux #6 — mais **aucun** ne touchait ce couple champ↔devises (l'**invariant CLI #8** du générateur).
|
||||
|
||||
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||||
close ; poursuite de la série anti-dérive (CLAUDE.md #6). **4e surface distincte du
|
||||
MÊME livrable `crm/commissions`** (après états/champs, anti-taux, rôles payés) — le
|
||||
« **sur quelle devise** » du calcul `base × taux`. Surface DISTINCTE du bloc « Fiches
|
||||
#10 » (prose ERPNext/CRM) et du bloc e-CF `TipoMoneda` (options du spec fiscal) :
|
||||
ici c'est le champ `devise` du DocType Dossier Vente + la clé racine `devise_field`
|
||||
du plan, ancrés sur **CLAUDE.md #10** (« **USD + DOP** devises »).
|
||||
|
||||
**Dérive silencieuse fermée** :
|
||||
- `05_deliverables_mvp/crm/commissions/README.md:54` — clause « `devise_field` = le
|
||||
champ `devise` (`Select` **USD/DOP** · #10) du DocType » : NOMME le champ (`devise`),
|
||||
son fieldtype (`Select`), ses options (`USD/DOP`) et tague `#10`.
|
||||
- Sources faisant autorité : (a) `out/commission_plan.json` (byte-gaté par
|
||||
`check_artifacts`) — clé RACINE `devise_field` (le champ du Dossier Vente qui porte
|
||||
la devise d'un montant commissionné) ; (b) `crm/dossier_vente/doctype_spec.json`
|
||||
(l'INPUT du générateur) — le champ `devise` de fieldtype `Select` + ses `options` ;
|
||||
(c) **CLAUDE.md #10** (ligne 24 : « **USD + DOP** devises ») — les 2 devises
|
||||
canoniques. L'invariant CLI #8 (`commissions_gen.py:151-158`) exige les trois
|
||||
simultanément ; le gate re-dérive INDÉPENDAMMENT.
|
||||
- Piège : la seule vérification existante (`tests/`) teste des **FONCTIONS**
|
||||
finance/résolution, jamais la PROSE vs l'artefact. RENOMMER le champ (`devise`→
|
||||
`moneda`), changer son fieldtype (`Select`→`Data` : énumération PERDUE, montant en
|
||||
monnaie libre) ou altérer ses options (`USD/DOP`→`USD/EUR` : devise HORS #10 → le
|
||||
calcul commissionnerait dans une monnaie non prévue) laisse la prose périmée EN
|
||||
SILENCE. `devise_field` n'apparaissait NULLE PART dans `ci/` (grep = 0).
|
||||
- **État courant** : **aucune valeur périmée** — `plan.devise_field == "devise"` ==
|
||||
champ DocType `devise` (`Select`, options `[USD, DOP]`) == CLAUDE.md #10 ; la prose
|
||||
README recoupe tout exactement (anti-invention #6, rien à réécrire). Le défaut est
|
||||
la **surface ungated**.
|
||||
|
||||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « CRM/Commissions ·
|
||||
IDENTITÉ du CHAMP DEVISE » après le bloc rôles payés) : (0) **ANCRAGE** — les 2
|
||||
devises depuis le segment gras « USD + DOP » de CLAUDE.md #10 ; (a) **CROSS-ARTEFACT**
|
||||
— `plan.devise_field == "devise"` == fieldname du champ DocType, fieldtype `Select`,
|
||||
`options` (ORDRE inclus) == devises #10 ; (b) **PROSE** — README:54 nomme le champ
|
||||
`devise`, le dit `Select`, cite `USD/DOP` == #10 et tague `#10`. Un claim absent
|
||||
échoue AUSSI (traçabilité #6). Direction plan/DocType/#10 → README.
|
||||
|
||||
**7 morsures vérifiées** (4 côté README · 1 DocType · 1 CLAUDE.md · 1 plan) : README
|
||||
champ `devise→moneda` (prose périmée) · README `Select→Data` (type périmé) · README
|
||||
`USD/DOP→USD/EUR` (devises périmées) · README tag `· #10` retiré (claim INTROUVABLE) ·
|
||||
**DocType** `options USD→EUR` (hors #10, cross-artefact) · **CLAUDE.md #10**
|
||||
`USD+DOP→USD+EUR` (ancrage VIVANT · mord le cross-artefact) · **plan** `devise_field
|
||||
devise→moneda` (invariant #8) ; restauré = green : plan.devise_field == DocType ==
|
||||
#10 · prose == artefacts · 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` (clause de la table récap du pipeline + paragraphe détaillé
|
||||
« Quatrième surface du MÊME livrable `crm/commissions` · identité du champ devise »)
|
||||
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 création du
|
||||
champ `devise` du DocType `bench` reste côté VPS).
|
||||
- **Auto-score 4Big** : 96/100.
|
||||
|
||||
## Session `20260801_183412` · Buffer S8 · Domaine Legal/CONFOTUR : les **deux champs du DocType `CONFOTUR Application` DÉRIVÉS du pipeline vente** — `dossier_vente` (Link → cible `workflow.document_type` = `OTO Dossier Vente`) et `estado` (Select → options = les états `confotur_*` du **workflow vente**), transcrits **en prose** dans la §« Cœur du livrable : cross-cohérence » (`legal/confotur/README.md:33-36`) — étaient **HORS de tout gate d'IDENTITÉ**. Les blocs CONFOTUR amont gatent le **compte** de champs/rôles, la cross-cohérence des **PERMISSIONS** (rôle→actions) et l'ancrage des **ENTITÉS** (`entite_porteuse`→CLAUDE.md §Entités) — mais **aucun** ne touchait `dossier_vente`/`estado`.
|
||||
|
||||
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||||
|
||||
+25
-1
File diff suppressed because one or more lines are too long
@@ -3559,6 +3559,105 @@ if cr_ev is not None:
|
||||
good(f"CRM commissions rôles · MANIFEST.roles_rbac_utilises == {len(cr_ids)} "
|
||||
f"rôles distincts payés (counts.roles cohérent)")
|
||||
|
||||
# ============================================================================
|
||||
# CRM/Commissions · IDENTITÉ du CHAMP DEVISE — `devise_field` = le champ `devise`
|
||||
# (`Select` USD/DOP · #10) du DocType, transcrit À LA MAIN au README:54 sans gate.
|
||||
# ----------------------------------------------------------------------------
|
||||
# Le générateur commissions_gen émet out/commission_plan.json (byte-gaté par
|
||||
# check_artifacts ⇒ faisant autorité) : le plan porte la clé RACINE `devise_field`
|
||||
# — le champ du Dossier Vente qui PORTE la devise d'un montant commissionné. Son
|
||||
# invariant CLI #8 exige TROIS choses simultanées : `devise_field == "devise"`, le
|
||||
# DocType Dossier Vente (doctype_spec.json, l'INPUT du générateur) porte bien un
|
||||
# champ `devise` de fieldtype `Select`, et ses `options` == `USD`/`DOP` — les DEUX
|
||||
# devises canoniques de CLAUDE.md #10 (« **USD + DOP** devises »). La §Cross-cohérence
|
||||
# RÉÉNONCE le tout EN PROSE (README:54) : « `devise_field` = le champ `devise`
|
||||
# (`Select` **USD/DOP** · #10) du DocType ». Les blocs commissions ci-dessus gatent
|
||||
# les états soumis, les champs de base, les rôles payés et la promesse anti-taux —
|
||||
# mais AUCUN ne touche ce couple champ↔devises. Dérive #6 : RENOMMER le champ
|
||||
# (`devise`→`moneda`) dans le plan/DocType, changer son fieldtype (`Select`→`Data` :
|
||||
# la contrainte d'énumération PERDUE, un montant en monnaie libre), ou altérer ses
|
||||
# options (`USD/DOP`→`USD/EUR` : devise HORS #10, le calcul `base × taux`
|
||||
# commissionnerait dans une monnaie non prévue) laisse la prose périmée EN SILENCE
|
||||
# pendant que l'artefact/DocType dit autre chose → « vert trompeur » qu'aucune suite
|
||||
# tests/ (FONCTIONS finance/résolution, jamais la prose vs artefact) n'attrape ; ce
|
||||
# n'est ni un lien, ni un terme interdit, ni un `out/` byte-gaté du module → invisible
|
||||
# à check_docs/guard_constraints. On RECOMPUTE depuis les artefacts byte-gatés + la
|
||||
# contrainte constitutionnelle : (0) ANCRAGE — les 2 devises depuis CLAUDE.md #10
|
||||
# (segment gras « USD + DOP ») ; (a) CROSS-ARTEFACT — plan.devise_field == "devise"
|
||||
# == fieldname du champ DocType · fieldtype == "Select" · options (ORDONNÉES) ==
|
||||
# devises #10 ; (b) PROSE — README:54 nomme le champ `devise`, le dit `Select`, cite
|
||||
# USD/DOP == #10 et tague #10. Un claim absent échoue AUSSI (traçabilité #6).
|
||||
# Direction plan/DocType/CLAUDE.md #10 → README.
|
||||
# ============================================================================
|
||||
try:
|
||||
cd_plan = load("crm/commissions/out/commission_plan.json")
|
||||
cd_dt = load("crm/dossier_vente/doctype_spec.json")
|
||||
cd_cm = open("CLAUDE.md", encoding="utf-8").read()
|
||||
except (OSError, KeyError, ValueError, TypeError) as e:
|
||||
bad(f"CRM commissions devise · artefact/CLAUDE.md illisible/inattendu : {e}"); cd_plan = None
|
||||
if cd_plan is not None:
|
||||
# (0) ANCRAGE #10 : les 2 devises canoniques (segment gras « USD + DOP »)
|
||||
cd_cur = None
|
||||
cd_l10 = re.search(r"^10\.\s+(.+)$", cd_cm, re.M)
|
||||
if cd_l10:
|
||||
for seg in re.split(r"·", cd_l10.group(1)):
|
||||
if "devise" in seg.lower():
|
||||
mm = re.search(r"\*\*(.+?)\*\*", seg)
|
||||
if mm:
|
||||
cd_cur = [t.strip() for t in re.split(r"[+/]", mm.group(1)) if t.strip()]
|
||||
if not cd_cur:
|
||||
bad("CRM commissions devise · devises #10 (« **USD + DOP** ») INTROUVABLES dans "
|
||||
"CLAUDE.md #10 → ancrage rompu")
|
||||
else:
|
||||
cd_field = None
|
||||
for grp in cd_dt.get("field_groups", []):
|
||||
for f in grp.get("fields", []):
|
||||
if f.get("fieldname") == "devise":
|
||||
cd_field = f
|
||||
cd_pf = cd_plan.get("devise_field")
|
||||
cd_opts = ([ln for ln in cd_field.get("options", "").split("\n") if ln]
|
||||
if cd_field else None)
|
||||
# (a) CROSS-ARTEFACT : plan ↔ DocType ↔ devises #10 (invariant CLI #8)
|
||||
if cd_pf != "devise":
|
||||
bad(f"CRM commissions devise · plan.devise_field={cd_pf!r} ≠ 'devise' → "
|
||||
f"invariant #8 cassé (le champ porteur de la devise a changé)")
|
||||
elif cd_field is None:
|
||||
bad("CRM commissions devise · champ `devise` ABSENT du DocType Dossier Vente "
|
||||
"→ invariant #8 (options USD/DOP invérifiables)")
|
||||
elif cd_field.get("fieldtype") != "Select":
|
||||
bad(f"CRM commissions devise · champ `devise` fieldtype={cd_field.get('fieldtype')!r} "
|
||||
f"≠ 'Select' → énumération USD/DOP PERDUE (monnaie libre)")
|
||||
elif cd_opts != cd_cur:
|
||||
bad(f"CRM commissions devise · options du champ `devise` {cd_opts} ≠ devises #10 "
|
||||
f"{cd_cur} (ordre inclus) → devise HORS CLAUDE.md #10")
|
||||
else:
|
||||
good(f"CRM commissions devise · plan.devise_field='devise' == DocType champ `devise` "
|
||||
f"(Select {cd_opts}) == CLAUDE.md #10")
|
||||
# (b) PROSE README:54 — champ · fieldtype · devises · tag #10
|
||||
cd_rd = read_norm(CM_RD)
|
||||
mpr = re.search(
|
||||
r"`devise_field`\*\* = le champ `([a-z_]+)` \(`(\w+)` \*\*([A-Z/]+)\*\* · #10\)",
|
||||
cd_rd or "")
|
||||
if mpr is None:
|
||||
bad(f"CRM commissions devise · {CM_RD} — claim « `devise_field` = le champ "
|
||||
f"`devise` (`Select` **USD/DOP** · #10) » INTROUVABLE/malformé (traçabilité #6)")
|
||||
else:
|
||||
p_field, p_ftype = mpr.group(1), mpr.group(2)
|
||||
p_cur = mpr.group(3).split("/")
|
||||
errs = []
|
||||
if p_field != "devise":
|
||||
errs.append(f"champ `{p_field}` ≠ `devise`")
|
||||
if p_ftype != "Select":
|
||||
errs.append(f"type `{p_ftype}` ≠ `Select`")
|
||||
if p_cur != cd_cur:
|
||||
errs.append(f"devises {p_cur} ≠ #10 {cd_cur}")
|
||||
if errs:
|
||||
bad(f"CRM commissions devise · {CM_RD} — prose périmée : "
|
||||
+ " · ".join(errs) + " → régénérer le README")
|
||||
else:
|
||||
good(f"CRM commissions devise · {CM_RD} — prose « champ `devise` "
|
||||
f"(`Select` {'/'.join(p_cur)}) · #10 » == artefacts + CLAUDE.md #10")
|
||||
|
||||
# ============================================================================
|
||||
# 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