> ## 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.

# Configure contextual refinement

> Learn context-dependent corrections to an acquired command sequence, then use the retained correction without feedback.

Use `contextual_execution` after you have acquired and selected an execution. This mechanism learns an offset for each command coordinate as a function of the initial context. Your application keeps the selected base sequence and combines it with the returned offsets before execution.

The examples use the production base URL and helpers from [Domain configuration](/docs/machina/configuration). Their request contracts follow the available trajectory schemas and exercised client workflow; this guide does not report a production validation run.

## Keep the base and context contract together

This example continues with a two-coordinate command interface. Both coordinates use normalized values in `[-1, 1]`, and each command lasts `0.5` seconds. The selected base contains between one and eight commands.

| Value                   | Shape                                      | Meaning                                                                                            |
| ----------------------- | ------------------------------------------ | -------------------------------------------------------------------------------------------------- |
| `selected_base.actions` | `H × 2`                                    | Actual acquired sequence returned as `selected_execution` by the preceding structural stage        |
| One context             | `4`                                        | `[target_x, target_y, initial_vx, initial_vy]` in a fixed application encoding                     |
| `contexts`              | `N × 4`                                    | Contexts measured at real training resets                                                          |
| Evaluated `offsets`     | `H × 2`                                    | Additive corrections in the same normalized command units as the base                              |
| Executed command list   | `8 × 2`, unless the environment terminates | Corrected base followed by neutral `[0, 0]` commands under this application's fixed execution rule |

`H` is the selected base length, not the original acquisition limit. Corrections cover those `H` commands. Neutral padding is an application rule applied afterward; it is not an API field or an extra learned command. Keep this rule identical during comparisons and retained use.

Keep the context coordinate order, normalization, base sequence, command decoder, command duration and padding rule together when saving the controller. The refinement Domain stores corrections; its configuration does not include the base sequence. Changing the base or its command count changes what the offsets mean.

## Configure the refinement Domain

Use `PREFIX`, `trajectory` and `create_stage` from the configuration guide, `structural_domains` from [Structural stages](/docs/machina/structural-stages), and the application's `reset_and_measure` adapter from [Sequence acquisition](/docs/machina/acquisition).

Before running this guide, implement the following application hooks. These are not API operations:

| Hook                                            | Required behavior                                                                                                                                                                                                 |
| ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `registered_context_ids(partition)`             | Return the IDs of actual saved scenarios in the requested application-owned partition. Each ID maps to reset conditions, including the initial state, target and environment randomness.                          |
| `reset_and_measure(context_id)`                 | Reset the registered scenario and return its measured `state` and requested `goal` using the acquisition adapter. Reject invalid reset measurements before constructing a refinement context.                     |
| `execute_actions(actions, command_seconds=0.5)` | Execute the supplied command list from the current reset state and return measured `completion` and `progress` using the definition below. Preserve the same limits and termination rules used by earlier stages. |

Register separate `refinement-support`, `refinement-training` and `evaluation` partitions in your scenario registry. The support vectors configure the context representation; the training scenarios supply paired comparisons; the evaluation scenarios remain unused until retained evaluation. The code below constructs support vectors from real resets using the same coordinate scales as acquisition.

```python theme={null}
import math

def reset_context(context_id):
    initial = reset_and_measure(context_id)
    if initial["initial_valid"] is not True:
        raise ValueError("Refinement requires a valid measured reset context")
    state, goal = initial["state"], initial["goal"]
    assert len(state) == 4 and len(goal) == 2
    context = [goal[0], goal[1], state[2], state[3]]
    assert all(math.isfinite(x) and abs(x) <= 1e12 for x in context)
    return context

support_context_ids = registered_context_ids("refinement-support")
assert 1 <= len(support_context_ids) <= 257
assert len(support_context_ids) == len(set(support_context_ids))
training_contexts = [reset_context(cid) for cid in support_context_ids]

structural_domain = structural_domains["ordering"]
selected_base = trajectory(structural_domain, "state")["selected_execution"]
base_actions = selected_base["actions"]
H = len(base_actions)

assert 1 <= H <= 8
assert all(len(row) == 2 for row in base_actions)
assert all(math.isfinite(x) and -1 <= x <= 1
           for row in base_actions for x in row)
assert 1 <= len(training_contexts) <= 257
assert all(len(row) == 4 for row in training_contexts)
assert all(math.isfinite(x) for row in training_contexts for x in row)

refinement_domain = PREFIX + "-refinement"
objective_names = ["completion", "progress"]
config = {
    "mechanism": "contextual_execution",
    "horizon": H,
    "action_dimensions": 2,
    "contexts": training_contexts,
    "objective_names": objective_names,
    "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, config)
```

