# OperationKind vs OperationType: identity versus routing The pipeline has **two orthogonal axes** for talking about an operation, and they are easy to confuse because their names look almost alike. They answer different questions, live in different repositories, and — crucially — do **not** share value strings. - **`OperationKind` — identity.** *What kind of work is this?* - **`OperationType` — routing.** *Which worker queue should run it?* This page is the canonical reference for the distinction. When in doubt, decide whether you are asking about an operation's **identity** or its **routing**, then use the matching axis and the {ref}`mapping table ` below — not the words. ## `OperationKind` — the identity axis | | | |---|---| | **Home** | `ccat_ops_db.models` (ops-db) | | **Role** | Identity of a unit of work; the polymorphic discriminator of the uniform `Operation` model | | **Drives** | recovery, the circuit breaker, Redis task-state, and the Failure-event key | `OperationKind` is the single source of truth for *what an operation is*. Its values are byte-identical to the frozen breadcrumb strings already stored in the failure history, so identity is the same name everywhere — recovery, the circuit breaker, the operation-row discriminator, and the failure-event key all reference the enum member, never a free-text literal. It has **six** members. Note the deliberate name/value **asymmetry** on two of them (`PACKAGING` and `ARCHIVE`): the *names* follow the stage, the *values* follow the frozen breadcrumb strings. | Member | Value | Stage | |--------------|-------------------------|----------------------------------| | `PACKAGING` | `raw_data_package` | Package raw files at the source | | `BUNDLING` | `data_transfer_package` | Bundle packages for transfer | | `TRANSFER` | `transfer` | Move bytes between sites | | `UNPACK` | `unpack` | Unpack a transferred package | | `ARCHIVE` | `long_term_archive` | Write to long-term storage | | `STAGING` | `staging` | Stage a package for processing | For the model itself, see the ops-db [operation model reference](https://ccatobs.github.io/data-center-documentation/ops-db/docs/source/concepts/operation_model.html) and {doc}`../adr/0003-uniform-pipeline-operation-model`. ## `OperationType` — the routing axis | | | |---|---| | **Home** | `ccat_data_transfer.operation_types` (data-transfer) | | **Role** | Routing: selects the worker queue for a task; drives worker queue discovery | | **Drives** | `QUEUE_OPERATIONS_BY_LOCATION_TYPE` → location-specific queue names; worker self-discovery at startup | `OperationType` is the routing contract. Queue names are built from its values and workers self-discover their queues at startup, so this axis answers *where the work runs*, not *what it is*. It is a separate, frozen contract from identity. It has **eight** members: | Member | Value | |-----------------------------------|-------------------------------| | `RAW_DATA_PACKAGE_CREATION` | `raw_data_package_creation` | | `DELETION` | `deletion` | | `DATA_TRANSFER_PACKAGE_CREATION` | `data_transfer_package_creation` | | `DATA_TRANSFER_UNPACKING` | `data_transfer_unpacking` | | `DATA_TRANSFER` | `data_transfer` | | `STAGING` | `staging` | | `LONG_TERM_ARCHIVE_TRANSFER` | `long_term_archive_transfer` | | `MONITORING` | `monitoring` | Two of these routing types — `DELETION` and `MONITORING` — are **not** `OperationKind`s. They name work that has no operation-identity row: - **`deletion`** is not a unit of work with a `Status`. Deletion is a `PhysicalCopyStatus` state machine *on the artifact* (`PRESENT → DELETION_* → DELETED`), running in the destroy direction. Folding it into the `Operation` model would fabricate an op row for an artifact transition — see {doc}`../adr/0003-uniform-pipeline-operation-model` (decision 6). - **`monitoring`** is routing-only: it names the per-location monitoring queue, not a pipeline operation that produces or consumes a `PhysicalCopy`. (mapping-table)= ## The mapping table The two axes are orthogonal: a given stage's identity value and its routing value are **different strings**, even when they describe the same step. This is the table to rely on. | Stage | Identity — `OperationKind` value | Routing — `OperationType` value | |-----------|----------------------------------|-----------------------------------| | Packaging | `raw_data_package` | `raw_data_package_creation` | | Bundling | `data_transfer_package` | `data_transfer_package_creation` | | Transfer | `transfer` | `data_transfer` | | Unpack | `unpack` | `data_transfer_unpacking` | | Archive | `long_term_archive` | `long_term_archive_transfer` | | Staging | `staging` | `staging` | | Deletion | *(no kind — artifact state machine)* | `deletion` | | Monitoring| *(no kind — routing only)* | `monitoring` | Read across any row and the two value columns differ (the lone exception is staging, where both happen to read `staging`). The bottom two rows have a routing value but **no identity** — they are not operations. ## One honest caveat The two axis names (`OperationKind` / `OperationType`) and several of their values are near-synonyms, so rely on the **identity-versus-routing distinction and the mapping table above, not on the words**. :::{seealso} {doc}`concepts` — Sites, DataLocations, Operations, Managers, Queues, Routes {doc}`routing` — how work is routed to location-specific queues {doc}`../adr/0003-uniform-pipeline-operation-model` — the uniform operation model and the identity/routing split (decision 6 on deletion) :::