PD-273 — Plan d'implémentation¶
1. Contexte¶
L'audit formel PV-AUDIT-001 a identifié 3 checks Prolog en statut PARTIEL. L'objectif est de corriger ces 3 écarts pour atteindre 24/24 checks OK, sans régression.
3 Gaps identifiés¶
| # | Check | Problème | Solution |
|---|---|---|---|
| 1 | check_audit_trigger_update_delete | extract-facts.py génère 'BEFORE UPDATE OR DELETE' au lieu de immutable ou prevent_update_delete | Modifier extract-facts.py pour normaliser l'atome du trigger |
| 2 | check_audit_signature_sign | Méthode est signAuditEntry() mais Prolog cherche sign | Modifier le Prolog pour accepter signAuditEntry OU ajouter alias sign() |
| 3 | check_destruction_sequence | Séquence PostgreSQL brute, pas d'entité TypeORM détectable | Modifier le Prolog pour accepter service_method(destruction_audit, logDestruction) |
2. Approche hybride (extract-facts.py + Prolog)¶
L'approche recommandée par le besoin est hybride : - Gap 1 : Modifier extract-facts.py pour normaliser les atomes de triggers - Gap 2 : Ajouter alias sign() dans AuditSignatureService (modification backend minimale) - Gap 3 : Modifier les règles Prolog pour reconnaître le pattern existant
3. Tâches¶
TASK-1 : Modifier extract-facts.py — normalisation atomes triggers¶
Fichier : scripts/formal/extract-facts.py Modification : Dans la logique de génération de table_trigger/3, normaliser les events de trigger : - 'BEFORE UPDATE OR DELETE' → atome prevent_update_delete - 'BEFORE UPDATE' → atome prevent_update - 'BEFORE DELETE' → atome prevent_delete
INV couverts : INV-273-03 CA couverts : CA-273-01
TASK-2 : Modifier Prolog check_audit_trigger_update_delete¶
Fichier : docs/normes/pv-audit/formal/pv_audit_compliance.pl Modification : Adapter la règle pour accepter le nouvel atome prevent_update_delete :
INV couverts : INV-273-03 CA couverts : CA-273-01
TASK-3 : Ajouter alias sign() dans AuditSignatureService¶
Fichier : src/modules/audit/services/audit-signature.service.ts Modification : Ajouter une méthode sign() qui délègue à signAuditEntry() :
INV couverts : INV-273-04 CA couverts : CA-273-02
TASK-4 : Modifier Prolog check_destruction_sequence¶
Fichier : docs/normes/pv-audit/formal/pv_audit_compliance.pl Modification : Adapter la règle pour accepter le service existant :
check_destruction_sequence :-
service_method(destruction_audit, logDestruction), !.
check_destruction_sequence :-
entity_column(audit_log, destruction_seq, _), !.
INV couverts : INV-273-05 CA couverts : CA-273-03
TASK-5 : Mettre à jour test_data.pl¶
Fichier : docs/normes/pv-audit/formal/test_data.pl Modification : Mettre à jour les faits de test statiques pour refléter les nouveaux atomes : - table_trigger(audit_log, trg_audit_log_immutable, prevent_update_delete). - service_method(audit_signature, sign). - service_method(destruction_audit, logDestruction).
INV couverts : INV-273-01, INV-273-02 CA couverts : CA-273-04, CA-273-05
TASK-6 : Tests d'intégration Prolog¶
Fichier : Exécution swipl dans CI Action : Vérifier que les 24 checks passent avec les faits mis à jour :
INV couverts : INV-273-01, INV-273-02 CA couverts : CA-273-04, CA-273-05
TASK-7 : Test unitaire Jest alias sign()¶
Fichier : src/modules/audit/services/__tests__/audit-signature.service.spec.ts Action : Ajouter un test vérifiant que sign() délègue à signAuditEntry() :
it('sign() should delegate to signAuditEntry()', async () => {
const spy = jest.spyOn(service, 'signAuditEntry').mockResolvedValue(mockEntry);
const result = await service.sign(mockEntry);
expect(spy).toHaveBeenCalledWith(mockEntry);
expect(result).toBe(mockEntry);
});
INV couverts : INV-273-04 CA couverts : CA-273-02
4. Contraintes techniques¶
Dépendances inter-PD¶
| Story | Statut | Nature |
|---|---|---|
| PD-272 | DONE | Trigger trg_legal_composite_proof_immutable (même pattern, autre table) |
| PD-250 | DONE | Séquence audit_destruction_seq (créée par migration PD-250) |
Framework de test¶
- Prolog : SWI-Prolog (
swipl) — tests déterministes viarun_audit. - Jest : Tests unitaires NestJS pour alias
sign() - extract-facts.py : Python 3, exécution locale
Compatibilité¶
- Pas de dépendance ESM
- Pas de migration DDL (aucune modification de schéma)
5. Mapping INV/CA → Tâches/Tests¶
| Invariant/CA | Tâche couvrant | Test couvrant |
|---|---|---|
| INV-273-01 | TASK-5, TASK-6 | TC-NOM-273-04 (Prolog run_audit) |
| INV-273-02 | TASK-5, TASK-6 | TC-NOM-273-05 (Prolog run_audit) |
| INV-273-03 | TASK-1, TASK-2 | TC-NOM-273-01 (check Prolog) |
| INV-273-04 | TASK-3 | TC-NOM-273-02 (check Prolog + Jest TASK-7) |
| INV-273-05 | TASK-4 | TC-NOM-273-03 (check Prolog) |
| INV-273-06 | TASK-5, TASK-6 | TC-NOM-273-06 (2 runs Prolog) |
| INV-273-07 | N/A (par construction) | TC-ERR-273-03 |
| CA-273-01 | TASK-1, TASK-2 | TC-NOM-273-01 |
| CA-273-02 | TASK-3 | TC-NOM-273-02, TASK-7 |
| CA-273-03 | TASK-4 | TC-NOM-273-03 |
| CA-273-04 | TASK-5, TASK-6 | TC-NOM-273-05 |
| CA-273-05 | TASK-6 | TC-NOM-273-04 |
| CA-273-06 | TASK-6 | TC-ERR-273-01/02/03/04 |
6. Ordre d'exécution¶
- TASK-1 (extract-facts.py) — prérequis pour la génération des bons faits
- TASK-2 (Prolog check trigger) — dépend de TASK-1 pour l'atome correct
- TASK-3 (alias sign()) — indépendant
- TASK-4 (Prolog check destruction) — indépendant
- TASK-5 (test_data.pl) — après TASK-½/4
- TASK-7 (Jest sign()) — après TASK-3
- TASK-6 (run Prolog complet) — vérification finale après toutes les modifications
7. Risques¶
| Risque | Probabilité | Mitigation |
|---|---|---|
| L'atome normalisé casse d'autres règles Prolog | Faible | Vérifier les 24 checks après chaque modification |
L'alias sign() crée une confusion API | Faible | Méthode documentée comme alias dans le code |
| extract-facts.py ne supporte pas le nouveau mapping | Faible | Tester avec --norm-pv-audit après modification |