[DTP-Worker] Sprint 8 · buffer L75 · Domaine Legal : la synthèse du DocType « CONFOTUR Application » (« 18 champs · 14 de donnée · 4 sections · 3 rôles · 2 évènements de dépôt ») était transcrite À LA MAIN dans DEUX docs (README du module legal/confotur + cellule de la fiche agent onapi_legal, mêmes 5 nombres du même spec) sans AUCUN gate — ajouter un champ/section/rôle au confotur_spec ferait dériver les deux docs en silence pendant que legal/confotur/out/MANIFEST.json (byte-gaté par check_artifacts, counts recomptés du confotur_spec.json à chaque build) dit autre chose → nouveau bloc dans check_readme_claims recomputant le quintuplet (fields + data_fields + sections + roles + depot_events) depuis MANIFEST.counts et exigeant l'égalité avec les deux docs (4 morsures vérifiées : dérive sections README · dérive champs 2e doc · dérive évènements de dépôt captée là où le total de champs est aveugle · claim disparu = red)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+12
-1
@@ -20,7 +20,7 @@ et manuellement (`workflow_dispatch`). Jobs statiques (+ une suite `unittest` pa
|
||||
| `check-artifacts` | `ci/check_artifacts.sh` | Reproductibilité : chaque `out/*.json` versionné == build frais | ✅ oui |
|
||||
| `check-regression` | `ci/check_regression.sh` | Fraîcheur : `qa/regression/out/regression_run.json` (`run`) == run frais + verdict PASS | ✅ oui |
|
||||
| `check-ci-integrity` | `ci/check_ci_integrity.sh` | Intégrité du câblage : `gate.needs` == tous les jobs non-manuels · chaque `ci/*.sh` câblé au gate | ✅ oui |
|
||||
| `check-readme-claims` | `ci/check_readme_claims.sh` | Intégrité des chiffres des docs d'entrée : chaque nombre de `README.md` « État courant », de la fiche QA « Verdict agrégé » **et** de la colonne « Tests » par suite des tables de fiches **et** des agrégats en prose (Total CRM / RBAC / e-CF) **et** des comptes par workspace des portails (cartes/liens/rôles, ×2 docs) **et** des comptes RBAC des 3 volets (table Nb rôles/profil, ligne agrégée apply_plan, ventilation userperm) **et** des comptes de mots-clés SEO (total + fr/en/es, ×2 docs) **et** du pipeline vente CRM (états/transitions, ×2 docs) **et** de l'app mobile Expo (onglets/rôles/langues/identifiants a_confirmer) == artefact cité (#6) | ✅ oui |
|
||||
| `check-readme-claims` | `ci/check_readme_claims.sh` | Intégrité des chiffres des docs d'entrée : chaque nombre de `README.md` « État courant », de la fiche QA « Verdict agrégé » **et** de la colonne « Tests » par suite des tables de fiches **et** des agrégats en prose (Total CRM / RBAC / e-CF) **et** des comptes par workspace des portails (cartes/liens/rôles, ×2 docs) **et** des comptes RBAC des 3 volets (table Nb rôles/profil, ligne agrégée apply_plan, ventilation userperm) **et** des comptes de mots-clés SEO (total + fr/en/es, ×2 docs) **et** du pipeline vente CRM (états/transitions, ×2 docs) **et** de l'app mobile Expo (onglets/rôles/langues/identifiants a_confirmer) **et** du DocType CONFOTUR (champs/données/sections/rôles/évènements de dépôt, ×2 docs) == artefact cité (#6) | ✅ oui |
|
||||
| `gate` | — | Agrégat vert = gate qualité 4Big franchi | ✅ oui |
|
||||
|
||||
Aucune dépendance réseau/marketplace hors `actions/checkout`. Tout tourne avec
|
||||
@@ -209,6 +209,17 @@ identifiants_a_confirmer}`, byte-gaté par `check_artifacts`). Recomputer **les
|
||||
quatre** volets mord une dérive de n'importe lequel (ajouter un rôle/portail RBAC,
|
||||
une langue, un credential store) là où un seul nombre resterait aveugle.
|
||||
|
||||
Même classe enfin sur le **DocType CONFOTUR Application** (livrable `legal/confotur`) :
|
||||
la ligne de synthèse du README du module (« **18 champs** (14 de donnée) · **4
|
||||
sections** · **3 rôles** · … · **2 évènements de dépôt** ») **et** la cellule de la
|
||||
fiche agent `onapi_legal` transcrivaient **à la main** le même quintuplet, dérivé du
|
||||
spec du DocType. Les cinq nombres sont recomputés depuis
|
||||
`legal/confotur/out/MANIFEST.json` (`counts.{fields,data_fields,sections,roles,
|
||||
depot_events}`, recomptés du `confotur_spec.json` à chaque build, byte-gaté par
|
||||
`check_artifacts`) et comparés aux **deux** docs. Recomputer **les cinq** volets mord
|
||||
une dérive de n'importe lequel (ajouter un champ/une section/un rôle au spec) là où un
|
||||
seul nombre resterait aveugle.
|
||||
|
||||
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é). stdlib pur
|
||||
(bash/git/python3), zéro réseau.
|
||||
|
||||
@@ -67,6 +67,11 @@
|
||||
# a_confirmer » transcrit À LA MAIN → app_config
|
||||
# MANIFEST.counts (onglets/roles_couverts/langues/identifiants_a_confirmer,
|
||||
# recomptés de rbac_50_roles + seo_spec + a_confirmer, byte-gatés)
|
||||
# legal/confotur/README.md + 03_agents/onapi_legal/AGENT.md (DocType CONFOTUR) :
|
||||
# • quintuplet « 18 champs (14 de donnée) · 4 sections · 3 rôles · 2 évènements
|
||||
# de dépôt » transcrit À LA MAIN dans DEUX docs → confotur
|
||||
# MANIFEST.counts (fields/data_fields/sections/roles/depot_events, recomptés
|
||||
# de confotur_spec.json, byte-gatés)
|
||||
# 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é).
|
||||
#
|
||||
@@ -740,6 +745,63 @@ if mob_exp is not None:
|
||||
bad(f"Mobile · {MOB_RD} — dit {'/'.join(m.groups())} MAIS MANIFEST dit "
|
||||
f"{'/'.join(mob_exp)} ({mob_src}) → régénérer le README")
|
||||
|
||||
# ============================================================================
|
||||
# Legal · DocType CONFOTUR Application (champs / sections / rôles / évènements de
|
||||
# dépôt) — même classe de « vert trompeur », transcrit À LA MAIN dans DEUX docs.
|
||||
# ----------------------------------------------------------------------------
|
||||
# Le générateur confotur émet out/MANIFEST.json dont `counts` porte fields,
|
||||
# data_fields, sections, roles et depot_events, RECOMPTÉS à chaque build depuis
|
||||
# confotur_spec.json (byte-gaté par check_artifacts ⇒ artefact faisant autorité).
|
||||
# Ce quintuplet est recopié À LA MAIN à DEUX endroits : la ligne de synthèse du
|
||||
# README du module (05_deliverables_mvp/legal/confotur/README.md — « 18 champs
|
||||
# (14 de donnée) · 4 sections · 3 rôles · … · 2 évènements de dépôt ») ET la
|
||||
# cellule de la fiche agent onapi_legal (03_agents/onapi_legal/AGENT.md — mêmes 5
|
||||
# nombres, chacun en gras). Aucun gate ne les couvrait : ajouter un champ/une
|
||||
# section/un rôle au spec ferait dériver LES DEUX docs en silence pendant que
|
||||
# l'artefact dit autre chose — même piège que les mots-clés SEO ou les triplets
|
||||
# par workspace des portails. On RECOMPUTE ici les 5 nombres depuis
|
||||
# MANIFEST.counts (déjà byte-gaté · zéro duplication du compteur du générateur)
|
||||
# et on exige l'égalité avec les DEUX docs. Un claim absent échoue AUSSI
|
||||
# (traçabilité). Recomputer les 5 (et pas le seul total de champs) mord une dérive
|
||||
# de N'IMPORTE lequel des volets là où un seul nombre resterait aveugle.
|
||||
# ============================================================================
|
||||
CONF_RD = f"{D}/legal/confotur/README.md"
|
||||
CONF_FI = "03_agents/onapi_legal/AGENT.md"
|
||||
try:
|
||||
conf_c = load("legal/confotur/out/MANIFEST.json")["counts"]
|
||||
conf_exp = (str(conf_c["fields"]),
|
||||
str(conf_c["data_fields"]),
|
||||
str(conf_c["sections"]),
|
||||
str(conf_c["roles"]),
|
||||
str(conf_c["depot_events"]))
|
||||
except (OSError, KeyError, ValueError) as e:
|
||||
bad(f"Legal confotur · MANIFEST illisible/inattendu : {e}"); conf_exp = None
|
||||
if conf_exp is not None:
|
||||
conf_src = (f"champs={conf_exp[0]} données={conf_exp[1]} sections={conf_exp[2]} "
|
||||
f"rôles={conf_exp[3]} dépôts={conf_exp[4]}")
|
||||
# README du module (sans gras) et fiche agent (chaque nombre en gras) —
|
||||
# même quintuplet, deux mises en forme distinctes du même artefact.
|
||||
conf_docs = (
|
||||
(CONF_RD, r"(\d+) champs \((\d+) de donnée\) · (\d+) sections · (\d+) rôles"
|
||||
r" · soumissible · (\d+) évènements de dépôt"),
|
||||
(CONF_FI, r"\*\*(\d+) champs\*\* \((\d+) de donnée\) · \*\*(\d+) sections\*\*"
|
||||
r" · \*\*(\d+) rôles/permissions\*\* · \*\*(\d+) évènements de dépôt\*\*"),
|
||||
)
|
||||
for path_f, pat in conf_docs:
|
||||
txt = read_norm(path_f)
|
||||
if txt is None:
|
||||
continue
|
||||
m = re.search(pat, txt)
|
||||
if m is None:
|
||||
bad(f"Legal confotur · {path_f} — synthèse DocType INTROUVABLE "
|
||||
f"(attendu {conf_src})")
|
||||
elif m.groups() == conf_exp:
|
||||
good(f"Legal confotur · {path_f} — {'/'.join(m.groups())} == "
|
||||
f"MANIFEST ({conf_src})")
|
||||
else:
|
||||
bad(f"Legal confotur · {path_f} — dit {'/'.join(m.groups())} MAIS "
|
||||
f"MANIFEST dit {'/'.join(conf_exp)} ({conf_src}) → régénérer le doc")
|
||||
|
||||
sys.exit(1 if FAIL else 0)
|
||||
PY
|
||||
rc=$?
|
||||
|
||||
Reference in New Issue
Block a user