Aller au contenu

PD-295 — Bibliothèque documentaire vers mémoire vivante (spécification canonique contractuelle)

1. Objectif

La User Story PD-295 DOIT permettre, au démarrage du step 0 du workflow /gov, l’injection automatique et non bloquante de connaissances issues de 3 sources: - learnings historiques pondérés par réutilisation, - fiches de veille pertinentes, - clarifications PO passées du même domaine.

La story DOIT également maintenir un cycle de vie explicite des learnings (scope story|domain|global + archivage), sans changer la stack existante du projet.

2. Périmètre / Hors périmètre

Inclus

  • B1: indexation FAISS des fiches de veille depuis ProbatioVault-doc/docs/veille/**/*.md.
  • B2: persistance du verbatim des 4 réponses PO du step 0 dans PD-XX-clarifications.md + indexation.
  • B3: calcul de reuse_score à partir des injections historisées.
  • B4: migration scope, promotion (story→domain→global) et éviction vers archive.
  • B5: injection unifiée step 0 en 3 sections (learnings, veille, clarifications), non bloquante en cas d’erreur source.
  • Mesure post-merge des KPI CS-1..CS-4 via scripts/analyze-compounding.py (hors Gate 8).

Exclu

  • Toute migration de moteur de stockage.
  • Toute refonte de pipeline existant hors périmètre B1..B5.
  • Signature HMAC, clé Vault, canonicalisation JCS, fail-closed strict, filtre PII, purge RGPD multi-artefacts, rate-limit lecture, reranker neural, BM25 hybride, knowledge graph, skill router, résumés hiérarchiques.
  • Toute exigence SaaS multi-tenant ou conformité externe non applicable au contexte mono-utilisateur interne.

3. Définitions

Terme Définition
Step 0 Étape d’expression de besoin dans /gov.
Learning Entrée capitalisée dans learnings.jsonl issue des gates/REX.
Clarification Verbatim brut des 4 réponses PO du step 0, persistant en Markdown.
Veille Fiche Markdown dans ProbatioVault-doc/docs/veille/ avec frontmatter YAML.
reuse_score Score de réutilisation: nb_injections*0.4 + nb_stories_gate8_go_apres_injection*0.4 + nb_domains_distincts*0.2.
Scope Niveau de portée d’un learning: story, domain, global, archived.
Éviction Déplacement d’un learning vers learnings-archive.jsonl, non indexé.
Injection unifiée Bloc Markdown step 0 contenant 3 sections sources.

4. Invariants (non négociables)

