cmdx 1.8.0 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.DS_Store +0 -0
- data/.cursor/prompts/docs.md +3 -3
- data/.cursor/prompts/llms.md +1 -3
- data/.cursor/prompts/yardoc.md +1 -0
- data/.irbrc +14 -2
- data/CHANGELOG.md +64 -45
- data/LLM.md +159 -53
- data/README.md +26 -83
- data/docs/.DS_Store +0 -0
- data/docs/assets/favicon.ico +0 -0
- data/docs/assets/favicon.svg +1 -0
- data/docs/attributes/coercions.md +12 -24
- data/docs/attributes/defaults.md +3 -16
- data/docs/attributes/definitions.md +16 -30
- data/docs/attributes/naming.md +3 -13
- data/docs/attributes/transformations.md +63 -0
- data/docs/attributes/validations.md +14 -33
- data/docs/basics/chain.md +14 -23
- data/docs/basics/context.md +13 -22
- data/docs/basics/execution.md +8 -26
- data/docs/basics/setup.md +8 -19
- data/docs/callbacks.md +19 -32
- data/docs/deprecation.md +8 -25
- data/docs/getting_started.md +109 -76
- data/docs/index.md +132 -0
- data/docs/internationalization.md +6 -18
- data/docs/interruptions/exceptions.md +10 -16
- data/docs/interruptions/faults.md +8 -25
- data/docs/interruptions/halt.md +12 -27
- data/docs/logging.md +7 -17
- data/docs/middlewares.md +13 -29
- data/docs/outcomes/result.md +21 -38
- data/docs/outcomes/states.md +8 -22
- data/docs/outcomes/statuses.md +10 -21
- data/docs/stylesheets/extra.css +42 -0
- data/docs/tips_and_tricks.md +7 -46
- data/docs/workflows.md +23 -38
- data/examples/active_record_query_tagging.md +46 -0
- data/examples/paper_trail_whatdunnit.md +39 -0
- data/lib/cmdx/attribute.rb +88 -6
- data/lib/cmdx/attribute_registry.rb +20 -0
- data/lib/cmdx/attribute_value.rb +56 -10
- data/lib/cmdx/callback_registry.rb +31 -2
- data/lib/cmdx/chain.rb +34 -1
- data/lib/cmdx/coercion_registry.rb +18 -0
- data/lib/cmdx/coercions/array.rb +2 -0
- data/lib/cmdx/coercions/big_decimal.rb +3 -0
- data/lib/cmdx/coercions/boolean.rb +5 -0
- data/lib/cmdx/coercions/complex.rb +2 -0
- data/lib/cmdx/coercions/date.rb +4 -0
- data/lib/cmdx/coercions/date_time.rb +5 -0
- data/lib/cmdx/coercions/float.rb +2 -0
- data/lib/cmdx/coercions/hash.rb +4 -0
- data/lib/cmdx/coercions/integer.rb +2 -0
- data/lib/cmdx/coercions/rational.rb +2 -0
- data/lib/cmdx/coercions/string.rb +2 -0
- data/lib/cmdx/coercions/symbol.rb +2 -0
- data/lib/cmdx/coercions/time.rb +5 -0
- data/lib/cmdx/configuration.rb +119 -3
- data/lib/cmdx/context.rb +36 -0
- data/lib/cmdx/deprecator.rb +6 -3
- data/lib/cmdx/errors.rb +22 -0
- data/lib/cmdx/executor.rb +136 -7
- data/lib/cmdx/faults.rb +14 -0
- data/lib/cmdx/identifier.rb +2 -0
- data/lib/cmdx/locale.rb +3 -0
- data/lib/cmdx/log_formatters/json.rb +2 -0
- data/lib/cmdx/log_formatters/key_value.rb +2 -0
- data/lib/cmdx/log_formatters/line.rb +2 -0
- data/lib/cmdx/log_formatters/logstash.rb +2 -0
- data/lib/cmdx/log_formatters/raw.rb +2 -0
- data/lib/cmdx/middleware_registry.rb +20 -0
- data/lib/cmdx/middlewares/correlate.rb +11 -0
- data/lib/cmdx/middlewares/runtime.rb +4 -0
- data/lib/cmdx/middlewares/timeout.rb +4 -0
- data/lib/cmdx/pipeline.rb +24 -5
- data/lib/cmdx/railtie.rb +13 -0
- data/lib/cmdx/result.rb +133 -2
- data/lib/cmdx/task.rb +103 -8
- data/lib/cmdx/utils/call.rb +2 -0
- data/lib/cmdx/utils/condition.rb +3 -0
- data/lib/cmdx/utils/format.rb +5 -0
- data/lib/cmdx/validator_registry.rb +18 -0
- data/lib/cmdx/validators/exclusion.rb +2 -0
- data/lib/cmdx/validators/format.rb +2 -0
- data/lib/cmdx/validators/inclusion.rb +2 -0
- data/lib/cmdx/validators/length.rb +14 -0
- data/lib/cmdx/validators/numeric.rb +14 -0
- data/lib/cmdx/validators/presence.rb +2 -0
- data/lib/cmdx/version.rb +4 -1
- data/lib/cmdx/workflow.rb +10 -0
- data/lib/cmdx.rb +9 -0
- data/lib/generators/cmdx/locale_generator.rb +0 -1
- data/lib/generators/cmdx/templates/install.rb +9 -0
- data/mkdocs.yml +122 -0
- data/src/cmdx-dark-logo.png +0 -0
- data/src/cmdx-favicon.svg +1 -0
- data/src/cmdx-light-logo.png +0 -0
- data/src/cmdx-logo.svg +1 -0
- metadata +14 -3
- data/lib/cmdx/freezer.rb +0 -51
- data/src/cmdx-logo.png +0 -0
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 9220688eed061c4c48562665fe9c2c780a2ecc08642eeaedb095d6bfc312e643
         | 
