
# Workflow Event Log

The workflow event log records a trace for every durable workflow boundary. Each trace event can include the step input, output, public state before the step, public state after the step, runtime context, artifact references, streaming chunks, timing, and error details.

## What gets recorded

| Event | When | Data captured |
|---|---|---|
| `step_started` | Before a step handler runs | Job ID, queue, attempt, step name, step type, input, and state before execution |
| `step_completed` | After a step handler succeeds | Input, output, state before, state after, context, artifacts, chunks, and duration |
| `step_failed` | When a step handler throws | Input, state before, state after when available, context, error class, error message, trace, and duration |
| `step_branch_completed` | When one parallel branch succeeds | Branch input, output, state before, state after, context, and duration |
| `step_item_completed` | When one for-each item succeeds | Item input, output, state before, state after, item metadata, context, and duration |
| `workflow_waiting` | When a wait step parks the run | Wait type, wait targets, wait mode, result key, match metadata, and state while waiting |
| `workflow_resumed` | When a wait step is satisfied | Resume payload, state before resuming, and state after resuming |
| `workflow_replayed` | When an export is recreated | Source workflow metadata and replay state |

## Querying the timeline

```php
$events = Queuety::workflow_timeline( $workflow_id );

foreach ( $events as $event ) {
    echo $event['step_index'] . ' ' . $event['event'] . ' ' . $event['handler'] . "\n";

    if ( 'step_completed' === $event['event'] ) {
        $input        = $event['input'];
        $output       = $event['output'];
        $state_before = $event['state_before'];
        $state_after  = $event['state_after'];
    }

    if ( 'step_failed' === $event['event'] ) {
        echo 'Error: ' . $event['error']['message'] . "\n";
    }
}
```

Each event row contains:

- `id`
- `workflow_id`
- `job_id`
- `parent_event_id`
- `step_index`
- `step_name`
- `step_type`
- `handler`
- `event`
- `queue`
- `attempt`
- `input`
- `output`
- `state_before`
- `state_after`
- `context`
- `artifacts`
- `chunks`
- `error`
- `duration_ms`
- `created_at`

## Normalized trace bundle

Use `workflow_trace()` when building a debugger UI:

```php
$trace = Queuety::workflow_trace( $workflow_id );
```

The trace bundle includes:

- `workflow`
- `steps`
- `events`
- `jobs`
- `logs`
- `artifacts`
- `chunks`
- `signals`
- `wait_dependencies`

`steps` groups events by step index and includes the latest important event for each step.

## Step state lookup

```php
$state = Queuety::workflow_state_at( $workflow_id, $step_index );
```

This returns the public `state_after` from the latest completed or resumed event for that step, or `null` when no state was recorded.

## Runtime trace metadata

Handlers can add application-level trace details while they run:

```php
Queuety::trace_input( [ 'resolved' => $resolved_input ] );
Queuety::trace_context( [ 'ability' => 'content/load-post' ] );
Queuety::trace_output( [ 'post' => $post ] );
```

Step handlers can also return reserved trace metadata:

```php
return [
    'result' => 'done',
    '_queuety_trace' => [
        'input' => [ 'resolved' => $resolved_input ],
        'context' => [ 'node_id' => 'loadPost' ],
        'artifacts' => [
            [ 'key' => 'brief', 'kind' => 'markdown' ],
        ],
    ],
];
```

The `_queuety_trace` key is stored in the event log and is not merged into workflow state.

## CLI

View the timeline as a table:

```bash
wp queuety workflow timeline 42
```

View state after a step:

```bash
wp queuety workflow state-at 42 0
```

## Retention

Event logs accumulate over time. Use `prune()` to delete old trace events:

```php
$deleted = Queuety::workflow_events()->prune( 30 );
```
