cmdx 1.8.0 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.DS_Store +0 -0
- data/.cursor/prompts/docs.md +3 -3
- data/.cursor/prompts/llms.md +1 -3
- data/.cursor/prompts/yardoc.md +1 -0
- data/.irbrc +14 -2
- data/CHANGELOG.md +64 -45
- data/LLM.md +159 -53
- data/README.md +26 -83
- data/docs/.DS_Store +0 -0
- data/docs/assets/favicon.ico +0 -0
- data/docs/assets/favicon.svg +1 -0
- data/docs/attributes/coercions.md +12 -24
- data/docs/attributes/defaults.md +3 -16
- data/docs/attributes/definitions.md +16 -30
- data/docs/attributes/naming.md +3 -13
- data/docs/attributes/transformations.md +63 -0
- data/docs/attributes/validations.md +14 -33
- data/docs/basics/chain.md +14 -23
- data/docs/basics/context.md +13 -22
- data/docs/basics/execution.md +8 -26
- data/docs/basics/setup.md +8 -19
- data/docs/callbacks.md +19 -32
- data/docs/deprecation.md +8 -25
- data/docs/getting_started.md +109 -76
- data/docs/index.md +132 -0
- data/docs/internationalization.md +6 -18
- data/docs/interruptions/exceptions.md +10 -16
- data/docs/interruptions/faults.md +8 -25
- data/docs/interruptions/halt.md +12 -27
- data/docs/logging.md +7 -17
- data/docs/middlewares.md +13 -29
- data/docs/outcomes/result.md +21 -38
- data/docs/outcomes/states.md +8 -22
- data/docs/outcomes/statuses.md +10 -21
- data/docs/stylesheets/extra.css +42 -0
- data/docs/tips_and_tricks.md +7 -46
- data/docs/workflows.md +23 -38
- data/examples/active_record_query_tagging.md +46 -0
- data/examples/paper_trail_whatdunnit.md +39 -0
- data/lib/cmdx/attribute.rb +88 -6
- data/lib/cmdx/attribute_registry.rb +20 -0
- data/lib/cmdx/attribute_value.rb +56 -10
- data/lib/cmdx/callback_registry.rb +31 -2
- data/lib/cmdx/chain.rb +34 -1
- data/lib/cmdx/coercion_registry.rb +18 -0
- data/lib/cmdx/coercions/array.rb +2 -0
- data/lib/cmdx/coercions/big_decimal.rb +3 -0
- data/lib/cmdx/coercions/boolean.rb +5 -0
- data/lib/cmdx/coercions/complex.rb +2 -0
- data/lib/cmdx/coercions/date.rb +4 -0
- data/lib/cmdx/coercions/date_time.rb +5 -0
- data/lib/cmdx/coercions/float.rb +2 -0
- data/lib/cmdx/coercions/hash.rb +4 -0
- data/lib/cmdx/coercions/integer.rb +2 -0
- data/lib/cmdx/coercions/rational.rb +2 -0
- data/lib/cmdx/coercions/string.rb +2 -0
- data/lib/cmdx/coercions/symbol.rb +2 -0
- data/lib/cmdx/coercions/time.rb +5 -0
- data/lib/cmdx/configuration.rb +119 -3
- data/lib/cmdx/context.rb +36 -0
- data/lib/cmdx/deprecator.rb +6 -3
- data/lib/cmdx/errors.rb +22 -0
- data/lib/cmdx/executor.rb +136 -7
- data/lib/cmdx/faults.rb +14 -0
- data/lib/cmdx/identifier.rb +2 -0
- data/lib/cmdx/locale.rb +3 -0
- data/lib/cmdx/log_formatters/json.rb +2 -0
- data/lib/cmdx/log_formatters/key_value.rb +2 -0
- data/lib/cmdx/log_formatters/line.rb +2 -0
- data/lib/cmdx/log_formatters/logstash.rb +2 -0
- data/lib/cmdx/log_formatters/raw.rb +2 -0
- data/lib/cmdx/middleware_registry.rb +20 -0
- data/lib/cmdx/middlewares/correlate.rb +11 -0
- data/lib/cmdx/middlewares/runtime.rb +4 -0
- data/lib/cmdx/middlewares/timeout.rb +4 -0
- data/lib/cmdx/pipeline.rb +24 -5
- data/lib/cmdx/railtie.rb +13 -0
- data/lib/cmdx/result.rb +133 -2
- data/lib/cmdx/task.rb +103 -8
- data/lib/cmdx/utils/call.rb +2 -0
- data/lib/cmdx/utils/condition.rb +3 -0
- data/lib/cmdx/utils/format.rb +5 -0
- data/lib/cmdx/validator_registry.rb +18 -0
- data/lib/cmdx/validators/exclusion.rb +2 -0
- data/lib/cmdx/validators/format.rb +2 -0
- data/lib/cmdx/validators/inclusion.rb +2 -0
- data/lib/cmdx/validators/length.rb +14 -0
- data/lib/cmdx/validators/numeric.rb +14 -0
- data/lib/cmdx/validators/presence.rb +2 -0
- data/lib/cmdx/version.rb +4 -1
- data/lib/cmdx/workflow.rb +10 -0
- data/lib/cmdx.rb +9 -0
- data/lib/generators/cmdx/locale_generator.rb +0 -1
- data/lib/generators/cmdx/templates/install.rb +9 -0
- data/mkdocs.yml +122 -0
- data/src/cmdx-dark-logo.png +0 -0
- data/src/cmdx-favicon.svg +1 -0
- data/src/cmdx-light-logo.png +0 -0
- data/src/cmdx-logo.svg +1 -0
- metadata +14 -3
- data/lib/cmdx/freezer.rb +0 -51
- data/src/cmdx-logo.png +0 -0
    
        data/docs/basics/context.md
    CHANGED
    
    | @@ -1,17 +1,10 @@ | |
