cmdx 1.9.1 → 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/CHANGELOG.md +10 -0
- data/LLM.md +429 -376
- data/README.md +1 -1
- data/docs/basics/setup.md +17 -0
- data/docs/callbacks.md +1 -1
- data/docs/getting_started.md +13 -2
- 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/configuration.rb +15 -0
- data/lib/cmdx/executor.rb +31 -14
- data/lib/cmdx/version.rb +1 -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,8 +375,9 @@ class ModerateBlogPost < CMDx::Task | |
| 369 375 | 
             
            end
         | 
| 370 376 | 
             
            ```
         | 
| 371 377 |  | 
| 372 | 
            -
             | 
| 373 | 
            -
             | 
| 378 | 
            +
            !!! tip
         | 
| 379 | 
            +
             | 
| 380 | 
            +
                Use **present tense verbs + noun** for task names, eg: `ModerateBlogPost`, `ScheduleAppointment`, `ValidateDocument`
         | 
| 374 381 |  | 
| 375 382 | 
             
            ## Type safety
         | 
| 376 383 |  | 
| @@ -381,18 +388,13 @@ CMDx includes built-in RBS (Ruby Type Signature) inline annotations throughout t | |
| 381 388 | 
             
            - **Self-documenting code** — Clear method signatures and return types
         | 
| 382 389 | 
             
            - **Refactoring confidence** — Type-aware refactoring reduces bugs
         | 
| 383 390 |  | 
| 384 | 
            -
            ---
         | 
| 385 | 
            -
             | 
| 386 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/basics/setup.md
         | 
| 387 | 
            -
            ---
         | 
| 388 | 
            -
             | 
| 389 391 | 
             
            # Basics - Setup
         | 
| 390 392 |  | 
| 391 | 
            -
            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.
         | 
| 392 394 |  | 
| 393 395 | 
             
            ## Structure
         | 
| 394 396 |  | 
| 395 | 
            -
            Tasks inherit from `CMDx::Task` and  | 
| 397 | 
            +
            Tasks need only two things: inherit from `CMDx::Task` and define a `work` method:
         | 
| 396 398 |  | 
| 397 399 | 
             
            ```ruby
         | 
| 398 400 | 
             
            class ValidateDocument < CMDx::Task
         | 
| @@ -402,7 +404,7 @@ class ValidateDocument < CMDx::Task | |
| 402 404 | 
             
            end
         | 
| 403 405 | 
             
            ```
         | 
| 404 406 |  | 
| 405 | 
            -
             | 
| 407 | 
            +
            Without a `work` method, execution raises `CMDx::UndefinedMethodError`.
         | 
| 406 408 |  | 
| 407 409 | 
             
            ```ruby
         | 
| 408 410 | 
             
            class IncompleteTask < CMDx::Task
         | 
| @@ -412,10 +414,25 @@ end | |
| 412 414 | 
             
            IncompleteTask.execute #=> raises CMDx::UndefinedMethodError
         | 
| 413 415 | 
             
            ```
         | 
| 414 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 | 
            +
             | 
| 415 433 | 
             
            ## Inheritance
         | 
| 416 434 |  | 
| 417 | 
            -
             | 
| 418 | 
            -
            Create a base class to share common configuration across tasks:
         | 
| 435 | 
            +
            Share configuration across tasks using inheritance:
         | 
| 419 436 |  | 
| 420 437 | 
             
            ```ruby
         | 
| 421 438 | 
             
            class ApplicationTask < CMDx::Task
         | 
| @@ -441,10 +458,11 @@ end | |
| 441 458 |  | 
| 442 459 | 
             
            ## Lifecycle
         | 
| 443 460 |  | 
| 444 | 
            -
            Tasks follow a predictable  | 
| 461 | 
            +
            Tasks follow a predictable execution pattern:
         | 
| 445 462 |  | 
| 446 | 
            -
             | 
| 447 | 
            -
             | 
| 463 | 
            +
            !!! danger "Caution"
         | 
| 464 | 
            +
             | 
| 465 | 
            +
                Tasks are single-use objects. Once executed, they're frozen and immutable.
         | 
| 448 466 |  | 
| 449 467 | 
             
            | Stage | State | Status | Description |
         | 
| 450 468 | 
             
            |-------|-------|--------|-------------|
         | 
| @@ -453,20 +471,15 @@ Tasks follow a predictable call pattern with specific states and statuses: | |
| 453 471 | 
             
            | **Execution** | `executing` | `success`/`failed`/`skipped` | `work` method runs |
         | 
| 454 472 | 
             
            | **Completion** | `executed` | `success`/`failed`/`skipped` | Result finalized |
         | 
| 455 473 | 
             
            | **Freezing** | `executed` | `success`/`failed`/`skipped` | Task becomes immutable |
         | 
| 456 | 
            -
             | 
| 457 | 
            -
            ---
         | 
| 458 | 
            -
             | 
| 459 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/basics/execution.md
         | 
| 460 | 
            -
            ---
         | 
| 474 | 
            +
            | **Rollback** | `executed` | `failed`/`skipped` | Work undone |
         | 
| 461 475 |  | 
| 462 476 | 
             
            # Basics - Execution
         | 
| 463 477 |  | 
| 464 | 
            -
             | 
| 478 | 
            +
            CMDx offers two execution methods with different error handling approaches. Choose based on your needs: safe result handling or exception-based control flow.
         | 
| 465 479 |  | 
| 466 | 
            -
            ## Methods | 
| 480 | 
            +
            ## Execution Methods
         | 
| 467 481 |  | 
| 468 | 
            -
             | 
| 469 | 
            -
            Create a new instance for subsequent executions.
         | 
| 482 | 
            +
            Both methods return results, but handle failures differently:
         | 
| 470 483 |  | 
| 471 484 | 
             
            | Method | Returns | Exceptions | Use Case |
         | 
| 472 485 | 
             
            |--------|---------|------------|----------|
         | 
| @@ -475,10 +488,7 @@ Create a new instance for subsequent executions. | |
| 475 488 |  | 
| 476 489 | 
             
            ## Non-bang Execution
         | 
| 477 490 |  | 
| 478 | 
            -
             | 
| 479 | 
            -
            This is the preferred method for most use cases.
         | 
| 480 | 
            -
             | 
| 481 | 
            -
            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.
         | 
| 482 492 |  | 
| 483 493 | 
             
            ```ruby
         | 
| 484 494 | 
             
            result = CreateAccount.execute(email: "user@example.com")
         | 
| @@ -496,23 +506,22 @@ result.status           #=> "success" | |
| 496 506 |  | 
| 497 507 | 
             
            ## Bang Execution
         | 
| 498 508 |  | 
| 499 | 
            -
             | 
| 500 | 
            -
             | 
| 501 | 
            -
            It raises any unhandled non-fault exceptions caused during execution.
         | 
| 509 | 
            +
            Raises `CMDx::Fault` exceptions on failure or skip. Returns results only on success.
         | 
| 502 510 |  | 
| 503 511 | 
             
            | Exception | Raised When |
         | 
| 504 512 | 
             
            |-----------|-------------|
         | 
| 505 513 | 
             
            | `CMDx::FailFault` | Task execution fails |
         | 
| 506 514 | 
             
            | `CMDx::SkipFault` | Task execution is skipped |
         | 
| 507 515 |  | 
| 508 | 
            -
             | 
| 509 | 
            -
             | 
| 516 | 
            +
            !!! warning "Important"
         | 
| 517 | 
            +
             | 
| 518 | 
            +
                Behavior depends on `task_breakpoints` or `workflow_breakpoints` config. Default: only failures raise exceptions.
         | 
| 510 519 |  | 
| 511 520 | 
             
            ```ruby
         | 
| 512 521 | 
             
            begin
         | 
| 513 522 | 
             
              result = CreateAccount.execute!(email: "user@example.com")
         | 
| 514 523 | 
             
              SendWelcomeEmail.execute(result.context)
         | 
| 515 | 
            -
            rescue CMDx:: | 
| 524 | 
            +
            rescue CMDx::FailFault => e
         | 
| 516 525 | 
             
              ScheduleAccountRetryJob.perform_later(e.result.context.email)
         | 
| 517 526 | 
             
            rescue CMDx::SkipFault => e
         | 
| 518 527 | 
             
              Rails.logger.info("Account creation skipped: #{e.result.reason}")
         | 
| @@ -534,7 +543,7 @@ task.id                      #=> "abc123..." (unique task ID) | |
| 534 543 | 
             
            task.context.email           #=> "user@example.com"
         | 
| 535 544 | 
             
            task.context.send_welcome    #=> true
         | 
| 536 545 | 
             
            task.result.state            #=> "initialized"
         | 
| 537 | 
            -
            result.status | 
| 546 | 
            +
            task.result.status           #=> "success"
         | 
| 538 547 |  | 
| 539 548 | 
             
            # Manual execution
         | 
| 540 549 | 
             
            task.execute
         | 
