PD-272 — Immutabilité DB des preuves composites (legal_composite_proofs)¶
1. Objectif¶
Contractualiser l'exigence d'immutabilité au niveau PostgreSQL pour toute preuve composite persistée dans legal_composite_proofs, afin de garantir qu'après création : - toute tentative de modification est rejetée, - toute tentative de suppression est rejetée, - la création initiale reste autorisée.
Cette exigence matérialise PROOF-12 et aligne l'implémentation avec les invariants formels (TLA+, Alloy, Z).
2. Périmètre / Hors périmètre¶
Inclus¶
- Protection DB inconditionnelle de la table
legal_composite_proofscontreUPDATEetDELETE. - Rejet explicite avec message d'erreur métier contractualisé :
legal_composite_proofs: modification interdite — preuve immutablelegal_composite_proofs: suppression interdite — preuve immutable- Maintien de l'autorisation
INSERT. - Vérification de conformité par passage du check Prolog
check_proof_immutable_trigger. - Non-régression des tests existants.
Exclu¶
- Modification de l'entité TypeORM
LegalCompositeProof. - Modification du service
LegalCompositeProofService. - Ajout/modification de triggers sur d'autres tables (PD-273, PD-274).
- Changement du modèle métier de cycle de vie des preuves composites.
3. Définitions¶
- ProofEnvelope / preuve composite : artefact probant central persistant une preuve finalisée.
- Immutabilité post-persistance : propriété interdisant toute altération/suppression d'une ligne après insertion.
- Trigger d'immutabilité : mécanisme PostgreSQL interceptant
UPDATEetDELETEavant exécution et bloquant l'opération. - PROOF-12 : exigence normative imposant l'immutabilité après persistance.
- INV-07 / ImmutableAfterFinalize : invariant formel TLA+ correspondant.
- ASSERT-08 / ImmutableAfterGeneration : invariant formel Alloy correspondant.
4. Invariants (non négociables)¶
| ID | Règle | Justification |
|---|---|---|
| INV-272-01 | Toute ligne de legal_composite_proofs est immutable immédiatement après insertion. | Conformité PROOF-12 et modèles formels. |
| INV-272-02 | Toute tentative UPDATE sur legal_composite_proofs est rejetée avec l'erreur legal_composite_proofs: modification interdite — preuve immutable. | Garantit l'intégrité probante contre altération directe DB. |
| INV-272-03 | Toute tentative DELETE sur legal_composite_proofs est rejetée avec l'erreur legal_composite_proofs: suppression interdite — preuve immutable. | Garantit la conservation de la preuve et sa traçabilité. |
| INV-272-04 | INSERT dans legal_composite_proofs reste autorisé. | Préserve le flux nominal de génération de preuve. |
| INV-272-05 | La règle d'immutabilité est inconditionnelle (aucune exception selon statut/acteur/contexte). | Supprime les zones d'ambiguïté et réduit le risque de contournement. |
| INV-272-06 | Invariant d'état terminal : pour l'état métier implicite PERSISTED_IMMUTABLE, toute transition sortante → * de type modification/suppression est INTERDITE. | Exigence explicite de machine à états et interdiction des transitions non documentées. |
| INV-272-07 | (Domaine crypto-proof) Tout artefact cryptographique temporaire est chiffré au repos (AES-256-GCM ou HSM envelope), aucun secret en clair en base. | Invariant transversal obligatoire crypto/crypto-proof. |
| INV-272-08 | Le contrôle formel check_proof_immutable_trigger doit produire un statut OK. | Critère objectif de conformité audit PV-PROOF-001. |
5. Flux nominaux¶
- Création de preuve composite
- Précondition : demande de génération valide.
- Action : insertion d'une nouvelle ligne dans
legal_composite_proofs. -
Résultat attendu : insertion acceptée (INV-272-04), preuve persistée immutable (INV-272-01).
-
Tentative de modification post-création
- Précondition : ligne existante dans
legal_composite_proofs. - Action : opération
UPDATE. -
Résultat attendu : opération rejetée avec message exact contractuel (INV-272-02).
-
Tentative de suppression post-création
- Précondition : ligne existante dans
legal_composite_proofs. - Action : opération
DELETE. -
Résultat attendu : opération rejetée avec message exact contractuel (INV-272-03).
-
Contrôle de conformité
- Action : exécution de
check_proof_immutable_trigger. - Résultat attendu : statut OK (INV-272-08).
5bis. Diagrammes¶
Machine à états — Cycle de vie d'une preuve composite¶
La preuve composite possède un état terminal unique PERSISTED_IMMUTABLE dont aucune transition sortante n'est autorisée (INV-272-06).
stateDiagram-v2
[*] --> INSERT_PENDING : Demande de génération valide
INSERT_PENDING --> PERSISTED_IMMUTABLE : INSERT accepté (INV-272-04)
INSERT_PENDING --> [*] : Échec INSERT (contrainte DB)
PERSISTED_IMMUTABLE --> PERSISTED_IMMUTABLE : UPDATE rejeté (INV-272-02)
PERSISTED_IMMUTABLE --> PERSISTED_IMMUTABLE : DELETE rejeté (INV-272-03)
note right of PERSISTED_IMMUTABLE
État terminal — INV-272-06
Aucune transition sortante autorisée.
Immutabilité inconditionnelle (INV-272-05).
end note Séquence — Trigger d'immutabilité PostgreSQL¶
Interactions entre le service applicatif, TypeORM, PostgreSQL et le trigger d'immutabilité pour les trois opérations (INSERT, UPDATE, DELETE).
sequenceDiagram
participant Service as LegalCompositeProofService
participant ORM as TypeORM
participant PG as PostgreSQL
participant Trigger as Trigger immutabilité
Note over Service, Trigger: Flux nominal — INSERT autorisé (INV-272-04)
Service->>ORM: save(proofEntity)
ORM->>PG: INSERT INTO legal_composite_proofs
PG-->>ORM: OK — ligne persistée
ORM-->>Service: ProofEntity (PERSISTED_IMMUTABLE)
Note over Service, Trigger: Tentative UPDATE — rejetée (INV-272-02)
Service->>ORM: save(existingProof) / update()
ORM->>PG: UPDATE legal_composite_proofs SET ...
PG->>Trigger: BEFORE UPDATE
Trigger--xPG: RAISE EXCEPTION «modification interdite — preuve immutable»
PG--xORM: QueryFailedError
ORM--xService: Exception PostgreSQL (ERR-272-01)
Note over Service, Trigger: Tentative DELETE — rejetée (INV-272-03)
Service->>ORM: remove(existingProof) / delete()
ORM->>PG: DELETE FROM legal_composite_proofs
PG->>Trigger: BEFORE DELETE
Trigger--xPG: RAISE EXCEPTION «suppression interdite — preuve immutable»
PG--xORM: QueryFailedError
ORM--xService: Exception PostgreSQL (ERR-272-02) 6. Cas d'erreur¶
- ERR-272-01 — Modification interdite
- Déclencheur :
UPDATEsurlegal_composite_proofs. - Réponse attendue : exception PostgreSQL avec message exact
legal_composite_proofs: modification interdite — preuve immutable. -
Effet : aucune mutation persistée.
-
ERR-272-02 — Suppression interdite
- Déclencheur :
DELETEsurlegal_composite_proofs. - Réponse attendue : exception PostgreSQL avec message exact
legal_composite_proofs: suppression interdite — preuve immutable. -
Effet : aucune suppression persistée.
-
ERR-272-03 — Non-conformité audit
- Déclencheur :
check_proof_immutable_triggernon OK. - Réponse attendue : story non conforme, livraison refusée tant que l'écart persiste.
7. Critères d'acceptation (testables)¶
| ID | Critère | Observable |
|---|---|---|
| CA-272-01 | Le mécanisme d'immutabilité existe sur legal_composite_proofs. | Métadonnées DB et check Prolog confirment la présence du contrôle. |
| CA-272-02 | Tout UPDATE est bloqué. | Exception PostgreSQL levée avec message exact de modification interdite. |
| CA-272-03 | Tout DELETE est bloqué. | Exception PostgreSQL levée avec message exact de suppression interdite. |
| CA-272-04 | INSERT reste autorisé. | Insertion réussie sur table sans erreur d'immutabilité. |
| CA-272-05 | check_proof_immutable_trigger retourne OK. | Sortie du contrôle formel = OK. |
| CA-272-06 | Absence de régression. | Suite de tests existante au vert. |
8. Scénarios de test (Given / When / Then)¶
- ST-272-01 — Insertion autorisée
- Given aucune ligne cible n'existe
- When une preuve composite est créée
-
Then l'insertion est acceptée et la ligne est persistée
-
ST-272-02 — Update interdit
- Given une ligne existe dans
legal_composite_proofs - When un
UPDATEest tenté sur n'importe quelle colonne - Then une exception PostgreSQL est levée avec
legal_composite_proofs: modification interdite — preuve immutable -
And aucune donnée n'est modifiée
-
ST-272-03 — Delete interdit
- Given une ligne existe dans
legal_composite_proofs - When un
DELETEest tenté - Then une exception PostgreSQL est levée avec
legal_composite_proofs: suppression interdite — preuve immutable -
And la ligne reste présente
-
ST-272-04 — Conformité Prolog
- Given le schéma DB déployé
- When
check_proof_immutable_triggerest exécuté -
Then le résultat est OK
-
ST-272-05 — Non-régression
- Given la baseline de tests existants
- When la suite est exécutée après intégration
- Then tous les tests précédemment passants restent passants
9. Hypothèses explicites¶
| ID | Hypothèse | Impact si faux |
|---|---|---|
| H-272-01 | Le nom exact de la table cible est legal_composite_proofs. | Si nom/schéma diffère, contrôle appliqué au mauvais objet ou absent. |
| H-272-02 | Le check check_proof_immutable_trigger vérifie bien un blocage UPDATE et DELETE. | Risque de faux positif de conformité. |
| H-272-03 | Aucun cas métier légitime n'exige la suppression/mise à jour d'une preuve composite persistée. | Nécessiterait une révision normative de PROOF-12. |
| H-272-04 | La story cible le projet ProbatioVault-backend (stack réelle : NestJS + TypeORM + PostgreSQL). | Si projet cible différent, section contraintes techniques invalide. |
| H-272-05 | Le learning PD-171 (append-only trigger) est applicable à ce cas d'immutabilité stricte. | Si non applicable, risque de divergence de pattern qualité. |
10. Points à clarifier¶
- Schéma PostgreSQL explicite : schéma qualifié de
legal_composite_proofsnon fourni (ex.public/vault_legal). - Standard d'erreur DB attendu : seul le message est contractuel ; code SQLSTATE attendu non précisé.
Références¶
- JIRA :
PD-272 - Repos concernés :
ProbatioVault-backend - Documents associés :
- RFC PV-PROOF-001 (PROOF-12)
- TLA+
PV_Proof.tla(INV-07 ImmutableAfterFinalize) - Alloy
PV_Proof.als(ASSERT-08 ImmutableAfterGeneration) - Z
PV_Proof.zed(THM-07 Preservation immutabilite) - Audit formel PV-PROOF-001
- Learning PD-171 (pattern trigger append-only/immutabilité)