cmdx 1.7.5 → 1.9.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/.DS_Store +0 -0
- data/.cursor/prompts/docs.md +3 -3
- data/.cursor/prompts/llms.md +1 -3
- data/.cursor/prompts/rspec.md +1 -1
- data/.irbrc +14 -2
- data/CHANGELOG.md +62 -29
- data/LLM.md +203 -78
- data/README.md +23 -85
- data/docs/.DS_Store +0 -0
- data/docs/assets/favicon.ico +0 -0
- data/docs/assets/favicon.svg +1 -0
- data/docs/attributes/coercions.md +19 -29
- data/docs/attributes/defaults.md +3 -16
- data/docs/attributes/definitions.md +29 -39
- data/docs/attributes/naming.md +3 -13
- data/docs/attributes/transformations.md +63 -0
- data/docs/attributes/validations.md +23 -40
- data/docs/basics/chain.md +14 -23
- data/docs/basics/context.md +13 -22
- data/docs/basics/execution.md +8 -26
- data/docs/basics/setup.md +8 -19
- data/docs/callbacks.md +19 -32
- data/docs/deprecation.md +8 -25
- data/docs/getting_started.md +101 -77
- data/docs/index.md +120 -0
- data/docs/internationalization.md +6 -18
- data/docs/interruptions/exceptions.md +10 -16
- data/docs/interruptions/faults.md +8 -25
- data/docs/interruptions/halt.md +31 -25
- data/docs/logging.md +7 -17
- data/docs/middlewares.md +13 -29
- data/docs/outcomes/result.md +21 -38
- data/docs/outcomes/states.md +8 -22
- data/docs/outcomes/statuses.md +10 -21
- data/docs/stylesheets/extra.css +42 -0
- data/docs/tips_and_tricks.md +7 -46
- data/docs/workflows.md +23 -38
- data/examples/active_record_query_tagging.md +46 -0
- data/examples/paper_trail_whatdunnit.md +39 -0
- data/lib/cmdx/attribute.rb +9 -2
- data/lib/cmdx/attribute_value.rb +31 -10
- data/lib/cmdx/callback_registry.rb +12 -2
- data/lib/cmdx/coercions/hash.rb +6 -1
- data/lib/cmdx/configuration.rb +10 -2
- data/lib/cmdx/deprecator.rb +3 -3
- data/lib/cmdx/errors.rb +1 -1
- data/lib/cmdx/executor.rb +97 -9
- data/lib/cmdx/log_formatters/logstash.rb +4 -4
- data/lib/cmdx/pipeline.rb +4 -4
- data/lib/cmdx/railtie.rb +9 -0
- data/lib/cmdx/result.rb +10 -1
- data/lib/cmdx/task.rb +12 -7
- data/lib/cmdx/version.rb +1 -1
- data/lib/cmdx.rb +1 -0
- data/lib/generators/cmdx/templates/install.rb +9 -0
- data/lib/locales/af.yml +2 -2
- data/lib/locales/ar.yml +2 -2
- data/lib/locales/az.yml +2 -2
- data/lib/locales/be.yml +2 -2
- data/lib/locales/bg.yml +2 -2
- data/lib/locales/bn.yml +2 -2
- data/lib/locales/bs.yml +2 -2
- data/lib/locales/ca.yml +2 -2
- data/lib/locales/cnr.yml +2 -2
- data/lib/locales/cs.yml +2 -2
- data/lib/locales/cy.yml +2 -2
- data/lib/locales/da.yml +2 -2
- data/lib/locales/de.yml +2 -2
- data/lib/locales/dz.yml +2 -2
- data/lib/locales/el.yml +2 -2
- data/lib/locales/en.yml +2 -2
- data/lib/locales/eo.yml +2 -2
- data/lib/locales/es.yml +2 -2
- data/lib/locales/et.yml +2 -2
- data/lib/locales/eu.yml +2 -2
- data/lib/locales/fa.yml +2 -2
- data/lib/locales/fi.yml +2 -2
- data/lib/locales/fr.yml +2 -2
- data/lib/locales/fy.yml +2 -2
- data/lib/locales/gd.yml +2 -2
- data/lib/locales/gl.yml +2 -2
- data/lib/locales/he.yml +2 -2
- data/lib/locales/hi.yml +2 -2
- data/lib/locales/hr.yml +2 -2
- data/lib/locales/hu.yml +2 -2
- data/lib/locales/hy.yml +2 -2
- data/lib/locales/id.yml +2 -2
- data/lib/locales/is.yml +2 -2
- data/lib/locales/it.yml +2 -2
- data/lib/locales/ja.yml +2 -2
- data/lib/locales/ka.yml +2 -2
- data/lib/locales/kk.yml +2 -2
- data/lib/locales/km.yml +2 -2
- data/lib/locales/kn.yml +2 -2
- data/lib/locales/ko.yml +2 -2
- data/lib/locales/lb.yml +2 -2
- data/lib/locales/lo.yml +2 -2
- data/lib/locales/lt.yml +2 -2
- data/lib/locales/lv.yml +2 -2
- data/lib/locales/mg.yml +2 -2
- data/lib/locales/mk.yml +2 -2
- data/lib/locales/ml.yml +2 -2
- data/lib/locales/mn.yml +2 -2
- data/lib/locales/mr-IN.yml +2 -2
- data/lib/locales/ms.yml +2 -2
- data/lib/locales/nb.yml +2 -2
- data/lib/locales/ne.yml +2 -2
- data/lib/locales/nl.yml +2 -2
- data/lib/locales/nn.yml +2 -2
- data/lib/locales/oc.yml +2 -2
- data/lib/locales/or.yml +2 -2
- data/lib/locales/pa.yml +2 -2
- data/lib/locales/pl.yml +2 -2
- data/lib/locales/pt.yml +2 -2
- data/lib/locales/rm.yml +2 -2
- data/lib/locales/ro.yml +2 -2
- data/lib/locales/ru.yml +2 -2
- data/lib/locales/sc.yml +2 -2
- data/lib/locales/sk.yml +2 -2
- data/lib/locales/sl.yml +2 -2
- data/lib/locales/sq.yml +2 -2
- data/lib/locales/sr.yml +2 -2
- data/lib/locales/st.yml +2 -2
- data/lib/locales/sv.yml +2 -2
- data/lib/locales/sw.yml +2 -2
- data/lib/locales/ta.yml +2 -2
- data/lib/locales/te.yml +2 -2
- data/lib/locales/th.yml +2 -2
- data/lib/locales/tl.yml +2 -2
- data/lib/locales/tr.yml +2 -2
- data/lib/locales/tt.yml +2 -2
- data/lib/locales/ug.yml +2 -2
- data/lib/locales/uk.yml +2 -2
- data/lib/locales/ur.yml +2 -2
- data/lib/locales/uz.yml +2 -2
- data/lib/locales/vi.yml +2 -2
- data/lib/locales/wo.yml +2 -2
- data/lib/locales/zh-CN.yml +2 -2
- data/lib/locales/zh-HK.yml +2 -2
- data/lib/locales/zh-TW.yml +2 -2
- data/lib/locales/zh-YUE.yml +2 -2
- data/mkdocs.yml +122 -0
- data/src/cmdx-dark-logo.png +0 -0
- data/src/cmdx-favicon.svg +1 -0
- data/src/cmdx-light-logo.png +0 -0
- data/src/cmdx-logo.svg +1 -0
- metadata +15 -4
- data/lib/cmdx/freezer.rb +0 -51
- data/src/cmdx-logo.png +0 -0
    
        data/docs/logging.md
    CHANGED
    
    | @@ -1,16 +1,10 @@ | |
