otto 2.0.0.pre3 → 2.0.0.pre8

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.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +1 -1
  3. data/.github/workflows/claude-code-review.yml +1 -1
  4. data/.github/workflows/code-smells.yml +143 -0
  5. data/.gitignore +4 -0
  6. data/.pre-commit-config.yaml +2 -2
  7. data/.reek.yml +99 -0
  8. data/CHANGELOG.rst +156 -0
  9. data/CLAUDE.md +74 -540
  10. data/Gemfile +4 -2
  11. data/Gemfile.lock +58 -19
  12. data/README.md +49 -1
  13. data/examples/advanced_routes/README.md +137 -20
  14. data/examples/authentication_strategies/README.md +212 -19
  15. data/examples/backtrace_sanitization_demo.rb +86 -0
  16. data/examples/basic/README.md +61 -10
  17. data/examples/error_handler_registration.rb +136 -0
  18. data/examples/logging_improvements.rb +76 -0
  19. data/examples/mcp_demo/README.md +187 -27
  20. data/examples/security_features/README.md +249 -30
  21. data/examples/simple_geo_resolver.rb +107 -0
  22. data/lib/otto/core/configuration.rb +15 -20
  23. data/lib/otto/core/error_handler.rb +138 -8
  24. data/lib/otto/core/file_safety.rb +2 -2
  25. data/lib/otto/core/freezable.rb +2 -2
  26. data/lib/otto/core/middleware_stack.rb +2 -2
  27. data/lib/otto/core/router.rb +61 -8
  28. data/lib/otto/core/uri_generator.rb +2 -2
  29. data/lib/otto/core.rb +2 -0
  30. data/lib/otto/design_system.rb +2 -2
  31. data/lib/otto/env_keys.rb +61 -12
  32. data/lib/otto/helpers/base.rb +2 -2
  33. data/lib/otto/helpers/request.rb +8 -3
  34. data/lib/otto/helpers/response.rb +2 -2
  35. data/lib/otto/helpers/validation.rb +2 -2
  36. data/lib/otto/helpers.rb +2 -0
  37. data/lib/otto/locale/config.rb +2 -2
  38. data/lib/otto/locale/middleware.rb +160 -0
  39. data/lib/otto/locale.rb +10 -0
  40. data/lib/otto/logging_helpers.rb +273 -0
  41. data/lib/otto/mcp/auth/token.rb +2 -2
  42. data/lib/otto/mcp/protocol.rb +2 -2
  43. data/lib/otto/mcp/rate_limiting.rb +2 -2
  44. data/lib/otto/mcp/registry.rb +2 -2
  45. data/lib/otto/mcp/route_parser.rb +2 -2
  46. data/lib/otto/mcp/schema_validation.rb +2 -2
  47. data/lib/otto/mcp/server.rb +2 -2
  48. data/lib/otto/mcp.rb +2 -0
  49. data/lib/otto/privacy/config.rb +2 -0
  50. data/lib/otto/privacy/geo_resolver.rb +199 -29
  51. data/lib/otto/privacy/ip_privacy.rb +2 -0
  52. data/lib/otto/privacy/redacted_fingerprint.rb +18 -8
  53. data/lib/otto/privacy.rb +2 -0
  54. data/lib/otto/response_handlers/auto.rb +2 -0
  55. data/lib/otto/response_handlers/base.rb +2 -0
  56. data/lib/otto/response_handlers/default.rb +2 -0
  57. data/lib/otto/response_handlers/factory.rb +2 -0
  58. data/lib/otto/response_handlers/json.rb +2 -0
  59. data/lib/otto/response_handlers/redirect.rb +2 -0
  60. data/lib/otto/response_handlers/view.rb +2 -0
  61. data/lib/otto/response_handlers.rb +2 -2
  62. data/lib/otto/route.rb +4 -4
  63. data/lib/otto/route_definition.rb +42 -15
  64. data/lib/otto/route_handlers/base.rb +2 -0
  65. data/lib/otto/route_handlers/class_method.rb +26 -26
  66. data/lib/otto/route_handlers/factory.rb +2 -2
  67. data/lib/otto/route_handlers/instance_method.rb +16 -6
  68. data/lib/otto/route_handlers/lambda.rb +8 -20
  69. data/lib/otto/route_handlers/logic_class.rb +33 -8
  70. data/lib/otto/route_handlers.rb +2 -2
  71. data/lib/otto/security/authentication/auth_failure.rb +2 -2
  72. data/lib/otto/security/authentication/auth_strategy.rb +11 -4
  73. data/lib/otto/security/authentication/route_auth_wrapper/response_builder.rb +123 -0
  74. data/lib/otto/security/authentication/route_auth_wrapper/role_authorization.rb +120 -0
  75. data/lib/otto/security/authentication/route_auth_wrapper/strategy_resolver.rb +69 -0
  76. data/lib/otto/security/authentication/route_auth_wrapper.rb +185 -195
  77. data/lib/otto/security/authentication/strategies/api_key_strategy.rb +2 -0
  78. data/lib/otto/security/authentication/strategies/noauth_strategy.rb +2 -0
  79. data/lib/otto/security/authentication/strategies/permission_strategy.rb +2 -0
  80. data/lib/otto/security/authentication/strategies/role_strategy.rb +2 -0
  81. data/lib/otto/security/authentication/strategies/session_strategy.rb +2 -0
  82. data/lib/otto/security/authentication/strategy_result.rb +6 -5
  83. data/lib/otto/security/authentication.rb +2 -2
  84. data/lib/otto/security/authorization_error.rb +73 -0
  85. data/lib/otto/security/config.rb +2 -2
  86. data/lib/otto/security/configurator.rb +17 -2
  87. data/lib/otto/security/csrf.rb +2 -2
  88. data/lib/otto/security/middleware/csrf_middleware.rb +11 -1
  89. data/lib/otto/security/middleware/ip_privacy_middleware.rb +31 -11
  90. data/lib/otto/security/middleware/rate_limit_middleware.rb +2 -0
  91. data/lib/otto/security/middleware/validation_middleware.rb +15 -0
  92. data/lib/otto/security/rate_limiter.rb +2 -2
  93. data/lib/otto/security/rate_limiting.rb +2 -2
  94. data/lib/otto/security/validator.rb +2 -2
  95. data/lib/otto/security.rb +3 -0
  96. data/lib/otto/static.rb +2 -2
  97. data/lib/otto/utils.rb +27 -2
  98. data/lib/otto/version.rb +3 -3
  99. data/lib/otto.rb +174 -14
  100. data/otto.gemspec +7 -3
  101. metadata +25 -15
  102. data/benchmark_middleware_wrap.rb +0 -163
  103. data/changelog.d/20251014_144317_delano_54_thats_a_wrapper.rst +0 -36
  104. data/changelog.d/20251014_161526_delano_54_thats_a_wrapper.rst +0 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: abc8be5b60ac2a33d84dd0b89aec0e30797d36a995fdc26db7d9d2e65b28553f