| 1 1 | 
             
            # Basics - Context
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 5 | 
            -
            ## Table of Contents
         | 
| 6 | 
            -
             | 
| 7 | 
            -
            - [Assigning Data](#assigning-data)
         | 
| 8 | 
            -
            - [Accessing Data](#accessing-data)
         | 
| 9 | 
            -
            - [Modifying Context](#modifying-context)
         | 
| 10 | 
            -
            - [Data Sharing](#data-sharing)
         | 
| 3 | 
            +
            Context is your data container for inputs, intermediate values, and outputs. It makes sharing data between tasks effortless.
         | 
| 11 4 |  | 
| 12 5 | 
             
            ## Assigning Data
         | 
| 13 6 |  | 
| 14 | 
            -
            Context  | 
| 7 | 
            +
            Context automatically captures all task inputs, normalizing keys to symbols:
         | 
| 15 8 |  | 
| 16 9 | 
             
            ```ruby
         | 
| 17 10 | 
             
            # Direct execution
         | 
| @@ -21,12 +14,13 @@ CalculateShipping.execute(weight: 2.5, destination: "CA") | |
| 21 14 | 
             
            CalculateShipping.new(weight: 2.5, "destination" => "CA")
         | 
| 22 15 | 
             
            ```
         | 
| 23 16 |  | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 17 | 
            +
            !!! warning "Important"
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                String keys convert to symbols automatically. Prefer symbols for consistency.
         | 
| 26 20 |  | 
| 27 21 | 
             
            ## Accessing Data
         | 
| 28 22 |  | 
| 29 | 
            -
             | 
| 23 | 
            +
            Access context data using method notation, hash keys, or safe accessors:
         | 
| 30 24 |  | 
| 31 25 | 
             
            ```ruby
         | 
| 32 26 | 
             
            class CalculateShipping < CMDx::Task
         | 
| @@ -49,8 +43,9 @@ class CalculateShipping < CMDx::Task | |
| 49 43 | 
             
            end
         | 
| 50 44 | 
             
            ```
         | 
| 51 45 |  | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 46 | 
            +
            !!! warning "Important"
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                Undefined attributes return `nil` instead of raising errors—perfect for optional data.
         | 
| 54 49 |  | 
| 55 50 | 
             
            ## Modifying Context
         | 
| 56 51 |  | 
| @@ -91,12 +86,13 @@ class CalculateShipping < CMDx::Task | |
| 91 86 | 
             
            end
         | 
| 92 87 | 
             
            ```
         | 
| 93 88 |  | 
| 94 | 
            -
             | 
| 95 | 
            -
             | 
| 89 | 
            +
            !!! tip
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                Use context for both input values and intermediate results. This creates natural data flow through your task execution pipeline.
         | 
| 96 92 |  | 
| 97 93 | 
             
            ## Data Sharing
         | 
| 98 94 |  | 
| 99 | 
            -
             | 
| 95 | 
            +
            Share context across tasks for seamless data flow:
         | 
| 100 96 |  | 
| 101 97 | 
             
            ```ruby
         | 
| 102 98 | 
             
            # During execution
         | 
| @@ -123,8 +119,3 @@ result = CalculateShipping.execute(destination: "New York, NY") | |
| 123 119 |  | 
| 124 120 | 
             
            CreateShippingLabel.execute(result)
         | 
| 125 121 | 
             
            ```
         | 
| 126 | 
            -
             | 
| 127 | 
            -
            ---
         | 
| 128 | 
            -
             | 
| 129 | 
            -
            - **Prev:** [Basics - Execution](execution.md)
         | 
| 130 | 
            -
            - **Next:** [Basics - Chain](chain.md)
         | 
    
        data/docs/basics/execution.md
    CHANGED
    
    | @@ -1,19 +1,10 @@ | |
| 1 1 | 
             
            # Basics - Execution
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 3 | 
            +
            CMDx offers two execution methods with different error handling approaches. Choose based on your needs: safe result handling or exception-based control flow.
         | 
| 4 4 |  | 
| 5 | 
            -
            ##  | 
| 5 | 
            +
            ## Execution Methods
         | 
| 6 6 |  | 
| 7 | 
            -
             | 
| 8 | 
            -
            - [Non-bang Execution](#non-bang-execution)
         | 
| 9 | 
            -
            - [Bang Execution](#bang-execution)
         | 
| 10 | 
            -
            - [Direct Instantiation](#direct-instantiation)
         | 
| 11 | 
            -
            - [Result Details](#result-details)
         | 
| 12 | 
            -
             | 
| 13 | 
            -
            ## Methods Overview
         | 
| 14 | 
            -
             | 
| 15 | 
            -
            Tasks are single-use objects. Once executed, they are frozen and cannot be executed again.
         | 
| 16 | 
            -
            Create a new instance for subsequent executions.
         | 
| 7 | 
            +
            Both methods return results, but handle failures differently:
         | 
| 17 8 |  | 
| 18 9 | 
             
            | Method | Returns | Exceptions | Use Case |
         | 
| 19 10 | 
             
            |--------|---------|------------|----------|
         | 
| @@ -22,10 +13,7 @@ Create a new instance for subsequent executions. | |
| 22 13 |  | 
| 23 14 | 
             
            ## Non-bang Execution
         | 
| 24 15 |  | 
| 25 | 
            -
             | 
| 26 | 
            -
            This is the preferred method for most use cases.
         | 
| 27 | 
            -
             | 
| 28 | 
            -
            Any unhandled exceptions will be caught and returned as a task failure.
         | 
| 16 | 
            +
            Always returns a `CMDx::Result`, never raises exceptions. Perfect for most use cases.
         | 
| 29 17 |  | 
| 30 18 | 
             
            ```ruby
         | 
| 31 19 | 
             
            result = CreateAccount.execute(email: "user@example.com")
         | 
| @@ -43,17 +31,16 @@ result.status           #=> "success" | |
| 43 31 |  | 
| 44 32 | 
             
            ## Bang Execution
         | 
| 45 33 |  | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 48 | 
            -
            It raises any unhandled non-fault exceptions caused during execution.
         | 
| 34 | 
            +
            Raises `CMDx::Fault` exceptions on failure or skip. Returns results only on success.
         | 
| 49 35 |  | 
| 50 36 | 
             
            | Exception | Raised When |
         | 
| 51 37 | 
             
            |-----------|-------------|
         | 
| 52 38 | 
             
            | `CMDx::FailFault` | Task execution fails |
         | 
| 53 39 | 
             
            | `CMDx::SkipFault` | Task execution is skipped |
         | 
| 54 40 |  | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 41 | 
            +
            !!! warning "Important"
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                Behavior depends on `task_breakpoints` or `workflow_breakpoints` config. Default: only failures raise exceptions.
         | 
| 57 44 |  | 
| 58 45 | 
             
            ```ruby
         | 
| 59 46 | 
             
            begin
         | 
| @@ -107,8 +94,3 @@ result.chain        #=> Task execution chain | |
| 107 94 | 
             
            result.context      #=> Context with all task data
         | 
| 108 95 | 
             
            result.metadata     #=> Hash with execution metadata
         | 
| 109 96 | 
             
            ```
         | 
| 110 | 
            -
             | 
| 111 | 
            -
            ---
         | 
| 112 | 
            -
             | 
| 113 | 
            -
            - **Prev:** [Basics - Setup](setup.md)
         | 
| 114 | 
            -
            - **Next:** [Basics - Context](context.md)
         | 
    
        data/docs/basics/setup.md
    CHANGED
    
    | @@ -1,16 +1,10 @@ | |
| 1 1 | 
             
            # Basics - Setup
         | 
| 2 2 |  | 
| 3 | 
            -
            Tasks are the  | 
| 4 | 
            -
             | 
| 5 | 
            -
            ## Table of Contents
         | 
| 6 | 
            -
             | 
| 7 | 
            -
            - [Structure](#structure)
         | 
| 8 | 
            -
            - [Inheritance](#inheritance)
         | 
| 9 | 
            -
            - [Lifecycle](#lifecycle)
         | 
| 3 | 
            +
            Tasks are the heart of CMDx—self-contained units of business logic with built-in validation, error handling, and execution tracking.
         | 
| 10 4 |  | 
| 11 5 | 
             
            ## Structure
         | 
| 12 6 |  | 
| 13 | 
            -
            Tasks inherit from `CMDx::Task` and  | 
| 7 | 
            +
            Tasks need only two things: inherit from `CMDx::Task` and define a `work` method:
         | 
| 14 8 |  | 
| 15 9 | 
             
            ```ruby
         | 
| 16 10 | 
             
            class ValidateDocument < CMDx::Task
         | 
| @@ -20,7 +14,7 @@ class ValidateDocument < CMDx::Task | |
| 20 14 | 
             
            end
         | 
| 21 15 | 
             
            ```
         | 
| 22 16 |  | 
| 23 | 
            -
             | 
| 17 | 
            +
            Without a `work` method, execution raises `CMDx::UndefinedMethodError`.
         | 
| 24 18 |  | 
| 25 19 | 
             
            ```ruby
         | 
| 26 20 | 
             
            class IncompleteTask < CMDx::Task
         | 
| @@ -32,8 +26,7 @@ IncompleteTask.execute #=> raises CMDx::UndefinedMethodError | |
| 32 26 |  | 
| 33 27 | 
             
            ## Inheritance
         | 
| 34 28 |  | 
| 35 | 
            -
             | 
| 36 | 
            -
            Create a base class to share common configuration across tasks:
         | 
| 29 | 
            +
            Share configuration across tasks using inheritance:
         | 
| 37 30 |  | 
| 38 31 | 
             
            ```ruby
         | 
| 39 32 | 
             
            class ApplicationTask < CMDx::Task
         | 
| @@ -59,10 +52,11 @@ end | |
| 59 52 |  | 
| 60 53 | 
             
            ## Lifecycle
         | 
| 61 54 |  | 
| 62 | 
            -
            Tasks follow a predictable  | 
| 55 | 
            +
            Tasks follow a predictable execution pattern:
         | 
| 56 | 
            +
             | 
| 57 | 
            +
            !!! danger "Caution"
         | 
| 63 58 |  | 
| 64 | 
            -
             | 
| 65 | 
            -
            > Tasks are single-use objects. Once executed, they are frozen and cannot be executed again.
         | 
| 59 | 
            +
                Tasks are single-use objects. Once executed, they're frozen and immutable.
         | 
| 66 60 |  | 
| 67 61 | 
             
            | Stage | State | Status | Description |
         | 
| 68 62 | 
             
            |-------|-------|--------|-------------|
         | 
| @@ -71,8 +65,3 @@ Tasks follow a predictable call pattern with specific states and statuses: | |
| 71 65 | 
             
            | **Execution** | `executing` | `success`/`failed`/`skipped` | `work` method runs |
         | 
| 72 66 | 
             
            | **Completion** | `executed` | `success`/`failed`/`skipped` | Result finalized |
         | 
| 73 67 | 
             
            | **Freezing** | `executed` | `success`/`failed`/`skipped` | Task becomes immutable |
         | 
| 74 | 
            -
             | 
| 75 | 
            -
            ---
         | 
| 76 | 
            -
             | 
| 77 | 
            -
            - **Prev:** [Getting Started](../getting_started.md)
         | 
| 78 | 
            -
            - **Next:** [Basics - Execution](execution.md)
         | 
    
        data/docs/callbacks.md
    CHANGED
    
    | @@ -1,36 +1,27 @@ | |
| 1 1 | 
             
            # Callbacks
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 3 | 
            +
            Run custom logic at specific points during task execution. Callbacks have full access to task context and results, making them perfect for logging, notifications, cleanup, and more.
         | 
| 4 4 |  | 
| 5 | 
            -
             | 
| 5 | 
            +
            See [Global Configuration](getting_started.md#callbacks) for framework-wide callback setup.
         | 
| 6 6 |  | 
| 7 | 
            -
             | 
| 8 | 
            -
            > Callbacks execute in the order they are declared within each hook type. Multiple callbacks of the same type execute in declaration order (FIFO: first in, first out).
         | 
| 7 | 
            +
            !!! warning "Important"
         | 
| 9 8 |  | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
            - [Available Callbacks](#available-callbacks)
         | 
| 13 | 
            -
            - [Declarations](#declarations)
         | 
| 14 | 
            -
              - [Symbol References](#symbol-references)
         | 
| 15 | 
            -
              - [Proc or Lambda](#proc-or-lambda)
         | 
| 16 | 
            -
              - [Class or Module](#class-or-module)
         | 
| 17 | 
            -
              - [Conditional Execution](#conditional-execution)
         | 
| 18 | 
            -
            - [Callback Removal](#callback-removal)
         | 
| 9 | 
            +
                Callbacks execute in declaration order (FIFO). Multiple callbacks of the same type run sequentially.
         | 
| 19 10 |  | 
| 20 11 | 
             
            ## Available Callbacks
         | 
| 21 12 |  | 
| 22 | 
            -
            Callbacks execute in  | 
| 13 | 
            +
            Callbacks execute in a predictable lifecycle order:
         | 
| 23 14 |  | 
| 24 15 | 
             
            ```ruby
         | 
| 25 16 | 
             
            1. before_validation           # Pre-validation setup
         | 
| 26 | 
            -
            2. before_execution            #  | 
| 17 | 
            +
            2. before_execution            # Prepare for execution
         | 
| 27 18 |  | 
| 28 | 
            -
            # --- Task#work  | 
| 19 | 
            +
            # --- Task#work executes ---
         | 
| 29 20 |  | 
| 30 | 
            -
            3. on_[complete|interrupted]   #  | 
| 31 | 
            -
            4. on_executed                 #  | 
| 32 | 
            -
            5. on_[success|skipped|failed] #  | 
| 33 | 
            -
            6. on_[good|bad]               #  | 
| 21 | 
            +
            3. on_[complete|interrupted]   # State-based (execution lifecycle)
         | 
| 22 | 
            +
            4. on_executed                 # Always runs after work completes
         | 
| 23 | 
            +
            5. on_[success|skipped|failed] # Status-based (business outcome)
         | 
| 24 | 
            +
            6. on_[good|bad]               # Outcome-based (success/skip vs fail)
         | 
| 34 25 | 
             
            ```
         | 
| 35 26 |  | 
| 36 27 | 
             
            ## Declarations
         | 
| @@ -73,7 +64,7 @@ Use anonymous functions for inline callback logic: | |
| 73 64 | 
             
            ```ruby
         | 
| 74 65 | 
             
            class ProcessBooking < CMDx::Task
         | 
| 75 66 | 
             
              # Proc
         | 
| 76 | 
            -
              on_interrupted proc {  | 
| 67 | 
            +
              on_interrupted proc { ReservationSystem.pause! }
         | 
| 77 68 |  | 
| 78 69 | 
             
              # Lambda
         | 
| 79 70 | 
             
              on_complete -> { ReservationSystem.resume! }
         | 
| @@ -120,10 +111,10 @@ class ProcessBooking < CMDx::Task | |
| 120 111 | 
             
              before_execution :notify_guest, if: :messaging_enabled?, unless: :messaging_blocked?
         | 
| 121 112 |  | 
| 122 113 | 
             
              # Proc
         | 
| 123 | 
            -
              on_failure :increment_failure, if: -> | 
| 114 | 
            +
              on_failure :increment_failure, if: -> { Rails.env.production? && self.class.name.include?("Legacy") }
         | 
| 124 115 |  | 
| 125 116 | 
             
              # Lambda
         | 
| 126 | 
            -
              on_success :ping_housekeeping, if: proc {  | 
| 117 | 
            +
              on_success :ping_housekeeping, if: proc { context.rooms_need_cleaning? }
         | 
| 127 118 |  | 
| 128 119 | 
             
              # Class or Module
         | 
| 129 120 | 
             
              on_complete :send_confirmation, unless: MessagingPermissionCheck
         | 
| @@ -138,7 +129,7 @@ class ProcessBooking < CMDx::Task | |
| 138 129 | 
             
              private
         | 
| 139 130 |  | 
| 140 131 | 
             
              def messaging_enabled?
         | 
| 141 | 
            -
                context.guest.messaging_preference | 
| 132 | 
            +
                context.guest.messaging_preference == true
         | 
| 142 133 | 
             
              end
         | 
| 143 134 |  | 
| 144 135 | 
             
              def messaging_blocked?
         | 
| @@ -149,10 +140,11 @@ end | |
| 149 140 |  | 
| 150 141 | 
             
            ## Callback Removal
         | 
| 151 142 |  | 
| 152 | 
            -
            Remove callbacks  | 
| 143 | 
            +
            Remove unwanted callbacks dynamically:
         | 
| 144 | 
            +
             | 
| 145 | 
            +
            !!! warning "Important"
         | 
| 153 146 |  | 
| 154 | 
            -
             | 
| 155 | 
            -
            > Only one removal operation is allowed per `deregister` call. Multiple removals require separate calls.
         | 
| 147 | 
            +
                Each `deregister` call removes one callback. Use multiple calls for batch removals.
         | 
| 156 148 |  | 
| 157 149 | 
             
            ```ruby
         | 
| 158 150 | 
             
            class ProcessBooking < CMDx::Task
         | 
| @@ -163,8 +155,3 @@ class ProcessBooking < CMDx::Task | |
| 163 155 | 
             
              deregister :callback, :on_complete, BookingConfirmationCallback
         | 
| 164 156 | 
             
            end
         | 
| 165 157 | 
             
            ```
         | 
| 166 | 
            -
             | 
| 167 | 
            -
            ---
         | 
| 168 | 
            -
             | 
| 169 | 
            -
            - **Prev:** [Attributes - Defaults](attributes/defaults.md)
         | 
| 170 | 
            -
            - **Next:** [Middlewares](middlewares.md)
         | 
    
        data/docs/deprecation.md
    CHANGED
    
    | @@ -1,28 +1,16 @@ | |
| 1 1 | 
             
            # Task Deprecation
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 5 | 
            -
            ## Table of Contents
         | 
| 6 | 
            -
             | 
| 7 | 
            -
            - [Modes](#modes)
         | 
| 8 | 
            -
              - [Raise](#raise)
         | 
| 9 | 
            -
              - [Log](#log)
         | 
| 10 | 
            -
              - [Warn](#warn)
         | 
| 11 | 
            -
            - [Declarations](#declarations)
         | 
| 12 | 
            -
              - [Symbol or String](#symbol-or-string)
         | 
| 13 | 
            -
              - [Boolean or Nil](#boolean-or-nil)
         | 
| 14 | 
            -
              - [Method](#method)
         | 
| 15 | 
            -
              - [Proc or Lambda](#proc-or-lambda)
         | 
| 16 | 
            -
              - [Class or Module](#class-or-module)
         | 
| 3 | 
            +
            Manage legacy tasks gracefully with built-in deprecation support. Choose how to handle deprecated tasks—log warnings for awareness, issue Ruby warnings for development, or prevent execution entirely.
         | 
| 17 4 |  | 
| 18 5 | 
             
            ## Modes
         | 
| 19 6 |  | 
| 20 7 | 
             
            ### Raise
         | 
| 21 8 |  | 
| 22 | 
            -
             | 
| 9 | 
            +
            Prevent task execution completely. Perfect for tasks that must no longer run.
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            !!! warning
         | 
| 23 12 |  | 
| 24 | 
            -
             | 
| 25 | 
            -
            > Use `:raise` mode carefully in production environments as it will break existing workflows immediately.
         | 
| 13 | 
            +
                Use `:raise` mode carefully—it will break existing workflows immediately.
         | 
| 26 14 |  | 
| 27 15 | 
             
            ```ruby
         | 
| 28 16 | 
             
            class ProcessObsoleteAPI < CMDx::Task
         | 
| @@ -39,7 +27,7 @@ result = ProcessObsoleteAPI.execute | |
| 39 27 |  | 
| 40 28 | 
             
            ### Log
         | 
| 41 29 |  | 
| 42 | 
            -
             | 
| 30 | 
            +
            Allow execution while tracking deprecation in logs. Ideal for gradual migrations.
         | 
| 43 31 |  | 
| 44 32 | 
             
            ```ruby
         | 
| 45 33 | 
             
            class ProcessLegacyFormat < CMDx::Task
         | 
| @@ -62,7 +50,7 @@ result.successful? #=> true | |
| 62 50 |  | 
| 63 51 | 
             
            ### Warn
         | 
| 64 52 |  | 
| 65 | 
            -
             | 
| 53 | 
            +
            Issue Ruby warnings visible during development and testing. Keeps production logs clean while alerting developers.
         | 
| 66 54 |  | 
| 67 55 | 
             
            ```ruby
         | 
| 68 56 | 
             
            class ProcessOldData < CMDx::Task
         | 
| @@ -77,7 +65,7 @@ result = ProcessOldData.execute | |
| 77 65 | 
             
            result.successful? #=> true
         | 
| 78 66 |  | 
| 79 67 | 
             
            # Ruby warning appears in stderr:
         | 
| 80 | 
            -
            # [ProcessOldData] DEPRECATED: migrate to replacement or discontinue use
         | 
| 68 | 
            +
            # [ProcessOldData] DEPRECATED: migrate to a replacement or discontinue use
         | 
| 81 69 | 
             
            ```
         | 
| 82 70 |  | 
| 83 71 | 
             
            ## Declarations
         | 
| @@ -155,8 +143,3 @@ class OutdatedConnector < CMDx::Task | |
| 155 143 | 
             
              settings(deprecated: OutdatedTaskDeprecator.new)
         | 
| 156 144 | 
             
            end
         | 
| 157 145 | 
             
            ```
         | 
| 158 | 
            -
             | 
| 159 | 
            -
            ---
         | 
| 160 | 
            -
             | 
| 161 | 
            -
            - **Prev:** [Internationalization (i18n)](internationalization.md)
         | 
| 162 | 
            -
            - **Next:** [Workflows](workflows.md)
         | 
    
        data/docs/getting_started.md
    CHANGED
    
    | @@ -1,51 +1,33 @@ | |
| 1 1 | 
             
            # Getting Started
         | 
| 2 2 |  | 
| 3 | 
            -
            CMDx is a Ruby framework for building maintainable, observable business logic through composable command objects.  | 
| 4 | 
            -
             | 
| 5 | 
            -
            **Common  | 
| 6 | 
            -
             | 
| 7 | 
            -
            - Inconsistent patterns across  | 
| 8 | 
            -
            -  | 
| 9 | 
            -
            - Fragile  | 
| 10 | 
            -
             | 
| 11 | 
            -
            ** | 
| 12 | 
            -
             | 
| 13 | 
            -
            -  | 
| 14 | 
            -
            -  | 
| 15 | 
            -
            -  | 
| 16 | 
            -
            -  | 
| 17 | 
            -
            -  | 
| 18 | 
            -
            -  | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
              - [Coercions](#coercions)
         | 
| 32 | 
            -
              - [Validators](#validators)
         | 
| 33 | 
            -
            - [Task Configuration](#task-configuration)
         | 
| 34 | 
            -
              - [Settings](#settings)
         | 
| 35 | 
            -
              - [Registrations](#registrations)
         | 
| 36 | 
            -
            - [Configuration Management](#configuration-management)
         | 
| 37 | 
            -
              - [Access](#access)
         | 
| 38 | 
            -
              - [Resetting](#resetting)
         | 
| 39 | 
            -
            - [Task Generator](#task-generator)
         | 
| 40 | 
            -
             | 
| 41 | 
            -
            ## Compose, Execute, React, Observe pattern
         | 
| 42 | 
            -
             | 
| 43 | 
            -
            CMDx encourages breaking business logic into composable tasks. Each task can be combined into larger workflows, executed with standardized flow control, and fully observed through logging, validations, and context.
         | 
| 44 | 
            -
             | 
| 45 | 
            -
            - *Compose* → Define small, contract-driven tasks with typed attributes, validations, and natural workflow composition.
         | 
| 46 | 
            -
            - *Execute* → Run tasks with clear outcomes, intentional halts, and pluggable behaviors via middlewares and callbacks.
         | 
| 47 | 
            -
            - *React* → Adapt to outcomes by chaining follow-up tasks, handling faults, or shaping future flows.
         | 
| 48 | 
            -
            - *Observe* → Capture immutable results, structured logs, and full execution chains for reliable tracing and insight.
         | 
| 3 | 
            +
            CMDx is a Ruby framework for building maintainable, observable business logic through composable command objects. It brings structure, consistency, and powerful developer tools to your business processes.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            **Common challenges it solves:**
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            - Inconsistent service object patterns across your codebase
         | 
| 8 | 
            +
            - Limited logging makes debugging a nightmare
         | 
| 9 | 
            +
            - Fragile error handling erodes confidence
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            **What you get:**
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            - Consistent, standardized architecture
         | 
| 14 | 
            +
            - Built-in flow control and error handling
         | 
| 15 | 
            +
            - Composable, reusable workflows
         | 
| 16 | 
            +
            - Comprehensive logging for observability
         | 
| 17 | 
            +
            - Attribute validation with type coercions
         | 
| 18 | 
            +
            - Sensible defaults and developer-friendly APIs
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            ## The CERO Pattern
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            CMDx embraces the Compose, Execute, React, Observe (CERO) pattern—a simple yet powerful approach to building reliable business logic.
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            🧩 **Compose** — Define small, focused tasks with typed attributes and validations
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            ⚡ **Execute** — Run tasks with clear outcomes and pluggable behaviors
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            🔄 **React** — Adapt to outcomes by chaining follow-up tasks or handling faults
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            🔍 **Observe** — Capture structured logs and execution chains for debugging
         | 
| 49 31 |  | 
| 50 32 | 
             
            ## Installation
         | 
| 51 33 |  | 
| @@ -65,39 +47,78 @@ This creates `config/initializers/cmdx.rb` file. | |
| 65 47 |  | 
| 66 48 | 
             
            ## Configuration Hierarchy
         | 
| 67 49 |  | 
| 68 | 
            -
            CMDx  | 
| 50 | 
            +
            CMDx uses a straightforward two-tier configuration system:
         | 
| 69 51 |  | 
| 70 | 
            -
            1. **Global Configuration | 
| 71 | 
            -
            2. **Task Settings | 
| 52 | 
            +
            1. **Global Configuration** — Framework-wide defaults
         | 
| 53 | 
            +
            2. **Task Settings** — Class-level overrides using `settings`
         | 
| 72 54 |  | 
| 73 | 
            -
             | 
| 74 | 
            -
             | 
| 55 | 
            +
            !!! warning "Important"
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                Task settings take precedence over global config. Settings are inherited from parent classes and can be overridden in subclasses.
         | 
| 75 58 |  | 
| 76 59 | 
             
            ## Global Configuration
         | 
| 77 60 |  | 
| 78 | 
            -
             | 
| 79 | 
            -
            Globally these settings are initialized with sensible defaults.
         | 
| 61 | 
            +
            Configure framework-wide defaults that apply to all tasks. These settings come with sensible defaults out of the box.
         | 
| 80 62 |  | 
| 81 63 | 
             
            ### Breakpoints
         | 
| 82 64 |  | 
| 83 | 
            -
             | 
| 65 | 
            +
            Control when `execute!` raises a `CMDx::Fault` based on task status.
         | 
| 84 66 |  | 
| 85 67 | 
             
            ```ruby
         | 
| 86 68 | 
             
            CMDx.configure do |config|
         | 
| 87 | 
            -
              # String or Array[String]
         | 
| 88 | 
            -
              config.task_breakpoints = "failed"
         | 
| 69 | 
            +
              config.task_breakpoints = "failed" # String or Array[String]
         | 
| 89 70 | 
             
            end
         | 
| 90 71 | 
             
            ```
         | 
| 91 72 |  | 
| 92 | 
            -
             | 
| 73 | 
            +
            For workflows, configure which statuses halt the execution pipeline:
         | 
| 93 74 |  | 
| 94 75 | 
             
            ```ruby
         | 
| 95 76 | 
             
            CMDx.configure do |config|
         | 
| 96 | 
            -
              # String or Array[String]
         | 
| 97 77 | 
             
              config.workflow_breakpoints = ["skipped", "failed"]
         | 
| 98 78 | 
             
            end
         | 
| 99 79 | 
             
            ```
         | 
| 100 80 |  | 
| 81 | 
            +
            ### Backtraces
         | 
| 82 | 
            +
             | 
| 83 | 
            +
            Enable detailed backtraces for non-fault exceptions to improve debugging. Optionally clean up stack traces to remove framework noise.
         | 
| 84 | 
            +
             | 
| 85 | 
            +
            !!! note
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                In Rails environments, `backtrace_cleaner` defaults to `Rails.backtrace_cleaner.clean`.
         | 
| 88 | 
            +
             | 
| 89 | 
            +
            ```ruby
         | 
| 90 | 
            +
            CMDx.configure do |config|
         | 
| 91 | 
            +
              # Truthy
         | 
| 92 | 
            +
              config.backtrace = true
         | 
| 93 | 
            +
             | 
| 94 | 
            +
              # Via callable (must respond to `call(backtrace)`)
         | 
| 95 | 
            +
              config.backtrace_cleaner = AdvanceCleaner.new
         | 
| 96 | 
            +
             | 
| 97 | 
            +
              # Via proc or lambda
         | 
| 98 | 
            +
              config.backtrace_cleaner = ->(backtrace) { backtrace[0..5] }
         | 
| 99 | 
            +
            end
         | 
| 100 | 
            +
            ```
         | 
| 101 | 
            +
             | 
| 102 | 
            +
            ### Exception Handlers
         | 
| 103 | 
            +
             | 
| 104 | 
            +
            Register handlers that run when non-fault exceptions occur.
         | 
| 105 | 
            +
             | 
| 106 | 
            +
            !!! tip
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                Use exception handlers to send errors to your APM of choice.
         | 
| 109 | 
            +
             | 
| 110 | 
            +
            ```ruby
         | 
| 111 | 
            +
            CMDx.configure do |config|
         | 
| 112 | 
            +
              # Via callable (must respond to `call(task, exception)`)
         | 
| 113 | 
            +
              config.exception_handler = NewRelicReporter
         | 
| 114 | 
            +
             | 
| 115 | 
            +
              # Via proc or lambda
         | 
| 116 | 
            +
              config.exception_handler = proc do |task, exception|
         | 
| 117 | 
            +
                APMService.report(exception, extra_data: { task: task.name, id: task.id })
         | 
| 118 | 
            +
              end
         | 
| 119 | 
            +
            end
         | 
| 120 | 
            +
            ```
         | 
| 121 | 
            +
             | 
| 101 122 | 
             
            ### Logging
         | 
| 102 123 |  | 
| 103 124 | 
             
            ```ruby
         | 
| @@ -108,7 +129,7 @@ end | |
| 108 129 |  | 
| 109 130 | 
             
            ### Middlewares
         | 
| 110 131 |  | 
| 111 | 
            -
            See the [ | 
| 132 | 
            +
            See the [Middlewares](middlewares.md#declarations) docs for task level configurations.
         | 
| 112 133 |  | 
| 113 134 | 
             
            ```ruby
         | 
| 114 135 | 
             
            CMDx.configure do |config|
         | 
| @@ -132,12 +153,13 @@ CMDx.configure do |config| | |
| 132 153 | 
             
            end
         | 
| 133 154 | 
             
            ```
         | 
| 134 155 |  | 
| 135 | 
            -
             | 
| 136 | 
            -
             | 
| 156 | 
            +
            !!! note
         | 
| 157 | 
            +
             | 
| 158 | 
            +
                Middlewares are executed in registration order. Each middleware wraps the next, creating an execution chain around task logic.
         | 
| 137 159 |  | 
| 138 160 | 
             
            ### Callbacks
         | 
| 139 161 |  | 
| 140 | 
            -
            See the [Callbacks]( | 
| 162 | 
            +
            See the [Callbacks](callbacks.md#declarations) docs for task level configurations.
         | 
| 141 163 |  | 
| 142 164 | 
             
            ```ruby
         | 
| 143 165 | 
             
            CMDx.configure do |config|
         | 
| @@ -163,7 +185,7 @@ end | |
| 163 185 |  | 
| 164 186 | 
             
            ### Coercions
         | 
| 165 187 |  | 
| 166 | 
            -
            See the [Attributes - Coercions]( | 
| 188 | 
            +
            See the [Attributes - Coercions](attributes/coercions.md#declarations) docs for task level configurations.
         | 
| 167 189 |  | 
| 168 190 | 
             
            ```ruby
         | 
| 169 191 | 
             
            CMDx.configure do |config|
         | 
| @@ -189,7 +211,7 @@ end | |
| 189 211 |  | 
| 190 212 | 
             
            ### Validators
         | 
| 191 213 |  | 
| 192 | 
            -
            See the [Attributes - Validations]( | 
| 214 | 
            +
            See the [Attributes - Validations](attributes/validations.md#declarations) docs for task level configurations.
         | 
| 193 215 |  | 
| 194 216 | 
             
            ```ruby
         | 
| 195 217 | 
             
            CMDx.configure do |config|
         | 
| @@ -224,6 +246,8 @@ class GenerateInvoice < CMDx::Task | |
| 224 246 | 
             
                # Global configuration overrides
         | 
| 225 247 | 
             
                task_breakpoints: ["failed"],                # Breakpoint override
         | 
| 226 248 | 
             
                workflow_breakpoints: [],                    # Breakpoint override
         | 
| 249 | 
            +
                backtrace: true,                             # Toggle backtrace
         | 
| 250 | 
            +
                backtrace_cleaner: ->(bt) { bt[0..5] },      # Backtrace cleaner
         | 
| 227 251 | 
             
                logger: CustomLogger.new($stdout),           # Custom logger
         | 
| 228 252 |  | 
| 229 253 | 
             
                # Task configuration settings
         | 
| @@ -231,7 +255,10 @@ class GenerateInvoice < CMDx::Task | |
| 231 255 | 
             
                log_level: :info,                            # Log level override
         | 
| 232 256 | 
             
                log_formatter: CMDx::LogFormatters::Json.new # Log formatter override
         | 
| 233 257 | 
             
                tags: ["billing", "financial"],              # Logging tags
         | 
| 234 | 
            -
                deprecated: true | 
| 258 | 
            +
                deprecated: true,                            # Task deprecations
         | 
| 259 | 
            +
                retries: 3,                                  # Non-fault exception retries
         | 
| 260 | 
            +
                retry_on: [External::ApiError],              # List of exceptions to retry on
         | 
| 261 | 
            +
                retry_jitter: 1                              # Space between retry iteration, eg: current retry num + 1
         | 
| 235 262 | 
             
              )
         | 
| 236 263 |  | 
| 237 264 | 
             
              def work
         | 
| @@ -240,13 +267,13 @@ class GenerateInvoice < CMDx::Task | |
| 240 267 | 
             
            end
         | 
| 241 268 | 
             
            ```
         | 
| 242 269 |  | 
| 243 | 
            -
             | 
| 244 | 
            -
             | 
| 270 | 
            +
            !!! warning "Important"
         | 
| 271 | 
            +
             | 
| 272 | 
            +
                Retries reuse the same context. By default, all `StandardError` exceptions are retried unless you specify `retry_on`.
         | 
| 245 273 |  | 
| 246 274 | 
             
            ### Registrations
         | 
| 247 275 |  | 
| 248 | 
            -
            Register middlewares, callbacks, coercions, and validators  | 
| 249 | 
            -
            Deregister options that should not be available.
         | 
| 276 | 
            +
            Register or deregister middlewares, callbacks, coercions, and validators for specific tasks:
         | 
| 250 277 |  | 
| 251 278 | 
             
            ```ruby
         | 
| 252 279 | 
             
            class SendCampaignEmail < CMDx::Task
         | 
| @@ -298,8 +325,9 @@ end | |
| 298 325 |  | 
| 299 326 | 
             
            ### Resetting
         | 
| 300 327 |  | 
| 301 | 
            -
             | 
| 302 | 
            -
             | 
| 328 | 
            +
            !!! warning
         | 
| 329 | 
            +
             | 
| 330 | 
            +
                Resetting affects your entire application. Use this primarily in test environments.
         | 
| 303 331 |  | 
| 304 332 | 
             
            ```ruby
         | 
| 305 333 | 
             
            # Reset to framework defaults
         | 
| @@ -336,10 +364,15 @@ class ModerateBlogPost < CMDx::Task | |
| 336 364 | 
             
            end
         | 
| 337 365 | 
             
            ```
         | 
| 338 366 |  | 
| 339 | 
            -
             | 
| 340 | 
            -
             | 
| 367 | 
            +
            !!! tip
         | 
| 368 | 
            +
             | 
| 369 | 
            +
                Use **present tense verbs + noun** for task names, eg: `ModerateBlogPost`, `ScheduleAppointment`, `ValidateDocument`
         | 
| 370 | 
            +
             | 
| 371 | 
            +
            ## Type safety
         | 
| 341 372 |  | 
| 342 | 
            -
             | 
| 373 | 
            +
            CMDx includes built-in RBS (Ruby Type Signature) inline annotations throughout the codebase, providing type information for static analysis and editor support.
         | 
| 343 374 |  | 
| 344 | 
            -
            - ** | 
| 345 | 
            -
            - ** | 
| 375 | 
            +
            - **Type checking** — Catch type errors before runtime using tools like Steep or TypeProf
         | 
| 376 | 
            +
            - **Better IDE support** — Enhanced autocomplete, navigation, and inline documentation
         | 
| 377 | 
            +
            - **Self-documenting code** — Clear method signatures and return types
         | 
| 378 | 
            +
            - **Refactoring confidence** — Type-aware refactoring reduces bugs
         |