Aller au contenu

PD-299 — Consolidation PD-298 : robustesse sharing app et durcissement workflow gouvernance

1. Objectif

La User Story PD-299 DOIT résorber la dette technique identifiée sur PD-298 côté application mobile et DOIT ajouter des garde-fous de gouvernance empêchant la récurrence des mêmes écarts (tests absents, points cross-module oubliés, extensions plan→spec non ratifiées, prompts companion incomplets).

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

Inclus

  • A1 à A7 côté ProbatioVault-app (tests sharing, guard owner, auth réelle, telemetry PII-free, fallback maskIp, blocage offline, correction useProofShares).
  • A8 avec critère testable de preuve de validation humaine PO/Legal des textes ARB-7, ARB-8 et notice RGPD 90 jours.
  • B1 à B6 côté ProbatioVault-ia-governance (check 6c.bis, cap Gate 8 zéro test, injection companion source, règle learnings universelle, traçabilité placeholders 6a, détection plan→spec).
  • Blocage explicite des transitions de workflow quand une condition contractuelle échoue.

Exclu

  • Refonte globale du module sharing.
  • Modification des règles de scoring Gate 3 et Gate 5.
  • Automatisation de la décision juridique de fond par IA.
  • Vérification automatique de la validité juridique substantielle des textes ARB-7/ARB-8/RGPD-90j (hors périmètre vérification automatique).
  • Vérification automatique de l’intention réelle d’un approbateur humain au-delà de la trace Atlassian (hors périmètre vérification automatique).
  • Vérification automatique de la pertinence métier des arbitrages PO et des décisions de ratification au-delà de leur présence formelle (hors périmètre vérification automatique).

3. Définitions

Terme Définition
Story companion Story dépendante d’une story source, nécessitant reprise explicite des arbitrages/invariants de la source.
6c.bis Contrôle post-synthèse step 6c vérifiant que les points cross-module du plan sont effectivement dans le diff.
Zéro test test_file_count == 0 sur le module livré, avec comptage sur le glob *.{test,spec}.{ts,tsx}.
Cap Gate 8 Règle imposant test_coverage = 6.0 exactement en cas de zéro test sur projet app/backend.
Extension plan→spec Endpoint/header/timeout présent dans le plan mais absent des contrats de la spec.
Ratification PO Validation humaine explicite autorisant une extension plan→spec, matérialisée par un commentaire Jira horodaté et signé par l’identifiant utilisateur.
Source canonique companion Fichier <story_source_id>-specification.md de la story source, sections ## 4. Invariants et ## Arbitrages — Vérification formelle post-step 1.
Allowlist metadata stricte Schéma Zod strict n’acceptant que les clés explicitement autorisées.
État terminal État sans transition sortante autorisée (-> * : INTERDITE).

4. Invariants (non négociables)