| 4 | 
            +
              data.tar.gz: f470f2ccebce524942277865f2967979244dde07ba1a43095c7f95209127c635
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 155e2d09a4ca6147a7df578b0f2952ab81e781d5c492d821a4b71b08b41ef510cfccade001cc2e593f08ea1876ba6e5b658595a2bddaf6919f243c8df07d0569
         | 
| 7 | 
            +
              data.tar.gz: fd0dba94495d6d139dc13507169143ee83f13dfac521d6ef607800c6d6e4cfd13e47cc03e2f27e047b185a0b9ebfc0a9d080143f7c6c2ec61aec139f38ea17cd
         | 
    
        data/.DS_Store
    CHANGED
    
    | Binary file | 
    
        data/.cursor/prompts/docs.md
    CHANGED
    
    | @@ -3,10 +3,10 @@ You are a senior Ruby developer with expert knowledge of CMDx and writing docume | |
| 3 3 | 
             
            Update the active tab using the following guidelines:
         | 
| 4 4 |  | 
| 5 5 | 
             
            - Follow best practices and implementation
         | 
| 6 | 
            -
            - Use a consistent professional voice
         | 
| 6 | 
            +
            - Use a consistent warm, friendly and professional voice
         | 
| 7 7 | 
             
            - Examples should be concise, non-repetitive, and realistic
         | 
| 8 8 | 
             
            - Update any pre-existing documentation to match stated rules
         | 
| 9 9 | 
             
            - Examples should not cross boundaries or focus
         | 
| 10 | 
            -
            - Docs must cover both typical use cases, including  | 
| 11 | 
            -
            - Use  | 
| 10 | 
            +
            - Docs must cover both typical use cases, including invalid and error conditions
         | 
