Evolution depth — the model tier ladder
“Model depth” is the algorithm-complexity tier a model sits at. Kaireon defines an evolution ladder so a model can graduate from a simple, data-cheap algorithm to a richer one as it accumulates evidence and demonstrates lift.The tier ladder
ALGORITHM_TIERS (platform/src/domain/algorithms.ts) lists six tiers:
scorecard → bayesian → logistic_regression → gradient_boosted. The /upgrade endpoint returns 400 No upgrade available once a model reaches gradient_boosted, and the readiness thresholds below stop there too. thompson_bandit and epsilon_greedy are model types you create directly, not rungs the upgrade ladder climbs to.
Readiness thresholds — EvolutionConfig
EvolutionConfigSchema defines a per-model, nullable config (defaults apply when unset):
The
thresholds block gates each promotion on BOTH a minimum sample count and a minimum AUC:
Reading readiness — GET /evolution-history
GET /api/v1/algorithm-models/{id}/evolution-history reports where a model sits on the ladder and how close it is to the next rung:
progress.progressPct— the average of the sample-progress % and AUC-progress % toward the next tier (each capped at 100).progress.readyToEvolve—trueonceprogressPct >= 100(both sample and AUC targets met).timeline[]— the model’s version history with the model type at each version.
Triggering the upgrade — POST /upgrade (manual)
Promotion is a manual action — POST /api/v1/algorithm-models/{id}/upgrade (RBAC admin/editor). It:
- Creates a new
draftmodel of the next tier (key: "{key}-upgraded-{newType}"), seeded with that tier’s default hyperparameters and the current model’stargetField,targetSchemaKey, andpredictors. - With
{"createExperiment": true}in the body, also creates a draft champion/challengerExperiment(50/50 split) with the current model as champion and the upgraded model as challenger. - Returns
{ upgraded, experiment }with201.
draft and inert — you still run it through the lifecycle to make it score.
Auto-rollback guard on champion promotion
A champion promotion that includes a metrics snapshot (AUC and error rate) now consults the auto-rollback evaluator BEFORE the transaction that demotes the incumbent.Trigger
The guard fires only when:toStatus === "champion", ANDmetricsSnapshot.aucis supplied by the caller, AND- The incumbent champion in the same family has a stored
metricsSnapshot.aucto compare against.
Thresholds
Override per call via
rollbackThresholds. To force a promotion that
breaches a threshold, pass bypassRollbackGuard: true — the
returned object surfaces rollbackGuardBreaches so the bypass is
auditable.
Failure mode
When the guard fires and bypass is not set,promoteModel
throws ModelRegistryError(...) with reason rollback_guard. The
incumbent champion stays in place; no DB state changes.
TS-side preprocessing orchestrator
lib/ml/preprocessing.ts bundles WOE binning + target encoding into
a single fitPreprocessing / applyPreprocessing API. Why TS-side
instead of porting into gbm_trainer.py:
- Most Kaireon scoring engines (bayesian, thompson, online, epsilon, scorecard) live entirely in TS and never cross the Python boundary. A TS-side bridge makes binning + encoding available to all engines, not just GBM.
- Keeps W6.2 testable + deterministic without a Python service in CI.
Honest limit
V1 fits encoders only. Saving / loading them across train + score boundaries is the caller’s responsibility —AlgorithmModel.modelState
is the natural home but is not yet auto-populated from this orchestrator.
The Python gbm_trainer.py path IS wired, though: serializeFitForGbmTrainer()
emits the {bin_edges, target_encodings} payload the ml-worker /train/gbm
route accepts, so a caller can ship the fit alongside the training data and
keep Python-side training aligned with TS-side scoring.