ID Règle Justification
INV-295-01 B1 DOIT scanner ProbatioVault-doc/docs/veille/**/*.md et ignorer les fichiers invalides sans arrêter le flux global. Robustesse non bloquante demandée.
INV-295-02 Chaque fiche veille valide DOIT produire une ligne data/veille.jsonl conforme au modèle §5.1. Traçabilité et indexabilité.
INV-295-03 B2 DOIT persister le verbatim brut des 4 réponses PO, sans résumé ni filtrage, dans PD-XX-clarifications.md. Besoin v3 explicite.
INV-295-04 Les clarifications persistées DOIVENT être indexées dans data/clarifications.jsonl + index FAISS dédié. Réutilisation ultérieure.
INV-295-05 B3 DOIT appliquer exactement la formule reuse_score (coefficients 0.4/0.4/0.2). Source de vérité scoring.
INV-295-06 data/learnings-scores.jsonl DOIT être jointable avec learnings.jsonl via {story, gate, tags_hash}. Cohérence des enrichissements.
INV-295-07 La recherche learnings DOIT utiliser reuse_score en tri secondaire. Promotion des learnings utiles.
INV-295-08 Migration initiale B4: tout learning existant sans scope DOIT être positionné à scope: story. Point de départ explicite.
INV-295-09 Promotion story → domain autorisée seulement si reuse_score >= 0.3. Règle métier demandée.
INV-295-10 Promotion domain → global autorisée seulement si reuse_score >= 0.6. Règle métier demandée.
INV-295-11 Éviction autorisée seulement si nb_injections == 0 ET âge > 56 jours. Règle métier demandée.
INV-295-12 learnings-archive.jsonl n’est jamais indexé dans l’index actif d’injection. Éviction effective.
INV-295-13 B5 DOIT produire 3 sections avec cardinalités cibles 5/3/3. Contrat d’injection unifiée.
INV-295-14 Si une source retourne 0 résultat: section affichée avec aucun résultat, sans blocage step 0. Non blocant demandé.
INV-295-15 Si une source échoue (fichier/Ollama/index): section vide + erreur stderr, sans blocage step 0. Non blocant demandé.
INV-295-16 Les mécanismes explicitement exclus au besoin v3 DOIVENT rester hors périmètre. Anti-régression “théâtre sécurité”.
INV-295-TR-01 Transition STORY_ACTIVE → DOMAIN_ACTIVE: AUTORISÉE (reuse_score >= 0.3). Promotion domaine.
INV-295-TR-02 Transition STORY_ACTIVE → GLOBAL_ACTIVE: INTERDITE. Saut direct non spécifié.
INV-295-TR-03 Transition STORY_ACTIVE → ARCHIVED: AUTORISÉE (stale §5.3). Éviction.
INV-295-TR-04 Transition DOMAIN_ACTIVE → STORY_ACTIVE: INTERDITE. Retour interdit explicitement.
INV-295-TR-05 Transition DOMAIN_ACTIVE → GLOBAL_ACTIVE: AUTORISÉE (reuse_score >= 0.6). Promotion globale.
INV-295-TR-06 Transition DOMAIN_ACTIVE → ARCHIVED: AUTORISÉE (stale §5.3). Éviction.
INV-295-TR-07 Transition GLOBAL_ACTIVE → DOMAIN_ACTIVE: INTERDITE. Retour interdit explicitement.
INV-295-TR-08 Transition GLOBAL_ACTIVE → STORY_ACTIVE: INTERDITE. Retour interdit explicitement.
INV-295-TR-09 Transition GLOBAL_ACTIVE → ARCHIVED: AUTORISÉE (stale §5.3). Éviction.
INV-295-TR-10 Transition ARCHIVED → STORY_ACTIVE: INTERDITE. État terminal.
INV-295-TR-11 Transition ARCHIVED → DOMAIN_ACTIVE: INTERDITE. État terminal.
INV-295-TR-12 Transition ARCHIVED → GLOBAL_ACTIVE: INTERDITE. État terminal.
INV-295-TR-13 ARCHIVED → * : INTERDITE (état terminal, résolution manuelle uniquement). Obligation explicite états terminaux.

5. Flux nominaux

5.1 Modèle de données contractuel (source unique des formats)