The helper sends `POST /domains/{domain_id}/trajectory/configure` with the JSON body `{"config": config}` after creating a fresh Domain and checking its trajectory state.

| Configuration field   | Required or default | Constraint                                                                         |
| --------------------- | ------------------- | ---------------------------------------------------------------------------------- |
| `mechanism`           | Required            | `"contextual_execution"`                                                           |
| `horizon`             | Required            | Integer from `1` to `256`; use the base command count                              |
| `action_dimensions`   | Required            | Integer from `1` to `32`; use the base row width                                   |
| `contexts`            | Required            | `1–257` numeric rows, each `1–128` coordinates; enforce one consistent width       |
| `objective_names`     | Required            | `1–8` nonempty names; preserve their order in feedback                             |
| `candidate_count`     | Default `8`         | Integer from `2` to `16`                                                           |
| `max_contexts`        | Default `64`        | Integer from `2` to `64`                                                           |
| `seed`                | Default `0`         | Integer from `0` to `2147483647`                                                   |
| `radius`              | Default `0.08`      | Positive numeric value                                                             |
| `retained_variance`   | Default `0.99`      | Positive numeric value; the supplied schema does not declare an upper bound of `1` |
| `contextual`          | Default `true`      | Boolean                                                                            |
| `action_trust_region` | Default `false`     | Boolean; this example explicitly enables it                                        |

The context vectors supplied at configuration establish the numeric context representation. `context_ids` used below are application identifiers for repeatable environment resets; they do not replace these vectors. The adapter owns the mapping from each identifier to its reset conditions.

## Propose a comparison

Prepare a batch of repeatable training contexts. Use a discovery subset and a separate confirmation subset within the batch. The example assigns alternating IDs to discovery; the remaining IDs are the confirmation contexts. These are training comparisons, not the final held-out evaluation.

```python theme={null}
context_ids = registered_context_ids("refinement-training")
assert 2 <= len(context_ids) <= config["max_contexts"]
assert len(context_ids) == len(set(context_ids))
assert set(context_ids).isdisjoint(support_context_ids)
assert all(isinstance(cid, str) and cid.strip() and len(cid) <= 128
           for cid in context_ids)
discovery_ids = context_ids[::2]
confirmation_ids = context_ids[1::2]
assert discovery_ids and confirmation_ids

proposal = trajectory(refinement_domain, "propose", {
    "state": training_contexts[0],
    "goal": [0.0],
    "mode": "explore",
    "request_id": PREFIX + "-refinement-update-0",
    "context_ids": context_ids,
    "discovery_context_ids": discovery_ids,
})
decision_id = proposal["decision_id"]
candidate_count = len(proposal["candidates"])
assert 2 <= candidate_count <= 16
```

`state` and `goal` are required by the shared proposal envelope. For this contextual comparison workflow, the client supplies one representative context as `state` and `[0.0]` as `goal`. Each execution's actual context is sent to `evaluate`; the placeholder goal is not a target action or a success label.

Use a fresh `request_id` for each new comparison. Keep the returned `decision_id` with the batch until its measured outcomes are submitted. Candidate indices are zero-based positions in this proposal's `candidates` array; do not reuse an index with another proposal's decision ID.

## Evaluate and execute every candidate on every context

Use the `reset_context` function defined above and your `execute_actions` adapter. In this example, measured completion is `0` or `1`, and measured progress lies in `[0, 1]`; larger values mean better outcomes.

Completion uses the same rule as the preceding guides: after the eight command slots, or an earlier task termination, the measured planar distance to the goal is at most `0.05` metres and the measured speed is at most `0.1` metres/second. A safety stop sets completion to false. Progress measures the fraction of the initial target distance removed, clipped to `[0, 1]`. If the initial distance is exactly zero, progress is `1` only when the final distance is also zero; otherwise it is `0`.

The application adapter computes these values from the actual initial and final measurements of each execution. The example's position and velocity coordinates are divided by one metre and one metre/second respectively, so the numeric thresholds below use those units directly.

```python theme={null}
def measure_refinement_outcome(initial_state, final_state, goal, safety_stopped):
    assert len(initial_state) == len(final_state) == 4 and len(goal) == 2
    assert all(math.isfinite(x) for row in (initial_state, final_state, goal)
               for x in row)
    initial_distance = math.hypot(initial_state[0] - goal[0],
                                  initial_state[1] - goal[1])
    final_distance = math.hypot(final_state[0] - goal[0],
                                final_state[1] - goal[1])
    final_speed = math.hypot(final_state[2], final_state[3])
    completion = (not safety_stopped
                  and final_distance <= 0.05 and final_speed <= 0.1)
    if initial_distance > 0:
        progress = max(0.0, min(1.0, 1.0 - final_distance / initial_distance))
    else:
        progress = float(final_distance == 0.0)
    return {"completion": float(completion), "progress": progress}
```

