# Le chemin d'une issue — du cahier des charges à la production

> Vue d'ensemble du processus, demandée par Enguerran le 25/08. Version graphique
> interactive : artefact « Le chemin d'une issue » (galerie Claude). Ce document
> est la version au dépôt — **c'est elle qui fait foi**.
>
> État : modèle arbitré les 24–25/08 (branche `staging` fixe, trois environnements,
> `main` au runbook manuel jusqu'après la bascule). Sources détaillées en pied.

## La ligne — neuf stations

```mermaid
flowchart TB
    S1["1 · ROADMAP & CADRAGE — dans le PROJECT<br/>axes → chantiers → sprints (§ étage amont)<br/>CDC, maquettes, instruction → l'issue naît PLANIFIÉE<br/><i>Enguerran + sessions d'instruction</i>"]
    S2["2 · CRÉATION DE L'ISSUE<br/>formulaire gabarit · 1 jalon (Avant/Post bascule)<br/>· 1 lot: · 1 type: · « Dépend de : BACK#n »<br/><i>l'auteur (pilote, fil, testeur)</i>"]
    P1{{"⛩ PORTES AUTO : gabarit:ok/non-conforme<br/>+ liaison (dépendance blocked_by + miroir)"}}
    S3["3 · DÉVELOPPEMENT<br/>1 issue = 1 branche = 1 PR · worktree<br/><i>fil de chantier (charte)</i>"]
    P2{{"⛩ CI SUR PR : suite complète REQUISE<br/>(protection de branche) · lint informatif"}}
    S4["4 · ANNONCE §5 — le fil S'ARRÊTE<br/>preuves + baseline · jamais de merge par le fil"]
    S5["5 · TRAIN → development<br/><i>chapeau (autorité §7 = Enguerran)</i>"]
    S6["6 · CONTRE-RECETTE technique<br/>Playwright + parcours Claude<br/>sur l'ENVIRONNEMENT DE DEV (continu)"]
    S7["7 · CAMPAGNE DE RECETTE → staging<br/>cérémonie scriptée — pilote, sur ordre d'Enguerran<br/>(photo de development)<br/>recette HUMAINE (Lilian) · correctifs :<br/>PR → staging PUIS report → development"]
    P3{{"⛩ report-release : ROUGE tant qu'un correctif<br/>n'est pas reporté · la cérémonie suivante REFUSE"}}
    S8["8 · PROMOTION → main → PROD<br/>train de promotion · prod = runbook MANUEL<br/>jusqu'après la bascule (décision ferme 25/08)"]
    S9["9 · FERMETURE SUR PREUVE<br/>la mesure est écrite DANS l'issue"]
    S1 --> S2 --> P1 --> S3 --> P2 --> S4 --> S5 --> S6 --> S7 --> P3 --> S8 --> S9
```

## L'étage amont — qu'est-ce qu'un Project ?

**Réponse à la question de modélisation (25/08) : 1 Project = 1 PRODUIT, permanent.**
Il traverse les releases et ne meurt jamais avec l'une d'elles. Tout ce qui a un
début et une fin — release, sprint, chantier — est un CHAMP ou une issue À
L'INTÉRIEUR, jamais un Project.

```mermaid
flowchart TB
    subgraph PROJ["PROJECT « Formind LMS » — permanent, un par produit, BACK + FRONT"]
        subgraph AXE["AXE stratégique — champ single-select (objectifs, grands axes)"]
            subgraph CHANTIER["CHANTIER — issue PARENTE + sous-issues natives (progression auto)"]
                subgraph SPRINT["SPRINT — champ Itération, daté (reprend le rôle des lot:)"]
                    I["ISSUES → station 2"]
                    B["BROUILLONS de cadrage<br/>convertis en issues"]
                    P["PRIORITÉ — champ P0/P1/P2"]
                end
            end
        end
    end
    JAL["RELEASES = jalons GitHub — transverses, lus par le champ Milestone"]
    PROJ -.lit.-> JAL
```

| modèle envisagé | ce qu'il coûte | verdict |
|---|---|---|
| 1 Project = 1 release | les automatisations se configurent À LA MAIN dans l'interface (mesuré 25/08, aucune API) → tout re-cliquer à chaque cycle ; la roadmap meurt avec la release | ❌ |
| 1 Project = 1 sous-partie | vision éclatée, N configurations ; le transverse BACK+FRONT se perd | ❌ (réservé au SaaS le jour où il devient un produit séparé) |
| **1 Project = 1 PRODUIT, permanent** | une configuration, une fois · roadmap multi-releases · axes/sprints/releases = champs internes · brouillons pour le cadrage AMONT | ✅ **recommandé** |

Le Project intervient donc **avant** la création d'issue : objectifs et priorités se
posent en brouillons et axes ; l'issue n'est créée qu'au moment où elle entre dans un
sprint. ⏸ Mise en place post-bascule (cap du 24/08) — d'ici là, jalons + `lot:`
jouent ce rôle.

## Les trois voies et leurs environnements

```mermaid
flowchart LR
    subgraph DEV["🔒 development"]
        D[("branche de travail<br/>les trains y mergent")]
    end
    subgraph STG["🔒 staging (nom fixe)"]
        S[("branche de recette<br/>FIGÉE entre deux cérémonies")]
    end
    subgraph PROD["🔒 main"]
        M[("la production")]
    end
    FILS["PR des fils"] --> D
    D -.->|"ligne CD à venir<br/>(conversation CI/CD dédiée)"| SDEV["SERVEUR DE DEV<br/>machine à venir<br/>contre-recette Playwright"]
    D ==>|"CÉRÉMONIE scriptée :<br/>tag d'archive + refus si non-reporté<br/>+ fenêtre force-push refermée"| S
    S -->|"CD auto : tests → deploy<br/>→ santé → retour arrière"| SSTG["SERVEUR STAGING<br/>recette humaine (Lilian)"]
    CORR["correctif de recette<br/>(PR — push direct refusé)"] --> S
    S -.->|"report OBLIGATOIRE<br/>⛩ report-release rougit sinon"| D
    S ==>|"recette validée →<br/>train de promotion"| M
    M -.->|"runbook MANUEL<br/>aucune CD avant la bascule"| SPROD["PRODUCTION<br/>OVH aujourd'hui → Hetzner<br/>à la bascule"]
```

## Recette et contre-recette — la simplification du 25/08

| | **Contre-recette** (technique) | **Recette** (humaine) |
|---|---|---|
| voie / environnement | `development` → serveur de dev | `staging` → serveur de recette |
| qui | Claude + banc Playwright (`tools/recette-visuelle`) | Lilian et les testeurs (`recette-*`) |
| quand | en continu, à chaque train | par campagnes — le contenu est figé |
| prouve | l'écran fait ce que la maquette demande | le produit est utilisable par un tiers |

Un bug trouvé en recette redevient une **issue ordinaire** : station 2 (gabarit,
jalon « Avant bascule », `lot: défauts-fonctionnels`), et il refait tout le chemin.

## Qui fait quoi

| acteur | décide | fait | ne fait jamais |
|---|---|---|---|
| **Enguerran** | tous les arbitrages · go trains/frontières | conversations train · serveurs · secrets | — |
| **Chapeau** | trajectoire, séquencement | commande les trains (§7) · route les arbitrages | ne produit aucun fichier |
| **Fils** | — | développent, prouvent, annoncent §5 | ne mergent ni ne déploient |
| **Pilote (Claude)** | — | portes, scripts, cérémonie (sur ordre d'Enguerran), contre-recette, consignation | ne tranche pas · pas de SSH |
| **Lilian / testeurs** | — | recette humaine, signalements → screening | — |
| **Session bascule** | — | serveurs, script de cérémonie, runbook prod | ne touche pas aux workflows |
| **GitHub (portes)** | — | tout le déterministe — chaque porte **vue échouer** avant d'être crue | ne juge jamais le fond |

## Les objets GitHub — qui porte quoi

| objet | porte | aujourd'hui | post-bascule |
|---|---|---|---|
| **Issue** (formulaire) | le travail au gabarit | ✅ | idem |
| **Milestone** | le QUAND : Avant / Post bascule — **obligatoire à la création** (règle 25/08) | ✅ | jalons par cycle |
| **`lot:`** | avec quoi ça part (lotissement) | ✅ | meurt à la bascule |
| **`type:`** | la nature : dev / bug / doc / run | préparé — `scripts/appliquer_typologie.sh` à la frontière | champ *single-select* du Project |
| **`statut:`** | l'avancement | manuel ⚠️ (deux à la fois : possible) | **remplacé par le Project** — automatique et strict |
| **dépendance `blocked_by`** | le lien front↔back, posé par la porte, miroir auto, `is:blocked` | ✅ | idem |
| **protection de branche** | contrôle requis + `enforce_admins` sur les 3 voies · force-push refusé hors cérémonie | ✅ | idem |
| **branches + tags** | 3 voies fixes · `recette-AAAA-MM-fin` = l'archive | ✅ (train) | idem |
| **Project v2** | vue transverse BACK+FRONT, statuts automatiques | ⏸ rien pendant la recette | ✅ la roadmap (cap 24/08) |

## Les portes, et leur état

| porte | verdict | état |
|---|---|---|
| conformité gabarit | `gabarit:ok` / `non-conforme` + manques listés | en service |
| liaison des volets | dépendance posée, réf. morte = échec bruyant | en service |
| CI de PR | suite requise ; lint informatif (arbitrage ouvert) | en service |
| report-release | rouge tant que staging ⊄ development | dans le train |
| mise en service | rouge si une porte dort hors branche par défaut | en service |
| porte-jalon + porte-type | refus sans jalon / sans type unique | **instruites, à venir** |
| verrous de cérémonie | tag avant reset · refus si non-reporté · fenêtre refermée | dans le train |

---

## Ce qui change à la bascule — les deux états

| | AVANT (aujourd'hui) | APRÈS la bascule |
|---|---|---|
| statuts | étiquettes `statut:` manuelles | **Project v2** : statut unique, automatique |
| lot / typologie | `lot:` (planification) + `type:` préparé | `lot:` meurt · `type:` devient champ strict du Project |
| production | **OVH** (serveur partagé, sortie de l'équipe externe en cours) | **Hetzner** (machine dédiée, dimensionnée au runbook §0.4) |
| déploiement prod | runbook manuel | à instruire — conversation CI/CD dédiée |
| serveur de dev | à créer (phase B) | en service, CD continue depuis `development` |

**La règle qui résume tout** : une information ne se retraduit jamais à la main —
elle vit dans UN objet que la machine lit, et chaque garde-fou a été **vu échouer**
une fois avant d'être cru.

Sources : `FIL_DE_CHANTIER.md` · `CADRE_ISSUES.md` · `docs/roadmap/26_PLAN_MODELE_RELEASE.md` (v3) ·
`docs/roadmap/14_RUNBOOK_BASCULE_PROD.md` §0.3 · `docs/context/STRUCTURATION_GITHUB_2026-08-24.md` §9.