ID Règle Justification
INV-299-01 Le module src/sharing/ DOIT contenir exactement 45 cas de test contractuels Jest alignés avec PD-298-tests. Fermeture dette A1.
INV-299-02 La couverture src/sharing/ DOIT être >= 80%. Critère qualité minimal contractuel.
INV-299-03 Le CTA “Partager” DOIT être visible uniquement si ownerUserId == currentUser.id (D-299-05). Empêche partage hors propriété.
INV-299-04 Tout appel API sharing DOIT inclure Authorization: Bearer <token> valide (D-299-07). Conformité auth PD-99.
INV-299-05 logShareEvent DOIT rejeter toute metadata hors allowlist stricte (D-299-09). Zéro PII en telemetry.
INV-299-06 maskIp DOIT retourner exactement IP masquée indisponible sur entrée invalide (D-299-11). Jamais d’IP brute en fallback.
INV-299-07 Si netinfo_is_connected != true (D-299-12), toute action sharing DOIT être bloquée avec erreur explicite. Fail-closed hors ligne.
INV-299-08 useProofShares NE DOIT JAMAIS être invoqué avec proof_id vide/undefined (D-299-13). Évite appel invalide silencieux.
INV-299-09 A8 est conforme uniquement si une preuve D-299-21 existe dans la source canonique Jira (commentaires tracés Atlassian) pour ARB-7, ARB-8, RGPD-90J, avec approbations PO+LEGAL horodatées et signées par identifiant utilisateur. Rend A8 testable avec non-répudiation minimale.
INV-299-10 /gov-impl DOIT exécuter 6c.bis après 6c sur les points cross-module déclarés (D-299-16). Prévention Pattern 1.
INV-299-11 Si un point cross-module déclaré est absent du diff (D-299-17), la transition vers step 7 est INTERDITE. Blocage précoce obligatoire.
INV-299-12 En Gate 8, si projet ∈ {app,backend} et test_file_count == 0 (D-299-14, glob *.{test,spec}.{ts,tsx}), test_coverage DOIT être forcé à exactement 6.0 (D-299-15), indépendamment de la valeur brute. Contrôle déterministe Pattern 2.
INV-299-13 Sous condition INV-299-12, la transition CHECKING -> NON_CONFORME DOIT être forcée tant que zéro test persiste, même si la moyenne arithmétique des autres critères est >= 7.0. Empêche GO/RESERVE sans tests.
INV-299-14 Pour toute story companion, le prompt reviewer DOIT inclure arbitrages PO + invariants issus de la source canonique companion (D-299-19), avec traçabilité source_story_id vérifiable. Réduction faux positifs Pattern 3.
INV-299-15 learnings-universal.md DOIT contenir la règle telemetry : Zod allowlist stricte, jamais Record<string, unknown>. Prévention Pattern 4.
INV-299-16 Le template 6a Decomposition.md DOIT contenir le bloc obligatoire “Données résolues (pré-implémentation)” avec source humaine. Traçabilité des résolutions.
INV-299-17 /gov-check-plan phase 4 DOIT exécuter detect-plan-extensions entre sources canoniques plan/spec et bloquer si au moins 1 extension non ratifiée (D-299-20) ou si kind est hors enum (erreur explicite). Évite extensions non contractées et rejets silencieux.
INV-299-18 Toute transition non listée en §5.4 est INTERDITE pour la seule FSM Gate 8 (PENDING,CHECKING,NON_CONFORME,GO,RESERVE,ESCALADE). Les transitions workflow (6c→6c.bis→7, Gate 5) sont des gardes séquentielles hors FSM. FSM fermée, auditabilité, scope explicite.

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 / contrainte Si invalide
D-299-01 story_id String UTF-8 4..11 [A-Z0-9-] Sensitive ^PD-[0-9]{1,4}$ Rejet du traitement
D-299-02 project_code Enum UTF-8 3..14 [a-z-] Sensitive ^(app|backend|ia-governance)$ Rejet du traitement
D-299-03 proof_id UUID v4 texte 36 [0-9a-fA-F-] Insensitive ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$ Blocage action sharing
D-299-04 share_id UUID v4 texte 36 [0-9a-fA-F-] Insensitive même regex UUID v4 Rejet navigation/action
D-299-05 user_id (ownerUserId,currentUser.id) UUID v4 texte 36 [0-9a-fA-F-] Insensitive même regex UUID v4 CTA caché
D-299-06 auth_access_token Token opaque UTF-8 1..4096 ASCII printable sans espace Sensitive ^\S+$ Appel API annulé, erreur auth
D-299-07 authorization_header Bearer<SP+><token> 8..4103 ASCII visible + espace ASCII Sensitive ^Bearer [ ]+[!-~]+$ Requête non émise
D-299-08 telemetry_action Enum string 11..24 [a-z_] Sensitive ^(share_create|share_revoke|share_list_view|share_detail_view|share_events_view|drm_warning_shown|drm_warning_acknowledged)$ Rejet log
D-299-09 telemetry_metadata Objet JSON strict 0 clé autorisée par défaut UTF-8 Clés sensitive Schéma strict (allowlist), défaut {} Erreur Zod, log rejeté
D-299-10 ip_input Texte IPv4/IPv6 1..45 [0-9a-fA-F:.] Insensitive IPv4/IPv6 parseable Retour D-299-11
D-299-11 ip_mask_fallback Littéral UTF-8 24 UTF-8 Sensitive valeur exacte IP masquée indisponible N/A (valeur de repli)
D-299-12 netinfo_is_connected Bool JSON n/a true|false|null n/a bool strict Action bloquée si ≠ true
D-299-13 proof_id pour useProofShares Référence D-299-03 36 idem D-299-03 idem non vide obligatoire Rejet appel hook
D-299-14 test_file_count Entier base10 1..10 digits [0-9] n/a >= 0, issu de count(*.{test,spec}.{ts,tsx}) Rejet check Gate 8
D-299-15 test_coverage_score Décimal base10 1..4 chars [0-9.] n/a 0.0 <= x <= 10.0 Rejet scoring
D-299-16 cross_module_point_path Chemin POSIX relatif 1..260 ASCII printable Sensitive ^[A-Za-z0-9._/-]+$ Step 6 bloqué
D-299-17 git_diff_path Chemin POSIX relatif 1..260 ASCII printable Sensitive ^[A-Za-z0-9._/-]+$ Contrôle 6c.bis invalide
D-299-18 companion_story_id String UTF-8 4..11 [A-Z0-9-] Sensitive ^PD-[0-9]{1,4}$ Injection companion rejetée
D-299-19 companion_injected_block Markdown UTF-8 1..2048 bytes additionnels UTF-8 printable Sensitive Contient sections extraites de la source canonique companion + source_story_id Prompt invalide
D-299-20 plan_extension_item Objet JSON {kind,key,status,ratification_ref?} 1 item min UTF-8 Sensitive kind ∈ {endpoint,header,timeout} + status ∈ {RATIFIED,UNRATIFIED} ; si kind hors enum: erreur explicite invalid plan_extension_item.kind et rejet du check Check rejeté + Gate 5 bloquée
D-299-21 legal_validation_entry Objet JSON/YAML (1 entrée par text_id) 3 entrées exactes UTF-8 Sensitive text_id ∈ {ARB-7,ARB-8,RGPD-90J} ; pour chaque entrée: approvals.PO et approvals.LEGAL requis avec {approver_id, approved_at, jira_comment_id} ; approver_id = email ou Jira username ; approved_at ISO8601 ; jira_comment_id non vide (commentaire Jira traçable Atlassian) A8 non conforme
D-299-22 correlation_id UUID v4 texte 36 [0-9a-fA-F-] Insensitive même regex UUID v4 Événement d’audit rejeté

