
# Machines à états

Les machines à états et les workflows répondent à des besoins différents.

Un workflow répond à la question « quelle tâche s’exécute ensuite ? ». Une machine à états répond à « dans quel état se trouve cette entité, et quels événements sont valides à partir d’ici ? ». Cette différence compte lorsque ce que vous construisez n’est pas simplement une suite d’étapes, mais une entité de longue durée qui réagit au fil du temps à des entrées externes, comme une session d’agent, un fil de discussion, un cycle de révision, un ticket ou un processus d’approbation.

## Exemple rapide

```php
use Queuety\Enums\StateMachineStatus;
use Queuety\Queuety;

$machine_id = Queuety::machine( 'agent_session' )
    ->version( 'agent-session.v1' )
    ->state( 'awaiting_user' )
    ->on( 'user_message', 'planning' )
    ->state( 'planning' )
    ->action( PlanSessionAction::class )
    ->on( 'planned', 'awaiting_review' )
    ->state( 'awaiting_review' )
    ->on( 'approve', 'completed', ReviewApprovedGuard::class )
    ->on( 'reject', 'awaiting_user' )
    ->state( 'completed', StateMachineStatus::Completed )
    ->dispatch( [ 'thread_id' => 42 ] );

Queuety::machine_event(
    $machine_id,
    'user_message',
    [ 'message' => 'Find competitors for this product' ]
);

Queuety::machine_event(
    $machine_id,
    'approve',
    [ 'approved' => true, 'reviewer' => 'editor@example.com' ]
);
```

Cette machine commence dans `awaiting_user`, passe à `planning` lorsqu’un message utilisateur arrive, permet à l’action en file d’émettre `planned`, puis attend dans `awaiting_review` jusqu’à ce qu’une approbation externe termine la session. Le point essentiel n’est pas la syntaxe du code en elle-même, mais le fait que le cycle de vie soit explicite, inspectable et piloté par les événements.

## Exécution d’une machine

Lorsqu’une instance de machine est envoyée, Queuety enregistre l’état actuel, la charge utile publique de l’état, la version et le hachage de la définition, les événements entrants valides pour l’état actuel, ainsi qu’une chronologie durable des événements.

Si l’état atteint comporte un `action()`, Queuety ajoute une tâche d’entrée d’état à la file d’attente. Cette action peut simplement mettre à jour l’état public et laisser la machine en attente du prochain événement, ou émettre `_event` et éventuellement `_event_payload` pour déclencher immédiatement la transition suivante. Si l’état n’a pas d’action ni de statut terminal, la machine attend simplement les événements externes envoyés avec `Queuety::machine_event()`.

## Choisir entre workflows et machines à états

Utilisez un workflow lorsque l’exécution suit fondamentalement des étapes : récupérer des données, effectuer chaque tâche, attendre, synthétiser, terminer. Ce modèle convient lorsque le processus a un début et une fin clairs et que la principale question est de savoir quelle tâche exécuter ensuite.

Utilisez une machine à états lorsque le comportement autorisé dépend de la phase actuelle du cycle de vie. Elle convient mieux lorsque les événements peuvent arriver dans un ordre différent, lorsque l’entité peut exister longtemps ou lorsque vous avez besoin d’inspecter explicitement son cycle de vie, avec des états tels que `awaiting_user`, `planning`, `running_agents`, `awaiting_review` et `completed`.

## Comment les deux s’articulent

Ces deux primitives fonctionnent mieux ensemble que l’une contre l’autre. Une action d’état peut envoyer un workflow lorsqu’une transition nécessite une exécution plus lourde, et un workflow peut renvoyer un événement à une machine une fois le travail terminé. En pratique, la machine à états régit le cycle de vie, tandis que les workflows exécutent les tâches coûteuses ou fortement structurées.

## Structure du constructeur

`StateMachineBuilder` reste volontairement simple. `initial()` et `state()` définissent le graphe du cycle de vie. `action()` associe du travail en file d’attente à un état. `on()` indique quels événements peuvent faire passer la machine à l’état suivant. `on_queue()`, `with_priority()` et `max_attempts()` déterminent comment les actions d’état sont exécutées, tandis que `version()` et `idempotency_key()` ajoutent des métadonnées durables à l’envoi. `dispatch()` crée l’instance de la machine.

