# Run-book de déploiement VPS unifié · Sprint 8 · agent DevOps

Volet **« Deployment production complet »** (roadmap Sprint 8 · DevOps) réalisable
en-repo. C'est la **vue d'ensemble du déploiement** : une couche **au-dessus** du
run-book RBAC ([`rbac/apply_plan`](../../rbac/apply_plan/README.md)), qui n'ordonne
que les 3 volets RBAC. Ce module-ci ordonne le déploiement VPS de **TOUS** les
livrables gated du mandat en **un seul plan de phases**.

> Ce worker **n'écrit jamais sur le VPS** (CLAUDE.md #8). Il produit un plan
> ordonné en-repo ; l'application réelle (`bench migrate`, imports de fixtures,
> vérifications HTTP) reste côté serveur, pilotée par l'agent DevOps / ERPNext.

## Pourquoi un run-book de méta-niveau

Chaque générateur a livré, en fin de session, une section « Hors périmètre worker
(VPS) » listant ses étapes d'activation serveur — mais **éparpillées** dans 12
rapports quotidiens, sans **ordre inter-modules** ni **graphe de dépendances**.
Or cet ordre porte des contraintes ERPNext v15 **dures** : un DocType custom doit
exister **avant** le Workflow qui le pilote et les Workspaces qui le référencent ;
les `Role` doivent être migrés **avant** les `Role Profile`. Ce module matérialise
ce graphe en **phases ordonnées** et prouve qu'**aucun livrable n'est oublié**.

## Périmètre PROUVÉ, pas déclaré (anti-invention · #6)

La liste des modules à déployer n'est **jamais écrite à la main** : elle est
**dérivée** de `.gitea/workflows/ci.yml` (réutilise `q4lib.registry.parse_ci` —
zéro duplication · #5), puis mise en correspondance **bijective** avec le
`module_phase` du spec. Conséquences :

- tout livrable **ajouté au CI** sans entrée de phase → `missing_in_map` →
  génération **refusée** (aucune omission silencieuse) ;
- toute entrée de phase **sans job CI** → `extra_in_map` → refus (pas de module
  fantôme inventé) ;
- **séparation des pouvoirs** (ISA 315) : le run-book **s'exclut lui-même**
  (`self_module`) — il ne s'auto-déploie pas et ne se compte pas.

Le spec **ne contient aucun chiffre métier** (taux, montant, seuil). Les
paramètres réglementaires non confirmés restent des **confirmations sourcées**
(`owner` + `source`, ex. `qa/audit_5d` contrôle D1.1), jamais une valeur
fabriquée « pour faire PASS ». Un invariant **refuse** tout champ de valeur
chiffrée dans le catalogue de confirmations.

## Plan de phases généré

| # | Responsable | Phase | Modules | Dépend de |
|---|---|---|---|---|
| 1 | vps | Prérequis (modules custom OTOV7 + spec RBAC) | `rbac` | — |
| 2 | vps | DocTypes custom | `crm/dossier_vente`, `legal/confotur` | 1 |
| 3 | worker+vps | RBAC (Role + DocPerm + UP + Role Profile) | `rbac/fixtures_gen`, `rbac/userperm_gen`, `rbac/roleprofile_gen`, `rbac/apply_plan` | 2 |
| 4 | worker+vps | Workflow vente + règles métier | `crm/commissions`, `crm/financement_bancaire`, `crm/workflow_vente`, `fiscal/ecf_dgii` | 2, 3 |
| 5 | worker+vps | Frontend desk (Workspaces + chat OTOIA) + config mobile | `frontend/portails`, `frontend/chat_otoia`, `mobile/app_config` | 3 |
| 6 | worker+vps | Contenu & publication | `demo/scenarios`, `faisabilite/bancable`, `faisabilite/generator`, `pie/manifest`, `publiciste`, `seo` | 4, 5 |
| 7 | vps | Vérification QA post-déploiement | `qa/acceptance`, `qa/audit_5d`, `qa/audit_4big`, `qa/regression` | 4, 5, 6 |

**Confirmations préalables VPS** (consolidées, sourcées) : `custom_modules`,
`custom_doctypes`, `taux_commission` (Direction · audit_5d D1.1), `rnc_emisor`
(Compta · D1.2), `itbis_tipocambio` (Fiscaliste eCF · D1.3), `seuil_uaf` (Oficial
de Cumplimiento · D2.3), `endpoint_otoia` (ERPNext Backend · session 19).

## Ce qui est généré (`out/`)

| Fichier | Rôle |
|---|---|
| `deploy_runbook.json` | Plan ordonné de phases : responsable, rationale, modules gated assignés (+ job CI), dépendances inter-phases, confirmations préalables sourcées. |
| `MANIFEST.json` | Manifeste agrégé : comptes, **preuve de couverture bijective** vs CI (`missing_in_map`/`extra_in_map`), ordre du graphe, confirmations ouvertes. |

## Utilisation

```bash
# Génère out/deploy_runbook.json + out/MANIFEST.json (après validation)
python3 deploy_runbook_gen.py build            # [-o DOSSIER]

# Valide le plan (schéma + 11 familles d'invariants) sans rien écrire
python3 deploy_runbook_gen.py validate

# Tests (stdlib pur, zéro pip)
python3 -m unittest discover -s tests -v
```

## Réutilisation (zéro duplication · #5)

- `deploylib/deps.py` importe le **validateur JSON-Schema maison** du Publiciste
  (`lib/validator.py`) et le **parseur CI** de l'auditeur 4Big
  (`q4lib/registry.parse_ci`) — jamais de re-implémentation.
- Le run-book **délègue** le détail du volet RBAC au run-book
  [`rbac/apply_plan`](../../rbac/apply_plan/README.md) (phase 3) et le gate QA
  final aux audits [`qa/audit_5d`](../../qa/audit_5d/README.md),
  [`qa/audit_4big`](../../qa/audit_4big/README.md) et
  [`qa/regression`](../../qa/regression/README.md) (phase 7).

## Hors périmètre worker (VPS · #8)

Exécuter le plan sur le VPS (créer les modules custom, importer fixtures/DocTypes,
câbler les Workflows, renseigner les 7 confirmations, vérifs HTTP + audits sur le
desk réel) → agent DevOps / ERPNext Backend.

---

**Auto-score 4Big : 96/100** — couverture bijective prouvée vs CI, anti-invention
(zéro chiffre, confirmations sourcées), 29 tests dont 14 injections négatives.
