Aller au contenu principal
Version: 1.0.0

Expiration et annulation durables des validations humaines

Une validation human.approve ou human.review suspend l'exécution au point humain. Le serveur projet peut conserver cette attente afin qu'une décision, une expiration ou une annulation garde le même sens après un redémarrage.

Cette capacité est validée localement dans le serveur projet. Elle complète la validation humaine existante et les contraintes source de rôle et de délai. Elle n'ajoute ni statement wait, ni scheduler général.

Validation dans un groupe parallèle​

Un même checkpoint peut conserver plusieurs continuations de branches. Le serveur présente la demande courante et la libère par sa décision exacte ; il ne traite pas cette décision comme une approbation globale du groupe. Après reprise, une autre occurrence peut demander une nouvelle décision. Les branches terminées et les budgets restent conservés au redémarrage. Le plafond d'une attente courante par run ne signifie donc pas une seule validation pour toutes les branches. Voir Validation humaine.

Cycle de vie​

Attente humaine durable
checkpoint humain -> attente -> décision avant échéance -> reprise explicite
|-> expiration -------------> on expired, sinon fin
|-> annulation -------------> fin automatique

L'échéance est fixée une fois : with timeout_ms as <entier> choisit le délai de l'occurrence dans le programme. Sans délai source, le serveur applique 24 heures après la création de la demande. Elle est exprimée en UTC et ne change pas au redémarrage. L'heure du serveur fait autorité : une date ancienne envoyée par le client ne rend pas recevable une décision tardive.

La frontière est stricte :

décision recevable <=> acceptée par le serveur avant l'échéance
expiration <=> heure du serveur supérieure ou égale à l'échéance

À l'instant exact de l'échéance, l'expiration gagne.

Trois issues possibles​

IssueComportement
Décision à tempsLa décision est conservée durablement. Elle ne relance pas seule l'exécution : la reprise existante doit être demandée explicitement.
ExpirationLe serveur reprend avec expired : il suit uniquement la branche source on expired si elle existe, sinon termine le run. La continuation approuvée n'est pas exécutée.
AnnulationUne opération d'interaction en état awaiting_human peut être annulée avant l'échéance si aucune décision n'a déjà gagné. Le checkpoint se termine alors avec l'issue cancelled.

Une annulation demandée à l'échéance ou après celle-ci devient une expiration. Une annulation ne défait pas les effets qui auraient déjà eu lieu avant la validation humaine.

Redémarrage et crash​

Avant d'accepter des requêtes, le serveur projet relit ses attentes, termine les expirations déjà dues et reprend les terminalisations automatiques interrompues. Une résolution déjà enregistrée reste la seule résolution : un redémarrage, deux réveils proches ou une seconde demande ne doivent pas la remplacer.

Si le serveur est arrêté au moment de l'échéance, aucun timer ne s'exécute en arrière-plan. L'expiration est observée au prochain démarrage. Un résultat terminal déjà conservé peut alors être reprojeté vers les surfaces sans réexécuter le runtime. Les événements de pause et de terminaison portent une corrélation durable : leur réparation ne crée pas un nouvel événement après qu'une projection identique a déjà été enregistrée.

Dans les résumés de trace, les événements humains utilisent toujours authority_ref = approval_ref. Leur related_ref vaut decision:<valeur> : decision:pending pendant la demande et la pause, puis l'issue réellement observée. Ces références servent à l'audit et à la réparation ; la trace ne remplace pas le record durable qui arbitre l'issue.

Si un état invalide empêche une terminalisation pendant le scan initial, le serveur refuse de commencer à écouter. Si l'échec apparaît ensuite, la résolution acquise reste durable et le worker local retente toutes les 30 secondes. Rafraîchir ou relire la demande ne déclenche pas de tentative avant ce prochain instant ; une autre décision ne peut pas profiter de l'incident pour remplacer la résolution.

Capacité et limites​

La portée actuelle est volontairement bornée :

  • un serveur projet local, mono-processus, propriétaire de ses fichiers ;
  • capacité de 100 attentes par défaut, configurable jusqu’à 10 000 avec --max-pending-approvals ; les attentes parallèles conservent leurs occurrences ;
  • au plus 100 sessions d'interaction, sans éviction d'une session portant une opération non terminale comme awaiting_human ou interrupted ;
  • réservation de la capacité avant une nouvelle exécution susceptible de se mettre en attente ;
  • un seul prochain réveil local, sans service de scheduling distinct ;
  • annulation via l'opération d'interaction existante, pas via une nouvelle route d'annulation de sandbox direct.

Quand la borne est atteinte, la nouvelle opération est refusée avant le runtime et avant tout handler. Si les 100 sessions d'interaction sont encore non terminales, une nouvelle session est elle aussi refusée plutôt que de supprimer un état reprenable.

Cette portée ne fournit pas de coordination multi-hôte, d'horloge distribuée, de rappel, de réassignation ou de purge automatique des records terminaux ni de garantie exactly-once. Le remplacement atomique des fichiers rend l'arbitrage cohérent dans la borne locale ; il ne crée pas de transaction distribuée avec un service externe.

Pour distinguer ce cycle de vie d'une continuation après interruption, lire Reprise durable bornée. Pour la syntaxe des barrières humaines, lire Validation humaine.

Une escalade explicite crée une nouvelle demande : voir le tutoriel rôles et délais.