Estimator Input/Output Contract#
A routee-powertrain model runs its predictions through an underlying estimator (an ONNX graph, an NGBoost model, …). For the ONNX case the inference engine consumes a positional float tensor — column 0, column 1, … — so a consumer must feed features in the exact order the model was trained on. Getting the order wrong does not error; it silently produces wrong energy.
To make that order unambiguous, every estimator ships a self-describing input/output contract. This page documents the contract so downstream consumers (notably routee-compass) can read it instead of relying on an out-of-band assumption.
Where the contract lives#
The contract lives in two artifacts, each with a different reader:
metadata.json— the ordered contract is stored once, in thecontractsection (feature_setorder,distance,target,predict_method). This is the source of truth for any reader that has the metadata.estimator.input_specin the same file carries only the estimator mechanics —lookback,grouping_column,pad_strategy— not a second copy of the columns.The estimator binary itself — for ONNX models the resolved, positional contract is embedded in the graph's
metadata_props, so a bare.onnxfile is self-describing without the sidecarmetadata.json. This is the copy a consumer that only has the binary (e.g. routee-compass) reads.
The two are not redundant: they serve different consumers. On load, powertrain
raises if the binary's embedded order disagrees with the contract in
metadata.json — a corrupt or hand-edited artifact fails loudly rather than
mispredicting.
The fields#
The resolved, positional contract embedded in the ONNX binary (and the
in-memory InputSpec) carries:
Field |
Meaning |
|---|---|
|
Ordered positional columns of the input tensor. Each is |
|
Ordered positional columns of the output tensor. Point estimators emit one column per energy target; NGBoost appends a |
|
|
|
Name of the distance column — the RATE multiplier, and the final RAW input position. |
|
Rows of prior context per prediction. |
|
Column that buckets rows into independent sequences (e.g. |
|
How the lookback window is padded at a sequence start ( |
In metadata.json, only the last three (lookback/grouping_column/pad_strategy)
appear under estimator.input_spec; the ordered columns come from the contract
section (and are embedded in full in the binary).
ONNX metadata_props keys#
For ONNX estimators the same fields are embedded under these keys (all values are JSON where noted):
Key |
Value |
|---|---|
|
JSON array of |
|
JSON array of |
|
|
|
distance column name |
|
integer (written only when |
|
grouping column name (written only when |
|
|
The input tensor node is named "input" and the output node "output".
How a consumer should use it#
On load, read
routee_input_columnsfrom the.onnxmetadata_props(via the ONNX session's model metadata).Note that the names are powertrain feature names (
speed_mph,grade_percent). Map each powertrain column to the consumer's source value by the config's declared mapping, and useunitsto drive any unit conversion.Build the feature vector in contract order (
routee_input_columns), not in the order the consumer's config happens to list features.Validate at load: every embedded input column must have a mapping and a compatible unit; otherwise error.
Migrating older artifacts#
Registry entries minted before the contract existed carry no embedded
input_columns. Re-embed them (deriving the contract from each model's own
metadata) with:
python scripts/backfill_input_contract.py <registry_root>