| 1 1 | 
             
            # Logging
         | 
| 2 2 |  | 
| 3 | 
            -
            CMDx  | 
| 4 | 
            -
             | 
| 5 | 
            -
            ## Table of Contents
         | 
| 6 | 
            -
             | 
| 7 | 
            -
            - [Formatters](#formatters)
         | 
| 8 | 
            -
            - [Structure](#structure)
         | 
| 9 | 
            -
            - [Usage](#usage)
         | 
| 3 | 
            +
            CMDx automatically logs every task execution with structured data, making debugging and monitoring effortless. Choose from multiple formatters to match your logging infrastructure.
         | 
| 10 4 |  | 
| 11 5 | 
             
            ## Formatters
         | 
| 12 6 |  | 
| 13 | 
            -
             | 
| 7 | 
            +
            Choose the format that works best for your logging system:
         | 
| 14 8 |  | 
| 15 9 | 
             
            | Formatter | Use Case | Output Style |
         | 
| 16 10 | 
             
            |-----------|----------|--------------|
         | 
| @@ -40,12 +34,13 @@ E, [2022-07-17T18:43:15.000000 #3784] ERROR -- BillingWorkflow: | |
| 40 34 | 
             
            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"}
         | 
| 41 35 | 
             
            ```
         | 
| 42 36 |  | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 37 | 
            +
            !!! tip
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                Use logging as a low-level event stream to track all tasks in a request. Combine with correlation for powerful distributed tracing.
         | 
| 45 40 |  | 
| 46 41 | 
             
            ## Structure
         | 
| 47 42 |  | 
| 48 | 
            -
             | 
| 43 | 
            +
            Every log entry includes rich metadata. Available fields depend on execution context and outcome.
         | 
| 49 44 |  | 
| 50 45 | 
             
            ### Core Fields
         | 
| 51 46 |  | 
| @@ -86,7 +81,7 @@ All log entries include comprehensive execution metadata. Field availability dep | |
| 86 81 |  | 
| 87 82 | 
             
            ## Usage
         | 
| 88 83 |  | 
| 89 | 
            -
             | 
| 84 | 
            +
            Access the framework logger directly within tasks:
         | 
| 90 85 |  | 
| 91 86 | 
             
            ```ruby
         | 
| 92 87 | 
             
            class ProcessSubscription < CMDx::Task
         | 
| @@ -97,8 +92,3 @@ class ProcessSubscription < CMDx::Task | |
| 97 92 | 
             
              end
         | 
| 98 93 | 
             
            end
         | 
| 99 94 | 
             
            ```
         | 
| 100 | 
            -
             | 
| 101 | 
            -
            ---
         | 
| 102 | 
            -
             | 
| 103 | 
            -
            - **Prev:** [Middlewares](middlewares.md)
         | 
| 104 | 
            -
            - **Next:** [Internationalization (i18n)](internationalization.md)
         | 
    
        data/docs/middlewares.md
    CHANGED
    
    | @@ -1,27 +1,16 @@ | |
| 1 1 | 
             
            # Middlewares
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 3 | 
            +
            Wrap task execution with middleware for cross-cutting concerns like authentication, caching, timeouts, and monitoring. Think Rack middleware, but for your business logic.
         | 
| 4 4 |  | 
| 5 | 
            -
             | 
| 5 | 
            +
            See [Global Configuration](getting_started.md#middlewares) for framework-wide setup.
         | 
| 6 6 |  | 
| 7 | 
            -
            ##  | 
| 7 | 
            +
            ## Execution Order
         | 
| 8 8 |  | 
| 9 | 
            -
             | 
| 10 | 
            -
            - [Declarations](#declarations)
         | 
| 11 | 
            -
              - [Proc or Lambda](#proc-or-lambda)
         | 
| 12 | 
            -
              - [Class or Module](#class-or-module)
         | 
| 13 | 
            -
            - [Removals](#removals)
         | 
| 14 | 
            -
            - [Built-in](#built-in)
         | 
| 15 | 
            -
              - [Timeout](#timeout)
         | 
| 16 | 
            -
              - [Correlate](#correlate)
         | 
| 17 | 
            -
              - [Runtime](#runtime)
         | 
| 9 | 
            +
            Middleware wraps task execution in layers, like an onion:
         | 
| 18 10 |  | 
| 19 | 
            -
             | 
| 11 | 
            +
            !!! note
         | 
| 20 12 |  | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
            > [!NOTE]
         | 
| 24 | 
            -
            > Middleware executes in the order they are registered, with the first registered middleware being the outermost wrapper.
         | 
| 13 | 
            +
                First registered = outermost wrapper. They execute in registration order.
         | 
| 25 14 |  | 
| 26 15 | 
             
            ```ruby
         | 
| 27 16 | 
             
            class ProcessCampaign < CMDx::Task
         | 
| @@ -97,10 +86,11 @@ end | |
| 97 86 |  | 
| 98 87 | 
             
            ## Removals
         | 
| 99 88 |  | 
| 100 | 
            -
             | 
| 89 | 
            +
            Remove class or module-based middleware globally or per-task:
         | 
| 90 | 
            +
             | 
| 91 | 
            +
            !!! warning
         | 
| 101 92 |  | 
| 102 | 
            -
             | 
| 103 | 
            -
            > Only one removal operation is allowed per `deregister` call. Multiple removals require separate calls.
         | 
| 93 | 
            +
                Each `deregister` call removes one middleware. Use multiple calls for batch removals.
         | 
| 104 94 |  | 
| 105 95 | 
             
            ```ruby
         | 
| 106 96 | 
             
            class ProcessCampaign < CMDx::Task
         | 
| @@ -113,7 +103,7 @@ end | |
| 113 103 |  | 
| 114 104 | 
             
            ### Timeout
         | 
| 115 105 |  | 
| 116 | 
            -
             | 
| 106 | 
            +
            Prevent tasks from running too long:
         | 
| 117 107 |  | 
| 118 108 | 
             
            ```ruby
         | 
| 119 109 | 
             
            class ProcessReport < CMDx::Task
         | 
| @@ -149,7 +139,7 @@ result.metadata #=> { limit: 3 } | |
| 149 139 |  | 
| 150 140 | 
             
            ### Correlate
         | 
| 151 141 |  | 
| 152 | 
            -
             | 
| 142 | 
            +
            Add correlation IDs for distributed tracing and request tracking:
         | 
| 153 143 |  | 
| 154 144 | 
             
            ```ruby
         | 
| 155 145 | 
             
            class ProcessExport < CMDx::Task
         | 
| @@ -179,8 +169,7 @@ result.metadata #=> { correlation_id: "550e8400-e29b-41d4-a716-446655440000" } | |
| 179 169 |  | 
| 180 170 | 
             
            ### Runtime
         | 
| 181 171 |  | 
| 182 | 
            -
             | 
| 183 | 
            -
            The calculation uses a monotonic clock and the time is returned in milliseconds.
         | 
| 172 | 
            +
            Track task execution time in milliseconds using a monotonic clock:
         | 
| 184 173 |  | 
| 185 174 | 
             
            ```ruby
         | 
| 186 175 | 
             
            class PerformanceMonitoringCheck
         | 
| @@ -200,8 +189,3 @@ end | |
| 200 189 | 
             
            result = ProcessExport.execute
         | 
| 201 190 | 
             
            result.metadata #=> { runtime: 1247 } (ms)
         | 
| 202 191 | 
             
            ```
         | 
| 203 | 
            -
             | 
| 204 | 
            -
            ---
         | 
| 205 | 
            -
             | 
| 206 | 
            -
            - **Prev:** [Callbacks](callbacks.md)
         | 
| 207 | 
            -
            - **Next:** [Logging](logging.md)
         | 
    
        data/docs/outcomes/result.md
    CHANGED
    
    | @@ -1,27 +1,14 @@ | |
| 1 1 | 
             
            # Outcomes - Result
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 5 | 
            -
            ## Table of Contents
         | 
| 6 | 
            -
             | 
| 7 | 
            -
            - [Result Attributes](#result-attributes)
         | 
| 8 | 
            -
            - [Lifecycle Information](#lifecycle-information)
         | 
| 9 | 
            -
            - [Outcome Analysis](#outcome-analysis)
         | 
| 10 | 
            -
            - [Chain Analysis](#chain-analysis)
         | 
| 11 | 
            -
            - [Index and Position](#index-and-position)
         | 
| 12 | 
            -
            - [Block Yield](#block-yield)
         | 
| 13 | 
            -
            - [Handlers](#handlers)
         | 
| 14 | 
            -
            - [Pattern Matching](#pattern-matching)
         | 
| 15 | 
            -
              - [Array Pattern](#array-pattern)
         | 
| 16 | 
            -
              - [Hash Pattern](#hash-pattern)
         | 
| 17 | 
            -
              - [Pattern Guards](#pattern-guards)
         | 
| 3 | 
            +
            Results are your window into task execution. They expose everything: outcome, state, timing, context, and metadata.
         | 
| 18 4 |  | 
| 19 5 | 
             
            ## Result Attributes
         | 
| 20 6 |  | 
| 21 | 
            -
             | 
| 7 | 
            +
            Access essential execution information:
         | 
| 22 8 |  | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 9 | 
            +
            !!! warning "Important"
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                Results are immutable after execution completes.
         | 
| 25 12 |  | 
| 26 13 | 
             
            ```ruby
         | 
| 27 14 | 
             
            result = BuildApplication.execute(version: "1.2.3")
         | 
| @@ -43,7 +30,7 @@ result.metadata #=> { error_code: "BUILD_TOOL.NOT_FOUND" } | |
| 43 30 |  | 
| 44 31 | 
             
            ## Lifecycle Information
         | 
| 45 32 |  | 
| 46 | 
            -
             | 
| 33 | 
            +
            Check execution state and status with predicate methods:
         | 
| 47 34 |  | 
| 48 35 | 
             
            ```ruby
         | 
| 49 36 | 
             
            result = BuildApplication.execute(version: "1.2.3")
         | 
| @@ -65,7 +52,7 @@ result.bad?         #=> false (skipped or failed) | |
| 65 52 |  | 
| 66 53 | 
             
            ## Outcome Analysis
         | 
| 67 54 |  | 
| 68 | 
            -
             | 
| 55 | 
            +
            Get a unified outcome string combining state and status:
         | 
| 69 56 |  | 
| 70 57 | 
             
            ```ruby
         | 
| 71 58 | 
             
            result = BuildApplication.execute(version: "1.2.3")
         | 
| @@ -75,7 +62,7 @@ result.outcome #=> "success" (state and status) | |
| 75 62 |  | 
| 76 63 | 
             
            ## Chain Analysis
         | 
| 77 64 |  | 
| 78 | 
            -
             | 
| 65 | 
            +
            Trace fault origins and propagation:
         | 
| 79 66 |  | 
| 80 67 | 
             
            ```ruby
         | 
| 81 68 | 
             
            result = DeploymentWorkflow.execute(app_name: "webapp")
         | 
| @@ -116,7 +103,7 @@ result.chain.results[result.index] == result #=> true | |
| 116 103 |  | 
| 117 104 | 
             
            ## Block Yield
         | 
| 118 105 |  | 
| 119 | 
            -
             | 
| 106 | 
            +
            Execute code with direct result access:
         | 
| 120 107 |  | 
| 121 108 | 
             
            ```ruby
         | 
| 122 109 | 
             
            BuildApplication.execute(version: "1.2.3") do |result|
         | 
| @@ -132,34 +119,35 @@ end | |
| 132 119 |  | 
| 133 120 | 
             
            ## Handlers
         | 
| 134 121 |  | 
| 135 | 
            -
             | 
| 122 | 
            +
            Handle outcomes with functional-style methods. Handlers return the result for chaining:
         | 
| 136 123 |  | 
| 137 124 | 
             
            ```ruby
         | 
| 138 125 | 
             
            result = BuildApplication.execute(version: "1.2.3")
         | 
| 139 126 |  | 
| 140 127 | 
             
            # Status-based handlers
         | 
| 141 128 | 
             
            result
         | 
| 142 | 
            -
              . | 
| 143 | 
            -
              . | 
| 144 | 
            -
              . | 
| 129 | 
            +
              .handle_success { |result| notify_deployment_ready(result) }
         | 
| 130 | 
            +
              .handle_failed { |result| handle_build_failure(result) }
         | 
| 131 | 
            +
              .handle_skipped { |result| log_skip_reason(result) }
         | 
| 145 132 |  | 
| 146 133 | 
             
            # State-based handlers
         | 
| 147 134 | 
             
            result
         | 
| 148 | 
            -
              . | 
| 149 | 
            -
              . | 
| 135 | 
            +
              .handle_complete { |result| update_build_status(result) }
         | 
| 136 | 
            +
              .handle_interrupted { |result| cleanup_partial_artifacts(result) }
         | 
| 150 137 |  | 
| 151 138 | 
             
            # Outcome-based handlers
         | 
| 152 139 | 
             
            result
         | 
| 153 | 
            -
              . | 
| 154 | 
            -
              . | 
| 140 | 
            +
              .handle_good { |result| increment_success_counter(result) }
         | 
| 141 | 
            +
              .handle_bad { |result| alert_operations_team(result) }
         | 
| 155 142 | 
             
            ```
         | 
| 156 143 |  | 
| 157 144 | 
             
            ## Pattern Matching
         | 
| 158 145 |  | 
| 159 | 
            -
             | 
| 146 | 
            +
            Use Ruby 3.0+ pattern matching for elegant outcome handling:
         | 
| 147 | 
            +
             | 
| 148 | 
            +
            !!! warning "Important"
         | 
| 160 149 |  | 
| 161 | 
            -
             | 
| 162 | 
            -
            > Pattern matching requires Ruby 3.0+
         | 
| 150 | 
            +
                Pattern matching works with both array and hash deconstruction.
         | 
| 163 151 |  | 
| 164 152 | 
             
            ### Array Pattern
         | 
| 165 153 |  | 
| @@ -203,8 +191,3 @@ in { runtime: time } if time > performance_threshold | |
| 203 191 | 
             
              investigate_build_performance(result)
         | 
| 204 192 | 
             
            end
         | 
| 205 193 | 
             
            ```
         | 
| 206 | 
            -
             | 
| 207 | 
            -
            ---
         | 
| 208 | 
            -
             | 
| 209 | 
            -
            - **Prev:** [Interruptions - Exceptions](../interruptions/exceptions.md)
         | 
| 210 | 
            -
            - **Next:** [Outcomes - States](states.md)
         | 
    
        data/docs/outcomes/states.md
    CHANGED
    
    | @@ -1,16 +1,6 @@ | |
| 1 1 | 
             
            # Outcomes - States
         | 
| 2 2 |  | 
| 3 | 
            -
            States  | 
| 4 | 
            -
            the progress of tasks through their complete execution journey. States provide
         | 
| 5 | 
            -
            insight into where a task is in its lifecycle and enable lifecycle-based
         | 
| 6 | 
            -
            decision making and monitoring.
         | 
| 7 | 
            -
             | 
| 8 | 
            -
            ## Table of Contents
         | 
| 9 | 
            -
             | 
| 10 | 
            -
            - [Definitions](#definitions)
         | 
| 11 | 
            -
            - [Transitions](#transitions)
         | 
| 12 | 
            -
            - [Predicates](#predicates)
         | 
| 13 | 
            -
            - [Handlers](#handlers)
         | 
| 3 | 
            +
            States track where a task is in its execution lifecycle—from creation through completion or interruption.
         | 
| 14 4 |  | 
| 15 5 | 
             
            ## Definitions
         | 
| 16 6 |  | 
| @@ -34,8 +24,9 @@ State-Status combinations: | |
| 34 24 |  | 
| 35 25 | 
             
            ## Transitions
         | 
| 36 26 |  | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 27 | 
            +
            !!! danger "Caution"
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                States are managed automatically—never modify them manually.
         | 
| 39 30 |  | 
| 40 31 | 
             
            ```ruby
         | 
| 41 32 | 
             
            # Valid state transition flow
         | 
| @@ -62,19 +53,14 @@ result.executed?    #=> true (complete OR interrupted) | |
| 62 53 |  | 
| 63 54 | 
             
            ## Handlers
         | 
| 64 55 |  | 
| 65 | 
            -
             | 
| 56 | 
            +
            Handle lifecycle events with state-based handlers. Use `handle_executed` for cleanup that runs regardless of outcome:
         | 
| 66 57 |  | 
| 67 58 | 
             
            ```ruby
         | 
| 68 59 | 
             
            result = ProcessVideoUpload.execute
         | 
| 69 60 |  | 
| 70 61 | 
             
            # Individual state handlers
         | 
| 71 62 | 
             
            result
         | 
| 72 | 
            -
              . | 
| 73 | 
            -
              . | 
| 74 | 
            -
              . | 
| 63 | 
            +
              .handle_complete { |result| send_upload_notification(result) }
         | 
| 64 | 
            +
              .handle_interrupted { |result| cleanup_temp_files(result) }
         | 
| 65 | 
            +
              .handle_executed { |result| log_upload_metrics(result) }
         | 
| 75 66 | 
             
            ```
         | 
| 76 | 
            -
             | 
| 77 | 
            -
            ---
         | 
| 78 | 
            -
             | 
| 79 | 
            -
            - **Prev:** [Outcomes - Result](result.md)
         | 
| 80 | 
            -
            - **Next:** [Outcomes - Statuses](statuses.md)
         | 
    
        data/docs/outcomes/statuses.md
    CHANGED
    
    | @@ -1,13 +1,6 @@ | |
| 1 1 | 
             
            # Outcomes - Statuses
         | 
| 2 2 |  | 
| 3 | 
            -
            Statuses represent the business outcome  | 
| 4 | 
            -
             | 
| 5 | 
            -
            ## Table of Contents
         | 
| 6 | 
            -
             | 
| 7 | 
            -
            - [Definitions](#definitions)
         | 
| 8 | 
            -
            - [Transitions](#transitions)
         | 
| 9 | 
            -
            - [Predicates](#predicates)
         | 
| 10 | 
            -
            - [Handlers](#handlers)
         | 
| 3 | 
            +
            Statuses represent the business outcome—did the task succeed, skip, or fail? This differs from state, which tracks the execution lifecycle.
         | 
| 11 4 |  | 
| 12 5 | 
             
            ## Definitions
         | 
| 13 6 |  | 
| @@ -19,8 +12,9 @@ Statuses represent the business outcome of task execution logic, indicating how | |
| 19 12 |  | 
| 20 13 | 
             
            ## Transitions
         | 
| 21 14 |  | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 15 | 
            +
            !!! warning "Important"
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                Status transitions are final and unidirectional. Once skipped or failed, tasks can't return to success.
         | 
| 24 18 |  | 
| 25 19 | 
             
            ```ruby
         | 
| 26 20 | 
             
            # Valid status transitions
         | 
| @@ -53,24 +47,19 @@ result.bad?     #=> true if skipped OR failed (not success) | |
| 53 47 |  | 
| 54 48 | 
             
            ## Handlers
         | 
| 55 49 |  | 
| 56 | 
            -
             | 
| 50 | 
            +
            Branch business logic with status-based handlers. Use `handle_good` and `handle_bad` for success/skip vs failed outcomes:
         | 
| 57 51 |  | 
| 58 52 | 
             
            ```ruby
         | 
| 59 53 | 
             
            result = ProcessNotification.execute
         | 
| 60 54 |  | 
| 61 55 | 
             
            # Individual status handlers
         | 
| 62 56 | 
             
            result
         | 
| 63 | 
            -
              . | 
| 64 | 
            -
              . | 
| 65 | 
            -
              . | 
| 57 | 
            +
              .handle_success { |result| mark_notification_sent(result) }
         | 
| 58 | 
            +
              .handle_skipped { |result| log_notification_skipped(result) }
         | 
| 59 | 
            +
              .handle_failed { |result| queue_retry_notification(result) }
         | 
| 66 60 |  | 
| 67 61 | 
             
            # Outcome-based handlers
         | 
| 68 62 | 
             
            result
         | 
| 69 | 
            -
              . | 
| 70 | 
            -
              . | 
| 63 | 
            +
              .handle_good { |result| update_message_stats(result) }
         | 
| 64 | 
            +
              .handle_bad { |result| track_delivery_failure(result) }
         | 
| 71 65 | 
             
            ```
         | 
| 72 | 
            -
             | 
| 73 | 
            -
            ---
         | 
| 74 | 
            -
             | 
| 75 | 
            -
            - **Prev:** [Outcomes - States](states.md)
         | 
| 76 | 
            -
            - **Next:** [Attributes - Definitions](../attributes/definitions.md)
         | 
| @@ -0,0 +1,42 @@ | |
| 1 | 
            +
            :root  > * {
         | 
| 2 | 
            +
              /* Primary color shades */
         | 
| 3 | 
            +
              --md-primary-fg-color:        #fe1817;
         | 
| 4 | 
            +
              --md-primary-fg-color--light: #fe1817;
         | 
| 5 | 
            +
              --md-primary-fg-color--dark:  #fe1817;
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              /* Accent color shades */
         | 
| 8 | 
            +
              --md-accent-fg-color:                hsla(#{hex2hsl(#fe1817)}, 1);
         | 
| 9 | 
            +
              --md-accent-fg-color--transparent:   hsla(#{hex2hsl(#fe1817)}, 0.1);
         | 
| 10 | 
            +
            }
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            /* Atom One Light Pro syntax highlighting */
         | 
| 13 | 
            +
            [data-md-color-scheme="default"] {
         | 
| 14 | 
            +
              --md-code-hl-color:            #2c3036;
         | 
| 15 | 
            +
              --md-code-hl-keyword-color:    #a626a4;
         | 
| 16 | 
            +
              --md-code-hl-string-color:     #50a14f;
         | 
| 17 | 
            +
              --md-code-hl-name-color:       #e4564a;
         | 
| 18 | 
            +
              --md-code-hl-function-color:   #4078f2;
         | 
| 19 | 
            +
              --md-code-hl-number-color:     #ca7601;
         | 
| 20 | 
            +
              --md-code-hl-constant-color:   #c18401;
         | 
| 21 | 
            +
              --md-code-hl-comment-color:    #9ca0a4;
         | 
| 22 | 
            +
              --md-code-hl-operator-color:   #0184bc;
         | 
| 23 | 
            +
              --md-code-hl-punctuation-color:#383a42;
         | 
| 24 | 
            +
              --md-code-hl-variable-color:   #e4564a;
         | 
| 25 | 
            +
              --md-code-hl-generic-color:    #e4564a;
         | 
| 26 | 
            +
            }
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            /* Atom One Dark Pro syntax highlighting */
         | 
| 29 | 
            +
            [data-md-color-scheme="slate"] {
         | 
| 30 | 
            +
              --md-code-hl-color:            #e5e5e6;
         | 
| 31 | 
            +
              --md-code-hl-keyword-color:    #c678dd;
         | 
| 32 | 
            +
              --md-code-hl-string-color:     #98c379;
         | 
| 33 | 
            +
              --md-code-hl-name-color:       #e06c75;
         | 
| 34 | 
            +
              --md-code-hl-function-color:   #61afef;
         | 
| 35 | 
            +
              --md-code-hl-number-color:     #d19a66;
         | 
| 36 | 
            +
              --md-code-hl-constant-color:   #d19a66;
         | 
| 37 | 
            +
              --md-code-hl-comment-color:    #7f848e;
         | 
| 38 | 
            +
              --md-code-hl-operator-color:   #56b6c2;
         | 
| 39 | 
            +
              --md-code-hl-punctuation-color:#abb2bf;
         | 
| 40 | 
            +
              --md-code-hl-variable-color:   #e06c75;
         | 
| 41 | 
            +
              --md-code-hl-generic-color:    #e06c75;
         | 
| 42 | 
            +
            }
         | 
    
        data/docs/tips_and_tricks.md
    CHANGED
    
    | @@ -1,16 +1,6 @@ | |
| 1 1 | 
             
            # Tips and Tricks
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 5 | 
            -
            ## Table of Contents
         | 
| 6 | 
            -
             | 
| 7 | 
            -
            - [Project Organization](#project-organization)
         | 
| 8 | 
            -
              - [Directory Structure](#directory-structure)
         | 
| 9 | 
            -
              - [Naming Conventions](#naming-conventions)
         | 
| 10 | 
            -
              - [Story Telling](#story-telling)
         | 
| 11 | 
            -
              - [Style Guide](#style-guide)
         | 
| 12 | 
            -
            - [Attribute Options](#attribute-options)
         | 
| 13 | 
            -
            - [ActiveRecord Query Tagging](#activerecord-query-tagging)
         | 
| 3 | 
            +
            Best practices, patterns, and techniques to build maintainable CMDx applications.
         | 
| 14 4 |  | 
| 15 5 | 
             
            ## Project Organization
         | 
| 16 6 |  | 
| @@ -54,7 +44,7 @@ class TokenGeneration < CMDx::Task; end    # ❌ Avoid | |
| 54 44 |  | 
| 55 45 | 
             
            ### Story Telling
         | 
| 56 46 |  | 
| 57 | 
            -
             | 
| 47 | 
            +
            Break down complex logic into descriptive methods that read like a narrative:
         | 
| 58 48 |  | 
| 59 49 | 
             
            ```ruby
         | 
| 60 50 | 
             
            class ProcessOrder < CMDx::Task
         | 
| @@ -86,7 +76,7 @@ end | |
| 86 76 |  | 
| 87 77 | 
             
            ### Style Guide
         | 
| 88 78 |  | 
| 89 | 
            -
            Follow  | 
| 79 | 
            +
            Follow this order for consistent, readable tasks:
         | 
| 90 80 |  | 
| 91 81 | 
             
            ```ruby
         | 
| 92 82 | 
             
            class ExportReport < CMDx::Task
         | 
| @@ -129,7 +119,7 @@ end | |
| 129 119 |  | 
| 130 120 | 
             
            ## Attribute Options
         | 
| 131 121 |  | 
| 132 | 
            -
            Use  | 
| 122 | 
            +
            Use `with_options` to reduce duplication:
         | 
| 133 123 |  | 
| 134 124 | 
             
            ```ruby
         | 
| 135 125 | 
             
            class ConfigureCompany < CMDx::Task
         | 
| @@ -155,36 +145,7 @@ class ConfigureCompany < CMDx::Task | |
| 155 145 | 
             
            end
         | 
| 156 146 | 
             
            ```
         | 
| 157 147 |  | 
| 158 | 
            -
            ##  | 
| 159 | 
            -
             | 
| 160 | 
            -
            Automatically tag SQL queries for better debugging:
         | 
| 161 | 
            -
             | 
| 162 | 
            -
            ```ruby
         | 
| 163 | 
            -
            # config/application.rb
         | 
| 164 | 
            -
            config.active_record.query_log_tags_enabled = true
         | 
| 165 | 
            -
            config.active_record.query_log_tags << :cmdx_task_class
         | 
| 166 | 
            -
            config.active_record.query_log_tags << :cmdx_chain_id
         | 
| 167 | 
            -
             | 
| 168 | 
            -
            # app/tasks/application_task.rb
         | 
| 169 | 
            -
            class ApplicationTask < CMDx::Task
         | 
| 170 | 
            -
              before_execution :set_execution_context
         | 
| 171 | 
            -
             | 
| 172 | 
            -
              private
         | 
| 173 | 
            -
             | 
| 174 | 
            -
              def set_execution_context
         | 
| 175 | 
            -
                # NOTE: This could easily be made into a middleware
         | 
| 176 | 
            -
                ActiveSupport::ExecutionContext.set(
         | 
| 177 | 
            -
                  cmdx_task_class: self.class.name,
         | 
| 178 | 
            -
                  cmdx_chain_id: chain.id
         | 
| 179 | 
            -
                )
         | 
| 180 | 
            -
              end
         | 
| 181 | 
            -
            end
         | 
| 182 | 
            -
             | 
| 183 | 
            -
            # SQL queries will now include comments like:
         | 
| 184 | 
            -
            # /*cmdx_task_class:ExportReportTask,cmdx_chain_id:018c2b95-b764-7615*/ SELECT * FROM reports WHERE id = 1
         | 
| 185 | 
            -
            ```
         | 
| 186 | 
            -
             | 
| 187 | 
            -
            ---
         | 
| 148 | 
            +
            ## Advanced Examples
         | 
| 188 149 |  | 
| 189 | 
            -
            -  | 
| 190 | 
            -
            -  | 
| 150 | 
            +
            - [Active Record Query Tagging](https://github.com/drexed/cmdx/blob/main/examples/active_record_query_tagging.md)
         | 
| 151 | 
            +
            - [Paper Trail Whatdunnit](https://github.com/drexed/cmdx/blob/main/examples/paper_trail_whatdunnit.md)
         | 
    
        data/docs/workflows.md
    CHANGED
    
    | @@ -1,26 +1,14 @@ | |
| 1 1 | 
             
            # Workflows
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 5 | 
            -
            ## Table of Contents
         | 
| 6 | 
            -
             | 
| 7 | 
            -
            - [Declarations](#declarations)
         | 
| 8 | 
            -
              - [Task](#task)
         | 
| 9 | 
            -
              - [Group](#group)
         | 
| 10 | 
            -
              - [Conditionals](#conditionals)
         | 
| 11 | 
            -
            - [Halt Behavior](#halt-behavior)
         | 
| 12 | 
            -
              - [Task Configuration](#task-configuration)
         | 
| 13 | 
            -
              - [Group Configuration](#group-configuration)
         | 
| 14 | 
            -
            - [Nested Workflows](#nested-workflows)
         | 
| 15 | 
            -
            - [Parallel Execution](#parallel-execution)
         | 
| 16 | 
            -
            - [Task Generator](#task-generator)
         | 
| 3 | 
            +
            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.
         | 
| 17 4 |  | 
| 18 5 | 
             
            ## Declarations
         | 
| 19 6 |  | 
| 20 | 
            -
            Tasks  | 
| 7 | 
            +
            Tasks run in declaration order (FIFO), sharing a common context across the pipeline.
         | 
| 21 8 |  | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 9 | 
            +
            !!! warning
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                Don't define a `work` method in workflows—the module handles execution automatically.
         | 
| 24 12 |  | 
| 25 13 | 
             
            ### Task
         | 
| 26 14 |  | 
| @@ -35,15 +23,17 @@ class OnboardingWorkflow < CMDx::Task | |
| 35 23 | 
             
            end
         | 
| 36 24 | 
             
            ```
         | 
| 37 25 |  | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 26 | 
            +
            !!! tip
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                Execute tasks in parallel via the [cmdx-parallel](https://github.com/drexed/cmdx-parallel) gem.
         | 
| 40 29 |  | 
| 41 30 | 
             
            ### Group
         | 
| 42 31 |  | 
| 43 | 
            -
            Group related tasks  | 
| 32 | 
            +
            Group related tasks to share configuration:
         | 
| 44 33 |  | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 34 | 
            +
            !!! warning "Important"
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                Settings and conditionals apply to all tasks in the group.
         | 
| 47 37 |  | 
| 48 38 | 
             
            ```ruby
         | 
| 49 39 | 
             
            class ContentModerationWorkflow < CMDx::Task
         | 
| @@ -78,10 +68,10 @@ class OnboardingWorkflow < CMDx::Task | |
| 78 68 | 
             
              task SendWelcomeEmail, if: :email_configured?, unless: :email_disabled?
         | 
| 79 69 |  | 
| 80 70 | 
             
              # Proc
         | 
| 81 | 
            -
              task SendWelcomeEmail, if: -> | 
| 71 | 
            +
              task SendWelcomeEmail, if: -> { Rails.env.production? && self.class.name.include?("Premium") }
         | 
| 82 72 |  | 
| 83 73 | 
             
              # Lambda
         | 
| 84 | 
            -
              task SendWelcomeEmail, if: proc {  | 
| 74 | 
            +
              task SendWelcomeEmail, if: proc { context.features_enabled? }
         | 
| 85 75 |  | 
| 86 76 | 
             
              # Class or Module
         | 
| 87 77 | 
             
              task SendWelcomeEmail, unless: ContentAccessCheck
         | 
| @@ -95,7 +85,7 @@ class OnboardingWorkflow < CMDx::Task | |
| 95 85 | 
             
              private
         | 
| 96 86 |  | 
| 97 87 | 
             
              def email_configured?
         | 
| 98 | 
            -
                context.user.email_address | 
| 88 | 
            +
                context.user.email_address == true
         | 
| 99 89 | 
             
              end
         | 
| 100 90 |  | 
| 101 91 | 
             
              def email_disabled?
         | 
| @@ -106,9 +96,7 @@ end | |
| 106 96 |  | 
| 107 97 | 
             
            ## Halt Behavior
         | 
| 108 98 |  | 
| 109 | 
            -
            By default skipped tasks  | 
| 110 | 
            -
            This is configurable via global and task level breakpoint settings. Task and group configurations
         | 
| 111 | 
            -
            can be used together within a workflow.
         | 
| 99 | 
            +
            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.
         | 
| 112 100 |  | 
| 113 101 | 
             
            ```ruby
         | 
| 114 102 | 
             
            class AnalyticsWorkflow < CMDx::Task
         | 
| @@ -164,7 +152,7 @@ end | |
| 164 152 |  | 
| 165 153 | 
             
            ## Nested Workflows
         | 
| 166 154 |  | 
| 167 | 
            -
             | 
| 155 | 
            +
            Build hierarchical workflows by composing workflows within workflows:
         | 
| 168 156 |  | 
| 169 157 | 
             
            ```ruby
         | 
| 170 158 | 
             
            class EmailPreparationWorkflow < CMDx::Task
         | 
| @@ -191,10 +179,11 @@ end | |
| 191 179 |  | 
| 192 180 | 
             
            ## Parallel Execution
         | 
| 193 181 |  | 
| 194 | 
            -
             | 
| 182 | 
            +
            Run tasks concurrently using the [Parallel](https://github.com/grosser/parallel) gem. It automatically uses all available processors for maximum throughput.
         | 
| 183 | 
            +
             | 
| 184 | 
            +
            !!! warning
         | 
| 195 185 |  | 
| 196 | 
            -
             | 
| 197 | 
            -
            > Context cannot be modified during parallel execution. Ensure that all required data is preloaded into the context before parallelization begins.
         | 
| 186 | 
            +
                Context is read-only during parallel execution. Load all required data beforehand.
         | 
| 198 187 |  | 
| 199 188 | 
             
            ```ruby
         | 
| 200 189 | 
             
            class SendWelcomeNotifications < CMDx::Task
         | 
| @@ -232,10 +221,6 @@ class SendNotifications < CMDx::Task | |
| 232 221 | 
             
            end
         | 
| 233 222 | 
             
            ```
         | 
| 234 223 |  | 
| 235 | 
            -
             | 
| 236 | 
            -
            > Use **present tense verbs + pluralized noun** for workflow task names, eg: `SendNotifications`, `DownloadFiles`, `ValidateDocuments`
         | 
| 237 | 
            -
             | 
| 238 | 
            -
            ---
         | 
| 224 | 
            +
            !!! tip
         | 
| 239 225 |  | 
| 240 | 
            -
             | 
| 241 | 
            -
            - **Next:** [Tips and Tricks](tips_and_tricks.md)
         | 
| 226 | 
            +
                Use **present tense verbs + pluralized noun** for workflow task names, eg: `SendNotifications`, `DownloadFiles`, `ValidateDocuments`
         | 
| @@ -0,0 +1,46 @@ | |
| 1 | 
            +
            # Active Record Query Tagging
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Add a comment to every query indicating some context to help you track down where that query came from, eg:
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            ```sh
         | 
| 6 | 
            +
            /*cmdx_task_class:ExportReportTask,cmdx_chain_id:018c2b95-b764-7615*/ SELECT * FROM reports WHERE id = 1
         | 
| 7 | 
            +
            ```
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            ### Setup
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            ```ruby
         | 
| 12 | 
            +
            # config/application.rb
         | 
| 13 | 
            +
            config.active_record.query_log_tags_enabled = true
         | 
| 14 | 
            +
            config.active_record.query_log_tags += [
         | 
| 15 | 
            +
              :cmdx_correlation_id,
         | 
| 16 | 
            +
              :cmdx_chain_id,
         | 
| 17 | 
            +
              :cmdx_task_class,
         | 
| 18 | 
            +
              :cmdx_task_id
         | 
| 19 | 
            +
            ]
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            # lib/cmdx_query_tagging_middleware.rb
         | 
| 22 | 
            +
            class CmdxQueryTaggingMiddleware
         | 
| 23 | 
            +
              def self.call(task, **options, &)
         | 
| 24 | 
            +
                ActiveSupport::ExecutionContext.set(
         | 
| 25 | 
            +
                  cmdx_correlation_id: task.result.metadata[:correlation_id],
         | 
| 26 | 
            +
                  cmdx_chain_id: task.chain.id,
         | 
| 27 | 
            +
                  cmdx_task_class: task.class.name,
         | 
| 28 | 
            +
                  cmdx_task_id: task.id,
         | 
| 29 | 
            +
                  &
         | 
| 30 | 
            +
                )
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
            end
         | 
| 33 | 
            +
            ```
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            ### Usage
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            ```ruby
         | 
| 38 | 
            +
            class MyTask < CMDx::Task
         | 
| 39 | 
            +
              register :middleware, CmdxQueryTaggingMiddleware
         | 
| 40 | 
            +
             | 
| 41 | 
            +
              def work
         | 
| 42 | 
            +
                # Do work...
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
            end
         | 
| 46 | 
            +
            ```
         |