Upgrade from miura-nexus 0.61.4 to 0.65.x¶
Use this page if you still run the 0.61.4 client and want the 0.65 release. You can upgrade in one step—you do not need to install 0.62 or 0.63 along the way.
Most workflows that only read collections, upload local files, or download results need little or no code change. If you author recipes, import from connectors, or read published tables from a run handle, start with the table below.
Upgrade at a glance¶
Recipe authors on a backend that requires a case-grouping binding must follow Recipe execution on binding-required backends.
get, list_items, download, and local upload without case grouping stay
as they are. Bumping the package does not migrate collection data or force you
to rewrite recipes you already run successfully.
| Existing usage | Impact | Required action |
|---|---|---|
| Basic collection reads / download | None | None |
| Local upload / plan without case grouping | None | None |
| Read/write existing collections | None | None |
| Create or run a new recipe on a binding-required backend | Breaking | Upgrade to 0.65.x; create an admitted case binding and pass it as cases= to deploy_recipe |
| Run an existing recipe with a persisted admitted binding | None | None |
RunHandle.catalog_asset() / catalog_publication() |
Breaking | Use catalog_asset() on the target collection |
Connector discovery APIs (ConnectorDiscovery*) |
Breaking | Rename discovery → inventory; provide source_prefix; set transfer_binding_id before apply() |
Early 0.62 / 0.63 case-grouping / with_case_grouping |
Breaking | Bind with cases= from upload.cases / plan.cases |
Reusing AsyncNexus after close() |
Behavior | Fix client lifecycle (async with or new client) |
Assuming UploadResult.total_size_bytes is always an int |
Behavior | Handle None |
get_or_create_recipe when the stored executable differs |
Behavior | Catch RecipeSpecConflictError or use deploy_recipe |
Nested optional() schema folders |
Behavior | Re-check if you relied on old child-required semantics |
| Tests matching “Not authenticated” on permission denials | Behavior | Update string matchers only |
If every row marked Breaking or Behavior does not apply to your code, no source changes are expected for the common 0.61.4 collection workflows above.
Before you upgrade¶
- Scan the impact matrix and note which rows apply.
- Complete every applicable item in the migration checklist.
- Know your rollback posture before you install.
- Install
0.65.x, then verify.
Rollback¶
Client-only rollback to miura-nexus==0.61.4 is not viable for recipe
authoring on a backend that requires a case-grouping binding. 0.61.4 can
still read and write ordinary collection data, but it cannot create or send an
admitted binding for a new recipe execution.
For other workflows, rollback is expected to be safe without a data migration
provided you have not started using APIs introduced after 0.61.4 (case
grouping, deploy_recipe revisions with case pins, connector inventory apply,
collection description writes, inventory summary).
Once you create data or recipes that only newer workflows understand (for example recipes bound with admitted case membership, or connector imports via the inventory apply path), a client downgrade may still read older resources but will not drive those newer workflows. Prefer validating on an isolated test project first if you plan to adopt those features.
Migration checklist¶
Only perform an item if the corresponding API appears in your code. When every applicable box is done, the source migration is complete.
- Replace
run.catalog_asset()/run.catalog_publication()withcollection.catalog_asset()on the target collection. - Rename connector discovery types and fields to inventory
(
ConnectorInventoryScope,inventory_scope, …). - For connector datasources, provide the now-required
source_prefixand ensuremax_keysis within the supported 1–20000 range. - Set
transfer_binding_idbefore connectorapply(); leave any optional transfer override unset unless you intentionally set one for a single run. - Prefer
async with AsyncNexus(...)— API calls afterclose()now raise. - Allow
UploadResult.total_size_bytes is None(unknown size, not zero). - Catch
RecipeSpecConflictErrorfromget_or_create_recipe, or switch todeploy_recipe. - If your backend requires case-grouping bindings, do not retain
0.61.4for recipe authoring. Upgrade to0.65.x, create an admitted case result, and pass itsAdmittedCasesascases=todeploy_recipe. - If you used early 0.62 / 0.63 case-grouping helpers: bind with
cases=(upload.cases/plan.cases); dropwith_case_grouping/update(case_grouping=...).
Optional product adoption (CaseStructure, case grouping, connector import,
miura.sdk facade) is not required to finish this migration — see
New capabilities through 0.65.x after you verify.
Install 0.65.x¶
Install the latest 0.65 release from the same package index you already use:
python -m pip install --upgrade "miura-nexus>=0.65,<0.66"
# extras as before, e.g. python -m pip install --upgrade "miura-nexus[pandas,sigma]>=0.65,<0.66"
Breaking changes¶
Recipe execution on binding-required backends¶
Breaking platform compatibility change — affects 0.61.4 recipe authors.
Deployments that require admitted case membership expect every recipe execution to resolve a
case-grouping binding. A 0.61.4 client has no API for creating an admitted
case result or sending that binding. Creating a recipe with create_recipe() or
get_or_create_recipe() can succeed, but executing it fails with HTTP 400:
Not affected: collection reads, downloads, local uploads, and reads of already published catalog assets. An existing recipe with a persisted admitted binding can continue to run.
What to do: upgrade the client and use the admitted binding flow:
grouping = CaseGrouping.root_path("/", 1)
upload = await source.upload(datasource, case_grouping=grouping)
recipe = await project.deploy_recipe("transform", spec, cases=upload.cases)
run = await project.run_recipe(recipe)
The backend has a deprecated legacy-tag fallback for a pre-created binding, but
that is not a complete 0.61.4 authoring workflow and should not be used as a
long-term compatibility contract.
Catalog asset from the collection, not the run¶
Breaking change — only if you use RunHandle.catalog_asset() or
RunHandle.catalog_publication().
Not affected: code that already uses collection-level catalog_asset() /
catalog_assets.
What changed: Run-scoped shortcuts are removed. Resolve published tables from the target collection.
What to do: Point at the collection that owns the published table. See Published tables.
Connector discovery → inventory¶
Breaking change — only if your code constructs connector datasources (or
imports ConnectorDiscoveryScope / ConnectorDiscoveryJobRef).
Not affected: callers that never used connector datasources.
| 0.61.4 | 0.65.x |
|---|---|
ConnectorDiscoveryScope |
ConnectorInventoryScope |
ConnectorDiscoveryJobRef |
ConnectorInventoryJobRef |
discovery_scope / discovery_job |
inventory_scope / inventory_job |
discovery_job_id |
inventory_job_id |
ManifestProvenance.CONNECTOR_DISCOVERY |
CONNECTOR_INVENTORY |
optional source_prefix |
required source_prefix |
soft max_keys |
include_glob default **/*, max_keys in 1–20000 |
What to do:
- Rename imports and fields.
- Always set
source_prefix; keepmax_keysbetween 1 and 20000 if you set it. - Set
transfer_binding_idonConnectorDataSourcebeforeapply(). - For a normal import, leave optional transfer overrides unset. Set an override only when you intentionally redirect a single run.
- Use async collections for connector import — the sync API rejects connector datasources.
Guide: Import files from a remote connector.
Preview case-grouping APIs (cases=)¶
Breaking change — only if you wrote against early 0.62 / 0.63 wheels or docs.
Not affected: 0.61.4 callers only when they do not author recipes on a
binding-required backend. Those callers must upgrade as described above; this
section otherwise only concerns early 0.62 / 0.63 preview APIs.
What changed: Membership is bound on deploy/update with cases=
(AdmittedCases from upload.cases / plan.cases, or an admitted
CaseGroupingResult). recipe.update(case_grouping=...) and
with_case_grouping helpers are gone. Raw CaseGrouping, upload, or plan
objects are rejected at the binding site. RecipeSpec factories still take
grouping intent on case_grouping= (authoring, not the admitted pin).
What to do:
upload = await collection.upload(datasource, schema=schema, case_grouping=grouping)
recipe = await project.deploy_recipe("my-recipe", spec, cases=upload.cases)
await recipe.update(cases=plan.cases) # rebind later
Important behavior changes¶
These APIs remain available, but their behavior or returned values changed.
Closed clients can no longer be reused¶
Who is affected: Code that calls an AsyncNexus client after close().
What changed: Such calls now raise RuntimeError. Previously a new HTTP
session was opened implicitly.
What to do: Use async with AsyncNexus(...) or create a new client.
Upload size may be unknown¶
Who is affected: Code that formats or arithmetic on
UploadResult.total_size_bytes without a null check.
What changed: The field is int | None. For connector apply(), None
means unmeasured (not zero). Local uploads still always count.
What to do:
get_or_create_recipe rejects executable drift¶
Who is affected: Idempotent bootstrap that assumed “same name ⇒ return whatever exists” even when the requested executable spec differed.
What changed: Mismatch raises RecipeSpecConflictError; the stored recipe is
left unchanged.
What to do: Catch RecipeSpecConflictError, or prefer
project.deploy_recipe(name, spec, cases=...) for create / no-op / revise.
Permission errors show the real denial¶
Who is affected: Tests or logs that match the old
permission_denied: Not authenticated string on grant failures.
What changed: Permission denials no longer look like missing API keys when your credentials are fine and the resource simply denied the action. API-key hints are reserved for genuine authentication failures.
What to do: Update those matchers only. Everyday callers need no change.
Token refresh defaults¶
Who is affected: Environments where token refresh was wired to a non-default auth client without an explicit override.
What changed: Refresh-token exchanges default to the nexus-hub-atlas
Keycloak client. nexus-core is not the default while that profile is not
generally available in production.
What to do: Hub Atlas users need no change. To use Core, set
MIURA_INTERNAL_KEYCLOAK_CLIENT_ID=nexus-core. If authentication starts
failing after the upgrade, set the token-refresh client to the client that
issued your API key.
Optional schema parents skip required descendants¶
Who is affected: Schemas that nest required members under optional()
folders and expected child requirements to fire when the parent is absent.
What changed: optional() is per-node. Absent optional parents skip required
descendants.
What to do: Re-check those schemas if you relied on the old interpretation.
Verify the upgrade¶
Run the paths you actually depend on:
- Authentication succeeds
- Read an existing collection (
get/list_items) - Upload one representative local datasource
- Run one existing recipe and wait for completion
- Resolve its published output via collection
catalog_asset(), if applicable - Run connector plan/apply, if applicable
- Download one representative result
If these pass, the 0.61.4 → 0.65.x migration is complete.
Everything below is optional modernization — stop here if your only goal is a green bump.
New capabilities through 0.65.x¶
Nothing in this section is required for a successful upgrade.
Authoring from miura.sdk¶
from miura.sdk import CaseStructure, File, Number, RecipeSpec, ResourceMap, Schema, capture, one_or_more
Recipe helpers: miura.sdk.recipe. Optional Sigma: miura.sdk.sigma (plain
import miura.sdk does not require the [sigma] extra).
CaseStructure, case grouping, and CaseSet¶
from miura.sdk import CaseStructure, File, Number, capture, one_or_more
case_id = capture("case_id", Number(min_digits=6, max_digits=6))
structure = CaseStructure.folder(
path="sim_" + case_id,
members={"mesh": File("mesh.stl"), "field": File("field.xdmf")},
)
schema = structure.schema(count=one_or_more())
case_grouping = structure.case_grouping()
upload = await collection.upload(
datasource,
schema=schema,
case_grouping=case_grouping,
)
# upload.cases → AdmittedCases pin for deploy
Also: collection.plan(..., case_grouping=), case_set(...),
probe_case_grouping(), live CaseSet reads. Guides:
Describe simulations,
Case discovery.
Deploy → run recipe lifecycle¶
from miura.sdk import RecipeInputs
recipe = await project.deploy_recipe("convert", spec, cases=upload.cases)
run = await recipe.run(inputs=RecipeInputs.PINNED) # or "latest"
deploy_recipecreates, no-ops, or revises (create_reciperemains create-only).inputs="pinned"(default) vsinputs="latest"for membership at run time.project.available_writers/available_readers; pass writers as plain strings (writer="parquet_tabular").
Guide: Transform cases with a recipe.
Connector plan() → apply()¶
Same review-before-run flow as local upload. See Import files from a remote connector.
Connector plans can also opt into case grouping:
from miura.nexus.case_grouping import CaseGrouping
case_grouping = CaseGrouping.root_path("/", depth=1)
plan = await collection.plan(
connector_datasource,
case_grouping=case_grouping,
)
recipe = await project.deploy_recipe("transform", spec, cases=plan.cases)
Check plan.validation_gates and plan.is_admissible before applying the plan.
If connector-origin grouping is not enabled by the deployment, the client
raises ValueError rather than silently ignoring the request.
Collection description and inventory summary¶
- Optional Markdown description CRUD (
CollectionDescriptiononmiura.sdk). - Collection inventory summary (
Nonewhen unavailable).
Sigma factories and pipeline input manifests¶
RecipeSpec.from_sigma_converter / from_sigma_dataset_generator, plus
attach_pipeline_input_manifest() for attaching a pipeline input manifest to a
recipe data_ref.
Reliability fixes¶
Usually no code change — same APIs, more correct behavior:
- Uploads tolerate brief finalize retries instead of failing immediately.
- Large or slow local uploads are more stable.
- Staging uploads no longer send unsigned headers that object storage rejects.
- Downloads find the right object when the storage key and item URI diverge.
- HTTP 422 responses include field-level validation detail.
- Uploads without case grouping are not blocked when grouping was skipped as a precondition.
Update only if you asserted exact old error strings.
Documentation changes¶
Getting Started now leads with CaseStructure.folder and deploy → run.
Runnable examples are listed under
Example scripts. Update bookmarks or CI that
still pointed at the old tree.