Repository navigation
Conversation
Change map
Requirement: registry versions must point at their bundle and support aliases (MLOps build). Existing: |
|
Warning Review limit reachedEnable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. Next included review available in 24 minutes. View limit details
Walkthrough
Priority: Merge Risk:
|
b63d82f to
bc742a3
Compare
d106960 to
3c40f67
Compare
bc742a3 to
aff3ebc
Compare
aff3ebc to
29ded0c
Compare
75ef25b to
a3ce235
Compare
29ded0c to
05ed020
Compare
a3ce235 to
70a332a
Compare
05ed020 to
53471bc
Compare
70a332a to
48367fa
Compare
53471bc to
4739ce2
Compare
48367fa to
4e5b58d
Compare
4739ce2 to
0009580
Compare
4e5b58d to
8bc9770
Compare
0009580 to
01dbfee
Compare
01dbfee to
7b019a0
Compare
d89b9f7 to
68401e3
Compare
fbfc9a5 to
c153ef2
Compare
68401e3 to
40295d5
Compare
c153ef2 to
fb48237
Compare
40295d5 to
ecae4a6
Compare
fb48237 to
d42d943
Compare
ecae4a6 to
eafd735
Compare
d42d943 to
e7a6da7
Compare
eafd735 to
e53f222
Compare
e7a6da7 to
ca4703c
Compare
e53f222 to
7f4539e
Compare
ca4703c to
238a52e
Compare
7f4539e to
248091b
Compare
238a52e to
18e3b42
Compare
There was a problem hiding this comment.
Note
Quiet mode is enabled, so only the most important comments were posted inline. Other review comments are grouped below.

Other comments: 2
packages/kumo-engine/docs/mlops.md: 2
87-87:Minor · Functional Correctness · Quick win Correct the result described for
Trainer.export.
Trainer.export(config)returns aPublishedModel. It does not setresult.published_model. If a reader follows this sentence after callingTrainer.export, the stated field can remainNone. Distinguishtrainer.export(config).versionfromfit(...).published_model.version.
88-88:Minor · Data Integrity & Integration · Quick win Describe Snowflake alias restoration as an attempt.
The statement that a failed alias move puts the alias back promises a successful rollback. The stated implementation only attempts to restore the previous assignment. If that restoration also fails, the alias can remain unset. Say that Snowflake attempts restoration and that callers should check the alias after a failed move.
🧹 Nitpick comments: 1
packages/kumo-engine/test/test_trainer_registry.py: 1
618-622:Trivial · Maintainability & Code Quality · Quick win Make the fake resolve the requested alias.
_AliasingSink.fetch_modelalways copiesCHURN_GNN@latest, and the alias-loading test never assignsprod. The test can therefore pass ifTrainer.load_from_connectordrops or changes the forwarded alias. Resolvelocation.aliasthroughself.aliases, and assignprodbefore loading.

