# Structuration GitHub — instruction du 24 août 2026

> **Ce document existe parce que ce qui reste dans une conversation est perdu avec
> elle.** Demande d'Enguerran le 24/08 : poser le fonctionnement GitHub **en amont**
> de la CI/CD, et consigner au dépôt.
>
> ⚠️ **Il n'implémente rien et ne tranche rien.** Il établit ce qui existe, mesuré,
> et pose les arbitrages. La CI/CD part dans une conversation dédiée — décision
> d'Enguerran du 24/08, qui acte l'alerte portée par cette session depuis son début.

> **Mise à jour du 24/08 (soir)** — la zone aveugle « Projects » est **levée** : le
> scope a été obtenu et les mesures sont au §2.4. Elles **corrigent deux affirmations**
> de la première version : le rattachement du stock ne demande pas de renseigner les
> statuts un par un, et l'arbitrage « jalon *ou* champ » n'est pas un ou/ou.

---

## ⚠️ LE CAP — décision d'Enguerran du 24/08

> **On finit jusqu'à la bascule sur le format actuel. On prépare la roadmap future
> en utilisant Projects, post-bascule.**

**Ce que ça veut dire concrètement :**

| | |
|---|---|
| **jusqu'à la bascule** | **rien ne change.** Étiquettes `statut:*` et jalons restent la source. On ne touche **ni** au champ `Status` d'un projet, **ni** aux étiquettes, **ni** aux jalons. |
| **après la bascule** | la roadmap se construit dans un **Project v2**, en s'appuyant sur ce que ce document a mesuré. |

⚠️ **Les six arbitrages du §5 ne sont donc PAS abandonnés — ils sont DIFFÉRÉS.** Ils
se reposeront au moment de bâtir la roadmap post-bascule, et ce document est écrit
pour qu'on n'ait pas à tout réinstruire à ce moment-là.

⚠️ **Et une conséquence immédiate** : **aucune suppression d'étiquette avant la
bascule.** L'inventaire du §7 sert à préparer le tri, pas à l'exécuter. *Avant de
supprimer quoi que ce soit, il faut être sûr de ne perdre aucune information* —
demande explicite d'Enguerran, et le §7 montre que quatre familles d'étiquettes sur
six n'ont **aucun** équivalent dans un projet.

## Le besoin, dans les mots d'Enguerran

> « Limiter au maximum le besoin de **retraduire** un statut ou un lien à chaque
> fois, et le rendre **plus strict** qu'une simple ligne écrite dans le CA. »

Deux exigences distinctes, qu'il faut garder distinctes :

- **ne plus retraduire** — l'information doit être portée par un objet que la
  machine lit, pas par de la prose qu'un humain réinterprète ;
- **être strict** — l'objet doit rendre l'état incohérent *impossible*, pas
  seulement déconseillé.

---

## 1. Ce que la session du 23-24/08 a livré, et ce qu'Enguerran a décidé

### Livré et fusionné

| | |
|---|---|
| **#645** (BACK) + **FRONT#356** | le volet lié devient une **dépendance GitHub** ; sonde de mise en service |
| **#650** (BACK) | charte §6 (le canal entre conversations) et §7 (le mandat des trains) |

Le dispositif : la ligne `- Dépend de : BACK#396` du champ « Liens » — **qui existait
déjà** — est lue par `.github/workflows/liaison-volets.yml`, qui pose la dépendance
`blocked_by`. Détecteur déterministe hors ligne, 21 cas au corpus dont 8 pièges.
Documentation : `docs/process/CADRE_ISSUES.md`.

⚠️ **En attente d'un geste d'Enguerran** : le secret `TOKEN_LIAISON` (procédure
complète dans `CADRE_ISSUES.md`). Sans lui la porte **échoue bruyamment** — délibéré.

### Arbitrages rendus par Enguerran