Référencement unique : les sections §6 à §8 réutilisent ces IDs (D-299-*) sans redéfinition de format.

5.2 Bornes numériques contractuelles

Paramètre Défaut Min Max Unité Contexte de référence Percentile Hors bornes
sharing_test_cases_required 45 45 45 cas de test module src/sharing/ n/a NON_CONFORME
sharing_coverage_threshold 80 80 100 % couverture src/sharing/ n/a NON_CONFORME si <80, rejet si >100
gate8_zero_test_trigger 0 0 0 fichier *.{test,spec}.{ts,tsx} Gate 8 app/backend n/a rejet check
gate8_zero_test_cap_score 6.0 6.0 6.0 score /10 critère test_coverage Gate 8 n/a rejet verdict
cross_module_missing_points_tolerance 0 0 0 fichier manquant contrôle 6c.bis n/a blocage step 7
unratified_extensions_tolerance 0 0 0 extension /gov-check-plan phase 4 n/a blocage Gate 5
companion_context_addition 2 0 2 KiB bloc stable reviewer n/a rejet prompt si dépassement
metadata_allowlist_keys_count_default 0 0 0 clé telemetry sharing n/a erreur Zod
legal_notice_retention_days 90 90 90 jours texte RGPD A8 n/a validation Legal KO
legal_texts_required 3 3 3 texte A8 (ARB-7,ARB-8,RGPD-90J) n/a A8 non conforme
legal_approvals_required 2 2 2 approbations par texte A8 (PO + LEGAL) n/a A8 non conforme