Les actions d’état peuvent également exposer une méthode `config()` facultative, utilisant les mêmes clés de stratégie de ressources que les étapes et les gestionnaires de workflow. Cela permet de placer une transition d’état coûteuse dans un groupe de concurrence partagé ou de lui attribuer un coût supérieur lorsqu’une action consomme plus de budget qu’une étape normale.

Le modèle général des ressources est décrit dans [Gestion des ressources](https://queuety.inline0.dev/fr/docs/features/resource-management).

## Contrats

Les actions d’entrée d’état implémentent `Queuety\Contracts\StateAction` :

```php
namespace Queuety\Contracts;

interface StateAction {
    public function handle( array $state, ?string $event = null, array $event_payload = [], array $payload = [] ): array|string;
}
```

`$payload` correspond à la charge utile structurée de la définition de l’action ; elle est vide si l’action a été indiquée sous la forme d’un simple nom de classe. Queuety crée les actions avec `new $class()`. Une classe d’action doit donc avoir un constructeur sans argument obligatoire.

Les actions d’état peuvent également définir une méthode `config()` facultative avec `concurrency_group`, `concurrency_limit` et `cost_units` lorsque l’action d’entrée en file d’attente doit participer à l’admission des workers, aux budgets pondérés des files d’attente ou des fournisseurs, ainsi qu’à d’autres stratégies de ressources.

Les gardes de transition implémentent `Queuety\Contracts\StateGuard` :

```php
namespace Queuety\Contracts;

interface StateGuard {
    public function allows( array $state, array $event_payload, string $event, array $payload = [] ): bool;
}
```

## API d’inspection

Utilisez la façade pour inspecter les machines en cours d’exécution :

```php
$status   = Queuety::machine_status( $machine_id );
$machines = Queuety::list_machines();
$events   = Queuety::machine_timeline( $machine_id );
$trace    = Queuety::machine_trace( $machine_id );
$state    = Queuety::machine_state_at( $machine_id, $event_id );
```

Les machines à états ne disposent d’aucune commande WP-CLI : `wp queuety workflow ...` concerne uniquement les workflows. Utilisez ces API PHP, par exemple avec `wp eval`, pour inspecter les machines depuis la ligne de commande.

Ces API exposent le nom de l’état actuel, le statut du cycle de vie, l’état public, les événements disponibles, les métadonnées de définition, la chronologie complète des transitions et un ensemble de traces normalisé pour les interfaces de débogage. Les lignes de la liste des machines comprennent la version de la définition, son hachage et la clé d’idempotence. Les écrans de liste peuvent ainsi afficher la version source et la version d’exécution sans charger chaque machine individuellement. L’ensemble de traces comprend les états regroupés, les événements bruts, les tâches d’action corrélées, les journaux, les références aux artefacts, les références aux fragments, les entrées et sorties du gestionnaire, l’état avant et après, le contexte, les durées et les erreurs structurées.

## Sessions d’agent

Les machines à états sont particulièrement utiles pour les systèmes d’agents qui fonctionnent davantage comme des sessions que comme des pipelines. Une session qui passe par `awaiting_user`, `planning`, `running_agents`, `awaiting_review` et `completed` se comprend généralement mieux comme un cycle de vie explicite que comme une très longue définition de workflow comportant de nombreuses attentes et transitions en arrière.

## Voir aussi

- [Neuron Machine à états de session](https://queuety.inline0.dev/fr/docs/examples/neuron-session-state-machine)
- [Neuron Machine à états de mémoire et de révision](https://queuety.inline0.dev/fr/docs/examples/neuron-memory-review)
- [Orchestration d’agents](https://queuety.inline0.dev/fr/docs/workflows/agent-orchestration)
- [Signaux de workflow](https://queuety.inline0.dev/fr/docs/workflows/signals)
- [Dépendances de workflow](https://queuety.inline0.dev/fr/docs/workflows/dependencies)
- [Répétitions](https://queuety.inline0.dev/fr/docs/workflows/repeats)
- [Artefacts](https://queuety.inline0.dev/fr/docs/features/artifacts)
- [PHP API](https://queuety.inline0.dev/fr/docs/api)
