PD-295 — Review de spécification (Gate 3)¶
Auditeur indépendant. Aucune correction proposée. Aucune reformulation. Aucune implémentation.
Documents audités : - PD-295-specification.md - PD-295-tests.md (audit limité aux ambiguïtés/contradictions/non-testabilités/risques, sans verdict de couverture)
Synthèse des écarts¶
| # | Type | Référence | Gravité |
|---|---|---|---|
| 1 | Contradiction | INV-295-07 vs §5.1.4 (reuse_score) | Bloquant |
| 2 | Contradiction | ERR-295-10 vs §5.12 (clé idempotence) | Bloquant |
| 3 | Non testable | CA-295-20 / INV-295-17 (CS-1 baseline non figée) | Bloquant |
| 4 | Ambiguïté | INV-295-09 (nb_domains non défini) | Majeur |
| 5 | Incohérence Spec↔Tests | ST-295-07 vs INV-295-07 | Majeur |
| 6 | Contradiction | INV-295-04 (Ringbearer-only) vs INV-295-05 / CA-295-05 | Majeur |
| 7 | Non testable | CA-295-17, CA-295-18, CA-295-19 | Majeur |
| 8 | Ambiguïté | Q-295-02 / CA-295-13 (cardinalité clarifications B5) | Majeur |
| 9 | Contradiction | Q-295-06 — /morning "optionnel" vs "intégration" | Majeur |
| 10 | Hypothèse dangereuse | §5.12 — scope du lock vs B5 (race read/write) | Majeur |
| 11 | Ambiguïté | §5.7 step 4 — couplage tri par reuse_score ↔ fichier parallèle | Majeur |
| 12 | Non testable | TC-ERR-04 ne couvre qu'--domain (pas --project) | Mineur |
| 13 | Hypothèse dangereuse | §5.12 réconciliation — exécutant non spécifié | Mineur |
| 14 | Ambiguïté | §5.6 — fenêtre d'indexation des clarifications nouvelles | Mineur |
| 15 | Ambiguïté | §5.12 — query_hash non défini comme champ persistant | Mineur |
| 16 | Risque sécu/conformité | Clarifications PO — rétention/anonymisation non définies (Q-295-04) | Mineur |
| 17 | Hypothèse dangereuse | H-295-06 — bloc {{LEARNINGS}} "considéré vide" dans la spec elle-même | Mineur |
1. Contradiction — Formule reuse_score vs bornes du champ persisté¶
Type : Contradiction
Référence : INV-295-07, §5.1.4 (`data/learnings-scores.jsonl`.`reuse_score`),
§5.2 (`score_weight_sum=1.00`), CA-295-08, TC-NOM-08
Description : INV-295-07 définit reuse_score = 0.4*nb_injections
+ 0.4*nb_stories_gate8_go_apres_injection
+ 0.2*nb_domains_distincts. Les trois opérandes sont des
entiers non bornés (§5.1.4 : `nb_injections` 0..1e9,
`nb_stories_gate8_go_apres_injection` 0..1e9,
`nb_domains_distincts` 0..1e6). La somme pondérée produit
donc des valeurs potentiellement >> 1. Or §5.1.4 contraint
`reuse_score` au domaine `0.00..1.00` ("Comportement si
invalide : Ligne exclue + log erreur"). Aucune normalisation
(max-scaling, log, division par référentiel) n'est spécifiée.
Conséquence directe : pour tout learning ayant ne serait-ce
que `nb_injections=3`, le score brut dépasse 1 et la ligne
doit être exclue par sa propre validation de format.
Impact : (a) la formule contractuelle est mathématiquement
incompatible avec son propre format de stockage ; (b) les
seuils de promotion 0.30/0.60 (INV-295-09) deviennent
incohérents ; (c) TC-NOM-08 ne peut pas passer sans choisir
implicitement une convention non spécifiée.
Gravité : Bloquant
2. Contradiction — Clé d'idempotence vs comportement de rejeu différent¶
Type : Contradiction
Référence : ERR-295-10, TC-ERR-10, §5.12 ("Clé `story_id:step:source:query_hash`")
Description : §5.12 définit la clé d'idempotence comme incluant
`query_hash`. ERR-295-10 et TC-ERR-10 décrivent un cas de
"rejeu idempotence avec payload différent" devant être
rejeté en conflit. Or si le payload diffère, son hash
diffère, donc la clé composée diffère, donc il s'agit d'une
nouvelle entrée et non d'un rejeu : aucun conflit ne peut
survenir avec la définition donnée. Le critère de
déclenchement de ERR-295-10 est inatteignable.
Impact : Cas d'erreur contractuel non observable. TC-ERR-10 ne peut
pas être implémenté de manière déterministe.
Gravité : Bloquant
3. Règle non testable — CS-1 baseline non figée¶
Type : Non testable
Référence : CA-295-20, INV-295-17, Q-295-05, TC-NOM-24
Description : CA-295-20 exige une "amélioration Gate 8 GO v1 vs baseline
gelée". Q-295-05 reconnaît que la fenêtre baseline avant/
après B5 n'est pas contractualisée. Sans bornes temporelles
officielles ni définition de la métrique de comparaison
(delta absolu, ratio, seuil de significativité), aucun
verdict binaire reproductible n'est possible. La spec se
renvoie elle-même à une question ouverte pour un critère
d'acceptation.
Impact : Critère d'acceptation non vérifiable en l'état. Le verdict
Gate 8 sur ce CA est arbitraire.
Gravité : Bloquant
4. Ambiguïté — nb_domains dans INV-295-09¶
Type : Ambiguïté
Référence : INV-295-09, INV-295-07 (`nb_domains_distincts`), §5.4
Description : INV-295-09 utilise `nb_domains` comme condition de
promotion (`>=1` puis `>=2`). Le terme n'est défini nulle
part : s'agit-il du nombre de domaines distincts dans
lesquels le learning a été injecté, du nombre de domaines
distincts ayant produit Gate 8 GO après injection, ou du
nombre de domaines référencés dans `tags[]` ? §5.1.4
utilise `nb_domains_distincts` sans préciser non plus la
source. Pour un learning `scope=story` rattaché à un seul
domaine d'origine, `nb_domains>=1` est trivialement vrai et
la promotion `story->domain` se réduit à `reuse_score>=0.30`.
Impact : Règle de promotion non déterministe. TC-NOM-11 ("aux
frontières de seuil ... domaines contrôlés") ne peut pas
fixer un jeu de fixtures sans interpréter la définition.
Gravité : Majeur
5. Incohérence Spec↔Tests — ST-295-07 vs formule reuse_score¶
Type : Incohérence Spec↔Tests
Référence : ST-295-07 (PD-295-tests.md §3 implicite via TC-NOM-11),
ST-295-07 (PD-295-specification.md §8), INV-295-07
Description : ST-295-07 affirme : "Given un learning story avec
reuse_score=0.30 et nb_domains=1, When promotion B4, Then
état devient DOMAIN_ACTIVE." Aucun jeu d'entrées
(nb_injections, nb_stories_gate8_go, nb_domains_distincts)
ne permet d'obtenir simultanément reuse_score=0.30 ET
nb_domains=1 sans choisir une convention de normalisation
non spécifiée (cf. écart #1). Le test est sous-spécifié.
Impact : Le test ne peut pas être réalisé sans hypothèse implicite ;
deux implémentations conformes peuvent diverger sur le
verdict.
Gravité : Majeur
6. Contradiction — INV-295-04 conditionne la persistance au mode Ringbearer¶
Type : Contradiction
Référence : INV-295-04 vs INV-295-05, CA-295-04, CA-295-05, TC-NOM-04, TC-NOM-05
Description : INV-295-04 stipule que "en mode Ringbearer" les
clarifications sont persistées avant reprise. INV-295-05
(verbatim) et CA-295-04/CA-295-05 ne sont pas conditionnés
au mode. Statut en mode local : la persistance verbatim
est-elle obligatoire ou facultative ? Les tests TC-NOM-04
et TC-NOM-05 reprennent un préambule "step 0 Ringbearer"
comme s'il était la seule modalité.
Impact : Soit la spec laisse un trou de couverture pour le mode
local (B2 inopérante hors Ringbearer), soit l'invariant
INV-295-04 est mal scopé. La machine d'états des
clarifications est sous-spécifiée hors Ringbearer.
Gravité : Majeur
7. Règles non testables — KPIs CS-2/CS-3/CS-4¶
Type : Non testable
Référence : CA-295-17, CA-295-18, CA-295-19, INV-295-17, TC-NOM-21..23
Description : Trois critères d'acceptation reposent sur un horizon
temporel post-déploiement (2-3 mois, mensuel, "5 premières
stories post-B5") qui n'est pas vérifiable au moment de la
recette de PD-295. La spec confirme cet état (Verdict QA
"testable partiellement") mais maintient ces points dans
les critères d'acceptation contractuels au lieu de les
déplacer en KPIs post-livraison ou en jalons de
vérification différée explicites.
Impact : Trois CA non vérifiables au moment du Gate 8 nominal de
PD-295. Risque de fermeture artificielle.
Gravité : Majeur
8. Ambiguïté — Cardinalité des clarifications injectées en B5¶
Type : Ambiguïté
Référence : Q-295-02, CA-295-13, INV-295-12, TC-NOM-13
Description : INV-295-12 et CA-295-13 figent la cardinalité des
learnings (5) et de la veille (3) injectés en B5, mais
laissent celle des clarifications non spécifiée. TC-NOM-13
ne peut donc vérifier que la présence de la section, pas
sa borne. La spec elle-même renvoie à Q-295-02 (question
ouverte) pour un comportement injecté en production.
Impact : Comportement d'injection non déterministe sur une des
trois sources. Verdict Gate 8 sur INV-295-12 incomplet.
Gravité : Majeur
9. Contradiction — /morning optionnel vs intégré¶
Type : Contradiction
Référence : Q-295-06, CA-295-19 implicite, §5.2 (`morning_top_reused=3`),
§5.7 step 6
Description : §5.7 step 6 et §5.2 fixent une borne `morning_top_reused=3`
comme paramètre obligatoire (`Min=Max=3`, "Rejet
exécution"), ce qui suppose une intégration `/morning`
effective. Q-295-06 reconnaît que le besoin oscille entre
"optionnel" et "intégration". L'invariant correspondant
n'existe pas (aucun INV-295-* ne contractualise
`/morning`).
Impact : Hauteur d'engagement contractuel indéterminée. Si
optionnel, `morning_top_reused` ne devrait pas avoir un
défaut "rejet exécution". Si obligatoire, un invariant
dédié manque.
Gravité : Majeur
10. Hypothèse dangereuse — Scope du lock B4 vs lectures B5¶
Type : Hypothèse dangereuse
Référence : §5.12 ("Scope global sur ressources mutables B4"),
§5.9 (B5 lit learnings + scores), INV-295-18
Description : Le lock contractuel n'est défini que sur les opérations
mutantes de B4 (`learnings.jsonl`,
`learnings-archive.jsonl`, index actifs). B5 lit ces
mêmes ressources en parallèle au step 0. Aucune garantie
d'isolation lecteur/écrivain (snapshot, lock partagé,
version stamping) n'est spécifiée. Lecture pendant
promotion/éviction/réindexation peut produire une
injection sur un index incohérent ou amputé.
Impact : Race condition silencieuse côté B5. Aucun observable
contractuel ne la détecte ; aucun test ne la couvre
(TC-NOM-17..20 testent uniquement écrivain vs écrivain).
Gravité : Majeur
11. Ambiguïté — Couplage du tri sur reuse_score parallèle¶
Type : Ambiguïté
Référence : §5.7 step 4, INV-295-06, §5.1.4
Description : INV-295-06 impose que B3 écrive `learnings-scores.jsonl`
en fichier parallèle SANS modifier `learnings.jsonl`.
§5.7 step 4 exige un tri secondaire par `reuse_score`
côté recherche. Le mécanisme de jonction (clé de jointure
entre une ligne de `learnings.jsonl` et une ligne de
`learnings-scores.jsonl`) n'est pas spécifié : `story` et
`gate` (§5.1.4) ne suffisent pas à identifier un learning
individuel si plusieurs learnings sont produits par la
même story/gate.
Impact : Tri secondaire non implémentable de manière déterministe.
Test TC-NOM-09 sous-spécifié.
Gravité : Majeur
12. Couverture insuffisante — TC-ERR-04 ne teste qu'un argument manquant¶
Type : Incohérence Spec↔Tests
Référence : INV-295-14, CA-295-06, ERR-295-04, TC-ERR-04, ST-295-04
Description : INV-295-14 exige `--domain` ET `--project`. TC-ERR-04 et
ST-295-04 ne testent que l'absence de `--domain`. Le cas
"absence de `--project`" et le cas "les deux absents" ne
sont pas couverts.
Impact : L'invariant n'est que partiellement observable.
Gravité : Mineur
13. Hypothèse dangereuse — Exécutant de la réconciliation non spécifié¶
Type : Hypothèse dangereuse
Référence : §5.12 ("Réconciliation : Intervalle 5 min"), TC-NOM-20
Description : Le mécanisme de déclenchement périodique de la
réconciliation (cron, daemon, hook step 0, job manuel)
n'est pas spécifié. La spec présume l'existence d'un
ordonnanceur externe sans le contractualiser. TC-NOM-20
dépend donc d'un composant non couvert par PD-295.
Impact : INV-295-18 partiellement reposé sur une infrastructure
hors périmètre. Risque d'illusion de couverture.
Gravité : Mineur
14. Ambiguïté — Indexation incrémentale des clarifications¶
Type : Ambiguïté
Référence : §5.6 step 4, INV-295-15, ERR-295-05
Description : §5.6 dit "Indexer le corpus clarifications" sans préciser
si l'indexation est continue, batch (déclenchée par
`reindex-all`), ou hookée step 0. Entre deux exécutions
de `reindex-all`, les nouvelles clarifications produites
par d'autres stories ne sont pas interrogeables. La spec
n'expose pas explicitement cette latence.
Impact : Comportement temporel des recherches B5 non déterministe.
Gravité : Mineur
15. Ambiguïté — query_hash non défini comme champ¶
Type : Ambiguïté
Référence : §5.12 ("Clé `story_id:step:source:query_hash`"), §5.1.6
Description : `query_hash` est utilisé comme composant de clé
d'idempotence mais n'apparaît pas dans le schéma de
`learnings-injections.jsonl` (§5.1.6 ne liste que `query`
brut, 1..500 UTF-8). L'algorithme de hash (SHA-256,
FNV...), sa normalisation pré-hash (lowercase, NFKC,
trim) et son lieu de persistance ne sont pas spécifiés.
Impact : Vérification d'idempotence non reproductible.
Gravité : Mineur
16. Risque sécu/conformité — Rétention et anonymisation des clarifications¶
Type : Risque sécu/conformité
Référence : Q-295-04, INV-295-05 (verbatim), §5.6
Description : La spec impose la persistance verbatim de réponses PO et
l'indexation cross-projets, mais reconnaît (Q-295-04) que
la durée de conservation et l'anonymisation ne sont pas
définies. Verbatim cross-projet sans politique de
rétention expose à un risque RGPD si une réponse PO
contient une donnée personnelle ou un secret.
Impact : Trou de conformité documentaire. Aucun cas d'erreur
contractuel ne couvre la suppression sur demande.
Gravité : Mineur
17. Hypothèse dangereuse — Auto-relativisation de la spec¶
Type : Hypothèse dangereuse
Référence : H-295-06 ("Le bloc {{LEARNINGS}} contextuel n'est pas
injecté ... considéré vide")
Description : La spec contractuelle déclare elle-même comme hypothèse
que son propre mécanisme de contexte historique est
désactivé pour la story qui le définit. Ce n'est pas une
hypothèse fonctionnelle sur l'environnement cible mais un
aveu méta sur la rédaction du document. Sa place dans
§9 (hypothèses fonctionnelles) introduit une confusion
entre cadrage produit et conditions de rédaction.
Impact : Lisibilité contractuelle dégradée ; risque que le
relecteur considère que l'absence de learnings injectés
au step 0 est admise en run.
Gravité : Mineur
Cohérence des diagrammes (axe 5bis)¶
Diagramme d'état (§5bis)¶
Les transitions du diagramme correspondent intégralement à §5.4 et à INV-295-09 / INV-295-10 / INV-295-11. Les transitions interdites sont toutes représentées explicitement avec leur libellé "INTERDITE". Aucun écart détecté sur cet axe.
Diagramme de séquence (§5bis)¶
Les trois sources (learning, veille, clarification) sont tracées en parallèle avec leurs filtres et leurs traces. Format des vecteurs explicite (vector[768]). Un point reste implicite : la jonction learnings.jsonl ↔ learnings-scores.jsonl (cf. écart #11) n'apparaît ni sur le diagramme ni dans le pseudo-code (tri(distance,reuse_score) est posé comme primitive sans clé de jointure). Ce point est déjà remonté en écart Majeur au §11 ci-dessus, le diagramme reflète fidèlement la spec sans introduire d'incohérence supplémentaire.
Verdict de revue¶
Spécification globalement structurée et testable, mais comportant 3 écarts Bloquants (formule reuse_score incompatible avec son propre format de stockage, clé d'idempotence rendant ERR-295-10 inatteignable, CA-295-20 non testable par renvoi à une question ouverte) qui empêchent en l'état la production d'une implémentation déterministe et l'émission d'un verdict Gate 8 reproductible.
Les écarts Majeurs (8) portent essentiellement sur des trous de définition (nb_domains, cardinalité clarifications B5, scope du lock B4 vs lectures B5, jonction de tri sur fichier parallèle) et sur des CA dont l'horizon temporel sort du périmètre de recette de PD-295 (CS-2/CS-3/CS-4).