> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reilabs.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Run trajectory learning

> Configure a trajectory learner, execute and report trials, reuse acquired sequences, and add structural comparisons or contextual refinement through the API.

Trajectory learning learns command sequences from executed trials and measured outcomes. It is a branch of [reinforcement learning with adaptive structure (RLAS)](https://docs.reilabs.org/docs/neuroadapt/architecture.md#reinforcement-learning-with-adaptive-structure). Use it for numeric commands that your application can execute, measure, and revise across attempts.

Commands can represent process setpoints, staged operations, actuator inputs, or sequence edits through a fixed decoder. [Machina](https://docs.reilabs.org/docs/machina/index.md) uses this same learner in its robot and machine-control pipeline.

This guide takes you from a fresh Domain to acquisition and retained execution. It also shows how to add structural comparisons and contextual corrections.

## Choose the learning stage

| Your goal | Configure this mechanism | Run this loop |
| - | - | - |
| Acquire a numeric sequence | `episode_credit` | Propose, execute, observe |
| Select, shorten, or reorder acquired executions | `confirmed_execution` | Propose candidates, execute comparisons, observe |
| Learn corrections for the current context | `contextual_execution` | Propose candidates, evaluate offsets, execute comparisons, observe |
| Reuse an acquired sequence | Existing acquisition Domain | Propose with `mode: "frozen"`, then execute |
| Reuse learned corrections | Existing refinement Domain | Evaluate the current context, then execute the corrected base |

Begin with acquisition. Add later stages when your application needs selection, structural changes, or corrections across starting conditions.

## Define the execution contract

Before making API calls, define what a state coordinate, command, and outcome mean. Preserve those definitions throughout acquisition and reuse.

| Define in your application | What to specify |
| - | - |
| State | Measured coordinates, order, units, normalization, and invalid-measurement handling |
| Goal | Target coordinates and their corresponding state indices |
| Commands | Values applied together, physical bounds, decoder, and duration |
| Episode | Reset conditions, termination, and handling of shorter sequences |
| Outcome | A measured score with a fixed direction, scale, and assessment time |
| Run budget | Attempt count, execution cost, and stopping rule |

The example uses four state coordinates, a two-coordinate goal, and up to eight commands with two values each. Command values use `[-1, 1]`. The adapter holds each command for half a second and pads shorter sequences with its declared neutral command, `[0.0, 0.0]`.

These are example interface choices. Define the physical meaning of every coordinate and neutral input before execution. For a process task, map numeric controls to permitted setpoints in your adapter.

Implement these application hooks:

| Hook | Return or behavior |
| - | - |
| `reset_and_measure(reset_key)` | Restore a saved scenario and return `state`, `goal`, and Boolean `initial_valid` |
| `execute_sequence(actions)` | Execute commands and return actual `states` and `actions`, including any measured early termination |
| `measure_outcome(trace)` | Compute the declared higher-is-better score from the measured trace |

For this example, `measure_outcome` returns a value in `[0, 1]`. Use your task's measured completion, yield, purity, or other declared objective. Keep the actual completion criterion separately when the learning score measures partial progress.

The API supplies proposals and learns from observations. Your adapter supplies the environment execution and measurements.

## Connect and create a fresh learner

Use a Unit API Key in the server-side `ADAPT1_API_KEY` environment variable. The production base is `https://rei-neuroadapt-api.reilabs.org/api/v1`.

The following Python helper uses the standard library. Its journal preserves request intent, responses, and measured execution records. It stops on request errors so the caller can reconcile interrupted writes.

```python theme={null}
import json
import math
import os
import uuid
from pathlib import Path
from urllib.request import Request, urlopen

BASE = "https://rei-neuroadapt-api.reilabs.org/api/v1"
PREFIX = "trajectory-" + uuid.uuid4().hex[:16]
ACQUISITION_DOMAIN = PREFIX + "-acquisition"
RUN_DIR = Path("trajectory-runs") / PREFIX
RUN_DIR.mkdir(parents=True, exist_ok=True)

def journal(kind, payload):
    line = json.dumps({"kind": kind, "payload": payload}, allow_nan=False)
    with (RUN_DIR / "journal.jsonl").open("a", encoding="utf-8") as stream:
        stream.write(line + "\n")
        stream.flush()
        os.fsync(stream.fileno())

def post(path, body):
    encoded = json.dumps(body, allow_nan=False).encode("utf-8")
    if len(encoded) > 1024 * 1024:
        raise ValueError("Request exceeds the reference body limit")
    request = Request(
        BASE + path,
        data=encoded,
        method="POST",
        headers={
            "Authorization": "Bearer " + os.environ["ADAPT1_API_KEY"],
            "Content-Type": "application/json",
        },
    )
    journal("request", {"path": path, "body": body})
    with urlopen(request, timeout=180) as response:
        result = json.load(response)
    journal("response", {"path": path, "body": result})
    return result

def trajectory(domain, operation, body=None):
    return post(
        f"/domains/{domain}/trajectory/{operation}",
        {} if body is None else body,
    )

def create_stage(domain, config):
    post("/domains", {"domain_id": domain})
    state = trajectory(domain, "state")
    if state.get("status") != "not_configured":
        raise RuntimeError("Expected a fresh trajectory learner")
    receipt = trajectory(domain, "configure", {"config": config})
    state = trajectory(domain, "state")
    if state.get("status") == "not_configured":
        raise RuntimeError("Configuration was not applied")
    return receipt, state
```

Generate and save the prefix once for a fresh run. To resume, reload the same prefix, Domain IDs, and executor settings. Continue the existing learner after reconciling pending work.

Configure acquisition with the interface dimensions:

```python theme={null}
config = {
    "mechanism": "episode_credit",
    "state_dimensions": 4,
    "action_dimensions": 2,
    "goal_indices": [0, 1],
    "horizon": 8,
    "capacity": 128,
    "max_pending": 1,
    "seed": 1,
    "outcome_mode": "reward",
}
receipt, configured_state = create_stage(ACQUISITION_DOMAIN, config)
journal("manifest", {"prefix": PREFIX, "config": config})
```

| Setting | How to choose it |
| - | - |
| `state_dimensions` | Length of each measured state vector |
| `action_dimensions` | Number of values applied together in a command row |
| `goal_indices` | State coordinates corresponding to the goal, in the same order |
| `horizon` | Maximum logical command count per proposal |
| `capacity` | Upper bound on retained records |
| `max_pending` | Outstanding decisions your runner can execute and reconcile |
| `seed` | Learner seed, separate from environment reset seeds |
| `outcome_mode` | `reward` when your adapter supplies the measured outcome |

The example allows one outstanding proposal. Finish its observation or cancellation before requesting another exploratory proposal. Set the total attempt budget in your runner.

### Choose default or profile settings

Default settings leave the native acquisition defaults in place. Profile settings enable the optional learning switches for proposal edits and retention.

Merge this fragment into `config` before the initial `create_stage` call when your adapter provides measured per-command outcomes:

```json theme={null}
{
  "coherent_edits": true,
  "global_recall": true,
  "executed_prefix_mutation": true,
  "progress_guided_mutation": true,
  "sequence_compaction": true,
  "outcome_tier_exploration": true,
  "retain_prefix_failures": false
}
```

Sending `step_outcomes` alone does not enable progress-guided edits. Configure the relevant switches and return measurements for the commands that actually executed. If you only measure the final outcome, omit `step_outcomes` and keep progress-related switches disabled.

Save the resolved configuration returned by the service. Use the [configuration reference](https://docs.reilabs.org/docs/machina/configuration.md#acquisition-fields) for field ranges and deployed-limit guidance.

## Run acquisition

Each attempt uses the same Domain. Reset or measure the environment, request a sequence, execute it, and report what actually happened.

### Validate proposals and measured traces

For `T` executed commands, report `T` action rows and `T + 1` state rows. The first state is the measured starting state. Each later state follows its corresponding action.

| Observation field | Send |
| - | - |
| `decision_id` | ID returned by this proposal |
| `states` | Initial state followed by measured successor states |
| `actions` | Actual applied commands in the declared numeric coordinate system |
| `outcome` | Measured final score in reward mode |
| `observation_validity` | Optional Boolean values aligned with all state rows |
| `step_outcomes` | Optional measured values aligned with executed commands |

The following helpers enforce the example's dimensions and command bounds:

```python theme={null}
def numeric_vector(values, width):
    return (
        isinstance(values, list)
        and len(values) == width
        and all(isinstance(x, (int, float)) and not isinstance(x, bool)
                and math.isfinite(x) and abs(x) <= 1e12 for x in values)
    )

def executable_actions(actions):
    if not isinstance(actions, list) or not 1 <= len(actions) <= 8:
        raise ValueError("Expected between one and eight command rows")
    if not all(numeric_vector(row, 2) for row in actions):
        raise ValueError("Expected two finite values per command")
    if any(abs(x) > 1 for row in actions for x in row):
        raise ValueError("Command exceeds the declared bounds")
    return [list(row) for row in actions] + [
        [0.0, 0.0] for _ in range(8 - len(actions))
    ]

def measured_quality(trace):
    value = measure_outcome(trace)
    if not numeric_vector([value], 1) or not 0 <= value <= 1:
        raise ValueError("Expected the declared quality score in [0, 1]")
    return float(value)
```

### Execute and observe an attempt

Implement the adapter hooks above, then use this function for each saved training reset key:

```python theme={null}
def acquire_once(reset_key):
    initial = reset_and_measure(reset_key)
    if not numeric_vector(initial["state"], 4):
        raise ValueError("Invalid initial state")
    if not numeric_vector(initial["goal"], 2):
        raise ValueError("Invalid goal")
    if initial["initial_valid"] is not True:
        raise ValueError("This example requires a valid reset measurement")

    proposal = trajectory(ACQUISITION_DOMAIN, "propose", {
        "state": initial["state"],
        "goal": initial["goal"],
        "mode": "explore",
        "request_id": PREFIX + "-attempt-" + uuid.uuid4().hex,
    })
    commands = executable_actions(proposal["actions"])
    journal("execution_plan", {"reset_key": reset_key, "actions": commands})
    trace = execute_sequence(commands)
    journal("execution", trace)

    count = len(trace["actions"])
    if not 1 <= count <= len(commands):
        raise ValueError("Expected a nonempty executed prefix")
    if not all(numeric_vector(row, 2) for row in trace["actions"]):
        raise ValueError("Invalid executed action rows")
    if any(abs(x) > 1 for row in trace["actions"] for x in row):
        raise ValueError("Applied commands violate the declared bounds")
    if len(trace["states"]) != count + 1:
        raise ValueError("Expected one more state row than action rows")
    if not all(numeric_vector(row, 4) for row in trace["states"]):
        raise ValueError("Invalid measured states")
    if trace["states"][0] != initial["state"]:
        raise ValueError("Trace starts from a different measured state")

    body = {
        "decision_id": proposal["decision_id"],
        "states": trace["states"],
        "actions": trace["actions"],
        "outcome": measured_quality(trace),
    }
    if "observation_validity" in trace:
        validity = trace["observation_validity"]
        if (len(validity) != count + 1
                or any(type(value) is not bool for value in validity)
                or validity[0] is not True):
            raise ValueError("Validity must match the measured state rows")
        body["observation_validity"] = validity
    if "step_outcomes" in trace:
        if not numeric_vector(trace["step_outcomes"], count):
            raise ValueError("Step outcomes must match executed commands")
        body["step_outcomes"] = trace["step_outcomes"]

    receipt = trajectory(ACQUISITION_DOMAIN, "observe", body)
    state = trajectory(ACQUISITION_DOMAIN, "state")
    return receipt, state

def run_acquisition(training_reset_keys):
    for reset_key in training_reset_keys:
        acquire_once(reset_key)
```

Call `acquire_once` for one training reset before starting a longer run. Confirm the proposal ID, action shape, observation acknowledgement, and readable learner state. Then pass your application-owned training reset sequence to `run_acquisition`.

The helper sends `propose` and `observe` to `/domains/{domain_id}/trajectory/{operation}`. Always send `mode: "explore"` during acquisition. Frozen proposals do not provide the same training workflow.

Report an early stop using only the commands and states that actually occurred. Include padding only when it executed. Preserve the proposed controls separately when the adapter clips or changes them.

If validation fails after proposal, keep its decision ID and trace for recovery. Cancel the decision only when you intentionally abandon it. Cancellation contributes no outcome.

## Inspect and reuse acquired behavior

### Kept records

Acquisition revises retained executions. The active kept set can remain smaller than configured `capacity`. Inspect the actual records when choosing parents or preparing a structural stage.

Stop acquisition writes and finish pending decisions before exporting. This helper reads all retained pages and checks that the incumbent stays unchanged:

```python theme={null}
def export_executions(domain):
    records = []
    offset = 0
    expected_total = None
    incumbent_id = None
    while True:
        page = trajectory(domain, "records", {
            "best_only": True, "offset": offset, "limit": 64,
        })
        if expected_total is None:
            expected_total = page["total"]
            incumbent_id = page["incumbent_id"]
        elif (page["total"] != expected_total
              or page["incumbent_id"] != incumbent_id):
            raise RuntimeError("Acquisition changed during export")
        batch = page["records"]
        records.extend(batch)
        offset += len(batch)
        if offset == expected_total:
            break
        if not batch or offset > expected_total:
            raise RuntimeError("Unexpected records pagination")
    ids = [record["id"] for record in records]
    if not records or len(set(ids)) != len(ids) or incumbent_id not in ids:
        raise RuntimeError("Export lacks unique records or its incumbent")
    journal("retained_executions", {
        "records": records, "incumbent_id": incumbent_id,
    })
    return records, incumbent_id

records, incumbent_id = export_executions(ACQUISITION_DOMAIN)
```

Preserve each record's native `id`, `actions`, `initial_state`, and `initial_valid`. An `acquisition_reference` must identify a kept record. Keep a local mapping from that ID to its reset conditions when revisiting an acquired context.

### Execute with learning stopped

Use a reserved evaluation reset and request frozen controls:

```python theme={null}
def evaluate_acquired(reset_key):
    initial = reset_and_measure(reset_key)
    if (initial["initial_valid"] is not True
            or not numeric_vector(initial["state"], 4)
            or not numeric_vector(initial["goal"], 2)):
        raise ValueError("Invalid evaluation reset")
    before = trajectory(ACQUISITION_DOMAIN, "state")["fingerprint"]
    proposal = trajectory(ACQUISITION_DOMAIN, "propose", {
        "state": initial["state"],
        "goal": initial["goal"],
        "mode": "frozen",
        "request_id": PREFIX + "-evaluation-" + uuid.uuid4().hex,
    })
    trace = execute_sequence(executable_actions(proposal["actions"]))
    journal("evaluation", {"trace": trace, "quality": measured_quality(trace)})
    after = trajectory(ACQUISITION_DOMAIN, "state")["fingerprint"]
    if after != before:
        raise RuntimeError("Learner state changed during frozen evaluation")
    return trace
```

This path sends no observation. Keep evaluation outcomes in the application log. Reuse the same decoder, timing, padding, and score definitions.

## Add structural comparisons

Use `confirmed_execution` after acquisition when you want to select or restructure acquired plans. Create a separate Domain for each intervention.

| Intervention | Compare |
| - | - |
| `selection` | The supplied executions |
| `deletion` | Removal of command spans |
| `ordering` | Changes to the order of control changes |

This example selects among the exported executions using the same measured quality score:

```python theme={null}
selection_domain = PREFIX + "-selection"
create_stage(selection_domain, {
    "mechanism": "confirmed_execution",
    "executions": records,
    "incumbent_id": incumbent_id,
    "intervention": "selection",
    "command_budget": 8,
    "objective_names": ["quality"],
    "max_contexts": 4,
})

def compare_structural(domain, context_ids, request_id, reference_state):
    if not 1 <= len(context_ids) <= 4 or len(set(context_ids)) != len(context_ids):
        raise ValueError("Use one to four unique registered contexts")
    proposal = trajectory(domain, "propose", {
        "state": reference_state,
        "goal": [0.0],
        "mode": "explore",
        "request_id": request_id,
        "context_ids": context_ids,
    })
    if not proposal["candidates"]:
        raise RuntimeError("No comparison candidates returned")
    outcomes = []
    for index, candidate in enumerate(proposal["candidates"]):
        for context_id in context_ids:
            initial = reset_and_measure(context_id)
            if initial["initial_valid"] is not True:
                raise ValueError("Invalid comparison reset")
            actions = executable_actions(candidate["execution"]["actions"])
            trace = execute_sequence(actions)
            journal("comparison_execution", {
                "decision_id": proposal["decision_id"],
                "candidate_index": index, "context_id": context_id,
                "trace": trace,
            })
            outcomes.append({
                "candidate_index": index,
                "context_id": context_id,
                "objectives": [measured_quality(trace)],
            })
    return trajectory(domain, "observe", {
        "decision_id": proposal["decision_id"], "outcomes": outcomes,
    })
```

Each context ID must map to a saved scenario in your application. Reset that scenario before every candidate execution. The comparison envelope uses an exported `initial_state` and `[0.0]` as its goal placeholder. The reset scenario supplies the actual task target.

Run a nomination comparison, then a confirmation comparison on separate registered contexts. Use a fresh request ID for each. Read `trajectory/state` afterward and carry its `selected_execution` into the next stage.

```python theme={null}
def run_selection(nomination_context_ids, confirmation_context_ids):
    if set(nomination_context_ids) & set(confirmation_context_ids):
        raise ValueError("Keep nomination and confirmation contexts separate")
    for phase, context_ids in (
        ("nomination", nomination_context_ids),
        ("confirmation", confirmation_context_ids),
    ):
        compare_structural(
            selection_domain, context_ids,
            PREFIX + "-" + phase + "-" + uuid.uuid4().hex,
            records[0]["initial_state"],
        )
    selected = trajectory(selection_domain, "state")["selected_execution"]
    if not selected:
        raise RuntimeError("No selected execution returned")
    journal("selected_base", selected)
    return selected
```

For deletion or ordering, create another stage with the corresponding `intervention`. Supply the selected execution and its native ID. Carry the selected result forward even when it remains unchanged.

Count returned candidates multiplied by comparison contexts before scheduling execution. Include nomination, confirmation, and later refinement in the total budget. See the [structural-stage reference](https://docs.reilabs.org/docs/machina/structural-stages.md) for the complete multi-stage handoff.

## Add corrections for changing contexts

Use `contextual_execution` when a retained base needs corrections for different measured starts. Your application preserves the base and defines the context vector.

Acquisition can follow a shared lineage across starts. Use separate acquisition learners when you need independent searches. Refinement learns a correction around its supplied base.

Collect context vectors from actual training resets. Keep their coordinate order and scale fixed. Use separate scenario sets for representation support, training comparisons, and final evaluation.

The example context contains the two target errors and the remaining two state coordinates. Set `support_context_ids` to your saved support-scenario IDs. Build context vectors from actual resets:

```python theme={null}
def reset_context(context_id):
    initial = reset_and_measure(context_id)
    if (initial["initial_valid"] is not True
            or not numeric_vector(initial["state"], 4)
            or not numeric_vector(initial["goal"], 2)):
        raise ValueError("Invalid context measurement")
    state, goal = initial["state"], initial["goal"]
    context = [goal[0] - state[0], goal[1] - state[1], state[2], state[3]]
    if not numeric_vector(context, 4):
        raise ValueError("Invalid derived context")
    return context

if not 1 <= len(support_context_ids) <= 257:
    raise ValueError("Use the supported number of measured support contexts")
support_contexts = [reset_context(cid) for cid in support_context_ids]
```

Configure a new refinement Domain around the selected structural execution:

```python theme={null}
selected_base = trajectory(selection_domain, "state")["selected_execution"]
base_actions = selected_base["actions"]
executable_actions(base_actions)
refinement_domain = PREFIX + "-refinement"
refinement_config = {
    "mechanism": "contextual_execution",
    "horizon": len(base_actions),
    "action_dimensions": 2,
    "contexts": support_contexts,
    "objective_names": ["quality"],
    "candidate_count": 8,
    "max_contexts": 64,
    "seed": 18,
    "radius": 0.08,
    "retained_variance": 0.99,
    "contextual": True,
    "action_trust_region": True,
}
create_stage(refinement_domain, refinement_config)
```

Run each refinement update as follows:

1. Request `propose` with `mode: "explore"`, a fresh `request_id`, `state`, `goal`, `context_ids`, and `discovery_context_ids`.
2. Use a representative measured context as `state` and `[0.0]` as the proposal-envelope goal.
3. Reserve some comparison contexts for confirmation, outside `discovery_context_ids`.
4. Reset every candidate/context pair and measure its current context vector.
5. Call `evaluate` with `context`, `candidate_index`, and the proposal's `decision_id`.
6. Add the returned `offsets` to the preserved base, apply declared bounds, and execute.
7. Submit one complete `observe` body containing every candidate/context outcome, including confirmation contexts.

The `observe` body uses the same `decision_id` and `outcomes` structure as structural comparison. Each row contains `candidate_index`, `context_id`, and `objectives` in the configured order.

The `reset_context` helper resets each scenario and measures its context with the same encoding used in `support_contexts`.

For this example, compose corrections as follows:

```python theme={null}
def corrected_actions(offsets):
    if (len(offsets) != len(base_actions)
            or not all(numeric_vector(row, 2) for row in offsets)):
        raise ValueError("Offsets must match the base shape")
    corrected = [
        [max(-1.0, min(1.0, base + delta))
         for base, delta in zip(base_row, offset_row)]
        for base_row, offset_row in zip(base_actions, offsets)
    ]
    return executable_actions(corrected)
```

Run one complete comparison with this function. Choose comparison IDs outside `support_context_ids` and keep final evaluation IDs separate:

```python theme={null}
def refine_once(context_ids, discovery_context_ids):
    if (not 2 <= len(context_ids) <= refinement_config["max_contexts"]
            or len(set(context_ids)) != len(context_ids)
            or not all(isinstance(cid, str) and cid.strip() and len(cid) <= 128
                       for cid in context_ids)):
        raise ValueError("Invalid registered comparison contexts")
    discovery = set(discovery_context_ids)
    if (len(discovery) != len(discovery_context_ids)
            or not discovery or not discovery < set(context_ids)):
        raise ValueError("Use disjoint discovery and confirmation subsets")
    if set(context_ids) & set(support_context_ids):
        raise ValueError("Keep support and comparison contexts separate")
    proposal = trajectory(refinement_domain, "propose", {
        "state": support_contexts[0],
        "goal": [0.0],
        "mode": "explore",
        "request_id": PREFIX + "-refine-" + uuid.uuid4().hex,
        "context_ids": context_ids,
        "discovery_context_ids": discovery_context_ids,
    })
    candidate_count = len(proposal["candidates"])
    if candidate_count < 2:
        raise RuntimeError("Expected comparison candidates")
    outcomes = []
    for candidate_index in range(candidate_count):
        for context_id in context_ids:
            context = reset_context(context_id)
            if not numeric_vector(context, len(support_contexts[0])):
                raise ValueError("Context does not match the configured encoding")
            evaluated = trajectory(refinement_domain, "evaluate", {
                "context": context,
                "candidate_index": candidate_index,
                "decision_id": proposal["decision_id"],
            })
            trace = execute_sequence(corrected_actions(evaluated["offsets"]))
            journal("refinement_execution", {
                "decision_id": proposal["decision_id"],
                "candidate_index": candidate_index, "context_id": context_id,
                "trace": trace,
            })
            outcomes.append({
                "candidate_index": candidate_index,
                "context_id": context_id,
                "objectives": [measured_quality(trace)],
            })
    return trajectory(refinement_domain, "observe", {
        "decision_id": proposal["decision_id"], "outcomes": outcomes,
    })
```

During retained use, call `evaluate` with `{"context": current_context}` only. Omit `candidate_index` and `decision_id`. Execute `corrected_actions(response["offsets"])` and log the outcome without `observe`.

Keep the base, offset scale, context encoding, and command decoder with the refinement Domain ID. The configured radius is an initial setting. It can expand after successful comparisons and shrink after unsuccessful comparisons.

Use [contextual refinement](https://docs.reilabs.org/docs/machina/refinement.md) for the complete comparison loop and optional normalization, context-basis, and response-guidance settings.

## Inspect progress and manage the run

| What you observe | What to check |
| - | - |
| Different proposals execute identically | Compare raw commands with decoded, clipped, or rounded controls |
| The best score stops improving | Inspect retained parents, edit size, score resolution, and execution coverage |
| An inactive plan persists | Check early termination and inactivity in the outcome definition |
| Single high scores do not repeat | Use consistent repeated measurements in candidate comparisons |
| Corrections have little effect | Inspect radius, offset scale, bounds, and whether the base can express the required behavior |
| One context works and another fails | Check context delivery, scaling, and representation in training comparisons |

An equal-scoring revision can change the retained sequence. Read the outcome and execution record together when interpreting improvement flags.

The read-only `retest` mode does not update a retained score through an observation decision. Use comparison stages with fresh measurements when selecting among noisy executions.

Planning can select among live proposals, but each simulation consumes work. Record whether exact terminal scores or learned estimates determined selection. A deeper search using `acquisition_reference` depends on available kept records. See [planning integration](https://docs.reilabs.org/docs/planning/integration.md) and [evaluator readiness](https://docs.reilabs.org/docs/planning/options.md#check-evaluator-readiness).

## Resume and recover

Resume with the same Domain IDs and unchanged executor contract. Inspect learner state and pending work before continuing. Preserve the acquired base when resuming its contextual correction.

| Interrupted operation | Next action |
| - | - |
| Configuration | Read state and compare it with the saved intended configuration |
| Proposal | Recover its decision ID before issuing another exploratory proposal |
| Physical execution | Preserve the measured prefix and termination reason |
| Candidate comparison | Resume missing candidate/context executions, then submit the complete matrix |
| Observation | Inspect state and receipts before resending the saved body |
| Intentionally abandoned decision | Call `cancel` with its known `decision_id` |

`trajectory/reset` resets learner state. A new environment attempt uses the same learner and does not require this operation.

Use [retained use and recovery](https://docs.reilabs.org/docs/machina/retained-use.md) for reconciliation details. Follow [retry guidance](https://docs.reilabs.org/docs/neuroadapt/operational-behavior-and-retries.md) for backoff. Budget concurrent traffic together and check deployed limits before expanding the run.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.