4
- data.tar.gz: 003a6c148c47011bbdc185c0035d9788f319b34eaa4bd2067cf06199749abf46
3
+ metadata.gz: b094c2fc179b84631bf53b1e4b7f3cbcd661f83e1f8a88ab6c1f22d3e8b11cbd
4
+ data.tar.gz: 70a7588c86b8b3f31968b577a298f05c09cad5ef5d9fcf028f0feece2963e8fb
5
5
  SHA512:
6
- metadata.gz: 0b27bf0132a8648a0b7ba14c33e1c1553196447a34a826463572c2fb005c644cdcbadd9987b1b71787c41cc70332771034ac52bda39e76aaa2947c0b73138470
7
- data.tar.gz: c45a50e6420a3a6a072abdbb03177228132359cc52193fdcbac230ea0b6f6aac8c86613190d4cb6be192125db6999510467a3a4a5abe0f1fee46e07e202448aa
6
+ metadata.gz: c9e8f2f46cf51bc0799dd6030e52a48c1665b9978efb8bc686977be722e61b3c553f17db91d9fd795447b5b4882ac95af404a71e14f9b65d3935a992ecb768f1
7
+ data.tar.gz: d0c6f98edf2f468297dcb19bb9743b1a2858f2497cf40d2fc4332550a883542f2b7e1a1de8ac4b9f9d352b40c53e974d6c99aecee2679abc6b38868c02ae5bd6
@@ -45,7 +45,7 @@ jobs:
45
45
  bundler-cache: ${{ !matrix.experimental }}