Have `execute_actions` return this result using its measured trace and actual goal. Progress is an additional contextual-refinement objective in this example; it does not change the preceding stages' completion outcome or the command interface.

Reset separately for every candidate/context pair. Candidates must face the same reset conditions and scoring rules.

```python theme={null}
def compose_actions(offsets):
    if len(offsets) != H or any(len(row) != 2 for row in offsets):
        raise ValueError("offsets must match the selected base shape")
    if not all(math.isfinite(x) for row in offsets for x in row):
        raise ValueError("offsets must contain finite numbers")
    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 corrected + [[0.0, 0.0] for _ in range(8 - H)]

outcomes = []
for candidate_index in range(candidate_count):
    for context_id in context_ids:
        context = reset_context(context_id)
        assert len(context) == 4
        assert all(math.isfinite(x) for x in context)
        evaluated = trajectory(refinement_domain, "evaluate", {
            "context": context,
            "candidate_index": candidate_index,
            "decision_id": decision_id,
        })
        actions = compose_actions(evaluated["offsets"])
        result = execute_actions(actions, command_seconds=0.5)
        objectives = [float(result["completion"]), float(result["progress"])]
        assert objectives[0] in (0.0, 1.0)
        assert math.isfinite(objectives[1]) and 0 <= objectives[1] <= 1
        outcomes.append({
            "candidate_index": candidate_index,
            "context_id": context_id,
            "objectives": objectives,
        })
```

The `evaluate` request requires `context`. For a pending candidate, provide both `candidate_index` and `decision_id`. The consumed response field is `offsets`; it is not a complete action sequence. Add it to the saved base and apply the same action limits used in training.

This example uses direct addition and clipping. If your established adapter instead performs geometric retargeting, keep its transform and composition order unchanged throughout training and retained use. Do not add a geometric transform to an interface whose action coordinates are nongeometric.

## Submit one complete measured comparison

Feedback needs one row for every returned candidate and every requested context, including the confirmation contexts. Do not send only the winner or the discovery rows.

```python theme={null}
expected = {(i, cid) for i in range(candidate_count) for cid in context_ids}
actual = {(row["candidate_index"], row["context_id"]) for row in outcomes}
assert actual == expected and len(outcomes) == len(expected)
assert all(len(row["objectives"]) == len(objective_names) for row in outcomes)

observe_body = {"decision_id": decision_id, "outcomes": outcomes}
# The shared HTTP helper checks the serialized request against the 1 MiB limit.
observation = trajectory(refinement_domain, "observe", observe_body)
```

Each row uses `candidate_index`, `context_id` and `objectives`; the top-level body uses `decision_id` and `outcomes`. Keep objective values in the configured order. A simulator or task failure is a measured outcome; a missing execution is not. Finish all scheduled executions before submitting the batch, or resolve the interrupted decision without fabricating missing rows.

The request schema permits up to `32768` outcome rows, but the body must also fit the route's `1 MiB` limit. Size the candidate/context batch before running it. Do not divide one complete comparison into separate partial `observe` calls unless your deployed service explicitly supports that operation.

## Use the retained correction

After learning, omit both pending-candidate fields from `evaluate`. The client workflow uses this form to obtain the retained correction for a newly measured context.

```python theme={null}
held_out_context_ids = registered_context_ids("evaluation")
assert held_out_context_ids
assert set(held_out_context_ids).isdisjoint(support_context_ids)
assert set(held_out_context_ids).isdisjoint(context_ids)
held_out_context_id = held_out_context_ids[0]

before = trajectory(refinement_domain, "state")["fingerprint"]
context = reset_context(held_out_context_id)
retained = trajectory(refinement_domain, "evaluate", {"context": context})
result = execute_actions(compose_actions(retained["offsets"]),
                         command_seconds=0.5)
after = trajectory(refinement_domain, "state")["fingerprint"]
assert after == before
```

This path makes no `propose` or `observe` call. Save results in the application's evaluation log. An unchanged refinement fingerprint checks the state exposed by that mechanism; it does not by itself certify every other learner in the application.

See [Retained use and operational checks](/docs/machina/retained-use) for reconnecting, preserving the base and adapter, and handling interrupted requests.