Review info
-
Run configuration-
- Source mode: Auto
- Repository: NVIDIA/kumo-engine
- Branch: vedaant/mlops-scoring-defaults
- File: .coderabbit.yaml
- Commit: 248c49c
- Layers: Repository YAML
- Review profile: QUIET
- Plan: Enterprise
- Run ID:
0ccd3862-bc45-4b8c-99f6-a6b3e000a28d
Files selected for processing: 7-
packages/kumo-api/kumoapi/plugin.pypackages/kumo-engine/docs/mlops.mdpackages/kumo-engine/kumo/engine/__init__.pypackages/kumo-engine/kumo/engine/trainer/__init__.pypackages/kumo-engine/kumo/engine/trainer/trainer.pypackages/kumo-engine/test/test_scoring_defaults.pypackages/kumo-engine/test/test_trainer_registry.py
Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 1 remain after this review.
-
A scheduled score job cannot follow a promoted model: registries only hand out exact versions, and nothing ties a registry version back to the bundle it holds. ModelRegistryLocation gains `alias` (set after publishing, fetch by alias). Snowflake and Databricks registries implement ModelAliasingSink (a failed Snowflake move puts the alias back) and record the version's kumo_bundle_id; load_from_connector warns when the fetched bundle differs. kumo.MLOps(registry=ModelOutputConfig(connector, location=)) registers each fit's model after it is stored and tracked, returned as TrainingResult.registered_model (a failure warns). Aliases are checked before training. Databricks fetch accepts trailing-slash directories. Verified with test_trainer_registry.py, test_scoring_defaults.py, kumo-api test_plugin_registry.py and the Snowflake/Databricks registry tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Folded into #60 (tracking & registry), which now contains this PR's final code: the consolidated stack shows only the end state. Review continues there. |
Series: kumo-engine MLOps series: every snapshot, training table, model and prediction run carries a self-contained _provenance.json;
with kumo.mlops(...)stores each artifact under one artifact root, tracks fits and prediction runs in MLflow or Snowflake and registers models; volumes and stages can hold files; prediction runs are monitored for drift and realized performance.Stack: Models, registry and job templates: #57 → #59 → #65 → #71
Merge order: one linear stack; merge bottom to top (#53 first)
This PR: Adds explicit model aliases, a bundle id pointer, and registration through
kumo.MLOps(registry=...)for the Snowflake and Databricks model registries.Summary
This PR adds explicit model aliases, a bundle id pointer, and registration through
kumo.MLOps(registry=...)for the Snowflake and Databricks model registries. A version can be registered under an alias, promoted by moving the alias, and loaded by it; each version records which bundle it holds, and a fetch warns if the bundle it gets is a different one.Problem. Teams that publish Kumo models to a warehouse registry need to answer questions like these:
prod?Today none of these can be answered from the registry, and loading by a stable name is not possible.
Cause. A Kumo publish records only a
kumo_enginemarker, which exists so that listing can tell Kumo versions apart from other tools' versions. The engine already passesmetadata(spec_version,predictive_query,snapshot_id) andmetricstopublish_model, but neither registry stored them. The call each registry received before this PR:list_modelsandfetch_modelreturned no id.ModelRegistryLocationtakes a model name and an optional exact version; there was no alias API. With MLOps on (#50), nothing registered a fit's model: only a plainexport_config=published.Change.
Registration and aliases:
MLOps(registry=ModelOutputConfig(connector, location=...))registers each fit's model after the plainexport_config(if any), the root copy and tracking, and returns the version as the newTrainingResult.registered_model. Registration is independent ofexport=. If it fails,fitwarns and returns the result withregistered_model=None. A connector that cannot publish models, or an invalid alias, raises before training.TrainingResult.published_modelstays the plainexport_configresult. (A bareModelRegistryLocation, registered through MLflow, comes in Log, register and serve fitted models through MLflow pyfunc #65.)fit(export_config=ModelOutputConfig(connector, location=...))orTrainer.export(...)publishes as before, with or without a block, and also accepts analias.ModelRegistryLocation.aliascannot be combined withversion. On export, the version is published first and the alias is set on it afterwards. If setting it fails (including a sink without alias support), the call warns and still returns the published model.kumo.engine.set_model_aliasgoes through a new optionalModelAliasingSinkprotocol inkumoapi.plugin. A sink without it raisesNotImplementedErrorfor this new call and for fetching by alias.DEFAULT,FIRSTandLASTcan be fetched by but not set.PUT /api/2.1/unity-catalog/models/{name}/aliases/{alias}to set an alias andGETon the same path to fetch by it.kumoapi.plugin.check_model_aliasholds one alias syntax every registry accepts: a letter or underscore, then letters, digits or underscores (at most 255), and notDEFAULT,FIRST,LAST(Snowflake),LATESTorv<digits>(MLflow) in any case. Hyphens are refused because Snowflake would need a quoted identifier, which also excludes SageMaker'sSageMakerLifecycle-aliases. Both registries call it, andfit(forexport_config=and an MLOps registry) andTrainer.exportcall it before training or publishing, so an invalid export alias fails at once instead of after a fit has been published without it.Bundle id pointer: each published version now records the marker and
kumo_bundle_id, the bundle's content hash from #56. The bundle's own_provenance.jsonholds its lineage (snapshot, training table, source table versions), so the registry stores a pointer, not a copy. From a CPU fit on a small synthetic users/items/orders graph (PREDICT COUNT(orders.*, 0, 7, days) > 0 FOR EACH users.ID), hashes shortened:metrics.jsonand on the tracked fit run (Record fits in experiment tracking and publish models to registries #60, Record Trainer.fit in Snowflake Experiment Tracking through kumo.MLOps(tracking=) #68), where runs can be compared. Snowflake and Databricks versions record the same two keys.list_modelsand everyfetch_modelpath (by version, default, or alias) return the recordedkumo_bundle_idinPublishedModel.metadata, read through the sharedkumoapi.plugin.registry_lineage.Trainer.load_from_connectorcompares the recordedkumo_bundle_idwith the fetched bundle's id on every fetch; a mismatch is a warning only.fit(export_config=), the MLOps registry step andTrainer.export(Add TrainingResult.with_scoring_defaults and Trainer.export #57) publish through the same_publish, so all record the pointer and set the alias. Exporting a derived bundle fromTrainingResult.with_scoring_defaultspublishes the child's ownkumo_bundle_id, not the parent's.ModelRegistryLocation(version=None)docstring now says what fetch loads: Snowflake's default version, or the highest ready Kumo version in Databricks.docs/mlops.mdgains a "Registering models" section.Also fixed: Databricks fetch of a real bundle. The Unity Catalog Files API lists directories with a trailing slash (
.../1/model/), so the immediate-child check in the download rejected every real bundle andTrainer.load_from_connector(DatabricksConnector, location=...)raisedInvalid model artifact path returned by Databricks.The slash is stripped before the check; the fake Files API in the tests now lists directories the same way. Found in a live Databricks run.Not in this PR. Snowflake
task=is not set, so Snowflake model monitors cannot attach to Kumo versions yet; it needs a live check first because a server-side rejection would fail every publish.Not verified live: Snowflake
log_modelwith the pointer record, alias set/unset, the rollback and the one-alias rule; Databricks alias PUT/GET. Registry tests use the packages' fakes. The Databricks trailing-slash bug was found in a live workspace run; the fix is tested against the fake.Back-compat
This PR only records and exposes information on publish; aliases are a new opt-in field and a new call. No existing publish or fetch path gains a check that can fail.
registry=registered_modelisNone.registry=and registration failsregistered_model=None.kumo_bundle_idrecorded. The assigned version and the returnedPublishedModelare unchanged.kumo_bundle_idinPublishedModel.metadata; the id is still inside its bundle. No mismatch warning (nothing recorded).versionor with no versionmetadatanow carries the recordedkumo_bundle_id.bundle_id(written before #56)ValueErrorbefore training or publishing.fitturns it into the warning above).kumo_bundle_iddiffers from the fetched bundlemetadata.Invalid model artifact path).Testing Done
kumo_bundle_id; list and fetch (by version and by alias) return it; Snowflake alias set, move, rollback of a failed move and the refusals Snowflake requires; Databricks alias needs a positive version; every Databricks fetch test lists directories with a trailing slash.test_plugin_registry.py:check_model_aliassyntax and reserved names,registry_lineage.test_trainer_registry.py: an MLOps registry registers after the fit and sets the alias, and a failing registry warns and leavesregistered_modelunset; an invalid MLOps registry alias raises before training; the exact metadata passed topublish_model; export with an alias publishes then sets it, best-effort; the bundle-id mismatch warning; an alias fetch needs an aliasing sink; an invalid export alias is refused before publishing.test_scoring_defaults.py:Trainer.exportof a derived bundle publishes the child'skumo_bundle_id.test_trainer_registry.py,test_scoring_defaults.py, kumo-snowflaketest_registry.pyand kumo-apitest_plugin_registry.py: 69 passed; kumo-databrickstest_registry.py+test_uc_registry.py: 41 passed.Checklist
docs/mlops.md).🤖 Generated with Claude Code