| @@ -559,19 +568,15 @@ result.chain        #=> Task execution chain | |
| 559 568 | 
             
            # Context and metadata
         | 
| 560 569 | 
             
            result.context      #=> Context with all task data
         | 
| 561 570 | 
             
            result.metadata     #=> Hash with execution metadata
         | 
| 562 | 
            -
             | 
| 563 | 
            -
            ---
         | 
| 564 | 
            -
             | 
| 565 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/basics/context.md
         | 
| 566 | 
            -
            ---
         | 
| 571 | 
            +
            ```
         | 
| 567 572 |  | 
| 568 573 | 
             
            # Basics - Context
         | 
| 569 574 |  | 
| 570 | 
            -
             | 
| 575 | 
            +
            Context is your data container for inputs, intermediate values, and outputs. It makes sharing data between tasks effortless.
         | 
| 571 576 |  | 
| 572 577 | 
             
            ## Assigning Data
         | 
| 573 578 |  | 
| 574 | 
            -
            Context  | 
| 579 | 
            +
            Context automatically captures all task inputs, normalizing keys to symbols:
         | 
| 575 580 |  | 
| 576 581 | 
             
            ```ruby
         | 
| 577 582 | 
             
            # Direct execution
         | 
| @@ -581,12 +586,13 @@ CalculateShipping.execute(weight: 2.5, destination: "CA") | |
| 581 586 | 
             
            CalculateShipping.new(weight: 2.5, "destination" => "CA")
         | 
| 582 587 | 
             
            ```
         | 
| 583 588 |  | 
| 584 | 
            -
             | 
| 585 | 
            -
             | 
| 589 | 
            +
            !!! warning "Important"
         | 
| 590 | 
            +
             | 
| 591 | 
            +
                String keys convert to symbols automatically. Prefer symbols for consistency.
         | 
| 586 592 |  | 
| 587 593 | 
             
            ## Accessing Data
         | 
| 588 594 |  | 
| 589 | 
            -
             | 
| 595 | 
            +
            Access context data using method notation, hash keys, or safe accessors:
         | 
| 590 596 |  | 
| 591 597 | 
             
            ```ruby
         | 
| 592 598 | 
             
            class CalculateShipping < CMDx::Task
         | 
| @@ -609,8 +615,9 @@ class CalculateShipping < CMDx::Task | |
| 609 615 | 
             
            end
         | 
| 610 616 | 
             
            ```
         | 
| 611 617 |  | 
| 612 | 
            -
             | 
| 613 | 
            -
             | 
| 618 | 
            +
            !!! warning "Important"
         | 
| 619 | 
            +
             | 
| 620 | 
            +
                Undefined attributes return `nil` instead of raising errors—perfect for optional data.
         | 
| 614 621 |  | 
| 615 622 | 
             
            ## Modifying Context
         | 
| 616 623 |  | 
| @@ -651,12 +658,13 @@ class CalculateShipping < CMDx::Task | |
| 651 658 | 
             
            end
         | 
| 652 659 | 
             
            ```
         | 
| 653 660 |  | 
| 654 | 
            -
             | 
| 655 | 
            -
             | 
| 661 | 
            +
            !!! tip
         | 
| 662 | 
            +
             | 
| 663 | 
            +
                Use context for both input values and intermediate results. This creates natural data flow through your task execution pipeline.
         | 
| 656 664 |  | 
| 657 665 | 
             
            ## Data Sharing
         | 
| 658 666 |  | 
| 659 | 
            -
             | 
| 667 | 
            +
            Share context across tasks for seamless data flow:
         | 
| 660 668 |  | 
| 661 669 | 
             
            ```ruby
         | 
| 662 670 | 
             
            # During execution
         | 
| @@ -684,21 +692,17 @@ result = CalculateShipping.execute(destination: "New York, NY") | |
| 684 692 | 
             
            CreateShippingLabel.execute(result)
         | 
| 685 693 | 
             
            ```
         | 
| 686 694 |  | 
| 687 | 
            -
            ---
         | 
| 688 | 
            -
             | 
| 689 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/basics/chain.md
         | 
| 690 | 
            -
            ---
         | 
| 691 | 
            -
             | 
| 692 695 | 
             
            # Basics - Chain
         | 
| 693 696 |  | 
| 694 | 
            -
            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.
         | 
| 695 698 |  | 
| 696 699 | 
             
            ## Management
         | 
| 697 700 |  | 
| 698 | 
            -
            Each thread maintains its own chain  | 
| 701 | 
            +
            Each thread maintains its own isolated chain using thread-local storage.
         | 
| 702 | 
            +
             | 
| 703 | 
            +
            !!! warning
         | 
| 699 704 |  | 
| 700 | 
            -
             | 
| 701 | 
            -
            > Chain operations are thread-local. Never share chain references across threads as this can lead to race conditions and data corruption.
         | 
| 705 | 
            +
                Chains are thread-local. Don't share chain references across threads—it causes race conditions.
         | 
| 702 706 |  | 
| 703 707 | 
             
            ```ruby
         | 
| 704 708 | 
             
            # Thread A
         | 
| @@ -720,10 +724,11 @@ CMDx::Chain.clear    #=> Clears current thread's chain | |
| 720 724 |  | 
| 721 725 | 
             
            ## Links
         | 
| 722 726 |  | 
| 723 | 
            -
             | 
| 727 | 
            +
            Tasks automatically create or join the current thread's chain:
         | 
| 728 | 
            +
             | 
| 729 | 
            +
            !!! warning "Important"
         | 
| 724 730 |  | 
| 725 | 
            -
             | 
| 726 | 
            -
            > 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.
         | 
| 727 732 |  | 
| 728 733 | 
             
            ```ruby
         | 
| 729 734 | 
             
            class ImportDataset < CMDx::Task
         | 
| @@ -746,7 +751,7 @@ end | |
| 746 751 |  | 
| 747 752 | 
             
            ## Inheritance
         | 
| 748 753 |  | 
| 749 | 
            -
             | 
| 754 | 
            +
            Subtasks automatically inherit the current thread's chain, building a unified execution trail:
         | 
| 750 755 |  | 
| 751 756 | 
             
            ```ruby
         | 
| 752 757 | 
             
            class ImportDataset < CMDx::Task
         | 
| @@ -771,10 +776,11 @@ chain.results.map { |r| r.task.class } | |
| 771 776 |  | 
| 772 777 | 
             
            ## Structure
         | 
| 773 778 |  | 
| 774 | 
            -
            Chains  | 
| 779 | 
            +
            Chains expose comprehensive execution information:
         | 
| 775 780 |  | 
| 776 | 
            -
             | 
| 777 | 
            -
             | 
| 781 | 
            +
            !!! warning "Important"
         | 
| 782 | 
            +
             | 
| 783 | 
            +
                Chain state reflects the first (outermost) task result. Subtasks maintain their own states.
         | 
| 778 784 |  | 
| 779 785 | 
             
            ```ruby
         | 
| 780 786 | 
             
            result = ImportDataset.execute(dataset_id: 456)
         | 
| @@ -795,21 +801,17 @@ chain.results.each_with_index do |result, index| | |
| 795 801 | 
             
            end
         | 
| 796 802 | 
             
            ```
         | 
| 797 803 |  | 
| 798 | 
            -
            ---
         | 
| 799 | 
            -
             | 
| 800 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/interruptions/halt.md
         | 
| 801 | 
            -
            ---
         | 
| 802 | 
            -
             | 
| 803 804 | 
             
            # Interruptions - Halt
         | 
| 804 805 |  | 
| 805 | 
            -
             | 
| 806 | 
            +
            Stop task execution intentionally using `skip!` or `fail!`. Both methods signal clear intent about why execution stopped.
         | 
| 806 807 |  | 
| 807 808 | 
             
            ## Skipping
         | 
| 808 809 |  | 
| 809 | 
            -
            `skip!`  | 
| 810 | 
            +
            Use `skip!` when the task doesn't need to run. It's a no-op, not an error.
         | 
| 811 | 
            +
             | 
| 812 | 
            +
            !!! warning "Important"
         | 
| 810 813 |  | 
| 811 | 
            -
             | 
| 812 | 
            -
            > 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.
         | 
| 813 815 |  | 
| 814 816 | 
             
            ```ruby
         | 
| 815 817 | 
             
            class ProcessInventory < CMDx::Task
         | 
| @@ -844,7 +846,7 @@ result.reason #=> "Warehouse closed" | |
| 844 846 |  | 
| 845 847 | 
             
            ## Failing
         | 
| 846 848 |  | 
| 847 | 
            -
            `fail!`  | 
| 849 | 
            +
            Use `fail!` when the task can't complete successfully. It signals controlled, intentional failure:
         | 
| 848 850 |  | 
| 849 851 | 
             
            ```ruby
         | 
| 850 852 | 
             
            class ProcessRefund < CMDx::Task
         | 
| @@ -879,7 +881,7 @@ result.reason #=> "Refund period has expired" | |
| 879 881 |  | 
| 880 882 | 
             
            ## Metadata Enrichment
         | 
| 881 883 |  | 
| 882 | 
            -
             | 
| 884 | 
            +
            Enrich halt calls with metadata for better debugging and error handling:
         | 
| 883 885 |  | 
| 884 886 | 
             
            ```ruby
         | 
