Audit Trail Y.A.N.I.
Chaque action de Y.A.N.I. est tracable. Le module lib/yani/audit-trail.tsdefinit un contrat canonique et des builders purs, sans effet de bord, pour produire des entrees d'audit conformes au RGPD et a l'IA-Act europeen.
Vue d'ensemble
Le module d'audit trail est volontairement pur : aucune persistance, aucune donnee personnelle figee dans le code, et aucun Date.now() qui fuiterait dans les sorties sans une horloge injectable. Il se contente de construire et de validerdes entrees d'audit canoniques. La route API, le tableau de bord /yani/knowset l'export RGPD (livres dans des slices ulterieures) consomment cette forme.
Tracabilite totale
Chaque action Y.A.N.I. (lecture de solde, ecriture memoire, export de donnees) genere une entree validee et immuable.
Module pur & deterministe
Horloge et identifiant injectables. Sortie gelee via Object.freeze. Tests reproductibles a 100 %.
Export structure
serializeAuditTrail()produit un JSON trie par horodatage, brique de l'export RGPD en moins de 30 secondes.
Origine : TASK-2026-0305 (Slice 1)
/api/yani/forget), le tableau de bord /yani/knowset l'export RGPD (JSON / PDF).Pourquoi un audit trail
Un agent IA autonome qui agit sur des donnees financieres doit pouvoir justifier chacune de ses actions. L'audit trail repond a trois exigences reglementaires distinctes :
RGPD
Droit a l'information, droit d'acces et droit a l'effacement. L'utilisateur peut consulter et exporter tout ce que Y.A.N.I. sait de lui.
IA-Act (UE)
Transparence des systemes d'IA : journalisation des decisions, identification de l'acteur et de l'impact de chaque action automatisee.
Reversibilite
Revocation en 1 clic : toute regle ou autorisation accordee a Y.A.N.I. peut etre annulee avec effet immediat et trace.
Cycle de vie d'une entree
Voici comment une action utilisateur se transforme en entree d'audit immuable, puis comment l'historique est revoque ou exporte :
Contrat AuditEntry
L'entree d'audit canonique reflete le jeu de champs du critere d'acceptation : horodatage ISO-8601, acteur, type d'action, outil invoque, raison, impact, statut et identifiant. Le schema Zod est .strict() — tout champ inconnu est rejete.
1 import { z } from 'zod'; 2 3 export const auditEntrySchema = z 4 .object({ 5 id: z.string().min(1), 6 timestamp: z.string().refine(isIso8601, { message: 'timestamp must be ISO-8601' }), 7 actor: z.string().min(1), 8 actionType: z.enum(AUDIT_ACTION_TYPES), 9 tool: z.string().min(1), 10 reason: z.string().min(1), 11 impact: z.string().min(1), 12 status: z.enum(AUDIT_STATUSES), 13 }) 14 .strict(); 15 16 export type AuditEntry = z.infer<typeof auditEntrySchema>; 17 18 // Champs fournis par l'appelant — id et timestamp sont derives / injectes 19 export type AuditEntryInput = Omit<AuditEntry, 'id' | 'timestamp'>;
| Champ | Type | Description |
|---|---|---|
| id | string (>= 1) | Identifiant unique. Genere si non fourni (ex: aud_<base36>_<seq>). |
| timestamp | string ISO-8601 | Horodatage strict : la chaine doit faire un aller-retour sans perte via Date.toISOString(). |
| actor | string (>= 1) | Qui a declenche l'action (utilisateur, agent, systeme). |
| actionType | AuditActionType | Categorie d'action, parmi les 7 valeurs de AUDIT_ACTION_TYPES. |
| tool | string (>= 1) | Outil invoque. Pour une revocation, stocke l'identifiant de la regle revoquee. |
| reason | string (>= 1) | Raison lisible de l'action. |
| impact | string (>= 1) | Description de l'effet concret de l'action. |
| status | AuditStatus | Resultat, parmi les 4 valeurs de AUDIT_STATUSES. |
Horodatage ISO-8601 strict
timestamp ne se contente pas de parser la date : elle verifie que new Date(value).toISOString() === value. Une chaine comme 2026-06-22 sans heure est donc rejetee — seul le format complet ISO-8601 (2026-06-22T10:30:00.000Z) est accepte.Types d'actions
Les categories d'actions auditables sont definies dans la constante AUDIT_ACTION_TYPES. Le type AuditActionType en derive automatiquement.
TOOL_INVOKEDOutil invoque
RULE_CREATEDRegle creee
RULE_REVOKEDRegle revoquee
BALANCE_READSolde lu
MEMORY_WRITEMemoire ecrite
DATA_EXPORTEDDonnees exportees
DATA_FORGOTTENDonnees effacees
Statuts d'audit
L'issue d'une action auditee est l'une des 4 valeurs de AUDIT_STATUSES. La valeur REVOKED_BY_USER signale specifiquement une revocation en 1 clic.
Succes
SUCCESSL'action a abouti sans erreur.
Echec
FAILUREL'action a echoue. La cause est portee par le champ reason.
En attente
PENDINGL'action est en cours et n'a pas encore de resultat final.
Revoquee par l’utilisateur
REVOKED_BY_USERL'utilisateur a annule une regle ou autorisation en 1 clic. Statut produit par createRevocationEntry.
Builders purs
La fonction createAuditEntry construit une entree validee et gelee. Elle leve une erreur Zodsi un champ est invalide : c'est une defense en profondeur pour qu'une entree malformee ne puisse jamais rejoindre le journal.
1 import { createAuditEntry } from '@/lib/yani/audit-trail'; 2 3 // Cas nominal : Y.A.N.I. lit le solde de l'utilisateur 4 const entry = createAuditEntry({ 5 actor: 'user:42', 6 actionType: 'BALANCE_READ', 7 tool: 'banking.getBalance', 8 reason: "L'utilisateur a demande son solde courant", 9 impact: 'Lecture seule du solde du wallet principal', 10 status: 'SUCCESS', 11 }); 12 13 // entry.id — genere automatiquement (ex: aud_l8x2k_1) 14 // entry.timestamp — ISO-8601 de l'instant courant 15 // L'objet retourne est gele (Object.freeze) : immuable.
Pour des tests deterministes, injectez une horloge et un identifiant fixes via le second parametre AuditEntryOptions :
1 import { createAuditEntry } from '@/lib/yani/audit-trail'; 2 3 const entry = createAuditEntry( 4 { 5 actor: 'user:42', 6 actionType: 'MEMORY_WRITE', 7 tool: 'memory.store', 8 reason: "Persistance d'une preference utilisateur", 9 impact: "Ajout d'une cle en memoire de session", 10 status: 'SUCCESS', 11 }, 12 { 13 now: new Date('2026-06-22T10:30:00.000Z'), // horloge injectee 14 id: 'aud_test_001', // identifiant fixe 15 }, 16 ); 17 18 // entry.id === 'aud_test_001' 19 // entry.timestamp === '2026-06-22T10:30:00.000Z'
Immuabilite garantie
Object.freeze. Une fois construite, elle ne peut plus etre mutee — la garantie d'integrite attendue d'un journal d'audit.Revocation 1-clic
createRevocationEntry produit une entree RULE_REVOKED avec le statut REVOKED_BY_USER. L'identifiant de la regle revoquee est stocke dans le champ tool, ce qui permet au tableau de bord de relier l'entree a la regle concernee.
1 import { createRevocationEntry } from '@/lib/yani/audit-trail'; 2 3 const revocation = createRevocationEntry({ 4 ruleId: 'rule_auto_transfer_77', 5 actor: 'user:42', 6 reason: "L'utilisateur retire l'autorisation de virement automatique", 7 // impact optionnel — defaut : 'rule disabled with immediate effect' 8 }); 9 10 // revocation.actionType === 'RULE_REVOKED' 11 // revocation.status === 'REVOKED_BY_USER' 12 // revocation.tool === 'rule_auto_transfer_77' (l'id de la regle revoquee) 13 // revocation.impact === 'rule disabled with immediate effect'
Le champ tool fait double emploi
tool ne designe pas un outil mais l'identifiant de la regle revoquee. Ce choix deliberé evite d'ajouter un champ specifique au contrat tout en conservant le lien entre l'entree et la regle.Export RGPD
serializeAuditTrailserialise un journal complet en JSON, trie par horodatage croissant. C'est la brique de base de l'export RGPD (critere d'acceptation n°4 : moins de 30 secondes).
1 import { 2 createAuditEntry, 3 serializeAuditTrail, 4 type AuditEntry, 5 } from '@/lib/yani/audit-trail'; 6 7 const entries: AuditEntry[] = [ 8 createAuditEntry({ 9 actor: 'user:42', 10 actionType: 'DATA_EXPORTED', 11 tool: 'gdpr.export', 12 reason: "L'utilisateur exerce son droit d'acces (RGPD art. 15)", 13 impact: 'Export complet du journal au format JSON', 14 status: 'SUCCESS', 15 }), 16 // ... autres entrees 17 ]; 18 19 // Serialisation deterministe, triee par timestamp croissant 20 const json = serializeAuditTrail(entries); 21 // -> string JSON indentee (2 espaces), prete a etre telechargee
Donnees personnelles (RGPD)
actor, reason). Le stockage et la diffusion de ces entrees doivent respecter le chiffrement au repos et les durees de conservation reglementaires.Conformite RGPD & IA-Act
Le module a ete concu autour des exigences de transparence et de reversibilite imposees aux systemes d'IA agissant sur des donnees financieres :
Droit a l’information & d’acces (RGPD)
Chaque action est journalisee avec son acteur, sa raison et son impact. L'utilisateur peut tout consulter et exporter.
Droit a l’effacement (RGPD)
L'action DATA_FORGOTTEN trace les effacements. La route /api/yani/forget consommera ce contrat dans une slice ulterieure.
Transparence (IA-Act)
Les decisions automatisees de Y.A.N.I. sont identifiees par type d'action et reliees a l'outil invoque.
Reversibilite (IA-Act)
Toute regle accordee a Y.A.N.I. peut etre revoquee en 1 clic avec effet immediat et trace REVOKED_BY_USER.
Prochaines etapes
Ressources associees
Derniere mise a jour : 22 juin 2026 — module lib/yani/audit-trail.ts(pur, side-effect free) : contrat AuditEntry (8 champs), 7 AUDIT_ACTION_TYPES, 4 AUDIT_STATUSES, builders createAuditEntry / createRevocationEntry / serializeAuditTrail, conformite RGPD & IA-Act, export JSON trie.