[DTP-Worker 20260803_093713] Auto exec · session 20260803_093713
CI / Contraintes NON-NÉGOCIABLES (CLAUDE.md) (push) Has been cancelled
CI / Validation JSON (schémas Faisabilité) (push) Has been cancelled
CI / Qualité documentaire (liens + 4Big) (push) Has been cancelled
CI / Reproductibilité des artefacts out/ (build == commité) (push) Has been cancelled
CI / Fraîcheur matrice de régression (run == commité) (push) Has been cancelled
CI / Intégrité du câblage CI (gate agrège tout · gates statiques verrouillés) (push) Has been cancelled
CI / Intégrité des chiffres du README (valeur == artefact cité · (push) Has been cancelled
CI / Publiciste · parser + schéma + generator (unittest) (push) Has been cancelled
CI / RBAC · 50 rôles + schéma (unittest) (push) Has been cancelled
CI / Faisabilité · générateur 4 volets + round-trip (unittest) (push) Has been cancelled
CI / RBAC · fixtures ERPNext (Role + Custom DocPerm) (push) Has been cancelled
CI / RBAC · plan User Permission (row-level) (push) Has been cancelled
CI / RBAC · Role Profile (bundles par portail) (push) Has been cancelled
CI / RBAC · run-book d'application unifié (agrégat 3 volets) (push) Has been cancelled
CI / Faisabilité · dossier bancable trilingue FR/EN/ES (push) Has been cancelled
CI / CRM · workflow vente ERPNext (lead → CONFOTUR) (push) Has been cancelled
CI / CRM · DocType porteur OTO Dossier Vente (push) Has been cancelled
CI / CRM · barème commissions vendeurs (push) Has been cancelled
CI / CRM · Financement Bancaire (gate hypothécaire RD) (push) Has been cancelled
CI / Fiscal · e-CF DGII (Compupar) (push) Has been cancelled
CI / Frontend · Workspaces 5 portails rôle (push) Has been cancelled
CI / Legal · DocType CONFOTUR Application (push) Has been cancelled
CI / QA · Audit 5D conformité (push) Has been cancelled
CI / SEO · mots-clés trilingues + schema.org + hreflang (push) Has been cancelled
CI / Chat OTOIA · montage par portail (Custom Block) (push) Has been cancelled
CI / QA · Audit 4Big (95+/100 sur 100% deliverables) (push) Has been cancelled
CI / Démo · Scénarios (run-sheet P07 banquier / P05 client) (push) Has been cancelled
CI / QA · Matrice de régression exhaustive (Sprint 8) (push) Has been cancelled
CI / DevOps · Run-book de déploiement VPS unifié (Sprint 8) (push) Has been cancelled
CI / QA · Matrice d'acceptation / traçabilité MVP (Sprint 8) (push) Has been cancelled
CI / Mobile · config app Expo/EAS (navigation par rôle) (push) Has been cancelled
CI / PIE · manifest de dépendances (Annexe 12 · V10.1) (push) Has been cancelled
CI / E2E baseline Playwright (manuel) (push) Has been cancelled
CI / Gate qualité (agrégat) (push) Has been cancelled
CI / Contraintes NON-NÉGOCIABLES (CLAUDE.md) (push) Has been cancelled
CI / Validation JSON (schémas Faisabilité) (push) Has been cancelled
CI / Qualité documentaire (liens + 4Big) (push) Has been cancelled
CI / Reproductibilité des artefacts out/ (build == commité) (push) Has been cancelled
CI / Fraîcheur matrice de régression (run == commité) (push) Has been cancelled
CI / Intégrité du câblage CI (gate agrège tout · gates statiques verrouillés) (push) Has been cancelled
CI / Intégrité des chiffres du README (valeur == artefact cité · (push) Has been cancelled
CI / Publiciste · parser + schéma + generator (unittest) (push) Has been cancelled
CI / RBAC · 50 rôles + schéma (unittest) (push) Has been cancelled
CI / Faisabilité · générateur 4 volets + round-trip (unittest) (push) Has been cancelled
CI / RBAC · fixtures ERPNext (Role + Custom DocPerm) (push) Has been cancelled
CI / RBAC · plan User Permission (row-level) (push) Has been cancelled
CI / RBAC · Role Profile (bundles par portail) (push) Has been cancelled
CI / RBAC · run-book d'application unifié (agrégat 3 volets) (push) Has been cancelled
CI / Faisabilité · dossier bancable trilingue FR/EN/ES (push) Has been cancelled
CI / CRM · workflow vente ERPNext (lead → CONFOTUR) (push) Has been cancelled
CI / CRM · DocType porteur OTO Dossier Vente (push) Has been cancelled
CI / CRM · barème commissions vendeurs (push) Has been cancelled
CI / CRM · Financement Bancaire (gate hypothécaire RD) (push) Has been cancelled
CI / Fiscal · e-CF DGII (Compupar) (push) Has been cancelled
CI / Frontend · Workspaces 5 portails rôle (push) Has been cancelled
CI / Legal · DocType CONFOTUR Application (push) Has been cancelled
CI / QA · Audit 5D conformité (push) Has been cancelled
CI / SEO · mots-clés trilingues + schema.org + hreflang (push) Has been cancelled
CI / Chat OTOIA · montage par portail (Custom Block) (push) Has been cancelled
CI / QA · Audit 4Big (95+/100 sur 100% deliverables) (push) Has been cancelled
CI / Démo · Scénarios (run-sheet P07 banquier / P05 client) (push) Has been cancelled
CI / QA · Matrice de régression exhaustive (Sprint 8) (push) Has been cancelled
CI / DevOps · Run-book de déploiement VPS unifié (Sprint 8) (push) Has been cancelled
CI / QA · Matrice d'acceptation / traçabilité MVP (Sprint 8) (push) Has been cancelled
CI / Mobile · config app Expo/EAS (navigation par rôle) (push) Has been cancelled
CI / PIE · manifest de dépendances (Annexe 12 · V10.1) (push) Has been cancelled
CI / E2E baseline Playwright (manuel) (push) Has been cancelled
CI / Gate qualité (agrégat) (push) Has been cancelled
This commit is contained in:
+22
-1
@@ -542,10 +542,31 @@ jobs:
|
|||||||
- name: Tests générateur config app mobile
|
- name: Tests générateur config app mobile
|
||||||
run: python3 -m unittest discover -s tests -v
|
run: python3 -m unittest discover -s tests -v
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
# PIE · manifest de dépendances (Annexe 12 · V10.1 · directive Project Identity
|
||||||
|
# Engine du 2026-08-03). La faisabilité = SSOT : ce module livre le P0 (schéma
|
||||||
|
# Project Master Data + graphe faisabilité→livrables downstream, §88). Zéro
|
||||||
|
# invention (#6) : contenu transcrit de la directive ; codes projets ancrés à
|
||||||
|
# CLAUDE.md §Projets ; annexe/version verbatim dans la directive ; modules
|
||||||
|
# downstream « gated » = répertoires de livrables réels (FS). Le worker n'écrit
|
||||||
|
# PAS le storage VPS /opt/oto/data/pie/{code}/ (#8). Schéma + 10 invariants.
|
||||||
|
# stdlib pur, zéro pip.
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
pie-manifest-tests:
|
||||||
|
name: PIE · manifest de dépendances (Annexe 12 · V10.1)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: 05_deliverables_mvp/pie/manifest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Tests générateur manifest PIE
|
||||||
|
run: python3 -m unittest discover -s tests -v
|
||||||
|
|
||||||
gate:
|
gate:
|
||||||
name: Gate qualité (agrégat)
|
name: Gate qualité (agrégat)
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [constraints-guard, validate-json, check-docs, check-artifacts, check-regression, check-ci-integrity, check-readme-claims, publiciste-tests, rbac-tests, faisabilite-gen-tests, rbac-fixtures-tests, rbac-userperm-tests, rbac-roleprofile-tests, rbac-applyplan-tests, bancable-tests, crm-workflow-vente-tests, crm-dossier-vente-tests, crm-commissions-tests, crm-financement-bancaire-tests, fiscal-ecf-tests, frontend-portails-tests, legal-confotur-tests, qa-audit-5d-tests, seo-tests, chat-otoia-tests, qa-audit-4big-tests, demo-scenario-tests, qa-regression-tests, devops-deploy-runbook-tests, qa-acceptance-tests, mobile-app-config-tests]
|
needs: [constraints-guard, validate-json, check-docs, check-artifacts, check-regression, check-ci-integrity, check-readme-claims, publiciste-tests, rbac-tests, faisabilite-gen-tests, rbac-fixtures-tests, rbac-userperm-tests, rbac-roleprofile-tests, rbac-applyplan-tests, bancable-tests, crm-workflow-vente-tests, crm-dossier-vente-tests, crm-commissions-tests, crm-financement-bancaire-tests, fiscal-ecf-tests, frontend-portails-tests, legal-confotur-tests, qa-audit-5d-tests, seo-tests, chat-otoia-tests, qa-audit-4big-tests, demo-scenario-tests, qa-regression-tests, devops-deploy-runbook-tests, qa-acceptance-tests, mobile-app-config-tests, pie-manifest-tests]
|
||||||
steps:
|
steps:
|
||||||
- name: Résultat
|
- name: Résultat
|
||||||
run: echo "✅ Gate qualité 4Big franchi — tous les checks verts."
|
run: echo "✅ Gate qualité 4Big franchi — tous les checks verts."
|
||||||
|
|||||||
@@ -149,7 +149,7 @@
|
|||||||
"file": "out/quality_report.json",
|
"file": "out/quality_report.json",
|
||||||
"pointer": "/coverage/ci_modules_count",
|
"pointer": "/coverage/ci_modules_count",
|
||||||
"label": "Modules sous gate qualité",
|
"label": "Modules sous gate qualité",
|
||||||
"valeur": 22,
|
"valeur": 24,
|
||||||
"resolu": true
|
"resolu": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -58,7 +58,7 @@
|
|||||||
| À dire | Chiffre | Source (preuve) |
|
| À dire | Chiffre | Source (preuve) |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Seuil bloquant 4Big | 95 | `qa/audit_4big` · `out/quality_report.json#/pass_score` |
|
| Seuil bloquant 4Big | 95 | `qa/audit_4big` · `out/quality_report.json#/pass_score` |
|
||||||
| Modules sous gate qualité | 22 | `qa/audit_4big` · `out/quality_report.json#/coverage/ci_modules_count` |
|
| Modules sous gate qualité | 24 | `qa/audit_4big` · `out/quality_report.json#/coverage/ci_modules_count` |
|
||||||
|
|
||||||
### 6. Le dossier de vente, pièce bancable finale · 2 min
|
### 6. Le dossier de vente, pièce bancable finale · 2 min
|
||||||
|
|
||||||
|
|||||||
@@ -89,6 +89,7 @@
|
|||||||
"faisabilite/bancable": "contenu",
|
"faisabilite/bancable": "contenu",
|
||||||
"seo": "contenu",
|
"seo": "contenu",
|
||||||
"demo/scenarios": "contenu",
|
"demo/scenarios": "contenu",
|
||||||
|
"pie/manifest": "contenu",
|
||||||
"qa/audit_5d": "verification-qa",
|
"qa/audit_5d": "verification-qa",
|
||||||
"qa/audit_4big": "verification-qa",
|
"qa/audit_4big": "verification-qa",
|
||||||
"qa/regression": "verification-qa",
|
"qa/regression": "verification-qa",
|
||||||
|
|||||||
@@ -5,14 +5,14 @@
|
|||||||
"self_module": "devops/deploy_runbook",
|
"self_module": "devops/deploy_runbook",
|
||||||
"counts": {
|
"counts": {
|
||||||
"phases": 7,
|
"phases": 7,
|
||||||
"modules": 23,
|
"modules": 24,
|
||||||
"modules_mapped": 23,
|
"modules_mapped": 24,
|
||||||
"confirmations": 7,
|
"confirmations": 7,
|
||||||
"confirmations_referenced": 7
|
"confirmations_referenced": 7
|
||||||
},
|
},
|
||||||
"coverage": {
|
"coverage": {
|
||||||
"ci_modules_count": 23,
|
"ci_modules_count": 24,
|
||||||
"mapped_modules_count": 23,
|
"mapped_modules_count": 24,
|
||||||
"bijective": true,
|
"bijective": true,
|
||||||
"missing_in_map": [],
|
"missing_in_map": [],
|
||||||
"extra_in_map": [],
|
"extra_in_map": [],
|
||||||
|
|||||||
@@ -188,6 +188,10 @@
|
|||||||
"module": "faisabilite/generator",
|
"module": "faisabilite/generator",
|
||||||
"ci_job": "faisabilite-gen-tests"
|
"ci_job": "faisabilite-gen-tests"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"module": "pie/manifest",
|
||||||
|
"ci_job": "pie-manifest-tests"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"module": "publiciste",
|
"module": "publiciste",
|
||||||
"ci_job": "publiciste-tests"
|
"ci_job": "publiciste-tests"
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# Caches Python
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
# Le dossier out/ EST commité (manifest de dépendances versionné) — voir README.
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
# PIE · Manifest de dépendances · Annexe 12 · V10.1
|
||||||
|
|
||||||
|
**Directive** : [`DIRECTIVE_PIE_PROJECT_IDENTITY_ENGINE_20260803.md`](../../../DIRECTIVE_PIE_PROJECT_IDENTITY_ENGINE_20260803.md)
|
||||||
|
(Michel · 2026-08-03) · **Auto-score 4Big : 96/100** (≥95 requis · CLAUDE.md #5).
|
||||||
|
|
||||||
|
## Rôle
|
||||||
|
|
||||||
|
Le **Project Identity Engine (PIE)** pose la faisabilité comme **Project DNA ·
|
||||||
|
source unique de vérité (SSOT)** : aucun livrable downstream (brochure, kit
|
||||||
|
banquier, site, app, contrat…) ne doit être recréé à la main si la donnée existe
|
||||||
|
déjà dans la faisabilité, et toute modification de la faisabilité régénère
|
||||||
|
sélectivement les livrables concernés.
|
||||||
|
|
||||||
|
Ce module livre le **P0** de la directive : le **schéma Project Master Data** +
|
||||||
|
le **manifest de dépendances** (§88 de la directive) — le graphe
|
||||||
|
`faisabilité → livrables downstream` versionnable, cross-vérifié.
|
||||||
|
|
||||||
|
Ce que ce worker **ne fait pas** (côté agents · VPS · CLAUDE.md #8) : le storage
|
||||||
|
réel `/opt/oto/data/pie/{code}/`, la génération effective des Brand Books / logos
|
||||||
|
(Flux) / PDF, et l'écriture dans ERPNext / Speckle. Ici : uniquement le contrat
|
||||||
|
de dépendances, à consommer par ces agents.
|
||||||
|
|
||||||
|
## Sortie (`out/`, commité)
|
||||||
|
|
||||||
|
| Fichier | Contenu |
|
||||||
|
|---|---|
|
||||||
|
| `pie_manifest.json` | 12 groupes Master Data · 4 règles de synchronisation · 13 livrables downstream · workflow 10 étapes · 9 marques · storage layout |
|
||||||
|
| `MANIFEST.json` | Traçabilité : sources d'ancrage + comptes dérivés + références des modules gated |
|
||||||
|
|
||||||
|
## Contenu (transcrit VERBATIM de la directive — zéro invention · #6)
|
||||||
|
|
||||||
|
- **Project Master Data** — 12 groupes (§16-29) : identité, localisation,
|
||||||
|
architecture, unités, budget, marketing, BIM, finances, juridique, images,
|
||||||
|
services, calendrier.
|
||||||
|
- **Règles de synchronisation** — 4 déclencheurs (§82-86) :
|
||||||
|
`prix` → brochures · kit banquier · contrats · site · app ·
|
||||||
|
`typologie` → plans · rendus · fiche unité · BIM ·
|
||||||
|
`amenities` → brochures · site · slogan · brand book ·
|
||||||
|
`livraison` → calendrier · brochures · trackers chantier.
|
||||||
|
- **Workflow** — 10 étapes (§108-133), de la validation faisabilité à la publication.
|
||||||
|
- **Marques** — 9 projets (§90-102), codes ancrés à `CLAUDE.md §Projets`.
|
||||||
|
|
||||||
|
### Downstream déjà gated par un module MVP (4/13)
|
||||||
|
|
||||||
|
| Livrable | Module implémenteur |
|
||||||
|
|---|---|
|
||||||
|
| Kit banquier | [`faisabilite/bancable`](../../faisabilite/bancable/README.md) |
|
||||||
|
| Contrats types | [`legal/confotur`](../../legal/confotur/README.md) |
|
||||||
|
| Page projet (site) | [`publiciste`](../../publiciste/README.md) |
|
||||||
|
| Section app mobile | [`mobile/app_config`](../../mobile/app_config/README.md) |
|
||||||
|
|
||||||
|
Les 9 autres (brand book, logos, brochures PDF, plans, rendus, fiche unité, BIM,
|
||||||
|
slogan, calendrier, trackers chantier) sont marqués `a_construire` (P1-P4 de la
|
||||||
|
directive) — aucun sur-engagement.
|
||||||
|
|
||||||
|
## Invariants (schéma + 10, ré-affichés à l'exécution)
|
||||||
|
|
||||||
|
1. Schéma draft-07 de `pie_manifest.json`.
|
||||||
|
2. 12 groupes Master Data, clés uniques == ensemble canonique (§16-29).
|
||||||
|
3. 4 règles sync, triggers == `{prix, typologie, amenities, livraison}` (§82-86).
|
||||||
|
4. Intégrité référentielle : chaque `downstream` + `trigger_group` pointe du réel.
|
||||||
|
5. Registre downstream : `statut` cohérent (`gated` ⇔ module non nul).
|
||||||
|
6. Chaque module downstream non nul **est un répertoire de livrable réel** (FS).
|
||||||
|
7. Workflow = étapes `1..N` contiguës et uniques.
|
||||||
|
8. Codes marques ⊆ `CLAUDE.md §Projets` (ancrage constitution).
|
||||||
|
9. `annexe` (12) + `version_workflow` (V10.1) **verbatim dans la directive**.
|
||||||
|
10. Storage layout hors-repo (`/opt/oto/data/pie/…`) — jamais le `out/` du module (#8).
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 pie_manifest_gen.py validate # schéma + 10 invariants, sans écrire
|
||||||
|
python3 pie_manifest_gen.py build # écrit out/pie_manifest.json + out/MANIFEST.json
|
||||||
|
python3 -m unittest discover -s tests -v
|
||||||
|
```
|
||||||
|
|
||||||
|
Sortie **déterministe** (tri stable, aucun horodatage) → re-générable
|
||||||
|
byte-identique, gaté par `ci/check_artifacts.sh`.
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"generated_from": "pie_spec.json",
|
||||||
|
"claude_md_source": "CLAUDE.md",
|
||||||
|
"directive_source": "DIRECTIVE_PIE_PROJECT_IDENTITY_ENGINE_20260803.md",
|
||||||
|
"engine": "OTO Project Identity Engine (PIE)",
|
||||||
|
"annexe": 12,
|
||||||
|
"version_workflow": "V10.1",
|
||||||
|
"ssot": "faisabilite",
|
||||||
|
"counts": {
|
||||||
|
"master_data_groups": 12,
|
||||||
|
"downstream_total": 13,
|
||||||
|
"downstream_gated": 4,
|
||||||
|
"downstream_a_construire": 9,
|
||||||
|
"sync_rules": 4,
|
||||||
|
"workflow_steps": 10,
|
||||||
|
"brands": 9
|
||||||
|
},
|
||||||
|
"modules_gated_references": [
|
||||||
|
{
|
||||||
|
"cle": "app",
|
||||||
|
"module": "mobile/app_config"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "contrats",
|
||||||
|
"module": "legal/confotur"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "kit_banquier",
|
||||||
|
"module": "faisabilite/bancable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "site",
|
||||||
|
"module": "publiciste"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"note_anti_invention": "Toute donnée est transcrite de la directive PIE (SSOT · #6) : aucune valeur projet (prix, surfaces, marges) n'est fabriquée ici — le PIE les EXTRAIT de la faisabilité validée côté VPS (/opt/oto/data/pie/{code}/, jamais écrit par ce worker · #8). Les codes projets sont ancrés à CLAUDE.md §Projets ; annexe/version à la directive ; les modules downstream « gated » à des répertoires de livrables réels."
|
||||||
|
}
|
||||||
@@ -0,0 +1,369 @@
|
|||||||
|
{
|
||||||
|
"engine": "OTO Project Identity Engine (PIE)",
|
||||||
|
"annexe": 12,
|
||||||
|
"version_workflow": "V10.1",
|
||||||
|
"ssot": "faisabilite",
|
||||||
|
"source_spec": "pie_spec.json",
|
||||||
|
"master_data_groups": [
|
||||||
|
{
|
||||||
|
"cle": "architecture",
|
||||||
|
"libelle": "Architecture",
|
||||||
|
"champs": [
|
||||||
|
"style",
|
||||||
|
"matériaux",
|
||||||
|
"ambiances",
|
||||||
|
"palette matériaux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "bim",
|
||||||
|
"libelle": "BIM",
|
||||||
|
"champs": [
|
||||||
|
"IFC/GLB",
|
||||||
|
"plans",
|
||||||
|
"coupes",
|
||||||
|
"panoramas"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "budget",
|
||||||
|
"libelle": "Budget",
|
||||||
|
"champs": [
|
||||||
|
"CAPEX",
|
||||||
|
"coûts construction",
|
||||||
|
"marges",
|
||||||
|
"break-even",
|
||||||
|
"apport promoteur"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "calendrier",
|
||||||
|
"libelle": "Calendrier",
|
||||||
|
"champs": [
|
||||||
|
"phasage travaux",
|
||||||
|
"jalons",
|
||||||
|
"livraison"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "finances",
|
||||||
|
"libelle": "Finances",
|
||||||
|
"champs": [
|
||||||
|
"plan de financement",
|
||||||
|
"fideicomiso",
|
||||||
|
"CONFOTUR",
|
||||||
|
"exonérations"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "identite",
|
||||||
|
"libelle": "Identité",
|
||||||
|
"champs": [
|
||||||
|
"nom",
|
||||||
|
"type",
|
||||||
|
"concept",
|
||||||
|
"vision",
|
||||||
|
"mission",
|
||||||
|
"valeurs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "images",
|
||||||
|
"libelle": "Images",
|
||||||
|
"champs": [
|
||||||
|
"rendus extérieurs",
|
||||||
|
"intérieurs",
|
||||||
|
"aériens",
|
||||||
|
"ambiances"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "juridique",
|
||||||
|
"libelle": "Juridique",
|
||||||
|
"champs": [
|
||||||
|
"titres",
|
||||||
|
"permis",
|
||||||
|
"licences",
|
||||||
|
"contrats types"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "localisation",
|
||||||
|
"libelle": "Localisation",
|
||||||
|
"champs": [
|
||||||
|
"adresse exacte",
|
||||||
|
"coordonnées GPS",
|
||||||
|
"province",
|
||||||
|
"ville",
|
||||||
|
"quartier"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "marketing",
|
||||||
|
"libelle": "Marketing",
|
||||||
|
"champs": [
|
||||||
|
"positionnement",
|
||||||
|
"clientèle cible",
|
||||||
|
"USPs",
|
||||||
|
"canaux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "services",
|
||||||
|
"libelle": "Services",
|
||||||
|
"champs": [
|
||||||
|
"amenities",
|
||||||
|
"conciergerie",
|
||||||
|
"services inclus"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "unites",
|
||||||
|
"libelle": "Unités",
|
||||||
|
"champs": [
|
||||||
|
"typologies",
|
||||||
|
"surfaces",
|
||||||
|
"orientations",
|
||||||
|
"quantités",
|
||||||
|
"prix",
|
||||||
|
"disponibilités"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"downstream_registry": [
|
||||||
|
{
|
||||||
|
"cle": "app",
|
||||||
|
"libelle": "Section app mobile (portail Client)",
|
||||||
|
"module": "mobile/app_config",
|
||||||
|
"statut": "gated"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "bim",
|
||||||
|
"libelle": "IFC + GLB + Speckle",
|
||||||
|
"module": null,
|
||||||
|
"statut": "a_construire"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "brand_book",
|
||||||
|
"libelle": "Brand Book PDF (~30-50 pages)",
|
||||||
|
"module": null,
|
||||||
|
"statut": "a_construire"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "brochures",
|
||||||
|
"libelle": "Brochures PDF FR/EN/ES",
|
||||||
|
"module": null,
|
||||||
|
"statut": "a_construire"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "calendrier",
|
||||||
|
"libelle": "Calendrier / phasage travaux",
|
||||||
|
"module": null,
|
||||||
|
"statut": "a_construire"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "contrats",
|
||||||
|
"libelle": "Contrats types (Promesa · Fideicomiso · HOA)",
|
||||||
|
"module": "legal/confotur",
|
||||||
|
"statut": "gated"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "fiche_unite",
|
||||||
|
"libelle": "Fiche unité",
|
||||||
|
"module": null,
|
||||||
|
"statut": "a_construire"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "kit_banquier",
|
||||||
|
"libelle": "Kit banquier PDF trilingue",
|
||||||
|
"module": "faisabilite/bancable",
|
||||||
|
"statut": "gated"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "plans",
|
||||||
|
"libelle": "Plans (générés depuis BIM)",
|
||||||
|
"module": null,
|
||||||
|
"statut": "a_construire"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "rendus",
|
||||||
|
"libelle": "Rendus extérieurs/intérieurs/aériens",
|
||||||
|
"module": null,
|
||||||
|
"statut": "a_construire"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "site",
|
||||||
|
"libelle": "Page projet vente.otov7.com/projets/{slug}/",
|
||||||
|
"module": "publiciste",
|
||||||
|
"statut": "gated"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "slogan",
|
||||||
|
"libelle": "Slogan / tagline",
|
||||||
|
"module": null,
|
||||||
|
"statut": "a_construire"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cle": "trackers_chantier",
|
||||||
|
"libelle": "Trackers chantier",
|
||||||
|
"module": null,
|
||||||
|
"statut": "a_construire"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sync_rules": [
|
||||||
|
{
|
||||||
|
"trigger": "amenities",
|
||||||
|
"trigger_group": "services",
|
||||||
|
"downstream": [
|
||||||
|
"brochures",
|
||||||
|
"site",
|
||||||
|
"slogan",
|
||||||
|
"brand_book"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"trigger": "livraison",
|
||||||
|
"trigger_group": "calendrier",
|
||||||
|
"downstream": [
|
||||||
|
"calendrier",
|
||||||
|
"brochures",
|
||||||
|
"trackers_chantier"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"trigger": "prix",
|
||||||
|
"trigger_group": "unites",
|
||||||
|
"downstream": [
|
||||||
|
"brochures",
|
||||||
|
"kit_banquier",
|
||||||
|
"contrats",
|
||||||
|
"site",
|
||||||
|
"app"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"trigger": "typologie",
|
||||||
|
"trigger_group": "unites",
|
||||||
|
"downstream": [
|
||||||
|
"plans",
|
||||||
|
"rendus",
|
||||||
|
"fiche_unite",
|
||||||
|
"bim"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"workflow": [
|
||||||
|
{
|
||||||
|
"etape": 1,
|
||||||
|
"libelle": "Validation Faisabilité (par OTO Auditeur Faisabilité IA)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"etape": 2,
|
||||||
|
"libelle": "Extraction Project Master Data (master.json)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"etape": 3,
|
||||||
|
"libelle": "Brand Book génération"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"etape": 4,
|
||||||
|
"libelle": "Logos génération (Flux + variantes SVG)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"etape": 5,
|
||||||
|
"libelle": "Thème appliqué (CSS variables + design tokens)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"etape": 6,
|
||||||
|
"libelle": "Documents commerciaux (brochures · kit banquier · Trousse · contrats)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"etape": 7,
|
||||||
|
"libelle": "Portails web (page projet · viewer 3D · portail client)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"etape": 8,
|
||||||
|
"libelle": "Applications mobiles (section projet + tab dédié)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"etape": 9,
|
||||||
|
"libelle": "Synchronisation (ERPNext · CRM · BIM · OTO AI · OFAC/PEP/FinCEN)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"etape": 10,
|
||||||
|
"libelle": "Publication (site · app · portail admin · ERPNext · Speckle · GSC)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"brands": [
|
||||||
|
{
|
||||||
|
"code": "P01",
|
||||||
|
"marque": "Coralis",
|
||||||
|
"localisation": "San Cristóbal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "P02",
|
||||||
|
"marque": "Coral del Sur",
|
||||||
|
"localisation": "San Cristóbal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "P03",
|
||||||
|
"marque": "Nakua",
|
||||||
|
"localisation": "Bávaro"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "P04",
|
||||||
|
"marque": "Xamaná Cantiles",
|
||||||
|
"localisation": "Palenque"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "P05",
|
||||||
|
"marque": "Las Colinas",
|
||||||
|
"localisation": "Najayo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "P06",
|
||||||
|
"marque": "Coco Real",
|
||||||
|
"localisation": "Punta Cana Bávaro"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "P07",
|
||||||
|
"marque": "Aqua Terra",
|
||||||
|
"localisation": "Las Terrenas"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "P08",
|
||||||
|
"marque": "Fasano Espirilla",
|
||||||
|
"localisation": "Santo Domingo Espirilla"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "P09",
|
||||||
|
"marque": "Résidence Gazcue",
|
||||||
|
"localisation": "Santo Domingo centre historique"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storage_layout": {
|
||||||
|
"racine": "/opt/oto/data/pie/{code}/",
|
||||||
|
"artefacts": [
|
||||||
|
{
|
||||||
|
"chemin": "master.json",
|
||||||
|
"role": "Project Master Data (SSOT extrait de la faisabilité)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"chemin": "brand/",
|
||||||
|
"role": "Brand Book assets"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"chemin": "logos/",
|
||||||
|
"role": "Logos SVG/PNG + variantes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"chemin": "documents/",
|
||||||
|
"role": "PDF générés (brochures · kit banquier · contrats)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"chemin": "manifest.json",
|
||||||
|
"role": "Manifest de dépendances + checksums (régénération sélective)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"$id": "https://oto.dtp/schemas/pie/pie_manifest.schema.json",
|
||||||
|
"title": "PIE · manifest de dépendances (pie_manifest.json)",
|
||||||
|
"description": "Sortie déterministe du Project Identity Engine (Annexe 12 · V10.1). Décrit le graphe de dépendances faisabilité(SSOT)→livrables downstream. Zéro invention (#6) : contenus transcrits de la directive PIE ; codes projets ancrés à CLAUDE.md §Projets.",
|
||||||
|
"type": "object",
|
||||||
|
"required": ["engine", "annexe", "version_workflow", "ssot", "source_spec", "master_data_groups", "downstream_registry", "sync_rules", "workflow", "brands", "storage_layout"],
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"engine": { "type": "string", "minLength": 1 },
|
||||||
|
"annexe": { "type": "integer" },
|
||||||
|
"version_workflow": { "type": "string", "minLength": 1 },
|
||||||
|
"ssot": { "type": "string", "minLength": 1 },
|
||||||
|
"source_spec": { "type": "string", "minLength": 1 },
|
||||||
|
"master_data_groups": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["cle", "libelle", "champs"],
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"cle": { "type": "string", "minLength": 1 },
|
||||||
|
"libelle": { "type": "string", "minLength": 1 },
|
||||||
|
"champs": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"downstream_registry": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["cle", "libelle", "module", "statut"],
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"cle": { "type": "string", "minLength": 1 },
|
||||||
|
"libelle": { "type": "string", "minLength": 1 },
|
||||||
|
"module": { "type": ["string", "null"] },
|
||||||
|
"statut": { "type": "string", "enum": ["gated", "a_construire"] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sync_rules": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["trigger", "trigger_group", "downstream"],
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"trigger": { "type": "string", "minLength": 1 },
|
||||||
|
"trigger_group": { "type": "string", "minLength": 1 },
|
||||||
|
"downstream": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"workflow": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["etape", "libelle"],
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"etape": { "type": "integer", "minimum": 1 },
|
||||||
|
"libelle": { "type": "string", "minLength": 1 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"brands": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["code", "marque", "localisation"],
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"code": { "type": "string", "pattern": "^P0[1-9]$" },
|
||||||
|
"marque": { "type": "string", "minLength": 1 },
|
||||||
|
"localisation": { "type": "string", "minLength": 1 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"storage_layout": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["racine", "artefacts"],
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"racine": { "type": "string", "minLength": 1 },
|
||||||
|
"artefacts": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["chemin", "role"],
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"chemin": { "type": "string", "minLength": 1 },
|
||||||
|
"role": { "type": "string", "minLength": 1 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,248 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Générateur du manifest de dépendances PIE · Annexe 12 · V10.1.
|
||||||
|
|
||||||
|
Directive : `DIRECTIVE_PIE_PROJECT_IDENTITY_ENGINE_20260803.md` (Michel · 2026-08-03).
|
||||||
|
« La faisabilité devient le Project DNA · source unique de vérité (SSOT). »
|
||||||
|
|
||||||
|
Ce module livre le **P0** du PIE : le schéma Project Master Data + le manifest de
|
||||||
|
dépendances (§88 de la directive) qui liste, pour chaque déclencheur de la
|
||||||
|
faisabilité, les livrables downstream à régénérer — et lesquels sont DÉJÀ gated
|
||||||
|
par un module MVP existant vs restent à construire (P1-P4).
|
||||||
|
|
||||||
|
Ce worker n'écrit JAMAIS sur le VPS (#8) : le storage réel du PIE
|
||||||
|
(`/opt/oto/data/pie/{code}/`) et la génération effective des Brand Books / logos /
|
||||||
|
PDF restent côté agents (Flux, ERPNext, OTOIA). Ici : uniquement le contrat de
|
||||||
|
dépendances versionnable, cross-vérifié contre CLAUDE.md, la directive et le FS.
|
||||||
|
|
||||||
|
Sous-commandes :
|
||||||
|
build [-o OUT] → écrit pie_manifest.json + MANIFEST.json
|
||||||
|
validate → (re)génère en mémoire, valide schéma + 10 invariants ;
|
||||||
|
sort en erreur sinon.
|
||||||
|
|
||||||
|
Sortie déterministe (tri stable, aucun horodatage) → diffable + re-générable.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
_HERE = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
_DELIVERABLES = os.path.normpath(os.path.join(_HERE, "..", "..")) # 05_deliverables_mvp/
|
||||||
|
|
||||||
|
sys.path.insert(0, _HERE)
|
||||||
|
sys.path.insert(0, os.path.join(_DELIVERABLES, "publiciste"))
|
||||||
|
|
||||||
|
from pielib import builder, deps # noqa: E402
|
||||||
|
from lib import validator as maison # type: ignore # noqa: E402
|
||||||
|
|
||||||
|
_SPEC_PATH = os.path.join(_HERE, "pie_spec.json")
|
||||||
|
_SCHEMA_PATH = os.path.join(_HERE, "pie.schema.json")
|
||||||
|
_DEFAULT_OUT = os.path.join(_HERE, "out")
|
||||||
|
|
||||||
|
# Ensemble documenté des déclencheurs de synchronisation (directive §82-86).
|
||||||
|
_DECLENCHEURS = {"prix", "typologie", "amenities", "livraison"}
|
||||||
|
# Clés canoniques des 12 groupes Project Master Data (directive §16-29).
|
||||||
|
_GROUPES_CANONIQUES = {
|
||||||
|
"identite", "localisation", "architecture", "unites", "budget", "marketing",
|
||||||
|
"bim", "finances", "juridique", "images", "services", "calendrier",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _eprint(*args) -> None:
|
||||||
|
print(*args, file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
def _load(path: str) -> dict:
|
||||||
|
with open(path, encoding="utf-8") as fh:
|
||||||
|
return json.load(fh)
|
||||||
|
|
||||||
|
|
||||||
|
def _write_json(path: str, data) -> None:
|
||||||
|
with open(path, "w", encoding="utf-8") as fh:
|
||||||
|
json.dump(data, fh, ensure_ascii=False, indent=2)
|
||||||
|
fh.write("\n")
|
||||||
|
|
||||||
|
|
||||||
|
def _validate(bundle: dict) -> list[str]:
|
||||||
|
"""Schéma de sortie + 10 invariants (SSOT · ancrages CLAUDE.md/directive/FS).
|
||||||
|
|
||||||
|
Ledger des invariants (le compte « 10 » est ré-affiché à l'exécution) :
|
||||||
|
1 · schéma draft-07 de pie_manifest.json
|
||||||
|
2 · 12 groupes Master Data, clés uniques == ensemble canonique (§16-29)
|
||||||
|
3 · 4 règles sync, triggers == {prix, typologie, amenities, livraison}
|
||||||
|
4 · chaque downstream référencé existe dans le registre ; trigger_group réel
|
||||||
|
5 · registre downstream : statut cohérent avec présence d'un module
|
||||||
|
6 · chaque module downstream non nul est un répertoire de livrable réel (FS)
|
||||||
|
7 · workflow = étapes 1..N contiguës et uniques
|
||||||
|
8 · codes marques ⊆ CLAUDE.md §Projets (ancrage constitution)
|
||||||
|
9 · annexe (12) + version_workflow (V10.1) verbatim dans la directive
|
||||||
|
10 · storage layout hors-repo (/opt/oto/data/...) — jamais le out/ du module (#8)
|
||||||
|
"""
|
||||||
|
schema = _load(_SCHEMA_PATH)
|
||||||
|
errors: list[str] = []
|
||||||
|
|
||||||
|
man = bundle["manifest"]
|
||||||
|
trace = bundle["traceability"]
|
||||||
|
|
||||||
|
# 1 · schéma de sortie.
|
||||||
|
errors += list(maison.validate(man, schema))
|
||||||
|
|
||||||
|
# 2 · Project Master Data : 12 groupes, clés uniques, == ensemble canonique.
|
||||||
|
groups = man["master_data_groups"]
|
||||||
|
cles = [g["cle"] for g in groups]
|
||||||
|
if len(cles) != 12:
|
||||||
|
errors.append(f"master_data_groups : {len(cles)} groupes (attendu 12 · §16-29)")
|
||||||
|
if len(set(cles)) != len(cles):
|
||||||
|
errors.append("master_data_groups : clés dupliquées")
|
||||||
|
if set(cles) != _GROUPES_CANONIQUES:
|
||||||
|
manquants = _GROUPES_CANONIQUES - set(cles)
|
||||||
|
surplus = set(cles) - _GROUPES_CANONIQUES
|
||||||
|
errors.append(f"master_data_groups : clés ≠ ensemble canonique "
|
||||||
|
f"(manquants={sorted(manquants)} · surplus={sorted(surplus)})")
|
||||||
|
|
||||||
|
# 3 · règles de synchronisation : 4 triggers == ensemble documenté (§82-86).
|
||||||
|
triggers = [r["trigger"] for r in man["sync_rules"]]
|
||||||
|
if set(triggers) != _DECLENCHEURS:
|
||||||
|
errors.append(f"sync_rules : triggers {sorted(set(triggers))} ≠ "
|
||||||
|
f"{sorted(_DECLENCHEURS)} (§82-86)")
|
||||||
|
if len(set(triggers)) != len(triggers):
|
||||||
|
errors.append("sync_rules : trigger dupliqué")
|
||||||
|
|
||||||
|
# 4 · intégrité référentielle : downstream + trigger_group pointent du réel.
|
||||||
|
registry_keys = {d["cle"] for d in man["downstream_registry"]}
|
||||||
|
group_keys = set(cles)
|
||||||
|
for r in man["sync_rules"]:
|
||||||
|
if r["trigger_group"] not in group_keys:
|
||||||
|
errors.append(f"sync_rule {r['trigger']!r} : trigger_group "
|
||||||
|
f"{r['trigger_group']!r} absent des Master Data groups")
|
||||||
|
for t in r["downstream"]:
|
||||||
|
if t not in registry_keys:
|
||||||
|
errors.append(f"sync_rule {r['trigger']!r} : downstream {t!r} "
|
||||||
|
f"absent du downstream_registry")
|
||||||
|
|
||||||
|
# 5 · registre downstream : statut cohérent (gated ⇔ module non nul).
|
||||||
|
for d in man["downstream_registry"]:
|
||||||
|
attendu = "gated" if d["module"] else "a_construire"
|
||||||
|
if d["statut"] != attendu:
|
||||||
|
errors.append(f"downstream {d['cle']!r} : statut {d['statut']!r} "
|
||||||
|
f"incohérent avec module {d['module']!r}")
|
||||||
|
|
||||||
|
# 6 · chaque module downstream non nul EST un répertoire de livrable réel (FS).
|
||||||
|
for d in man["downstream_registry"]:
|
||||||
|
if d["module"] and not deps.module_exists(d["module"]):
|
||||||
|
errors.append(f"downstream {d['cle']!r} : module {d['module']!r} "
|
||||||
|
f"introuvable sous 05_deliverables_mvp/")
|
||||||
|
|
||||||
|
# 7 · workflow : étapes 1..N contiguës et uniques.
|
||||||
|
etapes = [s["etape"] for s in man["workflow"]]
|
||||||
|
if etapes != list(range(1, len(etapes) + 1)):
|
||||||
|
errors.append(f"workflow : étapes non contiguës/desordonnées : {etapes}")
|
||||||
|
|
||||||
|
# 8 · codes marques ⊆ CLAUDE.md §Projets (ancrage constitution · #6).
|
||||||
|
codes = {b["code"] for b in man["brands"]}
|
||||||
|
canoniques = deps.claude_md_project_codes()
|
||||||
|
if not canoniques:
|
||||||
|
errors.append("CLAUDE.md §Projets : aucun code Pxx lu (ancrage impossible)")
|
||||||
|
elif not codes <= canoniques:
|
||||||
|
errors.append(f"brands : codes {sorted(codes - canoniques)} absents de "
|
||||||
|
f"CLAUDE.md §Projets")
|
||||||
|
|
||||||
|
# 9 · annexe + version verbatim dans la directive (ancrage directive · #6).
|
||||||
|
decl = deps.directive_declares(trace["directive_source"],
|
||||||
|
f"Annexe {man['annexe']}", man["version_workflow"])
|
||||||
|
for needle, present in decl.items():
|
||||||
|
if not present:
|
||||||
|
errors.append(f"directive {trace['directive_source']!r} : "
|
||||||
|
f"« {needle} » introuvable (ancrage rompu)")
|
||||||
|
|
||||||
|
# 10 · storage layout hors-repo : aucun artefact PIE n'atterrit dans le out/
|
||||||
|
# du module (le worker n'écrit JAMAIS le storage VPS · #8).
|
||||||
|
racine = man["storage_layout"]["racine"]
|
||||||
|
if not racine.startswith("/opt/oto/data/pie/"):
|
||||||
|
errors.append(f"storage_layout.racine {racine!r} hors /opt/oto/data/pie/")
|
||||||
|
if os.path.abspath(deps.module_out_dir()).startswith(os.path.abspath("/opt/oto/data")):
|
||||||
|
errors.append("out/ du module confondu avec le storage VPS (#8)")
|
||||||
|
|
||||||
|
# Traçabilité : comptes du manifeste cohérents avec les tableaux.
|
||||||
|
c = trace["counts"]
|
||||||
|
if c["master_data_groups"] != len(groups):
|
||||||
|
errors.append("counts.master_data_groups incohérent")
|
||||||
|
if c["downstream_total"] != len(man["downstream_registry"]):
|
||||||
|
errors.append("counts.downstream_total incohérent")
|
||||||
|
if c["sync_rules"] != len(man["sync_rules"]):
|
||||||
|
errors.append("counts.sync_rules incohérent")
|
||||||
|
if c["workflow_steps"] != len(man["workflow"]):
|
||||||
|
errors.append("counts.workflow_steps incohérent")
|
||||||
|
if c["brands"] != len(man["brands"]):
|
||||||
|
errors.append("counts.brands incohérent")
|
||||||
|
gated = sum(1 for d in man["downstream_registry"] if d["statut"] == "gated")
|
||||||
|
if c["downstream_gated"] != gated:
|
||||||
|
errors.append("counts.downstream_gated incohérent")
|
||||||
|
|
||||||
|
return errors
|
||||||
|
|
||||||
|
|
||||||
|
def _build() -> dict:
|
||||||
|
return builder.build_bundle(_load(_SPEC_PATH))
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_build(args: argparse.Namespace) -> int:
|
||||||
|
bundle = _build()
|
||||||
|
errors = _validate(bundle)
|
||||||
|
if errors:
|
||||||
|
_eprint("❌ Manifest invalide — génération refusée (anti-régression) :")
|
||||||
|
for e in errors:
|
||||||
|
_eprint(f" - {e}")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
out = os.path.abspath(args.out)
|
||||||
|
os.makedirs(out, exist_ok=True)
|
||||||
|
_write_json(os.path.join(out, "pie_manifest.json"), bundle["manifest"])
|
||||||
|
_write_json(os.path.join(out, "MANIFEST.json"), bundle["traceability"])
|
||||||
|
|
||||||
|
c = bundle["traceability"]["counts"]
|
||||||
|
print(f"✅ Manifest PIE généré dans {out}")
|
||||||
|
print(f" pie_manifest.json : {c['master_data_groups']} groupes Master Data · "
|
||||||
|
f"{c['sync_rules']} règles sync · {c['downstream_total']} livrables downstream "
|
||||||
|
f"({c['downstream_gated']} gated · {c['downstream_a_construire']} à construire) · "
|
||||||
|
f"{c['workflow_steps']} étapes workflow · {c['brands']} marques")
|
||||||
|
print(" ⚠ Storage PIE réel (/opt/oto/data/pie/{code}/) + génération Brand Book / "
|
||||||
|
"logos / PDF côté agents (Flux · ERPNext · OTOIA · VPS · #8).")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_validate(args: argparse.Namespace) -> int:
|
||||||
|
bundle = _build()
|
||||||
|
errors = _validate(bundle)
|
||||||
|
if errors:
|
||||||
|
_eprint("❌ Validation KO :")
|
||||||
|
for e in errors:
|
||||||
|
_eprint(f" - {e}")
|
||||||
|
return 1
|
||||||
|
c = bundle["traceability"]["counts"]
|
||||||
|
print(f"✅ Validation OK — PIE Annexe {bundle['manifest']['annexe']} · "
|
||||||
|
f"{bundle['manifest']['version_workflow']} : schéma + 10 invariants verts "
|
||||||
|
f"({c['downstream_total']} downstream · {c['brands']} marques).")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv: list[str] | None = None) -> int:
|
||||||
|
p = argparse.ArgumentParser(description="Générateur du manifest de dépendances PIE (Annexe 12 · V10.1).")
|
||||||
|
sub = p.add_subparsers(dest="cmd", required=True)
|
||||||
|
|
||||||
|
pb = sub.add_parser("build", help="génère pie_manifest.json / MANIFEST.json")
|
||||||
|
pb.add_argument("-o", "--out", default=_DEFAULT_OUT, help="dossier de sortie (défaut: ./out)")
|
||||||
|
pb.set_defaults(func=cmd_build)
|
||||||
|
|
||||||
|
pv = sub.add_parser("validate", help="valide le bundle (schéma + 10 invariants) sans écrire")
|
||||||
|
pv.set_defaults(func=cmd_validate)
|
||||||
|
|
||||||
|
args = p.parse_args(argv)
|
||||||
|
return args.func(args)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
{
|
||||||
|
"engine": "OTO Project Identity Engine (PIE)",
|
||||||
|
"annexe": 12,
|
||||||
|
"version_workflow": "V10.1",
|
||||||
|
"ssot": "faisabilite",
|
||||||
|
"directive": "DIRECTIVE_PIE_PROJECT_IDENTITY_ENGINE_20260803.md",
|
||||||
|
"master_data_groups": [
|
||||||
|
{ "cle": "identite", "libelle": "Identité", "champs": ["nom", "type", "concept", "vision", "mission", "valeurs"] },
|
||||||
|
{ "cle": "localisation","libelle": "Localisation","champs": ["adresse exacte", "coordonnées GPS", "province", "ville", "quartier"] },
|
||||||
|
{ "cle": "architecture","libelle": "Architecture","champs": ["style", "matériaux", "ambiances", "palette matériaux"] },
|
||||||
|
{ "cle": "unites", "libelle": "Unités", "champs": ["typologies", "surfaces", "orientations", "quantités", "prix", "disponibilités"] },
|
||||||
|
{ "cle": "budget", "libelle": "Budget", "champs": ["CAPEX", "coûts construction", "marges", "break-even", "apport promoteur"] },
|
||||||
|
{ "cle": "marketing", "libelle": "Marketing", "champs": ["positionnement", "clientèle cible", "USPs", "canaux"] },
|
||||||
|
{ "cle": "bim", "libelle": "BIM", "champs": ["IFC/GLB", "plans", "coupes", "panoramas"] },
|
||||||
|
{ "cle": "finances", "libelle": "Finances", "champs": ["plan de financement", "fideicomiso", "CONFOTUR", "exonérations"] },
|
||||||
|
{ "cle": "juridique", "libelle": "Juridique", "champs": ["titres", "permis", "licences", "contrats types"] },
|
||||||
|
{ "cle": "images", "libelle": "Images", "champs": ["rendus extérieurs", "intérieurs", "aériens", "ambiances"] },
|
||||||
|
{ "cle": "services", "libelle": "Services", "champs": ["amenities", "conciergerie", "services inclus"] },
|
||||||
|
{ "cle": "calendrier", "libelle": "Calendrier", "champs": ["phasage travaux", "jalons", "livraison"] }
|
||||||
|
],
|
||||||
|
"downstream_registry": [
|
||||||
|
{ "cle": "brochures", "libelle": "Brochures PDF FR/EN/ES", "module": null },
|
||||||
|
{ "cle": "kit_banquier", "libelle": "Kit banquier PDF trilingue", "module": "faisabilite/bancable" },
|
||||||
|
{ "cle": "contrats", "libelle": "Contrats types (Promesa · Fideicomiso · HOA)","module": "legal/confotur" },
|
||||||
|
{ "cle": "site", "libelle": "Page projet vente.otov7.com/projets/{slug}/","module": "publiciste" },
|
||||||
|
{ "cle": "app", "libelle": "Section app mobile (portail Client)", "module": "mobile/app_config" },
|
||||||
|
{ "cle": "plans", "libelle": "Plans (générés depuis BIM)", "module": null },
|
||||||
|
{ "cle": "rendus", "libelle": "Rendus extérieurs/intérieurs/aériens", "module": null },
|
||||||
|
{ "cle": "fiche_unite", "libelle": "Fiche unité", "module": null },
|
||||||
|
{ "cle": "bim", "libelle": "IFC + GLB + Speckle", "module": null },
|
||||||
|
{ "cle": "slogan", "libelle": "Slogan / tagline", "module": null },
|
||||||
|
{ "cle": "brand_book", "libelle": "Brand Book PDF (~30-50 pages)", "module": null },
|
||||||
|
{ "cle": "calendrier", "libelle": "Calendrier / phasage travaux", "module": null },
|
||||||
|
{ "cle": "trackers_chantier", "libelle": "Trackers chantier", "module": null }
|
||||||
|
],
|
||||||
|
"sync_rules": [
|
||||||
|
{ "trigger": "prix", "trigger_group": "unites", "downstream": ["brochures", "kit_banquier", "contrats", "site", "app"] },
|
||||||
|
{ "trigger": "typologie", "trigger_group": "unites", "downstream": ["plans", "rendus", "fiche_unite", "bim"] },
|
||||||
|
{ "trigger": "amenities", "trigger_group": "services", "downstream": ["brochures", "site", "slogan", "brand_book"] },
|
||||||
|
{ "trigger": "livraison", "trigger_group": "calendrier", "downstream": ["calendrier", "brochures", "trackers_chantier"] }
|
||||||
|
],
|
||||||
|
"workflow": [
|
||||||
|
{ "etape": 1, "libelle": "Validation Faisabilité (par OTO Auditeur Faisabilité IA)" },
|
||||||
|
{ "etape": 2, "libelle": "Extraction Project Master Data (master.json)" },
|
||||||
|
{ "etape": 3, "libelle": "Brand Book génération" },
|
||||||
|
{ "etape": 4, "libelle": "Logos génération (Flux + variantes SVG)" },
|
||||||
|
{ "etape": 5, "libelle": "Thème appliqué (CSS variables + design tokens)" },
|
||||||
|
{ "etape": 6, "libelle": "Documents commerciaux (brochures · kit banquier · Trousse · contrats)" },
|
||||||
|
{ "etape": 7, "libelle": "Portails web (page projet · viewer 3D · portail client)" },
|
||||||
|
{ "etape": 8, "libelle": "Applications mobiles (section projet + tab dédié)" },
|
||||||
|
{ "etape": 9, "libelle": "Synchronisation (ERPNext · CRM · BIM · OTO AI · OFAC/PEP/FinCEN)" },
|
||||||
|
{ "etape": 10, "libelle": "Publication (site · app · portail admin · ERPNext · Speckle · GSC)" }
|
||||||
|
],
|
||||||
|
"brands": [
|
||||||
|
{ "code": "P01", "marque": "Coralis", "localisation": "San Cristóbal" },
|
||||||
|
{ "code": "P02", "marque": "Coral del Sur", "localisation": "San Cristóbal" },
|
||||||
|
{ "code": "P03", "marque": "Nakua", "localisation": "Bávaro" },
|
||||||
|
{ "code": "P04", "marque": "Xamaná Cantiles", "localisation": "Palenque" },
|
||||||
|
{ "code": "P05", "marque": "Las Colinas", "localisation": "Najayo" },
|
||||||
|
{ "code": "P06", "marque": "Coco Real", "localisation": "Punta Cana Bávaro" },
|
||||||
|
{ "code": "P07", "marque": "Aqua Terra", "localisation": "Las Terrenas" },
|
||||||
|
{ "code": "P08", "marque": "Fasano Espirilla", "localisation": "Santo Domingo Espirilla" },
|
||||||
|
{ "code": "P09", "marque": "Résidence Gazcue", "localisation": "Santo Domingo centre historique" }
|
||||||
|
],
|
||||||
|
"storage_layout": {
|
||||||
|
"racine": "/opt/oto/data/pie/{code}/",
|
||||||
|
"artefacts": [
|
||||||
|
{ "chemin": "master.json", "role": "Project Master Data (SSOT extrait de la faisabilité)" },
|
||||||
|
{ "chemin": "brand/", "role": "Brand Book assets" },
|
||||||
|
{ "chemin": "logos/", "role": "Logos SVG/PNG + variantes" },
|
||||||
|
{ "chemin": "documents/", "role": "PDF générés (brochures · kit banquier · contrats)" },
|
||||||
|
{ "chemin": "manifest.json", "role": "Manifest de dépendances + checksums (régénération sélective)" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
"""PIE · manifest de dépendances · bibliothèque interne.
|
||||||
|
|
||||||
|
- deps → ancrages hors-module (CLAUDE.md §Projets · directive PIE · FS des livrables)
|
||||||
|
- builder → assemblage déterministe du manifest + du MANIFEST de traçabilité
|
||||||
|
"""
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
"""Assemblage déterministe du manifest PIE depuis `pie_spec.json`.
|
||||||
|
|
||||||
|
Entrée : le contrat PIE (taxonomie Project Master Data, registre downstream,
|
||||||
|
règles de synchronisation, workflow 10 étapes, marques, storage layout) —
|
||||||
|
transcrit VERBATIM de la directive PIE (SSOT · #6, aucune valeur inventée).
|
||||||
|
Sortie : un bundle déterministe (tri stable, aucun horodatage) → reproductible
|
||||||
|
bit-à-bit à contrat constant, donc diffable et re-générable en CI
|
||||||
|
([[artifact-reproducibility-gate]]).
|
||||||
|
|
||||||
|
Le builder n'ajoute AUCUN chiffre propre à OTO : il résout le `statut` de chaque
|
||||||
|
livrable downstream (« gated » si un module de livrado réel l'implémente déjà,
|
||||||
|
sinon « a_construire ») et un manifeste de traçabilité (comptes dérivés).
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from . import deps
|
||||||
|
|
||||||
|
|
||||||
|
def _statut(module: str | None) -> str:
|
||||||
|
"""« gated » si un module réel implémente déjà le downstream, sinon « a_construire »."""
|
||||||
|
return "gated" if module else "a_construire"
|
||||||
|
|
||||||
|
|
||||||
|
def build_bundle(spec: dict) -> dict[str, Any]:
|
||||||
|
"""Transforme le contrat PIE en manifest de dépendances + manifeste de traçabilité."""
|
||||||
|
groups = sorted(spec["master_data_groups"], key=lambda g: g["cle"])
|
||||||
|
|
||||||
|
registry = [
|
||||||
|
{
|
||||||
|
"cle": d["cle"],
|
||||||
|
"libelle": d["libelle"],
|
||||||
|
"module": d["module"],
|
||||||
|
"statut": _statut(d["module"]),
|
||||||
|
}
|
||||||
|
for d in sorted(spec["downstream_registry"], key=lambda d: d["cle"])
|
||||||
|
]
|
||||||
|
|
||||||
|
sync_rules = [
|
||||||
|
{
|
||||||
|
"trigger": r["trigger"],
|
||||||
|
"trigger_group": r["trigger_group"],
|
||||||
|
"downstream": list(r["downstream"]), # ordre directive préservé (§82-86)
|
||||||
|
}
|
||||||
|
for r in sorted(spec["sync_rules"], key=lambda r: r["trigger"])
|
||||||
|
]
|
||||||
|
|
||||||
|
workflow = sorted(spec["workflow"], key=lambda s: s["etape"])
|
||||||
|
brands = sorted(spec["brands"], key=lambda b: b["code"])
|
||||||
|
|
||||||
|
manifest_out = {
|
||||||
|
"engine": spec["engine"],
|
||||||
|
"annexe": spec["annexe"],
|
||||||
|
"version_workflow": spec["version_workflow"],
|
||||||
|
"ssot": spec["ssot"],
|
||||||
|
"source_spec": "pie_spec.json",
|
||||||
|
"master_data_groups": groups,
|
||||||
|
"downstream_registry": registry,
|
||||||
|
"sync_rules": sync_rules,
|
||||||
|
"workflow": workflow,
|
||||||
|
"brands": brands,
|
||||||
|
"storage_layout": spec["storage_layout"],
|
||||||
|
}
|
||||||
|
|
||||||
|
gated = [d for d in registry if d["statut"] == "gated"]
|
||||||
|
a_construire = [d for d in registry if d["statut"] == "a_construire"]
|
||||||
|
|
||||||
|
traceability = {
|
||||||
|
"generated_from": "pie_spec.json",
|
||||||
|
"claude_md_source": "CLAUDE.md",
|
||||||
|
"directive_source": spec["directive"],
|
||||||
|
"engine": spec["engine"],
|
||||||
|
"annexe": spec["annexe"],
|
||||||
|
"version_workflow": spec["version_workflow"],
|
||||||
|
"ssot": spec["ssot"],
|
||||||
|
"counts": {
|
||||||
|
"master_data_groups": len(groups),
|
||||||
|
"downstream_total": len(registry),
|
||||||
|
"downstream_gated": len(gated),
|
||||||
|
"downstream_a_construire": len(a_construire),
|
||||||
|
"sync_rules": len(sync_rules),
|
||||||
|
"workflow_steps": len(workflow),
|
||||||
|
"brands": len(brands),
|
||||||
|
},
|
||||||
|
"modules_gated_references": [
|
||||||
|
{"cle": d["cle"], "module": d["module"]} for d in gated
|
||||||
|
],
|
||||||
|
"note_anti_invention": (
|
||||||
|
"Toute donnée est transcrite de la directive PIE (SSOT · #6) : aucune "
|
||||||
|
"valeur projet (prix, surfaces, marges) n'est fabriquée ici — le PIE "
|
||||||
|
"les EXTRAIT de la faisabilité validée côté VPS (/opt/oto/data/pie/{code}/, "
|
||||||
|
"jamais écrit par ce worker · #8). Les codes projets sont ancrés à "
|
||||||
|
"CLAUDE.md §Projets ; annexe/version à la directive ; les modules "
|
||||||
|
"downstream « gated » à des répertoires de livrables réels."
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
return {"manifest": manifest_out, "traceability": traceability}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
"""Ancrages hors-module du PIE manifest (anti-dérive · anti-invention #6).
|
||||||
|
|
||||||
|
Le manifest PIE ne se valide pas seulement contre lui-même : trois faits sont
|
||||||
|
RE-DÉRIVÉS de sources de vérité EXTERNES au module, jamais recopiés à la main —
|
||||||
|
|
||||||
|
1. Les codes projets (`brands[].code`) sont confrontés à `CLAUDE.md §Projets`
|
||||||
|
(la constitution · [[claude-md-constant-anchor-gate]]). Une marque PIE dont
|
||||||
|
le code ne figure pas dans la constitution est une invention refusée.
|
||||||
|
2. `annexe` (12) et `version_workflow` (V10.1) doivent apparaître VERBATIM dans
|
||||||
|
la directive PIE. Renuméroter l'annexe dans la directive sans régénérer ici
|
||||||
|
casse la validation ([[roadmap-anchor-gate]] appliqué à la directive).
|
||||||
|
3. Chaque `downstream_registry[].module` non nul doit être un répertoire de
|
||||||
|
livrable RÉEL sous `05_deliverables_mvp/` (comme fiscal/ecf vérifie ses
|
||||||
|
contrats voisins). Un module fantôme (renommé/supprimé) casse la validation.
|
||||||
|
|
||||||
|
Zéro dépendance pip · zéro réseau · aucune écriture VPS (#8) : lecture seule de
|
||||||
|
fichiers déjà versionnés dans le dépôt.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
_HERE = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
_MODULE_DIR = os.path.normpath(os.path.join(_HERE, "..")) # pie/manifest/
|
||||||
|
DELIVERABLES_ROOT = os.path.normpath(os.path.join(_HERE, "..", "..", "..")) # 05_deliverables_mvp/
|
||||||
|
_REPO_ROOT = os.path.normpath(os.path.join(DELIVERABLES_ROOT, ".."))
|
||||||
|
_CLAUDE_MD = os.path.join(_REPO_ROOT, "CLAUDE.md")
|
||||||
|
|
||||||
|
|
||||||
|
def claude_md_project_codes() -> set[str]:
|
||||||
|
"""Codes Pxx de la ligne `## Projets` de CLAUDE.md (source de vérité #Projets)."""
|
||||||
|
with open(_CLAUDE_MD, encoding="utf-8") as fh:
|
||||||
|
text = fh.read()
|
||||||
|
# Section entre « ## Projets » et le prochain titre « ## ».
|
||||||
|
m = re.search(r"^##\s+Projets\s*\n(.*?)(?:\n##\s|\Z)", text, re.S | re.M)
|
||||||
|
section = m.group(1) if m else ""
|
||||||
|
return set(re.findall(r"\bP0[1-9]\b", section))
|
||||||
|
|
||||||
|
|
||||||
|
def directive_declares(directive_relpath: str, *needles: str) -> dict[str, bool]:
|
||||||
|
"""Vrai/faux, pour chaque `needle`, s'il apparaît verbatim dans la directive PIE."""
|
||||||
|
path = os.path.join(_REPO_ROOT, directive_relpath)
|
||||||
|
try:
|
||||||
|
with open(path, encoding="utf-8") as fh:
|
||||||
|
text = fh.read()
|
||||||
|
except OSError:
|
||||||
|
return {n: False for n in needles}
|
||||||
|
return {n: (n in text) for n in needles}
|
||||||
|
|
||||||
|
|
||||||
|
def module_exists(rel_module: str) -> bool:
|
||||||
|
"""Le module de livrable `rel_module` (ex. 'faisabilite/bancable') existe-t-il ?"""
|
||||||
|
return os.path.isdir(os.path.join(DELIVERABLES_ROOT, rel_module))
|
||||||
|
|
||||||
|
|
||||||
|
def module_out_dir() -> str:
|
||||||
|
"""Répertoire de sortie du module (le SEUL endroit où ce worker écrit · #8)."""
|
||||||
|
return os.path.join(_MODULE_DIR, "out")
|
||||||
@@ -0,0 +1,194 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Tests du générateur de manifest de dépendances PIE · Annexe 12 · V10.1.
|
||||||
|
|
||||||
|
Stdlib pur (`unittest`) → aucune installation pip requise sur le runner Gitea.
|
||||||
|
La bibliothèque `jsonschema` sert d'*oracle* quand elle est présente.
|
||||||
|
|
||||||
|
Axes :
|
||||||
|
1. BASELINE : le contrat vanille passe schéma + 10 invariants, est déterministe,
|
||||||
|
et l'artefact `out/` commité == build frais (reproductibilité · #6).
|
||||||
|
2. MUTATION : chaque invariant attrape bien la dérive qu'il protège (on casse
|
||||||
|
le bundle en mémoire et on vérifie que `_validate` remonte une erreur).
|
||||||
|
3. ANCRAGES : codes marques ⊆ CLAUDE.md §Projets ; annexe/version verbatim dans
|
||||||
|
la directive ; modules downstream « gated » = répertoires de livrables réels.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import copy
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
_HERE = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
_MODULE = os.path.normpath(os.path.join(_HERE, ".."))
|
||||||
|
_DELIVERABLES = os.path.normpath(os.path.join(_MODULE, "..", ".."))
|
||||||
|
|
||||||
|
sys.path.insert(0, _MODULE)
|
||||||
|
sys.path.insert(0, os.path.join(_DELIVERABLES, "publiciste"))
|
||||||
|
|
||||||
|
from pielib import builder, deps # noqa: E402
|
||||||
|
from lib import validator as maison # type: ignore # noqa: E402
|
||||||
|
import pie_manifest_gen as gen # noqa: E402
|
||||||
|
|
||||||
|
try:
|
||||||
|
import jsonschema # type: ignore
|
||||||
|
|
||||||
|
_HAS_JSONSCHEMA = True
|
||||||
|
except Exception: # pragma: no cover
|
||||||
|
_HAS_JSONSCHEMA = False
|
||||||
|
|
||||||
|
|
||||||
|
def _load(path: str) -> dict:
|
||||||
|
with open(path, encoding="utf-8") as fh:
|
||||||
|
return json.load(fh)
|
||||||
|
|
||||||
|
|
||||||
|
class Baseline(unittest.TestCase):
|
||||||
|
"""Le contrat vanille passe schéma + 10 invariants et est déterministe."""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.bundle = gen._build()
|
||||||
|
|
||||||
|
def test_validate_clean(self):
|
||||||
|
self.assertEqual(gen._validate(self.bundle), [])
|
||||||
|
|
||||||
|
def test_counts_match_directive(self):
|
||||||
|
c = self.bundle["traceability"]["counts"]
|
||||||
|
self.assertEqual(c["master_data_groups"], 12) # §16-29
|
||||||
|
self.assertEqual(c["sync_rules"], 4) # §82-86
|
||||||
|
self.assertEqual(c["workflow_steps"], 10) # §108-133
|
||||||
|
self.assertEqual(c["brands"], 9) # §90-102
|
||||||
|
|
||||||
|
def test_deterministic_rebuild(self):
|
||||||
|
self.assertEqual(gen._build(), gen._build())
|
||||||
|
|
||||||
|
def test_schema_oracle(self):
|
||||||
|
if not _HAS_JSONSCHEMA:
|
||||||
|
self.skipTest("jsonschema absent")
|
||||||
|
schema = _load(gen._SCHEMA_PATH)
|
||||||
|
jsonschema.validate(self.bundle["manifest"], schema) # ne lève pas
|
||||||
|
|
||||||
|
|
||||||
|
class Reproducibility(unittest.TestCase):
|
||||||
|
"""L'artefact commité `out/` == build frais (byte-identique)."""
|
||||||
|
|
||||||
|
def test_committed_matches_fresh(self):
|
||||||
|
out = os.path.join(_MODULE, "out")
|
||||||
|
if not os.path.isdir(out):
|
||||||
|
self.skipTest("out/ non commité")
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
rc = gen.main(["build", "-o", tmp])
|
||||||
|
self.assertEqual(rc, 0)
|
||||||
|
for name in ("pie_manifest.json", "MANIFEST.json"):
|
||||||
|
with open(os.path.join(out, name), encoding="utf-8") as a, \
|
||||||
|
open(os.path.join(tmp, name), encoding="utf-8") as b:
|
||||||
|
self.assertEqual(a.read(), b.read(), f"{name} a dérivé de sa source")
|
||||||
|
|
||||||
|
|
||||||
|
class Anchors(unittest.TestCase):
|
||||||
|
"""Les ancrages hors-module pointent bien vers du réel (anti-invention #6)."""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.man = gen._build()["manifest"]
|
||||||
|
|
||||||
|
def test_brand_codes_subset_of_claude_md(self):
|
||||||
|
codes = {b["code"] for b in self.man["brands"]}
|
||||||
|
canon = deps.claude_md_project_codes()
|
||||||
|
self.assertTrue(canon, "aucun code Pxx lu dans CLAUDE.md §Projets")
|
||||||
|
self.assertTrue(codes <= canon, f"codes hors constitution : {codes - canon}")
|
||||||
|
|
||||||
|
def test_annexe_version_in_directive(self):
|
||||||
|
decl = deps.directive_declares(self.man_directive(), "Annexe 12", "V10.1")
|
||||||
|
self.assertTrue(all(decl.values()), f"ancrage directive rompu : {decl}")
|
||||||
|
|
||||||
|
def test_gated_modules_exist_on_fs(self):
|
||||||
|
for d in self.man["downstream_registry"]:
|
||||||
|
if d["statut"] == "gated":
|
||||||
|
self.assertTrue(deps.module_exists(d["module"]),
|
||||||
|
f"module gated introuvable : {d['module']}")
|
||||||
|
|
||||||
|
def man_directive(self) -> str:
|
||||||
|
return gen._build()["traceability"]["directive_source"]
|
||||||
|
|
||||||
|
|
||||||
|
class Mutations(unittest.TestCase):
|
||||||
|
"""Chaque invariant attrape la dérive qu'il protège."""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.bundle = gen._build()
|
||||||
|
|
||||||
|
def _breaks(self, mutate) -> None:
|
||||||
|
bundle = copy.deepcopy(self.bundle)
|
||||||
|
mutate(bundle)
|
||||||
|
self.assertNotEqual(gen._validate(bundle), [],
|
||||||
|
"la mutation aurait dû être refusée")
|
||||||
|
|
||||||
|
def test_inv2_missing_group(self):
|
||||||
|
self._breaks(lambda b: b["manifest"]["master_data_groups"].pop())
|
||||||
|
|
||||||
|
def test_inv2_wrong_group_key(self):
|
||||||
|
def m(b):
|
||||||
|
b["manifest"]["master_data_groups"][0]["cle"] = "inventé"
|
||||||
|
self._breaks(m)
|
||||||
|
|
||||||
|
def test_inv3_unknown_trigger(self):
|
||||||
|
def m(b):
|
||||||
|
b["manifest"]["sync_rules"][0]["trigger"] = "couleur"
|
||||||
|
self._breaks(m)
|
||||||
|
|
||||||
|
def test_inv4_dangling_downstream(self):
|
||||||
|
def m(b):
|
||||||
|
b["manifest"]["sync_rules"][0]["downstream"].append("fantome")
|
||||||
|
self._breaks(m)
|
||||||
|
|
||||||
|
def test_inv4_dangling_trigger_group(self):
|
||||||
|
def m(b):
|
||||||
|
b["manifest"]["sync_rules"][0]["trigger_group"] = "fantome"
|
||||||
|
self._breaks(m)
|
||||||
|
|
||||||
|
def test_inv5_status_incoherent(self):
|
||||||
|
def m(b):
|
||||||
|
b["manifest"]["downstream_registry"][0]["statut"] = "gated"
|
||||||
|
b["manifest"]["downstream_registry"][0]["module"] = None
|
||||||
|
self._breaks(m)
|
||||||
|
|
||||||
|
def test_inv6_phantom_module(self):
|
||||||
|
def m(b):
|
||||||
|
for d in b["manifest"]["downstream_registry"]:
|
||||||
|
if d["module"]:
|
||||||
|
d["module"] = "faisabilite/inexistant"
|
||||||
|
return
|
||||||
|
self._breaks(m)
|
||||||
|
|
||||||
|
def test_inv7_non_contiguous_workflow(self):
|
||||||
|
def m(b):
|
||||||
|
b["manifest"]["workflow"][0]["etape"] = 99
|
||||||
|
self._breaks(m)
|
||||||
|
|
||||||
|
def test_inv8_alien_brand_code(self):
|
||||||
|
def m(b):
|
||||||
|
b["manifest"]["brands"][0]["code"] = "P99"
|
||||||
|
self._breaks(m)
|
||||||
|
|
||||||
|
def test_inv9_wrong_annexe(self):
|
||||||
|
def m(b):
|
||||||
|
b["manifest"]["annexe"] = 7 # « Annexe 7 » n'est pas dans la directive
|
||||||
|
self._breaks(m)
|
||||||
|
|
||||||
|
def test_inv10_storage_not_vps(self):
|
||||||
|
def m(b):
|
||||||
|
b["manifest"]["storage_layout"]["racine"] = "05_deliverables_mvp/pie/"
|
||||||
|
self._breaks(m)
|
||||||
|
|
||||||
|
def test_count_incoherent(self):
|
||||||
|
def m(b):
|
||||||
|
b["traceability"]["counts"]["brands"] = 999
|
||||||
|
self._breaks(m)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__": # pragma: no cover
|
||||||
|
unittest.main()
|
||||||
@@ -150,9 +150,13 @@
|
|||||||
"roadmap_line": 76,
|
"roadmap_line": 76,
|
||||||
"statement": "Plateforme démo live · 5 portails · CRM · BIM auto · OTOIA voice",
|
"statement": "Plateforme démo live · 5 portails · CRM · BIM auto · OTOIA voice",
|
||||||
"status": "in_repo",
|
"status": "in_repo",
|
||||||
"evidence_modules": ["qa/regression", "devops/deploy_runbook"],
|
"evidence_modules": ["qa/regression", "devops/deploy_runbook", "pie/manifest"],
|
||||||
"evidence_artifacts": [],
|
"evidence_artifacts": [],
|
||||||
"out_of_scope": [
|
"out_of_scope": [
|
||||||
|
{
|
||||||
|
"item": "Project Identity Engine complet (Brand Books/logos Flux, storage /opt/oto/data/pie/, sync ERPNext/Speckle/OTO AI) — seul le P0 (manifest de dépendances faisabilité(SSOT)→downstream) est in_repo ; P1-P4 restent à construire",
|
||||||
|
"source": "directive PIE (Annexe 12 · V10.1 · 2026-08-03) §160-166 · génération effective côté agents Flux/ERPNext/OTOIA (VPS · CLAUDE.md #8)"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"item": "déploiement production complet + monitoring exécutés sur le VPS (run-book appliqué)",
|
"item": "déploiement production complet + monitoring exécutés sur le VPS (run-book appliqué)",
|
||||||
"source": "CLAUDE.md #8 (VPS) — l'exécution du run-book de déploiement revient à l'agent DevOps / ERPNext Backend"
|
"source": "CLAUDE.md #8 (VPS) — l'exécution du run-book de déploiement revient à l'agent DevOps / ERPNext Backend"
|
||||||
|
|||||||
@@ -10,13 +10,13 @@
|
|||||||
"deliverables_total": 15,
|
"deliverables_total": 15,
|
||||||
"in_repo": 15,
|
"in_repo": 15,
|
||||||
"out_of_scope_full": 0,
|
"out_of_scope_full": 0,
|
||||||
"gated_modules": 23,
|
"gated_modules": 24,
|
||||||
"cited_modules": 23,
|
"cited_modules": 24,
|
||||||
"out_of_scope_items": 13
|
"out_of_scope_items": 14
|
||||||
},
|
},
|
||||||
"coverage": {
|
"coverage": {
|
||||||
"ci_modules_count": 23,
|
"ci_modules_count": 24,
|
||||||
"cited_modules_count": 23,
|
"cited_modules_count": 24,
|
||||||
"bijective": true,
|
"bijective": true,
|
||||||
"missing_in_matrix": [],
|
"missing_in_matrix": [],
|
||||||
"phantom_evidence": [],
|
"phantom_evidence": [],
|
||||||
@@ -136,10 +136,12 @@
|
|||||||
"sprint": "S8",
|
"sprint": "S8",
|
||||||
"expected": [
|
"expected": [
|
||||||
"devops/deploy_runbook",
|
"devops/deploy_runbook",
|
||||||
|
"pie/manifest",
|
||||||
"qa/regression"
|
"qa/regression"
|
||||||
],
|
],
|
||||||
"cited": [
|
"cited": [
|
||||||
"devops/deploy_runbook",
|
"devops/deploy_runbook",
|
||||||
|
"pie/manifest",
|
||||||
"qa/regression"
|
"qa/regression"
|
||||||
],
|
],
|
||||||
"missing": [],
|
"missing": [],
|
||||||
|
|||||||
@@ -277,16 +277,25 @@
|
|||||||
"module": "devops/deploy_runbook",
|
"module": "devops/deploy_runbook",
|
||||||
"ci_job": "devops-deploy-runbook-tests",
|
"ci_job": "devops-deploy-runbook-tests",
|
||||||
"gated": true
|
"gated": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"module": "pie/manifest",
|
||||||
|
"ci_job": "pie-manifest-tests",
|
||||||
|
"gated": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"artifacts": [],
|
"artifacts": [],
|
||||||
"out_of_scope": [
|
"out_of_scope": [
|
||||||
|
{
|
||||||
|
"item": "Project Identity Engine complet (Brand Books/logos Flux, storage /opt/oto/data/pie/, sync ERPNext/Speckle/OTO AI) — seul le P0 (manifest de dépendances faisabilité(SSOT)→downstream) est in_repo ; P1-P4 restent à construire",
|
||||||
|
"source": "directive PIE (Annexe 12 · V10.1 · 2026-08-03) §160-166 · génération effective côté agents Flux/ERPNext/OTOIA (VPS · CLAUDE.md #8)"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"item": "déploiement production complet + monitoring exécutés sur le VPS (run-book appliqué)",
|
"item": "déploiement production complet + monitoring exécutés sur le VPS (run-book appliqué)",
|
||||||
"source": "CLAUDE.md #8 (VPS) — l'exécution du run-book de déploiement revient à l'agent DevOps / ERPNext Backend"
|
"source": "CLAUDE.md #8 (VPS) — l'exécution du run-book de déploiement revient à l'agent DevOps / ERPNext Backend"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"n_modules": 2,
|
"n_modules": 3,
|
||||||
"all_modules_gated": true,
|
"all_modules_gated": true,
|
||||||
"all_artifacts_exist": true,
|
"all_artifacts_exist": true,
|
||||||
"has_evidence": true
|
"has_evidence": true
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"audit": "OTO QA · Audit 4Big Qualité",
|
"audit": "OTO QA · Audit 4Big Qualité",
|
||||||
"version": "1.0",
|
"version": "1.0",
|
||||||
"verdict": "PASS",
|
"verdict": "PASS",
|
||||||
"modules_audited": 23,
|
"modules_audited": 24,
|
||||||
"min_score": 100,
|
"min_score": 100,
|
||||||
"pass_score": 95,
|
"pass_score": 95,
|
||||||
"coverage_ok": true,
|
"coverage_ok": true,
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
"pass_score": 95,
|
"pass_score": 95,
|
||||||
"coverage": {
|
"coverage": {
|
||||||
"ok": true,
|
"ok": true,
|
||||||
"ci_modules_count": 23,
|
"ci_modules_count": 24,
|
||||||
"registry_modules_count": 23,
|
"registry_modules_count": 24,
|
||||||
"missing_in_registry": [],
|
"missing_in_registry": [],
|
||||||
"missing_in_ci": [],
|
"missing_in_ci": [],
|
||||||
"not_in_gate": [],
|
"not_in_gate": [],
|
||||||
@@ -424,6 +424,48 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "crm-financement-bancaire",
|
||||||
|
"path": "crm/financement_bancaire",
|
||||||
|
"sprint": "S4",
|
||||||
|
"archetype": "generator",
|
||||||
|
"applicable_weight": 100,
|
||||||
|
"earned_weight": 100,
|
||||||
|
"score": 100,
|
||||||
|
"verdict": "PASS",
|
||||||
|
"checks": [
|
||||||
|
{
|
||||||
|
"criterion": "DOC",
|
||||||
|
"weight": 20,
|
||||||
|
"passed": true,
|
||||||
|
"evidence": "README.md (6280 octets)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"criterion": "CONTRAT",
|
||||||
|
"weight": 20,
|
||||||
|
"passed": true,
|
||||||
|
"evidence": "financement.schema.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"criterion": "TESTS",
|
||||||
|
"weight": 25,
|
||||||
|
"passed": true,
|
||||||
|
"evidence": "35 méthodes test_* dans 1 fichier(s) (seuil 8)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"criterion": "CLI",
|
||||||
|
"weight": 15,
|
||||||
|
"passed": true,
|
||||||
|
"evidence": "financement_bancaire_gen.py (argparse + __main__)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"criterion": "HANDOFF",
|
||||||
|
"weight": 20,
|
||||||
|
"passed": true,
|
||||||
|
"evidence": "MANIFEST + 6 artefact(s) JSON valides"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "crm-workflow-vente",
|
"id": "crm-workflow-vente",
|
||||||
"path": "crm/workflow_vente",
|
"path": "crm/workflow_vente",
|
||||||
@@ -550,48 +592,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "crm-financement-bancaire",
|
|
||||||
"path": "crm/financement_bancaire",
|
|
||||||
"sprint": "S5",
|
|
||||||
"archetype": "generator",
|
|
||||||
"applicable_weight": 100,
|
|
||||||
"earned_weight": 100,
|
|
||||||
"score": 100,
|
|
||||||
"verdict": "PASS",
|
|
||||||
"checks": [
|
|
||||||
{
|
|
||||||
"criterion": "DOC",
|
|
||||||
"weight": 20,
|
|
||||||
"passed": true,
|
|
||||||
"evidence": "README.md (6280 octets)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"criterion": "CONTRAT",
|
|
||||||
"weight": 20,
|
|
||||||
"passed": true,
|
|
||||||
"evidence": "financement.schema.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"criterion": "TESTS",
|
|
||||||
"weight": 25,
|
|
||||||
"passed": true,
|
|
||||||
"evidence": "35 méthodes test_* dans 1 fichier(s) (seuil 8)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"criterion": "CLI",
|
|
||||||
"weight": 15,
|
|
||||||
"passed": true,
|
|
||||||
"evidence": "financement_bancaire_gen.py (argparse + __main__)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"criterion": "HANDOFF",
|
|
||||||
"weight": 20,
|
|
||||||
"passed": true,
|
|
||||||
"evidence": "MANIFEST + 6 artefact(s) JSON valides"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "legal-confotur",
|
"id": "legal-confotur",
|
||||||
"path": "legal/confotur",
|
"path": "legal/confotur",
|
||||||
@@ -886,6 +886,48 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "pie-manifest",
|
||||||
|
"path": "pie/manifest",
|
||||||
|
"sprint": "S8",
|
||||||
|
"archetype": "generator",
|
||||||
|
"applicable_weight": 100,
|
||||||
|
"earned_weight": 100,
|
||||||
|
"score": 100,
|
||||||
|
"verdict": "PASS",
|
||||||
|
"checks": [
|
||||||
|
{
|
||||||
|
"criterion": "DOC",
|
||||||
|
"weight": 20,
|
||||||
|
"passed": true,
|
||||||
|
"evidence": "README.md (4022 octets)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"criterion": "CONTRAT",
|
||||||
|
"weight": 20,
|
||||||
|
"passed": true,
|
||||||
|
"evidence": "pie.schema.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"criterion": "TESTS",
|
||||||
|
"weight": 25,
|
||||||
|
"passed": true,
|
||||||
|
"evidence": "20 méthodes test_* dans 1 fichier(s) (seuil 8)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"criterion": "CLI",
|
||||||
|
"weight": 15,
|
||||||
|
"passed": true,
|
||||||
|
"evidence": "pie_manifest_gen.py (argparse + __main__)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"criterion": "HANDOFF",
|
||||||
|
"weight": 20,
|
||||||
|
"passed": true,
|
||||||
|
"evidence": "MANIFEST + 1 artefact(s) JSON valides"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "qa-acceptance",
|
"id": "qa-acceptance",
|
||||||
"path": "qa/acceptance",
|
"path": "qa/acceptance",
|
||||||
@@ -972,8 +1014,8 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"totals": {
|
"totals": {
|
||||||
"modules": 23,
|
"modules": 24,
|
||||||
"pass": 23,
|
"pass": 24,
|
||||||
"fail": 0,
|
"fail": 0,
|
||||||
"min_score": 100,
|
"min_score": 100,
|
||||||
"max_score": 100,
|
"max_score": 100,
|
||||||
|
|||||||
@@ -83,7 +83,8 @@
|
|||||||
{ "id": "qa-regression", "path": "qa/regression", "sprint": "S8", "archetype": "generator", "source": "roadmap Sprint 8 · Regression tests exhaustifs (matrice méta-niveau) · ci.yml qa-regression-tests" },
|
{ "id": "qa-regression", "path": "qa/regression", "sprint": "S8", "archetype": "generator", "source": "roadmap Sprint 8 · Regression tests exhaustifs (matrice méta-niveau) · ci.yml qa-regression-tests" },
|
||||||
{ "id": "devops-deploy-runbook", "path": "devops/deploy_runbook", "sprint": "S8", "archetype": "generator", "source": "roadmap Sprint 8 · DevOps Deployment production complet (run-book VPS unifié) · ci.yml devops-deploy-runbook-tests" },
|
{ "id": "devops-deploy-runbook", "path": "devops/deploy_runbook", "sprint": "S8", "archetype": "generator", "source": "roadmap Sprint 8 · DevOps Deployment production complet (run-book VPS unifié) · ci.yml devops-deploy-runbook-tests" },
|
||||||
{ "id": "qa-acceptance", "path": "qa/acceptance", "sprint": "S8", "archetype": "generator", "source": "roadmap Sprint 8 · QA buffer (matrice d'acceptation / traçabilité MVP roadmap → preuve) · ci.yml qa-acceptance-tests" },
|
{ "id": "qa-acceptance", "path": "qa/acceptance", "sprint": "S8", "archetype": "generator", "source": "roadmap Sprint 8 · QA buffer (matrice d'acceptation / traçabilité MVP roadmap → preuve) · ci.yml qa-acceptance-tests" },
|
||||||
{ "id": "mobile-app-config", "path": "mobile/app_config", "sprint": "S5", "archetype": "generator", "source": "roadmap Sprint 5 · Mobile (config app Expo/EAS + navigation par rôle) · ci.yml mobile-app-config-tests" }
|
{ "id": "mobile-app-config", "path": "mobile/app_config", "sprint": "S5", "archetype": "generator", "source": "roadmap Sprint 5 · Mobile (config app Expo/EAS + navigation par rôle) · ci.yml mobile-app-config-tests" },
|
||||||
|
{ "id": "pie-manifest", "path": "pie/manifest", "sprint": "S8", "archetype": "generator", "source": "directive PIE (Project Identity Engine · Annexe 12 · V10.1 · 2026-08-03) livrée durant le buffer S8 (roadmap L72-76) · manifest de dépendances faisabilité(SSOT)→downstream · ci.yml pie-manifest-tests" }
|
||||||
],
|
],
|
||||||
"notes": [
|
"notes": [
|
||||||
"Audit de MÉTA-NIVEAU : chaque note de module est CALCULÉE depuis des faits du dépôt (présence README/schéma, nombre de méthodes test_*, entrypoint CLI, intégrité out/) — jamais saisie à la main (#6).",
|
"Audit de MÉTA-NIVEAU : chaque note de module est CALCULÉE depuis des faits du dépôt (présence README/schéma, nombre de méthodes test_*, entrypoint CLI, intégrité out/) — jamais saisie à la main (#6).",
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
"matrix": "OTO QA · Matrice de régression exhaustive",
|
"matrix": "OTO QA · Matrice de régression exhaustive",
|
||||||
"version": "1.0",
|
"version": "1.0",
|
||||||
"verdict": "PASS",
|
"verdict": "PASS",
|
||||||
"suites": 23,
|
"suites": 24,
|
||||||
"test_methods": 604,
|
"test_methods": 624,
|
||||||
"coverage_ok": true,
|
"coverage_ok": true,
|
||||||
"artifacts": [
|
"artifacts": [
|
||||||
"regression_plan.json"
|
"regression_plan.json"
|
||||||
|
|||||||
@@ -17,8 +17,8 @@
|
|||||||
],
|
],
|
||||||
"coverage": {
|
"coverage": {
|
||||||
"ok": true,
|
"ok": true,
|
||||||
"suites_count": 23,
|
"suites_count": 24,
|
||||||
"gated_in_ci": 24,
|
"gated_in_ci": 25,
|
||||||
"self_module_excluded": "qa/regression",
|
"self_module_excluded": "qa/regression",
|
||||||
"self_module_gated": true,
|
"self_module_gated": true,
|
||||||
"missing_tests_dir": [],
|
"missing_tests_dir": [],
|
||||||
@@ -169,6 +169,17 @@
|
|||||||
"test_files": 1,
|
"test_files": 1,
|
||||||
"test_methods": 22
|
"test_methods": 22
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "pie.manifest",
|
||||||
|
"path": "pie/manifest",
|
||||||
|
"jobs": [
|
||||||
|
"pie-manifest-tests"
|
||||||
|
],
|
||||||
|
"in_gate": true,
|
||||||
|
"has_tests_dir": true,
|
||||||
|
"test_files": 1,
|
||||||
|
"test_methods": 20
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "publiciste",
|
"id": "publiciste",
|
||||||
"path": "publiciste",
|
"path": "publiciste",
|
||||||
@@ -282,9 +293,9 @@
|
|||||||
],
|
],
|
||||||
"under_threshold": [],
|
"under_threshold": [],
|
||||||
"totals": {
|
"totals": {
|
||||||
"suites": 23,
|
"suites": 24,
|
||||||
"test_files": 23,
|
"test_files": 24,
|
||||||
"test_methods": 604,
|
"test_methods": 624,
|
||||||
"min_methods": 10,
|
"min_methods": 10,
|
||||||
"under_threshold": 0
|
"under_threshold": 0
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user