--- title: "Understand Job Output" description: "What a job's result table looks like - the columns each object type produces (id, inputs, output, transforms, dependent, explainer, block/segment/rule) and how to read them." ---
TL;DR
When you run a job (a Simulation, Monitoring run, and so on), the platform produces a result table: one row per record, keyed by id, with each input under its own alias and the result in output. The columns follow a consistent pattern per object type - a Model adds dependent, transform, and explainer columns; a Policy adds a column for every block, segment, and rule. This page is the reference for that pattern.
## What is it? Every job runs a registered object (a Data Element, Feature, Model, or Policy) over a sample of records and returns a **result table**. Each row is one record (one instance of the object's entity, such as an application or an account), `id` is the key, the inputs sit under their own aliases, and the result lands in `output`. You meet this table in a few places: * The **Job Result** section of a completed job, as a sample preview. * As the `data` PySpark DataFrame in a [Report Definition](/user-guide/how-tos/register-reports/) or a Figure. * As the data you pull into the [Notebook](/user-guide/how-tos/use-the-notebook/). Two conventions hold across every object type: * **`id`** is always the key column. Each row is one record; the values come from that record's platform key (an application ID, a loan ID, and so on), but the column itself is always called `id`. * **`output`** is always the object's own result: the Data Element's value, the Feature's value, the model score, or the policy decision. What sits *between* `id` and `output` is what differs by object type. The rest of this page walks each one. The examples share a running theme, a FICO-based `credit_tier`, though each object shows its own columns. ## Data Element A Data Element exposes one column from a registered table. Its output is a straight passthrough (or a light cast) of that source column. Columns: * `id` - the key. * the **source column** - the raw table column the Data Element reads, named after that column (not after the Data Element's alias). * `output` - the Data Element's value. For a Data Element `de_fico` that reads `fico` from the applications table, the source column and `output` carry the same value:
idficooutput
A1001742742
A1002605605
## Data Aggregate A [Data Aggregate](/user-guide/how-tos/register-a-data-aggregate/) groups many rows by a join key and rolls them up to one row per key (for example, aggregating an applicant's accounts up to one row per application). The column set is the same shape - `id`, the inputs, `output` - but the **grain and values change**: * `id` is the **target** key: the value you grouped by. Each row is one group, not one source row. * Each input appears by its alias, but its values are **collapsed** to the target grain: inputs already at the target grain stay single values, while inputs at the finer grain become a list of the grouped values. * `output` is the single aggregated result per row. For an aggregate `max_account_balance` that groups accounts by application and takes the maximum `account_balance` per application. It also reads `applicant_state`, which is already at the application grain, to show the contrast:
idaccount_balanceapplicant_stateoutput
A1001[1200, 340, 9800]CA9800
A1002[500, 500]TX500
`account_balance` sits at the finer grain (one value per account), so it collapses to a **list** of the grouped values; `applicant_state` is already at the target grain (one value per application), so it stays a **single value**. The join key you grouped by does not appear as a separate column, and the individual source rows are not shown - they are collapsed into the lists you see. ## Feature A [Feature](/user-guide/how-tos/register-a-feature/) is a derived value computed from one or more inputs (Data Elements or other Features). Columns: * `id` - the key. * **one column per input** - each named by its alias. * `output` - the Feature's value. For the `credit_tier` Feature (one input, `de_fico`, bucketed into `A` / `B` / `C`):
idde_ficooutput
A1001742A
A1002605C
A multi-input Feature simply adds a column per input. A `credit_tier` that also read `dti` would show `id`, `de_fico`, `dti`, `output`. ## Feature Aggregate A [Feature Aggregate](/user-guide/how-tos/register-a-feature-aggregate/) behaves like a Data Aggregate: same `id` + inputs + `output` shape, but rolled up to **one row per join key**, with inputs collapsed to that grain and one `output` per row. See [Data Aggregate](#data-aggregate) above for how the values collapse. ## Model A Model adds a few columns to the Feature pattern: its transforms, the target it was trained against, and (optionally) its explainer. Columns: * `id` - the key. * **one column per input** - each named by its alias. Inputs can be Data Elements, Features, or other Models. * **one column per transform** - if the Model defines any [Transforms](/user-guide/how-tos/register-a-model-definition/), each named by the transform's alias. * `dependent` - the target the Model predicts. This column is literally named `dependent`, and appears only when a dependent is configured. * `output` - the model score. This column is always named `output`, regardless of the alias you gave the score. * `explainer` - a single column, present only when a [Model Explainer](/user-guide/how-tos/register-a-model-explainer/) is enabled. It holds a **map of per-input contributions** (feature importance) or a **list of reason codes**, depending on the explainer, packed into that one column. For a binary-classification Model that takes `credit_tier` and `dti` as inputs, with an explainer enabled:
idcredit_tierdtidependentoutputexplainer
A1001A0.3100.08{"credit_tier": -0.12, "dti": 0.03}
A1002C0.5210.63{"credit_tier": 0.21, "dti": 0.09}
:::note[Model type does not change the shape] Every model type - Binary Classification, Regression, Multi-class, Time Series - produces exactly **one** `output` column. A multi-class or array-output model returns its structured value (a list, say) into that single column; it is not spread into one column per class. ::: ## Policy A Policy is a [Decision Workflow](/user-guide/how-tos/register-policy-decision-workflow/) built from blocks. Its output table carries a column for **every part of the workflow** - each block, each segment, each rule - so you can trace exactly how each record was decided. To make the columns concrete, here is a small cross-sell policy that decides which members to make a credit-card offer to. It chains an **Eligibility Criteria** block, a **Credit Card Selection Strategy** block, a **Member NPV** derived variable, then an **Offer Creation** block and an **Offer Filtering** block. Each decision block carries a rule or two; neither uses segments, so their rules use the shorter two-part naming.
Block 1 - Eligibility Criteriarule-1.1: no active card · rule-1.2: tenure >= 6 months
met, else Not Eligible
Block 2 - Credit Card Selection Strategyrule-2.1: credit_score >= 660 · rule-2.2: income >= 30000
met, else Not Assigned
Block 3 - Member NPV (Derived Variable)member_npv = expected_revenue - expected_cost
↓
Block 4 - Offer Creationbuild candidate card offers
↓
Block 5 - Offer Filteringrule-5.1: member_npv > 0
rolls up to
output
Columns: * `id` - the key. * **one column per input** - each named by its alias (`tenure_months`, `active_card`, `credit_score`, `income`). * **``** - one column per **derived variable** (its computed value), **offer-config**, and **framework** output. Here that is `member_npv`. * **`block-`** - one per block, where `n` is the block's position (1-based) in the workflow. Holds the block's outcome. A Derived Variable block contributes **two** columns: its value under ``, and its flow decision under `block-`. A Derived Variable block has no decision outcome, so its `block-` reads `Continue` to show flow proceeded. * **`segment-.`** - one per segment, where `s` is its block and `n` is the segment's position. Holds whether the record fell into that segment. This policy's blocks have no segments, so no `segment-` columns appear. * **`rule-.`** - one per rule in a block with no segments, where `s` is the block and `r` is the rule's position. Holds whether the rule passed. For example, Rule 2.1 in the diagram becomes `rule-2.1`: block 2, rule 1. (A block that **does** use segments names its rules `rule-..`, adding the segment index.) * `output` - the policy's overall decision (the outcome of the last block the record reached). The values follow a consistent convention: * **Rule and segment columns are booleans**: `True` (rule passed / in this segment), `False`, or `None` (the record never reached this point, because an earlier block decided it). * **`block-` and `output` are outcome strings**, title-cased. The built-in outcomes are `Continue` (flow moves to the next block), `Auto Approval`, `Auto Denial`, and `Manual Review`. A workflow can also define **custom end nodes** with their own names - this policy uses `Not Eligible`, `Not Assigned`, and `Offer Generated`. `output` is always a terminal outcome, never `Continue`. For the workflow above, one member who clears every block and gets an offer, and one who fails eligibility at the first block:
idcredit_scoremember_npvblock-1block-2block-3block-4block-5rule-1.1rule-2.1rule-5.1output
M1001712184.50ContinueContinueContinueContinueOffer GeneratedTrueTrueTrueOffer Generated
M1002648NoneNot EligibleNoneNoneNoneNoneFalseNoneNoneNot Eligible
Reading the rows: member `M1001` passes `rule-1.1` at Eligibility so `block-1` is `Continue`, and keeps clearing each block until Offer Filtering emits `Offer Generated`, which becomes `output`. Member `M1002` fails `rule-1.1`, so `block-1` is the custom end node `Not Eligible`; every later block is `None` because the record was already decided, and `output` carries that same `Not Eligible`. (The table is trimmed to one rule per block; a real policy shows a column for every rule.) :::note[Segments add an index to rule names] This policy's blocks have no segments, so rules are named `rule-.` (two parts). When a block uses segments, its segment columns appear as `segment-.` and its rules gain the segment index: `rule-..` (three parts). ::: ## Column order Within the table, columns come in a fixed order: `id` first, then inputs, then the object-specific columns (transforms, blocks, segments, rules, derived variables, and so on), then `output` last. Within each of those groups, columns are sorted alphabetically by name. Run a job for your object and open its **Job Result** to see the exact columns and order for your case. ## What's Next * [Run a Simulation](/user-guide/how-tos/run-a-simulation/) to produce a job output and open its **Job Result**. * [Register Reports](/user-guide/how-tos/register-reports/) that read this data as `data` and summarize it. * [Use the Notebook](/user-guide/how-tos/use-the-notebook/) to pull job output into your own analysis.