Aller au contenu

PD-295 — Revue de spécification (Gate 3)

Auditeur : rôle contractuel indépendant. Portée : PD-295-specification.md (contractuel) + PD-295-tests.md (limité aux risques contractuels, sans conclure sur la couverture).


Écart 1

Type : Ambiguïté Référence : spec §5.1 D-295-08 reuse_score + §5.2 weight_* + §4 INV-295-05 + §5.6 Description : Le reuse_score est déclaré comme « Nombre décimal JSON » dans l’intervalle 0.0000..999999.9999, tandis que §5.2 qualifie les coefficients de « ratio » figés à 0.4/0.4/0.2. Or la formule INV-295-05 applique ces coefficients à des comptes bruts (nb_injections, nb_stories_gate8_go_apres_injection, nb_domains_distincts), bornés respectivement à 999999, 999999 et 2048 (D-295-09..11). Le résultat n’est donc ni un ratio (∈ [0,1]) ni un score normalisé : c’est une somme pondérée non bornée. Le vocabulaire « ratio »/« score » est incohérent avec la sémantique réelle de la valeur. Impact : Rend ambiguë la comparaison avec les seuils de promotion 0.3 et 0.6 (INV-295-09/10). Avec la formule actuelle, un seul nb_injections=1 produit reuse_score = 0.4, ce qui franchit immédiatement le seuil story→domain : le scénario TC-NOM-05 confirme d’ailleurs des scores de 1.0 et 1.8 (très au-dessus de 0.6 = promotion globale), alors que les seuils sont probablement pensés pour un score normalisé. Gravité : Majeur


Écart 2

Type : Contradiction Référence : spec §5.5 (flux B2 clarifications) vs §5bis (diagramme de séquence, branche CLR) Description : §5.5 spécifie la recherche clarifications via « filtres --domain et --project » (sélection structurée), sans recherche sémantique. Le diagramme de séquence §5bis modélise au contraire un appel CLR → OLL: embed(domain+project) puis FAI: knn_search(embedding, 3) (recherche vectorielle). Les deux mécanismes sont incompatibles (filtrage exact vs KNN). Impact : Mécanisme de récupération des clarifications sous-déterminé — impossible de contractualiser top_k_clarifications_step0=3 sans savoir s’il s’agit d’un TOP-K sémantique ou d’une limite de pagination sur filtre exact. Impact direct sur CA-295-04 et INV-295-04. Gravité : Majeur


Écart 3

