Aller au contenu

Je procède à l'audit de la spécification PD-293 et des tests associés.

PD-293 — Specification Review

Écarts identifiés


1. Contradiction entre INV-293-07 et le protocole de messagerie

Type : Contradiction Référence : INV-293-07, §5.1 (message_type), §5.3 (flux métier), H-293-04 Description : INV-293-07 déclare « Le workflow /gov est consommé tel quel ; PD-293 ne modifie pas son comportement interne ». Or le protocole §5.1 exige que le Ringbearer émette des messages typés (STATUS_UPDATE, ESCALADE, GATE_RESULT, WORKFLOW_DONE) via le broker. Le workflow /gov actuel ne produit aucun de ces messages. H-293-04 reconnaît cette tension ("Le protocole messages requis est supporté par les peers sans adaptation de /gov") mais la formule comme hypothèse alors qu'elle contredit directement INV-293-07. Soit /gov doit être adapté (violation INV-293-07), soit un composant intermédiaire (wrapper, hook, intercepteur) doit exister — et ce composant n'est spécifié nulle part. Impact : Le flux nominal complet (escalades, gate results, workflow done) est inapplicable sans résolution de cette contradiction. Gravité : Bloquant


2. Schema JSON .gov-lord-state.json : peer_id obligatoire en état STARTING

