Skip to content

Tables and objects in your workspace

When you need it

Read this page when you open a project's schema after the first runs and want to know what each table is, who created it, whether you need it, and what grows over time. A Bundle project touches four kinds of objects: your data, its predictions, its registered models and the shared monitoring store. Skyulf never creates your data tables; the jobs create everything else when they first need it.

flowchart LR
    subgraph IN["input_schema: you own these"]
        T["training table"]
        S["scoring source"]
        L["outcomes (labels) table"]
    end
    subgraph OUT["output_schema"]
        P["predictions"]
    end
    subgraph META["metadata_schema"]
        M["registered model"]
    end
    subgraph MON["monitoring_catalog.monitoring_schema: shared by all projects"]
        D["4 Delta tables"]
        V["8 views"]
        R["4 reference tables per monitored model version"]
    end
    T --> TR["train job"] --> M
    S --> SC["score job"] --> P
    M --> SC
    P --> MO["monitoring job"]
    L --> MO
    TR -. "enrollment" .-> R
    MO --> D
    D --> V

The four locations come from deployment/variables.yml: input_schema, output_schema and metadata_schema for the project, and monitoring_catalog plus monitoring_schema for the monitoring store. They may all be the same schema, but separating them keeps each schema readable (see recommended layout).

Your data: input_schema

Table Created by Purpose
Training table (training_table in config/training.yml) You Rows the model learns from. Training pins a Delta version of it.
Scoring source (config/inference.yml) You Rows to predict. It needs no target; Change Data Feed lets the score job read only new inserts.
Outcomes table (monitoring_label_table in deployment/targets.yml) You Actual values that arrive later, keyed by the same record key, with the time each value became known. Optional: without it, monitoring measures drift but not performance.

These may be one table or several; see Choose a table layout. Check or create your source tables explains how to verify them before the first run. The prepared examples create them with their own loaders (load_nyctaxi.sql, real_data/load_data.py); a normal project uses tables you already have.

Predictions: output_schema

Table Created by Purpose
Prediction table (prediction_table in config/inference.yml) Score job, on its first run One row per scored source row: record key, prediction, probabilities for classifiers, model name, version and run, and, when the model can exclude rows, scoring_status and exclusion_reason. Extra output columns from scoring rules (for example no2_band) are added here.
<prediction_table>_v<version> plus a view under the logical name Score job with on_model_change: rescore_all One physical table per model version; the view always points at the current generation. Older generations remain until you remove them.

The default on_model_change: score_new_rows mode keeps one table and appends new predictions. See Scoring.

Feature tables (optional)

Projects that use config/features.yml and src/features/groups/ also run a features job. It writes one output table per feature group and the merged feature table that training and lookup read. Online serving can add an online copy of a feature table. See Feature tables and online features. Projects without feature groups, such as the real_data examples, have none of these.

Models: metadata_schema

The train job registers the model as a Unity Catalog registered model (model_name in config/training.yml), for example air_quality_no2_model. It appears in the schema's model list, not as a table. Each training run adds a version; the champion alias marks the version that scoring uses. The MLflow experiment, with runs, metrics, SHAP and chart artifacts, lives in the workspace path from experiment_name, not in a schema.

The shared monitoring store

The first monitoring enrollment creates the store in monitoring_catalog.monitoring_schema. One store serves every project and model that uses the same catalog and schema; later projects reuse it instead of creating their own. See Store setup for permissions and upgrades.

Four Delta tables (they hold data)

Table What it holds
model_inventory One row per monitored model in each environment and project: which model and version, which tables, and its monitoring settings. Enrollment writes it.
monitoring_results One immutable row per monitoring observation: the full report with drift, quality and performance evidence. The monitoring job only appends.
performance_actions For each performance-policy result, whether a retraining request was made or skipped and why, recorded without rewriting the observation.
retraining_requests Every retraining request and its submission receipt, and the shared cooldown gate per train job, so two triggers cannot start training twice.

Eight views (no data of their own)

They read the Delta tables above and exist for the dashboard and your own queries.