| 11 | 
            +
            - Use mkdocs Admonitions to emphasize critical information (https://squidfunk.github.io/mkdocs-material/reference/admonitions/)
         | 
| 12 12 | 
             
            - Optimize for LLM's including coding and AI agents
         | 
    
        data/.cursor/prompts/llms.md
    CHANGED
    
    | @@ -4,9 +4,7 @@ Process the following instructions in the order given: | |
| 4 4 | 
             
            2. Append all files within `docs/**/*.md` into @LLM.md
         | 
| 5 5 | 
             
              2a. Use order outlined in the table of contents of @README.md
         | 
| 6 6 | 
             
              2b. Process one file at a time faster performance and improved accuracy
         | 
| 7 | 
            -
              2c.  | 
| 8 | 
            -
              2c. Remove the navigations below `---` from the chunk
         | 
| 9 | 
            -
              2d. Wrap the chunk the files GitHub url the top and a spacer at the bottom like so:
         | 
| 7 | 
            +
              2c. Wrap the chunk the files GitHub url the top and a spacer at the bottom like so:
         | 
| 10 8 | 
             
                  ```
         | 
| 11 9 |  | 
| 12 10 | 
             
                  ---
         | 
    
        data/.cursor/prompts/yardoc.md
    CHANGED
    
    | @@ -12,3 +12,4 @@ Add yardoc to the active tab using the following guidelines: | |
| 12 12 | 
             
            - Method level docs should include `@example`, `param`, `@options`, `@return`, and any `@raise`
         | 
| 13 13 | 
             
            - Hash `@params` should expand with possible `@option`
         | 
| 14 14 | 
             
            - Module and method level docs should NOT include `@since`
         | 
| 15 | 
            +
            - Add RBS inline comments after YARDoc block
         | 
    
        data/.irbrc
    CHANGED
    
    | @@ -2,5 +2,17 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            require "pp"
         | 
| 4 4 |  | 
| 5 | 
            -
            #  | 
| 6 | 
            -
             | 
| 5 | 
            +
            # rubocop:disable Style/MixinUsage
         | 
| 6 | 
            +
            unless defined?(CMDx)
         | 
| 7 | 
            +
              require_relative "lib/cmdx"
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              require_relative "spec/support/helpers/task_builders"
         | 
| 10 | 
            +
              require_relative "spec/support/helpers/workflow_builders"
         | 
| 11 | 
            +
              include CMDx::Testing::TaskBuilders
         | 
| 12 | 
            +
              include CMDx::Testing::WorkflowBuilders
         | 
| 13 | 
            +
            end
         | 
| 14 | 
            +
            # rubocop:enable Style/MixinUsage
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            def reload!
         | 
| 17 | 
            +
              exec("irb")
         | 
| 18 | 
            +
            end
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -4,27 +4,44 @@ All notable changes to this project will be documented in this file. | |
| 4 4 |  | 
| 5 5 | 
             
            The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
         | 
| 6 6 |  | 
| 7 | 
            -
            ## [TODO]
         | 
| 8 | 
            -
            - Update exceptions with more info on how to fix the issue
         | 
| 9 | 
            -
            - Add trnasform option to attributes
         | 
| 10 | 
            -
            - Add option to output failure backtraces
         | 
| 11 | 
            -
            - Add durability (retries) to execution
         | 
| 12 | 
            -
             - N-retries (3 default)
         | 
| 13 | 
            -
             - Backoff strategy
         | 
| 14 | 
            -
             - On specific errors
         | 
| 15 | 
            -
             | 
| 16 7 | 
             
            ## [UNRELEASED]
         | 
| 17 8 |  | 
| 18 | 
            -
            -  | 
| 9 | 
            +
            ## [1.9.1] - 2025-10-22
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            ### Added
         | 
| 12 | 
            +
            - Added RBS inlines type signatures
         | 
| 13 | 
            +
            - Added YARDocs for `attr_reader` and `attr_accessor` methods
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            ## [1.9.0] - 2025-10-21
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            ### Added
         | 
| 18 | 
            +
            - Added `transform` option to attributes
         | 
| 19 | 
            +
            - Added option to output failure backtraces
         | 
| 20 | 
            +
            - Added exception handling for non-bang methods
         | 
| 21 | 
            +
            - Added durability with automatic retries to execution
         | 
| 22 | 
            +
            - Added `to_h` hash coercion support
         | 
| 23 | 
            +
            - Added comprehensive MkDocs configuration with material theme
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            ### Changed
         | 
| 26 | 
            +
            - Improved performance of task settings setup
         | 
| 27 | 
            +
            - Improved error messages for raised exceptions
         | 
| 28 | 
            +
            - Improved inheritance of parent settings
         | 
| 29 | 
            +
            - Cleaned halt backtrace frames for better readability
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            ### Removed
         | 
| 32 | 
            +
            - Removed `Freezer` module and moved logic into executor `freeze_execution!` method
         | 
| 33 | 
            +
            - Removed task parameter from callback signature
         | 
| 34 | 
            +
            - Removed task and workflow arguments from conditional checks
         | 
| 35 | 
            +
            - Removed chain persistence after execution in specs
         | 
| 19 36 |  | 
| 20 37 | 
             
            ## [1.8.0] - 2025-09-22
         | 
| 21 38 |  | 
| 22 | 
            -
            ###  | 
| 23 | 
            -
            -  | 
| 24 | 
            -
            -  | 
| 25 | 
            -
            - Reordered logstash formatter keys
         | 
| 26 | 
            -
            - Improved already defined  | 
| 27 | 
            -
            -  | 
| 39 | 
            +
            ### Changed
         | 
| 40 | 
            +
            - Generalized locale values for fault `invalid` and `unspecified`
         | 
| 41 | 
            +
            - Nested attribute error messages under `error` key within metadata
         | 
| 42 | 
            +
            - Reordered logstash formatter keys for consistency
         | 
| 43 | 
            +
            - Improved error message for already defined items
         | 
| 44 | 
            +
            - Changed hash coercion for `nil` to return `{}`
         | 
| 28 45 |  | 
| 29 46 | 
             
            ## [1.7.5] - 2025-09-10
         | 
| 30 47 |  | 
| @@ -42,69 +59,71 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), | |
| 42 59 |  | 
| 43 60 | 
             
            ## [1.7.3] - 2025-09-03
         | 
| 44 61 |  | 
| 45 | 
            -
            ###  | 
| 46 | 
            -
            -  | 
| 47 | 
            -
            -  | 
| 62 | 
            +
            ### Changed
         | 
| 63 | 
            +
            - Changed validation reasons to use generic values
         | 
| 64 | 
            +
            - Moved validation full message string to `:full_message` key within metadata
         | 
| 48 65 |  | 
| 49 66 | 
             
            ## [1.7.2] - 2025-09-03
         | 
| 50 67 |  | 
| 51 | 
            -
            ###  | 
| 52 | 
            -
            -  | 
| 68 | 
            +
            ### Changed
         | 
| 69 | 
            +
            - Changed correlation ID to be set before continuing to further steps
         | 
| 53 70 |  | 
| 54 71 | 
             
            ## [1.7.1] - 2025-08-26
         | 
| 55 72 |  | 
| 56 73 | 
             
            ### Added
         | 
| 57 | 
            -
            -  | 
| 74 | 
            +
            - Added result yielding when block is given to `execute` and `execute!` methods
         | 
| 58 75 |  | 
| 59 76 | 
             
            ## [1.7.0] - 2025-08-25
         | 
| 60 77 |  | 
| 61 78 | 
             
            ### Added
         | 
| 62 | 
            -
            -  | 
| 79 | 
            +
            - Added workflow generator
         | 
| 63 80 |  | 
| 64 | 
            -
            ###  | 
| 65 | 
            -
            -  | 
| 66 | 
            -
            -  | 
| 81 | 
            +
            ### Changed
         | 
| 82 | 
            +
            - Ported `cmdx-parallel` changes into core
         | 
| 83 | 
            +
            - Ported `cmdx-i18n` changes into core
         | 
| 67 84 |  | 
| 68 85 | 
             
            ## [1.6.2] - 2025-08-24
         | 
| 69 86 |  | 
| 70 | 
            -
            ###  | 
| 71 | 
            -
            -  | 
| 72 | 
            -
            -  | 
| 87 | 
            +
            ### Changed
         | 
| 88 | 
            +
            - Prefixed railtie I18n with `::` for compatibility with `CMDx::I18n`
         | 
| 89 | 
            +
            - Changed to use `cmdx-rspec` for matchers support
         | 
| 73 90 |  | 
| 74 91 | 
             
            ## [1.6.1] - 2025-08-23
         | 
| 75 92 |  | 
| 76 | 
            -
            ###  | 
| 77 | 
            -
            -  | 
| 78 | 
            -
            -  | 
| 93 | 
            +
            ### Changed
         | 
| 94 | 
            +
            - Changed task results to be logged before freezing
         | 
| 95 | 
            +
            - Renamed `execute_tasks_sequentially` to `execute_tasks_in_sequence`
         | 
| 79 96 |  | 
| 80 97 | 
             
            ## [1.6.0] - 2025-08-22
         | 
| 81 98 |  | 
| 82 | 
            -
            ###  | 
| 83 | 
            -
            -  | 
| 84 | 
            -
             | 
| 85 | 
            -
             | 
| 99 | 
            +
            ### Added
         | 
| 100 | 
            +
            - Added workflow task `:breakpoints` support
         | 
| 101 | 
            +
             | 
| 102 | 
            +
            ### Changed
         | 
| 103 | 
            +
            - Renamed `Worker` class to `Executor`
         | 
| 104 | 
            +
            - Moved workflow `work` logic into `Pipeline`
         | 
| 86 105 |  | 
| 87 106 | 
             
            ## [1.5.2] - 2025-08-22
         | 
| 88 107 |  | 
| 89 | 
            -
            ###  | 
| 90 | 
            -
            -  | 
| 108 | 
            +
            ### Changed
         | 
| 109 | 
            +
            - Renamed workflow `execution_groups` attribute to `pipeline`
         | 
| 91 110 |  | 
| 92 111 | 
             
            ## [1.5.1] - 2025-08-21
         | 
| 93 112 |  | 
| 94 | 
            -
            ###  | 
| 95 | 
            -
            -  | 
| 96 | 
            -
            -  | 
| 97 | 
            -
            -  | 
| 113 | 
            +
            ### Changed
         | 
| 114 | 
            +
            - Prefixed locale I18n with `::` for compatibility with `CMDx::I18n`
         | 
| 115 | 
            +
            - Added safe navigation to length and numeric validators
         | 
| 116 | 
            +
            - Updated railtie file path to point to correct directory
         | 
| 98 117 |  | 
| 99 118 | 
             
            ## [1.5.0] - 2025-08-21
         | 
| 100 119 |  | 
| 101 | 
            -
            ###  | 
| 102 | 
            -
            - BREAKING  | 
| 120 | 
            +
            ### Changed
         | 
| 121 | 
            +
            - **BREAKING**: Revamped CMDx for improved clarity, transparency, and higher performance
         | 
| 103 122 |  | 
| 104 123 | 
             
            ## [1.1.2] - 2025-07-20
         | 
| 105 124 |  | 
| 106 125 | 
             
            ### Changed
         | 
| 107 | 
            -
            - All  | 
| 126 | 
            +
            - All changes between versions `0.1.0` and `1.1.2` should be reviewed within their respective git tags
         | 
| 108 127 |  | 
| 109 128 | 
             
            ## [0.1.0] - 2025-03-07
         | 
| 110 129 |  | 
    
        data/LLM.md
    CHANGED
    
    | @@ -87,6 +87,45 @@ CMDx.configure do |config| | |
| 87 87 | 
             
            end
         | 
| 88 88 | 
             
            ```
         | 
| 89 89 |  | 
| 90 | 
            +
            ### Backtraces
         | 
| 91 | 
            +
             | 
| 92 | 
            +
            Enable backtraces to be logged on any non-fault exceptions for improved debugging context. Run them through a cleaner to remove unwanted stack trace noise.
         | 
| 93 | 
            +
             | 
| 94 | 
            +
            > [!NOTE]
         | 
| 95 | 
            +
            > The `backtrace_cleaner` is set to `Rails.backtrace_cleaner.clean` in a Rails env by default.
         | 
| 96 | 
            +
             | 
| 97 | 
            +
            ```ruby
         | 
| 98 | 
            +
            CMDx.configure do |config|
         | 
| 99 | 
            +
              # Truthy
         | 
| 100 | 
            +
              config.backtrace = true
         | 
| 101 | 
            +
             | 
| 102 | 
            +
              # Via callable (must respond to `call(backtrace)`)
         | 
| 103 | 
            +
              config.backtrace_cleaner = AdvanceCleaner.new
         | 
| 104 | 
            +
             | 
| 105 | 
            +
              # Via proc or lambda
         | 
| 106 | 
            +
              config.backtrace_cleaner = ->(backtrace) { backtrace[0..5] }
         | 
| 107 | 
            +
            end
         | 
| 108 | 
            +
            ```
         | 
| 109 | 
            +
             | 
| 110 | 
            +
            ### Exception Handlers
         | 
| 111 | 
            +
             | 
| 112 | 
            +
            Use exception handlers are called on non-fault standard error based exceptions.
         | 
| 113 | 
            +
             | 
| 114 | 
            +
            > [!TIP]
         | 
| 115 | 
            +
            > Use exception handlers to send errors to your APM of choice.
         | 
| 116 | 
            +
             | 
| 117 | 
            +
            ```ruby
         | 
| 118 | 
            +
            CMDx.configure do |config|
         | 
| 119 | 
            +
              # Via callable (must respond to `call(task, exception)`)
         | 
| 120 | 
            +
              config.exception_handler = NewRelicReporter
         | 
| 121 | 
            +
             | 
| 122 | 
            +
              # Via proc or lambda
         | 
| 123 | 
            +
              config.exception_handler = proc do |task, exception|
         | 
| 124 | 
            +
                APMService.report(exception, extra_data: { task: task.name, id: task.id })
         | 
| 125 | 
            +
              end
         | 
| 126 | 
            +
            end
         | 
| 127 | 
            +
            ```
         | 
| 128 | 
            +
             | 
| 90 129 | 
             
            ### Logging
         | 
| 91 130 |  | 
| 92 131 | 
             
            ```ruby
         | 
| @@ -213,6 +252,8 @@ class GenerateInvoice < CMDx::Task | |
| 213 252 | 
             
                # Global configuration overrides
         | 
| 214 253 | 
             
                task_breakpoints: ["failed"],                # Breakpoint override
         | 
| 215 254 | 
             
                workflow_breakpoints: [],                    # Breakpoint override
         | 
| 255 | 
            +
                backtrace: true,                             # Toggle backtrace
         | 
| 256 | 
            +
                backtrace_cleaner: ->(bt) { bt[0..5] },      # Backtrace cleaner
         | 
| 216 257 | 
             
                logger: CustomLogger.new($stdout),           # Custom logger
         | 
| 217 258 |  | 
| 218 259 | 
             
                # Task configuration settings
         | 
| @@ -220,7 +261,10 @@ class GenerateInvoice < CMDx::Task | |
| 220 261 | 
             
                log_level: :info,                            # Log level override
         | 
| 221 262 | 
             
                log_formatter: CMDx::LogFormatters::Json.new # Log formatter override
         | 
| 222 263 | 
             
                tags: ["billing", "financial"],              # Logging tags
         | 
| 223 | 
            -
                deprecated: true | 
| 264 | 
            +
                deprecated: true,                            # Task deprecations
         | 
| 265 | 
            +
                retries: 3,                                  # Non-fault exception retries
         | 
| 266 | 
            +
                retry_on: [External::ApiError],              # List of exceptions to retry on
         | 
| 267 | 
            +
                retry_jitter: 1                              # Space between retry iteration, eg: current retry num + 1
         | 
| 224 268 | 
             
              )
         | 
| 225 269 |  | 
| 226 270 | 
             
              def work
         | 
| @@ -229,8 +273,8 @@ class GenerateInvoice < CMDx::Task | |
| 229 273 | 
             
            end
         | 
| 230 274 | 
             
            ```
         | 
| 231 275 |  | 
| 232 | 
            -
            > [! | 
| 233 | 
            -
            >  | 
| 276 | 
            +
            > [!IMPORTANT]
         | 
| 277 | 
            +
            > Retries reuse the same context when executing its work. By default all `StandardErrors` will be retried if no `retry_on` option is passed.
         | 
| 234 278 |  | 
| 235 279 | 
             
            ### Registrations
         | 
| 236 280 |  | 
| @@ -328,6 +372,15 @@ end | |
| 328 372 | 
             
            > [!TIP]
         | 
| 329 373 | 
             
            > Use **present tense verbs + noun** for task names, eg: `ModerateBlogPost`, `ScheduleAppointment`, `ValidateDocument`
         | 
| 330 374 |  | 
| 375 | 
            +
            ## Type safety
         | 
| 376 | 
            +
             | 
| 377 | 
            +
            CMDx includes built-in RBS (Ruby Type Signature) inline annotations throughout the codebase, providing type information for static analysis and editor support.
         | 
| 378 | 
            +
             | 
| 379 | 
            +
            - **Type checking** — Catch type errors before runtime using tools like Steep or TypeProf
         | 
| 380 | 
            +
            - **Better IDE support** — Enhanced autocomplete, navigation, and inline documentation
         | 
| 381 | 
            +
            - **Self-documenting code** — Clear method signatures and return types
         | 
| 382 | 
            +
            - **Refactoring confidence** — Type-aware refactoring reduces bugs
         | 
| 383 | 
            +
             | 
| 331 384 | 
             
            ---
         | 
| 332 385 |  | 
| 333 386 | 
             
            url: https://github.com/drexed/cmdx/blob/main/docs/basics/setup.md
         | 
| @@ -1170,6 +1223,9 @@ result.reason   #=> "[ActiveRecord::NotFoundError] record not found" | |
| 1170 1223 | 
             
            result.cause    #=> <ActiveRecord::NotFoundError>
         | 
| 1171 1224 | 
             
            ```
         | 
| 1172 1225 |  | 
| 1226 | 
            +
            > [!NOTE]
         | 
| 1227 | 
            +
            > The `exception_handler` setting only works with non-bang execution as it catches all exceptions preventing them from reaching your apps global error handler.
         | 
| 1228 | 
            +
             | 
| 1173 1229 | 
             
            ### Bang execution
         | 
| 1174 1230 |  | 
| 1175 1231 | 
             
            The `execute!` method allows unhandled exceptions to propagate, enabling standard Ruby exception handling while respecting CMDx fault configuration.
         | 
| @@ -1321,19 +1377,19 @@ result = BuildApplication.execute(version: "1.2.3") | |
| 1321 1377 |  | 
| 1322 1378 | 
             
            # Status-based handlers
         | 
| 1323 1379 | 
             
            result
         | 
| 1324 | 
            -
              . | 
| 1325 | 
            -
              . | 
| 1326 | 
            -
              . | 
| 1380 | 
            +
              .handle_success { |result| notify_deployment_ready(result) }
         | 
| 1381 | 
            +
              .handle_failed { |result| handle_build_failure(result) }
         | 
| 1382 | 
            +
              .handle_skipped { |result| log_skip_reason(result) }
         | 
| 1327 1383 |  | 
| 1328 1384 | 
             
            # State-based handlers
         | 
| 1329 1385 | 
             
            result
         | 
| 1330 | 
            -
              . | 
| 1331 | 
            -
              . | 
| 1386 | 
            +
              .handle_complete { |result| update_build_status(result) }
         | 
| 1387 | 
            +
              .handle_interrupted { |result| cleanup_partial_artifacts(result) }
         | 
| 1332 1388 |  | 
| 1333 1389 | 
             
            # Outcome-based handlers
         | 
| 1334 1390 | 
             
            result
         | 
| 1335 | 
            -
              . | 
| 1336 | 
            -
              . | 
| 1391 | 
            +
              .handle_good { |result| increment_success_counter(result) }
         | 
| 1392 | 
            +
              .handle_bad { |result| alert_operations_team(result) }
         | 
| 1337 1393 | 
             
            ```
         | 
| 1338 1394 |  | 
| 1339 1395 | 
             
            ## Pattern Matching
         | 
| @@ -1455,9 +1511,9 @@ result = ProcessVideoUpload.execute | |
| 1455 1511 |  | 
| 1456 1512 | 
             
            # Individual state handlers
         | 
| 1457 1513 | 
             
            result
         | 
| 1458 | 
            -
              . | 
| 1459 | 
            -
              . | 
| 1460 | 
            -
              . | 
| 1514 | 
            +
              .handle_complete { |result| send_upload_notification(result) }
         | 
| 1515 | 
            +
              .handle_interrupted { |result| cleanup_temp_files(result) }
         | 
| 1516 | 
            +
              .handle_executed { |result| log_upload_metrics(result) }
         | 
| 1461 1517 | 
             
            ```
         | 
| 1462 1518 |  | 
| 1463 1519 | 
             
            ---
         | 
| @@ -1520,14 +1576,14 @@ result = ProcessNotification.execute | |
| 1520 1576 |  | 
| 1521 1577 | 
             
            # Individual status handlers
         | 
| 1522 1578 | 
             
            result
         | 
| 1523 | 
            -
              . | 
| 1524 | 
            -
              . | 
| 1525 | 
            -
              . | 
| 1579 | 
            +
              .handle_success { |result| mark_notification_sent(result) }
         | 
| 1580 | 
            +
              .handle_skipped { |result| log_notification_skipped(result) }
         | 
| 1581 | 
            +
              .handle_failed { |result| queue_retry_notification(result) }
         | 
| 1526 1582 |  | 
| 1527 1583 | 
             
            # Outcome-based handlers
         | 
| 1528 1584 | 
             
            result
         | 
| 1529 | 
            -
              . | 
| 1530 | 
            -
              . | 
| 1585 | 
            +
              .handle_good { |result| update_message_stats(result) }
         | 
| 1586 | 
            +
              .handle_bad { |result| track_delivery_failure(result) }
         | 
| 1531 1587 | 
             
            ```
         | 
| 1532 1588 |  | 
| 1533 1589 | 
             
            ---
         | 
| @@ -2419,6 +2475,80 @@ end | |
| 2419 2475 |  | 
| 2420 2476 | 
             
            ---
         | 
| 2421 2477 |  | 
| 2478 | 
            +
            url: https://github.com/drexed/cmdx/blob/main/docs/attributes/transformations.md
         | 
| 2479 | 
            +
            ---
         | 
| 2480 | 
            +
             | 
| 2481 | 
            +
            # Attributes - Transformations
         | 
| 2482 | 
            +
             | 
| 2483 | 
            +
            Transformations allow you to modify attribute values after they are derived and coerced from their source but before any validations. This enables data normalization, formatting, and conditional processing within the attribute pipeline.
         | 
| 2484 | 
            +
             | 
| 2485 | 
            +
            ## Declarations
         | 
| 2486 | 
            +
             | 
| 2487 | 
            +
            ### Symbol References
         | 
| 2488 | 
            +
             | 
| 2489 | 
            +
            Reference instance methods by symbol for dynamic value transformations:
         | 
| 2490 | 
            +
             | 
| 2491 | 
            +
            ```ruby
         | 
| 2492 | 
            +
            class ProcessAnalytics < CMDx::Task
         | 
| 2493 | 
            +
              attribute :options, transform: :compact_blank
         | 
| 2494 | 
            +
            end
         | 
| 2495 | 
            +
            ```
         | 
| 2496 | 
            +
             | 
| 2497 | 
            +
            ### Proc or Lambda
         | 
| 2498 | 
            +
             | 
| 2499 | 
            +
            Use anonymous functions for dynamic value transformations:
         | 
| 2500 | 
            +
             | 
| 2501 | 
            +
            ```ruby
         | 
| 2502 | 
            +
            class CacheContent < CMDx::Task
         | 
| 2503 | 
            +
              # Proc
         | 
| 2504 | 
            +
              attribute :expire_hours, transform: proc { |v| v * 2 }
         | 
| 2505 | 
            +
             | 
| 2506 | 
            +
              # Lambda
         | 
| 2507 | 
            +
              attribute :compression, transform: ->(v) { v.to_s.upcase.strip[0..2]  }
         | 
| 2508 | 
            +
            end
         | 
| 2509 | 
            +
            ```
         | 
| 2510 | 
            +
             | 
| 2511 | 
            +
            ### Class or Module
         | 
| 2512 | 
            +
             | 
| 2513 | 
            +
            Use any object that responds to `call` for reusable transformation logic:
         | 
| 2514 | 
            +
             | 
| 2515 | 
            +
            ```ruby
         | 
| 2516 | 
            +
            class EmailNormalizer
         | 
| 2517 | 
            +
              def call(value)
         | 
| 2518 | 
            +
                value.to_s.downcase.strip
         | 
| 2519 | 
            +
              end
         | 
| 2520 | 
            +
            end
         | 
| 2521 | 
            +
             | 
| 2522 | 
            +
            class ProcessContacts < CMDx::Task
         | 
| 2523 | 
            +
              # Class or Module
         | 
| 2524 | 
            +
              attribute :email, transform: EmailNormalizer
         | 
| 2525 | 
            +
             | 
| 2526 | 
            +
              # Instance
         | 
| 2527 | 
            +
              attribute :email, transform: EmailNormalizer.new
         | 
| 2528 | 
            +
            end
         | 
| 2529 | 
            +
            ```
         | 
| 2530 | 
            +
             | 
| 2531 | 
            +
            ## Validations
         | 
| 2532 | 
            +
             | 
| 2533 | 
            +
            Transformed values are subject to the same validation rules as untransformed values, ensuring consistency and catching configuration errors early.
         | 
| 2534 | 
            +
             | 
| 2535 | 
            +
            ```ruby
         | 
| 2536 | 
            +
            class ScheduleBackup < CMDx::Task
         | 
| 2537 | 
            +
              # Coercions
         | 
| 2538 | 
            +
              attribute :retention_days, type: :integer, transform: proc { |v| v.clamp(1, 5) }
         | 
| 2539 | 
            +
             | 
| 2540 | 
            +
              # Validations
         | 
| 2541 | 
            +
              optional :frequency, transform: :downcase, inclusion: { in: %w[hourly daily weekly monthly] }
         | 
| 2542 | 
            +
            end
         | 
| 2543 | 
            +
            ```
         | 
| 2544 | 
            +
             | 
| 2545 | 
            +
            ---
         | 
| 2546 | 
            +
             | 
| 2547 | 
            +
            - **Prev:** [Attributes - Defaults](defaults.md)
         | 
| 2548 | 
            +
            - **Next:** [Callbacks](../callbacks.md)
         | 
| 2549 | 
            +
             | 
| 2550 | 
            +
            ---
         | 
| 2551 | 
            +
             | 
| 2422 2552 | 
             
            url: https://github.com/drexed/cmdx/blob/main/docs/callbacks.md
         | 
| 2423 2553 | 
             
            ---
         | 
| 2424 2554 |  | 
| @@ -2487,7 +2617,7 @@ Use anonymous functions for inline callback logic: | |
| 2487 2617 | 
             
            ```ruby
         | 
| 2488 2618 | 
             
            class ProcessBooking < CMDx::Task
         | 
| 2489 2619 | 
             
              # Proc
         | 
| 2490 | 
            -
              on_interrupted proc {  | 
| 2620 | 
            +
              on_interrupted proc { ReservationSystem.pause! }
         | 
| 2491 2621 |  | 
| 2492 2622 | 
             
              # Lambda
         | 
| 2493 2623 | 
             
              on_complete -> { ReservationSystem.resume! }
         | 
| @@ -2534,10 +2664,10 @@ class ProcessBooking < CMDx::Task | |
| 2534 2664 | 
             
              before_execution :notify_guest, if: :messaging_enabled?, unless: :messaging_blocked?
         | 
| 2535 2665 |  | 
| 2536 2666 | 
             
              # Proc
         | 
| 2537 | 
            -
              on_failure :increment_failure, if: -> | 
| 2667 | 
            +
              on_failure :increment_failure, if: -> { Rails.env.production? && self.class.name.include?("Legacy") }
         | 
| 2538 2668 |  | 
| 2539 2669 | 
             
              # Lambda
         | 
| 2540 | 
            -
              on_success :ping_housekeeping, if: proc {  | 
| 2670 | 
            +
              on_success :ping_housekeeping, if: proc { context.rooms_need_cleaning? }
         | 
| 2541 2671 |  | 
| 2542 2672 | 
             
              # Class or Module
         | 
| 2543 2673 | 
             
              on_complete :send_confirmation, unless: MessagingPermissionCheck
         | 
| @@ -2552,7 +2682,7 @@ class ProcessBooking < CMDx::Task | |
| 2552 2682 | 
             
              private
         | 
| 2553 2683 |  | 
| 2554 2684 | 
             
              def messaging_enabled?
         | 
| 2555 | 
            -
                context.guest.messaging_preference | 
| 2685 | 
            +
                context.guest.messaging_preference == true
         | 
| 2556 2686 | 
             
              end
         | 
| 2557 2687 |  | 
| 2558 2688 | 
             
              def messaging_blocked?
         | 
| @@ -3076,7 +3206,7 @@ result = ProcessOldData.execute | |
| 3076 3206 | 
             
            result.successful? #=> true
         | 
| 3077 3207 |  | 
| 3078 3208 | 
             
            # Ruby warning appears in stderr:
         | 
| 3079 | 
            -
            # [ProcessOldData] DEPRECATED: migrate to replacement or discontinue use
         | 
| 3209 | 
            +
            # [ProcessOldData] DEPRECATED: migrate to a replacement or discontinue use
         | 
| 3080 3210 | 
             
            ```
         | 
| 3081 3211 |  | 
| 3082 3212 | 
             
            ## Declarations
         | 
| @@ -3227,10 +3357,10 @@ class OnboardingWorkflow < CMDx::Task | |
| 3227 3357 | 
             
              task SendWelcomeEmail, if: :email_configured?, unless: :email_disabled?
         | 
| 3228 3358 |  | 
| 3229 3359 | 
             
              # Proc
         | 
| 3230 | 
            -
              task SendWelcomeEmail, if: -> | 
| 3360 | 
            +
              task SendWelcomeEmail, if: -> { Rails.env.production? && self.class.name.include?("Premium") }
         | 
| 3231 3361 |  | 
| 3232 3362 | 
             
              # Lambda
         | 
| 3233 | 
            -
              task SendWelcomeEmail, if: proc {  | 
| 3363 | 
            +
              task SendWelcomeEmail, if: proc { context.features_enabled? }
         | 
| 3234 3364 |  | 
| 3235 3365 | 
             
              # Class or Module
         | 
| 3236 3366 | 
             
              task SendWelcomeEmail, unless: ContentAccessCheck
         | 
| @@ -3244,7 +3374,7 @@ class OnboardingWorkflow < CMDx::Task | |
| 3244 3374 | 
             
              private
         | 
| 3245 3375 |  | 
| 3246 3376 | 
             
              def email_configured?
         | 
| 3247 | 
            -
                context.user.email_address | 
| 3377 | 
            +
                context.user.email_address == true
         | 
| 3248 3378 | 
             
              end
         | 
| 3249 3379 |  | 
| 3250 3380 | 
             
              def email_disabled?
         | 
| @@ -3536,33 +3666,9 @@ class ConfigureCompany < CMDx::Task | |
| 3536 3666 | 
             
            end
         | 
| 3537 3667 | 
             
            ```
         | 
| 3538 3668 |  | 
| 3539 | 
            -
            ##  | 
| 3669 | 
            +
            ## Advance Examples
         | 
| 3540 3670 |  | 
| 3541 | 
            -
             | 
| 3542 | 
            -
             | 
| 3543 | 
            -
            ```ruby
         | 
| 3544 | 
            -
            # config/application.rb
         | 
| 3545 | 
            -
            config.active_record.query_log_tags_enabled = true
         | 
| 3546 | 
            -
            config.active_record.query_log_tags << :cmdx_task_class
         | 
| 3547 | 
            -
            config.active_record.query_log_tags << :cmdx_chain_id
         | 
| 3548 | 
            -
             | 
| 3549 | 
            -
            # app/tasks/application_task.rb
         | 
| 3550 | 
            -
            class ApplicationTask < CMDx::Task
         | 
| 3551 | 
            -
              before_execution :set_execution_context
         | 
| 3552 | 
            -
             | 
| 3553 | 
            -
              private
         | 
| 3554 | 
            -
             | 
| 3555 | 
            -
              def set_execution_context
         | 
| 3556 | 
            -
                # NOTE: This could easily be made into a middleware
         | 
| 3557 | 
            -
                ActiveSupport::ExecutionContext.set(
         | 
| 3558 | 
            -
                  cmdx_task_class: self.class.name,
         | 
| 3559 | 
            -
                  cmdx_chain_id: chain.id
         | 
| 3560 | 
            -
                )
         | 
| 3561 | 
            -
              end
         | 
| 3562 | 
            -
            end
         | 
| 3563 | 
            -
             | 
| 3564 | 
            -
            # SQL queries will now include comments like:
         | 
| 3565 | 
            -
            # /*cmdx_task_class:ExportReportTask,cmdx_chain_id:018c2b95-b764-7615*/ SELECT * FROM reports WHERE id = 1
         | 
| 3566 | 
            -
            ```
         | 
| 3671 | 
            +
            - [Active Record Query Tagging](https://github.com/drexed/cmdx/blob/main/examples/active_record_query_tagging.md)
         | 
| 3672 | 
            +
            - [Paper Trail Whatdunnit](https://github.com/drexed/cmdx/blob/main/examples/paper_trail_whatdunnit.md)
         | 
| 3567 3673 |  | 
| 3568 3674 | 
             
            ---
         |