cmdx 1.9.0 → 1.10.0
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/.cursor/prompts/llms.md +3 -13
- data/.cursor/prompts/yardoc.md +1 -0
- data/CHANGELOG.md +16 -0
- data/LLM.md +436 -374
- data/README.md +7 -2
- data/docs/basics/setup.md +17 -0
- data/docs/callbacks.md +1 -1
- data/docs/getting_started.md +22 -2
- data/docs/index.md +13 -1
- data/docs/retries.md +121 -0
- data/docs/tips_and_tricks.md +2 -1
- data/examples/stoplight_circuit_breaker.md +36 -0
- data/lib/cmdx/attribute.rb +82 -1
- data/lib/cmdx/attribute_registry.rb +20 -0
- data/lib/cmdx/attribute_value.rb +25 -0
- data/lib/cmdx/callback_registry.rb +19 -0
- 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 +2 -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 +126 -3
- data/lib/cmdx/context.rb +36 -0
- data/lib/cmdx/deprecator.rb +3 -0
- data/lib/cmdx/errors.rb +22 -0
- data/lib/cmdx/executor.rb +71 -11
- 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 +20 -1
- data/lib/cmdx/railtie.rb +4 -0
- data/lib/cmdx/result.rb +123 -1
- data/lib/cmdx/task.rb +91 -1
- 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 +8 -0
- data/lib/generators/cmdx/locale_generator.rb +0 -1
- data/mkdocs.yml +3 -1
- metadata +3 -1
    
        data/LLM.md
    CHANGED
    
    | @@ -1,40 +1,33 @@ | |
| 1 | 
            -
            #  | 
| 2 | 
            -
             | 
| 3 | 
            -
            This file contains all the CMDx documentation consolidated from the docs directory.
         | 
| 1 | 
            +
            # Getting Started
         | 
| 4 2 |  | 
| 5 | 
            -
             | 
| 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.
         | 
| 6 4 |  | 
| 7 | 
            -
             | 
| 8 | 
            -
            ---
         | 
| 5 | 
            +
            **Common challenges it solves:**
         | 
| 9 6 |  | 
| 10 | 
            -
             | 
| 7 | 
            +
            - Inconsistent service object patterns across your codebase
         | 
| 8 | 
            +
            - Limited logging makes debugging a nightmare
         | 
| 9 | 
            +
            - Fragile error handling erodes confidence
         | 
| 11 10 |  | 
| 12 | 
            -
             | 
| 11 | 
            +
            **What you get:**
         | 
| 13 12 |  | 
| 14 | 
            -
             | 
| 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
         | 
| 15 19 |  | 
| 16 | 
            -
             | 
| 17 | 
            -
            - Minimal or no logging, making debugging painful
         | 
| 18 | 
            -
            - Fragile designs that erode developer confidence
         | 
| 20 | 
            +
            ## The CERO Pattern
         | 
| 19 21 |  | 
| 20 | 
            -
             | 
| 22 | 
            +
            CMDx embraces the Compose, Execute, React, Observe (CERO) pattern—a simple yet powerful approach to building reliable business logic.
         | 
| 21 23 |  | 
| 22 | 
            -
             | 
| 23 | 
            -
            - Provides flow control and error handling
         | 
| 24 | 
            -
            - Supports composable, reusable workflows
         | 
| 25 | 
            -
            - Includes detailed logging for observability
         | 
| 26 | 
            -
            - Defines input attributes with fallback defaults
         | 
| 27 | 
            -
            - Adds validations and type coercions
         | 
| 28 | 
            -
            - Plus many other developer-friendly tools
         | 
| 24 | 
            +
            🧩 **Compose** — Define small, focused tasks with typed attributes and validations
         | 
| 29 25 |  | 
| 30 | 
            -
             | 
| 26 | 
            +
            ⚡ **Execute** — Run tasks with clear outcomes and pluggable behaviors
         | 
| 31 27 |  | 
| 32 | 
            -
             | 
| 28 | 
            +
            🔄 **React** — Adapt to outcomes by chaining follow-up tasks or handling faults
         | 
| 33 29 |  | 
| 34 | 
            -
             | 
| 35 | 
            -
            - **Execute** → Run tasks with clear outcomes, intentional halts, and pluggable behaviors via middlewares and callbacks.
         | 
| 36 | 
            -
            - **React** → Adapt to outcomes by chaining follow-up tasks, handling faults, or shaping future flows.
         | 
| 37 | 
            -
            - **Observe** → Capture immutable results, structured logs, and full execution chains for reliable tracing and insight.
         | 
| 30 | 
            +
            🔍 **Observe** — Capture structured logs and execution chains for debugging
         | 
| 38 31 |  | 
| 39 32 | 
             
            ## Installation
         | 
| 40 33 |  | 
| @@ -54,45 +47,54 @@ This creates `config/initializers/cmdx.rb` file. | |
| 54 47 |  | 
| 55 48 | 
             
            ## Configuration Hierarchy
         | 
| 56 49 |  | 
| 57 | 
            -
            CMDx  | 
| 50 | 
            +
            CMDx uses a straightforward two-tier configuration system:
         | 
| 51 | 
            +
             | 
| 52 | 
            +
            1. **Global Configuration** — Framework-wide defaults
         | 
| 53 | 
            +
            2. **Task Settings** — Class-level overrides using `settings`
         | 
| 58 54 |  | 
| 59 | 
            -
             | 
| 60 | 
            -
            2. **Task Settings**: Class-level overrides via `settings`
         | 
| 55 | 
            +
            !!! warning "Important"
         | 
| 61 56 |  | 
| 62 | 
            -
             | 
| 63 | 
            -
            > Task-level settings take precedence over global configuration. Settings are inherited from superclasses and can be overridden in subclasses.
         | 
| 57 | 
            +
                Task settings take precedence over global config. Settings are inherited from parent classes and can be overridden in subclasses.
         | 
| 64 58 |  | 
| 65 59 | 
             
            ## Global Configuration
         | 
| 66 60 |  | 
| 67 | 
            -
             | 
| 68 | 
            -
            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.
         | 
| 69 62 |  | 
| 70 63 | 
             
            ### Breakpoints
         | 
| 71 64 |  | 
| 72 | 
            -
             | 
| 65 | 
            +
            Control when `execute!` raises a `CMDx::Fault` based on task status.
         | 
| 73 66 |  | 
| 74 67 | 
             
            ```ruby
         | 
| 75 68 | 
             
            CMDx.configure do |config|
         | 
| 76 | 
            -
              # String or Array[String]
         | 
| 77 | 
            -
              config.task_breakpoints = "failed"
         | 
| 69 | 
            +
              config.task_breakpoints = "failed" # String or Array[String]
         | 
| 78 70 | 
             
            end
         | 
| 79 71 | 
             
            ```
         | 
| 80 72 |  | 
| 81 | 
            -
             | 
| 73 | 
            +
            For workflows, configure which statuses halt the execution pipeline:
         | 
| 82 74 |  | 
| 83 75 | 
             
            ```ruby
         | 
| 84 76 | 
             
            CMDx.configure do |config|
         | 
| 85 | 
            -
              # String or Array[String]
         | 
| 86 77 | 
             
              config.workflow_breakpoints = ["skipped", "failed"]
         | 
| 87 78 | 
             
            end
         | 
| 88 79 | 
             
            ```
         | 
| 89 80 |  | 
| 81 | 
            +
            ### Rollback
         | 
| 82 | 
            +
             | 
| 83 | 
            +
            Control when a `rollback` of task execution is called.
         | 
| 84 | 
            +
             | 
| 85 | 
            +
            ```ruby
         | 
| 86 | 
            +
            CMDx.configure do |config|
         | 
| 87 | 
            +
              config.rollback_on = ["failed"] # String or Array[String]
         | 
| 88 | 
            +
            end
         | 
| 89 | 
            +
            ```
         | 
| 90 | 
            +
             | 
| 90 91 | 
             
            ### Backtraces
         | 
| 91 92 |  | 
| 92 | 
            -
            Enable backtraces  | 
| 93 | 
            +
            Enable detailed backtraces for non-fault exceptions to improve debugging. Optionally clean up stack traces to remove framework noise.
         | 
| 94 | 
            +
             | 
| 95 | 
            +
            !!! note
         | 
| 93 96 |  | 
| 94 | 
            -
             | 
| 95 | 
            -
            > The `backtrace_cleaner` is set to `Rails.backtrace_cleaner.clean` in a Rails env by default.
         | 
| 97 | 
            +
                In Rails environments, `backtrace_cleaner` defaults to `Rails.backtrace_cleaner.clean`.
         | 
| 96 98 |  | 
| 97 99 | 
             
            ```ruby
         | 
| 98 100 | 
             
            CMDx.configure do |config|
         | 
| @@ -109,10 +111,11 @@ end | |
| 109 111 |  | 
| 110 112 | 
             
            ### Exception Handlers
         | 
| 111 113 |  | 
| 112 | 
            -
             | 
| 114 | 
            +
            Register handlers that run when non-fault exceptions occur.
         | 
| 115 | 
            +
             | 
| 116 | 
            +
            !!! tip
         | 
| 113 117 |  | 
| 114 | 
            -
             | 
| 115 | 
            -
            > Use exception handlers to send errors to your APM of choice.
         | 
| 118 | 
            +
                Use exception handlers to send errors to your APM of choice.
         | 
| 116 119 |  | 
| 117 120 | 
             
            ```ruby
         | 
| 118 121 | 
             
            CMDx.configure do |config|
         | 
| @@ -136,7 +139,7 @@ end | |
| 136 139 |  | 
| 137 140 | 
             
            ### Middlewares
         | 