| 885 887 | 
             
            class ProcessRenewal < CMDx::Task
         | 
| @@ -979,7 +981,7 @@ end | |
| 979 981 |  | 
| 980 982 | 
             
            ## Best Practices
         | 
| 981 983 |  | 
| 982 | 
            -
            Always  | 
| 984 | 
            +
            Always provide a reason for better debugging and clearer exception messages:
         | 
| 983 985 |  | 
| 984 986 | 
             
            ```ruby
         | 
| 985 987 | 
             
            # Good: Clear, specific reason
         | 
| @@ -997,10 +999,11 @@ fail! #=> "Unspecified" | |
| 997 999 |  | 
| 998 1000 | 
             
            ## Manual Errors
         | 
| 999 1001 |  | 
| 1000 | 
            -
             | 
| 1002 | 
            +
            For rare cases, manually add errors before halting:
         | 
| 1001 1003 |  | 
| 1002 | 
            -
             | 
| 1003 | 
            -
             | 
| 1004 | 
            +
            !!! warning "Important"
         | 
| 1005 | 
            +
             | 
| 1006 | 
            +
                Manual errors don't stop execution—you still need to call `fail!` or `skip!`.
         | 
| 1004 1007 |  | 
| 1005 1008 | 
             
            ```ruby
         | 
| 1006 1009 | 
             
            class ProcessRenewal < CMDx::Task
         | 
| @@ -1015,14 +1018,9 @@ class ProcessRenewal < CMDx::Task | |
| 1015 1018 | 
             
            end
         | 
| 1016 1019 | 
             
            ```
         | 
| 1017 1020 |  | 
| 1018 | 
            -
            ---
         | 
| 1019 | 
            -
             | 
| 1020 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/interruptions/faults.md
         | 
| 1021 | 
            -
            ---
         | 
| 1022 | 
            -
             | 
| 1023 1021 | 
             
            # Interruptions - Faults
         | 
| 1024 1022 |  | 
| 1025 | 
            -
            Faults are  | 
| 1023 | 
            +
            Faults are exceptions raised by `execute!` when tasks halt. They carry rich context about execution state, enabling sophisticated error handling patterns.
         | 
| 1026 1024 |  | 
| 1027 1025 | 
             
            ## Fault Types
         | 
| 1028 1026 |  | 
| @@ -1032,8 +1030,9 @@ Faults are exception mechanisms that halt task execution via `skip!` and `fail!` | |
| 1032 1030 | 
             
            | `CMDx::SkipFault` | `skip!` method | Optional processing, early returns |
         | 
| 1033 1031 | 
             
            | `CMDx::FailFault` | `fail!` method | Validation errors, processing failures |
         | 
| 1034 1032 |  | 
| 1035 | 
            -
             | 
| 1036 | 
            -
             | 
| 1033 | 
            +
            !!! warning "Important"
         | 
| 1034 | 
            +
             | 
| 1035 | 
            +
                All faults inherit from `CMDx::Fault` and expose result, task, context, and chain data.
         | 
| 1037 1036 |  | 
| 1038 1037 | 
             
            ## Fault Handling
         | 
| 1039 1038 |  | 
| @@ -1054,7 +1053,7 @@ end | |
| 1054 1053 |  | 
| 1055 1054 | 
             
            ## Data Access
         | 
| 1056 1055 |  | 
| 1057 | 
            -
             | 
| 1056 | 
            +
            Access rich execution data from fault exceptions:
         | 
| 1058 1057 |  | 
| 1059 1058 | 
             
            ```ruby
         | 
| 1060 1059 | 
             
            begin
         | 
| @@ -1083,7 +1082,7 @@ end | |
| 1083 1082 |  | 
| 1084 1083 | 
             
            ### Task-Specific Matching
         | 
| 1085 1084 |  | 
| 1086 | 
            -
             | 
| 1085 | 
            +
            Handle faults only from specific tasks using `for?`:
         | 
| 1087 1086 |  | 
| 1088 1087 | 
             
            ```ruby
         | 
| 1089 1088 | 
             
            begin
         | 
| @@ -1113,7 +1112,7 @@ end | |
| 1113 1112 |  | 
| 1114 1113 | 
             
            ## Fault Propagation
         | 
| 1115 1114 |  | 
| 1116 | 
            -
             | 
| 1115 | 
            +
            Propagate failures with `throw!` to preserve context and maintain the error chain:
         | 
| 1117 1116 |  | 
| 1118 1117 | 
             
            ### Basic Propagation
         | 
| 1119 1118 |  | 
| @@ -1160,7 +1159,7 @@ end | |
| 1160 1159 |  | 
| 1161 1160 | 
             
            ## Chain Analysis
         | 
| 1162 1161 |  | 
| 1163 | 
            -
             | 
| 1162 | 
            +
            Trace fault origins and propagation through the execution chain:
         | 
| 1164 1163 |  | 
| 1165 1164 | 
             
            ```ruby
         | 
| 1166 1165 | 
             
            result = DocumentWorkflow.execute(invalid_data)
         | 
| @@ -1189,23 +1188,19 @@ if result.failed? | |
| 1189 1188 | 
             
            end
         | 
| 1190 1189 | 
             
            ```
         | 
| 1191 1190 |  | 
| 1192 | 
            -
            ---
         | 
| 1193 | 
            -
             | 
| 1194 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/interruptions/exceptions.md
         | 
| 1195 | 
            -
            ---
         | 
| 1196 | 
            -
             | 
| 1197 1191 | 
             
            # Interruptions - Exceptions
         | 
| 1198 1192 |  | 
| 1199 | 
            -
             | 
| 1193 | 
            +
            Exception handling differs between `execute` and `execute!`. Choose the method that matches your error handling strategy.
         | 
| 1200 1194 |  | 
| 1201 1195 | 
             
            ## Exception Handling
         | 
| 1202 1196 |  | 
| 1203 | 
            -
             | 
| 1204 | 
            -
             | 
| 1197 | 
            +
            !!! warning "Important"
         | 
| 1198 | 
            +
             | 
| 1199 | 
            +
                Prefer `skip!` and `fail!` over raising exceptions—they signal intent more clearly.
         | 
| 1205 1200 |  | 
| 1206 1201 | 
             
            ### Non-bang execution
         | 
| 1207 1202 |  | 
| 1208 | 
            -
             | 
| 1203 | 
            +
            Captures all exceptions and returns them as failed results:
         | 
| 1209 1204 |  | 
| 1210 1205 | 
             
            ```ruby
         | 
| 1211 1206 | 
             
            class CompressDocument < CMDx::Task
         | 
| @@ -1223,12 +1218,13 @@ result.reason   #=> "[ActiveRecord::NotFoundError] record not found" | |
| 1223 1218 | 
             
            result.cause    #=> <ActiveRecord::NotFoundError>
         | 
| 1224 1219 | 
             
            ```
         | 
| 1225 1220 |  | 
| 1226 | 
            -
             | 
| 1227 | 
            -
             | 
| 1221 | 
            +
            !!! note
         | 
| 1222 | 
            +
             | 
| 1223 | 
            +
                Use `exception_handler` with `execute` to send exceptions to APM tools before they become failed results.
         | 
| 1228 1224 |  | 
| 1229 1225 | 
             
            ### Bang execution
         | 
| 1230 1226 |  | 
| 1231 | 
            -
             | 
| 1227 | 
            +
            Lets exceptions propagate naturally for standard Ruby error handling:
         | 
| 1232 1228 |  | 
| 1233 1229 | 
             
            ```ruby
         | 
| 1234 1230 | 
             
            class CompressDocument < CMDx::Task
         | 
| @@ -1245,21 +1241,17 @@ rescue ActiveRecord::NotFoundError => e | |
| 1245 1241 | 
             
            end
         | 
| 1246 1242 | 
             
            ```
         | 
| 1247 1243 |  | 
| 1248 | 
            -
            ---
         | 
| 1249 | 
            -
             | 
| 1250 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/outcomes/result.md
         | 
| 1251 | 
            -
            ---
         | 
| 1252 | 
            -
             | 
| 1253 1244 | 
             
            # Outcomes - Result
         | 
| 1254 1245 |  | 
| 1255 | 
            -
             | 
| 1246 | 
            +
            Results are your window into task execution. They expose everything: outcome, state, timing, context, and metadata.
         | 
| 1256 1247 |  | 
| 1257 1248 | 
             
            ## Result Attributes
         | 
| 1258 1249 |  | 
| 1259 | 
            -
             | 
| 1250 | 
            +
            Access essential execution information:
         | 
| 1251 | 
            +
             | 
| 1252 | 
            +
            !!! warning "Important"
         | 
| 1260 1253 |  | 
| 1261 | 
            -
             | 
| 1262 | 
            -
            > Result objects are immutable after task execution completes and reflect the final state.
         | 
| 1254 | 
            +
                Results are immutable after execution completes.
         | 
| 1263 1255 |  | 
| 1264 1256 | 
             
            ```ruby
         | 
