Aller au contenu

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_proofs contre UPDATE et DELETE.
  • Rejet explicite avec message d'erreur métier contractualisé :
  • legal_composite_proofs: modification interdite — preuve immutable
  • legal_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 UPDATE et DELETE avant 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

  1. Création de preuve composite
  2. Précondition : demande de génération valide.
  3. Action : insertion d'une nouvelle ligne dans legal_composite_proofs.
  4. Résultat attendu : insertion acceptée (INV-272-04), preuve persistée immutable (INV-272-01).

  5. Tentative de modification post-création

  6. Précondition : ligne existante dans legal_composite_proofs.
  7. Action : opération UPDATE.
  8. Résultat attendu : opération rejetée avec message exact contractuel (INV-272-02).

  9. Tentative de suppression post-création

  10. Précondition : ligne existante dans legal_composite_proofs.
  11. Action : opération DELETE.
  12. Résultat attendu : opération rejetée avec message exact contractuel (INV-272-03).

  13. Contrôle de conformité

  14. Action : exécution de check_proof_immutable_trigger.
  15. 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 : UPDATE sur legal_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 : DELETE sur legal_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_trigger non 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 UPDATE est 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 DELETE est 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_trigger est 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

  1. Schéma PostgreSQL explicite : schéma qualifié de legal_composite_proofs non fourni (ex. public/vault_legal).
  2. 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é)