[DTP-Worker] Sprint 8 · buffer L60 · Domaine SEO (2e surface) : la COMPOSITION du graphe schema.org (« graphe JSON-LD Organization + une Residence par projet ») était décrite EN PROSE dans le README du module seo sans AUCUN gate d'IDENTITÉ. Le bloc SEO existant ne gate que le COMPTE de mots-clés (total + fr/en/es via MANIFEST.counts) — surface distincte du MÊME README. Ces @type sont DATA-DERIVED : l'ensemble des @type du @graph de seo/out/seo_schema_org.json (byte-gaté par check_artifacts) = un nœud racine Organization (@id …#organization) + une Residence par projet, listings uniformes. Aucun gate ne comparait ces TYPES à l'artefact : RENOMMER le @type des listings (Residence→Apartment, un @type voisin du rango schema.org) · AJOUTER un 3e type de nœud (Offer/Product) · CASSER la bijection (2 nœuds pour un projet) ferait dériver la prose en silence pendant que le graphe byte-gaté dit autre chose — « vert trompeur » qu'aucune suite tests/ (qui teste des FONCTIONS de génération, pas la prose du README) n'attrape → nouveau bloc recomputant l'ENSEMBLE des @type depuis SON artefact byte-gaté (zéro duplication du contrat du générateur #6) et exigeant que la parenthèse README les nomme EXACTEMENT. Contrôle par ENSEMBLE (absent ET en trop mordus via set-diff) + le type « par projet » nommé == @type des listings. Cohérences croisées en bonus (mordent un artefact INTERNEMENT incohérent) : nœud racine Organization SINGLETON · listings UNIFORMES (un seul @type) et en BIJECTION avec les projets (listings == projects == schema_org_nodes−1 du MANIFEST) · aucune offers (statuts sans prix · USD #10). Un claim absent échoue AUSSI. 6 morsures vérifiées : prose listing Residence→Apartment captée (absents=[Residence] en trop=[Apartment] + « par projet » désaligné) · prose racine Organization→Business captée · artefact +nœud Offer (prose absente + listings non uniformes) capté · artefact 1 listing Residence→Apartment (non uniforme) capté · MANIFEST listings 9→8 (bijection cassée) capté · composition prose supprimée (INTROUVABLE) captée ; restauré = green : racine Organization singleton · 9 × Residence · total 10 nœuds · aucune offers == seo_schema_org.@graph. État courant : aucun type périmé (anti-invention #6, rien à réécrire) — le défaut est la surface ungated. ci/README.md (table + détail « 2e surface SEO ») mis à jour · 7 gates re-verts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,31 @@
|
|||||||
# Activity Log · 2026-07-31 · Claude Code DTP
|
# Activity Log · 2026-07-31 · Claude Code DTP
|
||||||
|
|
||||||
|
## Session `20260731_173114` · Buffer S8 · Domaine SEO (2e surface) : la **composition du graphe schema.org** (« graphe JSON-LD (`Organization` + une `Residence` par projet) ») était décrite EN PROSE dans le README du module `seo` sans AUCUN gate d'IDENTITÉ — le bloc SEO existant ne gate que le COMPTE de mots-clés (total + fr/en/es).
|
||||||
|
|
||||||
|
- **Constat** : les `@type` du `@graph` de `seo/out/seo_schema_org.json` (byte-gaté)
|
||||||
|
sont l'ensemble faisant autorité : un nœud racine `Organization` (`@id …#organization`)
|
||||||
|
+ une `Residence` par projet. Le README:16 les transcrit à la main. Renommer le
|
||||||
|
`@type` des listings (`Residence`→`Apartment`), ajouter un 3ᵉ type (`Offer`/`Product`)
|
||||||
|
ou casser la bijection ferait dériver la prose en silence pendant que l'artefact
|
||||||
|
dit autre chose — « vert trompeur » qu'aucune suite tests/ (qui teste des FONCTIONS
|
||||||
|
de génération, pas la prose) n'attrape.
|
||||||
|
- **Gate ajouté** (`ci/check_readme_claims.sh`) : recompute l'ENSEMBLE des `@type`
|
||||||
|
depuis `seo_schema_org.@graph` (zéro duplication du contrat du générateur #6) et
|
||||||
|
exige que la parenthèse README les nomme EXACTEMENT (set-diff absent ET en trop ;
|
||||||
|
plus le type « par projet » nommé == le `@type` des listings). Cohérences croisées
|
||||||
|
en bonus : racine `Organization` SINGLETON · listings UNIFORMES (un seul `@type`)
|
||||||
|
et en BIJECTION avec les projets (`listings == projects == schema_org_nodes−1` du
|
||||||
|
MANIFEST) · aucune `offers` (statuts sans prix · USD #10).
|
||||||
|
- **6 morsures vérifiées** : prose listing `Residence`→`Apartment` captée (absents=[Residence]
|
||||||
|
en trop=[Apartment] + « par projet » désaligné) · prose racine `Organization`→`Business`
|
||||||
|
captée · artefact +nœud `Offer` (prose absente + listings non uniformes) capté · artefact
|
||||||
|
1 listing `Residence`→`Apartment` (non uniforme) capté · MANIFEST `listings` 9→8 (bijection
|
||||||
|
cassée) capté · composition prose supprimée (INTROUVABLE) captée ; restauré = green
|
||||||
|
(`Organization` racine singleton · 9 × `Residence` · total 10 nœuds · aucune offers).
|
||||||
|
- État courant : aucun type périmé (anti-invention #6, rien à réécrire) — le défaut est
|
||||||
|
la surface ungated. `ci/README.md` (table + détail « 2ᵉ surface SEO ») mis à jour ·
|
||||||
|
**7 gates re-verts**.
|
||||||
|
|
||||||
## Session `20260731_170112` · Buffer S8 · Domaine RBAC/fixtures_gen : le **catalogue des DocTypes `custom`** à créer sur le VPS (« `Faisabilité`, `Publiciste Log`, `CONFOTUR Application`, `API Access` ») ET la **séparation des pouvoirs** (« `set_user_permissions` n'est émis que pour le rôle **RBAC Admin** ») étaient transcrits À LA MAIN dans le README du module sans AUCUN gate d'IDENTITÉ — le bloc racine ne gate que le COMPTE (« 50 rôles / 116 DocPerm » via l'agrégat RBAC de l'apply_plan).
|
## Session `20260731_170112` · Buffer S8 · Domaine RBAC/fixtures_gen : le **catalogue des DocTypes `custom`** à créer sur le VPS (« `Faisabilité`, `Publiciste Log`, `CONFOTUR Application`, `API Access` ») ET la **séparation des pouvoirs** (« `set_user_permissions` n'est émis que pour le rôle **RBAC Admin** ») étaient transcrits À LA MAIN dans le README du module sans AUCUN gate d'IDENTITÉ — le bloc racine ne gate que le COMPTE (« 50 rôles / 116 DocPerm » via l'agrégat RBAC de l'apply_plan).
|
||||||
|
|
||||||
**Tâche** : **Sprint 8 · buffer L75** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
**Tâche** : **Sprint 8 · buffer L75** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||||||
|
|||||||
+17
-2
@@ -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-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-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-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 + énumération des transitions à séparation des pouvoirs `{action | allow_self_approval=0}` recomputée de `workflow.json`) **et** de l'app mobile Expo (onglets/rôles/langues/identifiants a_confirmer + énumération ordonnée des onglets recomputée de `role_navigation`, bijection onglet⇔portail) **et** du DocType CONFOTUR (champs/données/sections/rôles/évènements de dépôt, ×2 docs) **et** de l'audit 5D (contrôles/dimensions ×2 docs + ventilation verdict pass/fail/à-confirmer + énumération des open items `control→dimension→propriétaire` recomputée de `audit_report.open_items`) **et** du run-book de déploiement VPS (phases ×2 dans la fiche devops + confirmations préalables count & énumération dans le README) **et** du run-sheet de démo (nombre de modules cités dans le diagramme du README) **et** du montage Chat OTOIA par portail (`Custom Block`/configs runtime/portails, tous = 5 aujourd'hui, ×2 docs) **et** du module de recette `qa/acceptance` (couple livrables de sprint + métriques succès MVP, ×2 docs de module au-delà du README d'entrée) **et** du barème de l'auditeur 4Big (nombre de critères en prose + poids par critère de la table + « generator (N critères) », recomputés de `quality_report.criteria`) **et** de la carte de renormalisation par archétype de l'auditeur 4Big (critères EXCLUS de `data_room`/`parser`/`contract`, recomputés des `checks` par archétype de `quality_report.modules`) **et** du contrat de format de l'e-NCF fiscal (`E + tipoeCF(2) + secuencia(10) = 13` : préfixe/longueurs des segments/longueur totale, ×3 README + fiche `erpnext_backend`, recomputés du bloc `e_ncf` d'`ecf_plan.json` + cohérences croisées `1+tipo+seq==longueur` & `|regex digits|==tipo+seq`) **et** de la cross-cohérence du barème de commissions `crm/commissions` (états brouillon exclus recomputés de `{doc_status=0}` de `workflow.json` + champs de base recomputés de `{base_field}` de `commission_plan.json` + invariant 3 « commissionne seulement des états soumis ») **et** du catalogue RBAC `rbac/fixtures_gen` (DocTypes `custom` à créer énumérés == `MANIFEST.custom_doctypes_a_confirmer` + séparation des pouvoirs : le rôle unique porteur de `set_user_permissions` == `custom_docperm.json`) == 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 + énumération des transitions à séparation des pouvoirs `{action | allow_self_approval=0}` recomputée de `workflow.json`) **et** de l'app mobile Expo (onglets/rôles/langues/identifiants a_confirmer + énumération ordonnée des onglets recomputée de `role_navigation`, bijection onglet⇔portail) **et** du DocType CONFOTUR (champs/données/sections/rôles/évènements de dépôt, ×2 docs) **et** de l'audit 5D (contrôles/dimensions ×2 docs + ventilation verdict pass/fail/à-confirmer + énumération des open items `control→dimension→propriétaire` recomputée de `audit_report.open_items`) **et** du run-book de déploiement VPS (phases ×2 dans la fiche devops + confirmations préalables count & énumération dans le README) **et** du run-sheet de démo (nombre de modules cités dans le diagramme du README) **et** du montage Chat OTOIA par portail (`Custom Block`/configs runtime/portails, tous = 5 aujourd'hui, ×2 docs) **et** du module de recette `qa/acceptance` (couple livrables de sprint + métriques succès MVP, ×2 docs de module au-delà du README d'entrée) **et** du barème de l'auditeur 4Big (nombre de critères en prose + poids par critère de la table + « generator (N critères) », recomputés de `quality_report.criteria`) **et** de la carte de renormalisation par archétype de l'auditeur 4Big (critères EXCLUS de `data_room`/`parser`/`contract`, recomputés des `checks` par archétype de `quality_report.modules`) **et** du contrat de format de l'e-NCF fiscal (`E + tipoeCF(2) + secuencia(10) = 13` : préfixe/longueurs des segments/longueur totale, ×3 README + fiche `erpnext_backend`, recomputés du bloc `e_ncf` d'`ecf_plan.json` + cohérences croisées `1+tipo+seq==longueur` & `|regex digits|==tipo+seq`) **et** de la cross-cohérence du barème de commissions `crm/commissions` (états brouillon exclus recomputés de `{doc_status=0}` de `workflow.json` + champs de base recomputés de `{base_field}` de `commission_plan.json` + invariant 3 « commissionne seulement des états soumis ») **et** du catalogue RBAC `rbac/fixtures_gen` (DocTypes `custom` à créer énumérés == `MANIFEST.custom_doctypes_a_confirmer` + séparation des pouvoirs : le rôle unique porteur de `set_user_permissions` == `custom_docperm.json`) **et** de la composition du graphe schema.org SEO (les `@type` du `@graph` — `Organization` racine + une `Residence` par projet — recomputés de `seo_schema_org.json` + bijection listing⇔projet & absence d'`offers`) == artefact cité (#6) | ✅ oui |
|
||||||
| `gate` | — | Agrégat vert = gate qualité 4Big franchi | ✅ oui |
|
| `gate` | — | Agrégat vert = gate qualité 4Big franchi | ✅ oui |
|
||||||
|
|
||||||
Aucune dépendance réseau/marketplace hors `actions/checkout`. Tout tourne avec
|
Aucune dépendance réseau/marketplace hors `actions/checkout`. Tout tourne avec
|
||||||
@@ -184,7 +184,22 @@ recomputé depuis `seo/out/MANIFEST.json` (`counts.keywords_total` +
|
|||||||
byte-gaté par `check_artifacts`). Recomputer les **trois** langues, pas seulement
|
byte-gaté par `check_artifacts`). Recomputer les **trois** langues, pas seulement
|
||||||
le total, attrape une **compensation** entre langues (fr −1 / en +1) qui laisserait
|
le total, attrape une **compensation** entre langues (fr −1 / en +1) qui laisserait
|
||||||
le total juste et la ventilation fausse — ajouter un projet ferait sinon dériver
|
le total juste et la ventilation fausse — ajouter un projet ferait sinon dériver
|
||||||
**les deux** docs en silence.
|
**les deux** docs en silence. **2ᵉ surface du même README SEO** : la table
|
||||||
|
« Livrables » décrit **en prose** la composition du graphe schema.org (« graphe
|
||||||
|
JSON-LD (`Organization` + une `Residence` par projet) »). Le bloc des comptes de
|
||||||
|
mots-clés est **aveugle** à ces `@type` : **renommer** le type des listings
|
||||||
|
(`Residence` → `Apartment`, un `@type` voisin du rango schema.org), **ajouter** un
|
||||||
|
3ᵉ type de nœud (`Offer`/`Product`) ou **casser** la bijection (deux nœuds pour un
|
||||||
|
projet) laisse la prose figée pendant que `seo/out/seo_schema_org.json` (byte-gaté
|
||||||
|
par `check_artifacts`) dit autre chose. On recompute l'**ensemble** des `@type` du
|
||||||
|
`@graph` et on exige que la parenthèse les nomme **exactement** (set-diff : absent
|
||||||
|
ET en trop ; plus le type « par projet » nommé == le `@type` des listings). En
|
||||||
|
bonus, trois cohérences croisées de l'artefact : le nœud racine `Organization`
|
||||||
|
(`@id …#organization`) est un **singleton**, les listings sont **uniformes** (un
|
||||||
|
seul `@type`) et en **bijection** avec les projets (`listings == projects ==
|
||||||
|
schema_org_nodes−1` du MANIFEST), et le graphe ne porte **aucune** `offers` —
|
||||||
|
cohérent avec « aucun prix pour un statut sans prix » (USD · #10). Un claim
|
||||||
|
supprimé (« composition INTROUVABLE ») échoue **aussi**.
|
||||||
|
|
||||||
Même classe enfin sur le **pipeline vente CRM** : le couple « **9 états · 11
|
Même classe enfin sur le **pipeline vente CRM** : le couple « **9 états · 11
|
||||||
transitions** » (titre de section du README du module `crm/workflow_vente`) et le
|
transitions** » (titre de section du README du module `crm/workflow_vente`) et le
|
||||||
|
|||||||
@@ -1805,6 +1805,101 @@ if fx_cdt is not None:
|
|||||||
bad(f"RBAC fixtures · {FX_RD} — nomme « {mr.group(1).strip()} » MAIS "
|
bad(f"RBAC fixtures · {FX_RD} — nomme « {mr.group(1).strip()} » MAIS "
|
||||||
f"set_user_permissions porté par {fx_sup[0]!r} → régénérer le README")
|
f"set_user_permissions porté par {fx_sup[0]!r} → régénérer le README")
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# SEO · la COMPOSITION du graphe schema.org (JSON-LD) — un nœud racine
|
||||||
|
# `Organization` + une `Residence` PAR PROJET — décrite EN PROSE dans le README
|
||||||
|
# sans AUCUN gate d'IDENTITÉ.
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Le générateur SEO émet out/seo_schema_org.json (byte-gaté par check_artifacts ⇒
|
||||||
|
# faisant autorité). Son `@graph` est l'ENSEMBLE des nœuds JSON-LD : exactement UN
|
||||||
|
# nœud racine `Organization` (@id …#organization) + un listing PAR PROJET, tous du
|
||||||
|
# même @type. Le README:16 décrit cette structure À LA MAIN : « graphe JSON-LD
|
||||||
|
# (`Organization` + une `Residence` par projet) ». Le bloc SEO existant ne gate que
|
||||||
|
# le COMPTE de mots-clés (keywords_total + ventilation par langue) — jamais les
|
||||||
|
# @type du graphe ni la bijection un-listing-par-projet. Aucun gate ne comparait
|
||||||
|
# ces TYPES à l'artefact : RENOMMER le @type des listings (Residence → Apartment,
|
||||||
|
# rango schema.org) OU AJOUTER un 3ᵉ type de nœud (Offer/Product) OU casser la
|
||||||
|
# bijection (2 nœuds pour un projet) ferait dériver la prose en silence pendant que
|
||||||
|
# le graphe byte-gaté dit autre chose — « vert trompeur » qu'aucune suite tests/
|
||||||
|
# (qui teste des FONCTIONS de génération, pas la prose du README) n'attrape. Même
|
||||||
|
# patron que l'énumération des onglets Mobile ou du catalogue custom RBAC. On
|
||||||
|
# RECOMPUTE l'ENSEMBLE des @type depuis SON artefact byte-gaté (zéro duplication du
|
||||||
|
# contrat du générateur #6) et on exige que la prose les nomme EXACTEMENT (absent ET
|
||||||
|
# en trop via set-diff). Cohérences croisées en bonus : le nœud racine Organization
|
||||||
|
# est un SINGLETON ; les listings sont uniformes (un seul @type) et en BIJECTION avec
|
||||||
|
# les projets (listings == projects == schema_org_nodes−1 du MANIFEST byte-gaté) ;
|
||||||
|
# aucune `offers` (statuts sans prix · USD #10). Un claim absent échoue AUSSI.
|
||||||
|
# ============================================================================
|
||||||
|
SEO_SG_RD = f"{D}/seo/README.md"
|
||||||
|
try:
|
||||||
|
sg = load("seo/out/seo_schema_org.json")["@graph"]
|
||||||
|
seo_cnt = load("seo/out/MANIFEST.json")["counts"]
|
||||||
|
sg_org = [n for n in sg if str(n.get("@id", "")).endswith("#organization")]
|
||||||
|
sg_list = [n for n in sg if not str(n.get("@id", "")).endswith("#organization")]
|
||||||
|
sg_types = {n["@type"] for n in sg} # ensemble des @type du graphe
|
||||||
|
org_types = {n["@type"] for n in sg_org}
|
||||||
|
list_types = {n["@type"] for n in sg_list}
|
||||||
|
sg_offers = sum(1 for n in sg if "offers" in n)
|
||||||
|
except (OSError, KeyError, ValueError, TypeError) as e:
|
||||||
|
bad(f"SEO schema.org · artefact illisible/inattendu : {e}"); sg = None
|
||||||
|
if sg is not None:
|
||||||
|
n_proj = seo_cnt.get("projects")
|
||||||
|
# bonus 1 : racine Organization = SINGLETON, d'un seul @type
|
||||||
|
if len(sg_org) != 1 or len(org_types) != 1:
|
||||||
|
bad(f"SEO schema.org · nœud racine #organization non-singleton "
|
||||||
|
f"({len(sg_org)} nœud(s), types={sorted(org_types)}) → graphe suspect")
|
||||||
|
else:
|
||||||
|
good(f"SEO schema.org · racine {sorted(org_types)[0]!r} — singleton (1 nœud)")
|
||||||
|
# bonus 2 : listings uniformes + bijection 1 par projet + total du MANIFEST
|
||||||
|
if not sg_list or len(list_types) != 1:
|
||||||
|
bad(f"SEO schema.org · listings non uniformes (types={sorted(list_types)}) "
|
||||||
|
f"→ un @type unique attendu par projet")
|
||||||
|
elif not (len(sg_list) == n_proj == seo_cnt.get("listings")
|
||||||
|
== seo_cnt.get("schema_org_nodes", 0) - 1):
|
||||||
|
bad(f"SEO schema.org · bijection cassée : {len(sg_list)} listing(s) MAIS "
|
||||||
|
f"projects={n_proj} listings={seo_cnt.get('listings')} "
|
||||||
|
f"schema_org_nodes={seo_cnt.get('schema_org_nodes')} (attendu 1+{n_proj})")
|
||||||
|
else:
|
||||||
|
good(f"SEO schema.org · {len(sg_list)} × {sorted(list_types)[0]!r} — bijection "
|
||||||
|
f"un listing par projet ({n_proj}) · total {seo_cnt.get('schema_org_nodes')} nœuds")
|
||||||
|
# bonus 3 : aucune offers/prix (statuts sans prix · #10 · cohérent MANIFEST.offers)
|
||||||
|
if sg_offers != 0 or seo_cnt.get("offers") != 0:
|
||||||
|
bad(f"SEO schema.org · {sg_offers} nœud(s) `offers` (MANIFEST.offers="
|
||||||
|
f"{seo_cnt.get('offers')}) → prix non attendu pour statuts sans prix (#10)")
|
||||||
|
else:
|
||||||
|
good("SEO schema.org · aucune `offers`/prix (statuts sans prix · USD #10)")
|
||||||
|
seo_sg_rd = read_norm(SEO_SG_RD)
|
||||||
|
if seo_sg_rd is not None:
|
||||||
|
# README:16 — la parenthèse décrit la composition du graphe : ENSEMBLE des @type
|
||||||
|
msg = re.search(r"graphe JSON-LD \(([^)]*)\)", seo_sg_rd)
|
||||||
|
if msg is None:
|
||||||
|
bad(f"SEO schema.org · {SEO_SG_RD} — composition « graphe JSON-LD (…) » "
|
||||||
|
f"INTROUVABLE (attendu {sorted(sg_types)})")
|
||||||
|
else:
|
||||||
|
prose_types = set(re.findall(r"`([A-Za-z]+)`", msg.group(1)))
|
||||||
|
if prose_types == sg_types:
|
||||||
|
good(f"SEO schema.org · {SEO_SG_RD} — @type {sorted(prose_types)} == "
|
||||||
|
f"seo_schema_org.@graph")
|
||||||
|
else:
|
||||||
|
miss = sorted(sg_types - prose_types); extra = sorted(prose_types - sg_types)
|
||||||
|
detail = (f" · absents={miss}" if miss else "") + \
|
||||||
|
(f" · en trop={extra}" if extra else "")
|
||||||
|
bad(f"SEO schema.org · {SEO_SG_RD} — nomme {sorted(prose_types)} MAIS "
|
||||||
|
f"graphe {sorted(sg_types)}{detail} → régénérer le README")
|
||||||
|
# README:16 — le type PAR PROJET nommé == le @type des listings (racine distincte)
|
||||||
|
if len(list_types) == 1:
|
||||||
|
mpp = re.search(r"une `([A-Za-z]+)` par projet", seo_sg_rd)
|
||||||
|
lt = sorted(list_types)[0]
|
||||||
|
if mpp is None:
|
||||||
|
bad(f"SEO schema.org · {SEO_SG_RD} — « une `<type>` par projet » "
|
||||||
|
f"INTROUVABLE (attendu {lt!r})")
|
||||||
|
elif mpp.group(1) == lt:
|
||||||
|
good(f"SEO schema.org · {SEO_SG_RD} — « une `{lt}` par projet » == "
|
||||||
|
f"listings du graphe")
|
||||||
|
else:
|
||||||
|
bad(f"SEO schema.org · {SEO_SG_RD} — dit « une `{mpp.group(1)}` par projet » "
|
||||||
|
f"MAIS listings sont `{lt}` → régénérer le README")
|
||||||
|
|
||||||
sys.exit(1 if FAIL else 0)
|
sys.exit(1 if FAIL else 0)
|
||||||
PY
|
PY
|
||||||
rc=$?
|
rc=$?
|
||||||
|
|||||||
Reference in New Issue
Block a user