> ## Documentation Index
> Fetch the complete documentation index at: https://jephalabs.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Types and Enums

> Core domain types, enums, and value objects used across QTG

# Types and Enums

> **Source of truth**: `src/qtg/domain/types.py`, `src/qtg/domain/states.py`
> **Public re-export**: `src/qtg/domain/__init__.py`

The QTG v3 domain layer defines all classification values as `enum.StrEnum`. They are stored as strings in the DB and referenced as type-safe enums in Python code. This document explains every enum defined in the domain.

***

## Table of Contents

1. [TransportFamily](#transportfamily)
2. [VenueType](#venuetype)
3. [ChainFamily](#chainfamily)
4. [CompletionAssurance](#completionassurance)
5. [NodeKind](#nodekind)
6. [EdgeType](#edgetype)
7. [GraphShape](#graphshape)
8. [PlanTemplateStatus](#plantemplatestatus)
9. [ApprovalStatus](#approvalstatus)
10. [ReservationStatus](#reservationstatus)
11. [CallbackOutboxStatus](#callbackoutboxstatus)
12. [RequestState / NodeState](#requeststate--nodestate)

***

## TransportFamily

Top-level classification of transfer method. At the plan-template level, it determines which transport path is used.

```python theme={null}
class TransportFamily(enum.StrEnum):
    cex = "cex"
    cctp = "cctp"
    bridge = "bridge"
```

| Value    | Description                                                                                                                                                                     | Related Executor                                                                           |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| `cex`    | Exchange (CEX) withdrawal/deposit path. Upbit, Binance, Bybit, Coinbase, OKX, and more                                                                                          | `CexWithdrawalActionExecutor`, `CexWithdrawalObserveExecutor`, `CexDepositObserveExecutor` |
| `cctp`   | Circle CCTP (Cross-Chain Transfer Protocol)                                                                                                                                     | `CctpBurnExecutor`, `CctpMintExecutor`, related observe executors                          |
| `bridge` | Generic bridge lane. Implemented send executors: Chainlink CCIP (`exec.ccip.send`), USDT0 / LayerZero native-OFT (`exec.usdt0.send`), and Stargate (`exec.stargate.send`, Pro). | `exec.ccip.send`, `exec.usdt0.send`, `exec.stargate.send` (Pro)                            |

### Usage

* transport classification for plan templates (used in future routing decisions)
* lane separation in executor selection logic

***

## VenueType

Type of venue where funds are located.

```python theme={null}
class VenueType(enum.StrEnum):
    exchange = "exchange"
    chain = "chain"
    bridge = "bridge"
```

| Value      | Description                            | Example                    |
| ---------- | -------------------------------------- | -------------------------- |
| `exchange` | Centralized exchange                   | Upbit, Binance, Bybit      |
| `chain`    | On-chain address (EOA, smart contract) | Ethereum, Solana, Ripple   |
| `bridge`   | Bridge protocol                        | Circle CCTP TokenMessenger |

### Usage

* source/destination venue classification in intent
* filtering eligible plan templates by the source\_venue\_type + destination\_venue\_type combination during routing decisions

***

## ChainFamily

Blockchain network family. Signing scheme, RPC interface, and address format are consistent within a family.

```python theme={null}
class ChainFamily(enum.StrEnum):
    evm = "evm"
    solana = "solana"
    bitcoin = "bitcoin"
    ripple = "ripple"
    unknown = "unknown"
```

| Value     | Description                               | Signing scheme            | Usage example                                |
| --------- | ----------------------------------------- | ------------------------- | -------------------------------------------- |
| `evm`     | Ethereum Virtual Machine-compatible chain | ECDSA secp256k1           | Ethereum, Polygon, Arbitrum, Base, Avalanche |
| `solana`  | Solana family                             | Ed25519                   | Solana mainnet                               |
| `bitcoin` | Bitcoin and UTXO family                   | ECDSA secp256k1           | Bitcoin mainnet                              |
| `ripple`  | XRP Ledger                                | ECDSA secp256k1 / Ed25519 | XRP Ledger                                   |
| `unknown` | Unknown classification                    | N/A                       | fallback                                     |

### Usage

* `SignerRegistryEntry.chain_families` (JSON array) — list of chain families supported by the signer
* `SigningIntent.chain_family` — specifies the chain family in the signing request
* decides chain-specific RPC call behavior inside executors

***

## CompletionAssurance

Assurance level required for a node/request to be considered "complete." It indicates how deep the verification goes.

```python theme={null}
class CompletionAssurance(enum.StrEnum):
    provider_completed = "provider_completed"
    destination_observed = "destination_observed"
    destination_credited = "destination_credited"
    destination_finalized = "destination_finalized"
    protocol_finalized = "protocol_finalized"
```

| Value                   | Description                                                          | Assurance level |
| ----------------------- | -------------------------------------------------------------------- | --------------- |
| `provider_completed`    | provider (exchange/protocol) reports completion                      | lowest          |
| `destination_observed`  | receive transaction detected on the destination chain                | medium          |
| `destination_credited`  | deposit confirmed at the destination (exchange balance credit, etc.) | high            |
| `destination_finalized` | destination-chain finality confirmed (N confirmations)               | high            |
| `protocol_finalized`    | protocol-level finality (CCTP attestation + mint, etc.)              | highest         |

### Usage

* `MovementPlanVersion.completion_policy` (JSON) — plan-level completion policy
* `MovementRequest.completion_policy_snapshot` — snapshot taken when the request is created
* used to decide how far observe nodes should execute

### Assurance-level hierarchy

```mermaid theme={null}
flowchart TB
    A["provider_completed<br/>(weakest assurance)"] --> B[destination_observed]
    B --> C[destination_credited]
    C --> D[destination_finalized]
    D --> E["protocol_finalized<br/>(strongest assurance)"]
```

The higher the required assurance level, the more observe nodes are included in the plan graph.

***

## NodeKind

Classification of node roles within the plan graph. It is a **core distinction in the v3 architecture** and directly affects executor selection and state-transition strategy.

```python theme={null}
class NodeKind(enum.StrEnum):
    action = "action"
    observe = "observe"
    manual_gate = "manual_gate"
    compensation = "compensation"
    post_action = "post_action"
```

| Value          | Description                                              | Side Effect | Representative examples                                                                                                                      |
| -------------- | -------------------------------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `action`       | Execution node that changes external state               | **Yes**     | `cex_withdrawal`, `cctp_burn`, `cctp_mint`                                                                                                   |
| `observe`      | Observation node that **only reads** external state      | **No**      | `cex_withdrawal_status`, `cex_deposit_status`, `destination_chain_receive_observe`, `destination_chain_finality_observe`, `protocol_observe` |
| `manual_gate`  | Gate that requires operator manual review/approval       | **No**      | `manual_review`, `manual_confirm`                                                                                                            |
| `compensation` | Node that executes a compensating transaction on failure | **Yes**     | (future refund, reverse transfer, and more)                                                                                                  |
| `post_action`  | Post-completion processing (notification, logging, etc.) | **No**      | (future notification, audit log, and more)                                                                                                   |

### Importance of the action vs observe distinction

This distinction directly affects the system's safety model:

1. **`has_side_effect` decision**: `action` nodes are typically set to `has_side_effect=True`. This flag determines the `FAILED` vs `MANUAL_INTERVENTION` judgment in state derivation. (See [states-and-transitions.md](/reference/domain/states-and-transitions) for details.)

2. **Whether signing is required**: `action` nodes may have `signing_required=True` (especially on-chain tx). `observe` nodes do not require signing.

3. **Meaning of UNKNOWN state**: UNKNOWN on an `action` node means a fund movement may have happened. UNKNOWN on an `observe` node means only that the lookup failed.

4. **Recovery strategy**: `action` UNKNOWN -> attempt txid confirmation from the provider. `observe` UNKNOWN -> simple retry.

### manual\_gate behavior

* If there is a READY node whose `node_key` starts with the `manual_` prefix
* and there are no other active execution nodes
* `derive_request_state()` returns `WAITING_MANUAL_ACTION`
* when the operator clears the manual gate through the API, the request returns to `EXECUTING`

### DB usage

* `MovementPlanNode.node_kind` (String(32)) — plan node definition
* `ExecutionContext.node_kind` — passed into execution context

***

## EdgeType

Type of connection (edge) between nodes in the plan graph. It determines under which condition the transition moves to the next node.

```python theme={null}
class EdgeType(enum.StrEnum):
    on_success = "on_success"
    on_failure = "on_failure"
    on_timeout = "on_timeout"
    on_cancel = "on_cancel"
    on_manual_resume = "on_manual_resume"
```

| Value              | Description                             | Trigger condition        |
| ------------------ | --------------------------------------- | ------------------------ |
| `on_success`       | predecessor node completes successfully | `NodeState.COMPLETED`    |
| `on_failure`       | predecessor node fails                  | `NodeState.FAILED`       |
| `on_timeout`       | predecessor node times out              | timeout\_policy exceeded |
| `on_cancel`        | request/node is canceled                | `NodeState.CANCELLED`    |
| `on_manual_resume` | operator manually resumes               | manual gate cleared      |

### DB usage

* `MovementPlanEdge.edge_type` (String(32))
* `MovementPlanEdge.from_node_id` → `MovementPlanEdge.to_node_id`
* `MovementPlanEdge.condition_expr` — additional conditional expression (optional)
* `MovementPlanEdge.priority` — priority among the same edge\_type

### Role in Frontier Advancement

Currently, `advance_after_completion()` looks up successors of the completed node through `get_successor_keys()`. Branching logic by edge type is planned for `graph_runtime` (in v3.0, only the `on_success` path is active).

***

## GraphShape

Topology shape of the plan graph. Determined at compile time and used to judge runtime requirements.

```python theme={null}
class GraphShape(enum.StrEnum):
    LINEAR = "linear"
    BRANCHING = "branching"
    MERGING = "merging"
    SPLIT = "split"
    HYBRID = "hybrid"
```

| Value       | Description                                                             | Example                                                            |
| ----------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------ |
| `LINEAR`    | Straight chain. Each node has exactly one predecessor and one successor | CEX 3-node lane: action -> withdrawal\_observe -> deposit\_observe |
| `BRANCHING` | One node splits into multiple paths                                     | on\_success / on\_failure branch                                   |
| `MERGING`   | Multiple paths merge into one                                           | merge after parallel observe                                       |
| `SPLIT`     | Parallel execution (fork)                                               | simultaneous withdrawals                                           |
| `HYBRID`    | combination of branching + merging                                      | complex pipeline                                                   |

### DB usage

* `MovementPlanVersion.graph_shape` (Enum) — plan-version level
* `MovementPlanVersion.requires_graph_runtime` (Boolean) — `True` when not `LINEAR`

### v3.0 executability

```python theme={null}
# MovementPlanVersion
executable_in_v3_0: bool  # Only LINEAR is True
non_executable_reasons: list  # List of reasons the plan is not executable
```

The v3.0 runtime can execute only `LINEAR` graphs. `BRANCHING`, `MERGING`, `SPLIT`, and `HYBRID` require graph runtime and are marked with `MovementPlanVersion.executable_in_v3_0 = False`. This constraint is propagated to `MovementRequest` as well.

***

## PlanTemplateStatus

Lifecycle state of a plan template.

```python theme={null}
class PlanTemplateStatus(enum.StrEnum):
    draft = "draft"
    active = "active"
    archived = "archived"
```

| Value      | Description                                                                |
| ---------- | -------------------------------------------------------------------------- |
| `draft`    | In progress. Cannot be used for new requests                               |
| `active`   | In operation. Can be used for new requests                                 |
| `archived` | Archived. Existing requests remain, but it cannot be used for new requests |

### DB usage

* `MovementPlanTemplate.status` (Enum, default=`draft`)

***

## ApprovalStatus

Approval state of a request.

```python theme={null}
class ApprovalStatus(enum.StrEnum):
    pending = "pending"
    approved = "approved"
    rejected = "rejected"
```

| Value      | Description          |
| ---------- | -------------------- |
| `pending`  | Waiting for approval |
| `approved` | Approval completed   |
| `rejected` | Approval rejected    |

### DB usage

* `MovementRequest.approval_status` (Enum, default=`pending`)
* Tracked separately from RequestState. When RequestState transitions from `PENDING_APPROVAL` to `APPROVED`, `approval_status` also changes to `approved`.

***

## ReservationStatus

State of hardcap reservation (resource reservation).

```python theme={null}
class ReservationStatus(enum.StrEnum):
    none = "none"
    held = "held"
    consumed = "consumed"
    released = "released"
```

| Value      | Description                       | Transition condition                                                                                       |
| ---------- | --------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `none`     | No reservation (initial)          | when request is created                                                                                    |
| `held`     | Reservation held                  | after validation passes and reservation is acquired                                                        |
| `consumed` | Consumed (completed successfully) | when request reaches `COMPLETED`                                                                           |
| `released` | Released (failure/cancel/expiry)  | when request reaches `FAILED`/`CANCELLED`/`REJECTED`/`EXPIRED` (when side-effect conditions are satisfied) |

### DB usage

* `MovementRequest.reservation_status` (Enum, default=`none`)

### Detailed release conditions

Based on the `should_release_reservation()` function:
Based on `should_release_reservation()`:

* `REJECTED`, `EXPIRED` -> always released
* `CANCELLED`, `FAILED` -> released only when there is no side-effect-bearing COMPLETED node
* if a side-effect-completed node exists -> do not release (funds are in transit)

***

## CallbackOutboxStatus

Delivery state of a callback outbox message.

```python theme={null}
class CallbackOutboxStatus(enum.StrEnum):
    pending = "pending"
    sent = "sent"
    dlq = "dlq"
```

| Value     | Description                                                         |
| --------- | ------------------------------------------------------------------- |
| `pending` | waiting for delivery / retry                                        |
| `sent`    | delivery succeeded                                                  |
| `dlq`     | Dead Letter Queue. delivery abandoned after exceeding max\_attempts |

### DB usage

* `MovementCallbackOutbox.status` (Enum, default=`pending`)
* `MovementCallbackOutbox.max_attempts` (default=5)
* `MovementCallbackOutbox.attempts` — current attempt count

***

## RequestState / NodeState

Detailed descriptions of the state enums are organized in [states-and-transitions.md](/reference/domain/states-and-transitions). This section records only their location and re-export information.

* **Defined in**: `src/qtg/domain/states.py`
* **Re-export**: `qtg.domain.RequestState`, `qtg.domain.NodeState`
* RequestState: 12 values (RECEIVED, VALIDATED, PENDING\_APPROVAL, APPROVED, EXECUTING, WAITING\_MANUAL\_ACTION, COMPLETED, FAILED, MANUAL\_INTERVENTION, REJECTED, EXPIRED, CANCELLED)
* NodeState: 12 values (BLOCKED, READY, PREPARING, AWAITING\_SIGNATURE, SUBMITTING, SUBMITTED, OBSERVING, COMPLETED, FAILED, UNKNOWN, CANCELLED, SKIPPED)

***

## Full enum import path

All domain enums can be imported directly from `qtg.domain`:

```python theme={null}
from qtg.domain import (
    # types.py
    ChainFamily,
    CompletionAssurance,
    EdgeType,
    NodeKind,
    TransportFamily,
    VenueType,
    # states.py
    ApprovalStatus,
    CallbackOutboxStatus,
    GraphShape,
    NodeState,
    PlanTemplateStatus,
    RequestState,
    ReservationStatus,
)
```

`domain/__init__.py` re-exports all public types through `__all__`.

***

## DB column mapping summary

| Enum                   | Table.column                                               | Column type                                |
| ---------------------- | ---------------------------------------------------------- | ------------------------------------------ |
| `PlanTemplateStatus`   | `movement_plan_templates.status`                           | `Enum`                                     |
| `GraphShape`           | `movement_plan_versions.graph_shape`                       | `Enum`                                     |
| `RequestState`         | `movement_requests.request_state`                          | `Enum` (indexed)                           |
| `ApprovalStatus`       | `movement_requests.approval_status`                        | `Enum`                                     |
| `ReservationStatus`    | `movement_requests.reservation_status`                     | `Enum`                                     |
| `NodeState`            | `movement_request_nodes.node_state`                        | `Enum` (indexed)                           |
| `CallbackOutboxStatus` | `movement_callback_outbox.status`                          | `Enum` (indexed)                           |
| `NodeKind`             | `movement_plan_nodes.node_kind`                            | `String(32)` (string, not SQLAlchemy Enum) |
| `EdgeType`             | `movement_plan_edges.edge_type`                            | `String(32)` (string, not SQLAlchemy Enum) |
| `TransportFamily`      | (inside JSON fields)                                       | string                                     |
| `VenueType`            | (inside JSON fields)                                       | string                                     |
| `ChainFamily`          | `signer_registry.chain_families` (inside JSON arrays)      | string                                     |
| `CompletionAssurance`  | `completion_policy` of plan\_version/request (inside JSON) | string                                     |

`NodeKind` and `EdgeType` are stored in the DB as `String`, not SQLAlchemy `Enum`. Python code uses StrEnum, but at the DB-schema level only string constraints apply.

***

## Cross-References

* [states-and-transitions.md](/reference/domain/states-and-transitions) — RequestState/NodeState transition graph, derive logic
* [error-taxonomy.md](/reference/domain/error-taxonomy) — error-to-state-transition mapping
* [executor-signer-protocols.md](/reference/domain/executor-signer-protocols) — use of these types in ExecutionContext
* [../infrastructure/data-model.md](/reference/infrastructure/data-model) — DB schema details
