ump_spec.models.recipe
module ump-spec
provisional (not yet in the spec) G-DATA-06 is in the gate registry but not yet in the specification’s gate catalogue, so it is not normative.
Transform recipes: how a derived dataset was made (POC blueprint TRANSFORM-RECIPES §4 and §6; spec §6).
TransformRecipe is the normative form of <output>.recipe.json (schema ump.transform_recipe/0.1),
the file finprint writes beside an analyst’s output. The client package keeps its own copy of these
models (analysts install it without ump_spec); its committed JSON Schema
(packages/finprint/schema/transform_recipe.schema.json) MUST equal schemas/transform-recipe.json, and
a test in finprint fails on drift. Class names are part of the schema ($defs keys), so they match the
client package exactly, and every one carries a Recipe prefix (or is unique, ReaderSpec,
TransformRecipe) so the web’s merged type bundle has no name collision with Note.
What a recipe never holds: row values, cell outputs, environment variables, absolute paths (basenames only),
values of arguments whose name looks secret ("<redacted>") and string arguments longer than 200
characters (a short prefix plus their hash). Merkle leaves hold the recipe’s sha256 only, never its body.
RecipeRef is what a catalogued Dataset carries (Dataset.recipe): a pointer to the stored recipe
blob plus the few facts the catalogue page and gate G-DATA-06 read. apps/data never executes a recipe,
so verification is always the analyst’s own report (checked_by: "self").
Classes
Section titled “Classes”ReaderSpec
Section titled “ReaderSpec”class
class ReaderSpec(_Model)Fields
| Name | Type | Default | Description |
|---|---|---|---|
fn | Literal['read_csv', 'read_excel', 'read_parquet', 'read_catalogue'] | ||
kwargs | dict[str, Any] | dict() | Reader keyword arguments, tagged JSON (no path). |
replayable | bool | True |
Source: packages/ump-spec/src/ump_spec/models/recipe.py, line 68
RecipeCell
Section titled “RecipeCell”class
class RecipeCell(_Model)Fields
| Name | Type | Default | Description |
|---|---|---|---|
execution_count | int | None | None | |
order | int | ||
source | str | ||
frames_changed | list[str] | list() |
Source: packages/ump-spec/src/ump_spec/models/recipe.py, line 120
RecipeEnvironment
Section titled “RecipeEnvironment”class
class RecipeEnvironment(_Model)Fields
| Name | Type | Default | Description |
|---|---|---|---|
python | str | ||
pandas | str | ||
numpy | str | ||
ump_recipe | str | ||
platform | str |
Source: packages/ump-spec/src/ump_spec/models/recipe.py, line 140
RecipeExternalInput
Section titled “RecipeExternalInput”class
class RecipeExternalInput(_Model)A recipe input with no catalogued match in the client’s scope (UNCATALOGUED_INPUT).
Fields
| Name | Type | Default | Description |
|---|---|---|---|
input_id | str | ||
name | str | None | None | |
source | Literal['file', 'catalogue', 'in_memory'] | 'file' | |
sha256 | str | None | None | |
catalogue_fingerprint | str | None | None | |
fingerprint_seen | str | None | None | fetch_record.fingerprint_seen the recipe carried, kept so the hash a catalogue read saw is not lost. |
Source: packages/ump-spec/src/ump_spec/models/recipe.py, line 205
RecipeInput
Section titled “RecipeInput”class
class RecipeInput(_Model)Fields
| Name | Type | Default | Description |
|---|---|---|---|
input_id | str | Also the frame id steps use to refer to this input. | |
name | str | ||
source | Literal['file', 'catalogue', 'in_memory'] | ||
path_basename | str | None | None | |
sha256 | str | None | None | sha256 hex of the file bytes (stored catalogue datasets: blob hash). |
fingerprint | str | Canonical-rows fingerprint of the frame as read (see fingerprint_basis). | |
fingerprint_basis | str | RECIPE_FINGERPRINT_BASIS | |
dataset_id | str | None | None | |
catalogue_fingerprint | str | None | None | The catalogue’s rule (ump_spec.rules.canonical_rows_fingerprint, basis canonical_rows) over the frame as read, cells as plain JSON values; column and row order free. apps/data matches inputs to connected datasets by it. |
fingerprint_seen | str | None | None | fetch_record.fingerprint_seen from apps/data when read from the catalogue (blob hash for stored datasets, canonical rows of the raw rows for connected ones). |
copy_policy | _CopyPolicy | None | None | |
reader | ReaderSpec | None | None | |
rows | int | ||
columns | dict[str, str] | Column name to pandas dtype. |
Source: packages/ump-spec/src/ump_spec/models/recipe.py, line 74
RecipeInputMatch
Section titled “RecipeInputMatch”class
class RecipeInputMatch(_Model)A recipe input matched to a catalogued dataset in the same client’s scope (a derived_from edge).
Fields
| Name | Type | Default | Description |
|---|---|---|---|
input_id | str | ||
name | str | None | None | |
dataset_id | str | ||
dataset_version | int | None | None | The version of the matched dataset whose hash the input matched (its derived_from edge points at that dataset). |
matched_by | Literal['sha256', 'catalogue_fingerprint', 'dataset_id', 'dataset_id_drifted'] | sha256: file or blob bytes; catalogue_fingerprint: canonical rows of a connected dataset; dataset_id: read from the catalogue and its hashes agree; dataset_id_drifted: the input names this dataset but no catalogued version’s hash agrees (the source changed since it was catalogued, note DATA_DRIFTED). The dataset’s access terms apply either way. |
Source: packages/ump-spec/src/ump_spec/models/recipe.py, line 190
RecipeNote
Section titled “RecipeNote”class
class RecipeNote(_Model)Fields
| Name | Type | Default | Description |
|---|---|---|---|
code | RecipeNoteCode | ||
severity | Literal['info', 'warn'] | ||
message | str | ||
cells | list[int] | list() | Notebook execution counts the note is about. |
step_id | str | None | None |
Source: packages/ump-spec/src/ump_spec/models/recipe.py, line 60
RecipeOutput
Section titled “RecipeOutput”class
class RecipeOutput(_Model)Fields
| Name | Type | Default | Description |
|---|---|---|---|
path_basename | str | None | None | |
frame_id | str | ||
format | Literal['csv', 'parquet'] | 'csv' | |
sha256 | str | None | None | sha256 hex of the file as written; null when rows were not written. |
fingerprint | str | Canonical-rows fingerprint of the file as written and read back. | |
fingerprint_basis | str | RECIPE_FINGERPRINT_BASIS | |
rows | int | ||
columns | dict[str, str] | ||
rows_written | bool | True | |
index_written | bool | False |
Source: packages/ump-spec/src/ump_spec/models/recipe.py, line 127
RecipeRef
Section titled “RecipeRef”class
class RecipeRef(_Model)What a catalogued dataset keeps of its recipe (Dataset.recipe). The body lives in the blob store.
Fields
| Name | Type | Default | Description |
|---|---|---|---|
blob_uri | str | blob://sha256/<hex> of the recipe JSON as uploaded. | |
sha256 | str | sha256 hex of the recipe JSON bytes; the only part of a recipe a Merkle leaf may hold. | |
recipe_id | str | None | None | |
title | str | None | None | |
steps | int | Number of recorded steps. | |
capture | RecipeCapture | 'full' | |
verification | RecipeVerificationRef | RecipeVerificationRef() | |
inputs_matched | list[RecipeInputMatch] | list() | |
inputs_external | list[RecipeExternalInput] | list() | |
output_matches | bool | output.sha256 equals the uploaded file’s sha256. False: the recipe describes a different file (RECIPE_OUTPUT_MISMATCH). |
Source: packages/ump-spec/src/ump_spec/models/recipe.py, line 217
RecipeStep
Section titled “RecipeStep”class
class RecipeStep(_Model)Fields
| Name | Type | Default | Description |
|---|---|---|---|
step_id | str | ||
kind | Literal['named', 'verb', 'cell_edit'] | ||
op | str | Method name, ‘loc.setitem’, ‘groupby.sum’, ‘call:pandas.concat’, a named step’s function name, or ‘unrecorded_change’. | |
args | dict[str, Any] | dict() | Tagged JSON: frames as {‘frame’: id}, series expressions as {‘expr’: …}. |
code | str | None | None | |
code_sha256 | str | None | None | |
inputs | list[str] | list() | Frame ids read by this step; the first is ‘self’. |
output | str | ||
output_kind | Literal['frame', 'series'] | 'frame' | |
rows_before | int | None | None | |
rows_after | int | ||
columns_added | list[str] | list() | |
columns_removed | list[str] | list() | |
dtype_changes | dict[str, str] | dict() | |
fingerprint | str | In-memory hash of this step’s output (basis memory_hash/ump_recipe-1: values, column and index names, shape); replay compares it with the replayed object. | |
replayable | bool | True | |
cell | int | None | None | Notebook execution count when the step ran. |
note | str | None | None |
Source: packages/ump-spec/src/ump_spec/models/recipe.py, line 96
RecipeVerification
Section titled “RecipeVerification”class
class RecipeVerification(_Model)Fields
| Name | Type | Default | Description |
|---|---|---|---|
status | RecipeVerificationStatus | 'not_checked' | |
first_divergent_step | str | None | None | |
checked_at | datetime | None | None | |
checked_by | Literal['self'] | None | None | |
message | str | None | None |
Source: packages/ump-spec/src/ump_spec/models/recipe.py, line 148
RecipeVerificationRef
Section titled “RecipeVerificationRef”class
class RecipeVerificationRef(_Model)The recipe’s own verification as uploaded. Self-reported: apps/data never replays a recipe.
Fields
| Name | Type | Default | Description |
|---|---|---|---|
status | RecipeVerificationStatus | 'not_checked' | |
checked_at | datetime | None | None | |
checked_by | Literal['self'] | None | None | Always ‘self’ when checked: the analyst’s machine ran the replay, not UMP. |
first_divergent_step | str | None | None | Step id (or ‘output’) where a replay first differed; only with not_reproduced. |
Source: packages/ump-spec/src/ump_spec/models/recipe.py, line 179
TransformRecipe
Section titled “TransformRecipe”class
class TransformRecipe(_Model)<output>.recipe.json: inputs by hash, steps, notebook cells, the output’s fingerprint and the
analyst’s own replay check.
Fields
| Name | Type | Default | Description |
|---|---|---|---|
schema_version | Literal['ump.transform_recipe/0.1'] | 'ump.transform_recipe/0.1' | |
recipe_id | str | ||
title | str | ||
created_at | datetime | ||
author | str | None | None | |
inputs | list[RecipeInput] | ||
steps | list[RecipeStep] | ||
cells | list[RecipeCell] | list() | |
cells_included | bool | True | |
output | RecipeOutput | ||
capture | Literal['full', 'partial'] | 'full' | |
notes | list[RecipeNote] | list() | |
environment | RecipeEnvironment | ||
verification | RecipeVerification | RecipeVerification() |
Source: packages/ump-spec/src/ump_spec/models/recipe.py, line 156
Constants
Section titled “Constants”| Name | Type | Value | Description |
|---|---|---|---|
CATALOGUE_FINGERPRINT_BASIS | 'canonical_rows' | Basis of inputs[].catalogue_fingerprint: rules.canonical_rows_fingerprint over the frame’s cells as plain JSON values, the same basis a connected dataset registers its sha256 under. | |
RECIPE_FINGERPRINT_BASIS | 'canonical_rows/ump_recipe-2' | Basis of inputs[].fingerprint and output.fingerprint (the client package’s round-trip rule). | |
RECIPE_NOTE_CODES | tuple[str, ...] | ('RECIPE_PARTIAL', 'RECIPE_UNVERIFIED', 'RECIPE_NOT_REPRODUCED', 'RECIPE_OUTP... | |
RECIPE_SCHEMA_VERSION | 'ump.transform_recipe/0.1' | ||
RECIPE_STEP_HASH_BASIS | 'memory_hash/ump_recipe-1' | ||
RECIPE_VERIFICATION_STATUSES | tuple[str, ...] | ('not_checked', 'reproduced', 'not_reproduced', 'not_replayable', 'inputs_mis... | |
RecipeCapture | Literal['full', 'partial'] | ||
RecipeNoteCode | Literal['RECIPE_PARTIAL', 'RECIPE_UNVERIFIED', 'RECIPE_NOT_REPRODUCED', 'RECI... | ||
RecipeVerificationStatus | Literal['not_checked', 'reproduced', 'not_reproduced', 'not_replayable', 'inp... | not_checked is untested, not failed (RECIPE_UNVERIFIED). |