46
46
 
47
47
  - name: Setup tmate session
48
- uses: mxschmitt/action-tmate@7b6a61a73bbb9793cb80ad69b8dd8ac19261834c # v3
48
+ uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101 # v3
49
49
  if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
50
50
  with:
51
51
  detached: true
@@ -54,7 +54,7 @@ jobs:
54
54
  - name: Remove claude-review label
55
55
  # Remove label whether success or failure - prevents getting stuck
56
56
  if: always() && github.event.action != 'opened'
57
- uses: actions/github-script@v7
57
+ uses: actions/github-script@v8
58
58
  with:
59
59
  script: |
60
60
  try {
@@ -0,0 +1,143 @@
1
+ # .github/workflows/code-smells.yml
2
+ ---
3
+ name: Code Smells
4
+
5
+ on:
6
+ pull_request:
7
+ branches: [main]
8
+ push:
9
+ branches: [main]
10
+ workflow_dispatch:
11
+
12
+ permissions:
13
+ contents: read
14
+ pull-requests: write # Needed to post comments on PRs
15
+
16
+ jobs:
17
+ reek-analysis:
18
+ name: Reek Code Analysis
19
+ runs-on: ubuntu-24.04
20
+ timeout-minutes: 5
21
+
22
+ steps:
23
+ - name: Checkout code
24
+ uses: actions/checkout@v5
25
+
26
+ - name: Set up Ruby
27
+ uses: ruby/setup-ruby@v1
28
+ with:
29
+ ruby-version: 3.4
30
+
31
+ - name: Install dependencies with optional groups
32
+ run: |
33
+ bundle config set --local path 'vendor/bundle'
34
+ bundle config set --local with 'development test'
35
+ bundle install --jobs 4 --retry 3
36
+
37
+ - name: Run Reek analysis
38
+ run: |
39
+ echo "=== Running Reek code analysis ==="
40
+ echo "This analysis identifies code smells and potential improvements."
41
+ echo "Results are informational and won't fail the build."
42
+ echo ""
43
+
44
+ # Run reek and capture output (don't fail on warnings)
45
+ # Use success-exit-code to prevent failures from stopping the analysis
46
+ bundle exec reek --format=text --success-exit-code 0 --failure-exit-code 0 || true
47
+
48
+ echo ""
49
+ echo "=== Reek analysis complete ==="
50
+ continue-on-error: true # Don't fail the build on code smells
51
+
52
+ - name: Generate Reek report
53
+ run: |
54
+ echo "=== Generating detailed Reek report ==="
55
+
56
+ # Generate JSON report for potential future processing
57
+ bundle exec reek --format=json --success-exit-code 0 --failure-exit-code 0 > reek-report.json || true
58
+
59
+ # If no JSON was generated, create an empty valid JSON array
60
+ if [ ! -s reek-report.json ]; then
61
+ echo "[]" > reek-report.json
62
+ echo "No code smells detected - created empty report"
63
+ else
64
+ echo "Reek JSON report generated: $(wc -l < reek-report.json) lines"
65
+ echo "Top code smell types found:"
66
+ jq -r '.[].smells[].smell_type' reek-report.json 2>/dev/null | sort | uniq -c | sort -rn | head -10 || echo "Unable to parse JSON report"
67
+ fi
68
+
69
+ # Also generate a human-readable HTML report for easier viewing
70
+ bundle exec reek --format=html --success-exit-code 0 --failure-exit-code 0 > reek-report.html || echo "<!-- No code smells detected -->" > reek-report.html
71
+ continue-on-error: true
72
+
73
+ - name: Upload Reek report as artifact
74
+ uses: actions/upload-artifact@v5
75
+ if: always()
76
+ with:
77
+ name: reek-report
78
+ path: |
79
+ reek-report.json
80
+ reek-report.html
81
+ if-no-files-found: ignore
82
+ retention-days: 30
83
+
84
+ additional-checks:
85
+ name: Additional Quality Checks
86
+ runs-on: ubuntu-24.04
87
+ timeout-minutes: 5
88
+
89
+ steps:
90
+ - name: Checkout code
91
+ uses: actions/checkout@v5
92
+
93
+ - name: Set up Ruby
94
+ uses: ruby/setup-ruby@v1
95
+ with:
96
+ ruby-version: 3.4
97
+ bundler-cache: true
98
+
99
+ - name: Configure Bundler for secure gem installation
100
+ run: |
101
+ bundle config set --local path 'vendor/bundle'
102
+ bundle config set --local deployment 'false'
103
+
104
+ - name: Install dependencies
105
+ run: bundle install --jobs 4 --retry 3
106
+
107
+ - name: Check for TODO/FIXME comments
108
+ run: |
109
+ echo "=== Scanning for TODO/FIXME comments ==="
110
+ echo "This helps track technical debt and action items."
111
+ echo ""
112
+
113
+ # Find TODO/FIXME comments (excluding vendor and tmp directories)
114
+ find . -name "*.rb" -not -path "./vendor/*" -not -path "./tmp/*" | \
115
+ xargs grep -Hn -i -E "(TODO|FIXME|HACK|XXX|NOTE):" 2>/dev/null | \
116
+ head -20 || echo "No TODO/FIXME comments found"
117
+ continue-on-error: true
118
+
119
+ - name: Check Ruby file syntax
120
+ run: |
121
+ echo "=== Checking Ruby syntax ==="
122
+ echo "Validates that all Ruby files have correct syntax."
123
+ echo ""
124
+
125
+ find . -name "*.rb" -not -path "./vendor/*" -not -path "./tmp/*" | \
126
+ while read -r file; do
127
+ if ! ruby -c "$file" > /dev/null 2>&1; then
128
+ echo "Syntax error in: $file"
129
+ ruby -c "$file"
130
+ fi
131
+ done
132
+ continue-on-error: true
133
+
134
+ - name: Check for long lines
135
+ run: |
136
+ echo "=== Checking for long lines (>120 characters) ==="
137
+ echo "Identifies potentially hard-to-read code lines."
138
+ echo ""
139
+
140
+ find . -name "*.rb" -not -path "./vendor/*" -not -path "./tmp/*" | \
141
+ xargs grep -Hn "^.\{121,\}$" | \
142
+ head -10 || echo "No overly long lines found"
143
+ continue-on-error: true
data/.gitignore CHANGED
@@ -11,8 +11,12 @@
11
11
  .*.json
12
12
  !LICENSE.txt
13
13
  !spec/fixtures/*.txt
14
+ !examples/**/*.md
15
+ !README.md
16
+ !CLAUDE.md
14
17
  .ruby-version
15
18
  appendonlydir
19
+ data/
16
20
  etc/config
17
21
  log
18
22
  tmp
@@ -96,12 +96,12 @@ repos:
96
96
 
97
97
  # Commit message issue tracking integration
98
98
  - repo: https://github.com/avilaton/add-msg-issue-prefix-hook
99
- rev: v0.0.12
99
+ rev: v0.0.13
100
100
  hooks:
101
101
  - id: add-msg-issue-prefix
102
102
  stages: [prepare-commit-msg]
103
103
  description: Automatically prefix commits with issue numbers
104
104
  args:
105
105
  - "--default="
106
- - '--pattern=(?:i18n(?=\/)|[a-zA-Z0-9]{0,10}-?[0-9]{1,5})'
106
+ - "--pattern=(i18n(?=/)|([a-zA-Z0-9]{0,10}-?[0-9]{1,5}))"
107
107
  - "--template=[#{}]"
data/.reek.yml ADDED
@@ -0,0 +1,99 @@
1
+ # .reek.yml
2
+ #
3
+ # Reek configuration for Otto
4
+ #
5
+ # Basic commands:
6
+ # bundle exec reek # Analyze all Ruby files
7
+ # bundle exec reek lib/ # Analyze specific directory
8
+ # bundle exec reek lib/otto.rb # Analyze specific file
9
+ # bundle exec reek --help # Show all options
10
+ # bundle exec reek --docs # Open documentation
11
+ #
12
+ # Advanced usage:
13
+ # bundle exec reek --format=html > report.html # Generate HTML report
14
+ # bundle exec reek --format=json # JSON output for CI
15
+ # bundle exec reek --config .reek.yml # Use specific config
16
+ # bundle exec reek --show-docs IrresponsibleModule # Explain specific smell
17
+ # bundle exec reek --failure-exit-code 1 # Exit with error on smells (for CI)
18
+
19
+ ---
20
+ detectors:
21
+ # Disable some detectors for initial adoption
22
+ # You can gradually enable these as you clean up the codebase
23
+
24
+ # Class/Module Structure
25
+ IrresponsibleModule:
26
+ enabled: false # Modules without documentation - start with this disabled
27
+
28
+ # Method Complexity
29
+ TooManyStatements:
30
+ enabled: true
31
+ max_statements: 15 # Default is 5, relaxed for initial adoption
32
+
33
+ TooManyMethods:
34
+ enabled: true
35
+ max_methods: 25 # Default is 15, relaxed for ORMs which often have many methods
36
+
37
+ LongParameterList:
38
+ enabled: true
39
+ max_params: 4 # Default is 3, slightly relaxed
40
+
41
+ # Data Classes and Feature Envy
42
+ DataClump:
43
+ enabled: true
44
+
45
+ FeatureEnvy:
46
+ enabled: true
47
+
48
+ # Control Structure
49
+ NestedIterators:
50
+ enabled: true
51
+ max_allowed_nesting: 2 # Default is 1, relaxed for data processing
52
+
53
+ # Variable and Constant Usage
54
+ UnusedParameters:
55
+ enabled: true
56
+
57
+ InstanceVariableAssumption:
58
+ enabled: true
59
+
60
+ # Naming
61
+ UncommunicativeParameterName:
62
+ enabled: true
63
+ reject:
64
+ - "/^.$/" # Single letter names
65
+ - "/[0-9]$/" # Names ending in numbers
66
+ - "/^_/" # Names starting with underscore (common Ruby pattern)
67
+ accept: []
68
+
69
+ UncommunicativeVariableName:
70
+ enabled: true
71
+ reject:
72
+ - "/^.$/" # Single letter names
73
+ - "/[0-9]$/" # Names ending in numbers
74
+ accept:
75
+ - e # Exception variable
76
+ - id # Common identifier
77
+ - db # Database connection
78
+ - op # Operation
79
+ - io # Input/output
80
+
81
+ UncommunicativeMethodName:
82
+ enabled: true
83
+ reject:
84
+ - "/^.$/" # Single letter method names
85
+ - "/[0-9]$/" # Methods ending in numbers
86
+ accept:
87
+ - "<<" # Common Ruby operator overload
88
+
89
+ # Directory and file exclusions
90
+ exclude_paths:
91
+ - "vendor/**/*.rb"
92
+ - "tmp/**/*.rb"
93
+ - "try/**/*.rb" # Test files using tryouts framework
94
+ - "examples/**/*.rb" # Example code files
95
+ - "bin/*" # Executable scripts
96
+ - "*.gemspec" # Gem specification files
97
+
98
+ # Note: For limiting warnings output, use CLI: bundle exec reek | head -50
99
+ # Note: For failure exit codes, use CLI: bundle exec reek --failure-exit-code 1
data/CHANGELOG.rst CHANGED
@@ -7,6 +7,161 @@ The format is based on `Keep a Changelog <https://keepachangelog.com/en/1.1.0/>`
7
7
 
8
8
  <!--scriv-insert-here-->
9
9
 
10
+ .. _changelog-2.0.0.pre8:
11
+
12
+ 2.0.0.pre8 — 2025-11-27
13
+ =======================
14
+
15
+ Fixed
16
+ -----
17
+
18
+ - Routes declaring ``response=json`` now return 401 JSON errors instead of 302 redirects when authentication fails, regardless of Accept header. The route's explicit configuration takes precedence over content negotiation.
19
+
20
+ .. _changelog-2.0.0.pre7:
21
+
22
+ 2.0.0.pre7 — 2025-11-24
23
+ =======================
24
+
25
+ Added
26
+ -----
27
+
28
+ - Error handler registration system for expected business logic errors. Register handlers with ``otto.register_error_handler(ErrorClass, status: 404, log_level: :info)`` to return proper HTTP status codes and avoid logging expected errors as 500s with backtraces. Supports custom response handlers via blocks for complete control over error responses.
29
+
30
+ Changed
31
+ -------
32
+
33
+ - Backtrace logging now always logs at ERROR level (was DEBUG) with sanitized file paths for security. Backtraces for unhandled 500 errors are always logged regardless of ``OTTO_DEBUG`` setting, with paths sanitized to prevent exposing system information (project files show relative paths, gems show ``[GEM] name-version/path``, Ruby stdlib shows ``[RUBY] filename``).
34
+ - Increased backtrace limit from 10 to 20 lines for critical errors to provide better debugging context.
35
+
36
+ AI Assistance
37
+ -------------
38
+
39
+ - Implemented error handler registration architecture with comprehensive test coverage (17 test cases) using sequential thinking to work through security implications and design decisions. AI assisted with path sanitization strategy, error classification patterns, and ensuring backward compatibility with existing error handling.
40
+
41
+ Improved backtrace sanitization security and readability
42
+ --------------------------------------------------------
43
+
44
+ **Security Enhancements:**
45
+
46
+ - Fixed bundler gem path detection to correctly sanitize git-based gems
47
+ - Now properly handles nested gem paths like ``/gems/3.4.0/bundler/gems/otto-abc123/``
48
+ - Strips git hash suffixes from bundler gems (``otto-abc123def456`` → ``otto``)
49
+ - Removes version numbers from regular gems (``rack-3.2.4`` → ``rack``)
50
+ - Prevents exposure of absolute paths, usernames, and project names in logs
51
+
52
+ **Improvements:**
53
+
54
+ - Bundler gems now show as ``[GEM] otto/lib/otto/route.rb:142`` instead of ``[GEM] 3.4.0/bundler/gems/...``
55
+ - Regular gems show cleaner output: ``[GEM] rack/lib/rack.rb:20`` instead of ``[GEM] rack-3.2.4/lib/rack.rb:20``
56
+ - Multi-hyphenated gem names handled correctly (``active-record-import-1.5.0`` → ``active-record-import``)
57
+ - Better handling of version-only directory names in gem paths
58
+
59
+ **Documentation:**
60
+
61
+ - Added comprehensive backtrace sanitization section to CLAUDE.md
62
+ - Documented security guarantees and sanitization rules
63
+ - Added examples showing before/after path transformations
64
+ - Created comprehensive test suite for backtrace sanitization
65
+
66
+ **Rationale:**
67
+
68
+ Raw backtraces expose sensitive information:
69
+ - Usernames (``/Users/alice/``, ``/home/admin/``)
70
+ - Project structure and internal organization
71
+ - Gem installation paths and Ruby versions
72
+ - System architecture details
73
+
74
+ This improvement ensures all backtraces are sanitized automatically, preventing accidental leakage of sensitive system information while maintaining readability for debugging.
75
+
76
+ .. _changelog-2.0.0.pre6:
77
+
78
+ 2.0.0.pre6
79
+ ==========
80
+
81
+ Changed
82
+ -------
83
+
84
+ - **BREAKING**: ``Otto.on_request_complete`` is now an instance method instead of a class method. This fixes duplicate callback invocations in multi-app architectures (e.g., Rack::URLMap with multiple Otto instances). Each Otto instance now maintains its own isolated set of callbacks that only fire for requests processed by that specific instance.
85
+
86
+ **Migration**: Change ``Otto.on_request_complete { |req, res, dur| ... }`` to ``otto.on_request_complete { |req, res, dur| ... }``
87
+
88
+ - **Logging**: Eliminated duplicate error logging in route handlers. Previously, errors produced two log lines ("Handler execution failed" + "Unhandled error in request"). Now produces a single comprehensive error log with all context (handler, duration, error_id). Lambda handlers now use centralized error handling for consistency. #86
89
+
90
+ Fixed
91
+ -----
92
+
93
+ - Fixed issue #84 where ``on_request_complete`` callbacks would fire N times per request in multi-app architectures, causing duplicate logging and metrics
94
+ - Fixed ``Otto.structured_log`` to respect ``Otto.debug`` flag - debug logs are now properly skipped when ``Otto.debug = false``
95
+
96
+ AI Assistance
97
+ -------------
98
+
99
+ - This enhancement was developed with assistance from Claude Code (Opus 4.1)
100
+
101
+ .. _changelog-2.0.0.pre5:
102
+
103
+ 2.0.0.pre5 — 2025-10-21
104
+ =======================
105
+
106
+ Added
107
+ -----
108
+
109
+ - Added ``Otto::LoggingHelpers.log_timed_operation`` for automatic timing and error handling of operations
110
+ - Added ``Otto::LoggingHelpers.log_backtrace`` for consistent backtrace logging with correlation fields
111
+ - Added microsecond-precision timing to configuration freeze process
112
+ - Added unique error ID generation for nested error handler failures (links via ``original_error_id``)
113
+
114
+ Changed
115
+ -------
116
+
117
+ - Timing precision standardization: All timing calculations now use microsecond precision instead of milliseconds. This affects authentication duration tracking and request lifecycle timing. Duration values are now reported in microseconds as integers (e.g., ``15200`` instead of ``15.2``).
118
+ - Request completion hooks API improvement: ``Otto.on_request_complete`` callbacks now receive a ``Rack::Response`` object instead of the raw ``[status, headers, body]`` tuple. This provides a more developer-friendly API consistent with ``Rack::Request``, allowing clean access via ``res.status``, ``res.headers``, and ``res.body`` instead of array indexing.
119
+ - All timing now uses microseconds (``Otto::Utils.now_in_μs``) for consistency
120
+ - Configuration freeze process now logs detailed timing metrics
121
+
122
+ Documentation
123
+ -------------
124
+
125
+ - Added example application demonstrating three new logging patterns (``examples/logging_improvements.rb``)
126
+ - Documented base context pattern for downstream projects to inject custom correlation fields
127
+ - Added output examples for both structured and standard loggers
128
+
129
+ AI Assistance
130
+ -------------
131
+
132
+ - This enhancement was developed with assistance from Claude Code (Opus 4.1)
133
+
134
+ .. _changelog-2.0.0.pre4:
135
+
136
+
137
+ 2.0.0.pre4 — 2025-10-20
138
+ =======================
139
+ Changed
140
+ -------
141
+ - Authentication moved from middleware to RouteAuthWrapper at handler level (executes after routing)
142
+ - RouteAuthWrapper now wraps all routes and provides session persistence, security headers, strategy caching, and pattern matching (exact, prefix, fallback)
143
+ - env['otto.strategy_result'] now guaranteed present on all routes (authenticated or anonymous)
144
+ - Renamed MiddlewareStack#build_app to #wrap (reflects per-request wrapping vs one-time initialization)
145
+
146
+ Removed
147
+ -------
148
+ - AuthenticationMiddleware (executed before routing)
149
+ - enable_authentication! (RouteAuthWrapper handles auth automatically)
150
+ - Defensive nil fallback from LogicClassHandler (no longer needed)
151
+
152
+ Fixed
153
+ -----
154
+ - Session persistence: env['rack.session'] now references same object as strategy_result.session
155
+ - Security headers included on all auth failure responses (401/302)
156
+ - Anonymous routes now receive StrategyResult with IP metadata
157
+
158
+ Documentation
159
+ -------------
160
+ - Updated CLAUDE.md with RouteAuthWrapper architecture
161
+ - Updated env_keys.rb to document strategy_result guarantee
162
+ - Added tests for anonymous route handling
163
+
164
+
10
165
  .. _changelog-2.0.0.pre2:
11
166
 
12
167
  2.0.0.pre2 — 2025-10-11
@@ -60,6 +215,7 @@ AI Assistance
60
215
  - Comprehensive migration of Logic classes and documentation with AI guidance for consistency
61
216
  - Automated test validation and intelligent file organization following Ruby conventions
62
217
 
218
+
63
219
  .. _changelog-2.0.0-pre1:
64
220
 
65
221
  2.0.0-pre1 — 2025-09-10