| 1265 1257 | 
             
            result = BuildApplication.execute(version: "1.2.3")
         | 
| @@ -1281,7 +1273,7 @@ result.metadata #=> { error_code: "BUILD_TOOL.NOT_FOUND" } | |
| 1281 1273 |  | 
| 1282 1274 | 
             
            ## Lifecycle Information
         | 
| 1283 1275 |  | 
| 1284 | 
            -
             | 
| 1276 | 
            +
            Check execution state and status with predicate methods:
         | 
| 1285 1277 |  | 
| 1286 1278 | 
             
            ```ruby
         | 
| 1287 1279 | 
             
            result = BuildApplication.execute(version: "1.2.3")
         | 
| @@ -1303,7 +1295,7 @@ result.bad?         #=> false (skipped or failed) | |
| 1303 1295 |  | 
| 1304 1296 | 
             
            ## Outcome Analysis
         | 
| 1305 1297 |  | 
| 1306 | 
            -
             | 
| 1298 | 
            +
            Get a unified outcome string combining state and status:
         | 
| 1307 1299 |  | 
| 1308 1300 | 
             
            ```ruby
         | 
| 1309 1301 | 
             
            result = BuildApplication.execute(version: "1.2.3")
         | 
| @@ -1313,7 +1305,7 @@ result.outcome #=> "success" (state and status) | |
| 1313 1305 |  | 
| 1314 1306 | 
             
            ## Chain Analysis
         | 
| 1315 1307 |  | 
| 1316 | 
            -
             | 
| 1308 | 
            +
            Trace fault origins and propagation:
         | 
| 1317 1309 |  | 
| 1318 1310 | 
             
            ```ruby
         | 
| 1319 1311 | 
             
            result = DeploymentWorkflow.execute(app_name: "webapp")
         | 
| @@ -1354,7 +1346,7 @@ result.chain.results[result.index] == result #=> true | |
| 1354 1346 |  | 
| 1355 1347 | 
             
            ## Block Yield
         | 
| 1356 1348 |  | 
| 1357 | 
            -
             | 
| 1349 | 
            +
            Execute code with direct result access:
         | 
| 1358 1350 |  | 
| 1359 1351 | 
             
            ```ruby
         | 
| 1360 1352 | 
             
            BuildApplication.execute(version: "1.2.3") do |result|
         | 
| @@ -1370,7 +1362,7 @@ end | |
| 1370 1362 |  | 
| 1371 1363 | 
             
            ## Handlers
         | 
| 1372 1364 |  | 
| 1373 | 
            -
             | 
| 1365 | 
            +
            Handle outcomes with functional-style methods. Handlers return the result for chaining:
         | 
| 1374 1366 |  | 
| 1375 1367 | 
             
            ```ruby
         | 
| 1376 1368 | 
             
            result = BuildApplication.execute(version: "1.2.3")
         | 
| @@ -1394,10 +1386,11 @@ result | |
| 1394 1386 |  | 
| 1395 1387 | 
             
            ## Pattern Matching
         | 
| 1396 1388 |  | 
| 1397 | 
            -
             | 
| 1389 | 
            +
            Use Ruby 3.0+ pattern matching for elegant outcome handling:
         | 
| 1390 | 
            +
             | 
| 1391 | 
            +
            !!! warning "Important"
         | 
| 1398 1392 |  | 
| 1399 | 
            -
             | 
| 1400 | 
            -
            > Pattern matching requires Ruby 3.0+
         | 
| 1393 | 
            +
                Pattern matching works with both array and hash deconstruction.
         | 
| 1401 1394 |  | 
| 1402 1395 | 
             
            ### Array Pattern
         | 
| 1403 1396 |  | 
| @@ -1442,17 +1435,9 @@ in { runtime: time } if time > performance_threshold | |
| 1442 1435 | 
             
            end
         | 
| 1443 1436 | 
             
            ```
         | 
| 1444 1437 |  | 
| 1445 | 
            -
            ---
         | 
| 1446 | 
            -
             | 
| 1447 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/outcomes/states.md
         | 
| 1448 | 
            -
            ---
         | 
| 1449 | 
            -
             | 
| 1450 1438 | 
             
            # Outcomes - States
         | 
| 1451 1439 |  | 
| 1452 | 
            -
            States  | 
| 1453 | 
            -
            the progress of tasks through their complete execution journey. States provide
         | 
| 1454 | 
            -
            insight into where a task is in its lifecycle and enable lifecycle-based
         | 
| 1455 | 
            -
            decision making and monitoring.
         | 
| 1440 | 
            +
            States track where a task is in its execution lifecycle—from creation through completion or interruption.
         | 
| 1456 1441 |  | 
| 1457 1442 | 
             
            ## Definitions
         | 
| 1458 1443 |  | 
| @@ -1476,8 +1461,9 @@ State-Status combinations: | |
| 1476 1461 |  | 
| 1477 1462 | 
             
            ## Transitions
         | 
| 1478 1463 |  | 
| 1479 | 
            -
             | 
| 1480 | 
            -
             | 
| 1464 | 
            +
            !!! danger "Caution"
         | 
| 1465 | 
            +
             | 
| 1466 | 
            +
                States are managed automatically—never modify them manually.
         | 
| 1481 1467 |  | 
| 1482 1468 | 
             
            ```ruby
         | 
| 1483 1469 | 
             
            # Valid state transition flow
         | 
| @@ -1504,7 +1490,7 @@ result.executed?    #=> true (complete OR interrupted) | |
| 1504 1490 |  | 
| 1505 1491 | 
             
            ## Handlers
         | 
| 1506 1492 |  | 
| 1507 | 
            -
             | 
| 1493 | 
            +
            Handle lifecycle events with state-based handlers. Use `handle_executed` for cleanup that runs regardless of outcome:
         | 
| 1508 1494 |  | 
| 1509 1495 | 
             
            ```ruby
         | 
| 1510 1496 | 
             
            result = ProcessVideoUpload.execute
         | 
| @@ -1516,14 +1502,9 @@ result | |
| 1516 1502 | 
             
              .handle_executed { |result| log_upload_metrics(result) }
         | 
| 1517 1503 | 
             
            ```
         | 
| 1518 1504 |  | 
| 1519 | 
            -
            ---
         | 
| 1520 | 
            -
             | 
| 1521 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/outcomes/statuses.md
         | 
| 1522 | 
            -
            ---
         | 
| 1523 | 
            -
             | 
| 1524 1505 | 
             
            # Outcomes - Statuses
         | 
| 1525 1506 |  | 
| 1526 | 
            -
            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.
         | 
| 1527 1508 |  | 
| 1528 1509 | 
             
            ## Definitions
         | 
| 1529 1510 |  | 
| @@ -1535,8 +1516,9 @@ Statuses represent the business outcome of task execution logic, indicating how | |
| 1535 1516 |  | 
| 1536 1517 | 
             
            ## Transitions
         | 
| 1537 1518 |  | 
| 1538 | 
            -
             | 
| 1539 | 
            -
             | 
| 1519 | 
            +
            !!! warning "Important"
         | 
| 1520 | 
            +
             | 
| 1521 | 
            +
                Status transitions are final and unidirectional. Once skipped or failed, tasks can't return to success.
         | 
| 1540 1522 |  | 
| 1541 1523 | 
             
            ```ruby
         | 
| 1542 1524 | 
             
            # Valid status transitions
         | 
| @@ -1569,7 +1551,7 @@ result.bad?     #=> true if skipped OR failed (not success) | |
| 1569 1551 |  | 
| 1570 1552 | 
             
            ## Handlers
         | 
| 1571 1553 |  | 
| 1572 | 
            -
             | 
| 1554 | 
            +
            Branch business logic with status-based handlers. Use `handle_good` and `handle_bad` for success/skip vs failed outcomes:
         | 
| 1573 1555 |  | 
| 1574 1556 | 
             
            ```ruby
         | 
| 1575 1557 | 
             
            result = ProcessNotification.execute
         | 
| @@ -1586,19 +1568,15 @@ result | |
| 1586 1568 | 
             
              .handle_bad { |result| track_delivery_failure(result) }
         | 
| 1587 1569 | 
             
            ```
         | 
| 1588 1570 |  | 
| 1589 | 
            -
            ---
         | 
| 1590 | 
            -
             | 
| 1591 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/attributes/definitions.md
         | 
| 1592 | 
            -
            ---
         | 
| 1593 | 
            -
             | 
| 1594 1571 | 
             
            # Attributes - Definitions
         | 
| 1595 1572 |  | 
| 1596 | 
            -
            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.
         | 
| 1597 1574 |  | 
| 1598 1575 | 
             
            ## Declarations
         | 
| 1599 1576 |  | 
| 1600 | 
            -
             | 
