---
name: process_state_machine
kind: function
lang: cpp
domain: core
version: "1.0.0"
purity: pure
signature: "fn_ui::ProcessState fn_ui::process_transition(fn_ui::ProcessState s, fn_ui::ProcessEvent e); const char* fn_ui::process_state_name(fn_ui::ProcessState); const char* fn_ui::process_event_name(fn_ui::ProcessEvent)"
description: "State machine puro para procesos async. Estados: Idle, Running, Success, Error. Eventos: Trigger, Spawned, Finished, Failed, Timeout, Reset. Transiciones invalidas devuelven el mismo estado sin mutar."
tags: [state_machine, process, async, runner, pure]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: []
tested: true
tests: ["process_transition: idle/spawned -> running", "process_transition: running -> success/error", "process_transition: reset from terminal", "process_transition: invalid events keep state", "process_state_name and process_event_name"]
test_file_path: "cpp/tests/test_process_state_machine.cpp"
file_path: "cpp/functions/core/process_state_machine.cpp"
params:
  - name: s
    desc: "Estado actual (Idle, Running, Success, Error)"
  - name: e
    desc: "Evento a aplicar (Trigger, Spawned, Finished, Failed, Timeout, Reset)"
output: "Nuevo ProcessState. Si la transicion (s, e) no esta definida, devuelve s sin cambios. process_state_name y process_event_name retornan punteros a literales staticos (no alocan)."
---

# process_state_machine

Las apps del registry usan `process_runner` (impuro: threads, mutex, popen)
para lanzar reindex, builds, deploys... Esta funcion extrae el contrato de
estados a una tabla pura que se puede testear, simular y compartir con CLIs
y bots sin depender del runner concreto.

## Tabla de transiciones

| Estado actual | Evento     | Nuevo estado |
|---------------|------------|--------------|
| Idle          | Spawned    | Running      |
| Idle          | Trigger    | Idle (la solicitud no cambia el estado por si sola — el runner debe Spawnar) |
| Running       | Finished   | Success      |
| Running       | Failed     | Error        |
| Running       | Timeout    | Error        |
| Success       | Reset      | Idle         |
| Error         | Reset      | Idle         |
| cualquier otra combinacion | | mismo estado |

`Trigger` se mantiene como evento explicito para que el runner pueda emitir
"se pidio lanzar" antes de saber si el proceso arranca (util para logs y UI).

## API

```cpp
namespace fn_ui {

enum class ProcessState { Idle, Running, Success, Error };
enum class ProcessEvent { Trigger, Spawned, Finished, Failed, Timeout, Reset };

ProcessState process_transition(ProcessState s, ProcessEvent e);
const char*  process_state_name(ProcessState s);
const char*  process_event_name(ProcessEvent e);

}
```

## Uso desde process_runner

`process_runner` mantiene su `std::atomic<int>` con el estado, pero llama a
`process_transition` para decidir el siguiente valor. Esto evita que la
logica de transicion se duplique entre el thread productor y la UI consumer.
