// Portes d'approbation. Rien ne part sans qu'un humain ait vu ce qui part. export type GateDecision = 'allowed' | 'needs-approval' | 'refused'; export interface Outbound { to: string[]; subject: string; template?: string; } // Envoyer, transferer et creer une regle sont les trois actions qu'un agent // ne fait jamais seul : ce sont celles qui sortent du systeme. const GUARDED = new Set(['send', 'forward', 'rule.create']); export function gate(action: string, mail: Outbound): GateDecision { if (!GUARDED.has(action)) return 'allowed'; // Une regle de transfert automatique est une exfiltration silencieuse si // personne ne la relit : jamais d'approbation implicite dessus. if (action === 'rule.create') return 'needs-approval'; return 'needs-approval'; } // Les envois identiques se presentent groupes : un operateur qui approuve // trente fois la meme chose finit par ne plus lire (issue #14). export function batchKey(mail: Outbound): string { return `${mail.template ?? 'raw'}:${[...mail.to].sort().join(',')}`; }