| 1601 | 
            -
             | 
| 1577 | 
            +
            !!! tip
         | 
| 1578 | 
            +
             | 
| 1579 | 
            +
                Prefer using the `required` and `optional` alias for `attributes` for brevity and to clearly signal intent.
         | 
| 1602 1580 |  | 
| 1603 1581 | 
             
            ### Optional
         | 
| 1604 1582 |  | 
| @@ -1667,7 +1645,7 @@ PublishArticle.execute( | |
| 1667 1645 |  | 
| 1668 1646 | 
             
            ## Sources
         | 
| 1669 1647 |  | 
| 1670 | 
            -
            Attributes  | 
| 1648 | 
            +
            Attributes read from any accessible object—not just context. Use sources to pull data from models, services, or any callable:
         | 
| 1671 1649 |  | 
| 1672 1650 | 
             
            ### Context
         | 
| 1673 1651 |  | 
| @@ -1747,10 +1725,11 @@ end | |
| 1747 1725 |  | 
| 1748 1726 | 
             
            ## Nesting
         | 
| 1749 1727 |  | 
| 1750 | 
            -
             | 
| 1728 | 
            +
            Build complex structures with nested attributes. Children inherit their parent as source and support all attribute options:
         | 
| 1751 1729 |  | 
| 1752 | 
            -
             | 
| 1753 | 
            -
             | 
| 1730 | 
            +
            !!! note
         | 
| 1731 | 
            +
             | 
| 1732 | 
            +
                Nested attributes support all features: naming, coercions, validations, defaults, and more.
         | 
| 1754 1733 |  | 
| 1755 1734 | 
             
            ```ruby
         | 
| 1756 1735 | 
             
            class ConfigureServer < CMDx::Task
         | 
| @@ -1803,15 +1782,17 @@ ConfigureServer.execute( | |
| 1803 1782 | 
             
            )
         | 
| 1804 1783 | 
             
            ```
         | 
| 1805 1784 |  | 
| 1806 | 
            -
             | 
| 1807 | 
            -
             | 
| 1785 | 
            +
            !!! warning "Important"
         | 
| 1786 | 
            +
             | 
| 1787 | 
            +
                Child requirements only apply when the parent is provided—perfect for optional structures.
         | 
| 1808 1788 |  | 
| 1809 1789 | 
             
            ## Error Handling
         | 
| 1810 1790 |  | 
| 1811 | 
            -
             | 
| 1791 | 
            +
            Validation failures provide detailed, structured error messages:
         | 
| 1792 | 
            +
             | 
| 1793 | 
            +
            !!! note
         | 
| 1812 1794 |  | 
| 1813 | 
            -
             | 
| 1814 | 
            -
            > 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.
         | 
| 1815 1796 |  | 
| 1816 1797 | 
             
            ```ruby
         | 
| 1817 1798 | 
             
            class ConfigureServer < CMDx::Task
         | 
| @@ -1861,17 +1842,13 @@ result.metadata #=> { | |
| 1861 1842 | 
             
                            #   }
         | 
| 1862 1843 | 
             
            ```
         | 
| 1863 1844 |  | 
| 1864 | 
            -
            ---
         | 
| 1865 | 
            -
             | 
| 1866 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/attributes/naming.md
         | 
| 1867 | 
            -
            ---
         | 
| 1868 | 
            -
             | 
| 1869 1845 | 
             
            # Attributes - Naming
         | 
| 1870 1846 |  | 
| 1871 | 
            -
             | 
| 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
         | 
| 1872 1850 |  | 
| 1873 | 
            -
             | 
| 1874 | 
            -
            > 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.
         | 
| 1875 1852 |  | 
| 1876 1853 | 
             
            ## Prefix
         | 
| 1877 1854 |  | 
| @@ -1934,16 +1911,11 @@ end | |
| 1934 1911 | 
             
            ScheduleMaintenance.execute(scheduled_at: DateTime.new(2024, 12, 15, 2, 0, 0))
         | 
| 1935 1912 | 
             
            ```
         | 
| 1936 1913 |  | 
| 1937 | 
            -
            ---
         | 
| 1938 | 
            -
             | 
| 1939 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/attributes/coercions.md
         | 
| 1940 | 
            -
            ---
         | 
| 1941 | 
            -
             | 
| 1942 1914 | 
             
            # Attributes - Coercions
         | 
| 1943 1915 |  | 
| 1944 | 
            -
             | 
| 1916 | 
            +
            Automatically convert inputs to expected types. Coercions handle everything from simple string-to-integer conversions to JSON parsing.
         | 
| 1945 1917 |  | 
| 1946 | 
            -
             | 
| 1918 | 
            +
            See [Global Configuration](https://github.com/drexed/cmdx/blob/main/docs/getting_started.md#coercions) for custom coercion setup.
         | 
| 1947 1919 |  | 
| 1948 1920 | 
             
            ## Usage
         | 
| 1949 1921 |  | 
| @@ -1974,8 +1946,9 @@ ParseMetrics.execute( | |
| 1974 1946 | 
             
            )
         | 
| 1975 1947 | 
             
            ```
         | 
| 1976 1948 |  | 
| 1977 | 
            -
             | 
| 1978 | 
            -
             | 
| 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.
         | 
| 1979 1952 |  | 
| 1980 1953 | 
             
            ## Built-in Coercions
         | 
| 1981 1954 |  | 
| @@ -1997,8 +1970,9 @@ ParseMetrics.execute( | |
| 1997 1970 |  | 
| 1998 1971 | 
             
            ## Declarations
         | 
| 1999 1972 |  | 
| 2000 | 
            -
             | 
| 2001 | 
            -
             | 
| 1973 | 
            +
            !!! warning "Important"
         | 
| 1974 | 
            +
             | 
| 1975 | 
            +
                Custom coercions must raise `CMDx::CoercionError` with a descriptive message.
         | 
| 2002 1976 |  | 
| 2003 1977 | 
             
            ### Proc or Lambda
         | 
| 2004 1978 |  | 
| @@ -2048,10 +2022,11 @@ end | |
| 2048 2022 |  | 
| 2049 2023 | 
             
            ## Removals
         | 
| 2050 2024 |  | 
| 2051 | 
            -
            Remove  | 
| 2025 | 
            +
            Remove unwanted coercions:
         | 
| 2026 | 
            +
             | 
| 2027 | 
            +
            !!! warning
         | 
| 2052 2028 |  | 
| 2053 | 
            -
             | 
| 2054 | 
            -
            > 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.
         | 
| 2055 2030 |  | 
| 2056 2031 | 
             
            ```ruby
         | 
| 2057 2032 | 
             
            class TransformCoordinates < CMDx::Task
         | 
| @@ -2092,16 +2067,11 @@ result.metadata #=> { | |
| 2092 2067 | 
             
                            #   }
         | 
| 2093 2068 | 
             
            ```
         | 
| 2094 2069 |  | 
| 2095 | 
            -
            ---
         | 
| 2096 | 
            -
             | 
| 2097 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/attributes/validations.md
         | 
| 2098 | 
            -
            ---
         | 
| 2099 | 
            -
             | 
| 2100 2070 | 
             
            # Attributes - Validations
         | 
| 2101 2071 |  | 
| 2102 | 
            -
             | 
| 2072 | 
            +
            Ensure inputs meet requirements before execution. Validations run after coercions, giving you declarative data integrity checks.
         | 
| 2103 2073 |  | 
| 2104 | 
            -
             | 
| 2074 | 
            +
            See [Global Configuration](https://github.com/drexed/cmdx/blob/main/docs/getting_started.md#validators) for custom validator setup.
         | 
| 2105 2075 |  | 
| 2106 2076 | 
             
            ## Usage
         | 
| 2107 2077 |  | 
| @@ -2137,8 +2107,9 @@ ProcessSubscription.execute( | |
| 2137 2107 | 
             
            )
         | 
| 2138 2108 | 
             
            ```
         | 
| 2139 2109 |  | 
| 2140 | 
            -
             | 
| 2141 | 
            -
             | 
| 2110 | 
            +
            !!! tip
         | 
| 2111 | 
            +
             | 
| 2112 | 
            +
                Validations run after coercions, so you can validate the final coerced values rather than raw input.
         | 
| 2142 2113 |  | 
| 2143 2114 | 
             
            ## Built-in Validators
         | 
| 2144 2115 |  | 
| @@ -2293,8 +2264,9 @@ end | |
| 2293 2264 |  | 
| 2294 2265 | 
             
            ## Declarations
         | 
| 2295 2266 |  | 
| 2296 | 
            -
             | 
| 2297 | 
            -
             | 
| 2267 | 
            +
            !!! warning "Important"
         | 
| 2268 | 
            +
             | 
| 2269 | 
            +
                Custom validators must raise `CMDx::ValidationError` with a descriptive message.
         | 
| 2298 2270 |  | 
| 2299 2271 | 
             
            ### Proc or Lambda
         | 
| 2300 2272 |  | 
| @@ -2340,10 +2312,11 @@ end | |
| 2340 2312 |  | 
| 2341 2313 | 
             
            ## Removals
         | 
| 2342 2314 |  | 
| 2343 | 
            -
            Remove  | 
| 2315 | 
            +
            Remove unwanted validators:
         | 
| 2344 2316 |  | 
| 2345 | 
            -
             | 
| 2346 | 
            -
             | 
| 2317 | 
            +
            !!! warning
         | 
| 2318 | 
            +
             | 
| 2319 | 
            +
                Each `deregister` call removes one validator. Use multiple calls for batch removals.
         | 
| 2347 2320 |  | 
| 2348 2321 | 
             
            ```ruby
         | 
| 2349 2322 | 
             
            class SetupApplication < CMDx::Task
         | 
| @@ -2353,7 +2326,7 @@ end | |
| 2353 2326 |  | 
| 2354 2327 | 
             
            ## Error Handling
         | 
| 2355 2328 |  | 
| 2356 | 
            -
            Validation failures provide detailed | 
| 2329 | 
            +
            Validation failures provide detailed, structured error messages:
         | 
| 2357 2330 |  | 
| 2358 2331 | 
             
            ```ruby
         | 
| 2359 2332 | 
             
            class CreateProject < CMDx::Task
         | 
| @@ -2390,18 +2363,13 @@ result.metadata #=> { | |
| 2390 2363 | 
             
                            #   }
         | 
| 2391 2364 | 
             
            ```
         | 
| 2392 2365 |  | 
| 2393 | 
            -
            ---
         | 
| 2394 | 
            -
             | 
| 2395 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/attributes/defaults.md
         | 
| 2396 | 
            -
            ---
         | 
| 2397 | 
            -
             | 
| 2398 2366 | 
             
            # Attributes - Defaults
         | 
| 2399 2367 |  | 
| 2400 | 
            -
             | 
| 2368 | 
            +
            Provide fallback values for optional attributes. Defaults kick in when values aren't provided or are `nil`.
         | 
| 2401 2369 |  | 
| 2402 2370 | 
             
            ## Declarations
         | 
| 2403 2371 |  | 
| 2404 | 
            -
            Defaults  | 
| 2372 | 
            +
            Defaults work seamlessly with coercions, validations, and nested attributes:
         | 
| 2405 2373 |  | 
| 2406 2374 | 
             
            ### Static Values
         | 
| 2407 2375 |  | 
| @@ -2461,7 +2429,7 @@ end | |
| 2461 2429 |  | 
| 2462 2430 | 
             
            ## Coercions and Validations
         | 
| 2463 2431 |  | 
| 2464 | 
            -
            Defaults  | 
| 2432 | 
            +
            Defaults follow the same coercion and validation rules as provided values:
         | 
| 2465 2433 |  | 
| 2466 2434 | 
             
            ```ruby
         | 
| 2467 2435 | 
             
            class ScheduleBackup < CMDx::Task
         | 
| @@ -2473,14 +2441,9 @@ class ScheduleBackup < CMDx::Task | |
| 2473 2441 | 
             
            end
         | 
| 2474 2442 | 
             
            ```
         | 
| 2475 2443 |  | 
| 2476 | 
            -
            ---
         | 
| 2477 | 
            -
             | 
| 2478 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/attributes/transformations.md
         | 
| 2479 | 
            -
            ---
         | 
| 2480 | 
            -
             | 
| 2481 2444 | 
             
            # Attributes - Transformations
         | 
| 2482 2445 |  | 
| 2483 | 
            -
             | 
| 2446 | 
            +
            Modify attribute values after coercion but before validation. Perfect for normalization, formatting, and data cleanup.
         | 
| 2484 2447 |  | 
| 2485 2448 | 
             
            ## Declarations
         | 
| 2486 2449 |  | 
| @@ -2530,7 +2493,7 @@ end | |
| 2530 2493 |  | 
| 2531 2494 | 
             
            ## Validations
         | 
| 2532 2495 |  | 
| 2533 | 
            -
             | 
| 2496 | 
            +
            Validations run on transformed values, ensuring data consistency:
         | 
| 2534 2497 |  | 
| 2535 2498 | 
             
            ```ruby
         | 
| 2536 2499 | 
             
            class ScheduleBackup < CMDx::Task
         | 
| @@ -2542,39 +2505,30 @@ class ScheduleBackup < CMDx::Task | |
| 2542 2505 | 
             
            end
         | 
| 2543 2506 | 
             
            ```
         | 
| 2544 2507 |  | 
| 2545 | 
            -
            ---
         | 
| 2546 | 
            -
             | 
| 2547 | 
            -
            - **Prev:** [Attributes - Defaults](defaults.md)
         | 
| 2548 | 
            -
            - **Next:** [Callbacks](../callbacks.md)
         | 
| 2549 | 
            -
             | 
| 2550 | 
            -
            ---
         | 
| 2551 | 
            -
             | 
| 2552 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/callbacks.md
         | 
| 2553 | 
            -
            ---
         | 
| 2554 | 
            -
             | 
| 2555 2508 | 
             
            # Callbacks
         | 
| 2556 2509 |  | 
| 2557 | 
            -
             | 
| 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.
         | 
| 2558 2511 |  | 
| 2559 | 
            -
             | 
| 2512 | 
            +
            See [Global Configuration](https://github.com/drexed/cmdx/blob/main/docs/getting_started.md#callbacks) for framework-wide callback setup.
         | 
| 2560 2513 |  | 
| 2561 | 
            -
             | 
| 2562 | 
            -
             | 
| 2514 | 
            +
            !!! warning "Important"
         | 
| 2515 | 
            +
             | 
| 2516 | 
            +
                Callbacks execute in declaration order (FIFO). Multiple callbacks of the same type run sequentially.
         | 
| 2563 2517 |  | 
| 2564 2518 | 
             
            ## Available Callbacks
         | 
| 2565 2519 |  | 
| 2566 | 
            -
            Callbacks execute in  | 
| 2520 | 
            +
            Callbacks execute in a predictable lifecycle order:
         | 
| 2567 2521 |  | 
| 2568 2522 | 
             
            ```ruby
         | 
| 2569 2523 | 
             
            1. before_validation           # Pre-validation setup
         | 
| 2570 | 
            -
            2. before_execution            #  | 
| 2524 | 
            +
            2. before_execution            # Prepare for execution
         | 
| 2571 2525 |  | 
| 2572 | 
            -
            # --- Task#work  | 
| 2526 | 
            +
            # --- Task#work executes ---
         | 
| 2573 2527 |  | 
| 2574 | 
            -
            3. on_[complete|interrupted]   #  | 
| 2575 | 
            -
            4. on_executed                 #  | 
| 2576 | 
            -
            5. on_[success|skipped|failed] #  | 
| 2577 | 
            -
            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)
         | 
| 2578 2532 | 
             
            ```
         | 
| 2579 2533 |  | 
| 2580 2534 | 
             
            ## Declarations
         | 
| @@ -2626,7 +2580,7 @@ end | |
| 2626 2580 |  | 
| 2627 2581 | 
             
            ### Class or Module
         | 
| 2628 2582 |  | 
| 2629 | 
            -
            Implement reusable callback logic in dedicated classes:
         | 
| 2583 | 
            +
            Implement reusable callback logic in dedicated modules and classes:
         | 
| 2630 2584 |  | 
| 2631 2585 | 
             
            ```ruby
         | 
| 2632 2586 | 
             
            class BookingConfirmationCallback
         | 
| @@ -2693,10 +2647,11 @@ end | |
| 2693 2647 |  | 
| 2694 2648 | 
             
            ## Callback Removal
         | 
| 2695 2649 |  | 
| 2696 | 
            -
            Remove callbacks  | 
| 2650 | 
            +
            Remove unwanted callbacks dynamically:
         | 
| 2651 | 
            +
             | 
| 2652 | 
            +
            !!! warning "Important"
         | 
| 2697 2653 |  | 
| 2698 | 
            -
             | 
| 2699 | 
            -
            > 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.
         | 
| 2700 2655 |  | 
| 2701 2656 | 
             
            ```ruby
         | 
| 2702 2657 | 
             
            class ProcessBooking < CMDx::Task
         | 
| @@ -2708,23 +2663,19 @@ class ProcessBooking < CMDx::Task | |
| 2708 2663 | 
             
            end
         | 
| 2709 2664 | 
             
            ```
         | 
| 2710 2665 |  | 
| 2711 | 
            -
            ---
         | 
| 2712 | 
            -
             | 
| 2713 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/middlewares.md
         | 
| 2714 | 
            -
            ---
         | 
| 2715 | 
            -
             | 
| 2716 2666 | 
             
            # Middlewares
         | 
| 2717 2667 |  | 
| 2718 | 
            -
             | 
| 2668 | 
            +
            Wrap task execution with middleware for cross-cutting concerns like authentication, caching, timeouts, and monitoring. Think Rack middleware, but for your business logic.
         | 
| 2719 2669 |  | 
| 2720 | 
            -
             | 
| 2670 | 
            +
            See [Global Configuration](https://github.com/drexed/cmdx/blob/main/docs/getting_started.md#middlewares) for framework-wide setup.
         | 
| 2721 2671 |  | 
| 2722 | 
            -
            ## Order
         | 
| 2672 | 
            +
            ## Execution Order
         | 
| 2723 2673 |  | 
| 2724 | 
            -
            Middleware  | 
| 2674 | 
            +
            Middleware wraps task execution in layers, like an onion:
         | 
| 2725 2675 |  | 
| 2726 | 
            -
             | 
| 2727 | 
            -
             | 
| 2676 | 
            +
            !!! note
         | 
| 2677 | 
            +
             | 
| 2678 | 
            +
                First registered = outermost wrapper. They execute in registration order.
         | 
| 2728 2679 |  | 
| 2729 2680 | 
             
            ```ruby
         | 
| 2730 2681 | 
             
            class ProcessCampaign < CMDx::Task
         | 
| @@ -2800,10 +2751,11 @@ end | |
| 2800 2751 |  | 
| 2801 2752 | 
             
            ## Removals
         | 
| 2802 2753 |  | 
| 2803 | 
            -
             | 
| 2754 | 
            +
            Remove class or module-based middleware globally or per-task:
         | 
| 2755 | 
            +
             | 
| 2756 | 
            +
            !!! warning
         | 
| 2804 2757 |  | 
| 2805 | 
            -
             | 
| 2806 | 
            -
            > 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.
         | 
| 2807 2759 |  | 
| 2808 2760 | 
             
            ```ruby
         | 
| 2809 2761 | 
             
            class ProcessCampaign < CMDx::Task
         | 
| @@ -2816,7 +2768,7 @@ end | |
| 2816 2768 |  | 
| 2817 2769 | 
             
            ### Timeout
         | 
| 2818 2770 |  | 
| 2819 | 
            -
             | 
| 2771 | 
            +
            Prevent tasks from running too long:
         | 
| 2820 2772 |  | 
| 2821 2773 | 
             
            ```ruby
         | 
| 2822 2774 | 
             
            class ProcessReport < CMDx::Task
         | 
| @@ -2852,7 +2804,7 @@ result.metadata #=> { limit: 3 } | |
| 2852 2804 |  | 
| 2853 2805 | 
             
            ### Correlate
         | 
| 2854 2806 |  | 
| 2855 | 
            -
             | 
| 2807 | 
            +
            Add correlation IDs for distributed tracing and request tracking:
         | 
| 2856 2808 |  | 
| 2857 2809 | 
             
            ```ruby
         | 
| 2858 2810 | 
             
            class ProcessExport < CMDx::Task
         | 
| @@ -2882,8 +2834,7 @@ result.metadata #=> { correlation_id: "550e8400-e29b-41d4-a716-446655440000" } | |
| 2882 2834 |  | 
| 2883 2835 | 
             
            ### Runtime
         | 
| 2884 2836 |  | 
| 2885 | 
            -
             | 
| 2886 | 
            -
            The calculation uses a monotonic clock and the time is returned in milliseconds.
         | 
| 2837 | 
            +
            Track task execution time in milliseconds using a monotonic clock:
         | 
| 2887 2838 |  | 
| 2888 2839 | 
             
            ```ruby
         | 
| 2889 2840 | 
             
            class PerformanceMonitoringCheck
         | 
| @@ -2904,18 +2855,13 @@ result = ProcessExport.execute | |
| 2904 2855 | 
             
            result.metadata #=> { runtime: 1247 } (ms)
         | 
| 2905 2856 | 
             
            ```
         | 
| 2906 2857 |  | 
| 2907 | 
            -
            ---
         | 
| 2908 | 
            -
             | 
| 2909 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/logging.md
         | 
| 2910 | 
            -
            ---
         | 
| 2911 | 
            -
             | 
| 2912 2858 | 
             
            # Logging
         | 
| 2913 2859 |  | 
| 2914 | 
            -
            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.
         | 
| 2915 2861 |  | 
| 2916 2862 | 
             
            ## Formatters
         | 
| 2917 2863 |  | 
| 2918 | 
            -
             | 
| 2864 | 
            +
            Choose the format that works best for your logging system:
         | 
| 2919 2865 |  | 
| 2920 2866 | 
             
            | Formatter | Use Case | Output Style |
         | 
| 2921 2867 | 
             
            |-----------|----------|--------------|
         | 
| @@ -2945,12 +2891,13 @@ E, [2022-07-17T18:43:15.000000 #3784] ERROR -- BillingWorkflow: | |
| 2945 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"}
         | 
| 2946 2892 | 
             
            ```
         | 
| 2947 2893 |  | 
| 2948 | 
            -
             | 
| 2949 | 
            -
             | 
| 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.
         | 
| 2950 2897 |  | 
| 2951 2898 | 
             
            ## Structure
         | 
| 2952 2899 |  | 
| 2953 | 
            -
             | 
| 2900 | 
            +
            Every log entry includes rich metadata. Available fields depend on execution context and outcome.
         | 
| 2954 2901 |  | 
| 2955 2902 | 
             
            ### Core Fields
         | 
| 2956 2903 |  | 
| @@ -2991,7 +2938,7 @@ All log entries include comprehensive execution metadata. Field availability dep | |
| 2991 2938 |  | 
| 2992 2939 | 
             
            ## Usage
         | 
| 2993 2940 |  | 
| 2994 | 
            -
             | 
| 2941 | 
            +
            Access the framework logger directly within tasks:
         | 
| 2995 2942 |  | 
| 2996 2943 | 
             
            ```ruby
         | 
| 2997 2944 | 
             
            class ProcessSubscription < CMDx::Task
         | 
| @@ -3003,18 +2950,13 @@ class ProcessSubscription < CMDx::Task | |
| 3003 2950 | 
             
            end
         | 
| 3004 2951 | 
             
            ```
         | 
| 3005 2952 |  | 
| 3006 | 
            -
            ---
         | 
| 3007 | 
            -
             | 
| 3008 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/internationalization.md
         | 
| 3009 | 
            -
            ---
         | 
| 3010 | 
            -
             | 
| 3011 2953 | 
             
            # Internationalization (i18n)
         | 
| 3012 2954 |  | 
| 3013 | 
            -
            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.
         | 
| 3014 2956 |  | 
| 3015 | 
            -
            ##  | 
| 2957 | 
            +
            ## Usage
         | 
| 3016 2958 |  | 
| 3017 | 
            -
             | 
| 2959 | 
            +
            All error messages are automatically localized based on your current locale:
         | 
| 3018 2960 |  | 
| 3019 2961 | 
             
            ```ruby
         | 
| 3020 2962 | 
             
            class ProcessQuote < CMDx::Task
         | 
| @@ -3033,11 +2975,11 @@ end | |
| 3033 2975 |  | 
| 3034 2976 | 
             
            ## Configuration
         | 
| 3035 2977 |  | 
| 3036 | 
            -
             | 
| 2978 | 
            +
            CMDx uses the `I18n` gem for localization. In Rails, locales load automatically.
         | 
| 3037 2979 |  | 
| 3038 | 
            -
            ###  | 
| 2980 | 
            +
            ### Copy Locale Files
         | 
| 3039 2981 |  | 
| 3040 | 
            -
             | 
| 2982 | 
            +
            Copy locale files to your Rails application's `config/locales` directory:
         | 
| 3041 2983 |  | 
| 3042 2984 | 
             
            ```bash
         | 
| 3043 2985 | 
             
            rails generate cmdx:locale [LOCALE]
         | 
| @@ -3135,23 +3077,141 @@ rails generate cmdx:locale fr | |
| 3135 3077 | 
             
            - zh-TW - Chinese (Traditional)
         | 
| 3136 3078 | 
             
            - zh-YUE - Chinese (Yue)
         | 
| 3137 3079 |  | 
| 3138 | 
            -
             | 
| 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.
         | 
| 3139 3083 |  | 
| 3140 | 
            -
             | 
| 3141 | 
            -
             | 
| 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 | 
            +
            ```
         | 
| 3142 3201 |  | 
| 3143 3202 | 
             
            # Task Deprecation
         | 
| 3144 3203 |  | 
| 3145 | 
            -
             | 
| 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.
         | 
| 3146 3205 |  | 
| 3147 3206 | 
             
            ## Modes
         | 
| 3148 3207 |  | 
| 3149 3208 | 
             
            ### Raise
         | 
| 3150 3209 |  | 
| 3151 | 
            -
             | 
| 3210 | 
            +
            Prevent task execution completely. Perfect for tasks that must no longer run.
         | 
| 3211 | 
            +
             | 
| 3212 | 
            +
            !!! warning
         | 
| 3152 3213 |  | 
| 3153 | 
            -
             | 
| 3154 | 
            -
            > 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.
         | 
| 3155 3215 |  | 
| 3156 3216 | 
             
            ```ruby
         | 
| 3157 3217 | 
             
            class ProcessObsoleteAPI < CMDx::Task
         | 
| @@ -3168,7 +3228,7 @@ result = ProcessObsoleteAPI.execute | |
| 3168 3228 |  | 
| 3169 3229 | 
             
            ### Log
         | 
| 3170 3230 |  | 
| 3171 | 
            -
             | 
| 3231 | 
            +
            Allow execution while tracking deprecation in logs. Ideal for gradual migrations.
         | 
| 3172 3232 |  | 
| 3173 3233 | 
             
            ```ruby
         | 
| 3174 3234 | 
             
            class ProcessLegacyFormat < CMDx::Task
         | 
| @@ -3191,7 +3251,7 @@ result.successful? #=> true | |
| 3191 3251 |  | 
| 3192 3252 | 
             
            ### Warn
         | 
| 3193 3253 |  | 
| 3194 | 
            -
             | 
| 3254 | 
            +
            Issue Ruby warnings visible during development and testing. Keeps production logs clean while alerting developers.
         | 
| 3195 3255 |  | 
| 3196 3256 | 
             
            ```ruby
         | 
| 3197 3257 | 
             
            class ProcessOldData < CMDx::Task
         | 
| @@ -3285,21 +3345,17 @@ class OutdatedConnector < CMDx::Task | |
| 3285 3345 | 
             
            end
         | 
| 3286 3346 | 
             
            ```
         | 
| 3287 3347 |  | 
| 3288 | 
            -
            ---
         | 
| 3289 | 
            -
             | 
| 3290 | 
            -
            url: https://github.com/drexed/cmdx/blob/main/docs/workflows.md
         | 
| 3291 | 
            -
            ---
         | 
| 3292 | 
            -
             | 
| 3293 3348 | 
             
            # Workflows
         | 
| 3294 3349 |  | 
| 3295 | 
            -
             | 
| 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.
         | 
| 3296 3351 |  | 
| 3297 3352 | 
             
            ## Declarations
         | 
| 3298 3353 |  | 
| 3299 | 
            -
            Tasks  | 
| 3354 | 
            +
            Tasks run in declaration order (FIFO), sharing a common context across the pipeline.
         | 
| 3355 | 
            +
             | 
| 3356 | 
            +
            !!! warning
         | 
| 3300 3357 |  | 
| 3301 | 
            -
             | 
| 3302 | 
            -
            > 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.
         | 
| 3303 3359 |  | 
| 3304 3360 | 
             
            ### Task
         | 
| 3305 3361 |  | 
| @@ -3314,15 +3370,17 @@ class OnboardingWorkflow < CMDx::Task | |
| 3314 3370 | 
             
            end
         | 
| 3315 3371 | 
             
            ```
         | 
| 3316 3372 |  | 
| 3317 | 
            -
             | 
| 3318 | 
            -
             | 
| 3373 | 
            +
            !!! tip
         | 
| 3374 | 
            +
             | 
| 3375 | 
            +
                Execute tasks in parallel via the [cmdx-parallel](https://github.com/drexed/cmdx-parallel) gem.
         | 
| 3319 3376 |  | 
| 3320 3377 | 
             
            ### Group
         | 
| 3321 3378 |  | 
| 3322 | 
            -
            Group related tasks  | 
| 3379 | 
            +
            Group related tasks to share configuration:
         | 
| 3323 3380 |  | 
| 3324 | 
            -
             | 
| 3325 | 
            -
             | 
| 3381 | 
            +
            !!! warning "Important"
         | 
| 3382 | 
            +
             | 
| 3383 | 
            +
                Settings and conditionals apply to all tasks in the group.
         | 
| 3326 3384 |  | 
| 3327 3385 | 
             
            ```ruby
         | 
| 3328 3386 | 
             
            class ContentModerationWorkflow < CMDx::Task
         | 
| @@ -3385,9 +3443,7 @@ end | |
| 3385 3443 |  | 
| 3386 3444 | 
             
            ## Halt Behavior
         | 
| 3387 3445 |  | 
| 3388 | 
            -
            By default skipped tasks  | 
| 3389 | 
            -
            This is configurable via global and task level breakpoint settings. Task and group configurations
         | 
| 3390 | 
            -
            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.
         | 
| 3391 3447 |  | 
| 3392 3448 | 
             
            ```ruby
         | 
| 3393 3449 | 
             
            class AnalyticsWorkflow < CMDx::Task
         | 
| @@ -3443,7 +3499,7 @@ end | |
| 3443 3499 |  | 
| 3444 3500 | 
             
            ## Nested Workflows
         | 
| 3445 3501 |  | 
| 3446 | 
            -
             | 
| 3502 | 
            +
            Build hierarchical workflows by composing workflows within workflows:
         | 
| 3447 3503 |  | 
| 3448 3504 | 
             
            ```ruby
         | 
| 3449 3505 | 
             
            class EmailPreparationWorkflow < CMDx::Task
         | 
| @@ -3470,10 +3526,11 @@ end | |
| 3470 3526 |  | 
| 3471 3527 | 
             
            ## Parallel Execution
         | 
| 3472 3528 |  | 
| 3473 | 
            -
             | 
| 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
         | 
| 3474 3532 |  | 
| 3475 | 
            -
             | 
| 3476 | 
            -
            > 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.
         | 
| 3477 3534 |  | 
| 3478 3535 | 
             
            ```ruby
         | 
| 3479 3536 | 
             
            class SendWelcomeNotifications < CMDx::Task
         | 
| @@ -3511,17 +3568,13 @@ class SendNotifications < CMDx::Task | |
| 3511 3568 | 
             
            end
         | 
| 3512 3569 | 
             
            ```
         | 
| 3513 3570 |  | 
| 3514 | 
            -
             | 
| 3515 | 
            -
            > Use **present tense verbs + pluralized noun** for workflow task names, eg: `SendNotifications`, `DownloadFiles`, `ValidateDocuments`
         | 
| 3516 | 
            -
             | 
| 3517 | 
            -
            ---
         | 
| 3571 | 
            +
            !!! tip
         | 
| 3518 3572 |  | 
| 3519 | 
            -
             | 
| 3520 | 
            -
            ---
         | 
| 3573 | 
            +
                Use **present tense verbs + pluralized noun** for workflow task names, eg: `SendNotifications`, `DownloadFiles`, `ValidateDocuments`
         | 
| 3521 3574 |  | 
| 3522 3575 | 
             
            # Tips and Tricks
         | 
| 3523 3576 |  | 
| 3524 | 
            -
             | 
| 3577 | 
            +
            Best practices, patterns, and techniques to build maintainable CMDx applications.
         | 
| 3525 3578 |  | 
| 3526 3579 | 
             
            ## Project Organization
         | 
| 3527 3580 |  | 
| @@ -3565,7 +3618,7 @@ class TokenGeneration < CMDx::Task; end    # ❌ Avoid | |
| 3565 3618 |  | 
| 3566 3619 | 
             
            ### Story Telling
         | 
| 3567 3620 |  | 
| 3568 | 
            -
             | 
| 3621 | 
            +
            Break down complex logic into descriptive methods that read like a narrative:
         | 
| 3569 3622 |  | 
| 3570 3623 | 
             
            ```ruby
         | 
| 3571 3624 | 
             
            class ProcessOrder < CMDx::Task
         | 
| @@ -3597,7 +3650,7 @@ end | |
| 3597 3650 |  | 
| 3598 3651 | 
             
            ### Style Guide
         | 
| 3599 3652 |  | 
| 3600 | 
            -
            Follow  | 
| 3653 | 
            +
            Follow this order for consistent, readable tasks:
         | 
| 3601 3654 |  | 
| 3602 3655 | 
             
            ```ruby
         | 
| 3603 3656 | 
             
            class ExportReport < CMDx::Task
         | 
| @@ -3640,7 +3693,7 @@ end | |
| 3640 3693 |  | 
| 3641 3694 | 
             
            ## Attribute Options
         | 
| 3642 3695 |  | 
| 3643 | 
            -
            Use  | 
| 3696 | 
            +
            Use `with_options` to reduce duplication:
         | 
| 3644 3697 |  | 
| 3645 3698 | 
             
            ```ruby
         | 
| 3646 3699 | 
             
            class ConfigureCompany < CMDx::Task
         | 
| @@ -3666,9 +3719,9 @@ class ConfigureCompany < CMDx::Task | |
| 3666 3719 | 
             
            end
         | 
| 3667 3720 | 
             
            ```
         | 
| 3668 3721 |  | 
| 3669 | 
            -
            ##  | 
| 3722 | 
            +
            ## More Examples
         | 
| 3670 3723 |  | 
| 3671 3724 | 
             
            - [Active Record Query Tagging](https://github.com/drexed/cmdx/blob/main/examples/active_record_query_tagging.md)
         | 
| 3672 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)
         | 
| 3673 3727 |  | 
| 3674 | 
            -
            ---
         |