ID Donnée Format / encodage Taille Jeu de caractères Case Regex Invalide
D-295-01 story_id String UTF-8 4..11 [A-Z0-9-] Sensitive ^[A-Z]{2,6}-[0-9]{1,4}$ Ligne rejetée + stderr
D-295-02 gate Entier JSON 0..10 n/a n/a n/a Ligne exclue du scoring
D-295-03 domain String UTF-8 2..64 [a-z0-9-] Sensitive ^[a-z0-9]+(?:-[a-z0-9]+)*$ Ligne rejetée + stderr
D-295-04 project Enum 2..32 ASCII lower-hyphen Sensitive n/a Ligne rejetée + stderr
D-295-05 tags[] Array JSON de strings 0..64 tags tag: [a-z0-9#-] Sensitive ^#[a-z0-9-]{1,63}$ Ligne exclue du scoring
D-295-06 tags_hash Hex SHA-256 lowercase 64 chars [a-f0-9] Sensitive ^[a-f0-9]{64}$ Jointure impossible, learning exclu
D-295-07 scope Enum {story,domain,global,archived} n/a ASCII Sensitive n/a Transition refusée
D-295-08 reuse_score Nombre décimal JSON 0.0000..999999.9999 n/a n/a n/a Valeur rejetée, score non publié
D-295-09 nb_injections Entier JSON 0..999999 n/a n/a n/a Valeur rejetée
D-295-10 nb_stories_gate8_go_apres_injection Entier JSON 0..999999 n/a n/a n/a Valeur rejetée
D-295-11 nb_domains_distincts Entier JSON 0..2048 n/a n/a n/a Valeur rejetée
D-295-12 date Date ISO 10 [0-9-] Sensitive ^\d{4}-\d{2}-\d{2}$ Ligne non éligible à l’éviction
D-295-13 verdict_veille Enum {signal,bruit,veille} n/a ASCII lower Sensitive n/a Fiche exclue de l’index veille
D-295-14 impact_pv Enum {fort,modere,faible,aucun} n/a ASCII lower Sensitive n/a Fiche exclue de l’index veille
D-295-15 clarification_filename Nom de fichier 24..31 [A-Z0-9.-] Sensitive ^PD-[0-9]{1,4}-clarifications\.md$ Écriture refusée
D-295-16 clarification_verbatim Texte UTF-8 brut 1..20000 chars UTF-8 printable + LF Sensitive n/a Persistance refusée
D-295-17 source_kind Enum {learning,veille,clarification} n/a ASCII lower Sensitive n/a Entrée d’injection rejetée

5.2 Bornes numériques contractuelles

Paramètre Défaut Min Max Unité Contexte de référence Percentile Hors bornes
po_questions_count 4 4 4 questions Step 0 /gov n/a Erreur de conformité
top_k_learnings_step0 5 5 5 éléments Injection step 0 n/a Erreur de conformité
top_k_veille_step0 3 3 3 éléments Injection step 0 n/a Erreur de conformité
top_k_clarifications_step0 3 3 3 éléments Injection step 0 n/a Erreur de conformité
weight_nb_injections 0.4 0.4 0.4 ratio Scoring B3 n/a Erreur de conformité
weight_gate8_go 0.4 0.4 0.4 ratio Scoring B3 n/a Erreur de conformité
weight_nb_domains 0.2 0.2 0.2 ratio Scoring B3 n/a Erreur de conformité
promotion_threshold_domain 0.3 0.3 0.3 score Promotion B4 n/a Transition refusée
promotion_threshold_global 0.6 0.6 0.6 score Promotion B4 n/a Transition refusée
eviction_age 56 56 56 jours Éviction B4 n/a Transition refusée
ollama_timeout 30000 30000 30000 ms Appel local Ollama n/a Source en erreur (non bloquant)
embedding_dimension 768 768 768 dimensions nomic-embed-text n/a Indexation rejetée

Aucune exigence de performance percentile (P95/P99) n’est contractualisée pour PD-295.

5.3 SLA temporels (transitions d’état)

SLA Défaut Min Max Configurabilité Expiration / dépassement
learning_stale_window 56 jours 56 jours 56 jours Non configurable dans PD-295 Si âge > 56 jours ET nb_injections == 0: transition vers ARCHIVED

Aucune autre transition temporelle identifiée.

5.4 Flux nominal B1 — Index veille

  1. Lecture des fiches ProbatioVault-doc/docs/veille/**/*.md.
  2. Extraction frontmatter YAML + H1 + résumé.
  3. Production data/veille.jsonl conforme §5.1.
  4. Génération embeddings via Ollama nomic-embed-text (dimension 768).
  5. Construction index FAISS veille.
  6. Exposition recherche /veille-search avec filtres --impact et --verdict.

5.5 Flux nominal B2 — Clarifications persistées

  1. Recueil des 4 réponses PO du step 0.
  2. Écriture verbatim brut dans PD-XX-clarifications.md (dossier epic).
  3. Indexation dans data/clarifications.jsonl + index FAISS clarifications.
  4. Exposition recherche /clarifications avec filtres --domain et --project.
  5. Suppression manuelle possible par suppression du fichier clarification puis réindexation globale.

5.6 Flux nominal B3 — Scoring de réutilisation

  1. Lecture des injections (learnings-injections.jsonl).
  2. Calcul reuse_score par learning selon INV-295-05.
  3. Écriture dans data/learnings-scores.jsonl avec clé de jointure {story, gate, tags_hash}.
  4. Tri secondaire des résultats learnings par reuse_score décroissant.

5.7 Flux nominal B4 — Promotion et éviction

  1. Migration initiale: scope=story pour les learnings existants sans scope.
  2. Promotion vers domain à partir de reuse_score >= 0.3.
  3. Promotion vers global à partir de reuse_score >= 0.6.
  4. Éviction vers learnings-archive.jsonl si stale.
  5. Exclusion des learnings archivés de toute indexation active.

5.8 Flux nominal B5 — Injection unifiée step 0

  1. Récupération learnings pertinents (max 5), pondérés par reuse_score.
  2. Récupération fiches veille (max 3) avec impact_pv ∈ {fort, modere}.
  3. Récupération clarifications passées même domaine (max 3).
  4. Construction d’un bloc Markdown à 3 sections.
  5. Cas 0 résultat source: section affiche aucun résultat.
  6. Cas erreur source: section vide + stderr, sans blocage du step 0.

5.9 Machine à états et transitions retour (obligatoire)

État STORY_ACTIVE (scope story)

Transition sortante Statut Condition Comportement
→ DOMAIN_ACTIVE AUTORISÉE reuse_score >= 0.3 Données conservées, visibilité élargie au domaine
→ GLOBAL_ACTIVE INTERDITE n/a Rejet, scope inchangé
→ ARCHIVED AUTORISÉE stale §5.3 Déplacement archive, non indexé

État DOMAIN_ACTIVE (scope domain)

Transition sortante Statut Condition Comportement
→ STORY_ACTIVE INTERDITE n/a Rejet downgrade, données conservées, scope inchangé
→ GLOBAL_ACTIVE AUTORISÉE reuse_score >= 0.6 Données conservées, visibilité globale
→ ARCHIVED AUTORISÉE stale §5.3 Déplacement archive, non indexé

État GLOBAL_ACTIVE (scope global)

Transition sortante Statut Condition Comportement
→ STORY_ACTIVE INTERDITE n/a Rejet downgrade, scope inchangé
→ DOMAIN_ACTIVE INTERDITE n/a Rejet downgrade, scope inchangé
→ ARCHIVED AUTORISÉE stale §5.3 Déplacement archive, non indexé

État ARCHIVED (scope archived, terminal)

Transition sortante Statut Condition Comportement
→ * INTERDITE n/a état terminal, résolution manuelle uniquement

Aucune transition retour autorisée. Toutes les transitions retour sont explicitement interdites.

Checklist machine à états: - [x] Chaque état liste ses transitions sortantes autorisées et interdites. - [x] État terminal ARCHIVED documenté avec → * : INTERDITE. - [x] Invariants de transition dédiés en §4 (INV-295-TR-*).

5.10 Clauses obligatoires “non applicables”

  • Stratégie de migration DDL: non applicable (aucune base relationnelle, aucune modification de colonne SQL).
  • Atomicité multi-composant DB + queue/append-only: non applicable.
  • Mécanismes de protection distribuée: Aucun mécanisme de protection distribuée applicable (module synchrone mono-instance).
  • Contraintes inter-modules (routes cross-module): Aucune contrainte inter-module applicable.
  • Invariant envelope encryption crypto: non applicable (domaine tooling, non crypto/crypto-proof).

5bis. Diagrammes (si applicable)

Diagramme d’état (>= 3 états)

stateDiagram-v2
    [*] --> STORY_ACTIVE

    STORY_ACTIVE --> DOMAIN_ACTIVE : AUTORISEE (reuse_score >= 0.3)
    STORY_ACTIVE --> GLOBAL_ACTIVE : INTERDITE
    STORY_ACTIVE --> ARCHIVED : AUTORISEE (nb_injections==0 && age>56j)

    DOMAIN_ACTIVE --> STORY_ACTIVE : INTERDITE
    DOMAIN_ACTIVE --> GLOBAL_ACTIVE : AUTORISEE (reuse_score >= 0.6)
    DOMAIN_ACTIVE --> ARCHIVED : AUTORISEE (nb_injections==0 && age>56j)

    GLOBAL_ACTIVE --> STORY_ACTIVE : INTERDITE
    GLOBAL_ACTIVE --> DOMAIN_ACTIVE : INTERDITE
    GLOBAL_ACTIVE --> ARCHIVED : AUTORISEE (nb_injections==0 && age>56j)

    ARCHIVED --> STORY_ACTIVE : INTERDITE (etat terminal)
    ARCHIVED --> DOMAIN_ACTIVE : INTERDITE (etat terminal)
    ARCHIVED --> GLOBAL_ACTIVE : INTERDITE (etat terminal)

Diagramme de séquence (flow multi-services)

sequenceDiagram
    participant GOV as /gov-step-0
    participant LRN as Learnings Search
    participant VEI as Veille Search
    participant CLR as Clarifications Search
    participant OLL as Ollama embeddings
    participant FAI as FAISS index
    participant FS as JSONL/Markdown storage

    GOV->>LRN: query_text + domain + top_k=5
    LRN->>OLL: embed(query_text) -> float32[768]
    OLL-->>LRN: embedding[768]
    LRN->>FAI: knn_search(embedding, 5)
    FAI-->>LRN: hits[{story_id,gate,tags_hash,reuse_score}]
    LRN-->>GOV: learning_section_md

    GOV->>VEI: query_text + impact={fort,modere} + top_k=3
    VEI->>OLL: embed(query_text) -> float32[768]
    OLL-->>VEI: embedding[768]
    VEI->>FAI: knn_search(embedding, 3)
    FAI-->>VEI: hits[{title,impact_pv,verdict_veille,summary}]
    VEI-->>GOV: veille_section_md

    GOV->>CLR: domain + project + top_k=3
    CLR->>OLL: embed(domain+project) -> float32[768]
    OLL-->>CLR: embedding[768]
    CLR->>FAI: knn_search(embedding, 3)
    FAI-->>CLR: hits[{story_id,clarification_verbatim_excerpt}]
    CLR-->>GOV: clarification_section_md

    alt Source retourne 0 résultat
        LRN-->>GOV: []
        GOV->>GOV: section = "aucun résultat"
    else Source en erreur
        VEI-->>GOV: erreur technique
        GOV->>FS: log stderr(error)
        GOV->>GOV: section = vide
    end

    GOV-->>GOV: assemble bloc markdown 3 sections

6. Cas d’erreur

ID Cas Réponse attendue
ERR-295-01 Donnée invalide au format §5.1 Rejet de la ligne concernée, log stderr, poursuite du traitement global
ERR-295-02 Fichier veille invalide (frontmatter incomplet) Fiche ignorée, indexation continue
ERR-295-03 learnings-injections.jsonl absent/inaccessible Scoring exécuté avec corpus disponible, score absent traité comme 0, log stderr
ERR-295-04 Échec Ollama (timeout/indisponible) pour une source Section concernée vide, log stderr, step 0 non bloqué
ERR-295-05 Index FAISS source absent/corrompu Section concernée vide, log stderr, step 0 non bloqué
ERR-295-06 Source valide mais aucun résultat Section affiche aucun résultat
ERR-295-07 Transition d’état interdite (scope) Refus de transition, scope inchangé, log stderr
ERR-295-08 Valeur numérique hors bornes §5.2 Erreur de conformité contractuelle (test KO)
ERR-295-09 Impossible d’écrire PD-XX-clarifications.md Erreur stderr, step 0 continue sans clarification persistée
ERR-295-10 Jointure {story,gate,tags_hash} impossible Learning exclu du calcul de score/promotion

7. Critères d’acceptation (testables)

ID Critère Observable
CA-295-01 B1 génère veille.jsonl à partir des fiches valides Nombre de lignes veille.jsonl = nombre de fiches valides parsées
CA-295-02 Les champs veille suivent §5.1 Validation regex/enums sans erreur
CA-295-03 B2 persiste verbatim brut des 4 réponses PO PD-XX-clarifications.md contient les 4 réponses non résumées
CA-295-04 B2 indexe les clarifications clarifications.jsonl et index FAISS clarifications présents
CA-295-05 B3 calcule reuse_score exact Dataset de test: score obtenu = formule INV-295-05
CA-295-06 Jointure scoring via {story,gate,tags_hash} Chaque ligne score pointe exactement 1 learning cible
CA-295-07 Tri secondaire par reuse_score actif À similarité égale, résultat au score plus élevé classé avant
CA-295-08 Migration B4 affecte scope: story aux entrées historiques 100% des entrées sans scope deviennent story
CA-295-09 Promotion domain/global respecte seuils 0.3/0.6 Tests seuils stricts passent/échouent correctement
CA-295-10 Éviction stale respecte règle 56 jours + nb_injections==0 Un learning stale est archivé; un learning non stale ne l’est pas
CA-295-11 L’archive n’est plus indexée Entrée archivée absente des résultats d’injection
CA-295-12 B5 produit exactement 3 sections (5/3/3 max) Bloc Markdown contient 3 sections avec cardinalités contractuelles
CA-295-13 0 résultat source ne bloque pas Section affiche aucun résultat, step 0 continue
CA-295-14 Erreur source ne bloque pas Section vide + log stderr + step 0 continue
CA-295-15 Transitions retour interdites sont refusées Tentative downgrade rejetée, scope inchangé
CA-295-16 État terminal ARCHIVED interdit toute sortie Toute transition sortante depuis ARCHIVED échoue
CA-295-17 Stack section 10 conforme au projet cible Mention explicite Python/FAISS/Ollama/Markdown/YAML, absence de Swift/Spring

8. Scénarios de test (Given / When / Then)

ID Given When Then
ST-295-01 Corpus veille valide présent L’indexation B1 est lancée veille.jsonl + index FAISS veille sont produits
ST-295-02 Une fiche veille avec frontmatter invalide B1 traite le corpus La fiche est ignorée, le reste est indexé
ST-295-03 Step 0 avec 4 réponses PO B2 s’exécute PD-XX-clarifications.md contient le verbatim brut
ST-295-04 Historique injections connu B3 calcule les scores reuse_score est conforme à la formule
ST-295-05 Learning scope=story, score=0.31 B4 applique promotion scope devient domain
ST-295-06 Learning scope=domain Une transition domain→story est demandée Transition refusée, scope inchangé
ST-295-07 Learning scope=global, nb_injections=0, âge=57 jours B4 applique éviction Learning déplacé en archive
ST-295-08 3 sources disponibles B5 injecte au step 0 Bloc Markdown 3 sections produit
ST-295-09 Source clarifications retourne 0 hit B5 injecte Section clarifications affiche aucun résultat
ST-295-10 Ollama indisponible pour la veille B5 injecte Section veille vide + erreur stderr, step 0 continue
ST-295-11 Learning scope=archived Une transition sortante est demandée Refus systématique (ARCHIVED terminal)
ST-295-12 Période post-merge de 3 mois écoulée analyze-compounding.py est exécuté CS-2/CS-3/CS-4 mesurables et historisés

9. Hypothèses explicites

ID Hypothèse Impact si faux
H-295-01 Usage mono-utilisateur, mono-instance active à un instant donné Risque d’écritures concurrentes non couvertes par PD-295
H-295-02 Le contexte step 0 fournit story_id, domain, project Filtrage clarifications et injection ciblée impossibles
H-295-03 Les fiches veille contiennent frontmatter YAML exploitable B1 ne peut pas construire veille.jsonl complet
H-295-04 learnings-injections.jsonl peut être vide au démarrage reuse_score initial faible, promotions retardées
H-295-05 Les KPI CS-1..CS-4 sont évalués hors Gate 8 Aucun blocage de livraison si KPI non atteints immédiatement
H-295-06 Les règles non testables ne sont pas admises dans PD-295 Toute règle ambiguë doit être déplacée en point à clarifier

10. Points à clarifier

10.1 Contraintes techniques (stack cible contractuelle)

Domaine Contrainte contractuelle
Langage d’automatisation Python 3 (scripts CLI)
Recherche vectorielle FAISS (faiss-cpu)
Embeddings Ollama local, modèle nomic-embed-text, dimension 768
Formats documentaires Markdown + frontmatter YAML
Formats de persistance JSONL, .faiss, .npy, Markdown
Environnements Laptop macOS et IA-Server Linux
Politique de changement Aucune migration de moteur, aucune refonte stack

10.2 Questions en suspens

ID Point à clarifier Impact
Q-295-01 Référence épique: valeur absente du besoin (Référence épique vide) Référence documentaire incomplète
Q-295-02 Baseline exacte de CS-1 (fenêtre historique de comparaison) KPI CS-1 potentiellement non reproductible
Q-295-03 Politique de tie-break final si similarité et reuse_score sont égaux Ordre de résultats potentiellement non déterministe
Q-295-04 Confirmation explicite que ARCHIVED reste terminal sans restauration en PD-295 Risque d’attente fonctionnelle non couverte
Q-295-05 Placeholder learnings contextuels ({{LEARNINGS}}) non renseigné Aucun enrichissement contextuel additionnel injecté dans cette spec

Références

  • Epic : Non communiqué (champ “Référence épique” vide au 2026-04-12)
  • JIRA : PD-295
  • Repos concernés : ProbatioVault-ia-governance, ProbatioVault-doc
  • Documents associés : docs/epics/tooling/PD-295-memoire-vivante-5-briques/PD-295-besoin.md, templates/outputs/PD-XX-specification.md