Type : Contradiction Référence : §5.4 (schema JSON), §5.2 (machine d'états STARTING) Description : Le schema §5.4 déclare peer_id comme required avec minLength: 1 pour chaque entrée story. Or en état STARTING, le peer n'est pas encore enregistré au broker — le peer_id est inconnu. Le schema ne permet ni null ni chaîne vide pour ce champ, rendant impossible la persistance d'une story en STARTING sans violer le schema. Impact : Toute story créée par start ne peut être persistée conformément au schema avant détection du peer. Gravité : Bloquant


3. Garde "story déjà active" absente de l'ordre contractuel des gardes start

Type : Contradiction Référence : §5.1 (règles globales normatives, point 3), ERR-293-02, TC-ERR-02 Description : L'ordre contractuel des gardes pour start est défini comme « quota → doublon idempotence → validation format complète » (§5.1 point 3). ERR-293-02 spécifie le rejet d'un start sur une story déjà active. Or cette vérification n'apparaît dans aucune position de l'ordre des gardes. TC-ERR-02 teste ce cas avec une clé différente, ce qui signifie que la garde idempotence ne le couvre pas (clé nouvelle = pas de doublon). La garde "story déjà active" est un 4e contrôle non positionné dans l'ordre contractuel. Impact : Comportement indéterminé : la story active est-elle rejetée avant ou après la validation format ? INV-293-14 (ordre contractuel stable) est partiellement violé. Gravité : Majeur


4. Diagramme de séquence : message de démarrage sans type défini

Type : Ambiguïté Référence : §5bis (diagramme de séquence), §5.1 (message_type enum) Description : Le diagramme de séquence montre O->>R: demande démarrage story_id=PD-293. Ce message n'a pas de message_type correspondant dans l'enum §5.1 (STATUS_UPDATE|ESCALADE|GATE_RESULT|WORKFLOW_DONE|PO_RESPONSE|PAUSE|RESUME|ABORT). Le mécanisme exact par lequel One Ring crée/lance un Ringbearer n'est pas spécifié : est-ce un fork de process, un appel CLI (claude --session), un message broker ? De même, les messages PAUSE et RESUME envoyés de O vers R dans le diagramme sont des message_type mais leur payload n'est pas documenté (quels champs obligatoires ?). Impact : Le flux start n'est pas implémentable par une équipe tierce sans interprétation. Gravité : Majeur


5. Fréquence de réconciliation non spécifiée

Type : Ambiguïté Référence : INV-293-11, TC-NOM-07 Description : INV-293-11 exige une « réconciliation périodique obligatoire » mais aucun paramètre ne définit l'intervalle de réconciliation. Est-ce à chaque cycle de polling (peer_poll_interval) ? À un multiple ? Sur demande ? Le tableau §5.1 des paramètres numériques ne contient aucun reconciliation_interval. TC-NOM-07 teste la réconciliation comme un événement déclenché, sans valider la périodicité. Impact : Critère non testable de manière déterministe (impossible de vérifier "périodique" sans borne). Gravité : Majeur


6. Interaction start_detection_timeout / first_liveness_timeout ambiguë

Type : Ambiguïté Référence : §5.1 (paramètres numériques), §5.2 (STARTING) Description : Deux timeouts gouvernent le démarrage : start_detection_timeout (30s, global) et first_liveness_timeout (10s, après détection peer). Si le peer apparaît à t=25s, la fenêtre first_liveness_timeout s'étend jusqu'à t=35s, dépassant start_detection_timeout (t=30s). Lequel prévaut ? La spec ne définit pas si first_liveness_timeout est borné par start_detection_timeout ou indépendant. Impact : Comportement non déterministe au cas limite ; deux implémentations conformes pourraient diverger. Gravité : Majeur


7. Champ current_escalade_id vs modèle multi-escalade FIFO

Type : Ambiguïté Référence : §5.4 (schema JSON, champ current_escalade_id), INV-293-13, §5.3 step 5 Description : Le schema story contient un champ current_escalade_id (string|null, singleton), tandis que INV-293-13 garantit la gestion simultanée de multiples escalades FIFO. Le champ singleton suggère qu'une seule escalade est "courante" par story, mais cette sémantique n'est pas définie : est-ce la plus ancienne OPEN ? La dernière reçue ? Le champ est-il mis à jour à chaque respond ? Aucune spécification de ce cycle de vie. Impact : Ambiguïté d'implémentation sur le lien story↔escalade_queue. Gravité : Mineur


8. Comportement de clamp non défini pour peer_poll_interval hors bornes

Type : Ambiguïté Référence : §5.1 (paramètres numériques, colonne "Hors bornes") Description : Pour peer_poll_interval, le comportement hors bornes est « Clamp + avertissement ». Le terme "clamp" n'est pas défini : borne inférieure (1s) si < 1, borne supérieure (10s) si > 10 ? Ou rejet ? La même ambiguïté n'existe pas pour les autres paramètres qui utilisent "Rejet" ou "Alerte". Impact : Faible, mais non testable sans définition précise. Gravité : Mineur


9. Pas de test pour les comportements à expiration des TTL

Type : Incohérence Spec↔Tests Référence : §5.1 (escalade_wait_ttl, pause_ttl), Tests §3-§7 Description : La spec définit trois TTL avec comportements explicites à expiration : - escalade_wait_ttl (72h) : « reste ESCALADED, alerte répétée au Sovereign » - pause_ttl (24h) : « PAUSED persistant + alerte ; aucune reprise automatique » - idempotency_ttl (24h) : purge du cache

Aucun test ne couvre ces comportements à expiration. Le comportement d'alerte répétée (fréquence ? canal ?) n'est pas testable en l'état. Impact : Trois comportements spécifiés sans couverture de test. Les TTL sont des SLA contractuels non vérifiés. Gravité : Majeur


10. Pas de test pour la stratégie de reconnexion broker (timings)

Type : Incohérence Spec↔Tests Référence : §5.3 step 10 (backoff 1s,2s,4s,8s,10s), TC-ERR-10 Description : §5.3 spécifie une stratégie de reconnexion « exponentielle bornée (1s, 2s, 4s, 8s, 10s max) ». TC-ERR-10 vérifie le mode dégradé et la reprise automatique, mais ne valide pas les intervalles de retry ni le plafond à 10s. Un test de non-régression devrait vérifier la séquence exacte de backoff. Impact : La séquence de backoff n'est pas vérifiée ; une implémentation avec backoff linéaire passerait le test. Gravité : Mineur


11. Absence de modèle de confiance/authentification entre peers

Type : Risque sécu/conformité Référence : §5.1, §5.3, INV-293-02, INV-293-05 Description : Le protocole de messagerie ne spécifie aucun mécanisme d'authentification entre One Ring, Ringbearers et broker. Tout processus local capable d'appeler claude-peers-mcp pourrait : (a) s'enregistrer comme un Ringbearer factice, (b) injecter des messages WORKFLOW_DONE ou ESCALADE usurpés, © émettre de faux STATUS_UPDATE pour maintenir un peer fantôme en vie. La validation §5.1 porte sur le format des messages, pas sur l'identité de l'émetteur. Impact : En contexte local MacBook, le risque est atténué (périmètre utilisateur unique). Cependant, l'absence totale de mention de ce risque dans les hypothèses ou hors-périmètre est un défaut d'exhaustivité. Si le périmètre évolue (multi-utilisateur, remote), l'absence de trust model devient critique. Gravité : Mineur (contexte local v1)


12. Pas de protection d'intégrité des logs d'audit §6.1

Type : Risque sécu/conformité Référence : §6.1 (format JSONL), INV-293-05 Description : Les rejets de validation produisent des logs JSONL. Aucun mécanisme de protection d'intégrité (signature, append-only, rotation) n'est spécifié pour ces logs. Dans un contexte ProbatioVault (plateforme de preuve), des logs d'audit non protégés sont une faiblesse de traçabilité. Le JSONL est modifiable par tout processus local. Impact : Auditabilité dégradée. Un incident post-mortem ne pourrait pas s'appuyer sur des logs non intègres. Gravité : Mineur (v1 scope local, mais à documenter comme limitation explicite)


13. Hypothèse H-293-04 en tension structurelle avec INV-293-07

Type : Hypothèse dangereuse Référence : H-293-04, INV-293-07, §5.1 Description : H-293-04 postule que « le protocole messages requis est supporté par les peers sans adaptation de /gov ». C'est une hypothèse structurellement dangereuse car : (1) /gov actuel n'émet pas de messages broker, (2) la spec exige des messages typés (ESCALADE, GATE_RESULT, etc.) en provenance du Ringbearer, (3) "impact si faux" = "nécessité d'une story séparée de compatibilité", ce qui invaliderait le périmètre de PD-293 lui-même. Cette hypothèse devrait être vérifiée avant Gate 5, pas traitée comme risque résiduel. Impact : Si faux, la spec entière est non implémentable sans story préalable. Gravité : Bloquant (si non vérifié avant implémentation)


14. Diagramme d'état : absence de transition STARTING→CRASHED

Type : Incohérence Spec↔Tests (5bis) Référence : §5bis (diagramme d'état), §5.2 (machine d'états) Description : Le diagramme d'état et la machine d'états §5.2 ne prévoient pas de transition STARTING→CRASHED. Si le peer s'enregistre au broker puis disparaît immédiatement (avant la première liveness), le seul chemin est first_liveness_timeout → START_FAILED. Cependant, le mécanisme de crash detection (absence peer > 2 cycles) s'applique-t-il aussi en état STARTING ? §5.2 STARTING ne liste que RUNNING et START_FAILED comme transitions sortantes, ce qui est cohérent. Mais cela signifie que la supervision crash (INV-293-08) ne s'applique qu'à partir de RUNNING — ce qui n'est pas explicité. Impact : Faible, mais le périmètre d'application d'INV-293-08 (« Un Ringbearer disparu ») devrait préciser qu'il exclut l'état STARTING. Gravité : Mineur


15. Diagramme de séquence : PO_RESPONSE réutilise escalade_text pour la réponse

Type : Ambiguïté Référence : §5bis (diagramme de séquence), §5.1 (modèle de données) Description : Le diagramme montre O->>R: PO_RESPONSE{story_id, escalade_text=<reponse>}. Le champ escalade_text est défini §5.1 comme texte d'escalade (la question), pas comme réponse. Réutiliser le même champ pour deux sémantiques différentes (question de l'escalade vs réponse du Sovereign) est source de confusion. Aucun champ response_text n'est défini dans le modèle canonique. Impact : Ambiguïté d'implémentation et de traçabilité (impossible de distinguer question/réponse dans les logs). Gravité : Majeur


Synthèse

Gravité Nombre
Bloquant 3
Majeur 5
Mineur 7

Bloquants : La contradiction INV-293-07 vs protocole de messagerie (#1, #13) est le risque principal — elle remet en question la faisabilité du flux nominal. Le schema JSON avec peer_id requis en STARTING (#2) est un défaut technique direct.

Points d'attention majeurs : L'absence de position de la garde "story déjà active" (#3), l'interaction des timeouts (#6), le champ escalade_text surchargé (#15) et l'absence de tests TTL (#9) nécessitent clarification avant Gate 5.