# `GEPA.State`
[🔗](https://github.com/nshkrdotcom/gepa_ex/blob/v0.3.0/lib/gepa/state.ex#L1)

Persistent state tracking the complete optimization history.

This is the heart of GEPA - all candidates, scores, Pareto fronts,
and lineage are stored here.

# `t`

```elixir
@type t() :: %GEPA.State{
  adapter_state: map(),
  best_outputs_valset:
    %{required(GEPA.Types.data_id()) =&gt; [{GEPA.Types.program_idx(), term()}]}
    | nil,
  budget_hooks: [(non_neg_integer(), non_neg_integer() -&gt; term())],
  evaluation_cache: term() | nil,
  frontier_type: :instance | :objective | :hybrid | :cartesian,
  full_program_trace: [map()],
  i: integer(),
  list_of_named_predictors: [String.t()],
  named_predictor_id_to_update_next_for_program_candidate: [non_neg_integer()],
  num_full_ds_evals: non_neg_integer(),
  num_metric_calls_by_discovery: [non_neg_integer()],
  objective_pareto_front: %{required(String.t()) =&gt; float()},
  parent_program_for_candidate: [[GEPA.Types.program_idx() | nil]],
  pareto_front_cartesian: %{
    required({GEPA.Types.data_id(), String.t()}) =&gt; float()
  },
  pareto_front_valset: %{required(GEPA.Types.data_id()) =&gt; float()},
  prog_candidate_objective_scores: [%{required(String.t()) =&gt; float()}],
  prog_candidate_val_subscores: [GEPA.Types.sparse_scores()],
  program_at_pareto_front_cartesian: %{
    required({GEPA.Types.data_id(), String.t()}) =&gt;
      MapSet.t(GEPA.Types.program_idx())
  },
  program_at_pareto_front_objectives: %{
    required(String.t()) =&gt; MapSet.t(GEPA.Types.program_idx())
  },
  program_at_pareto_front_valset: GEPA.Types.pareto_fronts(),
  program_candidates: [GEPA.Types.candidate()],
  total_num_evals: non_neg_integer(),
  validation_schema_version: pos_integer()
}
```

# `add_budget_hook`

```elixir
@spec add_budget_hook(t(), (non_neg_integer(), non_neg_integer() -&gt; term())) :: t()
```

Add a runtime-only budget hook.

Hooks are invoked by `increment_evals/2` and intentionally omitted from
persisted state.

# `add_program`

```elixir
@spec add_program(
  t(),
  GEPA.Types.candidate(),
  [GEPA.Types.program_idx()],
  GEPA.Types.sparse_scores(),
  Keyword.t()
) :: {t(), GEPA.Types.program_idx()}
```

Add a new program to the state and update Pareto fronts.

## Parameters

- `state`: Current state
- `new_candidate`: New program to add
- `parent_program_ids`: List of parent indices
- `val_scores`: Map of val_id -> score for new program

## Returns

`{new_state, new_program_idx}` tuple

# `consistent?`

```elixir
@spec consistent?(t()) :: boolean()
```

Return whether the state has internally consistent candidate-indexed fields.

# `from_dict`

```elixir
@spec from_dict(map()) :: t()
```

Build state from a persisted dictionary or legacy map payload.

# `get_pareto_front_mapping`

```elixir
@spec get_pareto_front_mapping(t()) :: map()
```

Return the active Pareto-front mapping for the configured frontier type.

# `get_program_average_val_subset`

```elixir
@spec get_program_average_val_subset(t(), GEPA.Types.program_idx()) ::
  {float(), non_neg_integer()}
```

Return average validation score and evaluated-count for a program.

# `get_program_score`

```elixir
@spec get_program_score(t(), GEPA.Types.program_idx()) :: {float(), non_neg_integer()}
```

Get average score for a program across evaluated validation examples.

## Returns

`{average_score, count}` tuple

# `increment_evals`

```elixir
@spec increment_evals(t(), non_neg_integer()) :: t()
```

Increment metric evaluation count and notify budget hooks.

# `load`

```elixir
@spec load(Path.t()) :: {:ok, t()} | {:error, term()}
```

Load persisted state from a run directory.

# `load!`

```elixir
@spec load!(Path.t()) :: t()
```

Load persisted state from a run directory or raise.

# `new`

```elixir
@spec new(
  GEPA.Types.candidate(),
  GEPA.EvaluationBatch.t(),
  [GEPA.Types.data_id()],
  Keyword.t()
) :: t()
```

Create new state from seed candidate and initial evaluation.

## Parameters

- `seed_candidate`: Initial program as map of component name -> text
- `eval_batch`: Results from evaluating seed on validation set
- `valset_ids`: List of validation example IDs

## Returns

New `GEPA.State` struct initialized with seed program

# `save`

```elixir
@spec save(t(), Path.t() | nil, keyword()) :: :ok
```

Persist state to a run directory.

GEPA Ex writes `gepa_state.etf` instead of upstream Python's pickle-based
`gepa_state.bin`, and also writes human-readable `candidates.json` and
`run_log.json` when available.

# `tracked_scores`

```elixir
@spec tracked_scores(t()) :: [float()]
```

Return per-program average validation scores in candidate-index order.

# `upgrade_dict`

```elixir
@spec upgrade_dict(map()) :: t()
```

Upgrade a persisted state dictionary into the current `GEPA.State` struct.

Accepts atom or string keys and migrates legacy list-shaped validation fields
to sparse maps.

# `validation_schema_version`

```elixir
@spec validation_schema_version() :: pos_integer()
```

Return the current persisted state schema version.

# `valset_evaluations`

```elixir
@spec valset_evaluations(t()) :: %{
  required(GEPA.Types.data_id()) =&gt; [GEPA.Types.program_idx()]
}
```

Return validation ids and program indices that have evaluated them.

# `write_valset_outputs`

```elixir
@spec write_valset_outputs(
  Path.t() | nil,
  [GEPA.Types.data_id()],
  [term()],
  integer(),
  GEPA.Types.program_idx()
) :: :ok
```

Write generated validation outputs to the run-directory inspection tree.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