Type : Ambiguïté Référence : spec §5.1 D-295-06 tags_hash + INV-295-06 Description : tags_hash est défini comme hex SHA-256 lowercase de 64 caractères, mais le procédé de canonicalisation (tri des tags ? séparateur ? normalisation Unicode ? inclusion du # initial ?) n’est pas spécifié. INV-295-06 exige pourtant une jointure déterministe {story, gate, tags_hash} entre learnings.jsonl et learnings-scores.jsonl. Impact : Deux producteurs implémentant la canonicalisation différemment généreront des hash divergents pour les mêmes tags → jointure impossible (ERR-295-10), learnings silencieusement exclus du scoring. Gravité : Majeur


Écart 4

Type : Non testable Référence : spec §5.1 D-295-04 project (Enum) Description : project est typé « Enum » dans la colonne Format mais la liste des valeurs autorisées n’est donnée nulle part dans la spécification (aucune énumération §3 ni §10.1). Le document de tests §9 signale déjà cette non-testabilité. Impact : Validation contractuelle de project impossible ; impossible de contrôler la règle CA-295-04 « recherche /clarifications --project » sans liste de valeurs de référence. Gravité : Majeur


Écart 5

Type : Ambiguïté Référence : spec §5.1 (schéma D-295 global) vs §5.4/§5.5 (flux B1/B2) Description : Le tableau §5.1 est présenté comme « source unique des formats » mais ne précise pas quels champs D-295-XX appartiennent à quel artefact (veille.jsonl, clarifications.jsonl, learnings-scores.jsonl). Les flux §5.4 à §5.8 mentionnent des champs (title, summary, clarification_verbatim_excerpt, …) sans renvoi explicite vers §5.1, et §5.1 omet des champs apparaissant dans le diagramme de séquence (title, summary, excerpt). Impact : Empêche TC-NOM-02 (« 100% des lignes passent les contraintes D-295 applicables à la veille ») d’être déterministe, la liste des « contraintes applicables » n’étant pas contractualisée. Incohérence Spec↔Tests. Gravité : Majeur


Écart 6

Type : Hypothèse dangereuse Référence : spec §9 H-295-01 (mono-user, mono-instance) + §5.⅘.5/5.6/5.7 (écritures JSONL) Description : La spec suppose mono-instance sans contractualiser aucune primitive d’écriture atomique (append-only garanti ? fsync ? lock fichier ? rename atomique ?). Les flux B1, B3, B4 réécrivent/mutent veille.jsonl, learnings-scores.jsonl, learnings.jsonl, learnings-archive.jsonl en parallèle d’un step 0 en cours de lecture. Impact : Si l’hypothèse est violée (exécution concurrente d’un second /gov-step-0, d’un cron d’indexation, ou d’une relance après crash), corruption silencieuse de JSONL possible (lignes tronquées, doublons, perte de l’archive). Aucun test ne couvre ce risque et aucun invariant (ex. rename atomique) n’est posé. Gravité : Majeur


Écart 7

Type : Non testable Référence : spec §5.7 (migration initiale B4) + INV-295-08 Description : La migration « 100% des entrées sans scope deviennent story » (INV-295-08, CA-295-08) n’a ni déclencheur contractuel (automatique au premier run ? commande dédiée ?), ni propriété d’idempotence, ni critère d’achèvement. La date de migration n’est pas persistée. Impact : Rejouer la migration sur un corpus déjà migré a un comportement non spécifié (écraser scope existant ? No-op ?). Impossible de scripter une vérification d’achèvement post-déploiement. Gravité : Mineur


Écart 8

Type : Incohérence Spec↔Tests Référence : spec §4 INV-295-13 (« cardinalités cibles 5/3/3 ») vs §5.2 top_k_*_step0 (« Min=Max=5/3/3 ») vs §5.8/CA-295-12 Description : INV-295-13 parle de « cardinalités cibles », §5.2 fige les top_k en min=max=valeur, CA-295-12 et TC-NOM-12 interprètent comme « cardinalités effectives limitées à 5/3/3 max ». Le vocable « cible » vs « max » vs « exact » n’est pas homogène. Impact : En cas de source retournant moins que top_k (sans être à 0), le test TC-NOM-12 ne dit pas si la cardinalité doit valoir le minimum disponible ou si c’est une erreur contractuelle. Gravité : Mineur


Écart 9

Type : Contradiction Référence : spec §6 ERR-295-03 (« score absent traité comme 0 ») vs §4 INV-295-05/07 Description : ERR-295-03 indique qu’en cas d’absence de learnings-injections.jsonl, un learning sans historique est traité « score absent équivalent à 0 en usage aval ». Mais INV-295-05 ne définit aucune valeur par défaut quand learnings-scores.jsonl n’a pas de ligne pour un learning donné, et INV-295-07 (tri secondaire) ne précise pas comment ordonner un score null vs un score numérique. TC-ERR-03 reproduit cette imprécision sans la lever. Impact : Comportement de tri indéterministe sur un learning non scoré : selon l’implémentation, il peut apparaître en tête (null < tout) ou en queue (null = 0 strict). Gravité : Mineur


Écart 10

Type : Risque sécurité/conformité Référence : spec §4 INV-295-03 + §5.1 D-295-16 clarification_verbatim + §2 (périmètre exclu : filtre PII, purge RGPD) Description : Le verbatim PO brut (jusqu’à 20 000 caractères) est persisté en Markdown et indexé vectoriellement, sans filtre PII et sans procédure de purge, explicitement hors périmètre. Même en usage interne mono-utilisateur (H-295-01), la spec ne documente aucun moyen de suppression ciblée (§5.5 mentionne uniquement « suppression manuelle par suppression du fichier clarification puis réindexation globale »), ce qui empêche toute révocation granulaire d’un contenu sensible persistant dans les embeddings et clarifications.jsonl. Impact : Auditabilité RGPD dégradée — une demande de suppression d’un verbatim spécifique impose une réindexation globale non contractualisée (durée, atomicité, concurrence avec step 0 en cours). Gravité : Mineur


Écart 11

Type : Incohérence Spec↔Tests Référence : spec §5.8 étape 2 (« fiches veille avec impact_pv ∈ {fort, modere} ») vs §7 CA-295-12 + TC-NOM-12 Description : Le filtre impact_pv ∈ {fort, modere} appliqué à la source veille pour l’injection B5 est normatif en §5.8 mais n’est couvert par aucun critère d’acceptation ni scénario de test (aucun TC-NOM n’isole une fiche impact_pv=faible pour vérifier qu’elle est exclue de l’injection). Impact : Une implémentation qui oublierait le filtre impact_pv ne serait détectée par aucun test contractuel ; régression silencieuse possible. Gravité : Majeur


Écart 12

Type : Ambiguïté Référence : spec §5.5 étape 2 (écriture verbatim) + §5.1 D-295-15 clarification_filename Description : La regex ^PD-[0-9]{1,4}-clarifications\.md$ fixe le format du nom de fichier mais la spec n’indique pas le comportement en cas de ré-exécution du step 0 pour la même story (écrasement ? append ? erreur ?). Les 4 réponses PO peuvent légitimement évoluer si la story est relancée, mais aucun invariant ne le couvre. Impact : Comportement de ré-entrée non spécifié → possible perte de verbatim historique ou, à l’inverse, duplication non déduplicable. Gravité : Mineur


Écart 13

Type : Non testable Référence : spec §10.2 Q-295-03 (tie-break) Description : La politique de départage lorsque similarité ET reuse_score sont strictement égaux n’est pas contractualisée (déjà identifié par l’auteur comme question ouverte). INV-295-07 ne parle que de « tri secondaire ». Impact : Ordre des résultats d’injection non reproductible → CS-1..CS-4 potentiellement non reproductibles bench-à-bench (cf. H-295-05). Gravité : Mineur


Écart 14

Type : Hypothèse dangereuse Référence : spec §4 INV-295-11 + §5.3 (learning_stale_window) + §5.7 étape 4 Description : L’éviction s’appuie sur « âge > 56 jours » mais la spec ne définit pas la base de calcul de l’âge (champ date D-295-12 = date de création ? dernière modification ? dernière injection ?). Le D-295-12 dit seulement « Date ISO » sans sémantique. Impact : Éviction appliquée sur un référentiel de date incorrect peut archiver prématurément ou indéfiniment conserver des learnings stale. CA-295-10 et TC-NOM-10 ne lèvent pas l’ambiguïté (ils supposent un « age » précalculé par la fixture). Gravité : Majeur


Synthèse

Gravité Nombre
Bloquant 0
Majeur 8 (Écarts 1, 2, 3, 4, 5, 6, 11, 14)
Mineur 6 (Écarts 7, 8, 9, 10, 12, 13)

Aucune correction ni reformulation n’est proposée, conformément au cadre Gate 3.