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, fallbackmaskIp, blocage offline, correctionuseProofShares). - 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) :
- La transition réouvre l’évaluation via
PENDING -> CHECKING. - Les checks sont réappliqués séquentiellement, non atomiquement, dans l’ordre logique de §5.4.
- Étape 1 : pré-check zéro-test (INV-299-12/13). Si échec,
CHECKING -> NON_CONFORMEimmédiat et arrêt de l’évaluation. - Étape 2 : uniquement si étape 1 passe, scoring arithmétique standard et application de la transition correspondante.
- Le premier check en échec suffit à maintenir
NON_CONFORME. - 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¶
-
F-299-01 — Qualification tests sharing
Précondition : modulesrc/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. -
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. -
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. -
F-299-04 — Telemetry PII-free
actionvalide (D-299-08).
metadatasoumise à D-299-09.
Toute clé hors allowlist : rejet log. -
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. -
F-299-06 — Blocage offline
Si D-299-12 ≠true, création/révocation/chargement sharing bloqués.
Message utilisateur explicite obligatoire. -
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. -
F-299-08 — Gate 8 zéro test déterministe
Gate 8 passe enCHECKING.
Siproject_code ∈ {app,backend}et D-299-14 = 0 (glob*.{test,spec}.{ts,tsx}) : D-299-15 est forcé à exactement6.0, quelle que soit la valeur brute, puis transition forcéeCHECKING -> NON_CONFORME.
Pour autres projets : scoring arithmétique standard inchangé. -
F-299-09 — Prompts companion enrichis avec source canonique
Pour D-299-18,assemble-promptcharge la source canonique companion (<story_source_id>-specification.md, sections## 4. Invariantset## Arbitrages — Vérification formelle post-step 1).
Le bloc stable inclut D-299-19 +source_story_id.
Bloc absent/incomplet => prompt reviewer non conforme. -
F-299-10 — Détection plan→spec avec validation de schéma
/gov-check-planphase 4 produit la liste D-299-20.
Sikindhors enum : rejet explicite du check (invalid plan_extension_item.kind) + blocage Gate 5.
Sinon, si au moins unstatus=UNRATIFIED: blocage + ratification PO exigée. -
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 inclutapprover_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, pascrypto/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)¶
- 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%. - Given un utilisateur non propriétaire, When l’écran preuve est affiché, Then le CTA “Partager” n’est pas rendu.
- Given un token valide en stockage sécurisé, When un appel
sharesApi.*est déclenché, Then le headerAuthorizationrespecte D-299-07 (^Bearer [ ]+[!-~]+$). - Given une
metadatacontenantrecipientEmail, WhenlogShareEventest invoqué, Then une erreur de validation est levée et rien n’est logué. - Given une IP invalide, When
maskIpest appelé, Then la valeur retournée estIP masquée indisponible. - Given
NetInfo.isConnected=false, When l’utilisateur tente de créer/révoquer un partage, Then l’action est bloquée avec erreur explicite. - Given
proofIdundefined, When l’écran détail partage se charge, Then aucun appeluseProofShares(undefined)n’est autorisé. - 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é.
- Given Gate 8 sur projet
appavectest_file_count=0, When pré-verdict s’exécute, Thentest_coverageest forcé à6.0exactement et le verdict passe en NON_CONFORME, même si la moyenne arithmétique resterait>= 7. - Given une story companion avec source canonique disponible, When
assemble-promptconstruit le reviewer prompt, Then le bloc stable contient arbitrages PO et invariants source avecsource_story_id. - Given une extension endpoint/header/timeout non ratifiée ou un
kindinvalide, When/gov-check-planphase 4 exécutedetect-plan-extensions, Then Gate 5 est bloquée avec erreur explicite. - 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¶
- Epic :
Référence épique(valeur métier non renseignée). - JIRA :
PD-299. - Repos concernés :
ProbatioVault-app,ProbatioVault-ia-governance. - Documents associés :
- PD-299-besoin.md
- gov-impl.md
- gov-gate.md
- gov-check-plan.md
- assemble-prompt.sh
- 6a Decomposition.md
- learnings-universal.md
- PD-298-specification.md
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é.