View Answers
current_health What is the latest state of each monitored model?
monitoring_issues Which quality, drift or performance-policy issues are open now?
metric_history Every recorded metric as one row (column, metric, value, threshold, issue). The easiest place to query drift and performance values.
performance_history Performance results together with the action taken for each.
complete_observations Full observations, excluding the small late-label-only reports a policy writes.
monitoring_identities Every model, version and context ever monitored, including earlier ones.
model_version_details Lineage and saved metadata of each concrete model version, including its training summary.
serving_windows Serving-endpoint observation windows used by the dashboard's serving charts.

Reference populations per monitored model version

Drift and retraining checks compare new data with what the model was trained on. Rereading the training table on every run would be slow and could see changed data, so enrollment copies the needed populations into immutable Delta tables. New format-2 references use two tables per identity and a source table that can be shared. The identity binds the monitored model, version and verified training evidence; source sharing additionally binds its physical Delta ID/version, selected columns, exact schema and row values, including duplicate counts.

Part What it holds Used for
monitor_ref_<identity>_population The seen rows plus a recorded boolean training-membership column. Temporal splits keep training rows; random splits also retain holdout rows. Drift selects training members; freshness checks use the complete seen population. The marker is removed before model/metric use and its name avoids feature collisions.
monitor_src_<identity> The verified, selected training source population, including the target. Historical reconstruction; shared only when content and schema match exactly.
_receipt One JSON record: the evidence these tables belong to, their table identities, the source table identity and the holdout metric values. Verifying the tables before use, and the training_holdout baseline of performance policies.

For N references with U distinct source populations, format 2 needs 2 * N + U tables. Two references using the same population need five tables. Four branches with four different target projections need twelve, even when their source table and Delta version are the same. A shared source table name alone never proves that its data can be reused.

Existing format-1 references still use _train, _seen, _source, _receipt. They remain readable and eligible for guarded cleanup; upgrades do not migrate or delete them. Both formats hold copies bounded by training limits. New projects with monitoring include a weekly cleanup job; protected references remain until unused and old enough. See retention and recovery.

Give every project the same monitoring schema reserved for the store (for example workspace.skyulf_monitoring), and keep each project's data, predictions and models in the project's own schemas. A project schema then holds only its own tables, and all monitoring objects sit in one place:

Schema Typical contents
Project schema(s) Training table, scoring source, outcomes table, prediction table, registered model
skyulf_monitoring The 4 Delta tables, 8 views, per-identity population/receipt tables and shared source populations; an audit table is added when maintenance records are written

The air_quality_no2 example uses this shared layout. A fresh installation has four project tables: observations_train, observations_score, labels and predictions. The store's four tables, eight views and per-version references are in workspace.skyulf_monitoring. The other two real_data examples keep their independent stores in their project schemas.

The single-table air-quality walkthrough uses three project tables: observations for both training and scoring, labels for outcomes, and predictions. Daily input inserts do not update old rows. It uses the same shared monitoring schema.

Changing monitoring_schema redirects future enrollment and observations; it does not move or delete an existing store. Redeploy, enroll the existing concrete model in the destination, and prepare its Spark references before observing. Verify the destination report before retiring old objects. For example, an older air-quality installation may still contain its original 20 objects until its 16 monitoring objects are separately reviewed and removed. Historical reports stay in that old store; they are not automatically copied to the new one.

What grows, and how to clean up

Object Grows with Clean up
Prediction table New source inserts Your retention policy; Skyulf does not delete predictions.
monitoring_results, performance_actions, retraining_requests Monitoring runs and decisions Keep observation/action evidence for audit. Request status, job cooldown gates and the reserved reference-admission row also receive guarded updates.
Reference tables New monitored identities and distinct source populations Use guarded reference cleanup; retained aliases, monitors, policy baselines and unfinished retraining protect references. Shared sources remain while another receipt needs them.
_v<version> prediction generations New versions in on_model_change: rescore_all mode Drop old generations once consumers use the new view.

Views never need cleanup. Do not drop or recreate the store's tables while any project still monitors into them; other projects share them.