5.3 SLA temporels (transitions)

Aucune transition temporelle identifiée.

Note contractuelle : la mention “rétention 90 jours” est une donnée textuelle à valider (D-299-21), pas un mécanisme d’expiration d’état applicatif dans PD-299.

5.4 Machine d’états (Gate 8 test-coverage)

Portée contractuelle : cette FSM fermée s’applique uniquement à Gate 8. Les enchaînements workflow (6c→6c.bis→7, Gate 5 plan→spec) restent des gardes séquentielles hors FSM.

États : PENDING, CHECKING, NON_CONFORME, GO, RESERVE, ESCALADE.

État PENDING

Transition sortante Statut Condition Comportement
PENDING -> CHECKING AUTORISÉE lancement Gate 8 pré-check exécuté
PENDING -> NON_CONFORME INTERDITE verdict sans check rejet
PENDING -> GO INTERDITE verdict sans check rejet
PENDING -> RESERVE INTERDITE verdict sans check rejet
PENDING -> ESCALADE INTERDITE escalade sans check rejet

État CHECKING

Transition sortante Statut Condition Comportement
CHECKING -> NON_CONFORME AUTORISÉE soit test_file_count==0 (app/backend, glob D-299-14) avec test_coverage=6.0 exact, soit règle de scoring NON_CONFORME blocage
CHECKING -> GO AUTORISÉE scoring arithmétique GO et absence de condition INV-299-12 passage GO
CHECKING -> RESERVE AUTORISÉE scoring arithmétique RESERVE et absence de condition INV-299-12 passage RESERVE
CHECKING -> ESCALADE AUTORISÉE blocage technique/décision humaine escalade
CHECKING -> PENDING INTERDITE retour sans correction rejet

État NON_CONFORME

Transition sortante Statut Condition Comportement
NON_CONFORME -> PENDING AUTORISÉE corrections effectuées + re-gate nouvelle évaluation complète
NON_CONFORME -> ESCALADE AUTORISÉE plafond itérations atteint ou plateau convergence décision PO requise
NON_CONFORME -> GO INTERDITE bypass correction rejet
NON_CONFORME -> RESERVE INTERDITE bypass correction rejet

Comportement retour (NON_CONFORME -> PENDING) :

  1. La transition réouvre l’évaluation via PENDING -> CHECKING.
  2. Les checks sont réappliqués séquentiellement, non atomiquement, dans l’ordre logique de §5.4.
  3. Étape 1 : pré-check zéro-test (INV-299-12/13). Si échec, CHECKING -> NON_CONFORME immédiat et arrêt de l’évaluation.
  4. Étape 2 : uniquement si étape 1 passe, scoring arithmétique standard et application de la transition correspondante.
  5. Le premier check en échec suffit à maintenir NON_CONFORME.
  6. Les gardes workflow hors FSM (6c.bis, plan→spec) restent évaluées séparément dans leurs commandes dédiées.

États terminaux

État Transition sortante Statut Comportement
GO GO -> * INTERDITE état terminal, résolution manuelle uniquement
RESERVE RESERVE -> * INTERDITE état terminal, résolution manuelle uniquement
ESCALADE ESCALADE -> * INTERDITE état terminal, résolution manuelle uniquement

Checklist machine à états :

  • Chaque état a ses transitions sortantes autorisées/interdites.
  • Chaque état terminal mentionne explicitement -> * : INTERDITE (état terminal, résolution manuelle uniquement).
  • Le scope de fermeture est explicitement limité à la FSM Gate 8.
  • Modèle couvert par invariant dédié (INV-299-18).

