PD-299 — Expression de Besoin¶
Story : [GOV+APP] Consolidation PD-298 — dette technique, guards cross-module, gate 8 tests, prompts companion Domaine : workflow (ia-governance) + sharing (app) Date : 2026-04-23 Statut : BESOIN Origine : PD-298 REX §10, Rétrospective §Recommandations, Patterns 1-4
1. Contexte¶
PD-298 (UI liens de partage sans compte) a été livrée en RESERVE (Gate 8, 7.5/10). Le REX et la rétrospective ont identifié 4 patterns récurrents impactant 2-3 stories chacun, plus une dette technique de 8 points dans le module app src/sharing/.
Cette story de consolidation regroupe : - Partie A : corrections techniques dans ProbatioVault-app (module sharing PD-298) - Partie B : améliorations du workflow de gouvernance dans ProbatioVault-ia-governance
Le regroupement se justifie par la cohérence : les améliorations B empêchent la récurrence des problèmes A.
2. Objectifs principaux¶
Partie A — Dette technique app (8 items)¶
A1 — Tests Jest module sharing (45 TC contractuels)¶
Implémenter les 45 scénarios de test contractuels de PD-298-tests.md en Jest pour le module src/sharing/. Couverture cible >= 80%. Pattern récurrent : 2e occurrence (PD-287, PD-298).
A2 — Câblage guard owner dans ProofDetailScreen¶
Monter canShowShareCta dans ProofDetailScreen.tsx pour garantir INV-298-12 : le CTA "Partager" ne s'affiche que si ownerUserId == currentUser.id. Pattern récurrent : 3e occurrence (PD-251, PD-279, PD-298).
A3 — Intégration auth réelle¶
Remplacer le stub getAuthToken() (retourne null) par l'intégration avec le système d'auth existant (PD-99). Tous les appels API sharing doivent inclure Authorization: Bearer.
A4 — Allowlist PII stricte en telemetry¶
Typer metadata dans logShareEvent() avec un z.object({}) Zod strict (allowlist). Supprimer Record<string, string|number|boolean>. INV-298-07 exige zéro email en log.
A5 — maskIp fallback robuste¶
maskIp() doit retourner "IP masquée indisponible" en fallback sur entrée invalide, jamais la valeur brute. INV-298-09.
A6 — Détection offline NetInfo¶
Utiliser @react-native-community/netinfo (déjà installé) pour bloquer les actions sharing hors ligne et afficher une erreur explicite. INV-298-17.
A7 — Fix useProofShares(undefined) dans ShareDetailScreen¶
Corriger ShareDetailScreen.tsx:46 qui appelle useProofShares(undefined) alors que le hook exige un proofId non vide.
A8 — Validation Legal textes ARB-7, ARB-8, RGPD¶
Faire valider par PO/Legal les textes de révocation (ARB-7), absence de DRM (ARB-8) et notice RGPD (rétention 90j) rédigés par l'orchestrateur IA. Mettre à jour les clés i18n si nécessaire.
Partie B — Améliorations workflow gouvernance (6 items)¶
B1 — Phase 6c.bis vérification cross-module¶
Après la synthèse 6c dans /gov-impl, ajouter un grep systématique des points d'intégration cross-module listés dans le plan §Mécanismes cross-module. Si le fichier cible n'est pas dans le diff → correction obligatoire avant step 7. Pattern 1 : 3 stories (PD-251, PD-279, PD-298).
B2 — Gate 8 check déterministe : 0 test = test_coverage plafonné à 6.0¶
Dans /gov-gate, ajouter un check pré-verdict Gate 8 : si find src/{module}/ -name "*.test.ts" | wc -l == 0, plafonner test_coverage à 6.0. Force NON_CONFORME ou ajout de tests. Pattern 2 : 2 stories (PD-287, PD-298).
B3 — Injection arbitrages story source dans prompts gates companion¶
Pour les stories companion (ex: PD-298 = companion de PD-287), assemble-prompt.sh doit injecter les arbitrages PO et invariants de la story source dans le bloc stable du prompt reviewer. Coût : +2KB contexte. Gain : -4 faux positifs par gate. Pattern 3 : 4 bloquants reclassés en Gate 3.
B4 — Règle Zod allowlist metadata telemetry dans learnings-universal¶
Ajouter dans learnings-universal.md : "Pour tout module telemetry avec invariant PII-free, typer metadata avec Zod allowlist stricte. Jamais Record<string, unknown>."
B5 — Traçabilité résolution placeholders en décomposition 6a¶
Ajouter un bloc obligatoire "Données résolues (pré-implémentation)" dans le template 6a Decomposition.md avec source humaine explicite (PO, Legal, story précédente).
B6 — Détection automatique extensions plan→spec¶
Créer scripts/detect-plan-extensions.py comparant endpoints/headers/timeouts du plan aux contrats de la spec. Invoqué par /gov-check-plan phase 4. Si extensions non ratifiées → forcer ratification PO ou retour Gate 3. Pattern récurrent : PD-287 + PD-298 (4+ extensions non ratifiées chacune).
3. Non-objectifs¶
NOBJ-1 — Pas de refonte du module sharing¶
Les corrections A1-A7 sont des fixes ciblés sur le code existant, pas un refactoring global.
NOBJ-2 — Pas de modification des gates ⅗¶
Seule la Gate 8 est modifiée (B2). Les gates 3 et 5 ne changent pas de scoring.
NOBJ-3 — Pas d'automatisation du Legal review¶
A8 est un process humain. L'IA ne valide pas les textes juridiques.
4. Contraintes¶
CTR-1 — Bi-projet¶
La story touche 2 repos : ProbatioVault-app (partie A) et ProbatioVault-ia-governance (partie B). Deux branches features, deux pipelines.
CTR-2 — Rétro-compatibilité scripts¶
Les modifications de assemble-prompt.sh (B3), gov-gate.md (B2), gov-impl.md (B1) doivent être rétro-compatibles. Les workflows en cours ne doivent pas être cassés.
CTR-3 — Tests existants non cassés¶
Les corrections app (A1-A7) ne doivent pas casser les tests existants du projet ProbatioVault-app.
5. Scénarios d'échec¶
SE-1 — Tests Jest cassent le build existant¶
Les nouveaux tests importent des modules de manière incompatible avec le setup Jest existant (ESM, mocks). Vérifier la config Jest avant d'écrire.
SE-2 — Phase 6c.bis trop stricte¶
Le grep cross-module bloque sur des faux positifs (fichier modifié pour autre raison). Prévoir un mécanisme d'override documenté.
SE-3 — Cap test_coverage=6.0 trop agressif¶
Des stories légitimement sans tests (doc, infra) seraient bloquées. Limiter le cap aux projets app/backend uniquement.
6. Invariants¶
INV-299-01 — Tests sharing >= 80% coverage¶
Après A1, npm test -- --testPathPattern=sharing doit passer avec >= 80% coverage sur src/sharing/.
INV-299-02 — Guard owner fonctionnel¶
Après A2, ProofDetailScreen n'affiche le CTA "Partager" que si le propriétaire est l'utilisateur connecté.
INV-299-03 — Auth header présent¶
Après A3, tous les appels sharesApi.* incluent Authorization: Bearer (vérifiable en log réseau).
INV-299-04 — PII impossible en metadata¶
Après A4, logShareEvent({metadata: {recipientEmail: "x"}}) lève une erreur Zod.
INV-299-05 — IP jamais brute¶
Après A5, maskIp("invalid") retourne "IP masquée indisponible", jamais la valeur d'entrée.
INV-299-06 — Offline bloqué¶
Après A6, les écrans sharing affichent une erreur si NetInfo.isConnected == false.
INV-299-07 — Phase 6c.bis exécutée¶
Après B1, /gov-impl vérifie les points d'intégration cross-module post-6c.
INV-299-08 — Gate 8 cap tests¶
Après B2, /gov-gate Gate 8 plafonne test_coverage à 6.0 si 0 test dans le module livré.
INV-299-09 — Prompts companion enrichis¶
Après B3, assemble-prompt.sh injecte les arbitrages de la story source pour les gates companion.
7. Périmètre MVP¶
Partie A (app) : A1-A7 obligatoires, A8 best-effort (dépend du Legal). Partie B (gov) : B1-B6 tous obligatoires.
Fin de l'Expression de Besoin PD-299.