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

# Planning Results

> Read the production plan, order fulfillments, and solver KPIs — then adjust and re-run.

## Overview

A completed [planning run](/product/planning-runs) carries three kinds of output:

1. **The production plan** — the interval-by-interval schedule the optimizer chose
2. **Order fulfillment status** — which demand orders the plan covers
3. **Solve KPIs** — how the solver did, and how much to trust the answer

Reading a plan is rarely a one-shot exercise. You look at what the optimizer chose, spot where it made a trade-off you don't like, adjust the [model](/product/planning-models) or the run's [inputs](/product/demand-and-supply), and re-run. This page covers what each output means and the adjust-and-re-run loop that turns a first-cut plan into one you can commit to.

## The Production Plan

The production plan is the primary output — a list of entries answering *what to produce, when, and how much*:

| Field               | Meaning                                                                                                                                                                                                                                       |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Entity**          | What is being produced — a SKU or an intermediate. Raw materials are supplied, not produced. Because a material is classified per entity *and* variant, the same entity can be produced under one variant and supplied as a raw under another |
| **Variant**         | Which BOM the optimizer chose, when the entity has more than one recipe                                                                                                                                                                       |
| **Date / interval** | When production happens, at the granularity of the model's interval unit                                                                                                                                                                      |
| **Quantity**        | How many units                                                                                                                                                                                                                                |

The plan respects flow balance across the horizon for every material:

```
end_inventory[t] = start_inventory[t] + produced[t] + supplied[t] − consumed[t]
```

and inventory never goes negative. The plan reports the resulting **end-of-interval inventory** for each material alongside the production entries, so you can read how stock rises and falls across the horizon, not just when production happens. Intermediates needed for a SKU appear as their own production entries in the intervals leading up to the SKU that consumes them — the lead-up chain is part of the plan, not an implementation detail.

## Order Fulfillment

Every demand order carries a **fulfilled** flag that flips to `true` when the plan covers the order in full. The flag is **boolean** — there is no partial-fulfillment state. Either the plan produces at least the ordered quantity by the order's fulfillment interval, or the order is unfulfilled.

An order ends up unfulfilled in two ways:

* **A soft-deadline order the optimizer chose to drop.** The lateness penalty was cheaper than what fulfilling would have cost elsewhere — usually a competing higher-weight order on the same constrained resource. Reading the plan against the run's resource capacities makes the trade-off visible.
* **A hard-deadline order.** Hard orders cannot be dropped — if a hard order cannot be fulfilled, the whole run reports [infeasible](/product/planning-runs#when-a-run-is-infeasible) rather than returning a plan with the order missing.

## Solve KPIs

| KPI                  | What it tells you                                                                                                                          |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| **Solver status**    | `optimal`, `feasible` (valid plan, time limit hit before proof), or `infeasible`                                                           |
| **Objective value**  | The weighted total loss the optimizer minimized. Lower is better — but only comparable across runs on the same model with the same weights |
| **Optimality gap**   | How close the plan is to a proven optimum. 2% means "no plan better by more than 2% exists"                                                |
| **Computation time** | Wall-clock solve time, in seconds                                                                                                          |

<Info>
  Beyond the four KPIs above, the solver keeps internal progress diagnostics — its **dual bound** (the proven lower bound on the objective) and **MIP nodes explored**. These are not part of the standard results view; they matter mostly when a hard instance times out and you want to gauge how stuck the solver got.
</Info>

Status and gap together are how you sanity-check a plan before acting on it: an **optimal** result at a tight gap is a plan you can commit to; a **feasible** result at a wide gap is a plan worth eyeballing — valid, but the solver couldn't prove it was close to the best.

## The Adjust-and-Re-Run Loop

First-cut plans are rarely the plan you ship — they are the plan that surfaces where the model's assumptions don't match your judgment. The knobs, in the order you typically reach for them:

* **Rebalance the two objectives.** Shifting the balance toward inventory protects stock targets at the expense of demand timing; shifting it toward demand does the reverse. Plan hits every due date but lets inventory drift? Shift toward inventory. Holds inventory beautifully but misses orders you cared about? Shift toward demand.
* **Re-tune per-tag weights.** A class of orders being dropped too readily deserves a higher [order-tag](/product/planning-models#order-tags) weight; an inventory goal being over-protected at others' expense deserves a lower one.
* **Update demand or supply as new information arrives.** New orders, a supply delay, a start-date shift — put the changed inputs on a *new* run rather than editing the old one, so before and after stay comparable.
* **Adjust or add custom constraints.** If the plan does something operationally impossible that the base model doesn't capture (a batching rule, a changeover limit), encode it as a [custom constraint](/product/planning-models#custom-constraints).
* **Extend the horizon or add capacity.** A perpetually tight or infeasible plan usually means the horizon is too short for the lead-up chain, or the declared capacity doesn't match what the floor can run.

<Tip>
  Change one thing per iteration. Runs are cheap and persistent — a chain of single-change runs tells you exactly which adjustment moved the plan, while a batch of simultaneous edits leaves you guessing.
</Tip>

## Comparing Runs

Every completed run remains available with its inputs and outputs intact. There is no dedicated side-by-side comparison view for planning runs today — the fastest way to compare two runs is to [ask Dexter](/product/dexter/chat-and-tasks): which orders changed fulfillment state, which intervals shifted production, how the objective moved, and where the trade-off landed. Dexter can also chart both plans for a specific SKU or resource so the difference is visible at a glance.
