PD-299 — Plan d'implémentation¶
- Story : PD-299 — Consolidation PD-298 : robustesse sharing app et durcissement workflow gouvernance
- Domaine :
workflow(avec livraisonsappetia-governance, scope partielbackendlimité à la règle B2 Gate 8) - Sources contractuelles :
PD-299-specification.md(révision 2026-04-23 21:58),PD-299-tests.md,PD-299-specification-review.md - Stacks contractuelles :
- ProbatioVault-app : React Native + Expo SDK 54 + TypeScript
- ProbatioVault-ia-governance : Shell (bash/zsh) + Python 3 + Markdown/YAML/JSON
- ProbatioVault-backend (règle B2 seulement) : NestJS + TypeORM + PostgreSQL (pas de livrable de code, cible de contrôle Gate 8)
0. Décisions techniques de résolution des ambiguïtés de la spec¶
Les ambiguïtés et contradictions documentées dans la revue de spécification (§2 à §7) sont tranchées ici par décisions explicites, sans modification de la spec. Chaque décision est référencée dans les hypothèses techniques (§8 H-T-*).
| ID | Point ambigu | Décision tranchée | Hypothèse associée |
|---|---|---|---|
| DEC-01 | Récursivité du glob *.{test,spec}.{ts,tsx} (E-AMB-03/E-SEC-04) | Le glob déployé est récursif : **/*.{test,spec}.{ts,tsx} évalué depuis <project_root>/src. Implémentation via find src -type f \( -name '*.test.ts' -o -name '*.test.tsx' -o -name '*.spec.ts' -o -name '*.spec.tsx' \) | wc -l. | H-T-01 |
| DEC-02 | Échelle « module livré » vs « projet » (E-AMB-04) | Le comptage test_file_count est évalué au niveau du projet cible (ProbatioVault-app/src, ProbatioVault-backend/src) identifié par project_code. Le « module livré » sert uniquement à la couverture fonctionnelle PD-298 (src/sharing/) pour INV-299-01/02. | H-T-02 |
| DEC-03 | D-299-19 min 1 byte vs §5.2 min 0 KiB (E-CON-01) | Borne inférieure appliquée : 1 byte (§5.1 prévaut, bloc vide interdit). La tolérance 0 KiB de §5.2 est traitée comme arrondi au plus proche de la valeur mesurée en octets. | H-T-03 |
| DEC-04 | ratification_ref absent sur RATIFIED (E-SEC-06/E-NT-05) | detect-plan-extensions rejette comme UNRATIFIED_MISSING_PROOF tout item status=RATIFIED dont ratification_ref est vide. Traité comme un cas UNRATIFIED (blocage Gate 5). | H-T-04 |
| DEC-05 | « Message explicite » non qualifié (E-AMB-09/E-NT-03) | Définition opérationnelle : chaque message explicite est un code d'erreur fermé (ex. SHARE_OFFLINE, SHARE_AUTH_INVALID, SHARE_OWNERSHIP_MISMATCH) émis via une classe d'erreur typée SharingError { code, userMessage, technicalDetail }. La table exhaustive des codes est en §6. | H-T-05 |
| DEC-06 | approver_id discrimination email/username (E-AMB-06) | Discriminateur : présence de @ → email (regex RFC 5322 simplifiée) ; sinon username Jira (regex ^[A-Za-z0-9][A-Za-z0-9._-]{2,63}$). L'entrée est normalisée en lowercase pour les emails, conservée pour les usernames. | H-T-06 |
| DEC-07 | Relation companion → source (E-AMB-07) | Résolution via champ explicite source_story_id déclaré en tête du besoin PD-XX-besoin.md de la story companion (bloc YAML front-matter). Absent → la story n'est pas companion, l'injection B3 est un no-op. | H-T-07 |
| DEC-08 | Unicité approver_id PO vs LEGAL et jira_comment_id (E-NT-04/E-SEC-03) | validate-legal-approvals.py impose : approver_id_PO != approver_id_LEGAL ET jira_comment_id_PO != jira_comment_id_LEGAL. Violation → A8 non conforme. | H-T-08 |
| DEC-09 | Vocabulaire « non-répudiation minimale » (E-AMB-05/E-CON-03/E-SEC-02) | Le module gov-legal rapporte le niveau comme traceability_only et jamais comme non-repudiation. Le libellé spec est conservé dans les artefacts, mais la sortie JSON utilise assurance_level=traceability_only. | H-T-09 |
| DEC-10 | Masquage token dans logs (E-SEC-01/E-IST-06) | La classe d'erreur SharingApiError masque automatiquement auth_access_token par substitution <REDACTED_TOKEN> avant sérialisation. Test de non-régression dédié (TC-NR-supp) ajouté au périmètre unitaire. | H-T-10 |
1. Découpage en composants¶
Neuf modules cibles, répartis en deux projets. Aucun chevauchement de files (voir PD-299-code-contracts.yaml).
1.1 ProbatioVault-app (4 modules)¶
| Module | Responsabilité | Chemins | Dépendances amont |
|---|---|---|---|
sharing-tests | Matérialisation des 45 tests Jest contractuels PD-298 + configuration coverage >=80% sur src/sharing/ (A1). | src/sharing/**/__tests__/**, jest.config.js (scope sharing) | sharing-ui, sharing-api, sharing-telemetry, sharing-legal (les tests exécutent ces modules) |
sharing-ui | Guard propriétaire CTA Partager (A2), blocage offline UI (A6), correction useProofShares pour ne jamais recevoir undefined (A7). Regroupe les écrans ProofScreen/ProofDetailScreen et les containers du flux sharing. | src/sharing/screens/**, src/sharing/components/**, src/sharing/guards/**, src/sharing/hooks/** | sharing-api (types ProofId, UserId), sharing-telemetry (erreurs typées) |
sharing-api | Authentification réelle Bearer sur tous les appels (A3), masquage token dans erreurs, préparation et validation du header Authorization conforme à D-299-07. | src/sharing/api/** | sharing-types (branded types PD-298 existants) |
sharing-telemetry | Allowlist Zod stricte metadata (A4), fallback maskIp fail-closed (A5), classes d'erreur typées partagées (SharingError, SharingApiError). | src/sharing/telemetry/**, src/sharing/masking/**, src/sharing/errors/** | sharing-types |
1.2 ProbatioVault-ia-governance (5 modules)¶
| Module | Responsabilité | Chemins | Dépendances amont |
|---|---|---|---|
gov-6cbis | Nouvelle phase 6c.bis exécutée après 6c par /gov-impl : compare la liste cross_module_point_path extraite du plan avec git diff --name-only. Blocage step 7 si écart >0 (B1). | scripts/gov-6cbis.sh, scripts/lib/extract-cross-module-points.py, mise à jour .claude/commands/gov-impl.md | helper gov-interact.sh |
gov-gate-zerotest | Nouveau pré-check Gate 8 dans verdict-scoring : si project_code ∈ {app,backend} et test_file_count==0 (glob récursif DEC-01), force test_coverage=6.0 exact et CHECKING→NON_CONFORME (B2). | scripts/lib/gate8-zero-test.py, intégration scripts/run-quality-gates.sh, mise à jour .claude/commands/gov-gate.md | FSM Gate 8 §5.4 |
gov-assemble-companion | Enrichissement de assemble-prompt.sh : chargement de la source canonique companion (<source_story_id>-specification.md, sections ## 4. Invariants et ## Arbitrages — Vérification formelle post-step 1), construction du bloc stable ≤ 2 KiB avec source_story_id (B3). | scripts/assemble-prompt.sh, scripts/lib/load-companion-source.py, template bloc stable | résolution DEC-07 (front-matter besoin) |
gov-check-extensions | Nouvelle phase 4 de /gov-check-plan : script detect-plan-extensions.py comparant endpoints/headers/timeouts entre plan et contrats de la spec. Validation de schéma stricte D-299-20 avec rejet explicite invalid plan_extension_item.kind. Blocage Gate 5 si ≥1 UNRATIFIED ou kind invalide (B6). | scripts/detect-plan-extensions.py, mise à jour .claude/commands/gov-check-plan.md | gov-legal (pour ratification_ref) |
gov-docs-guardrails | Mises à jour documentaires : règle telemetry allowlist Zod stricte dans .claude/rules/learnings-universal.md (B4) + bloc obligatoire « Données résolues (pré-implémentation) » dans templates/prompts/6a Decomposition.md avec champ source humaine typé (B5). | .claude/rules/learnings-universal.md, templates/prompts/6a Decomposition.md, scripts/check-6a-block.py | n/a |
1.3 Module transverse (hors découpage agents)¶
| Module | Responsabilité | Chemins |
|---|---|---|
gov-legal | Vérification A8 : script validate-legal-approvals.py qui charge la preuve D-299-21 (YAML), vérifie présence ARB-7/ARB-8/RGPD-90J, approbations PO+LEGAL, unicité DEC-08, format approver_id DEC-06, existence effective des jira_comment_id via API Atlassian. | scripts/validate-legal-approvals.py, templates/outputs/legal-validation.yaml |
Justification du regroupement : gov-legal est utilisé à la fois par gov-check-extensions (pour ratification_ref) et par la vérification A8 elle-même, mais ne constitue pas un « agent step 6b » autonome au sens decomposition — il est porté conjointement par gov-check-extensions (les deux scripts vivent ensemble).
2. Flux techniques¶
2.1 F-299-01 — Qualification tests sharing (A1, INV-299-01/02)¶
- Collecte : le corpus
PD-298-tests.mdest figé par référence versionnée ; on en extrait les 45 scénarios contractuels. - Matérialisation : chaque scénario produit un fichier
src/sharing/**/__tests__/<domaine>.<scénario>.test.ts(ou.tsxselon le rendu React Native Testing Library). - Comptage de contrôle :
jest --listTests --testPathPattern='src/sharing/'doit retourner exactement 45 entrées. - Couverture :
jest --coverage --collectCoverageFrom='src/sharing/**/*.{ts,tsx}' --coverageThreshold='{"global":{"statements":80,"branches":80,"functions":80,"lines":80}}'. - Échec → NON_CONFORME remonté par l'exécuteur CI + blocage Gate 8 par
gov-gate-zerotestdès quetest_file_count=0(DEC-01) ou couverture <80%.
2.2 F-299-02 — Guard propriétaire CTA Partager (A2, INV-299-03)¶
- Source de propriété :
proof.ownerUserId(D-299-05) chargé parsharing-apivia hook existantuseProofDetail(proofId). - Source de l'utilisateur courant :
useAuth()→currentUser.id(même branded typeUserId). - Comparaison stricte dans
sharing-ui/guards/OwnershipGuard.tsx:isOwner = isValidUuid(ownerUserId) && isValidUuid(currentUser?.id) && ownerUserId === currentUser.id. - Rendu : le composant
ShareCTAest monté uniquement siisOwner === true. Aucun fallback (INV-299-03). - Cas invalide :
ownerUserIdoucurrentUser.idnon-UUID → CTA caché silencieusement + log techniqueSHARE_OWNERSHIP_MISMATCH(DEC-05).
2.3 F-299-03 — Auth réelle appels sharing (A3, INV-299-04)¶
- Acquisition :
SharingApiClient.buildAuthHeader()litauth_access_token(D-299-06) viauseAuth().getAccessToken()(API existanteProbatioVault-app/src/auth). - Construction :
Authorization: \Bearer ${token}`` avec un seul espace ASCII (conformité RFC 6750 interprétée en plus strict que D-299-07, voir DEC-05 / §7). - Validation avant émission : regex exécutée sur la chaîne finale
^Bearer [!-~]+$. Rejet =throw new SharingApiError('SHARE_AUTH_INVALID')sans émission réseau. - Masquage : tout log/telemetry/crash reporter applique
maskToken()qui remplace la portion aprèsBearerpar<REDACTED_TOKEN>(DEC-10). - Token manquant / invalide →
SharingApiError('SHARE_AUTH_MISSING'), navigation vers écran login si applicable.
2.4 F-299-04 — Telemetry PII-free allowlist Zod (A4, INV-299-05)¶
- Schéma canonique dans
src/sharing/telemetry/schemas/metadata.ts: Allowlist par défaut vide (D-299-09, §5.2metadata_allowlist_keys_count_default=0). Toute clé additionnelle future passe par une PR explicite qui étend ce schéma. logShareEvent({ action, metadata })valideaction(enum D-299-08) puismetadataviashareTelemetryMetadataSchema.parse(metadata).- Erreur Zod → l'événement est rejeté et une trace technique
TELEMETRY_SCHEMA_VIOLATIONest émise (DEC-05). Rien n'est persisté, rien n'est envoyé. - Initialisation : tous les sites d'appel existants qui passaient
{recipientEmail, ip, userAgent, ...}doivent être corrigés en parallèle (A4 exige zéro leak).
2.5 F-299-05 — Fallback maskIp fail-closed (A5, INV-299-06)¶
- Entrée
ip_input(D-299-10). Parsing viaipaddr.js(déjà dépendance PD-298). - Si parsing échoue (exception ou
ipaddr.isValid(input) === false) → retour littéral exactIP masquée indisponible(D-299-11). Comparaison par identité===. - Aucune restitution de l'entrée brute, ni de fragment (pas de substring, pas de hash).
- Test d'identité stricte dans
sharing-tests:expect(maskIp('<script>')).toBe('IP masquée indisponible').
2.6 F-299-06 — Blocage offline (A6, INV-299-07)¶
- Hook central
useNetworkGuard()danssharing-ui/hooks/useNetworkGuard.ts: s'abonne à@react-native-community/netinfoet exposeisConnected: boolean. - Tous les handlers sharing (
onCreateShare,onRevokeShare,onLoadShares,onLoadEvents) exécutentif (!netInfo.isConnected) throw new SharingError('SHARE_OFFLINE', t('sharing.offline_blocked')). - UI : l'erreur remonte au composant qui affiche un
ErrorBanneravec le libellé traduit. Aucun appel API n'est émis. netinfo_is_connected === nullest traité commefalse(fail-closed, conformément à D-299-12).
2.7 F-299-07 — 6c.bis cross-module (B1, INV-299-10/11)¶
/gov-implétape 6c termine → appelscripts/gov-6cbis.sh <story_id> <project>.- Extraction :
extract-cross-module-points.pylit la section## Mécanismes cross-moduledu plan et produit la listecross_module_point_path(D-299-16, regex ASCII POSIX). Sortie YAML dans/tmp/<story>-cross-module-expected.yaml. - Diff effectif :
git -C <project_path> diff --name-only origin/main...HEAD→ listegit_diff_path(D-299-17). - Comparaison ensembliste :
missing = expected - diff. Tolérance 0 (§5.2). - Journalisation : chaque exécution écrit une entrée
6cbisdans.gov-local.jsonaveccorrelation_id(D-299-22) UUID v4 généré viauuidgen, timestamp ISO8601, listemissing. missingnon vide → transition step 7 INTERDITE, le script retourne exit code 2 et un motif listant chaque chemin manquant.gov_signal_escaladeest appelé en mode Ringbearer.
2.8 F-299-08 — Gate 8 zéro test déterministe (B2, INV-299-12/13)¶
- À l'entrée de Gate 8 (
CHECKING),gov-gate-zerotests'exécute avant le scoring arithmétique. - Résolution du chemin projet : si
project_code ∈ {app,backend},project_root= dossier git correspondant ; sinon l'étape est un no-op (ERR-299-13). - Comptage :
find "$project_root/src" -type f \( -name '*.test.ts' -o -name '*.test.tsx' -o -name '*.spec.ts' -o -name '*.spec.tsx' \) | wc -l(DEC-01, DEC-02). - Si
test_file_count == 0: test_coverageest forcé à exactement6.0dans le verdict JSON, indépendamment de la valeur brute (peut remonter, descendre, ou remplacer une valeur non calculée).- Transition
CHECKING → NON_CONFORMEforcée même si la moyenne arithmétique des autres critères est>= 7.0. - Motif :
forced_by_zero_test_ruleconsigné dans le verdict avecraw_test_coveragearchivé pour auditabilité. - Sinon : scoring arithmétique standard inchangé (F-299-08 branche
else).
2.9 F-299-09 — Injection source canonique companion (B3, INV-299-14)¶
assemble-prompt.shlit le besoin de la story courante pour extrairesource_story_id(DEC-07, front-matter YAML).- Si présent :
load-companion-source.py <source_story_id>résout le chemin de la spec source (data/specs-index/<project>/epics/<domain>/<source>/index.yaml→specification_path).- Extraction des sections
## 4. Invariantset## Arbitrages — Vérification formelle post-step 1via regex de section Markdown (header de niveau 2 + contenu jusqu'au prochain header de niveau ≤ 2). - Concaténation :
<companion_block> = "source_story_id: " + id + "\n\n## Invariants de la source\n" + invariants_block + "\n\n## Arbitrages de la source\n" + arbitrages_block. - Contrôle de taille :
len(companion_block.encode('utf-8'))doit être dans[1, 2048](DEC-03). Hors bornes → rejet avec exit 1 (ERR-299-11). - Si absent : la story n'est pas companion, aucune injection (no-op, pas d'erreur).
- Le bloc est inséré en tête du prompt reviewer, après le template stable, avant les documents d'entrée spécifiques — cohérent avec
workflow-rules.md(cache-first).
2.10 F-299-10 — detect-plan-extensions (B6, INV-299-17)¶
/gov-check-planatteint la phase 4 → appelscripts/detect-plan-extensions.py <plan_path> <spec_path>.- Extraction plan : parse des sections « endpoints », « headers », « timeouts » (conventions de section Markdown documentées dans
.claude/rules/workflow-rules.md). - Extraction spec : parse des tableaux de contrats §5.1 / sections équivalentes.
- Diff par clé : pour chaque endpoint/header/timeout du plan, recherche de la même clé dans la spec. Absence → item
{kind, key, status, ratification_ref?}. - Validation de schéma stricte :
kind ∈ {endpoint, header, timeout}— toute autre valeur → exit 2 + messageinvalid plan_extension_item.kind.status ∈ {RATIFIED, UNRATIFIED}.- Si
status=RATIFIEDetratification_refvide → reclassement enUNRATIFIED_MISSING_PROOF(DEC-04). - Blocage : tout item
UNRATIFIED*ou erreur de schéma → exit 1 avec liste des items + motif. Message explicite :gate5_blocked_by_unratified_extensions. - Artefact : rapport JSON sauvegardé dans
data/specs-index/<project>/epics/<domain>/<story>/plan-extensions.yaml(même format pour audits futurs).
2.11 F-299-11 — Validation A8 traçable (INV-299-09)¶
- Préalable : l'auteur humain remplit
docs/epics/<domain>/<story>/PD-299-legal-approvals.yamlavec 3 entrées (ARB-7,ARB-8,RGPD-90J). validate-legal-approvals.py <legal_yaml>exécute :- Présence des 3
text_id. - Pour chaque entrée :
approvals.POetapprovals.LEGALavec{approver_id, approved_at, jira_comment_id}. approver_iddiscriminé DEC-06 (email via regex RFC 5322 simplifiée ou username Jira regex^[A-Za-z0-9][A-Za-z0-9._-]{2,63}$).approved_atparsé ISO8601 (dateutil.parser.isoparse).jira_comment_idnon vide + existence effective viaGET /rest/api/3/issue/<story>/comment/<id>(token Jira CLAUDE.local.md). 404 → rejet.- Unicité DEC-08 :
approver_id_PO != approver_id_LEGALetjira_comment_id_PO != jira_comment_id_LEGAL. - Sortie JSON :
{assurance_level: "traceability_only", verdict: "PASS|FAIL", details: [...]}(DEC-09). - A8 est conforme si et seulement si le verdict est
PASSpour les 3 entrées.
2bis. Diagramme de dépendances agents (step 6b)¶
graph LR
subgraph Wave1_App["Wave 1 — ProbatioVault-app (parallélisables)"]
AT[sharing-types<br/>(existant PD-298)]
AE[sharing-telemetry<br/>A4 A5]
AA[sharing-api<br/>A3]
AU[sharing-ui<br/>A2 A6 A7]
end
subgraph Wave2_Tests["Wave 2 — Tests app"]
STS[sharing-tests<br/>A1]
end
subgraph Wave1_Gov["Wave 1 — ProbatioVault-ia-governance (parallélisables)"]
G6[gov-6cbis<br/>B1]
G8[gov-gate-zerotest<br/>B2]
GC[gov-assemble-companion<br/>B3]
GP[gov-check-extensions<br/>B6]
GD[gov-docs-guardrails<br/>B4 B5]
end
subgraph Wave3_Legal["Wave 3 — A8 Legal"]
LEG[gov-legal<br/>A8]
end
AT --> AE
AT --> AA
AE --> AU
AA --> AU
AE --> STS
AA --> STS
AU --> STS
GP --> LEG
G6 -.shared helper.-> GH[gov-interact.sh<br/>existant]
G8 -.shared helper.-> GH Waves d'exécution :
- Wave 1 (parallèle) : 4 agents app + 5 agents gov exécutables en parallèle (pas de dépendance cross-agent ni cross-projet). Les modules app s'appuient sur
sharing-typesdéjà livré par PD-298. - Wave 2 (séquentielle après Wave 1 app) :
sharing-testsqui exécute les 4 modules app. - Wave 3 (séquentielle après Wave 1 gov) :
gov-legalqui est consommé pargov-check-extensionspourratification_refet utilisé seul pour A8.
2ter. Mécanismes cross-module (OBLIGATOIRE)¶
Le flux sharing interagit avec le module preuves (ProbatioVault-app/src/proofs) dont une route/écran doit être protégée.
| Élément | Détail |
|---|---|
| Routes/écrans de l'autre module à protéger | Écran ProofDetailScreen (src/proofs/screens/ProofDetailScreen.tsx) qui ouvre le CTA ShareCTA et navigue vers ShareCreateScreen. |
| Controller/méthode | ProofDetailScreen rendu par ProofsStackNavigator (méthode renderDetail(props)). |
| Effet du guard | Le sous-composant ShareCTA est conditionné par OwnershipGuard (sharing-ui/guards/OwnershipGuard.tsx) : non-rendu si ownerUserId !== currentUser.id. |
| Mécanisme de jointure cross-module | proof.ownerUserId (champ déjà exposé par useProofDetail dans proofs-api) consommé par sharing-ui. Aucun schéma SQL (mobile). |
| Scope d'enregistrement | Local à ProofDetailScreen — pas un guard global de navigation. |
| Exceptions d'accès | Aucune. La spec ne définit pas de rôle spécifique ; aucun contournement admin n'est autorisé. |
cross_module_point_path attendus dans le diff (6c.bis) :
ProbatioVault-app/src/proofs/screens/ProofDetailScreen.tsx(injection du guard)ProbatioVault-app/src/sharing/guards/OwnershipGuard.tsx(nouveau composant)ProbatioVault-app/src/sharing/guards/index.ts(export)
3. Mapping invariants → mécanismes¶
| Invariant ID | Exigence | Mécanisme | Composant | Observable | Risque |
|---|---|---|---|---|---|
| INV-299-01 | 45 tests contractuels Jest sur src/sharing/ | Matérialisation F-299-01 + contrôle jest --listTests = 45 | sharing-tests | Sortie commande Jest = 45 lignes | Dérive du corpus PD-298-tests non détectée |
| INV-299-02 | Couverture src/sharing/ ≥ 80% | coverageThreshold Jest + CI pipeline | sharing-tests | Rapport coverage-summary.json | Flaky coverage dû aux snapshots React Native |
| INV-299-03 | CTA visible si ownerUserId == currentUser.id | OwnershipGuard rendant conditionnellement ShareCTA (F-299-02) | sharing-ui | UI snapshot : présence/absence du nœud ShareCTA | Regression propriétaire si futur refactor ProofDetailScreen |
| INV-299-04 | Header Authorization conforme D-299-07 | SharingApiClient.buildAuthHeader() + regex de sortie (F-299-03) | sharing-api | Trace réseau Jest-mock (nock) | Token en clair si DEC-10 contourné |
| INV-299-05 | metadata hors allowlist rejetée | shareTelemetryMetadataSchema Zod strictObject({}) (F-299-04) | sharing-telemetry | Exception Zod capturée + log TELEMETRY_SCHEMA_VIOLATION | Élargissement silencieux du schéma dans une PR future |
| INV-299-06 | maskIp('invalid') === 'IP masquée indisponible' | Fallback littéral dans maskIp (F-299-05) | sharing-telemetry (masking) | Test d'égalité stricte | Dépendance ipaddr.js qui retournerait silencieusement une valeur partielle |
| INV-299-07 | Actions sharing bloquées si netinfo_is_connected !== true | useNetworkGuard + throw SharingError('SHARE_OFFLINE') (F-299-06) | sharing-ui | Test unitaire + e2e avec NetInfo mocké | Handler nouveau ajouté sans check |
| INV-299-08 | useProofShares jamais invoqué avec proof_id vide | Hook wrapper useSafeProofShares qui vérifie proofId avant appel | sharing-ui (hooks) | Log HOOK_SKIPPED_INVALID_PROOF_ID + absence appel | Call-site oublié |
| INV-299-09 | Preuve D-299-21 complète et traçable | validate-legal-approvals.py (F-299-11) | gov-legal | Sortie JSON verdict=PASS + vérif API Atlassian | Commentaire Jira supprimé après validation (out of scope) |
| INV-299-10 | 6c.bis exécuté après 6c | Hook dans .claude/commands/gov-impl.md + log audit séquentiel (F-299-07) | gov-6cbis | Journal audit .gov-local.json avec timestamps ordonnés | Skip manuel du script |
| INV-299-11 | Step 7 bloqué si point cross-module manquant | Exit code 2 de gov-6cbis.sh (F-299-07) | gov-6cbis | Sortie stderr + état workflow .gov-local.json | Faux positif si parsing plan incomplet |
| INV-299-12 | test_coverage forcé 6.0 si test_file_count=0 | gov-gate-zerotest (F-299-08, DEC-01/02) | gov-gate-zerotest | Verdict JSON Gate 8 avec raw_test_coverage distinct | Glob non récursif résiduel → résolu par DEC-01 |
| INV-299-13 | Transition CHECKING→NON_CONFORME forcée zéro test | Priorité du pré-check sur scoring arithmétique | gov-gate-zerotest | Transition FSM enregistrée + motif forced_by_zero_test_rule | Ordre d'appel modifié silencieusement |
| INV-299-14 | Prompt companion enrichi source canonique + source_story_id | F-299-09 + contrôle taille DEC-03 | gov-assemble-companion | Bloc stable présent dans le prompt reviewer, assertion regex | Absence front-matter (DEC-07) → no-op loggué |
| INV-299-15 | Règle telemetry dans learnings-universal.md | Ajout paragraphe + contrôle textuel | gov-docs-guardrails | grep -c 'allowlist Zod stricte' learnings-universal.md >= 1 | Réécriture du fichier sans conserver la règle |
| INV-299-16 | Bloc « Données résolues » dans template 6a | Ajout section + check-6a-block.py | gov-docs-guardrails | grep -c 'Données résolues' '6a Decomposition.md' >= 1 | Modification concurrente du template |
| INV-299-17 | detect-plan-extensions bloque UNRATIFIED + kind invalide | F-299-10 + DEC-04 | gov-check-extensions | Exit codes distincts (1=UNRATIFIED, 2=kind invalide) | Extension furtive non parsée si section plan non canonique |
| INV-299-18 | FSM Gate 8 fermée §5.4 | Table de transitions dans gov-gate-zerotest + rejet explicite des transitions non listées | gov-gate-zerotest | Journal transitions FSM, tests TC-NOM-19/20/21 | Ajout d'une transition hors table non détecté si non testée |
4. Mapping critères d'acceptation → mécanismes¶
| Critère ID | Mécanisme(s) | Composant | Observable | Risque |
|---|---|---|---|---|
| CA-299-01 | F-299-01 matérialisation | sharing-tests | jest --listTests = 45 | Corpus PD-298 évolue sans sync |
| CA-299-02 | F-299-01 coverage threshold | sharing-tests | coverage-summary.json >= 80 | Snapshots flaky |
| CA-299-03 | F-299-02 OwnershipGuard | sharing-ui | Test rendu conditionnel | Regex UUID trop permissive |
| CA-299-04 | F-299-03 buildAuthHeader + regex | sharing-api | nock inspection header | Middleware fetch custom contourne |
| CA-299-05 | F-299-04 Zod strictObject | sharing-telemetry | Exception Zod test | Élargissement schema futur |
| CA-299-06 | F-299-05 fallback littéral | sharing-telemetry | Test identité === | Traduction i18n du littéral interdite |
| CA-299-07 | F-299-06 useNetworkGuard | sharing-ui | Test handler throw | Nouveau handler sans check |
| CA-299-08 | useSafeProofShares wrapper | sharing-ui | Test mount avec proofId=undefined | Hook interne bypass wrapper |
| CA-299-09 | F-299-07 6c.bis | gov-6cbis | Exit code 2 | Plan sans section cross-module |
| CA-299-10 | F-299-08 force 6.0 | gov-gate-zerotest | Verdict JSON | Ordre des checks modifié |
| CA-299-11 | F-299-08 priorité transition | gov-gate-zerotest | Transition FSM | Retour après re-gate non atomique (attendu) |
| CA-299-12 | F-299-09 injection companion | gov-assemble-companion | Assertion regex bloc stable | Source manquante DEC-07 |
| CA-299-13 | Règle textuelle ajoutée | gov-docs-guardrails | grep exact sur libellé | Fichier overwrite |
| CA-299-14 | Bloc template 6a + champ source humaine | gov-docs-guardrails | grep + contrôle format | Migration template future |
| CA-299-15 | F-299-10 validation schéma + UNRATIFIED | gov-check-extensions | Exit codes ½ distincts | Parsing plan non canonique |
| CA-299-16 | F-299-11 validation A8 avec Atlassian API | gov-legal | JSON verdict=PASS | Commentaire Jira supprimé |
5. Mapping tests (TC-*) → mécanismes + observables¶
5.1 Tests nominaux¶
| Test ID | Référence spec | Mécanisme(s) | Point(s) d'observation | Niveau |
|---|---|---|---|---|
| TC-NOM-01 | INV-299-01, CA-299-01 | F-299-01 + jest --listTests | Sortie commande Jest | Unit |
| TC-NOM-02 | INV-299-02, CA-299-02 | F-299-01 coverage threshold | coverage-summary.json | Unit |
| TC-NOM-03 | INV-299-03, CA-299-03 | F-299-02 OwnershipGuard | React Native Testing Library queries | Unit |
| TC-NOM-04 | INV-299-04, CA-299-04 | F-299-03 buildAuthHeader | nock + inspection header | Integration |
| TC-NOM-05 | INV-299-05, D-299-08/09 | F-299-04 Zod parse | Exception Zod + compteur log | Unit |
| TC-NOM-06 | INV-299-06, CA-299-06 | F-299-05 fallback littéral | Test === sur sortie | Unit |
| TC-NOM-07 | INV-299-07, CA-299-07 | F-299-06 + NetInfo mock | Assertion throw + message | Unit + e2e |
| TC-NOM-08 | INV-299-08, CA-299-08 | useSafeProofShares wrapper | Log hook skipped | Unit |
| TC-NOM-09 | F-299-07, D-299-22 | F-299-07 ordre 6c→6c.bis | Audit .gov-local.json | Integration (shell) |
| TC-NOM-10 | INV-299-11, ERR-299-09 | F-299-07 exit code 2 | Sortie script + motif | Integration |
| TC-NOM-11 | INV-299-12, CA-299-10 | F-299-08 force 6.0 | Verdict JSON | Integration |
| TC-NOM-12 | INV-299-13, §5.4 | F-299-08 priorité pré-check | Transition FSM logs | Integration |
| TC-NOM-13 | INV-299-14 | F-299-09 bloc stable + taille | Regex bloc + wc -c | Integration |
| TC-NOM-14 | INV-299-15 | grep règle textuelle | Sortie grep -c | Contrôle doc |
| TC-NOM-15 | INV-299-16 | grep bloc 6a + champ source humaine | Sortie grep -c | Contrôle doc |
| TC-NOM-16 | INV-299-17, CA-299-15 | F-299-10 blocage UNRATIFIED | Exit 1 script | Integration |
| TC-NOM-17 | INV-299-17 | F-299-10 branche RATIFIED valide | Exit 0 + rapport | Integration |
| TC-NOM-18 | INV-299-09, D-299-21 | F-299-11 validation complète | JSON verdict=PASS + Atlassian 200 | Integration |
| TC-NOM-19 | INV-299-18, §5.4 | Table transitions FSM | Journal transitions | Integration |
| TC-NOM-20 | INV-299-18 états terminaux | Rejet explicite dans pré-check | Rejet + état inchangé | Integration |
| TC-NOM-21 | INV-299-18 NC→PENDING | Réévaluation séquentielle | Trace exécution des checks | Integration |
5.2 Tests d'erreur¶
| Test ID | Référence spec | Mécanisme(s) | Observable | Niveau |
|---|---|---|---|---|
| TC-ERR-01 | ERR-299-01, D-299-01 | Validation story_id côté wrapper gov-6cbis.sh | Rejet immédiat + exit ≠ 0 | Integration |
| TC-ERR-02 | ERR-299-02, INV-299-03/08 | OwnershipGuard + useSafeProofShares | CTA caché + log | Unit |
| TC-ERR-03 | ERR-299-03 | SharingApiClient token absent → throw | Exception typée | Unit |
| TC-ERR-04 | ERR-299-04, D-299-07 | Regex header + rejet | Exception + motif SHARE_AUTH_INVALID | Unit |
| TC-ERR-05 | ERR-299-05, INV-299-05 | Zod parse fail | Exception Zod | Unit |
| TC-ERR-06 | ERR-299-06, D-299-11 | F-299-05 fallback | Test === | Unit |
| TC-ERR-07 | ERR-299-07, D-299-12 null | useNetworkGuard traite null comme false | Throw offline | Unit |
| TC-ERR-08 | ERR-299-08, INV-299-12/13 | F-299-08 + FSM | Verdict 6.0 + NON_CONFORME | Integration |
| TC-ERR-09 | ERR-299-09, D-299-17 | F-299-07 diff ensembliste | Exit 2 + liste manquants | Integration |
| TC-ERR-10 | ERR-299-10, INV-299-17 | F-299-10 UNRATIFIED | Exit 1 script | Integration |
| TC-ERR-11 | ERR-299-11, D-299-19 | F-299-09 contrôle taille/extraction | Exit 1 companion_block_invalid | Integration |
| TC-ERR-12 | ERR-299-12, INV-299-09 | F-299-11 validation A8 | verdict=FAIL + détails | Integration |
| TC-ERR-13 | ERR-299-13, F-299-08 | No-op pré-check si project_code hors {app,backend} | Verdict = scoring standard | Integration |
| TC-ERR-14 | ERR-299-14, INV-299-18 | Rejet transitions hors §5.4 | État inchangé + motif | Integration |
| TC-ERR-15 | ERR-299-15, D-299-20 | F-299-10 schéma strict | Exit 2 + message invalid plan_extension_item.kind | Integration |
5.3 Tests de non-régression¶
| Test ID | Objet | Mécanisme(s) de défense | Observable | Niveau |
|---|---|---|---|---|
| TC-NR-01 | Stabilité 45 tests + coverage | Rerun jest après changements | Sortie identique | Unit |
| TC-NR-02 | Guard propriétaire stable | Snapshot rendu ProofDetailScreen | Pas de régression CTA | Unit |
| TC-NR-03 | Déterminisme cap 6.0 | Rerun avec raw coverage varié | Score final toujours 6.0 | Integration |
| TC-NR-04 | Bloc companion stable | Baseline hash + comparaison | Hash stable post-update template | Integration |
| TC-NR-05 | Blocage extensions persistant | Rerun detect-plan-extensions | Exit code inchangé | Integration |
| TC-NR-06 | Règles doc persistantes | grep périodique CI | Compteur > 0 stable | Contrôle doc |
| TC-NR-07 | Fermeture FSM durable | Test exhaustif transitions terminales | Aucune transition sortante acceptée | Integration |
| TC-NR-08 | Ordre séquentiel NC→PENDING | Trace ordonnée des checks | Ordre conservé | Integration |
| TC-NR-SUPP-01 (ajouté) | Non-leak auth_access_token dans logs/erreurs | DEC-10 maskToken() systématique | Inspection console.log / Sentry mock | Unit |
5.4 Tests négatifs/adversariaux¶
| Test ID | Mécanisme(s) | Observable | Niveau |
|---|---|---|---|
| TC-NEG-01 | F-299-04 Zod .strict | Rejet PII | Unit |
| TC-NEG-02 | F-299-03 regex header + RFC 6750 strict | Rejet espaces multiples/CRLF | Unit |
| TC-NEG-03 | F-299-05 fallback | Rejet <script> | Unit |
| TC-NEG-04 | F-299-09 contrôle taille > 2 KiB | Rejet size limit exceeded | Integration |
| TC-NEG-05 | F-299-10 schéma strict | Rejet kind=cookie | Integration |
| TC-NEG-06 | F-299-02 validation UUID | CTA caché | Unit |
| TC-NEG-07 | F-299-10 mixte | Blocage + item fautif listé | Integration |
| TC-NEG-08 | FSM Gate 8 états terminaux | Rejet transition sortante | Integration |
| TC-NEG-09 | Glob récursif DEC-01 | test_file_count=1 si foo.spec.tsx sous src/sharing/__tests__/ | Integration |
6. Gestion des erreurs¶
6.1 Table des codes d'erreur (DEC-05)¶
| Code | Origine | Canal | Signification | Action |
|---|---|---|---|---|
SHARE_OWNERSHIP_MISMATCH | sharing-ui | Log technique (pas UI) | CTA caché suite à comparaison D-299-05 KO | Silencieux côté UI |
SHARE_AUTH_MISSING | sharing-api | Exception SharingApiError | Token absent ou expiré | Redirection login |
SHARE_AUTH_INVALID | sharing-api | Exception SharingApiError | Regex header KO (D-299-07) ou token contenant espace | Rejet requête + log <REDACTED_TOKEN> |
TELEMETRY_SCHEMA_VIOLATION | sharing-telemetry | Log technique + Sentry tag | Allowlist Zod rejette metadata | Événement non émis |
SHARE_OFFLINE | sharing-ui | SharingError + ErrorBanner | netinfo_is_connected !== true | UI bloquée |
HOOK_SKIPPED_INVALID_PROOF_ID | sharing-ui | Log technique | useSafeProofShares appelé sans proofId valide | Hook no-op |
SHARE_IP_MASK_UNAVAILABLE | sharing-telemetry | Retour littéral D-299-11 | Entrée IP invalide | Substitution fallback |
gate5_blocked_by_unratified_extensions | gov-check-extensions | Exit 1 + stderr | Extension plan→spec UNRATIFIED | Blocage Gate 5 |
invalid plan_extension_item.kind | gov-check-extensions | Exit 2 + stderr | kind hors enum | Blocage Gate 5 |
forced_by_zero_test_rule | gov-gate-zerotest | Verdict JSON + log | Cap zéro test appliqué | NON_CONFORME forcé |
step7_blocked_missing_cross_module | gov-6cbis | Exit 2 + stderr | Points cross-module manquants | Blocage step 7 |
companion_block_invalid | gov-assemble-companion | Exit 1 + stderr | Bloc companion hors [1, 2048] bytes ou sections absentes | Prompt non généré |
legal_validation_failed | gov-legal | Verdict JSON FAIL | Preuve A8 incomplète/non-unique/commentaire absent | A8 non conforme |
6.2 Propagation et isolement¶
- Côté app : toutes les erreurs typées dérivent de
SharingError. Le wrapper React NativeErrorBoundarycapture l'erreur dans chaque écran et afficheErrorBannersans révéler de détails techniques. - Côté gov : chaque script shell/Python retourne un exit code ≠ 0 pour tout blocage, avec un message stderr contenant le code DEC-05. L'orchestrateur
/gov*capture l'exit code et interrompt la transition concernée. - Corrélation : chaque événement gouvernance inclut un
correlation_idUUID v4 (D-299-22) généré à l'entrée de Gate 8/6c.bis/phase 4 et propagé dans tous les sous-appels.
7. Impacts sécurité¶
7.1 Risques identifiés¶
| Risque | Source (écart revue) | Mitigation | Journalisation |
|---|---|---|---|
Leak du token auth_access_token dans logs/crashreports | E-SEC-01, E-IST-06 | maskToken() systématique (DEC-10) + TC-NR-SUPP-01 | Sentry breadcrumbs filtrés |
| Confusion « non-répudiation » juridique | E-AMB-05, E-CON-03, E-NT-01, E-SEC-02 | assurance_level=traceability_only dans sortie JSON gov-legal (DEC-09) | Artefact legal-validation.yaml horodaté |
| Mono-acteur PO+LEGAL | E-NT-04, E-SEC-03 | Unicité DEC-08 dans validate-legal-approvals.py | Rapport détaillé A8 |
Homoglyphe/Unicode approver_id | E-SEC-07, E-SEC-08 | Regex ASCII strict + normalisation Unicode NFKC avant comparaison (protection anti-homoglyphes basique) | Log des substitutions Unicode détectées |
| Ratification fantôme (RATIFIED sans preuve) | E-SEC-06, E-NT-05 | DEC-04 reclassement UNRATIFIED_MISSING_PROOF + blocage | Rapport plan-extensions.yaml |
| Glob non récursif bloquant injuste | E-AMB-03, E-SEC-04 | DEC-01 glob récursif documenté + TC-NEG-09 | test_file_count tracé + raw_test_coverage archivé |
Injection CRLF dans auth_access_token | E-HD-03 | Regex D-299-06 + rejet amont + regex header finale | Exception SHARE_AUTH_INVALID |
| Interopérabilité RFC 6750 (multi-espaces) | E-SEC-05, E-AMB-12 | Émission à un espace unique ET regex de sortie ^Bearer [!-~]+$ (plus strict que D-299-07) | Rejet silencieux d'espaces multiples en émission |
7.2 Points de conformité¶
- RGPD : la règle telemetry allowlist Zod stricte (INV-299-05) élimine toute PII involontaire ; la rétention 90 jours de la notice RGPD est une donnée textuelle validée humainement (hors périmètre vérification automatique §10.2 spec).
- Art. II CONSTITUTIONAL (séparation des pouvoirs) : la règle d'unicité DEC-08 matérialise l'impossibilité d'auto-approbation PO+LEGAL sur un même texte.
- Art. I CONSTITUTIONAL (quality gates) : la règle B2 zéro test rend la Gate 8 plus conservatrice sans introduire de contournement.
7.3 Journalisation requise¶
correlation_id(D-299-22) dans chaque entrée d'audit (6c.bis, Gate 8, phase 4, validation A8).- Bundle probatoire par story : rapport coverage, comptage tests, verdict Gate 8, rapport 6c.bis, rapport
plan-extensions.yaml, rapportlegal-validation.yaml. Agrégé viascripts/gov-compounderexistant.
8. Hypothèses techniques¶
| ID | Hypothèse | Impact si faux |
|---|---|---|
| H-T-01 | Le glob récursif **/*.{test,spec}.{ts,tsx} évalué via find est cohérent avec la convention de test de ProbatioVault-app et ProbatioVault-backend (tests sous src/**/__tests__/ ou src/**/*.test.ts). | Faux positif si tests stockés hors src/ (ex. e2e/) — à vérifier dans Q-299 ouverte. |
| H-T-02 | Le project_code résout exactement un chemin git local (répertoire ProbatioVault-app, ProbatioVault-backend, ProbatioVault-ia-governance). | Scoring faussé si alias de chemin multiples. |
| H-T-03 | La borne min de companion_injected_block à 1 byte est acceptable par tous les flux reviewer (pas de tolérance 0). | Sur-contrainte si un reviewer attend vraiment un bloc vide (non rencontré en pratique). |
| H-T-04 | Un item RATIFIED sans ratification_ref est toujours une erreur (jamais un état transitoire légitime). | Blocage intempestif sur états transitoires de migration — non rencontré. |
| H-T-05 | Une classe d'erreur typée TypeScript + code DEC-05 est suffisante pour satisfaire « message explicite » côté auditeurs. | À confirmer en review Gate 5 (risque mineur). |
| H-T-06 | Le discriminateur @ pour approver_id email/username couvre tous les cas usuels ProbatioVault. | Usernames contenant @ non prévus (exotique). |
| H-T-07 | Le front-matter YAML source_story_id dans PD-XX-besoin.md est la convention retenue pour déclarer une story companion. | Si convention différente adoptée, B3 est no-op pour toutes les stories. |
| H-T-08 | L'unicité PO vs LEGAL (DEC-08) ne conflicte pas avec des approbations groupées légitimes (un même PO peut avoir un rôle dual dans d'autres contextes, pas sur un même texte A8). | Blocage d'approbations rares mais légitimes (surcoût documentaire acceptable). |
| H-T-09 | Le libellé assurance_level=traceability_only en sortie JSON est suffisant pour que les auditeurs externes ne sur-interprètent pas le vocabulaire « non-répudiation » textuel de la spec. | Résolu humainement en audit si nécessaire. |
| H-T-10 | La substitution <REDACTED_TOKEN> via maskToken() est appliquée avant toute sérialisation (incluant Sentry/crash reports Expo). | Risque de leak résiduel si un logger tiers sérialise avant passage par SharingApiError. |
| H-T-11 | Les commentaires Jira référencés par jira_comment_id sont accessibles via l'API Atlassian avec le token CLAUDE.local.md (scope read). | A8 non vérifiable si droits insuffisants (H-299-05 spec). |
| H-T-12 | Le CLI jest est invocable depuis ProbatioVault-app sans config spéciale (conformité PD-298). | À vérifier lors du scaffolding sharing-tests. |
Hypothèses spec reprises (H-299-01 à H-299-05 du §9 spec) intégrées implicitement : H-T-07 couvre H-299-01, H-T-02 couvre H-299-03, H-T-11 couvre H-299-05.
9. Points de vigilance (risques, dette, pièges)¶
9.1 Ambiguïtés spec résolues par décision (à re-confirmer en Gate 5)¶
- DEC-01/DEC-02 glob récursif et échelle projet : la spec laissait les deux dimensions ambigües (E-AMB-03, E-AMB-04). La décision ici est la plus sûre (récursif + projet) mais doit être validée explicitement par le PO en Gate 5 ; sinon risque d'écart interprétatif avec l'équipe d'audit.
- DEC-03 borne min 1 byte : contredit la lecture littérale de §5.2 (min=0 KiB). Alignement avec §5.1 assumé ; à ratifier par Gate 5.
- DEC-04
RATIFIEDsansratification_ref: la spec autorise le champ optionnel mais DEC-04 le rend obligatoire pourRATIFIED. Décision plus stricte = plus sûre, à ratifier. - DEC-05 codes d'erreur fermés : extension spec non ratifiée (au sens B6 du flux !). Méta-risque : l'introduction de ces codes peut elle-même déclencher
detect-plan-extensionsphase 4 → les codes DOIVENT être listés comme « headers/timeouts/endpoints » si applicable, sinon classés comme « constantes applicatives hors portéedetect-plan-extensions» (documenté dansgov-check-extensions).
9.2 Dettes techniques assumées¶
- Non-répudiation « minimale » ambiguë : la sortie JSON
traceability_onlydocumente la limite (DEC-09) mais le vocabulaire spec reste confus. Dette documentaire portée dans le REX → proposer une réécriture de la spec en itération future. - Homoglyphes Unicode : mitigation basique NFKC seulement ; pas de dictionnaire homoglyphe exhaustif. Risque résiduel accepté.
- Idempotence
detect-plan-extensions(E-HD-02) : script déterministe en entrée mais pas d'état persistant ; chaque run recrée le rapport. OK tant que Gate 5 ne conserve pas d'historique entre runs. - Atomicité non garantie en re-gate concurrentiel (E-HD-05) : l'implémentation suppose un seul processus Gate 8 par story à un instant donné (verrouillage implicite via
.gov-local.json).
9.3 Pièges spécifiques à l'intégration¶
gov-6cbis.shparsing du plan : la section « Mécanismes cross-module » doit être structurée identiquement àPD-299-plan.md§2ter. Un plan sans cette section produit un no-op silencieux →extract-cross-module-points.pydoit rejeter les plans dépourvus de section avec un code d'erreur explicite.- Ordre d'exécution Gate 8 :
gov-gate-zerotestdoit s'exécuter avant tout autre check sinon la priorité INV-299-12 peut être contournée. Test TC-NOM-21 vérifie cet ordre. assemble-prompt.shcache-first : l'ajout du bloc companion doit respecter l'ordre contenu statique → dynamique (workflow-rules.md). Le bloc companion, bien que dynamique parsource_story_id, reste stable pour une même story — à placer dans la portion cacheable.
9.4 Risques projet¶
- Le scope couvre 2 projets et 1 scope partiel backend : coordination inter-repos nécessaire en step 6b. Les agents gov et app sont indépendants (pas de dépendance cross-projet directe) mais partagent la story Jira.
- 9 modules en step 6b ≈ pression sur le prompt caching : conserver strictement l'ordre d'assemblage.
- Gate 8 sur la story PD-299 elle-même : en mode gouvernance,
test_file_countest calculé surProbatioVault-ia-governance(=ia-governance→ hors scope INV-299-12), donc la règle B2 ne s'applique pas à PD-299 côté gov — à contrôler pour éviter un faux positif récursif.
10. Hors périmètre¶
Alignement avec la spec §2 « Exclu » et §10.2 « Points hors périmètre vérification automatique » :
- Refonte globale du module sharing (hors A1-A8).
- Modification des règles de scoring Gate 3 et Gate 5 (seule Gate 8 est modifiée via B2).
- Automatisation de la décision juridique de fond.
- Vérification automatique de la validité juridique substantielle des textes ARB-7/ARB-8/RGPD-90j.
- Vérification cryptographique de l'intention des approbateurs (au-delà de la trace Atlassian).
- Vérification automatique de la pertinence métier des arbitrages PO.
- Écriture sur des routes du module preuves autres que le point d'intégration
ProofDetailScreen(le guard est additif, pas intrusif). - Implémentation d'un mécanisme d'expiration applicative pour la rétention 90 jours (donnée textuelle §5.3 spec).
- Intégration de nouveaux MCP, de nouveaux modèles LLM ou de nouvelles infrastructures.
11. Périmètre de test (OBLIGATOIRE)¶
| Niveau de test | In scope | Hors scope (justification) |
|---|---|---|
| Unitaire | Tous les composants des 9 modules (app + gov). Coverage ≥ 80% src/sharing/. | — |
| Intégration | Interactions sharing-api ↔ sharing-ui ↔ sharing-telemetry (via sharing-tests). Scripts shell /gov-impl, /gov-check-plan, /gov-gate couverts par harnais Bats existant + tests Python pytest pour les scripts Python. | — |
| E2E | Flux CTA Partager bout en bout via Detox (scénario : login → ouverture preuve → Partager → offline → blocage). | Out of scope uniquement si Detox indisponible en CI — auquel cas scénario reporté dans un ticket PD-299-E2E, sinon in scope. |
| Performance | — | Aucune exigence de perf explicite dans spec PD-299. |
| Sécurité | Tests négatifs TC-NEG-01 à TC-NEG-09 + TC-NR-SUPP-01 (non-leak token). | Audit sécurité externe : hors périmètre. |
Justifications hors scope : aucune exclusion autre que performance (non demandée) et audit sécurité externe (hors CI). Tous les autres niveaux sont couverts.
12. Code contracts similaires (réutilisation décisions)¶
Références principales identifiées a priori :
- PD-298
sharing-masking: patterns de déterminismemaskIpet fallback fermé — réutilisé à l'identique pour INV-299-06. - PD-298
sharing-validation: branded types + regex stricts — réutilisés pour D-299-05 (UUID v4), D-299-07 (header Bearer). - PD-297
ontologie-enrichissement: patterns d'extraction de sections Markdown — réutilisés pourload-companion-source.pyetextract-cross-module-points.py. - PD-296
formal-check.sh: convention exit code + verdict JSON +correlation_id— réutilisée pourgov-6cbis.sh,detect-plan-extensions.py,validate-legal-approvals.py.
13. Références¶
- Epic :
Référence épique(valeur métier non renseignée, Q-299-01). - Jira : PD-299.
- Repos concernés :
ProbatioVault-app,ProbatioVault-ia-governance(scope B2 supervisantProbatioVault-backend). - Documents associés :
- PD-299-besoin.md
- PD-299-specification.md
- PD-299-tests.md
- PD-299-specification-review.md
- PD-298-code-contracts.yaml
- gov-impl.md
- gov-gate.md
- gov-check-plan.md
- assemble-prompt.sh
- workflow-rules.md
- learnings-universal.md