5.5 Flux nominaux contractuels

  1. F-299-01 — Qualification tests sharing
    Précondition : module src/sharing/ ciblé.
    Le corpus PD-298-tests est matérialisé en 45 tests Jest.
    Le run de couverture du module respecte >= 80%.
    Sinon : NON_CONFORME.

  2. F-299-02 — Guard propriétaire CTA partage
    Le rendu CTA dépend strictement de D-299-05.
    Si IDs non égaux ou invalides : CTA absent.
    Aucun fallback permissif.

  3. F-299-03 — Auth réelle appels sharing
    Tout appel sharing construit D-299-07 à partir de D-299-06.
    Le header DOIT respecter ^Bearer [ ]+[!-~]+$ (pas de CR/LF, pas de caractères de contrôle).
    Si token ou header invalide : appel annulé et erreur explicite.

  4. F-299-04 — Telemetry PII-free
    action valide (D-299-08).
    metadata soumise à D-299-09.
    Toute clé hors allowlist : rejet log.

  5. F-299-05 — Masquage IP fail-closed
    Entrée IP invalide (D-299-10) => sortie D-299-11.
    La valeur brute initiale n’est jamais restituée.

  6. F-299-06 — Blocage offline
    Si D-299-12 ≠ true, création/révocation/chargement sharing bloqués.
    Message utilisateur explicite obligatoire.

  7. F-299-07 — Contrôle 6c.bis cross-module
    Après 6c, extraction de D-299-16 depuis le plan.
    Vérification présence dans D-299-17.
    Au moins un manquant => step 7 interdit.

  8. F-299-08 — Gate 8 zéro test déterministe
    Gate 8 passe en CHECKING.
    Si project_code ∈ {app,backend} et D-299-14 = 0 (glob *.{test,spec}.{ts,tsx}) : D-299-15 est forcé à exactement 6.0, quelle que soit la valeur brute, puis transition forcée CHECKING -> NON_CONFORME.
    Pour autres projets : scoring arithmétique standard inchangé.

  9. F-299-09 — Prompts companion enrichis avec source canonique
    Pour D-299-18, assemble-prompt charge la source canonique companion (<story_source_id>-specification.md, sections ## 4. Invariants et ## Arbitrages — Vérification formelle post-step 1).
    Le bloc stable inclut D-299-19 + source_story_id.
    Bloc absent/incomplet => prompt reviewer non conforme.

  10. F-299-10 — Détection plan→spec avec validation de schéma
    /gov-check-plan phase 4 produit la liste D-299-20.
    Si kind hors enum : rejet explicite du check (invalid plan_extension_item.kind) + blocage Gate 5.
    Sinon, si au moins un status=UNRATIFIED : blocage + ratification PO exigée.

  11. F-299-11 — Validation légale A8 traçable
    Existence de D-299-21 pour ARB-7, ARB-8, RGPD-90J avec rôles PO+LEGAL.
    Chaque approbation inclut approver_id, approved_at, jira_comment_id (non-répudiation minimale via trace Atlassian).
    Si incomplet : A8 non validé.

5.6 Contraintes inter-modules

Élément Contrat
Routes/écrans de l’autre module à protéger Écran preuve (Proof) qui ouvre le flux sharing (ShareCreate/CTA).
Mécanisme de protection Garde de propriété basée sur D-299-05 avant affichage CTA ou navigation.
Données nécessaires de l’autre schéma/module proof.owner_user_id, auth.current_user_id, proof.id.
Résolution de la FK cross-module proof.id (module preuves) → proof_id des requêtes sharing (D-299-03).
Scope d’enregistrement du guard Scope local écran preuve (pas global app-wide).
Exceptions d’accès Aucune exception de rôle spécifiée.
Contraintes cross-module gouvernance /gov-impl (6c.bis) et /gov-check-plan (phase 4) DOIVENT lire les contrats du plan/spec du projet cible et bloquer en cas d’écart.

5.7 Clauses obligatoires non applicables

  • Stratégie de migration DDL : non applicable (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).
  • Invariant envelope encryption crypto : non applicable (domaine workflow + sharing, pas crypto/crypto-proof).

5bis. Diagrammes (applicable)

Diagramme d’état

stateDiagram-v2
    [*] --> PENDING

    PENDING --> CHECKING: start Gate 8
    PENDING --> NON_CONFORME: INTERDITE
    PENDING --> GO: INTERDITE
    PENDING --> RESERVE: INTERDITE
    PENDING --> ESCALADE: INTERDITE

    CHECKING --> NON_CONFORME: project in app/backend && test_count==0 => test_coverage:=6.0 (exact, ignore raw) OR arithmetic non-conforme
    CHECKING --> GO: arithmetic GO (if no zero-test trigger)
    CHECKING --> RESERVE: arithmetic RESERVE (if no zero-test trigger)
    CHECKING --> ESCALADE: technical/human block
    CHECKING --> PENDING: INTERDITE

    NON_CONFORME --> PENDING: corrections + re-gate
    NON_CONFORME --> ESCALADE: v3 non-conforme or convergence plateau
    NON_CONFORME --> GO: INTERDITE
    NON_CONFORME --> RESERVE: INTERDITE

    GO --> PENDING: INTERDITE (etat terminal)
    GO --> CHECKING: INTERDITE (etat terminal)
    GO --> NON_CONFORME: INTERDITE (etat terminal)
    GO --> ESCALADE: INTERDITE (etat terminal)

    RESERVE --> PENDING: INTERDITE (etat terminal)
    RESERVE --> CHECKING: INTERDITE (etat terminal)
    RESERVE --> NON_CONFORME: INTERDITE (etat terminal)
    RESERVE --> ESCALADE: INTERDITE (etat terminal)

    ESCALADE --> PENDING: INTERDITE (etat terminal)
    ESCALADE --> CHECKING: INTERDITE (etat terminal)
    ESCALADE --> NON_CONFORME: INTERDITE (etat terminal)
    ESCALADE --> GO: INTERDITE (etat terminal)
    ESCALADE --> RESERVE: INTERDITE (etat terminal)

Diagramme de séquence

sequenceDiagram
    participant GI as /gov-impl
    participant Git as Git diff
    participant GG as /gov-gate
    participant VS as verdict-scoring
    participant AP as assemble-prompt.sh
    participant Src as Story source artifacts
    participant GCP as /gov-check-plan
    participant DPE as detect-plan-extensions
    participant FSM as Jira/FSM

    GI->>GI: extract(cross_module_point_path[]) depuis plan
    GI->>Git: diff_paths()
    GI->>GI: missing = cross_module_point_path - diff_paths
    alt missing > 0
        GI->>FSM: block(step7, reason=missing_cross_module_files)
    else missing == 0
        GI->>FSM: allow(step7)
    end

    GG->>GG: test_count = count(find(src/{module}, "*.{test,spec}.{ts,tsx}"))
    alt project in {app,backend} and test_count==0
        GG->>VS: test_coverage = 6.0 (forced exact, independent of raw)
        VS-->>GG: verdict=NON_CONFORME
        GG->>FSM: transition(CHECKING->NON_CONFORME)
    else
        GG->>VS: verdict = arithmetic(scores)
        VS-->>GG: GO/RESERVE/NON_CONFORME/ESCALADE
        GG->>FSM: transition according to verdict
    end

    AP->>Src: load_canonical(source_story_spec, sections=invariants+arbitrages)
    Src-->>AP: source_block + source_story_id
    AP->>AP: stable_prompt = template_stable + source_block
    AP-->>GG: reviewer_prompt(stable_prompt)

    GCP->>DPE: diff(plan.endpoints|headers|timeouts, spec.contracts)
    DPE-->>GCP: extension_items(kind,status,ratification_ref)
    alt exists kind hors enum
        GCP->>FSM: block(Gate5, reason=invalid_extension_kind) + explicit_error
    else exists UNRATIFIED
        GCP->>FSM: block(Gate5) + request_PO_ratification
    else
        GCP->>FSM: allow(Gate5)
    end

6. Cas d’erreur

ID Cas Réponse attendue
ERR-299-01 story_id invalide (D-299-01) Rejet immédiat du traitement
ERR-299-02 proof_id invalide/absent (D-299-03/D-299-13) CTA absent ou appel rejeté
ERR-299-03 Token auth absent/invalide (D-299-06) Appel sharing annulé + erreur auth explicite
ERR-299-04 Header Authorization invalide (D-299-07, regex stricte sans CR/LF) Requête non émise
ERR-299-05 metadata hors allowlist (D-299-09) Erreur Zod, log non émis
ERR-299-06 IP invalide (D-299-10) Retour exact D-299-11
ERR-299-07 netinfo_is_connected != true (D-299-12) Action sharing bloquée + message explicite
ERR-299-08 Zéro test sur projet app/backend (D-299-14) test_coverage=6.0 exact + NON_CONFORME forcé, indépendamment du score brut
ERR-299-09 Point cross-module manquant dans diff (D-299-16 vs D-299-17) Blocage step 7
ERR-299-10 Extension plan→spec non ratifiée (D-299-20) Blocage Gate 5 + ratification PO requise
ERR-299-11 Story companion sans source canonique exploitable (D-299-19) Prompt companion rejeté
ERR-299-12 Preuve validation A8 incomplète/non signée (D-299-21) A8 non validé
ERR-299-13 project_code hors scope du check B2 Check cap zéro-test non appliqué, scoring standard
ERR-299-14 Tentative de transition non listée en §5.4 Rejet (FSM Gate 8 fermée)
ERR-299-15 plan_extension_item.kind hors enum (D-299-20) Rejet explicite du check + blocage Gate 5

7. Critères d’acceptation (testables)

ID Critère Observable
CA-299-01 45 tests contractuels sharing présents Comptage fichiers/scénarios = 45
CA-299-02 Couverture sharing >= 80% Rapport coverage src/sharing/
CA-299-03 CTA partage visible uniquement au propriétaire Comparaison ownerUserId/currentUser.id vérifiée
CA-299-04 Tous appels sharing incluent Authorization conforme à D-299-07 Traces réseau/headers sans CR/LF
CA-299-05 metadata hors allowlist est rejetée Test logShareEvent({metadata:{recipientEmail:"x"}}) échoue
CA-299-06 maskIp("invalid") retourne D-299-11 Assertion exacte de chaîne
CA-299-07 Hors ligne, actions sharing bloquées UI affiche erreur explicite
CA-299-08 Aucun useProofShares(undefined) en exécution Hook reçoit toujours proof_id valide
CA-299-09 6c.bis bloque si point cross-module absent du diff Step 7 refusé
CA-299-10 Gate 8 app/backend avec zéro test force score final exactement 6.0 Valeur test_coverage forcée observée, même si raw < 6.0
CA-299-11 Gate 8 app/backend zéro test force NON_CONFORME Transition CHECKING->NON_CONFORME observée même si moyenne arithmétique >= 7.0
CA-299-12 Stories companion injectent arbitrages/invariants de la source canonique Prompt reviewer contient bloc source + source_story_id
CA-299-13 Règle telemetry ajoutée dans learnings-universal Texte exact détectable
CA-299-14 Template 6a contient bloc “Données résolues (pré-implémentation)” Bloc présent + champs source humaine
CA-299-15 detect-plan-extensions bloque extensions non ratifiées et rejette kind invalide explicitement Gate 5 bloquée + message d’erreur explicite
CA-299-16 A8 validé via preuve PO+Legal signée/horodatée avec jira_comment_id pour ARB-⅞/RGPD-90j Artefact de validation complet

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

  1. Given le module sharing sans tests sur *.{test,spec}.{ts,tsx}, When la campagne A1 est exécutée, Then 45 tests sont présents et la couverture atteint au moins 80%.
  2. Given un utilisateur non propriétaire, When l’écran preuve est affiché, Then le CTA “Partager” n’est pas rendu.
  3. Given un token valide en stockage sécurisé, When un appel sharesApi.* est déclenché, Then le header Authorization respecte D-299-07 (^Bearer [ ]+[!-~]+$).
  4. Given une metadata contenant recipientEmail, When logShareEvent est invoqué, Then une erreur de validation est levée et rien n’est logué.
  5. Given une IP invalide, When maskIp est appelé, Then la valeur retournée est IP masquée indisponible.
  6. Given NetInfo.isConnected=false, When l’utilisateur tente de créer/révoquer un partage, Then l’action est bloquée avec erreur explicite.
  7. Given proofId undefined, When l’écran détail partage se charge, Then aucun appel useProofShares(undefined) n’est autorisé.
  8. Given des points cross-module déclarés au plan, When 6c.bis compare avec le diff et qu’un fichier manque, Then step 7 est bloqué.
  9. Given Gate 8 sur projet app avec test_file_count=0, When pré-verdict s’exécute, Then test_coverage est forcé à 6.0 exactement et le verdict passe en NON_CONFORME, même si la moyenne arithmétique resterait >= 7.
  10. Given une story companion avec source canonique disponible, When assemble-prompt construit le reviewer prompt, Then le bloc stable contient arbitrages PO et invariants source avec source_story_id.
  11. Given une extension endpoint/header/timeout non ratifiée ou un kind invalide, When /gov-check-plan phase 4 exécute detect-plan-extensions, Then Gate 5 est bloquée avec erreur explicite.
  12. Given A8, When la vérification de clôture est faite, Then la preuve PO+Legal signée et horodatée est requise pour ARB-7, ARB-8 et RGPD-90j via commentaires Jira traçables.

9. Hypothèses explicites

ID Hypothèse Impact si faux
H-299-01 La relation story companion → story source est disponible et exploitable. B3 non déterministe.
H-299-02 Le plan contient une section exploitable des points cross-module. B1 inapplicable sans fallback contractuel.
H-299-03 Le module livré est résoluble en chemin src/{module}. B2 ne peut pas compter les tests.
H-299-04 Le token d’auth applicatif reste accessible via la couche auth existante. A3 bloqué (auth réelle indisponible).
H-299-05 Un accès aux artefacts Jira (commentaires) est disponible pour la vérification D-299-21. A8 non vérifiable.

10. Points à clarifier

10.1 Contraintes techniques (stack projet cible)

Projet concerné Stack contractuelle Preuve/indice
ProbatioVault-app React Native + Expo SDK 54 + TypeScript package.json (expo ^54), metro.config.js, app.config.js
ProbatioVault-ia-governance Shell (bash/zsh) + Python 3 + Markdown/YAML/JSON + Node.js (mcp-signal) scripts/*.sh, scripts/*.py, requirements.txt, mcp-signal/package.json
ProbatioVault-backend (scope B2 uniquement) NestJS + TypeORM + PostgreSQL Matrice stack contractuelle projet

Contrainte explicite : aucune substitution de stack n’est autorisée (ex. pas de Swift/SwiftUI pour l’app, pas de Spring Boot pour le backend).

10.2 Questions ouvertes

ID Question Impact
Q-299-01 Référence épique exacte (valeur métier) non fournie. Traçabilité Epic incomplète
Q-299-05 Le nom de composant cible A2 est-il ProofDetailScreen ou l’écran preuve actuel (ProofScreen) ? Ciblage guard potentiellement erroné
Q-299-06 Le schéma allowlist metadata doit-il rester vide ({}) ou contenir des clés explicites à l’initialisation ? Compatibilité telemetry

Références

Arbitrages — Vérification formelle post-step 1

Score : 96.5/100 — 6 flow_gaps MEDIUM (faux positifs documentés).

Les 6 issues détectées concernent des états du cycle de vie preuve (PD-279 : restituted, sealed, expired, disposed) absents du FSM §5.4 de PD-299. Ce FSM modélise exclusivement le scoring Gate 8 (états PENDING/CHECKING/NON_CONFORME/GO/RESERVE/ESCALADE), pas le cycle de vie des preuves. Les deux FSM sont orthogonaux.

Décision : faux positifs, workflow non bloqué.