1. **La dépendance `blocked_by`**, pas la sous-issue — une sous-issue dit « composant
   de » et n'admet qu'un parent ; FRONT#154 n'était pas un morceau de BACK#396, elle
   l'**attendait**.
2. **Structure d'abord, CI/CD ensuite** — puis, le 24/08 : **CI/CD en conversation dédiée**.
3. **Rien de rétroactif** — la règle ne vaut que pour les issues nouvelles.
4. **Charte §7** ratifié explicitement (délégation d'autorité : elle ne pouvait pas
   s'écrire sur le rapport de la conversation qui en bénéficie).

### Constats mesurés, versés au dépôt

| | où |
|---|---|
| la protection de `main` et `development` est **identique** dans les deux dépôts (`enforce_admins` compris) — la prémisse de `DEPLOIEMENT_STAGING.md` est **fausse**, et **D4 en découle** | commentaire sur #641 |
| **le lint n'est requis sur aucune des quatre branches** — un Pint/ESLint rouge entre sur `main` | #467 |
| coût d'un lint bloquant : BACK 87 runs / 2 échecs, FRONT 35 / 0 | #467 |
| `main-pipeline.yml` de la branche `pipeline` **armerait un déploiement de production** à chaque push sur `main` — désarmé aujourd'hui, triple mesure | #307 (fermée avec #455) |
| les étiquettes des deux dépôts ont divergé : `statut: en recette` a **deux sens différents** | **#646** |
| #455 : 22 fichiers applicatifs, conflit réel, 756 commits de retard | #464 |

**Six dispositifs faussement actifs** recensés à ce jour, plus **deux** trouvés dans
#455 (`pint` sans `--test`, couverture sur périmètre choisi). Point commun :
**aucun n'avait jamais rougi.**

---

## 2. L'état mesuré au 24/08 — ce que chaque outil porte réellement

### 2.1 Les étiquettes de statut

```
                        BACK      FRONT
issues ouvertes          262        88
sans étiquette statut     37        25     → 62 au total
avec 1 statut            225        61
avec PLUSIEURS statuts     0         2     ⚠️
```

Répartition : `à faire` 130+34 · `en recette` 90+24 · `en dev` 4+2 · `PR ouverte` 1+5.

⚠️ **La preuve que l'étiquette n'est pas stricte** : **FRONT#229 et FRONT#230 portent
`statut: à faire` ET `statut: en recette` en même temps.** Rien dans GitHub ne
l'empêche — une étiquette est multi-valuée par nature.

⚠️ **Et elle n'est pas partagée** : `statut: en recette` est décrit comme « mergée sur
staging » côté BACK et « Claude a comparé l'écran à sa maquette » côté FRONT (#646).
**Le même mot compte deux populations différentes** — c'est le chiffre de #631.

### 2.2 Les jalons

```
            ouvertes   avec jalon   sans jalon
BACK           262         171          91
FRONT           88          46          42
                                       133 au total
```

⚠️ **Un jalon est un objet PAR DÉPÔT.** BACK en a 12, FRONT 8, **numérotations
disjointes**, et BACK porte L0→L3 que FRONT n'a pas. « Le jalon L4.7 » n'est donc pas
une entité commune mais **deux objets homonymes** — rien ne les tient synchronisés.

### 2.3 Les liens entre dépôts — quatre formes, dont une jamais mesurée

Mesure du 23/08 (200 issues) : titre **12** · corps seulement **60** · absent **71** ·
sous-issues natives **0** · champ `parent` **absent** · `train-couple` posé **6 fois**
et **il ne dit pas avec quoi**.

⚠️ **Forme n°4, mesurée le 24/08 et absente de toutes les analyses précédentes** :
**49 issues du dépôt BACK portent l'étiquette `repo:front`.** Elles décrivent du
travail front, mais vivent dans le dépôt back.

**Sur ces 49, 37 ne citent AUCUNE issue FRONT.**

C'est la forme la plus opaque des quatre : ces 37 issues ne comptent pas dans les 143
du dépôt FRONT, ne portent aucune dépendance, et l'étiquette dit « c'est du front »
**sans dire où**. Le dépôt BACK sert donc de **backlog central de fait**, avec une
étiquette en guise d'aiguillage.

État des liens **typés** au 24/08 : `is:blocked` = **1**, `is:blocking` = **1**
(la paire posée par cette session), `no:parent-issue` = **88 sur 88**.

### 2.4 Les Projects — mesuré le 24/08 (zone aveugle levée)

> Cette section était marquée « zone aveugle » faute du scope `read:project`.
> **Le scope a été obtenu, les mesures ci-dessous remplacent les suppositions**,
> et elles corrigent deux affirmations de la première version (§4).

**Deux projets existent déjà, et aucun n'a jamais servi** — `@AAZTEKDEV's untitled
project` (créé le 18/08) et `@NumediaDev's untitled project` (créé le 07/11/2025).
**Zéro item chacun**, `updatedAt` = date de création. **Neuvième outil disponible,
gratuit, et inemployé** — après les sous-issues, les dépendances et les *issue types*.

#### Les champs natifs, présents sans rien configurer

| champ | type | ce qu'il règle |
|---|---|---|
| **Status** | `SINGLE_SELECT` — Todo / In Progress / Done | ⚠️ **mono-valué par construction** : FRONT#229 et #230 deviennent *impossibles* |
| **Repository** | `REPOSITORY` | **rend l'étiquette `repo:*` inutile** — le projet sait de quel dépôt vient chaque item |
| **Milestone** | `MILESTONE` | le jalon de *chaque* dépôt est lisible **dans une vue unique** |
| **Labels** | `LABELS` | les étiquettes existantes restent visibles, sans double saisie |
| **Parent issue** · **Sub-issues progress** | natifs | les liens natifs sont exposés comme champs |
| **Linked pull requests** | natif | le lien PR ↔ issue, sans prose |

⚠️ **Le champ `Milestone` change l'arbitrage n°2** : ce n'est **pas** « jalon *ou*
champ de projet ». Le projet **lit** le jalon de chaque dépôt et l'affiche
transversalement. Les deux cohabitent sans double saisie.

#### Les six automatisations natives — toutes actives

`Auto-add sub-issues to project` · `Auto-close issue` · `Item added to project` ·
`Item closed` · `Pull request linked to issue` · **`Pull request merged`**

⚠️ **`Pull request merged` est exactement ce que demande #630** (« déplacer
l'étiquette de statut à la fusion — JAMAIS fermer »), **sans écrire une ligne de
code**.

#### ⚠️ Éprouvées, pas seulement lues « enabled: true »

*Huit dispositifs de ce dépôt se sont révélés faussement actifs, et aucun n'avait
jamais rougi. « Actif » dans une configuration ne prouve rien.* Épreuve réelle du
24/08, sur le projet #2, items ajoutés puis retirés (0 item avant, 0 après) :

| épreuve | résultat |
|---|---|
| un même projet porte **BACK#646 et FRONT#355** | ✅ **le transverse fonctionne** |
| `Repository` et `Labels` à l'ajout | ✅ **renseignés seuls** |
| issue **ouverte** ajoutée | ✅ `Status = Todo` posé automatiquement |
| issue **fermée** (#307) ajoutée | ✅ **`Status = Done` posé automatiquement** |

⚠️ **Ce dernier résultat corrige une affirmation de la première version de ce
document.** Il y était écrit que le projet « n'est pas rétroactif tout seul : 350
issues à rattacher **et à renseigner** ». **C'est faux** : le statut se pose seul,
selon l'état réel de l'issue. Le rattachement du stock ne demande **aucun tri manuel
ouvert/fermé** — seulement l'ajout au projet, qui est scriptable.

**Reste non éprouvé** : `Pull request merged` → `Done`, qui exigerait de fusionner une
PR liée à une issue du projet. **À éprouver au premier train qui suivra la mise en
place** — et à ne pas tenir pour acquis d'ici là.

#### ⚠️⚠️ LE PIÈGE — toucher aux options du `Status` DÉSARME les automatisations

*Épreuve du 24/08, provoquée par la question d'Enguerran « es-tu sûr ? ». La réponse
était non, et voici pourquoi.*

Nos statuts réels sont **cinq** (`à faire`, `en dev`, `PR ouverte`, `en recette`,
`contre-recette`), le champ natif en propose **trois**. Épreuve, sur le projet vide :

1. remplacer les options par nos cinq statuts → **accepté** par l'API ;
2. ajouter une issue ouverte, puis une fermée → **aucun statut posé, ni pour l'une ni
   pour l'autre** ;
3. relecture des automatisations → **5 des 6 sont passées à `enabled: false`.**

**GitHub ne fait pas semblant** : il les désactive parce que l'option qu'elles
ciblaient n'existe plus. Ce n'est donc **pas** un dispositif faussement actif — c'est
le bon comportement. Mais l'effet pratique est net.

⚠️ **Et restaurer les noms d'origine ne les rallume PAS** : `updateProjectV2Field`
recrée les options avec de **nouveaux identifiants**, et les automatisations pointaient
les anciens. Contre-épreuve faite : options restaurées à `Todo | In Progress | Done`,
une issue ajoutée ne reçoit **toujours aucun statut** — alors que le second projet,
jamais touché, pose bien `Todo` sur la même issue.

⚠️ **La reconfiguration est MANUELLE, et il n'y a pas d'alternative** : la seule
mutation exposée par l'API GraphQL est `deleteProjectV2Workflow`. Aucune pour créer,
configurer ou réactiver. Les champs lisibles d'un `ProjectV2Workflow` se limitent à
`name`, `enabled`, `number`, `createdAt`, `updatedAt`. **Les automatisations d'un
projet se règlent exclusivement dans l'interface web.**

**État laissé** : le projet `@AAZTEKDEV's untitled project` (vide, jamais utilisé) a
**5 automatisations désactivées** et ses options restaurées. La remise en état est
quelques clics dans l'interface du projet. Le second projet est intact — il a servi de
témoin.

---

## 7. Inventaire exhaustif des étiquettes — pour préparer le tri, PAS pour l'exécuter

*Demande d'Enguerran : « avant de supprimer quoi que ce soit, il faut qu'on soit sûr
de ne perdre aucune info importante ».* Usage compté sur **toutes** les issues,
ouvertes **et** fermées.

**BACK : 33 étiquettes définies, 20 utilisées, 13 mortes.
FRONT : 21 définies, 11 utilisées, 10 mortes.**

| famille | usage | un Project la remplace-t-il ? |
|---|---|---|
| `statut:*` — 5 valeurs réelles | 272 | ⚠️ **oui, mais au prix des automatisations** (voir le piège ci-dessus) |
| `repo:back` · `repo:front` | 174 | ✅ champ **`Repository`** natif |
| **`repo:pipeline`** | 4 | ❌ **aucun dépôt de ce nom n'existe** — c'était une branche. Rien ne peut le porter. |
| `type:*` · `bloquant` (41) · `securite` · `conformite` · `P0` / `P1` | 224 | ❌ **multi-valués par nature** — ils restent des étiquettes |
| `train-couple` | 9 | ✅ remplacé par la dépendance `blocked_by` |
| `gabarit:ok` · `gabarit:non-conforme` | 7 | ❌ **posés par un workflow** — doivent rester des étiquettes |

**Conclusion : un Project remplace DEUX familles sur six.** L'affirmation « le projet
remplace les étiquettes de statut » est vraie sur la contrainte, **et coûteuse en
pratique**.

**À trier le moment venu, sans rien décider aujourd'hui :**

- **23 étiquettes ne servent nulle part** — dont les 8 étiquettes par défaut de GitHub
  (`documentation`, `duplicate`, `enhancement`, `good first issue`, `help wanted`,
  `invalid`, `question`, `wontfix`), plus `dependencies`, `javascript`, `php`,
  `type:design` ;
- ⚠️ **`statut: recette utilisateur` est définie dans LES DEUX dépôts et n'a JAMAIS
  servi** — un statut du processus de recette qui n'a jamais été posé ;
- ⚠️ **`statut: en recette` porte deux définitions différentes** selon le dépôt
  (#646) : tout comptage qui l'agrège additionne deux populations.

---

## 8. Qui fait quoi — déterministe contre humain

*Seconde question d'Enguerran, et elle commande la suite : ce qui n'est pas
déterministe devra être tenu par quelqu'un, indéfiniment.*

### Déterministe — la machine, sans personne

| | porté par |
|---|---|
| la dépendance `blocked_by`, son **miroir**, et `is:blocked` / `is:blocking` | GitHub, une fois la dépendance posée |
| **poser** cette dépendance à partir de la ligne `- Dépend de : BACK#396` | `liaison-volets.yml` ⚠️ *exige `TOKEN_LIAISON`* |
| `gabarit:ok` / `gabarit:non-conforme` + le commentaire listant les manques | `conformite-issues.yml` |
| l'alerte quand une porte n'est pas en service sur la branche par défaut | `mise-en-service.yml` |
| tests, lint, déploiement staging | la CI |
| `Repository`, `Labels`, `Milestone` d'un item de projet | GitHub, à l'ajout |
| l'**impossibilité** de porter deux statuts | la contrainte *single-select* |

### Humain — Enguerran, Claude, ou un dev

| | qui |
|---|---|
| **écrire la ligne `- Dépend de :`** — le seul geste qui déclenche toute la liaison | l'auteur de l'issue |
| choisir le lot, le jalon, la criticité | Enguerran |
| rattacher les ~350 issues au projet | scriptable, mais **quelqu'un le lance** |
| **configurer les automatisations d'un projet** | ⚠️ **interface web uniquement** |
| poser `TOKEN_LIAISON` | **Enguerran seul** |
| fermer une issue | ⚠️ rien ne l'empêche, même bloquée (mesuré) |

### ⚠️ La limite structurelle, qui ne dépend d'aucun outil

**Un statut n'est automatisable que s'il correspond à un ÉVÉNEMENT GitHub.**

- `à faire` → ajout au projet · `PR ouverte` → PR liée · `en recette` → PR fusionnée ·
  `Done` → fermeture : **dérivables** ;
- ⚠️ **`contre-recette` ne correspond à aucun événement GitHub.** C'est un état de
  processus — quelqu'un a rejoué des parcours sur les écrans réels. **Il restera
  humain quel que soit l'outil choisi.**

⚠️ **Et `Pull request merged` ne distingue pas `development` de `main`** : « en
recette » et « en production » ne sont pas séparables par l'automatisation native.
Toute solution qui les distingue demandera un workflow écrit, donc de la CI — c'est-à-
dire l'autre conversation.

---

## 3. Le diagnostic

**Trois des quatre informations qu'Enguerran veut cesser de retraduire — le statut,
le lot, l'aiguillage front/back — sont aujourd'hui portées par des ÉTIQUETTES**,
c'est-à-dire par l'outil GitHub :

- le **moins strict** — multi-valué, créable à la volée, aucune exclusion mutuelle ;
- le **seul qui ne traverse pas les dépôts** — deux jeux distincts, déjà divergents.

Le jalon, lui, est mono-valué (donc strict) mais reste **par dépôt**.

⚠️ **Aucun des deux outils employés aujourd'hui n'est à la fois strict et transverse.**
C'est la racine du problème, et c'est pourquoi il faut retraduire à chaque fois.

---

## 4. Ce que chaque outil peut porter — capacités, pas opinions

| | portée | strict ? | traverse les dépôts ? | lisible par machine |
|---|---|---|---|---|
| **Étiquette** | dépôt | ❌ multi-valuée, texte libre | ❌ jeux distincts | oui, mais sans sémantique |
| **Jalon** | dépôt | ✅ un seul par issue | ❌ objets homonymes | oui |
| **Project v2** | **compte** | ✅ champs typés, *single-select* | ✅ **oui, nativement** | oui, + **automatisations** |
| **Dépendance / sous-issue** | inter-dépôt | ✅ typée | ✅ **prouvé le 23/08** | oui (`is:blocked`, `advanced_search=true`) |

⚠️ **Piège de mesure déjà payé** : `is:blocked` n'existe **qu'avec
`advanced_search=true`**. En recherche REST classique **et en GraphQL** il rend `0`,
exactement comme un qualificatif inventé. Un contrôle écrit en GraphQL serait **vert
pour toujours**.

⚠️ **Les *issue types* sont hors de portée** : réservés aux organisations, et ce compte
est un **User** (`gh api users/AAZTEKDEV` → `"type": "User"`). Toute solution qui en
dépendrait est à écarter — sauf à migrer vers une organisation, ce qui est un sujet
en soi.

### Ce que le Project v2 apporterait, et qui répond mot pour mot au besoin

- un champ **Statut** en *single-select* → **FRONT#229 et #230 deviendraient
  structurellement impossibles** ;
- **un seul projet pour les deux dépôts** → un lot, un statut, une priorité qui ne se
  dédoublent plus ;
- des **automatisations natives** (PR fusionnée → statut, issue fermée → statut, ajout
  automatique au projet) → **c'est précisément « ne plus retraduire »**, et c'est ce
  que demandent #630 (« déplacer l'étiquette de statut à la fusion, JAMAIS fermer ») et
  #631 (120 bloquées « en recette », 59 sans statut).

### Ce qu'il n'apporte pas

- il **ne remplace pas** la dépendance : le lien reste porté par les issues ;
- un champ de projet **ne se voit pas dans une recherche d'issues classique** — les
  filtres vivent dans le projet ;
- ⚠️ **le rattachement du stock reste à faire** : ~350 issues à ajouter au projet.
  Mais **elles n'ont pas à être renseignées une par une** — mesuré le 24/08, le
  statut se pose seul selon l'état de l'issue (ouverte → `Todo`, fermée → `Done`).
  L'ajout est scriptable.

---

## 5. Les arbitrages ouverts — à trancher par Enguerran, non tranchés ici

1. **Le statut migre-t-il des étiquettes vers un champ de Project ?** Et si oui, les
   étiquettes `statut: *` sont-elles **supprimées** (une seule source, donc pas de
   contradiction possible) ou **conservées en lecture** (visibles sans ouvrir le
   projet, mais deux sources à tenir) ?
2. **Le lot : jalon ou champ de Project ?** ⚠️ **Question reformulée après mesure** —
   ce n'est pas un ou/ou. Le projet porte un champ **Milestone** natif qui lit le jalon
   de chaque dépôt et l'affiche transversalement : les jalons peuvent rester en place
   et devenir lisibles d'une seule vue. La vraie question devient : **garde-t-on les
   jalons comme source du lot** (ils restent deux objets homonymes à tenir
   synchronisés), **ou ajoute-t-on un champ « Lot » propre au projet** (une seule
   source, mais le jalon natif de GitHub ne dit alors plus le lot) ?
3. **Un projet unique pour les deux dépôts, ou un par dépôt ?** L'unique est le seul
   qui supprime la retraduction ; le double reproduit la divergence déjà mesurée.
4. **Que reste-t-il aux étiquettes ?** Proposition à instruire : ce qui est
   légitimement **multi-valué** — `type:*`, `securite`, `conformite`, `bloquant`.
   ⚠️ **Pour `repo:*`, la mesure a tranché** : le champ **Repository** est natif et
   renseigné seul. Les 49 `repo:front` du dépôt BACK n'ont plus lieu d'être comme
   étiquettes — **mais elles ne disent pas non plus où vit le travail**, ce qui reste
   l'objet de l'arbitrage n°5.
5. **Les 37 issues `repo:front` sans pendant FRONT** : on les **déplace** dans le dépôt
   FRONT (GitHub sait transférer une issue), ou on assume le **backlog central** et le
   projet porte le dépôt cible ? ⚠️ Le transfert change les numéros et casse les
   références écrites en prose.
6. **Qui écrit le statut ?** Automatisations seules (strict, mais tout état non prévu
   devient impossible à exprimer), ou automatisations + saisie humaine (souple, mais
   la contradiction revient par la porte de la main).

---

## 6. Ce qui doit être mesuré avant de décider

1. ~~Les Projects existants~~ — ✅ **fait le 24/08**, voir §2.4.
2. ~~Les automatisations natives~~ — ✅ **faites et éprouvées**, voir §2.4. **Sauf
   une** : `Pull request merged` → `Done` reste à éprouver sur un vrai train.
3. **Le coût réel du rattachement** des 350 issues, et s'il peut être scripté.
   ⚠️ **Ce point-ci est POST-BASCULE** (cap du 24/08) — il ne se pose qu'au moment de
   bâtir la roadmap future.
4. **Le sort des 133 issues sans jalon** — elles ne sont dans aucun lot, donc dans
   aucun comptage. C'est le chantier du lotissement, pas de celui-ci.

---

## 9. La typologie d'issues × les lots de bascule — instruction du 25/08

> Demande d'Enguerran (typologie : dev / bugs recette / doc / corrections run),
> avec directive : **s'aligner sur les étiquettes `lot:` posées par le lotissement
> ou les absorber — jamais les doublonner.** Proposer AVANT de créer. Ce chapitre
> propose ; il ne crée rien.

### L'existant, mesuré le 25/08 au soir

- **3 étiquettes `lot:`**, descriptions identiques dans les deux dépôts, couverture
  **totale** du jalon « Avant bascule » (BACK 9+16+19=44/44 · FRONT 2+8+1=11/11) :
  `lot: serveur-prod` · `lot: ci-cd-structure` · `lot: défauts-fonctionnels` ;
- jalons renommés : **« Avant bascule »** (due 13/09 indicatif) / **« Post-bascule »** ;
- famille `type:` : **BACK seulement** (`feat` 114 · `fix` 40 · `infra` 19 · `sec` 12,
  usage total ouvertes+fermées), **le FRONT n'en a aucune** ;
- ⚠️ recouvrement `lot:` × `type:` **presque vide** — 22 des 44 issues lotées du BACK
  n'ont AUCUN `type:` — et là où les deux existent, les sens se chevauchent
  (`serveur-prod` × `type:infra` = 10) ;
- ⚠️ doublon préexistant : **`type:sec` (12) ET `securite` (10)** vivent côte à côte.

### La clé de l'articulation : deux QUESTIONS différentes, deux durées de vie

| axe | question | vie | gardien |
|---|---|---|---|
| **`lot:`** | *avec quoi ça part* (planification de la bascule) | **meurt à la bascule** | lotissement |
| **typologie** | *quelle nature de travail* | **permanente** (survit en V2/SaaS) | processus |

**Ni absorption ni doublon : orthogonalité.** Absorber `lot:` dans la typologie
mélangerait une planification temporaire à une nature permanente ; créer une famille
`nature:` à côté de `type:` fabriquerait le doublon interdit. La proposition est donc :

### Proposition — UNE famille `type:`, quatre valeurs, les deux dépôts

| valeur | couvre | obtenue par |
|---|---|---|
| `type: dev` | features, refactors, chantiers | **renommage** de `type:feat` (114 rattachements conservés — un renommage GitHub suit les issues) |
| `type: bug` | défauts, dont bugs de recette | **renommage** de `type:fix` (40) — la provenance « recette » est déjà portée par `lot: défauts-fonctionnels` + le jalon, pas besoin de la répéter dans la nature |
| `type: doc` | documentation, consignations | création (l'étiquette `documentation` par défaut, 0 usage, se supprime) |
| `type: run` | exploitation, corrections d'exploitation, gestes serveur récurrents | création |

Compléments du même geste : **`type:sec` fusionne dans `securite`** (12 issues à
re-étiqueter — la sécurité est un DRAPEAU transversal, pas une nature : une issue
sécurité EST un dev ou un run) ; **`type:infra` se ventile** entre `type: dev`
(construire) et `type: run` (exploiter) — 19 issues à lire une à une, c'est le seul
coût manuel réel.

**La règle d'articulation, complète** : une issue porte **1 jalon** (Avant/Post
bascule) **+ 1 `lot:`** (si Avant bascule — au lotissement) **+ 1 `type:`** (nature).
⚠️ Une étiquette n'empêche pas le double marquage (FRONT#229/230 l'ont prouvé pour
`statut:`) : le verrou déterministe est **l'extension de la porte de gabarit** — le
même test que la porte-jalon instruite sur #649 peut vérifier « exactement un
`type:` » ; et post-bascule, le cap du 24/08 prévoit que le Project v2 porte la
nature en champ *single-select*, strict par construction.

### Ce que ça donne à la bascule

Les `lot:` se ferment avec le jalon « Avant bascule » ; la typologie **reprend le
rôle discriminant que L4.8 jouait** (le tri des défauts) sans hériter de sa
confusion : « qu'est-ce que c'est » reste, « quand ça part » disparaît avec le lot.

### ✅ GO d'Enguerran (25/08, 18h05) — et la préparation qui en découle

La proposition est **validée telle quelle**, avec la réserve actée : *préparation oui,
application à une FRONTIÈRE annoncée — jamais pendant que la recette vit.*

**La frontière est devenue UN geste rejouable** : `scripts/appliquer_typologie.sh`
— répétition à sec par défaut (`--dry-run`, jouée le 25/08 contre les vrais dépôts :
chaque geste énuméré, zéro refus), application réelle par `--appliquer` seulement.
Une issue `type:infra` absente de la table ci-dessous fait **refuser** le script —
jamais un choix silencieux.

### La ventilation de `type:infra` — lue issue par issue le 25/08

| → `type:dev` (construire) | → `type:run` (exploiter) |
|---|---|
| #658 staging/CD · #644 porte de liaison · #622 bump dompdf · #439 seeder de recette · #393 Sentry · #304 intégrer la CI pipeline · #27 tracking RGPD | #649 jalons divergés · #646 étiquettes divergées · #307 coordination deploy · #305 sauvegardes · #303 Composer serveur · #302 SPF/DKIM · #301 lignée de main · #181 bascule git · #157 migrations prod · #156 répétition générale · #137 recalage migrations · #136 MyISAM · #12 rattrapage schéma |

7 « dev », 13 « run ». Critère appliqué : *construit-on un dispositif, ou opère-t-on
des serveurs et des données ?* La table est **la** source du script — la compléter
ici d'abord, jamais dans le script seul.

### Coût total, honnête

2 renommages (154 rattachements suivent tout seuls) · 2 créations · 1 fusion
(12 issues) · 1 ventilation manuelle (19 issues) · pose de la famille côté FRONT
(aujourd'hui vierge). **Aucune bascule d'outillage pendant la recette** — le cap du
24/08 tient : tout ceci attend le go d'Enguerran, et rien n'est créé par ce chapitre.

## Ce que ce document ne fait pas

Il **ne crée aucun projet, ne renomme aucune étiquette, ne déplace aucune issue**. Il
n'a pas d'autorité sur le lotissement, qui traite les mêmes 355 issues au même moment
— ⚠️ **deux sessions sur le même stock ont déjà produit deux issues contradictoires
sans se voir (#575 contre #626).**
