Problem
fit and predict bind features positionally. The trained model stores no
feature identity, so predict trusts the caller to pass the same columns, in the
same order, that fit learned from. A count mismatch fails loud
(PREDICT_ERR_SCHEMA: "predict got N features but the model expects M"), but an
order mismatch does not: same count, wrong order, and you get a confidently
wrong prediction with no error.
The leading-name sugar just shipped (fit('churn', f..., label) mirroring
predict('churn', f...)) makes the two calls read in parallel, which helps a
human eyeball that the feature lists line up. It does not make the binding safe:
nothing enforces that they do.
Why it matters
This is the last silent-failure path in the tabular surface, and it contradicts
the project's fail-loud contract. A reordered SELECT, a refactor that swaps two
columns, or an ORM that emits columns in a different order than training all
produce a wrong answer that looks fine.
Proposed direction
Bind features by name/role, captured at fit time and checked at predict
time. Sketches, not yet decided:
- Store feature names, check on serve.
fit synthesizes f0..fN
internally today; instead capture the caller's column names where available,
or an explicit '{"features":["tenure","spend",...]}', and persist them in
the model. predict binds by name when given named inputs and errors on an
unknown or missing feature instead of trusting position.
- Predict from a row. A form that pulls features from a record by key, e.g.
predict('churn', json_object('tenure', tenure, 'spend', spend)) or a
table-valued predict_rows(model, ...), so binding is by name.
- Keep positional as the fast path, name-checked when identity is available;
never silently accept a positional list that disagrees with a stored schema.
Acceptance
- A model carries enough feature identity that a reordered
predict fails loud
(a distinct PREDICT_ERR_*) rather than scoring the wrong columns.
- Positional
fit/predict still works for the common case.
- The stored feature schema deserializes with the same bounds-checked,
deterministic guarantees as the rest of the registry.
- Adversarial tests: reordered features, renamed features, a missing or extra
named feature, and an old model with no stored schema (back-compat).
This changes the model format, so it targets v0.3. It is the robustness half
of the leading-name ergonomic change (which was the readability half).
Problem
fitandpredictbind features positionally. The trained model stores nofeature identity, so
predicttrusts the caller to pass the same columns, in thesame order, that
fitlearned from. A count mismatch fails loud(
PREDICT_ERR_SCHEMA: "predict got N features but the model expects M"), but anorder mismatch does not: same count, wrong order, and you get a confidently
wrong prediction with no error.
The leading-name sugar just shipped (
fit('churn', f..., label)mirroringpredict('churn', f...)) makes the two calls read in parallel, which helps ahuman eyeball that the feature lists line up. It does not make the binding safe:
nothing enforces that they do.
Why it matters
This is the last silent-failure path in the tabular surface, and it contradicts
the project's fail-loud contract. A reordered
SELECT, a refactor that swaps twocolumns, or an ORM that emits columns in a different order than training all
produce a wrong answer that looks fine.
Proposed direction
Bind features by name/role, captured at
fittime and checked atpredicttime. Sketches, not yet decided:
fitsynthesizesf0..fNinternally today; instead capture the caller's column names where available,
or an explicit
'{"features":["tenure","spend",...]}', and persist them inthe model.
predictbinds by name when given named inputs and errors on anunknown or missing feature instead of trusting position.
predict('churn', json_object('tenure', tenure, 'spend', spend))or atable-valued
predict_rows(model, ...), so binding is by name.never silently accept a positional list that disagrees with a stored schema.
Acceptance
predictfails loud(a distinct
PREDICT_ERR_*) rather than scoring the wrong columns.fit/predictstill works for the common case.deterministic guarantees as the rest of the registry.
named feature, and an old model with no stored schema (back-compat).
This changes the model format, so it targets v0.3. It is the robustness half
of the leading-name ergonomic change (which was the readability half).