| 138 141 |  | 
| 139 | 
            -
            See the [ | 
| 142 | 
            +
            See the [Middlewares](https://github.com/drexed/cmdx/blob/main/docs/middlewares.md#declarations) docs for task level configurations.
         | 
| 140 143 |  | 
| 141 144 | 
             
            ```ruby
         | 
| 142 145 | 
             
            CMDx.configure do |config|
         | 
| @@ -160,12 +163,13 @@ CMDx.configure do |config| | |
| 160 163 | 
             
            end
         | 
| 161 164 | 
             
            ```
         | 
| 162 165 |  | 
| 163 | 
            -
             | 
| 164 | 
            -
             | 
| 166 | 
            +
            !!! note
         | 
| 167 | 
            +
             | 
| 168 | 
            +
                Middlewares are executed in registration order. Each middleware wraps the next, creating an execution chain around task logic.
         | 
| 165 169 |  | 
| 166 170 | 
             
            ### Callbacks
         | 
| 167 171 |  | 
| 168 | 
            -
            See the [Callbacks]( | 
| 172 | 
            +
            See the [Callbacks](https://github.com/drexed/cmdx/blob/main/docs/callbacks.md#declarations) docs for task level configurations.
         | 
| 169 173 |  | 
| 170 174 | 
             
            ```ruby
         | 
| 171 175 | 
             
            CMDx.configure do |config|
         | 
| @@ -191,7 +195,7 @@ end | |
| 191 195 |  | 
| 192 196 | 
             
            ### Coercions
         | 
| 193 197 |  | 
| 194 | 
            -
            See the [Attributes - Coercions]( | 
| 198 | 
            +
            See the [Attributes - Coercions](https://github.com/drexed/cmdx/blob/main/docs/attributes/coercions.md#declarations) docs for task level configurations.
         | 
| 195 199 |  | 
| 196 200 | 
             
            ```ruby
         | 
| 197 201 | 
             
            CMDx.configure do |config|
         | 
| @@ -217,7 +221,7 @@ end | |
| 217 221 |  | 
| 218 222 | 
             
            ### Validators
         | 
| 219 223 |  | 
| 220 | 
            -
            See the [Attributes - Validations]( | 
| 224 | 
            +
            See the [Attributes - Validations](https://github.com/drexed/cmdx/blob/main/docs/attributes/validations.md#declarations) docs for task level configurations.
         | 
| 221 225 |  | 
| 222 226 | 
             
            ```ruby
         | 
| 223 227 | 
             
            CMDx.configure do |config|
         | 
| @@ -264,7 +268,8 @@ class GenerateInvoice < CMDx::Task | |
| 264 268 | 
             
                deprecated: true,                            # Task deprecations
         | 
| 265 269 | 
             
                retries: 3,                                  # Non-fault exception retries
         | 
| 266 270 | 
             
                retry_on: [External::ApiError],              # List of exceptions to retry on
         | 
| 267 | 
            -
                retry_jitter: 1 | 
| 271 | 
            +
                retry_jitter: 1,                             # Space between retry iteration, eg: current retry num + 1
         | 
| 272 | 
            +
                rollback_on: ["failed", "skipped"],          # Rollback on override
         | 
| 268 273 | 
             
              )
         | 
| 269 274 |  | 
| 270 275 | 
             
              def work
         | 
| @@ -273,13 +278,13 @@ class GenerateInvoice < CMDx::Task | |
| 273 278 | 
             
            end
         | 
| 274 279 | 
             
            ```
         | 
| 275 280 |  | 
| 276 | 
            -
             | 
| 277 | 
            -
             | 
| 281 | 
            +
            !!! warning "Important"
         | 
| 282 | 
            +
             | 
| 283 | 
            +
                Retries reuse the same context. By default, all `StandardError` exceptions (including faults) are retried unless you specify `retry_on` option for specific matches.
         | 
| 278 284 |  | 
| 279 285 | 
             
            ### Registrations
         | 
| 280 286 |  | 
| 281 | 
            -
            Register middlewares, callbacks, coercions, and validators  | 
| 282 | 
            -
            Deregister options that should not be available.
         | 
| 287 | 
            +
            Register or deregister middlewares, callbacks, coercions, and validators for specific tasks:
         | 
| 283 288 |  | 
| 284 289 | 
             
            ```ruby
         | 
| 285 290 | 
             
            class SendCampaignEmail < CMDx::Task
         | 
| @@ -331,8 +336,9 @@ end | |
| 331 336 |  | 
| 332 337 | 
             
            ### Resetting
         | 
| 333 338 |  | 
| 334 | 
            -
             | 
| 335 | 
            -
             | 
| 339 | 
            +
            !!! warning
         | 
| 340 | 
            +
             | 
| 341 | 
            +
                Resetting affects your entire application. Use this primarily in test environments.
         | 
| 336 342 |  | 
| 337 343 | 
             
            ```ruby
         | 
| 338 344 | 
             
            # Reset to framework defaults
         | 
| @@ -369,21 +375,26 @@ class ModerateBlogPost < CMDx::Task | |
| 369 375 | 
             
            end
         | 
| 370 376 | 
             
            ```
         | 
| 371 377 |  | 
| 372 | 
            -
             | 
| 373 | 
            -
            > Use **present tense verbs + noun** for task names, eg: `ModerateBlogPost`, `ScheduleAppointment`, `ValidateDocument`
         | 
| 378 | 
            +
            !!! tip
         | 
| 374 379 |  | 
| 375 | 
            -
             | 
| 380 | 
            +
                Use **present tense verbs + noun** for task names, eg: `ModerateBlogPost`, `ScheduleAppointment`, `ValidateDocument`
         | 
| 376 381 |  | 
| 377 | 
            -
             | 
| 378 | 
            -
             | 
| 382 | 
            +
            ## Type safety
         | 
| 383 | 
            +
             | 
| 384 | 
            +
            CMDx includes built-in RBS (Ruby Type Signature) inline annotations throughout the codebase, providing type information for static analysis and editor support.
         | 
| 385 | 
            +
             | 
| 386 | 
            +
            - **Type checking** — Catch type errors before runtime using tools like Steep or TypeProf
         | 
| 387 | 
            +
            - **Better IDE support** — Enhanced autocomplete, navigation, and inline documentation
         | 
| 388 | 
            +
            - **Self-documenting code** — Clear method signatures and return types
         | 
| 389 | 
            +
            - **Refactoring confidence** — Type-aware refactoring reduces bugs
         | 
| 379 390 |  | 
| 380 391 | 
             
            # Basics - Setup
         | 
| 381 392 |  | 
| 382 | 
            -
            Tasks are the  | 
| 393 | 
            +
            Tasks are the heart of CMDx—self-contained units of business logic with built-in validation, error handling, and execution tracking.
         | 
| 383 394 |  | 
| 384 395 | 
             
            ## Structure
         | 
| 385 396 |  | 
| 386 | 
            -
            Tasks inherit from `CMDx::Task` and  | 
| 397 | 
            +
            Tasks need only two things: inherit from `CMDx::Task` and define a `work` method:
         | 
| 387 398 |  | 
| 388 399 | 
             
            ```ruby
         | 
| 389 400 | 
             
            class ValidateDocument < CMDx::Task
         | 
| @@ -393,7 +404,7 @@ class ValidateDocument < CMDx::Task | |
| 393 404 | 
             
            end
         | 
| 394 405 | 
             
            ```
         | 
| 395 406 |  | 
| 396 | 
            -
             | 
| 407 | 
            +
            Without a `work` method, execution raises `CMDx::UndefinedMethodError`.
         | 
| 397 408 |  | 
| 398 409 | 
             
            ```ruby
         | 
| 399 410 | 
             
            class IncompleteTask < CMDx::Task
         | 
| @@ -403,10 +414,25 @@ end | |
| 403 414 | 
             
            IncompleteTask.execute #=> raises CMDx::UndefinedMethodError
         | 
| 404 415 | 
             
            ```
         | 
| 405 416 |  | 
| 417 | 
            +
            ## Rollback
         | 
| 418 | 
            +
             | 
| 419 | 
            +
            Undo any operations linked to the given status, helping to restore a pristine state.
         | 
| 420 | 
            +
             | 
| 421 | 
            +
            ```ruby
         | 
| 422 | 
            +
            class ValidateDocument < CMDx::Task
         | 
| 423 | 
            +
              def work
         | 
| 424 | 
            +
                # Your logic here...
         | 
| 425 | 
            +
              end
         | 
| 426 | 
            +
             | 
| 427 | 
            +
              def rollback
         | 
| 428 | 
            +
                # Your undo logic...
         | 
| 429 | 
            +
              end
         | 
| 430 | 
            +
            end
         | 
| 431 | 
            +
            ```
         | 
| 432 | 
            +
             | 
| 406 433 | 
             
            ## Inheritance
         | 
| 407 434 |  | 
| 408 | 
            -
             | 
| 409 | 
            -
            Create a base class to share common configuration across tasks:
         | 
| 435 | 
            +
            Share configuration across tasks using inheritance:
         | 
| 410 436 |  | 
| 411 437 | 
             
            ```ruby
         | 
| 412 438 | 
             
            class ApplicationTask < CMDx::Task
         | 
| @@ -432,10 +458,11 @@ end | |
| 432 458 |  | 
| 433 459 | 
             
            ## Lifecycle
         | 
| 434 460 |  | 
| 435 | 
            -
            Tasks follow a predictable  | 
| 461 | 
            +
            Tasks follow a predictable execution pattern:
         | 
| 462 | 
            +
             | 
| 463 | 
            +
            !!! danger "Caution"
         | 
| 436 464 |  | 
| 437 | 
            -
             | 
| 438 | 
            -
            > Tasks are single-use objects. Once executed, they are frozen and cannot be executed again.
         | 
| 465 | 
            +
                Tasks are single-use objects. Once executed, they're frozen and immutable.
         | 
| 439 466 |  | 
| 440 467 | 
             
            | Stage | State | Status | Description |
         | 
| 441 468 | 
             
            |-------|-------|--------|-------------|
         | 
| @@ -444,20 +471,15 @@ Tasks follow a predictable call pattern with specific states and statuses: | |
| 444 471 | 
             
            | **Execution** | `executing` | `success`/`failed`/`skipped` | `work` method runs |
         | 
| 445 472 | 
             
            | **Completion** | `executed` | `success`/`failed`/`skipped` | Result finalized |
         | 
| 446 473 | 
             
            | **Freezing** | `executed` | `success`/`failed`/`skipped` | Task becomes immutable |
         | 
| 447 | 
            -
             | 
| 448 | 
            -
            ---
         | 
| 449 | 
            -
             | 
| 450 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/basics/execution.md
         | 
| 451 | 
            -
            ---
         | 
| 474 | 
            +
            | **Rollback** | `executed` | `failed`/`skipped` | Work undone |
         | 
| 452 475 |  | 
| 453 476 | 
             
            # Basics - Execution
         | 
| 454 477 |  | 
| 455 | 
            -
             | 
| 478 | 
            +
            CMDx offers two execution methods with different error handling approaches. Choose based on your needs: safe result handling or exception-based control flow.
         | 
| 456 479 |  | 
| 457 | 
            -
            ## Methods | 
| 480 | 
            +
            ## Execution Methods
         | 
| 458 481 |  | 
| 459 | 
            -
             | 
| 460 | 
            -
            Create a new instance for subsequent executions.
         | 
| 482 | 
            +
            Both methods return results, but handle failures differently:
         | 
| 461 483 |  | 
| 462 484 | 
             
            | Method | Returns | Exceptions | Use Case |
         | 
| 463 485 | 
             
            |--------|---------|------------|----------|
         | 
| @@ -466,10 +488,7 @@ Create a new instance for subsequent executions. | |
| 466 488 |  | 
| 467 489 | 
             
            ## Non-bang Execution
         | 
| 468 490 |  | 
| 469 | 
            -
             | 
| 470 | 
            -
            This is the preferred method for most use cases.
         | 
| 471 | 
            -
             | 
| 472 | 
            -
            Any unhandled exceptions will be caught and returned as a task failure.
         | 
| 491 | 
            +
            Always returns a `CMDx::Result`, never raises exceptions. Perfect for most use cases.
         | 
| 473 492 |  | 
| 474 493 | 
             
            ```ruby
         | 
| 475 494 | 
             
            result = CreateAccount.execute(email: "user@example.com")
         | 
| @@ -487,23 +506,22 @@ result.status           #=> "success" | |
| 487 506 |  | 
| 488 507 | 
             
            ## Bang Execution
         | 
| 489 508 |  | 
| 490 | 
            -
             | 
| 491 | 
            -
             | 
| 492 | 
            -
            It raises any unhandled non-fault exceptions caused during execution.
         | 
| 509 | 
            +
            Raises `CMDx::Fault` exceptions on failure or skip. Returns results only on success.
         | 
| 493 510 |  | 
| 494 511 | 
             
            | Exception | Raised When |
         | 
| 495 512 | 
             
            |-----------|-------------|
         | 
| 496 513 | 
             
            | `CMDx::FailFault` | Task execution fails |
         | 
| 497 514 | 
             
            | `CMDx::SkipFault` | Task execution is skipped |
         | 
| 498 515 |  | 
| 499 | 
            -
             | 
| 500 | 
            -
             | 
| 516 | 
            +
            !!! warning "Important"
         | 
| 517 | 
            +
             | 
| 518 | 
            +
                Behavior depends on `task_breakpoints` or `workflow_breakpoints` config. Default: only failures raise exceptions.
         | 
| 501 519 |  | 
| 502 520 | 
             
            ```ruby
         | 
| 503 521 | 
             
            begin
         | 
| 504 522 | 
             
              result = CreateAccount.execute!(email: "user@example.com")
         | 
| 505 523 | 
             
              SendWelcomeEmail.execute(result.context)
         | 
| 506 | 
            -
            rescue CMDx:: | 
| 524 | 
            +
            rescue CMDx::FailFault => e
         | 
| 507 525 | 
             
              ScheduleAccountRetryJob.perform_later(e.result.context.email)
         | 
| 508 526 | 
             
            rescue CMDx::SkipFault => e
         | 
| 509 527 | 
             
              Rails.logger.info("Account creation skipped: #{e.result.reason}")
         | 
| @@ -525,7 +543,7 @@ task.id                      #=> "abc123..." (unique task ID) | |
| 525 543 | 
             
            task.context.email           #=> "user@example.com"
         | 
| 526 544 | 
             
            task.context.send_welcome    #=> true
         | 
| 527 545 | 
             
            task.result.state            #=> "initialized"
         | 
| 528 | 
            -
            result.status | 
| 546 | 
            +
            task.result.status           #=> "success"
         | 
| 529 547 |  | 
| 530 548 | 
             
            # Manual execution
         | 
| 531 549 | 
             
            task.execute
         | 
| @@ -550,19 +568,15 @@ result.chain        #=> Task execution chain | |
| 550 568 | 
             
            # Context and metadata
         | 
| 551 569 | 
             
            result.context      #=> Context with all task data
         | 
| 552 570 | 
             
            result.metadata     #=> Hash with execution metadata
         | 
| 553 | 
            -
             | 
| 554 | 
            -
            ---
         | 
| 555 | 
            -
             | 
| 556 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/basics/context.md
         | 
| 557 | 
            -
            ---
         | 
| 571 | 
            +
            ```
         | 
| 558 572 |  | 
| 559 573 | 
             
            # Basics - Context
         | 
| 560 574 |  | 
| 561 | 
            -
             | 
| 575 | 
            +
            Context is your data container for inputs, intermediate values, and outputs. It makes sharing data between tasks effortless.
         | 
| 562 576 |  | 
| 563 577 | 
             
            ## Assigning Data
         | 
| 564 578 |  | 
| 565 | 
            -
            Context  | 
| 579 | 
            +
            Context automatically captures all task inputs, normalizing keys to symbols:
         | 
| 566 580 |  | 
| 567 581 | 
             
            ```ruby
         | 
| 568 582 | 
             
            # Direct execution
         | 
| @@ -572,12 +586,13 @@ CalculateShipping.execute(weight: 2.5, destination: "CA") | |
| 572 586 | 
             
            CalculateShipping.new(weight: 2.5, "destination" => "CA")
         | 
| 573 587 | 
             
            ```
         | 
| 574 588 |  | 
| 575 | 
            -
             | 
| 576 | 
            -
             | 
| 589 | 
            +
            !!! warning "Important"
         | 
| 590 | 
            +
             | 
| 591 | 
            +
                String keys convert to symbols automatically. Prefer symbols for consistency.
         | 
| 577 592 |  | 
| 578 593 | 
             
            ## Accessing Data
         | 
| 579 594 |  | 
| 580 | 
            -
             | 
| 595 | 
            +
            Access context data using method notation, hash keys, or safe accessors:
         | 
| 581 596 |  | 
| 582 597 | 
             
            ```ruby
         | 
| 583 598 | 
             
            class CalculateShipping < CMDx::Task
         | 
| @@ -600,8 +615,9 @@ class CalculateShipping < CMDx::Task | |
| 600 615 | 
             
            end
         | 
| 601 616 | 
             
            ```
         | 
| 602 617 |  | 
| 603 | 
            -
             | 
| 604 | 
            -
             | 
| 618 | 
            +
            !!! warning "Important"
         | 
| 619 | 
            +
             | 
| 620 | 
            +
                Undefined attributes return `nil` instead of raising errors—perfect for optional data.
         | 
| 605 621 |  | 
| 606 622 | 
             
            ## Modifying Context
         | 
| 607 623 |  | 
| @@ -642,12 +658,13 @@ class CalculateShipping < CMDx::Task | |
| 642 658 | 
             
            end
         | 
| 643 659 | 
             
            ```
         | 
| 644 660 |  | 
| 645 | 
            -
             | 
| 646 | 
            -
             | 
| 661 | 
            +
            !!! tip
         | 
| 662 | 
            +
             | 
| 663 | 
            +
                Use context for both input values and intermediate results. This creates natural data flow through your task execution pipeline.
         | 
| 647 664 |  | 
| 648 665 | 
             
            ## Data Sharing
         | 
| 649 666 |  | 
| 650 | 
            -
             | 
| 667 | 
            +
            Share context across tasks for seamless data flow:
         | 
| 651 668 |  | 
| 652 669 | 
             
            ```ruby
         | 
| 653 670 | 
             
            # During execution
         | 
| @@ -675,21 +692,17 @@ result = CalculateShipping.execute(destination: "New York, NY") | |
| 675 692 | 
             
            CreateShippingLabel.execute(result)
         | 
| 676 693 | 
             
            ```
         | 
| 677 694 |  | 
| 678 | 
            -
            ---
         | 
| 679 | 
            -
             | 
| 680 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/basics/chain.md
         | 
| 681 | 
            -
            ---
         | 
| 682 | 
            -
             | 
| 683 695 | 
             
            # Basics - Chain
         | 
| 684 696 |  | 
| 685 | 
            -
            Chains automatically  | 
| 697 | 
            +
            Chains automatically track related task executions within a thread. Think of them as execution traces that help you understand what happened and in what order.
         | 
| 686 698 |  | 
| 687 699 | 
             
            ## Management
         | 
| 688 700 |  | 
| 689 | 
            -
            Each thread maintains its own chain  | 
| 701 | 
            +
            Each thread maintains its own isolated chain using thread-local storage.
         | 
| 690 702 |  | 
| 691 | 
            -
             | 
| 692 | 
            -
             | 
| 703 | 
            +
            !!! warning
         | 
| 704 | 
            +
             | 
| 705 | 
            +
                Chains are thread-local. Don't share chain references across threads—it causes race conditions.
         | 
| 693 706 |  | 
| 694 707 | 
             
            ```ruby
         | 
| 695 708 | 
             
            # Thread A
         | 
| @@ -711,10 +724,11 @@ CMDx::Chain.clear    #=> Clears current thread's chain | |
| 711 724 |  | 
| 712 725 | 
             
            ## Links
         | 
| 713 726 |  | 
| 714 | 
            -
             | 
| 727 | 
            +
            Tasks automatically create or join the current thread's chain:
         | 
| 728 | 
            +
             | 
| 729 | 
            +
            !!! warning "Important"
         | 
| 715 730 |  | 
| 716 | 
            -
             | 
| 717 | 
            -
            > Chain creation is automatic and transparent. You don't need to manually manage chain lifecycle.
         | 
| 731 | 
            +
                Chain management is automatic—no manual lifecycle handling needed.
         | 
| 718 732 |  | 
| 719 733 | 
             
            ```ruby
         | 
| 720 734 | 
             
            class ImportDataset < CMDx::Task
         | 
| @@ -737,7 +751,7 @@ end | |
| 737 751 |  | 
| 738 752 | 
             
            ## Inheritance
         | 
| 739 753 |  | 
| 740 | 
            -
             | 
| 754 | 
            +
            Subtasks automatically inherit the current thread's chain, building a unified execution trail:
         | 
| 741 755 |  | 
| 742 756 | 
             
            ```ruby
         | 
| 743 757 | 
             
            class ImportDataset < CMDx::Task
         | 
| @@ -762,10 +776,11 @@ chain.results.map { |r| r.task.class } | |
| 762 776 |  | 
| 763 777 | 
             
            ## Structure
         | 
| 764 778 |  | 
| 765 | 
            -
            Chains  | 
| 779 | 
            +
            Chains expose comprehensive execution information:
         | 
| 780 | 
            +
             | 
| 781 | 
            +
            !!! warning "Important"
         | 
| 766 782 |  | 
| 767 | 
            -
             | 
| 768 | 
            -
            > Chain state always reflects the first (outer-most) task result, not individual subtask outcomes. Subtasks maintain their own success/failure states.
         | 
| 783 | 
            +
                Chain state reflects the first (outermost) task result. Subtasks maintain their own states.
         | 
| 769 784 |  | 
| 770 785 | 
             
            ```ruby
         | 
| 771 786 | 
             
            result = ImportDataset.execute(dataset_id: 456)
         | 
| @@ -786,21 +801,17 @@ chain.results.each_with_index do |result, index| | |
| 786 801 | 
             
            end
         | 
| 787 802 | 
             
            ```
         | 
| 788 803 |  | 
| 789 | 
            -
            ---
         | 
| 790 | 
            -
             | 
| 791 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/interruptions/halt.md
         | 
| 792 | 
            -
            ---
         | 
| 793 | 
            -
             | 
| 794 804 | 
             
            # Interruptions - Halt
         | 
| 795 805 |  | 
| 796 | 
            -
             | 
| 806 | 
            +
            Stop task execution intentionally using `skip!` or `fail!`. Both methods signal clear intent about why execution stopped.
         | 
| 797 807 |  | 
| 798 808 | 
             
            ## Skipping
         | 
| 799 809 |  | 
| 800 | 
            -
            `skip!`  | 
| 810 | 
            +
            Use `skip!` when the task doesn't need to run. It's a no-op, not an error.
         | 
| 811 | 
            +
             | 
| 812 | 
            +
            !!! warning "Important"
         | 
| 801 813 |  | 
| 802 | 
            -
             | 
| 803 | 
            -
            > Skipping is a no-op, not a failure or error and are considered successful outcomes.
         | 
| 814 | 
            +
                Skipped tasks are considered "good" outcomes—they succeeded by doing nothing.
         | 
| 804 815 |  | 
| 805 816 | 
             
            ```ruby
         | 
| 806 817 | 
             
            class ProcessInventory < CMDx::Task
         | 
| @@ -835,7 +846,7 @@ result.reason #=> "Warehouse closed" | |
| 835 846 |  | 
| 836 847 | 
             
            ## Failing
         | 
| 837 848 |  | 
| 838 | 
            -
            `fail!`  | 
| 849 | 
            +
            Use `fail!` when the task can't complete successfully. It signals controlled, intentional failure:
         | 
| 839 850 |  | 
| 840 851 | 
             
            ```ruby
         | 
| 841 852 | 
             
            class ProcessRefund < CMDx::Task
         | 
| @@ -870,7 +881,7 @@ result.reason #=> "Refund period has expired" | |
| 870 881 |  | 
| 871 882 | 
             
            ## Metadata Enrichment
         | 
| 872 883 |  | 
| 873 | 
            -
             | 
| 884 | 
            +
            Enrich halt calls with metadata for better debugging and error handling:
         | 
| 874 885 |  | 
| 875 886 | 
             
            ```ruby
         | 
| 876 887 | 
             
            class ProcessRenewal < CMDx::Task
         | 
| @@ -970,7 +981,7 @@ end | |
| 970 981 |  | 
| 971 982 | 
             
            ## Best Practices
         | 
| 972 983 |  | 
| 973 | 
            -
            Always  | 
| 984 | 
            +
            Always provide a reason for better debugging and clearer exception messages:
         | 
| 974 985 |  | 
| 975 986 | 
             
            ```ruby
         | 
| 976 987 | 
             
            # Good: Clear, specific reason
         | 
| @@ -988,10 +999,11 @@ fail! #=> "Unspecified" | |
| 988 999 |  | 
| 989 1000 | 
             
            ## Manual Errors
         | 
| 990 1001 |  | 
| 991 | 
            -
             | 
| 1002 | 
            +
            For rare cases, manually add errors before halting:
         | 
| 992 1003 |  | 
| 993 | 
            -
             | 
| 994 | 
            -
             | 
| 1004 | 
            +
            !!! warning "Important"
         | 
| 1005 | 
            +
             | 
| 1006 | 
            +
                Manual errors don't stop execution—you still need to call `fail!` or `skip!`.
         | 
| 995 1007 |  | 
| 996 1008 | 
             
            ```ruby
         | 
| 997 1009 | 
             
            class ProcessRenewal < CMDx::Task
         | 
| @@ -1006,14 +1018,9 @@ class ProcessRenewal < CMDx::Task | |
| 1006 1018 | 
             
            end
         | 
| 1007 1019 | 
             
            ```
         | 
| 1008 1020 |  | 
| 1009 | 
            -
            ---
         | 
| 1010 | 
            -
             | 
| 1011 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/interruptions/faults.md
         | 
| 1012 | 
            -
            ---
         | 
| 1013 | 
            -
             | 
| 1014 1021 | 
             
            # Interruptions - Faults
         | 
| 1015 1022 |  | 
| 1016 | 
            -
            Faults are  | 
| 1023 | 
            +
            Faults are exceptions raised by `execute!` when tasks halt. They carry rich context about execution state, enabling sophisticated error handling patterns.
         | 
| 1017 1024 |  | 
| 1018 1025 | 
             
            ## Fault Types
         | 
| 1019 1026 |  | 
| @@ -1023,8 +1030,9 @@ Faults are exception mechanisms that halt task execution via `skip!` and `fail!` | |
| 1023 1030 | 
             
            | `CMDx::SkipFault` | `skip!` method | Optional processing, early returns |
         | 
| 1024 1031 | 
             
            | `CMDx::FailFault` | `fail!` method | Validation errors, processing failures |
         | 
| 1025 1032 |  | 
| 1026 | 
            -
             | 
| 1027 | 
            -
             | 
| 1033 | 
            +
            !!! warning "Important"
         | 
| 1034 | 
            +
             | 
| 1035 | 
            +
                All faults inherit from `CMDx::Fault` and expose result, task, context, and chain data.
         | 
| 1028 1036 |  | 
| 1029 1037 | 
             
            ## Fault Handling
         | 
| 1030 1038 |  | 
| @@ -1045,7 +1053,7 @@ end | |
| 1045 1053 |  | 
| 1046 1054 | 
             
            ## Data Access
         | 
| 1047 1055 |  | 
| 1048 | 
            -
             | 
| 1056 | 
            +
            Access rich execution data from fault exceptions:
         | 
| 1049 1057 |  | 
| 1050 1058 | 
             
            ```ruby
         | 
| 1051 1059 | 
             
            begin
         | 
| @@ -1074,7 +1082,7 @@ end | |
| 1074 1082 |  | 
| 1075 1083 | 
             
            ### Task-Specific Matching
         | 
| 1076 1084 |  | 
| 1077 | 
            -
             | 
| 1085 | 
            +
            Handle faults only from specific tasks using `for?`:
         | 
| 1078 1086 |  | 
| 1079 1087 | 
             
            ```ruby
         | 
| 1080 1088 | 
             
            begin
         | 
| @@ -1104,7 +1112,7 @@ end | |
| 1104 1112 |  | 
| 1105 1113 | 
             
            ## Fault Propagation
         | 
| 1106 1114 |  | 
| 1107 | 
            -
             | 
| 1115 | 
            +
            Propagate failures with `throw!` to preserve context and maintain the error chain:
         | 
| 1108 1116 |  | 
| 1109 1117 | 
             
            ### Basic Propagation
         | 
| 1110 1118 |  | 
| @@ -1151,7 +1159,7 @@ end | |
| 1151 1159 |  | 
| 1152 1160 | 
             
            ## Chain Analysis
         | 
| 1153 1161 |  | 
| 1154 | 
            -
             | 
| 1162 | 
            +
            Trace fault origins and propagation through the execution chain:
         | 
| 1155 1163 |  | 
| 1156 1164 | 
             
            ```ruby
         | 
| 1157 1165 | 
             
            result = DocumentWorkflow.execute(invalid_data)
         | 
| @@ -1180,23 +1188,19 @@ if result.failed? | |
| 1180 1188 | 
             
            end
         | 
| 1181 1189 | 
             
            ```
         | 
| 1182 1190 |  | 
| 1183 | 
            -
            ---
         | 
| 1184 | 
            -
             | 
| 1185 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/interruptions/exceptions.md
         | 
| 1186 | 
            -
            ---
         | 
| 1187 | 
            -
             | 
| 1188 1191 | 
             
            # Interruptions - Exceptions
         | 
| 1189 1192 |  | 
| 1190 | 
            -
             | 
| 1193 | 
            +
            Exception handling differs between `execute` and `execute!`. Choose the method that matches your error handling strategy.
         | 
| 1191 1194 |  | 
| 1192 1195 | 
             
            ## Exception Handling
         | 
| 1193 1196 |  | 
| 1194 | 
            -
             | 
| 1195 | 
            -
             | 
| 1197 | 
            +
            !!! warning "Important"
         | 
| 1198 | 
            +
             | 
| 1199 | 
            +
                Prefer `skip!` and `fail!` over raising exceptions—they signal intent more clearly.
         | 
| 1196 1200 |  | 
| 1197 1201 | 
             
            ### Non-bang execution
         | 
| 1198 1202 |  | 
| 1199 | 
            -
             | 
| 1203 | 
            +
            Captures all exceptions and returns them as failed results:
         | 
| 1200 1204 |  | 
| 1201 1205 | 
             
            ```ruby
         | 
| 1202 1206 | 
             
            class CompressDocument < CMDx::Task
         | 
| @@ -1214,12 +1218,13 @@ result.reason   #=> "[ActiveRecord::NotFoundError] record not found" | |
| 1214 1218 | 
             
            result.cause    #=> <ActiveRecord::NotFoundError>
         | 
| 1215 1219 | 
             
            ```
         | 
| 1216 1220 |  | 
| 1217 | 
            -
             | 
| 1218 | 
            -
             | 
| 1221 | 
            +
            !!! note
         | 
| 1222 | 
            +
             | 
| 1223 | 
            +
                Use `exception_handler` with `execute` to send exceptions to APM tools before they become failed results.
         | 
| 1219 1224 |  | 
| 1220 1225 | 
             
            ### Bang execution
         | 
| 1221 1226 |  | 
| 1222 | 
            -
             | 
| 1227 | 
            +
            Lets exceptions propagate naturally for standard Ruby error handling:
         | 
| 1223 1228 |  | 
| 1224 1229 | 
             
            ```ruby
         | 
| 1225 1230 | 
             
            class CompressDocument < CMDx::Task
         | 
| @@ -1236,21 +1241,17 @@ rescue ActiveRecord::NotFoundError => e | |
| 1236 1241 | 
             
            end
         | 
| 1237 1242 | 
             
            ```
         | 
| 1238 1243 |  | 
| 1239 | 
            -
            ---
         | 
| 1240 | 
            -
             | 
| 1241 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/outcomes/result.md
         | 
| 1242 | 
            -
            ---
         | 
| 1243 | 
            -
             | 
| 1244 1244 | 
             
            # Outcomes - Result
         | 
| 1245 1245 |  | 
| 1246 | 
            -
             | 
| 1246 | 
            +
            Results are your window into task execution. They expose everything: outcome, state, timing, context, and metadata.
         | 
| 1247 1247 |  | 
| 1248 1248 | 
             
            ## Result Attributes
         | 
| 1249 1249 |  | 
| 1250 | 
            -
             | 
| 1250 | 
            +
            Access essential execution information:
         | 
| 1251 | 
            +
             | 
| 1252 | 
            +
            !!! warning "Important"
         | 
| 1251 1253 |  | 
| 1252 | 
            -
             | 
| 1253 | 
            -
            > Result objects are immutable after task execution completes and reflect the final state.
         | 
| 1254 | 
            +
                Results are immutable after execution completes.
         | 
| 1254 1255 |  | 
| 1255 1256 | 
             
            ```ruby
         | 
| 1256 1257 | 
             
            result = BuildApplication.execute(version: "1.2.3")
         | 
| @@ -1272,7 +1273,7 @@ result.metadata #=> { error_code: "BUILD_TOOL.NOT_FOUND" } | |
| 1272 1273 |  | 
| 1273 1274 | 
             
            ## Lifecycle Information
         | 
| 1274 1275 |  | 
| 1275 | 
            -
             | 
| 1276 | 
            +
            Check execution state and status with predicate methods:
         | 
| 1276 1277 |  | 
| 1277 1278 | 
             
            ```ruby
         | 
| 1278 1279 | 
             
            result = BuildApplication.execute(version: "1.2.3")
         | 
| @@ -1294,7 +1295,7 @@ result.bad?         #=> false (skipped or failed) | |
| 1294 1295 |  | 
| 1295 1296 | 
             
            ## Outcome Analysis
         | 
| 1296 1297 |  | 
| 1297 | 
            -
             | 
| 1298 | 
            +
            Get a unified outcome string combining state and status:
         | 
| 1298 1299 |  | 
| 1299 1300 | 
             
            ```ruby
         | 
| 1300 1301 | 
             
            result = BuildApplication.execute(version: "1.2.3")
         | 
| @@ -1304,7 +1305,7 @@ result.outcome #=> "success" (state and status) | |
| 1304 1305 |  | 
| 1305 1306 | 
             
            ## Chain Analysis
         | 
| 1306 1307 |  | 
| 1307 | 
            -
             | 
| 1308 | 
            +
            Trace fault origins and propagation:
         | 
| 1308 1309 |  | 
| 1309 1310 | 
             
            ```ruby
         | 
| 1310 1311 | 
             
            result = DeploymentWorkflow.execute(app_name: "webapp")
         | 
| @@ -1345,7 +1346,7 @@ result.chain.results[result.index] == result #=> true | |
| 1345 1346 |  | 
| 1346 1347 | 
             
            ## Block Yield
         | 
| 1347 1348 |  | 
| 1348 | 
            -
             | 
| 1349 | 
            +
            Execute code with direct result access:
         | 
| 1349 1350 |  | 
| 1350 1351 | 
             
            ```ruby
         | 
| 1351 1352 | 
             
            BuildApplication.execute(version: "1.2.3") do |result|
         | 
| @@ -1361,7 +1362,7 @@ end | |
| 1361 1362 |  | 
| 1362 1363 | 
             
            ## Handlers
         | 
| 1363 1364 |  | 
| 1364 | 
            -
             | 
| 1365 | 
            +
            Handle outcomes with functional-style methods. Handlers return the result for chaining:
         | 
| 1365 1366 |  | 
| 1366 1367 | 
             
            ```ruby
         | 
| 1367 1368 | 
             
            result = BuildApplication.execute(version: "1.2.3")
         | 
| @@ -1385,10 +1386,11 @@ result | |
| 1385 1386 |  | 
| 1386 1387 | 
             
            ## Pattern Matching
         | 
| 1387 1388 |  | 
| 1388 | 
            -
             | 
| 1389 | 
            +
            Use Ruby 3.0+ pattern matching for elegant outcome handling:
         | 
| 1390 | 
            +
             | 
| 1391 | 
            +
            !!! warning "Important"
         | 
| 1389 1392 |  | 
| 1390 | 
            -
             | 
| 1391 | 
            -
            > Pattern matching requires Ruby 3.0+
         | 
| 1393 | 
            +
                Pattern matching works with both array and hash deconstruction.
         | 
| 1392 1394 |  | 
| 1393 1395 | 
             
            ### Array Pattern
         | 
| 1394 1396 |  | 
| @@ -1433,17 +1435,9 @@ in { runtime: time } if time > performance_threshold | |
| 1433 1435 | 
             
            end
         | 
| 1434 1436 | 
             
            ```
         | 
| 1435 1437 |  | 
| 1436 | 
            -
            ---
         | 
| 1437 | 
            -
             | 
| 1438 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/outcomes/states.md
         | 
| 1439 | 
            -
            ---
         | 
| 1440 | 
            -
             | 
| 1441 1438 | 
             
            # Outcomes - States
         | 
| 1442 1439 |  | 
| 1443 | 
            -
            States  | 
| 1444 | 
            -
            the progress of tasks through their complete execution journey. States provide
         | 
| 1445 | 
            -
            insight into where a task is in its lifecycle and enable lifecycle-based
         | 
| 1446 | 
            -
            decision making and monitoring.
         | 
| 1440 | 
            +
            States track where a task is in its execution lifecycle—from creation through completion or interruption.
         | 
| 1447 1441 |  | 
| 1448 1442 | 
             
            ## Definitions
         | 
| 1449 1443 |  | 
| @@ -1467,8 +1461,9 @@ State-Status combinations: | |
| 1467 1461 |  | 
| 1468 1462 | 
             
            ## Transitions
         | 
| 1469 1463 |  | 
| 1470 | 
            -
             | 
| 1471 | 
            -
             | 
| 1464 | 
            +
            !!! danger "Caution"
         | 
| 1465 | 
            +
             | 
| 1466 | 
            +
                States are managed automatically—never modify them manually.
         | 
| 1472 1467 |  | 
| 1473 1468 | 
             
            ```ruby
         | 
| 1474 1469 | 
             
            # Valid state transition flow
         | 
| @@ -1495,7 +1490,7 @@ result.executed?    #=> true (complete OR interrupted) | |
| 1495 1490 |  | 
| 1496 1491 | 
             
            ## Handlers
         | 
| 1497 1492 |  | 
| 1498 | 
            -
             | 
| 1493 | 
            +
            Handle lifecycle events with state-based handlers. Use `handle_executed` for cleanup that runs regardless of outcome:
         | 
| 1499 1494 |  | 
| 1500 1495 | 
             
            ```ruby
         | 
| 1501 1496 | 
             
            result = ProcessVideoUpload.execute
         | 
| @@ -1507,14 +1502,9 @@ result | |
| 1507 1502 | 
             
              .handle_executed { |result| log_upload_metrics(result) }
         | 
| 1508 1503 | 
             
            ```
         | 
| 1509 1504 |  | 
| 1510 | 
            -
            ---
         | 
| 1511 | 
            -
             | 
| 1512 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/outcomes/statuses.md
         | 
| 1513 | 
            -
            ---
         | 
| 1514 | 
            -
             | 
| 1515 1505 | 
             
            # Outcomes - Statuses
         | 
| 1516 1506 |  | 
| 1517 | 
            -
            Statuses represent the business outcome  | 
| 1507 | 
            +
            Statuses represent the business outcome—did the task succeed, skip, or fail? This differs from state, which tracks the execution lifecycle.
         | 
| 1518 1508 |  | 
| 1519 1509 | 
             
            ## Definitions
         | 
| 1520 1510 |  | 
| @@ -1526,8 +1516,9 @@ Statuses represent the business outcome of task execution logic, indicating how | |
| 1526 1516 |  | 
| 1527 1517 | 
             
            ## Transitions
         | 
| 1528 1518 |  | 
| 1529 | 
            -
             | 
| 1530 | 
            -
             | 
| 1519 | 
            +
            !!! warning "Important"
         | 
| 1520 | 
            +
             | 
| 1521 | 
            +
                Status transitions are final and unidirectional. Once skipped or failed, tasks can't return to success.
         | 
| 1531 1522 |  | 
| 1532 1523 | 
             
            ```ruby
         | 
| 1533 1524 | 
             
            # Valid status transitions
         | 
| @@ -1560,7 +1551,7 @@ result.bad?     #=> true if skipped OR failed (not success) | |
| 1560 1551 |  | 
| 1561 1552 | 
             
            ## Handlers
         | 
| 1562 1553 |  | 
| 1563 | 
            -
             | 
| 1554 | 
            +
            Branch business logic with status-based handlers. Use `handle_good` and `handle_bad` for success/skip vs failed outcomes:
         | 
| 1564 1555 |  | 
| 1565 1556 | 
             
            ```ruby
         | 
| 1566 1557 | 
             
            result = ProcessNotification.execute
         | 
| @@ -1577,19 +1568,15 @@ result | |
| 1577 1568 | 
             
              .handle_bad { |result| track_delivery_failure(result) }
         | 
| 1578 1569 | 
             
            ```
         | 
| 1579 1570 |  | 
| 1580 | 
            -
            ---
         | 
| 1581 | 
            -
             | 
| 1582 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/attributes/definitions.md
         | 
| 1583 | 
            -
            ---
         | 
| 1584 | 
            -
             | 
| 1585 1571 | 
             
            # Attributes - Definitions
         | 
| 1586 1572 |  | 
| 1587 | 
            -
            Attributes define  | 
| 1573 | 
            +
            Attributes define your task's interface with automatic validation, type coercion, and accessor generation. They're the contract between callers and your business logic.
         | 
| 1588 1574 |  | 
| 1589 1575 | 
             
            ## Declarations
         | 
| 1590 1576 |  | 
| 1591 | 
            -
             | 
| 1592 | 
            -
             | 
| 1577 | 
            +
            !!! tip
         | 
| 1578 | 
            +
             | 
| 1579 | 
            +
                Prefer using the `required` and `optional` alias for `attributes` for brevity and to clearly signal intent.
         | 
| 1593 1580 |  | 
| 1594 1581 | 
             
            ### Optional
         | 
| 1595 1582 |  | 
| @@ -1658,7 +1645,7 @@ PublishArticle.execute( | |
| 1658 1645 |  | 
| 1659 1646 | 
             
            ## Sources
         | 
| 1660 1647 |  | 
| 1661 | 
            -
            Attributes  | 
| 1648 | 
            +
            Attributes read from any accessible object—not just context. Use sources to pull data from models, services, or any callable:
         | 
| 1662 1649 |  | 
| 1663 1650 | 
             
            ### Context
         | 
| 1664 1651 |  | 
| @@ -1738,10 +1725,11 @@ end | |
| 1738 1725 |  | 
| 1739 1726 | 
             
            ## Nesting
         | 
| 1740 1727 |  | 
| 1741 | 
            -
             | 
| 1728 | 
            +
            Build complex structures with nested attributes. Children inherit their parent as source and support all attribute options:
         | 
| 1742 1729 |  | 
| 1743 | 
            -
             | 
| 1744 | 
            -
             | 
| 1730 | 
            +
            !!! note
         | 
| 1731 | 
            +
             | 
| 1732 | 
            +
                Nested attributes support all features: naming, coercions, validations, defaults, and more.
         | 
| 1745 1733 |  | 
| 1746 1734 | 
             
            ```ruby
         | 
| 1747 1735 | 
             
            class ConfigureServer < CMDx::Task
         | 
| @@ -1794,15 +1782,17 @@ ConfigureServer.execute( | |
| 1794 1782 | 
             
            )
         | 
| 1795 1783 | 
             
            ```
         | 
| 1796 1784 |  | 
| 1797 | 
            -
             | 
| 1798 | 
            -
             | 
| 1785 | 
            +
            !!! warning "Important"
         | 
| 1786 | 
            +
             | 
| 1787 | 
            +
                Child requirements only apply when the parent is provided—perfect for optional structures.
         | 
| 1799 1788 |  | 
| 1800 1789 | 
             
            ## Error Handling
         | 
| 1801 1790 |  | 
| 1802 | 
            -
             | 
| 1791 | 
            +
            Validation failures provide detailed, structured error messages:
         | 
| 1792 | 
            +
             | 
| 1793 | 
            +
            !!! note
         | 
| 1803 1794 |  | 
| 1804 | 
            -
             | 
| 1805 | 
            -
            > Nested attributes are only ever evaluated when the parent attribute is available and valid.
         | 
| 1795 | 
            +
                Nested attributes are only validated when their parent is present and valid.
         | 
| 1806 1796 |  | 
| 1807 1797 | 
             
            ```ruby
         | 
| 1808 1798 | 
             
            class ConfigureServer < CMDx::Task
         | 
| @@ -1852,17 +1842,13 @@ result.metadata #=> { | |
| 1852 1842 | 
             
                            #   }
         | 
| 1853 1843 | 
             
            ```
         | 
| 1854 1844 |  | 
| 1855 | 
            -
            ---
         | 
| 1856 | 
            -
             | 
| 1857 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/attributes/naming.md
         | 
| 1858 | 
            -
            ---
         | 
| 1859 | 
            -
             | 
| 1860 1845 | 
             
            # Attributes - Naming
         | 
| 1861 1846 |  | 
| 1862 | 
            -
             | 
| 1847 | 
            +
            Customize accessor method names to avoid conflicts and improve clarity. Affixing changes only the generated methods—not the original attribute names.
         | 
| 1848 | 
            +
             | 
| 1849 | 
            +
            !!! note
         | 
| 1863 1850 |  | 
| 1864 | 
            -
             | 
| 1865 | 
            -
            > Affixing modifies only the generated accessor method names within tasks.
         | 
| 1851 | 
            +
                Use naming when attributes conflict with existing methods or need better clarity in your code.
         | 
| 1866 1852 |  | 
| 1867 1853 | 
             
            ## Prefix
         | 
| 1868 1854 |  | 
| @@ -1925,16 +1911,11 @@ end | |
| 1925 1911 | 
             
            ScheduleMaintenance.execute(scheduled_at: DateTime.new(2024, 12, 15, 2, 0, 0))
         | 
| 1926 1912 | 
             
            ```
         | 
| 1927 1913 |  | 
| 1928 | 
            -
            ---
         | 
| 1929 | 
            -
             | 
| 1930 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/attributes/coercions.md
         | 
| 1931 | 
            -
            ---
         | 
| 1932 | 
            -
             | 
| 1933 1914 | 
             
            # Attributes - Coercions
         | 
| 1934 1915 |  | 
| 1935 | 
            -
             | 
| 1916 | 
            +
            Automatically convert inputs to expected types. Coercions handle everything from simple string-to-integer conversions to JSON parsing.
         | 
| 1936 1917 |  | 
| 1937 | 
            -
             | 
| 1918 | 
            +
            See [Global Configuration](https://github.com/drexed/cmdx/blob/main/docs/getting_started.md#coercions) for custom coercion setup.
         | 
| 1938 1919 |  | 
| 1939 1920 | 
             
            ## Usage
         | 
| 1940 1921 |  | 
| @@ -1965,8 +1946,9 @@ ParseMetrics.execute( | |
| 1965 1946 | 
             
            )
         | 
| 1966 1947 | 
             
            ```
         | 
| 1967 1948 |  | 
| 1968 | 
            -
             | 
| 1969 | 
            -
             | 
| 1949 | 
            +
            !!! tip
         | 
| 1950 | 
            +
             | 
| 1951 | 
            +
                Specify multiple coercion types for attributes that could be a variety of value formats. CMDx attempts each type in order until one succeeds.
         | 
| 1970 1952 |  | 
| 1971 1953 | 
             
            ## Built-in Coercions
         | 
| 1972 1954 |  | 
| @@ -1988,8 +1970,9 @@ ParseMetrics.execute( | |
| 1988 1970 |  | 
| 1989 1971 | 
             
            ## Declarations
         | 
| 1990 1972 |  | 
| 1991 | 
            -
             | 
| 1992 | 
            -
             | 
| 1973 | 
            +
            !!! warning "Important"
         | 
| 1974 | 
            +
             | 
| 1975 | 
            +
                Custom coercions must raise `CMDx::CoercionError` with a descriptive message.
         | 
| 1993 1976 |  | 
| 1994 1977 | 
             
            ### Proc or Lambda
         | 
| 1995 1978 |  | 
| @@ -2039,10 +2022,11 @@ end | |
| 2039 2022 |  | 
| 2040 2023 | 
             
            ## Removals
         | 
| 2041 2024 |  | 
| 2042 | 
            -
            Remove  | 
| 2025 | 
            +
            Remove unwanted coercions:
         | 
| 2026 | 
            +
             | 
| 2027 | 
            +
            !!! warning
         | 
| 2043 2028 |  | 
| 2044 | 
            -
             | 
| 2045 | 
            -
            > Only one removal operation is allowed per `deregister` call. Multiple removals require separate calls.
         | 
| 2029 | 
            +
                Each `deregister` call removes one coercion. Use multiple calls for batch removals.
         | 
| 2046 2030 |  | 
| 2047 2031 | 
             
            ```ruby
         | 
| 2048 2032 | 
             
            class TransformCoordinates < CMDx::Task
         | 
| @@ -2083,16 +2067,11 @@ result.metadata #=> { | |
| 2083 2067 | 
             
                            #   }
         | 
| 2084 2068 | 
             
            ```
         | 
| 2085 2069 |  | 
| 2086 | 
            -
            ---
         | 
| 2087 | 
            -
             | 
| 2088 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/attributes/validations.md
         | 
| 2089 | 
            -
            ---
         | 
| 2090 | 
            -
             | 
| 2091 2070 | 
             
            # Attributes - Validations
         | 
| 2092 2071 |  | 
| 2093 | 
            -
             | 
| 2072 | 
            +
            Ensure inputs meet requirements before execution. Validations run after coercions, giving you declarative data integrity checks.
         | 
| 2094 2073 |  | 
| 2095 | 
            -
             | 
| 2074 | 
            +
            See [Global Configuration](https://github.com/drexed/cmdx/blob/main/docs/getting_started.md#validators) for custom validator setup.
         | 
| 2096 2075 |  | 
| 2097 2076 | 
             
            ## Usage
         | 
| 2098 2077 |  | 
| @@ -2128,8 +2107,9 @@ ProcessSubscription.execute( | |
| 2128 2107 | 
             
            )
         | 
| 2129 2108 | 
             
            ```
         | 
| 2130 2109 |  | 
| 2131 | 
            -
             | 
| 2132 | 
            -
             | 
| 2110 | 
            +
            !!! tip
         | 
| 2111 | 
            +
             | 
| 2112 | 
            +
                Validations run after coercions, so you can validate the final coerced values rather than raw input.
         | 
| 2133 2113 |  | 
| 2134 2114 | 
             
            ## Built-in Validators
         | 
| 2135 2115 |  | 
| @@ -2284,8 +2264,9 @@ end | |
| 2284 2264 |  | 
| 2285 2265 | 
             
            ## Declarations
         | 
| 2286 2266 |  | 
| 2287 | 
            -
             | 
| 2288 | 
            -
             | 
| 2267 | 
            +
            !!! warning "Important"
         | 
| 2268 | 
            +
             | 
| 2269 | 
            +
                Custom validators must raise `CMDx::ValidationError` with a descriptive message.
         | 
| 2289 2270 |  | 
| 2290 2271 | 
             
            ### Proc or Lambda
         | 
| 2291 2272 |  | 
| @@ -2331,10 +2312,11 @@ end | |
| 2331 2312 |  | 
| 2332 2313 | 
             
            ## Removals
         | 
| 2333 2314 |  | 
| 2334 | 
            -
            Remove  | 
| 2315 | 
            +
            Remove unwanted validators:
         | 
| 2335 2316 |  | 
| 2336 | 
            -
             | 
| 2337 | 
            -
             | 
| 2317 | 
            +
            !!! warning
         | 
| 2318 | 
            +
             | 
| 2319 | 
            +
                Each `deregister` call removes one validator. Use multiple calls for batch removals.
         | 
| 2338 2320 |  | 
| 2339 2321 | 
             
            ```ruby
         | 
| 2340 2322 | 
             
            class SetupApplication < CMDx::Task
         | 
| @@ -2344,7 +2326,7 @@ end | |
| 2344 2326 |  | 
| 2345 2327 | 
             
            ## Error Handling
         | 
| 2346 2328 |  | 
| 2347 | 
            -
            Validation failures provide detailed | 
| 2329 | 
            +
            Validation failures provide detailed, structured error messages:
         | 
| 2348 2330 |  | 
| 2349 2331 | 
             
            ```ruby
         | 
| 2350 2332 | 
             
            class CreateProject < CMDx::Task
         | 
| @@ -2381,18 +2363,13 @@ result.metadata #=> { | |
| 2381 2363 | 
             
                            #   }
         | 
| 2382 2364 | 
             
            ```
         | 
| 2383 2365 |  | 
| 2384 | 
            -
            ---
         | 
| 2385 | 
            -
             | 
| 2386 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/attributes/defaults.md
         | 
| 2387 | 
            -
            ---
         | 
| 2388 | 
            -
             | 
| 2389 2366 | 
             
            # Attributes - Defaults
         | 
| 2390 2367 |  | 
| 2391 | 
            -
             | 
| 2368 | 
            +
            Provide fallback values for optional attributes. Defaults kick in when values aren't provided or are `nil`.
         | 
| 2392 2369 |  | 
| 2393 2370 | 
             
            ## Declarations
         | 
| 2394 2371 |  | 
| 2395 | 
            -
            Defaults  | 
| 2372 | 
            +
            Defaults work seamlessly with coercions, validations, and nested attributes:
         | 
| 2396 2373 |  | 
| 2397 2374 | 
             
            ### Static Values
         | 
| 2398 2375 |  | 
| @@ -2452,7 +2429,7 @@ end | |
| 2452 2429 |  | 
| 2453 2430 | 
             
            ## Coercions and Validations
         | 
| 2454 2431 |  | 
| 2455 | 
            -
            Defaults  | 
| 2432 | 
            +
            Defaults follow the same coercion and validation rules as provided values:
         | 
| 2456 2433 |  | 
| 2457 2434 | 
             
            ```ruby
         | 
| 2458 2435 | 
             
            class ScheduleBackup < CMDx::Task
         | 
| @@ -2464,14 +2441,9 @@ class ScheduleBackup < CMDx::Task | |
| 2464 2441 | 
             
            end
         | 
| 2465 2442 | 
             
            ```
         | 
| 2466 2443 |  | 
| 2467 | 
            -
            ---
         | 
| 2468 | 
            -
             | 
| 2469 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/attributes/transformations.md
         | 
| 2470 | 
            -
            ---
         | 
| 2471 | 
            -
             | 
| 2472 2444 | 
             
            # Attributes - Transformations
         | 
| 2473 2445 |  | 
| 2474 | 
            -
             | 
| 2446 | 
            +
            Modify attribute values after coercion but before validation. Perfect for normalization, formatting, and data cleanup.
         | 
| 2475 2447 |  | 
| 2476 2448 | 
             
            ## Declarations
         | 
| 2477 2449 |  | 
| @@ -2521,7 +2493,7 @@ end | |
| 2521 2493 |  | 
| 2522 2494 | 
             
            ## Validations
         | 
| 2523 2495 |  | 
| 2524 | 
            -
             | 
| 2496 | 
            +
            Validations run on transformed values, ensuring data consistency:
         | 
| 2525 2497 |  | 
| 2526 2498 | 
             
            ```ruby
         | 
| 2527 2499 | 
             
            class ScheduleBackup < CMDx::Task
         | 
| @@ -2533,39 +2505,30 @@ class ScheduleBackup < CMDx::Task | |
| 2533 2505 | 
             
            end
         | 
| 2534 2506 | 
             
            ```
         | 
| 2535 2507 |  | 
| 2536 | 
            -
            ---
         | 
| 2537 | 
            -
             | 
| 2538 | 
            -
            - **Prev:** [Attributes - Defaults](defaults.md)
         | 
| 2539 | 
            -
            - **Next:** [Callbacks](../callbacks.md)
         | 
| 2540 | 
            -
             | 
| 2541 | 
            -
            ---
         | 
| 2542 | 
            -
             | 
| 2543 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/callbacks.md
         | 
| 2544 | 
            -
            ---
         | 
| 2545 | 
            -
             | 
| 2546 2508 | 
             
            # Callbacks
         | 
| 2547 2509 |  | 
| 2548 | 
            -
             | 
| 2510 | 
            +
            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.
         | 
| 2549 2511 |  | 
| 2550 | 
            -
             | 
| 2512 | 
            +
            See [Global Configuration](https://github.com/drexed/cmdx/blob/main/docs/getting_started.md#callbacks) for framework-wide callback setup.
         | 
| 2551 2513 |  | 
| 2552 | 
            -
             | 
| 2553 | 
            -
             | 
| 2514 | 
            +
            !!! warning "Important"
         | 
| 2515 | 
            +
             | 
| 2516 | 
            +
                Callbacks execute in declaration order (FIFO). Multiple callbacks of the same type run sequentially.
         | 
| 2554 2517 |  | 
| 2555 2518 | 
             
            ## Available Callbacks
         | 
| 2556 2519 |  | 
| 2557 | 
            -
            Callbacks execute in  | 
| 2520 | 
            +
            Callbacks execute in a predictable lifecycle order:
         | 
| 2558 2521 |  | 
| 2559 2522 | 
             
            ```ruby
         | 
| 2560 2523 | 
             
            1. before_validation           # Pre-validation setup
         | 
| 2561 | 
            -
            2. before_execution            #  | 
| 2524 | 
            +
            2. before_execution            # Prepare for execution
         | 
| 2562 2525 |  | 
| 2563 | 
            -
            # --- Task#work  | 
| 2526 | 
            +
            # --- Task#work executes ---
         | 
| 2564 2527 |  | 
| 2565 | 
            -
            3. on_[complete|interrupted]   #  | 
| 2566 | 
            -
            4. on_executed                 #  | 
| 2567 | 
            -
            5. on_[success|skipped|failed] #  | 
| 2568 | 
            -
            6. on_[good|bad]               #  | 
| 2528 | 
            +
            3. on_[complete|interrupted]   # State-based (execution lifecycle)
         | 
| 2529 | 
            +
            4. on_executed                 # Always runs after work completes
         | 
| 2530 | 
            +
            5. on_[success|skipped|failed] # Status-based (business outcome)
         | 
| 2531 | 
            +
            6. on_[good|bad]               # Outcome-based (success/skip vs fail)
         | 
| 2569 2532 | 
             
            ```
         | 
| 2570 2533 |  | 
| 2571 2534 | 
             
            ## Declarations
         | 
| @@ -2617,7 +2580,7 @@ end | |
| 2617 2580 |  | 
| 2618 2581 | 
             
            ### Class or Module
         | 
| 2619 2582 |  | 
| 2620 | 
            -
            Implement reusable callback logic in dedicated classes:
         | 
| 2583 | 
            +
            Implement reusable callback logic in dedicated modules and classes:
         | 
| 2621 2584 |  | 
| 2622 2585 | 
             
            ```ruby
         | 
| 2623 2586 | 
             
            class BookingConfirmationCallback
         | 
| @@ -2684,10 +2647,11 @@ end | |
| 2684 2647 |  | 
| 2685 2648 | 
             
            ## Callback Removal
         | 
| 2686 2649 |  | 
| 2687 | 
            -
            Remove callbacks  | 
| 2650 | 
            +
            Remove unwanted callbacks dynamically:
         | 
| 2651 | 
            +
             | 
| 2652 | 
            +
            !!! warning "Important"
         | 
| 2688 2653 |  | 
| 2689 | 
            -
             | 
| 2690 | 
            -
            > Only one removal operation is allowed per `deregister` call. Multiple removals require separate calls.
         | 
| 2654 | 
            +
                Each `deregister` call removes one callback. Use multiple calls for batch removals.
         | 
| 2691 2655 |  | 
| 2692 2656 | 
             
            ```ruby
         | 
| 2693 2657 | 
             
            class ProcessBooking < CMDx::Task
         | 
| @@ -2699,23 +2663,19 @@ class ProcessBooking < CMDx::Task | |
| 2699 2663 | 
             
            end
         | 
| 2700 2664 | 
             
            ```
         | 
| 2701 2665 |  | 
| 2702 | 
            -
            ---
         | 
| 2703 | 
            -
             | 
| 2704 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/middlewares.md
         | 
| 2705 | 
            -
            ---
         | 
| 2706 | 
            -
             | 
| 2707 2666 | 
             
            # Middlewares
         | 
| 2708 2667 |  | 
| 2709 | 
            -
             | 
| 2668 | 
            +
            Wrap task execution with middleware for cross-cutting concerns like authentication, caching, timeouts, and monitoring. Think Rack middleware, but for your business logic.
         | 
| 2710 2669 |  | 
| 2711 | 
            -
             | 
| 2670 | 
            +
            See [Global Configuration](https://github.com/drexed/cmdx/blob/main/docs/getting_started.md#middlewares) for framework-wide setup.
         | 
| 2712 2671 |  | 
| 2713 | 
            -
            ## Order
         | 
| 2672 | 
            +
            ## Execution Order
         | 
| 2714 2673 |  | 
| 2715 | 
            -
            Middleware  | 
| 2674 | 
            +
            Middleware wraps task execution in layers, like an onion:
         | 
| 2716 2675 |  | 
| 2717 | 
            -
             | 
| 2718 | 
            -
             | 
| 2676 | 
            +
            !!! note
         | 
| 2677 | 
            +
             | 
| 2678 | 
            +
                First registered = outermost wrapper. They execute in registration order.
         | 
| 2719 2679 |  | 
| 2720 2680 | 
             
            ```ruby
         | 
| 2721 2681 | 
             
            class ProcessCampaign < CMDx::Task
         | 
| @@ -2791,10 +2751,11 @@ end | |
| 2791 2751 |  | 
| 2792 2752 | 
             
            ## Removals
         | 
| 2793 2753 |  | 
| 2794 | 
            -
             | 
| 2754 | 
            +
            Remove class or module-based middleware globally or per-task:
         | 
| 2755 | 
            +
             | 
| 2756 | 
            +
            !!! warning
         | 
| 2795 2757 |  | 
| 2796 | 
            -
             | 
| 2797 | 
            -
            > Only one removal operation is allowed per `deregister` call. Multiple removals require separate calls.
         | 
| 2758 | 
            +
                Each `deregister` call removes one middleware. Use multiple calls for batch removals.
         | 
| 2798 2759 |  | 
| 2799 2760 | 
             
            ```ruby
         | 
| 2800 2761 | 
             
            class ProcessCampaign < CMDx::Task
         | 
| @@ -2807,7 +2768,7 @@ end | |
| 2807 2768 |  | 
| 2808 2769 | 
             
            ### Timeout
         | 
| 2809 2770 |  | 
| 2810 | 
            -
             | 
| 2771 | 
            +
            Prevent tasks from running too long:
         | 
| 2811 2772 |  | 
| 2812 2773 | 
             
            ```ruby
         | 
| 2813 2774 | 
             
            class ProcessReport < CMDx::Task
         | 
| @@ -2843,7 +2804,7 @@ result.metadata #=> { limit: 3 } | |
| 2843 2804 |  | 
| 2844 2805 | 
             
            ### Correlate
         | 
| 2845 2806 |  | 
| 2846 | 
            -
             | 
| 2807 | 
            +
            Add correlation IDs for distributed tracing and request tracking:
         | 
| 2847 2808 |  | 
| 2848 2809 | 
             
            ```ruby
         | 
| 2849 2810 | 
             
            class ProcessExport < CMDx::Task
         | 
| @@ -2873,8 +2834,7 @@ result.metadata #=> { correlation_id: "550e8400-e29b-41d4-a716-446655440000" } | |
| 2873 2834 |  | 
| 2874 2835 | 
             
            ### Runtime
         | 
| 2875 2836 |  | 
| 2876 | 
            -
             | 
| 2877 | 
            -
            The calculation uses a monotonic clock and the time is returned in milliseconds.
         | 
| 2837 | 
            +
            Track task execution time in milliseconds using a monotonic clock:
         | 
| 2878 2838 |  | 
| 2879 2839 | 
             
            ```ruby
         | 
| 2880 2840 | 
             
            class PerformanceMonitoringCheck
         | 
| @@ -2895,18 +2855,13 @@ result = ProcessExport.execute | |
| 2895 2855 | 
             
            result.metadata #=> { runtime: 1247 } (ms)
         | 
| 2896 2856 | 
             
            ```
         | 
| 2897 2857 |  | 
| 2898 | 
            -
            ---
         | 
| 2899 | 
            -
             | 
| 2900 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/logging.md
         | 
| 2901 | 
            -
            ---
         | 
| 2902 | 
            -
             | 
| 2903 2858 | 
             
            # Logging
         | 
| 2904 2859 |  | 
| 2905 | 
            -
            CMDx  | 
| 2860 | 
            +
            CMDx automatically logs every task execution with structured data, making debugging and monitoring effortless. Choose from multiple formatters to match your logging infrastructure.
         | 
| 2906 2861 |  | 
| 2907 2862 | 
             
            ## Formatters
         | 
| 2908 2863 |  | 
| 2909 | 
            -
             | 
| 2864 | 
            +
            Choose the format that works best for your logging system:
         | 
| 2910 2865 |  | 
| 2911 2866 | 
             
            | Formatter | Use Case | Output Style |
         | 
| 2912 2867 | 
             
            |-----------|----------|--------------|
         | 
| @@ -2936,12 +2891,13 @@ E, [2022-07-17T18:43:15.000000 #3784] ERROR -- BillingWorkflow: | |
| 2936 2891 | 
             
            index=3 chain_id="018c2b95-b764-7615-a924-cc5b910ed1e5" type="Task" class="BillingWorkflow"  state="interrupted" status="failed" caused_failure={index: 2, class: "CalculateTax", status: "failed"} threw_failure={index: 1, class: "ValidateCustomer", status: "failed"}
         | 
| 2937 2892 | 
             
            ```
         | 
| 2938 2893 |  | 
| 2939 | 
            -
             | 
| 2940 | 
            -
             | 
| 2894 | 
            +
            !!! tip
         | 
| 2895 | 
            +
             | 
| 2896 | 
            +
                Use logging as a low-level event stream to track all tasks in a request. Combine with correlation for powerful distributed tracing.
         | 
| 2941 2897 |  | 
| 2942 2898 | 
             
            ## Structure
         | 
| 2943 2899 |  | 
| 2944 | 
            -
             | 
| 2900 | 
            +
            Every log entry includes rich metadata. Available fields depend on execution context and outcome.
         | 
| 2945 2901 |  | 
| 2946 2902 | 
             
            ### Core Fields
         | 
| 2947 2903 |  | 
| @@ -2982,7 +2938,7 @@ All log entries include comprehensive execution metadata. Field availability dep | |
| 2982 2938 |  | 
| 2983 2939 | 
             
            ## Usage
         | 
| 2984 2940 |  | 
| 2985 | 
            -
             | 
| 2941 | 
            +
            Access the framework logger directly within tasks:
         | 
| 2986 2942 |  | 
| 2987 2943 | 
             
            ```ruby
         | 
| 2988 2944 | 
             
            class ProcessSubscription < CMDx::Task
         | 
| @@ -2994,18 +2950,13 @@ class ProcessSubscription < CMDx::Task | |
| 2994 2950 | 
             
            end
         | 
| 2995 2951 | 
             
            ```
         | 
| 2996 2952 |  | 
| 2997 | 
            -
            ---
         | 
| 2998 | 
            -
             | 
| 2999 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/internationalization.md
         | 
| 3000 | 
            -
            ---
         | 
| 3001 | 
            -
             | 
| 3002 2953 | 
             
            # Internationalization (i18n)
         | 
| 3003 2954 |  | 
| 3004 | 
            -
            CMDx  | 
| 2955 | 
            +
            CMDx supports 90+ languages out of the box for all error messages, validations, coercions, and faults. Error messages automatically adapt to the current `I18n.locale`, making it easy to build applications for global audiences.
         | 
| 3005 2956 |  | 
| 3006 | 
            -
            ##  | 
| 2957 | 
            +
            ## Usage
         | 
| 3007 2958 |  | 
| 3008 | 
            -
             | 
| 2959 | 
            +
            All error messages are automatically localized based on your current locale:
         | 
| 3009 2960 |  | 
| 3010 2961 | 
             
            ```ruby
         | 
| 3011 2962 | 
             
            class ProcessQuote < CMDx::Task
         | 
| @@ -3024,11 +2975,11 @@ end | |
| 3024 2975 |  | 
| 3025 2976 | 
             
            ## Configuration
         | 
| 3026 2977 |  | 
| 3027 | 
            -
             | 
| 2978 | 
            +
            CMDx uses the `I18n` gem for localization. In Rails, locales load automatically.
         | 
| 3028 2979 |  | 
| 3029 | 
            -
            ###  | 
| 2980 | 
            +
            ### Copy Locale Files
         | 
| 3030 2981 |  | 
| 3031 | 
            -
             | 
| 2982 | 
            +
            Copy locale files to your Rails application's `config/locales` directory:
         | 
| 3032 2983 |  | 
| 3033 2984 | 
             
            ```bash
         | 
| 3034 2985 | 
             
            rails generate cmdx:locale [LOCALE]
         | 
| @@ -3126,23 +3077,141 @@ rails generate cmdx:locale fr | |
| 3126 3077 | 
             
            - zh-TW - Chinese (Traditional)
         | 
| 3127 3078 | 
             
            - zh-YUE - Chinese (Yue)
         | 
| 3128 3079 |  | 
| 3129 | 
            -
             | 
| 3080 | 
            +
            # Retries
         | 
| 3081 | 
            +
             | 
| 3082 | 
            +
            CMDx provides automatic retry functionality for tasks that encounter transient failures. This is essential for handling temporary issues like network timeouts, rate limits, or database locks without manual intervention.
         | 
| 3130 3083 |  | 
| 3131 | 
            -
             | 
| 3132 | 
            -
             | 
| 3084 | 
            +
            ## Basic Usage
         | 
| 3085 | 
            +
             | 
| 3086 | 
            +
            Configure retries upto n attempts without any delay.
         | 
| 3087 | 
            +
             | 
| 3088 | 
            +
            ```ruby
         | 
| 3089 | 
            +
            class FetchExternalData < CMDx::Task
         | 
| 3090 | 
            +
              settings retries: 3
         | 
| 3091 | 
            +
             | 
| 3092 | 
            +
              def work
         | 
| 3093 | 
            +
                response = HTTParty.get("https://api.example.com/data")
         | 
| 3094 | 
            +
                context.data = response.parsed_response
         | 
| 3095 | 
            +
              end
         | 
| 3096 | 
            +
            end
         | 
| 3097 | 
            +
            ```
         | 
| 3098 | 
            +
             | 
| 3099 | 
            +
            When an exception occurs during execution, CMDx automatically retries up to the configured limit.
         | 
| 3100 | 
            +
             | 
| 3101 | 
            +
            ## Selective Retries
         | 
| 3102 | 
            +
             | 
| 3103 | 
            +
            By default, CMDx retries on `StandardError` and its subclasses. Narrow this to specific exception types:
         | 
| 3104 | 
            +
             | 
| 3105 | 
            +
            ```ruby
         | 
| 3106 | 
            +
            class ProcessPayment < CMDx::Task
         | 
| 3107 | 
            +
              settings retries: 5, retry_on: [Stripe::RateLimitError, Net::ReadTimeout]
         | 
| 3108 | 
            +
             | 
| 3109 | 
            +
              def work
         | 
| 3110 | 
            +
                # Your logic here...
         | 
| 3111 | 
            +
              end
         | 
| 3112 | 
            +
            end
         | 
| 3113 | 
            +
            ```
         | 
| 3114 | 
            +
             | 
| 3115 | 
            +
            !!! warning "Important"
         | 
| 3116 | 
            +
             | 
| 3117 | 
            +
                Only exceptions matching the `retry_on` configuration will trigger retries. Uncaught exceptions immediately fail the task.
         | 
| 3118 | 
            +
             | 
| 3119 | 
            +
            ## Retry Jitter
         | 
| 3120 | 
            +
             | 
| 3121 | 
            +
            Add delays between retry attempts to avoid overwhelming external services or to implement exponential backoff strategies.
         | 
| 3122 | 
            +
             | 
| 3123 | 
            +
            ### Fixed Value
         | 
| 3124 | 
            +
             | 
| 3125 | 
            +
            Use a numeric value to calculate linear delay (`jitter * current_retry`):
         | 
| 3126 | 
            +
             | 
| 3127 | 
            +
            ```ruby
         | 
| 3128 | 
            +
            class ImportRecords < CMDx::Task
         | 
| 3129 | 
            +
              settings retries: 3, retry_jitter: 0.5
         | 
| 3130 | 
            +
             | 
| 3131 | 
            +
              def work
         | 
| 3132 | 
            +
                # Delays: 0s, 0.5s (retry 1), 1.0s (retry 2), 1.5s (retry 3)
         | 
| 3133 | 
            +
                context.records = ExternalAPI.fetch_records
         | 
| 3134 | 
            +
              end
         | 
| 3135 | 
            +
            end
         | 
| 3136 | 
            +
            ```
         | 
| 3137 | 
            +
             | 
| 3138 | 
            +
            ### Symbol References
         | 
| 3139 | 
            +
             | 
| 3140 | 
            +
            Define an instance method for custom delay logic:
         | 
| 3141 | 
            +
             | 
| 3142 | 
            +
            ```ruby
         | 
| 3143 | 
            +
            class SyncInventory < CMDx::Task
         | 
| 3144 | 
            +
              settings retries: 5, retry_jitter: :exponential_backoff
         | 
| 3145 | 
            +
             | 
| 3146 | 
            +
              def work
         | 
| 3147 | 
            +
                context.inventory = InventoryAPI.sync
         | 
| 3148 | 
            +
              end
         | 
| 3149 | 
            +
             | 
| 3150 | 
            +
              private
         | 
| 3151 | 
            +
             | 
| 3152 | 
            +
              def exponential_backoff(current_retry)
         | 
| 3153 | 
            +
                2 ** current_retry # 2s, 4s, 8s, 16s, 32s
         | 
| 3154 | 
            +
              end
         | 
| 3155 | 
            +
            end
         | 
| 3156 | 
            +
            ```
         | 
| 3157 | 
            +
             | 
| 3158 | 
            +
            ### Proc or Lambda
         | 
| 3159 | 
            +
             | 
| 3160 | 
            +
            Pass a proc for inline delay calculations:
         | 
| 3161 | 
            +
             | 
| 3162 | 
            +
            ```ruby
         | 
| 3163 | 
            +
            class PollJobStatus < CMDx::Task
         | 
| 3164 | 
            +
              # Proc
         | 
| 3165 | 
            +
              settings retries: 10, retry_jitter: proc { |retry_count| [retry_count * 0.5, 5.0].min }
         | 
| 3166 | 
            +
             | 
| 3167 | 
            +
              # Lambda
         | 
| 3168 | 
            +
              settings retries: 10, retry_jitter: ->(retry_count) { [retry_count * 0.5, 5.0].min }
         | 
| 3169 | 
            +
             | 
| 3170 | 
            +
              def work
         | 
| 3171 | 
            +
                # Delays: 0.5s, 1.0s, 1.5s, 2.0s, 2.5s, 3.0s, 3.5s, 4.0s, 4.5s, 5.0s (capped)
         | 
| 3172 | 
            +
                context.status = JobAPI.check_status(context.job_id)
         | 
| 3173 | 
            +
              end
         | 
| 3174 | 
            +
            end
         | 
| 3175 | 
            +
            ```
         | 
| 3176 | 
            +
             | 
| 3177 | 
            +
            ### Class or Module
         | 
| 3178 | 
            +
             | 
| 3179 | 
            +
            Implement reusable delay logic in dedicated modules and classes:
         | 
| 3180 | 
            +
             | 
| 3181 | 
            +
            ```ruby
         | 
| 3182 | 
            +
            class ExponentialBackoff
         | 
| 3183 | 
            +
              def call(task, retry_count)
         | 
| 3184 | 
            +
                base_delay = task.context.base_delay || 1.0
         | 
| 3185 | 
            +
                [base_delay * (2 ** retry_count), 60.0].min
         | 
| 3186 | 
            +
              end
         | 
| 3187 | 
            +
            end
         | 
| 3188 | 
            +
             | 
| 3189 | 
            +
            class FetchUserProfile < CMDx::Task
         | 
| 3190 | 
            +
              # Class or Module
         | 
| 3191 | 
            +
              settings retries: 4, retry_jitter: ExponentialBackoff
         | 
| 3192 | 
            +
             | 
| 3193 | 
            +
              # Instance
         | 
| 3194 | 
            +
              settings retries: 4, retry_jitter: ExponentialBackoff.new
         | 
| 3195 | 
            +
             | 
| 3196 | 
            +
              def work
         | 
| 3197 | 
            +
                # Your logic here...
         | 
| 3198 | 
            +
              end
         | 
| 3199 | 
            +
            end
         | 
| 3200 | 
            +
            ```
         | 
| 3133 3201 |  | 
| 3134 3202 | 
             
            # Task Deprecation
         | 
| 3135 3203 |  | 
| 3136 | 
            -
             | 
| 3204 | 
            +
            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.
         | 
| 3137 3205 |  | 
| 3138 3206 | 
             
            ## Modes
         | 
| 3139 3207 |  | 
| 3140 3208 | 
             
            ### Raise
         | 
| 3141 3209 |  | 
| 3142 | 
            -
             | 
| 3210 | 
            +
            Prevent task execution completely. Perfect for tasks that must no longer run.
         | 
| 3211 | 
            +
             | 
| 3212 | 
            +
            !!! warning
         | 
| 3143 3213 |  | 
| 3144 | 
            -
             | 
| 3145 | 
            -
            > Use `:raise` mode carefully in production environments as it will break existing workflows immediately.
         | 
| 3214 | 
            +
                Use `:raise` mode carefully—it will break existing workflows immediately.
         | 
| 3146 3215 |  | 
| 3147 3216 | 
             
            ```ruby
         | 
| 3148 3217 | 
             
            class ProcessObsoleteAPI < CMDx::Task
         | 
| @@ -3159,7 +3228,7 @@ result = ProcessObsoleteAPI.execute | |
| 3159 3228 |  | 
| 3160 3229 | 
             
            ### Log
         | 
| 3161 3230 |  | 
| 3162 | 
            -
             | 
| 3231 | 
            +
            Allow execution while tracking deprecation in logs. Ideal for gradual migrations.
         | 
| 3163 3232 |  | 
| 3164 3233 | 
             
            ```ruby
         | 
| 3165 3234 | 
             
            class ProcessLegacyFormat < CMDx::Task
         | 
| @@ -3182,7 +3251,7 @@ result.successful? #=> true | |
| 3182 3251 |  | 
| 3183 3252 | 
             
            ### Warn
         | 
| 3184 3253 |  | 
| 3185 | 
            -
             | 
| 3254 | 
            +
            Issue Ruby warnings visible during development and testing. Keeps production logs clean while alerting developers.
         | 
| 3186 3255 |  | 
| 3187 3256 | 
             
            ```ruby
         | 
| 3188 3257 | 
             
            class ProcessOldData < CMDx::Task
         | 
| @@ -3276,21 +3345,17 @@ class OutdatedConnector < CMDx::Task | |
| 3276 3345 | 
             
            end
         | 
| 3277 3346 | 
             
            ```
         | 
| 3278 3347 |  | 
| 3279 | 
            -
            ---
         | 
| 3280 | 
            -
             | 
| 3281 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/workflows.md
         | 
| 3282 | 
            -
            ---
         | 
| 3283 | 
            -
             | 
| 3284 3348 | 
             
            # Workflows
         | 
| 3285 3349 |  | 
| 3286 | 
            -
             | 
| 3350 | 
            +
            Compose multiple tasks into powerful, sequential pipelines. Workflows provide a declarative way to build complex business processes with conditional execution, shared context, and flexible error handling.
         | 
| 3287 3351 |  | 
| 3288 3352 | 
             
            ## Declarations
         | 
| 3289 3353 |  | 
| 3290 | 
            -
            Tasks  | 
| 3354 | 
            +
            Tasks run in declaration order (FIFO), sharing a common context across the pipeline.
         | 
| 3355 | 
            +
             | 
| 3356 | 
            +
            !!! warning
         | 
| 3291 3357 |  | 
| 3292 | 
            -
             | 
| 3293 | 
            -
            > Do **NOT** define a `work` method in workflow tasks. The included module automatically provides the execution logic.
         | 
| 3358 | 
            +
                Don't define a `work` method in workflows—the module handles execution automatically.
         | 
| 3294 3359 |  | 
| 3295 3360 | 
             
            ### Task
         | 
| 3296 3361 |  | 
| @@ -3305,15 +3370,17 @@ class OnboardingWorkflow < CMDx::Task | |
| 3305 3370 | 
             
            end
         | 
| 3306 3371 | 
             
            ```
         | 
| 3307 3372 |  | 
| 3308 | 
            -
             | 
| 3309 | 
            -
             | 
| 3373 | 
            +
            !!! tip
         | 
| 3374 | 
            +
             | 
| 3375 | 
            +
                Execute tasks in parallel via the [cmdx-parallel](https://github.com/drexed/cmdx-parallel) gem.
         | 
| 3310 3376 |  | 
| 3311 3377 | 
             
            ### Group
         | 
| 3312 3378 |  | 
| 3313 | 
            -
            Group related tasks  | 
| 3379 | 
            +
            Group related tasks to share configuration:
         | 
| 3314 3380 |  | 
| 3315 | 
            -
             | 
| 3316 | 
            -
             | 
| 3381 | 
            +
            !!! warning "Important"
         | 
| 3382 | 
            +
             | 
| 3383 | 
            +
                Settings and conditionals apply to all tasks in the group.
         | 
| 3317 3384 |  | 
| 3318 3385 | 
             
            ```ruby
         | 
| 3319 3386 | 
             
            class ContentModerationWorkflow < CMDx::Task
         | 
| @@ -3376,9 +3443,7 @@ end | |
| 3376 3443 |  | 
| 3377 3444 | 
             
            ## Halt Behavior
         | 
| 3378 3445 |  | 
| 3379 | 
            -
            By default skipped tasks  | 
| 3380 | 
            -
            This is configurable via global and task level breakpoint settings. Task and group configurations
         | 
| 3381 | 
            -
            can be used together within a workflow.
         | 
| 3446 | 
            +
            By default, skipped tasks don't stop the workflow—they're treated as no-ops. Configure breakpoints globally or per-task to customize this behavior.
         | 
| 3382 3447 |  | 
| 3383 3448 | 
             
            ```ruby
         | 
| 3384 3449 | 
             
            class AnalyticsWorkflow < CMDx::Task
         | 
| @@ -3434,7 +3499,7 @@ end | |
| 3434 3499 |  | 
| 3435 3500 | 
             
            ## Nested Workflows
         | 
| 3436 3501 |  | 
| 3437 | 
            -
             | 
| 3502 | 
            +
            Build hierarchical workflows by composing workflows within workflows:
         | 
| 3438 3503 |  | 
| 3439 3504 | 
             
            ```ruby
         | 
| 3440 3505 | 
             
            class EmailPreparationWorkflow < CMDx::Task
         | 
| @@ -3461,10 +3526,11 @@ end | |
| 3461 3526 |  | 
| 3462 3527 | 
             
            ## Parallel Execution
         | 
| 3463 3528 |  | 
| 3464 | 
            -
             | 
| 3529 | 
            +
            Run tasks concurrently using the [Parallel](https://github.com/grosser/parallel) gem. It automatically uses all available processors for maximum throughput.
         | 
| 3530 | 
            +
             | 
| 3531 | 
            +
            !!! warning
         | 
| 3465 3532 |  | 
| 3466 | 
            -
             | 
| 3467 | 
            -
            > Context cannot be modified during parallel execution. Ensure that all required data is preloaded into the context before parallelization begins.
         | 
| 3533 | 
            +
                Context is read-only during parallel execution. Load all required data beforehand.
         | 
| 3468 3534 |  | 
| 3469 3535 | 
             
            ```ruby
         | 
| 3470 3536 | 
             
            class SendWelcomeNotifications < CMDx::Task
         | 
| @@ -3502,17 +3568,13 @@ class SendNotifications < CMDx::Task | |
| 3502 3568 | 
             
            end
         | 
| 3503 3569 | 
             
            ```
         | 
| 3504 3570 |  | 
| 3505 | 
            -
             | 
| 3506 | 
            -
            > Use **present tense verbs + pluralized noun** for workflow task names, eg: `SendNotifications`, `DownloadFiles`, `ValidateDocuments`
         | 
| 3507 | 
            -
             | 
| 3508 | 
            -
            ---
         | 
| 3571 | 
            +
            !!! tip
         | 
| 3509 3572 |  | 
| 3510 | 
            -
             | 
| 3511 | 
            -
            ---
         | 
| 3573 | 
            +
                Use **present tense verbs + pluralized noun** for workflow task names, eg: `SendNotifications`, `DownloadFiles`, `ValidateDocuments`
         | 
| 3512 3574 |  | 
| 3513 3575 | 
             
            # Tips and Tricks
         | 
| 3514 3576 |  | 
| 3515 | 
            -
             | 
| 3577 | 
            +
            Best practices, patterns, and techniques to build maintainable CMDx applications.
         | 
| 3516 3578 |  | 
| 3517 3579 | 
             
            ## Project Organization
         | 
| 3518 3580 |  | 
| @@ -3556,7 +3618,7 @@ class TokenGeneration < CMDx::Task; end    # ❌ Avoid | |
| 3556 3618 |  | 
| 3557 3619 | 
             
            ### Story Telling
         | 
| 3558 3620 |  | 
| 3559 | 
            -
             | 
| 3621 | 
            +
            Break down complex logic into descriptive methods that read like a narrative:
         | 
| 3560 3622 |  | 
| 3561 3623 | 
             
            ```ruby
         | 
| 3562 3624 | 
             
            class ProcessOrder < CMDx::Task
         | 
| @@ -3588,7 +3650,7 @@ end | |
| 3588 3650 |  | 
| 3589 3651 | 
             
            ### Style Guide
         | 
| 3590 3652 |  | 
| 3591 | 
            -
            Follow  | 
| 3653 | 
            +
            Follow this order for consistent, readable tasks:
         | 
| 3592 3654 |  | 
| 3593 3655 | 
             
            ```ruby
         | 
| 3594 3656 | 
             
            class ExportReport < CMDx::Task
         | 
| @@ -3631,7 +3693,7 @@ end | |
| 3631 3693 |  | 
| 3632 3694 | 
             
            ## Attribute Options
         | 
| 3633 3695 |  | 
| 3634 | 
            -
            Use  | 
| 3696 | 
            +
            Use `with_options` to reduce duplication:
         | 
| 3635 3697 |  | 
| 3636 3698 | 
             
            ```ruby
         | 
| 3637 3699 | 
             
            class ConfigureCompany < CMDx::Task
         | 
| @@ -3657,9 +3719,9 @@ class ConfigureCompany < CMDx::Task | |
| 3657 3719 | 
             
            end
         | 
| 3658 3720 | 
             
            ```
         | 
| 3659 3721 |  | 
| 3660 | 
            -
            ##  | 
| 3722 | 
            +
            ## More Examples
         | 
| 3661 3723 |  | 
| 3662 3724 | 
             
            - [Active Record Query Tagging](https://github.com/drexed/cmdx/blob/main/examples/active_record_query_tagging.md)
         | 
| 3663 3725 | 
             
            - [Paper Trail Whatdunnit](https://github.com/drexed/cmdx/blob/main/examples/paper_trail_whatdunnit.md)
         | 
| 3726 | 
            +
            - [Stoplight Circuit Breaker](https://github.com/drexed/cmdx/blob/main/examples/stoplight_circuit_breaker.md)
         | 
| 3664 3727 |  | 
| 3665 | 
            -
            ---
         |