# ML Model Guide (XGBoost)

XGBoost is the built-in ML engine — no adapter installation or selection required.
CRUD operations use the standard GraphQL API. Specialized MCP tools handle training,
prediction, and data preview.

## Model Types

### Regression
Predicts continuous numeric values. Default eval metric: RMSE.
Use when your target column contains numbers (price, temperature, duration, etc.)

### Classification
Predicts categorical labels. Default eval metric: logloss (binary) or mlogloss (multiclass).
Use when your target column contains categories (pass/fail, color, grade, etc.)

## Interpreting metrics

Streaming tabular training reports metrics on a sample of the training rows.
These are in-sample diagnostics, not held-out validation scores. There is no
configurable validation split or early stopping on this path, and its
evaluationHistory is empty. Do not tune or approve a model solely from these
numbers: score separate data and compare with a mean/majority-class baseline.

## Hyperparameters

All optional — sensible defaults are used if omitted.

| Parameter | Default | Description |
|-----------|---------|-------------|
| maxDepth | 6 | Maximum tree depth. Higher = more complex, risk of overfitting |
| eta | 0.3 | Learning rate. Lower = slower but potentially better |
| rounds | 100 | Boosting rounds. More rounds with lower eta often helps |
| subsample | 1.0 | Row subsampling ratio (0-1). Lower reduces overfitting |
| colsampleBytree | 1.0 | Column subsampling ratio (0-1) |
| minChildWeight | 1.0 | Min sum of instance weight in a child node |
| gamma | 0.0 | Min loss reduction required to make a split |
| evalMetric | auto | Override: rmse, mae, logloss, auc, error, merror, mlogloss |

## GraphQL Operations for CRUD

Use `execute_graphql_query` / `execute_graphql_mutation` for these. Use `describe_type`
to explore the full input/output schemas.

### List models
```graphql
query {
  listMLModelConfigs(first: 20) {
    edges { node { id name modelType status lastTrainedAt } }
  }
}
```

### Read a model (with all training details)
```graphql
query GetModel($id: MLModelConfigID!) {
  getMLModelConfig(id: $id) {
    id name description modelType status
    dataQuerySQL
    spec {
      __typename
      ... on TabularModelSpec {
        targetColumn featureColumns
        hyperparameters { maxDepth eta rounds subsample colsampleBytree minChildWeight gamma evalMetric }
      }
      ... on TimeSeriesModelSpec { model timeColumn valueColumn forecastHorizon confidenceLevel }
    }
    trainingMetrics { rmse maxError accuracy logloss f1 bestRound totalRounds }
    featureImportance { feature gain rank }
    trainingError trainingDurationMs lastTrainedAt
  }
}
```

### Author a model with XML
XML is the sole authoring channel.
Submit `input.sourceXML` through `upsertMLModelSource`;
when updating, supply the id and observed authoring revision. Read back `source`
from `getMLModelConfig` before editing. Training and publication state are retained.

```xml
<ml-model format="1" name="my-model" backend="xgboost">
  <data-query><![CDATA[SELECT quantity, priority FROM jobs LIMIT 1000]]></data-query>
  <tabular task="REGRESSION" target-column="quantity">
    <features><feature column="priority"/></features>
    <hyperparameters rounds="200" eta="0.1"/>
  </tabular>
</ml-model>
```

### Delete a model
```graphql
mutation DeleteModel($id: MLModelConfigID!) {
  deleteMLModelConfig(id: $id) {
    success
    errors { path message }
  }
}
```

## Data Sources and Normalization

Training reads the uploaded CSV or the model's dataQuerySQL through the tenant-scoped
reporting engine. It replays the source when the backend needs another pass.
A preview sample limit does not cap training; use an explicit SQL LIMIT/filter if
limiting the training dataset is intentional.

A normalization stage runs once per incoming row, in stage order, without database,
network or other platform capabilities. The global `input` contains ONE record.
The historical name `row` is supported for saved stages. There is no global `rows`.
Return one transformed record, or nil to drop that row. For example:
```lua
if input.quantity == nil then return nil end
return { quantity = input.quantity, priority = input.priority }
```
`return input` passes the row through. SQL NULL/empty CSV cells arrive as nil/missing
values, not numbers. Nullable emitted fields remain NULL (blank in CSV/sampleRows).
A projection creates its declared output columns; removed input columns are not
reinserted. Handle missing values explicitly before arithmetic; substitute a value
only when your domain justifies it, never fabricate numeric zero automatically.

Use previewMLModelPipeline(id, stagesOverride, sampleLimit) to inspect unsaved stages
without training. sampleRows returns up to sampleLimit emitted rows (default 1000).
totalRows is the number sampled, not a full dataset count. Zero samples schema only;
negative limits are invalid. Filtering may require reading more source rows than are
returned. Stage diagnostics name the stage and source line/column when available;
runtime diagnostics omit row data and script-raised messages that may contain it.

## Feature Types (Auto-Detected)
- **numeric**: Numbers (Int, Float, Double, or parseable strings)
- **categorical**: String values (auto-encoded during training)
- **boolean**: true/false values

## Training Pipeline
1. Open the replayable CSV/SQL source and compile normalization stages
2. Stream transformed rows into the selected tabular/time-series backend
3. Capture metrics, artifact, schema and an immutable model version
4. Publish according to the config's publication policy

SQL pages use the reporting engine's configured PostgreSQL statement timeout,
currently 30 seconds PER PAGE, not a 30-second total training deadline. SQLSTATE
57014 plus a statement-timeout reason is distinguished from user/client cancellation.
Other database failures report their safe driver category and SQLSTATE. A run's
elapsed duration alone does not identify a timeout or a connection-pool failure.
Optimize/aggregate the full query rather than relying on a fast capped preview.
Normalization stages use the standard pipeline-stage scripting budgets separately.

## Typical Workflow

1. **Find data sources** — locate the queries and types your training data
   comes from.
2. **Choose data** — upload CSV or configure a tenant-scoped dataQuerySQL
3. **Preview data** — verify emitted columns, types and NULL counts with previewMLModelPipeline
4. **Create model** — `upsertMLModelSource` with authoritative XML and exactly one model: tabular or forecast
5. **Train** — start training, then query `getMLModelConfig(id)` for status and metrics
6. **Iterate** — adjust hyperparameters or features based on metrics, retrain
7. **Predict** — call the model with a feature map

## Tips
- Start with default hyperparameters, then tune based on metrics
- Feature importance helps identify which columns matter most
- For classification, check accuracy and logloss; for regression, check RMSE and max error
- The `bestRound` metric tells you if training could benefit from more rounds
- Retraining is supported — call `train_ml_model` again on trained or failed models