[DTP-Worker] Sprint 8 · buffer L75 · Domaine mobile : la ligne récap de l'app Expo (« 5 onglets · 44 rôles couverts · 3 langues · 13 identifiants a_confirmer ») était transcrite À LA MAIN dans le README du module mobile/app_config sans AUCUN gate — ajouter un rôle/portail au contrat RBAC, une langue au site ou un credential store ferait dériver le doc en silence pendant que mobile/app_config/out/MANIFEST.json (byte-gaté par check_artifacts, counts recomptés de rbac_50_roles + seo_spec + liste a_confirmer) dit autre chose → nouveau bloc dans check_readme_claims recomputant le quadruplet (onglets + roles_couverts + langues + identifiants_a_confirmer) depuis MANIFEST.counts et exigeant l'égalité (5 morsures vérifiées : dérive de chacun des 4 volets captée là où un seul nombre resterait 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) == 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) == 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
|
||||
@@ -198,6 +198,17 @@ dérive du 2ᵉ nombre là où le compte d'états seul (repris dans `dossier_ven
|
||||
resterait aveugle — ajouter un état/une transition ferait sinon dériver **les
|
||||
deux** docs en silence.
|
||||
|
||||
Même classe encore sur l'**app mobile Expo** : la ligne récap du README du module
|
||||
`mobile/app_config` (« **5 onglets** · **44 rôles** couverts · **3 langues** ·
|
||||
**13 identifiants `a_confirmer`** ») transcrivait **à la main** un quadruplet dont
|
||||
chaque nombre est recompté à chaque build depuis `rbac_50_roles.json` (portails
|
||||
métier + rôles), `seo_spec.json` (langues) et la liste `a_confirmer` (credentials
|
||||
EAS/stores jamais fabriqués). Les quatre sont recomputés depuis
|
||||
`mobile/app_config/out/MANIFEST.json` (`counts.{onglets,roles_couverts,langues,
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
@@ -62,6 +62,11 @@
|
||||
# Profile · 4 DocType custom + 5 Company + 4 rôles » → apply_plan MANIFEST
|
||||
# • ventilation « 28 entite · 16 groupe · 2 own · 4 equipe » → userperm MANIFEST
|
||||
# (les 3 MANIFEST recalculés du contrat rbac_50_roles.json, byte-gatés)
|
||||
# mobile/app_config/README.md (ligne récap de l'app Expo) :
|
||||
# • quadruplet « 5 onglets · 44 rôles couverts · 3 langues · 13 identifiants
|
||||
# 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)
|
||||
# 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é).
|
||||
#
|
||||
@@ -690,6 +695,51 @@ 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")
|
||||
|
||||
# ============================================================================
|
||||
# Mobile · récap de l'app Expo (onglets / rôles couverts / langues / identifiants
|
||||
# a_confirmer) — même classe de « vert trompeur », transcrite À LA MAIN.
|
||||
# ----------------------------------------------------------------------------
|
||||
# Le générateur app_config émet out/MANIFEST.json dont `counts` porte onglets,
|
||||
# roles_couverts, langues et identifiants_a_confirmer, RECOMPTÉS à chaque build
|
||||
# depuis rbac_50_roles.json (portails métier + rôles), seo_spec.json (langues) et
|
||||
# la liste `a_confirmer` (identifiants EAS/stores jamais fabriqués · byte-gaté par
|
||||
# check_artifacts ⇒ artefact faisant autorité). Ce quadruplet est recopié À LA
|
||||
# MAIN dans la ligne récap du README du module (05_deliverables_mvp/mobile/
|
||||
# app_config/README.md — « **5 onglets** … · **44 rôles** couverts · **3 langues**
|
||||
# · **13 identifiants `a_confirmer`** »). Aucun gate ne le couvrait : ajouter un
|
||||
# rôle/portail au contrat RBAC, une langue au site ou un credential store ferait
|
||||
# dériver le doc 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 4 nombres depuis MANIFEST.counts (déjà byte-gaté · zéro duplication du
|
||||
# compteur du générateur) et on exige l'égalité. Un claim absent échoue AUSSI
|
||||
# (traçabilité). Recomputer les 4 (et pas le seul total de rôles) mord une dérive
|
||||
# de N'IMPORTE lequel des volets là où un seul nombre resterait aveugle.
|
||||
# ============================================================================
|
||||
MOB_RD = f"{D}/mobile/app_config/README.md"
|
||||
try:
|
||||
mob_c = load("mobile/app_config/out/MANIFEST.json")["counts"]
|
||||
mob_exp = (str(mob_c["onglets"]),
|
||||
str(mob_c["roles_couverts"]),
|
||||
str(mob_c["langues"]),
|
||||
str(mob_c["identifiants_a_confirmer"]))
|
||||
except (OSError, KeyError, ValueError) as e:
|
||||
bad(f"Mobile · MANIFEST app_config illisible/inattendu : {e}"); mob_exp = None
|
||||
if mob_exp is not None:
|
||||
mob_src = (f"onglets={mob_exp[0]} rôles={mob_exp[1]} langues={mob_exp[2]} "
|
||||
f"identifiants={mob_exp[3]}")
|
||||
mob_pat = (r"\*\*(\d+) onglets\*\* \([^)]*\) · \*\*(\d+) rôles\*\* couverts · "
|
||||
r"\*\*(\d+) langues\*\* · \*\*(\d+) identifiants")
|
||||
mob_txt = read_norm(MOB_RD)
|
||||
if mob_txt is not None:
|
||||
m = re.search(mob_pat, mob_txt)
|
||||
if m is None:
|
||||
bad(f"Mobile · {MOB_RD} — récap app INTROUVABLE (attendu {mob_src})")
|
||||
elif m.groups() == mob_exp:
|
||||
good(f"Mobile · {MOB_RD} — {'/'.join(m.groups())} == MANIFEST ({mob_src})")
|
||||
else:
|
||||
bad(f"Mobile · {MOB_RD} — dit {'/'.join(m.groups())} MAIS MANIFEST dit "
|
||||
f"{'/'.join(mob_exp)} ({mob_src}) → régénérer le README")
|
||||
|
||||
sys.exit(1 if FAIL else 0)
|
||||
PY
|
||||
rc=$?
|
||||
|
||||
Reference in New Issue
Block a user