chronos-ruby 0.8.0.pre.1 → 0.9.0.pre.2

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +58 -0
  3. data/README.md +40 -10
  4. data/SECURITY.md +2 -0
  5. data/contracts/deploy-v1.schema.json +26 -0
  6. data/contracts/event-v1.schema.json +15 -1
  7. data/docs/adr/ADR-017-deploy-events-and-correlation.md +25 -0
  8. data/docs/adr/ADR-018-pre-1.0-hardening.md +9 -0
  9. data/docs/architecture.md +7 -1
  10. data/docs/compatibility.md +7 -2
  11. data/docs/configuration.md +18 -3
  12. data/docs/data-collected.md +6 -3
  13. data/docs/deprecation-policy.md +7 -0
  14. data/docs/examples/plain-ruby.md +7 -1
  15. data/docs/migration-from-airbrake.md +18 -0
  16. data/docs/modules/active-job.md +7 -0
  17. data/docs/modules/configuration.md +2 -0
  18. data/docs/modules/dependencies.md +2 -2
  19. data/docs/modules/deploy-tracking.md +86 -0
  20. data/docs/modules/ignore-rules.md +11 -0
  21. data/docs/modules/rails-legacy.md +3 -3
  22. data/docs/modules/sidekiq-legacy.md +1 -1
  23. data/docs/modules/telemetry-events.md +3 -1
  24. data/docs/performance.md +26 -1
  25. data/docs/privacy-lgpd.md +11 -2
  26. data/docs/protocol-v1.md +5 -0
  27. data/docs/release-1.0-readiness.md +18 -0
  28. data/docs/security-review.md +16 -0
  29. data/docs/semver.md +11 -0
  30. data/docs/troubleshooting.md +12 -0
  31. data/lib/chronos/agent.rb +30 -2
  32. data/lib/chronos/application/capture_exception.rb +7 -0
  33. data/lib/chronos/application/capture_telemetry.rb +17 -0
  34. data/lib/chronos/application/dependency_reporter.rb +12 -1
  35. data/lib/chronos/application/ignore_policy.rb +54 -0
  36. data/lib/chronos/application/remote_configuration.rb +1 -1
  37. data/lib/chronos/capistrano.rb +4 -0
  38. data/lib/chronos/configuration/apm_validation.rb +11 -0
  39. data/lib/chronos/configuration/validation.rb +16 -1
  40. data/lib/chronos/configuration.rb +14 -3
  41. data/lib/chronos/core/correlation_context.rb +65 -0
  42. data/lib/chronos/core/deploy_normalizer.rb +102 -0
  43. data/lib/chronos/core/payload_serializer.rb +4 -1
  44. data/lib/chronos/core/telemetry_event.rb +31 -4
  45. data/lib/chronos/integrations/active_job.rb +119 -0
  46. data/lib/chronos/integrations/capistrano.rb +61 -0
  47. data/lib/chronos/observability_facade.rb +9 -2
  48. data/lib/chronos/rails/installer.rb +7 -0
  49. data/lib/chronos/rails/notifications_subscriber.rb +29 -1
  50. data/lib/chronos/rails.rb +1 -0
  51. data/lib/chronos/version.rb +1 -1
  52. data/lib/chronos.rb +11 -1
  53. metadata +19 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 44c7cad424497d7998727de5a916594ecc3ce9dfda7580376fe4a754edd9096e
4
- data.tar.gz: 3f7a64cbf5b5879e107d7102c1f72cdd2ac4c941e1640a05b6210db79cd948f9
3
+ metadata.gz: ba6053cbe8155fba7fa99c0adf09db9e0aa38d33314b2355c49f1760233183fe
4
+ data.tar.gz: 138ee6958622e5e03d24863c553066c6368459fe423731950bcfcc63bfb12e02
5
5
  SHA512:
6
- metadata.gz: f62fa57bfcfec70f7172afc4c939d905aa9c7d9215960b73fa0c54406568b43b93e41b02ba22eb13b381243e06cf61a087544db00ed97ea4ce5805f84e9901e7
7
- data.tar.gz: 3a66ec4e2a85f7f2e79868523fe63a493aeb598aff810dfd21b84a25dd0505e21ee66cac35a7113927a9b4b5a5c5ea2f41d25b89b452b38088c0ef3570f876bf
6
+ metadata.gz: 58b5255dacdb15e3df4147cceb563e247989fa8cc2e72c23e79166e51c772ffc9ba0e87120c025de5d20cff04be21a7625cafb39d9f47793f82d156bdcb5cf09
7
+ data.tar.gz: 981f49d6f3d12314278456338e975797c27df3f7d93217eb2a8c9df630faa6081a683159b7694e0963cd7f9fa4ed6fae5f095b697a1ea9ce1c3159f388a5b36d
data/CHANGELOG.md CHANGED
@@ -12,6 +12,64 @@ All notable changes are documented here. The project follows Semantic Versioning
12
12
  - legacy CI now resolves Bundler 1.17.3 through `Gem.bin_path` on RubyGems versions that do not support the `_version_` executable selector.
13
13
  - documentation verification now reads source and Markdown files explicitly as UTF-8 on legacy container locales.
14
14
 
15
+ ## [0.9.0.pre.2] - 2026-07-21
16
+
17
+ ### Added
18
+
19
+ - bounded startup and runtime exception ignore rules through `config.ignore_rules` and `Chronos.ignore_if`;
20
+ - Active Job trace/request propagation without modifying public arguments, plus adapter, job/provider IDs, attempts, status, and failure telemetry;
21
+ - real-gem Sidekiq 4.2/5.2 Docker compatibility jobs;
22
+ - repeatable Rack comparison and fake-endpoint load gates;
23
+ - corrected `script/test_all` so `pipefail` no longer turns installed Rubies into false skips and an empty matrix fails;
24
+ - Airbrake migration, SemVer, deprecation, protocol stability, security review, and 1.0 readiness documentation.
25
+
26
+ ### Changed
27
+
28
+ - version advanced to `0.9.0.pre.2` instead of `1.0.0` because the full external legacy matrix has not yet supplied zero-failure evidence;
29
+ - Active Job identifiers are now documented collected fields and propagated context is bounded to trace/request IDs.
30
+
31
+ ### Fixed
32
+
33
+ - the Sidekiq 5 compatibility smoke now resolves the shared Sidekiq 4/5 fixture inside `examples/` instead of the nonexistent `/app/sidekiq-4` path.
34
+
35
+ ### Security
36
+
37
+ - local ignore rules are bounded to 100, contain callback failures, and cannot be installed remotely;
38
+ - fake-endpoint load validation rejects payloads containing the secret authentication key;
39
+ - package signing remains deferred until a trusted key lifecycle exists; protected publishing credentials remain required.
40
+
41
+ ### Known limitations
42
+
43
+ - compatibility stays `Best effort` until all new and existing GitHub Actions matrix jobs pass without skips;
44
+ - end-of-life runtimes and framework dependencies retain their upstream security risk;
45
+ - Active Job adapters that bypass standard serialization/execution hooks need dedicated evidence;
46
+ - comparative results are not a performance claim and must be published with controlled environment metadata.
47
+
48
+ ## [0.9.0.pre.1] - 2026-07-21
49
+
50
+ ### Added
51
+
52
+ - synchronous `Chronos.notify_deploy` API with bounded environment, revision, version, repository, actor, deploy ID, service, region, and instance fields;
53
+ - fixed bounded release/deploy correlation on every new exception and telemetry envelope;
54
+ - explicit configuration for `revision`, `deploy_id`, `region`, and `instance_id`;
55
+ - automatic deploy IDs and credential removal from common HTTP/SCP repository references;
56
+ - optional idempotent Capistrano post-publish task loaded through `chronos/capistrano`;
57
+ - manual, Kamal-command, and GitHub Actions deployment examples;
58
+ - deploy/correlation contracts, tests, benchmark, module documentation, and ADR-017.
59
+
60
+ ### Changed
61
+
62
+ - dependency inventory can be refreshed once after a successful deploy notification with the new release;
63
+ - deploy events use their normalized environment/service/release values in the common envelope;
64
+ - version advanced to `0.9.0.pre.1`.
65
+
66
+ ### Known limitations
67
+
68
+ - `notify_deploy` does not mutate the immutable correlation of an already running agent;
69
+ - Kamal support is command/documentation based rather than a plugin;
70
+ - Capistrano must load its task DSL before the optional Chronos entry point;
71
+ - deployment policy must decide whether a `false` notification result blocks publication.
72
+
15
73
  ## [0.8.0.pre.1] - 2026-07-20
16
74
 
17
75
  ### Added
data/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # Chronos Ruby
2
2
 
3
- Chronos Ruby is the framework-independent client for sending Ruby application errors and bounded telemetry to Chronos. Version 0.8 adds optional per-instance outbound `Net::HTTP` timing, privacy-safe cache identity, and one bounded dependency inventory per agent.
3
+ Chronos Ruby is the framework-independent client for sending Ruby application errors and bounded telemetry to Chronos. Version 0.9 adds synchronous deploy tracking and bounded release correlation across every event.
4
4
 
5
5
  ## What the gem collects
6
6
 
7
- Version 0.8 can collect:
7
+ Version 0.9 can collect:
8
8
 
9
9
  - exception class, message, structured backtrace, and chained causes;
10
10
  - timestamp, severity, tags, and an optional fingerprint;
@@ -13,6 +13,8 @@ Version 0.8 can collect:
13
13
  - application version, environment, and service name.
14
14
  - Rack method, normalized route, status, duration, request ID, host, query-free path, optional user agent, controller/action, response size, trace ID, and already-parsed parameters when the middleware is used;
15
15
  - bounded breadcrumbs explicitly supplied by the application or integration.
16
+ - release, revision, deploy ID, environment, service, region, and instance correlation;
17
+ - explicit bounded deployment metadata supplied through the public API or integration.
16
18
 
17
19
  See [Data collected](docs/data-collected.md) for the complete field table.
18
20
 
@@ -31,7 +33,7 @@ See [Compatibility](docs/compatibility.md).
31
33
  The current public build is a pre-release. Add its exact version to the application's `Gemfile`:
32
34
 
33
35
  ```ruby
34
- gem "chronos-ruby", "0.8.0.pre.1"
36
+ gem "chronos-ruby", "0.9.0.pre.2"
35
37
  ```
36
38
 
37
39
  Install with a Bundler version compatible with the application. For the oldest supported runtime:
@@ -52,7 +54,7 @@ gem install chronos-ruby --pre
52
54
  Version 0.5 exposes Rails support explicitly, keeping Rails and ActiveSupport out of plain Ruby applications:
53
55
 
54
56
  ```ruby
55
- gem "chronos-ruby", "0.8.0.pre.1", :require => "chronos/rails"
57
+ gem "chronos-ruby", "0.9.0.pre.2", :require => "chronos/rails"
56
58
  ```
57
59
 
58
60
  Generate the initializer with:
@@ -164,7 +166,15 @@ Chronos.configure do |config|
164
166
  end
165
167
  ```
166
168
 
167
- Local exception-specific ignore callbacks are not available in version 0.4. The server may provide a bounded list of exact fingerprints to ignore; it cannot provide regular expressions or executable rules.
169
+ Version `0.9.0.pre.2` adds bounded local rules after configuration:
170
+
171
+ ```ruby
172
+ Chronos.ignore_if do |notice|
173
+ notice.exception_class == "SomeExpectedError"
174
+ end
175
+ ```
176
+
177
+ Rules receive an immutable normalized notice, run before serialization/queueing, and must return exactly `true` to discard. The default limit is 20 and the hard configurable maximum is 100. A failing rule is contained. See [Bounded local ignore rules](docs/modules/ignore-rules.md).
168
178
 
169
179
  ## Performance monitoring
170
180
 
@@ -191,12 +201,12 @@ Version `0.6.0.pre.1` adds optional Sidekiq 4/5 middleware:
191
201
 
192
202
  ```ruby
193
203
  gem "sidekiq", "~> 5.0"
194
- gem "chronos-ruby", "0.8.0.pre.1", :require => "chronos/sidekiq"
204
+ gem "chronos-ruby", "0.9.0.pre.2", :require => "chronos/sidekiq"
195
205
  ```
196
206
 
197
207
  The client middleware propagates only trace/request identifiers in a versioned Sidekiq-envelope field and never changes worker arguments. The server records class, queue, JID, retry count, duration, calculable queue latency, bounded arguments/tags, status, and error class. Values pass through the shared sanitizer before delivery. Failed jobs are notified once and the original exception is re-raised. See [Sidekiq 4/5 legacy integration](docs/modules/sidekiq-legacy.md).
198
208
 
199
- The Rails subscriber continues to record basic Active Job class, queue, and duration. Full Active Job context propagation plus optional Resque and Delayed Job adapters are subsequent version 0.6 increments.
209
+ When Active Job is available, the Rails integration propagates only bounded trace/request identifiers in a namespaced serialized field without changing job arguments. It records adapter, job/provider IDs, class, queue, attempts, duration, status, and error class, and captures a supplied failure once. See [Active Job legacy integration](docs/modules/active-job.md).
200
210
 
201
211
  ## External HTTP, cache, and dependencies
202
212
 
@@ -220,7 +230,21 @@ Rails cache telemetry omits raw keys by default. Set `cache_key_mode = :sha256`
220
230
 
221
231
  ## Deploy tracking
222
232
 
223
- Deploy notifications are not implemented in version 0.8. `app_version` is included in event service metadata and the once-per-agent dependency inventory for release correlation.
233
+ Version 0.9 sends deployment metadata synchronously and adds a bounded correlation block to every event:
234
+
235
+ ```ruby
236
+ Chronos.notify_deploy(
237
+ :environment => "production",
238
+ :revision => ENV["GIT_SHA"],
239
+ :version => ENV["APP_VERSION"],
240
+ :repository => "owner/repository",
241
+ :actor => ENV["DEPLOY_USER"]
242
+ )
243
+ ```
244
+
245
+ Configure `app_version`, `revision`, `deploy_id`, `environment`, `service_name`, `region`, and `instance_id` in each newly deployed process so subsequent telemetry carries the same release identity. The gem never scans environment variables or Git automatically.
246
+
247
+ Optional Capistrano support loads through `chronos/capistrano`. Manual, Kamal-command, and GitHub Actions examples share the explicit deploy command under `examples/deploy/`. See [Deploy tracking and release correlation](docs/modules/deploy-tracking.md).
224
248
 
225
249
  ## Asynchronous queue
226
250
 
@@ -296,6 +320,11 @@ Chronos.configure do |config|
296
320
  config.external_http_enabled = false
297
321
  config.cache_key_mode = :none
298
322
  config.dependency_reporting = true
323
+ config.app_version = ENV["APP_VERSION"]
324
+ config.revision = ENV["GIT_SHA"]
325
+ config.deploy_id = ENV["DEPLOY_ID"]
326
+ config.region = ENV["REGION"]
327
+ config.instance_id = ENV["INSTANCE_ID"]
299
328
  end
300
329
  ```
301
330
 
@@ -307,7 +336,7 @@ Configuration errors are raised during `Chronos.configure`. Capture and delivery
307
336
 
308
337
  ## Benchmark
309
338
 
310
- Run the version 0.8 benchmarks with:
339
+ Run the version 0.9 benchmarks with:
311
340
 
312
341
  ```bash
313
342
  bundle _1.17.3_ exec ruby benchmarks/capture_exception.rb
@@ -320,13 +349,14 @@ bundle _1.17.3_ exec ruby benchmarks/rails_notifications.rb
320
349
  bundle _1.17.3_ exec ruby benchmarks/sidekiq_middleware.rb
321
350
  bundle _1.17.3_ exec ruby benchmarks/apm_aggregation.rb
322
351
  bundle _1.17.3_ exec ruby benchmarks/external_http.rb
352
+ bundle _1.17.3_ exec ruby benchmarks/correlation.rb
323
353
  ```
324
354
 
325
355
  Results depend on runtime, hardware, and payload. No performance comparison is claimed until repeatable measurements are published.
326
356
 
327
357
  ## Migration from Airbrake
328
358
 
329
- An Airbrake migration guide will be added before the legacy 1.0 release. Version 0.8 does not claim API compatibility or automatic replacement.
359
+ An Airbrake migration guide will be added before the legacy 1.0 release. Version 0.9 does not claim API compatibility or automatic replacement.
330
360
 
331
361
  ## Local development
332
362
 
data/SECURITY.md CHANGED
@@ -7,3 +7,5 @@ Never include live project keys, customer payloads, personal data, or production
7
7
  The Chronos 0.x line provides technical compatibility with end-of-life Ruby versions. It cannot provide security maintenance for the Ruby runtime, OpenSSL, operating system, Rails, or other dependencies used by the host application.
8
8
 
9
9
  Security fixes in the agent will be assessed for backporting to maintained Chronos version lines. No response-time commitment is made before a formal security process is published.
10
+
11
+ The current prerelease review and residual risks are recorded in [docs/security-review.md](docs/security-review.md). Release publishing uses a protected GitHub environment and a scoped RubyGems key. Package signing is deferred until the project has a trusted certificate issuance, rotation, revocation, and offline-key process; do not add a private signing key to the repository or workflow secrets without that process.
@@ -0,0 +1,26 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://chronos.example/schemas/deploy-v1.schema.json",
4
+ "title": "Chronos deploy payload v1",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": [
8
+ "deploy_id", "environment", "revision", "version", "repository",
9
+ "actor", "service", "region", "instance"
10
+ ],
11
+ "properties": {
12
+ "deploy_id": {"type": "string", "minLength": 1, "maxLength": 128},
13
+ "environment": {"type": "string", "minLength": 1, "maxLength": 128},
14
+ "revision": {"type": ["string", "null"], "maxLength": 128},
15
+ "version": {"type": ["string", "null"], "maxLength": 128},
16
+ "repository": {"type": ["string", "null"], "maxLength": 512},
17
+ "actor": {"type": ["string", "null"], "maxLength": 128},
18
+ "service": {"type": ["string", "null"], "maxLength": 128},
19
+ "region": {"type": ["string", "null"], "maxLength": 128},
20
+ "instance": {"type": ["string", "null"], "maxLength": 128}
21
+ },
22
+ "anyOf": [
23
+ {"properties": {"revision": {"type": "string", "minLength": 1}}},
24
+ {"properties": {"version": {"type": "string", "minLength": 1}}}
25
+ ]
26
+ }
@@ -20,7 +20,7 @@
20
20
  "properties": {
21
21
  "schema_version": {"const": "1.0"},
22
22
  "event_id": {"type": "string", "minLength": 1},
23
- "event_type": {"enum": ["exception", "request", "query", "job", "cache", "external_http", "dependencies", "metric_batch"]},
23
+ "event_type": {"enum": ["exception", "request", "query", "job", "cache", "external_http", "dependencies", "deploy", "metric_batch"]},
24
24
  "occurred_at": {"type": "string"},
25
25
  "sent_at": {"type": "string"},
26
26
  "project_key": {"type": "string", "minLength": 1},
@@ -34,6 +34,20 @@
34
34
  "instance_id": {"type": ["string", "null"]}
35
35
  }
36
36
  },
37
+ "correlation": {
38
+ "type": "object",
39
+ "additionalProperties": false,
40
+ "required": ["release", "revision", "deploy_id", "environment", "service", "region", "instance"],
41
+ "properties": {
42
+ "release": {"type": ["string", "null"], "maxLength": 128},
43
+ "revision": {"type": ["string", "null"], "maxLength": 128},
44
+ "deploy_id": {"type": ["string", "null"], "maxLength": 128},
45
+ "environment": {"type": ["string", "null"], "maxLength": 128},
46
+ "service": {"type": ["string", "null"], "maxLength": 128},
47
+ "region": {"type": ["string", "null"], "maxLength": 128},
48
+ "instance": {"type": ["string", "null"], "maxLength": 128}
49
+ }
50
+ },
37
51
  "runtime": {"type": "object"},
38
52
  "context": {"type": "object"},
39
53
  "payload": {"type": "object"}
@@ -0,0 +1,25 @@
1
+ # ADR-017 — Synchronous deploy events and immutable release correlation
2
+
3
+ ## Status
4
+
5
+ Accepted for version 0.9.
6
+
7
+ ## Context
8
+
9
+ The SaaS needs stable release dimensions to compare error and performance behavior before and after deployments. Deployment tools are short-lived processes, while application telemetry is long-lived and concurrent. Implicit Git, lockfile, or environment discovery would make behavior surprising and could expose credentials.
10
+
11
+ ## Decision
12
+
13
+ Add a versioned `deploy` telemetry payload delivered synchronously through the existing transport policy. Require an environment and either revision or version, generate a deploy ID when omitted, bound every field, and remove credentials from common repository URL forms.
14
+
15
+ Emit a `correlation` object on every new v1 envelope with release, revision, deploy ID, environment, service, region, and instance. Keep the schema property optional so payloads from earlier 0.x clients remain valid. Populate it from the immutable configuration snapshot for application events and from normalized deploy fields for deploy events. Do not mutate a running agent's correlation after notification.
16
+
17
+ Refresh the bounded dependency inventory after a successful deploy notification. Integrate Capistrano through its task DSL without a runtime dependency. Support Kamal by documented command and GitHub Actions through an example workflow.
18
+
19
+ ## Alternatives
20
+
21
+ Reading Git state, all environment variables, or deployment manifests automatically was rejected for determinism and privacy. Asynchronous-only deploy delivery was rejected because short-lived commands can exit before queue drain. Mutating global release state after `notify_deploy` was rejected because concurrent events could receive mixed correlation. Adding direct dependencies on Capistrano, Kamal, or GitHub SDKs was rejected for the legacy compatibility line.
22
+
23
+ ## Consequences
24
+
25
+ Every event has a stable bounded correlation shape and deploy commands receive an explicit success result. Applications must pass release metadata into each newly started process. Integration setup remains explicit, and delivery failure policy stays under the deployment pipeline's control.
@@ -0,0 +1,9 @@
1
+ # ADR-018: Pre-1.0 hardening gates
2
+
3
+ ## Decision
4
+
5
+ Keep the release at `0.9.0.pre.2` while any mandatory 1.0 evidence remains external or incomplete. Add bounded local ignore rules, Active Job envelope propagation, real Sidekiq compatibility jobs, repeatable comparative/load benchmarks, and explicit release/security policies.
6
+
7
+ ## Consequences
8
+
9
+ The stable API is not promised before the full legacy matrix passes. Active Job gains one namespaced serialized field without changing arguments. Application callbacks remain bounded in count but their execution cost belongs to the application. Package checksums are used until a trusted signing lifecycle is available.
data/docs/architecture.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Architecture
2
2
 
3
- Chronos Ruby 0.8 uses hexagonal boundaries so the legacy core remains independent of frameworks and delivery infrastructure.
3
+ Chronos Ruby 0.9 uses hexagonal boundaries so the legacy core remains independent of frameworks and delivery infrastructure.
4
4
 
5
5
  ```mermaid
6
6
  flowchart TB
@@ -24,6 +24,8 @@ flowchart TB
24
24
  NetHTTP[Explicit Net::HTTP instance wrapper] --> Facade
25
25
  Rails --> Cache[Core / CacheNormalizer]
26
26
  Application --> Dependencies[Application / DependencyReporter]
27
+ Deploy[Manual, Capistrano, Kamal command, GitHub workflow] --> Facade
28
+ Core --> Correlation[Core / DeployNormalizer and CorrelationContext]
27
29
  ```
28
30
 
29
31
  ## Boundaries
@@ -55,6 +57,10 @@ Version 0.7 routes request, query, and job observations through `ApmAggregator`.
55
57
 
56
58
  Version 0.8 prepends a wrapper only to each explicitly selected `Net::HTTP` object. The wrapper records bounded outcome metadata and feeds the existing APM aggregator; it does not modify `Net::HTTP` globally. `CacheNormalizer` turns public Rails cache notifications into bounded metadata before delivery. `DependencyReporter` reads already loaded runtime metadata once per agent under a mutex and queues it as a separate event.
57
59
 
60
+ Version 0.9 routes explicit deploy attributes through `DeployNormalizer`, synchronous `CaptureTelemetry`, the common sanitizer, and `DeliveryPipeline`. `CorrelationContext` supplies the same fixed seven-field shape to exception and telemetry serializers. Deploy event overrides apply only while serializing that event; the agent configuration remains immutable for concurrent application capture. A successful deployment resets the dependency reporter once and flushes the refreshed inventory.
61
+
62
+ Capistrano remains an optional integration task with no runtime dependency. Kamal and GitHub Actions call the same manual Ruby command rather than adding SDKs or transport paths.
63
+
58
64
  ## Failure policy
59
65
 
60
66
  Explicit invalid configuration raises `Chronos::ConfigurationError`. Capture, serialization, logger, worker, retry, circuit, TLS, network, HTTP, and remote-policy failures do not escape into the host application. They produce `false`, a classified transport result, a bounded state transition, or a bounded logger diagnostic.
@@ -13,16 +13,21 @@ Chronos Ruby 0.x is the legacy line. Technical compatibility does not make an en
13
13
 
14
14
  | Ruby | Sidekiq integration | Status | Evidence |
15
15
  |---|---|---|---|
16
- | 2.2.10–2.6 | Sidekiq 4 / 5 | Best effort | Middleware unit/integration contracts; dedicated real-gem matrix pending |
16
+ | 2.2.10 | Sidekiq 4.2.10 | Best effort | Unit/integration contracts and dedicated real-gem Docker job |
17
+ | 2.5.9 | Sidekiq 5.2.10 | Best effort | Unit/integration contracts and dedicated real-gem Docker job |
17
18
 
18
19
  Version 0.5 includes Rails 4.2 and 5.2 applications plus a dedicated matrix, but this document conservatively keeps the combinations at `Best effort` until all release-gate evidence, including fake-server payload validation, is green. Rails 5.0 uses the same feature-detected public APIs but does not yet have its own example application.
19
20
 
20
- Version `0.6.0.pre.1` uses the public Sidekiq 4/5 middleware signatures and remains `Best effort` until dedicated jobs exercise both real gem versions across their valid Ruby combinations.
21
+ Version `0.9.0.pre.2` adds dedicated Sidekiq 4.2.10 and 5.2.10 real-gem jobs. Status remains `Best effort` until both external jobs pass on the release candidate.
22
+
23
+ Active Job propagation uses the standard `serialize`, `deserialize`, and `perform_now` extension points with a namespaced bounded field. Rails 4.2/5.2 example jobs and unit contracts provide evidence; the complete external matrix must still pass before stable support is declared.
21
24
 
22
25
  Version `0.7.0.pre.1` keeps the same Ruby/Rails matrix and implements APM aggregation without modern concurrency or SQL-parser dependencies. Its compatibility remains `Best effort` until request/SQL/job aggregate payloads pass the dedicated fake-server gates for every listed runtime.
23
26
 
24
27
  Version `0.8.0.pre.1` uses per-object `Module#prepend`, legacy `Net::HTTP`, standard-library SHA-256, and loaded-spec feature detection. It adds no runtime dependency and keeps the same matrix. Outbound HTTP, cache, and dependency gates must pass every listed runtime before support is promoted.
25
28
 
29
+ Version `0.9.0.pre.1` adds only standard-library URI/SecureRandom processing, bounded hashes, and the existing synchronous delivery path. Capistrano is optional and feature-detected; Kamal and GitHub Actions integrations are commands/examples. The Ruby/Rails matrix remains unchanged and `Best effort` until deploy/correlation payload gates pass every listed runtime.
30
+
26
31
  Status meanings:
27
32
 
28
33
  - Supported: the complete required compatibility gate passes.
@@ -8,8 +8,12 @@
8
8
  | `project_key` | Yes when enabled | `nil` | Secret authentication key sent only as an HTTP header |
9
9
  | `host` | Yes when enabled | `nil` | Absolute Chronos HTTP endpoint; HTTPS is required by default |
10
10
  | `environment` | Recommended | `production` | Application environment |
11
- | `app_version` | Optional | `nil` | Release or revision identifier |
11
+ | `app_version` | Optional | `nil` | Application release/version identifier |
12
12
  | `service_name` | Recommended | `nil` | Logical service name |
13
+ | `revision` | Optional | `nil` | Source revision correlated with every event; maximum 128 bytes |
14
+ | `deploy_id` | Optional | `nil` | Deployment identifier correlated with every event; maximum 128 bytes |
15
+ | `region` | Optional | `nil` | Deployment region correlated with every event; maximum 128 bytes |
16
+ | `instance_id` | Optional | `nil` | Explicit instance correlation; otherwise runtime hostname is used |
13
17
  | `root_directory` | Optional | `Dir.pwd` | Used to identify application backtrace frames |
14
18
  | `logger` | Optional | `nil` | Logger receiving bounded internal diagnostics |
15
19
  | `timeout` | Optional | `5.0` | HTTP read timeout in seconds |
@@ -28,6 +32,8 @@
28
32
  | `allowlist_keys` | Optional | `[]` | Explicit key-name exceptions; content detection still runs |
29
33
  | `hash_keys` | Optional | `[]` | Scalar identifier keys replaced by scoped SHA-256 values |
30
34
  | `filters` | Optional | `[]` | Callable application-specific privacy filters |
35
+ | `ignore_rules` | Optional | `[]` | Callable local exception rules evaluated before serialization |
36
+ | `max_ignore_rules` | Optional | `20` | Maximum retained local rules; range 1–100 |
31
37
  | `anonymize_ip` | Recommended | `true` | Replaces the final octet of supplied IPv4 addresses |
32
38
  | `max_retries` | Optional | `3` | Maximum retry attempts after the first delivery failure |
33
39
  | `retry_base_interval` | Optional | `0.5` | Initial exponential-backoff delay in seconds |
@@ -39,7 +45,7 @@
39
45
  | `remote_configuration` | Optional | `true` | Accepts only the documented bounded remote policy fields |
40
46
  | `remote_config_max_bytes` | Optional | `4096` | Maximum remote policy response-header bytes |
41
47
  | `sampling_rate` | Optional | `1.0` | Local upper bound for event sampling |
42
- | `enabled_event_types` | Optional | exception, request, query, job, cache, external_http, dependencies, metric_batch | Local allowlist for supported event envelopes |
48
+ | `enabled_event_types` | Optional | exception, request, query, job, cache, external_http, dependencies, deploy, metric_batch | Local allowlist for supported event envelopes |
43
49
  | `max_remote_send_interval` | Optional | `60.0` | Local upper bound for remotely requested send spacing |
44
50
  | `context_store` | Optional | `:thread_local` | `:thread_local` or an object implementing `get`, `set`, `clear`, and `with_context` |
45
51
  | `breadcrumb_capacity` | Optional | `20` | Positive count of newest breadcrumbs retained per execution |
@@ -70,10 +76,17 @@ Chronos.configure do |config|
70
76
  config.host = ENV["CHRONOS_HOST"]
71
77
  config.environment = ENV["APP_ENV"] || "production"
72
78
  config.service_name = "billing"
79
+ config.app_version = ENV["APP_VERSION"]
80
+ config.revision = ENV["GIT_SHA"]
81
+ config.deploy_id = ENV["DEPLOY_ID"]
82
+ config.region = ENV["REGION"]
83
+ config.instance_id = ENV["INSTANCE_ID"]
73
84
  config.queue_size = 100
74
85
  config.workers = 1
75
86
  config.blocklist_keys += [:medical_record, /bank_account/i]
76
87
  config.hash_keys += [:customer_id]
88
+ config.ignore_rules << proc { |notice| notice.exception_class == "SomeExpectedError" }
89
+ config.max_ignore_rules = 20
77
90
  config.max_retries = 3
78
91
  config.backlog_size = 100
79
92
  config.circuit_failure_threshold = 5
@@ -97,8 +110,10 @@ Chronos.configure do |config|
97
110
  end
98
111
  ```
99
112
 
100
- Privacy matcher collections and filters are copied into the immutable runtime snapshot. Matchers must be String, Symbol, or Regexp values, and every custom filter must respond to `call`.
113
+ Privacy matcher collections, filters, and startup ignore rules are copied into the immutable runtime snapshot. Matchers must be String, Symbol, or Regexp values, and every filter/rule must respond to `call`. Runtime rules added through `Chronos.ignore_if` cannot exceed `max_ignore_rules`.
101
114
 
102
115
  The gem never reads all environment variables automatically. The host application decides which values to pass. See [Privacy and LGPD](privacy-lgpd.md) before adding application context.
103
116
 
104
117
  Remote configuration can only reduce collection within local bounds. It cannot increase `max_payload_size` or `sampling_rate`, enable an unsupported or locally disabled event type, change the endpoint, replace credentials, disable TLS verification, or install executable matching rules.
118
+
119
+ Release correlation values are copied into the immutable snapshot. Calling `Chronos.notify_deploy` reports a deployment but does not mutate those values for concurrent application events; configure each deployed process with its own release identity.
@@ -1,6 +1,6 @@
1
1
  # Data collected
2
2
 
3
- Version 0.8 emits exceptions, cache telemetry, one dependency inventory, and aggregated request/query/job/external-HTTP metric batches. All fields pass through the privacy sanitizer and bounded safe serializer before queueing, retry storage, or delivery.
3
+ Version 0.9 emits exceptions, cache telemetry, dependency/deploy events, and aggregated request/query/job/external-HTTP metric batches. All fields pass through the privacy sanitizer and bounded safe serializer before queueing, retry storage, or delivery.
4
4
 
5
5
  | Data | Default | Source |
6
6
  |---|---|---|
@@ -26,7 +26,8 @@ Version 0.8 emits exceptions, cache telemetry, one dependency inventory, and agg
26
26
  | View template basename and duration | Collected with Rails integration | `render_template.action_view` |
27
27
  | SQL operation name, cached flag, duration | Collected; SQL text omitted | `sql.active_record` |
28
28
  | Mailer/action and duration | Collected; message content omitted | `deliver.action_mailer` |
29
- | Active Job class, queue, duration | Collected when available; arguments omitted | `perform.active_job` |
29
+ | Active Job adapter, job/provider IDs, class, queue, attempts, duration, status, error class | Collected when available; arguments omitted | serialization and `perform.active_job` |
30
+ | Active Job trace/request IDs | Propagated in a bounded namespaced field | Current Chronos context |
30
31
  | Sidekiq class, queue, JID, retry count, duration, status, error class | Collected with optional middleware | Sidekiq job envelope and local clock |
31
32
  | Sidekiq queue latency | Collected when enqueue time is available | Sidekiq or Chronos envelope timestamp |
32
33
  | Sidekiq arguments | Collected, sanitized, and bounded | First 20 job arguments; collections/depth/strings limited |
@@ -45,8 +46,10 @@ Version 0.8 emits exceptions, cache telemetry, one dependency inventory, and agg
45
46
  | Cache key hash | Disabled by default | Project-scoped SHA-256 when `cache_key_mode = :sha256` |
46
47
  | Loaded gem names/versions and Ruby runtime | Once per agent by default; bounded | `Gem.loaded_specs` and Ruby constants |
47
48
  | Rails, web server, database adapter, Sidekiq, release | Included when safely detectable/configured | Loaded constants/specs and `app_version` |
49
+ | Event release, revision, deploy ID, environment, service, region, instance | Present as bounded correlation; values optional | Explicit immutable configuration or normalized deploy payload |
50
+ | Deploy environment, revision, version, repository, actor, deploy ID, service, region, instance | Explicit synchronous deploy API | Application/deployment integration arguments |
48
51
 
49
- The gem never collects request bodies, response bodies, raw query strings, cookies, HTTP authorization headers, environment variables in bulk, source code, raw SQL, SQL bind values, database rows, raw cache keys/values, mail bodies/recipients, gem paths, or lockfile contents. Sidekiq JIDs/arguments and bounded loaded gem names/versions are documented integration fields.
52
+ The gem never collects request bodies, response bodies, raw query strings, cookies, HTTP authorization headers, environment variables in bulk, Git state, source code, raw SQL, SQL bind values, database rows, raw cache keys/values, mail bodies/recipients, Active Job arguments, gem paths, or lockfile contents. Active Job IDs, Sidekiq JIDs/arguments, loaded gem names/versions, and deploy fields are documented integration data.
50
53
 
51
54
  APM dimensions never include user ID, job ID, raw URL, exception message, bind value, or cache key. Normalized routes replace common numeric/UUID segments. Normalized SQL can retain schema, table, and column identifiers; review those identifiers as part of the privacy audit.
52
55
 
@@ -0,0 +1,7 @@
1
+ # Deprecation policy
2
+
3
+ After `1.0.0`, a public API scheduled for removal remains available for at least one minor release and normally six months. The warning, replacement, first deprecated version, and earliest removal version must be documented in the changelog and migration material.
4
+
5
+ Warnings are emitted at most once per process through the configured safe logger and must not include application payloads. Security fixes, behavior that can expose secrets, and upstream runtime incompatibilities may require faster action; the security advisory and changelog must explain the exception. Ruby/Rails support changes are recorded in `docs/compatibility.md` before removal.
6
+
7
+ Prereleases may revise APIs without the full stable window, but every incompatible revision must remain explicit. Version `0.9.0.pre.2` introduces no removal.
@@ -29,4 +29,10 @@ For network-free per-instance outbound HTTP instrumentation, run:
29
29
  bundle _1.17.3_ exec ruby examples/plain-ruby/external_http.rb
30
30
  ```
31
31
 
32
- The examples demonstrate final event construction, key redaction, e-mail and Bearer-token detection, application-specific blocklisting, identifier hashing, and the bounded external HTTP payload without opening a socket.
32
+ For a network-free deploy event with complete release correlation, run:
33
+
34
+ ```bash
35
+ bundle _1.17.3_ exec ruby examples/plain-ruby/deploy_tracking.rb
36
+ ```
37
+
38
+ The examples demonstrate final event construction, privacy filtering, bounded external HTTP fields, and deploy correlation without opening a socket.
@@ -0,0 +1,18 @@
1
+ # Migration from Airbrake
2
+
3
+ Version `0.9.0.pre.2` provides a staged migration path. Run both agents only long enough to compare delivery, then remove Airbrake to avoid duplicate reports and overhead.
4
+
5
+ | Airbrake concept | Chronos equivalent |
6
+ |---|---|
7
+ | `Airbrake.configure` credentials/host | `Chronos.configure` with `project_id`, `project_key`, and `host` |
8
+ | `Airbrake.notify(error, params)` | `Chronos.notify(error, :parameters => params)` |
9
+ | `Airbrake.notify_sync` | `Chronos.notify_sync` |
10
+ | ignore/filter callbacks | `Chronos.ignore_if` and `config.filters` |
11
+ | deploy notification | `Chronos.notify_deploy` |
12
+ | Rack/Rails integration | `require "chronos/rails"` or Chronos Rack middleware |
13
+
14
+ Start with `error_notifications`, Rails capture, and APM enabled in one non-production environment. Configure the same application version and environment used by the old notifier. Compare exception count, class, sanitized context, deploy correlation, request/job metrics, and retry diagnostics. Never copy an Airbrake project key into Chronos.
15
+
16
+ Chronos callbacks receive a normalized immutable `Chronos::Core::Notice`, not an Airbrake notice. Filters operate on each sanitized key/value pair. Translate callback logic explicitly and add tests; do not assume callback argument compatibility. Chronos intentionally omits request/response bodies, raw SQL, binds, cookies, authorization headers, mail content, and raw cache keys.
17
+
18
+ Before removing Airbrake, exercise a synchronous notification, an asynchronous notification followed by `Chronos.flush`, a Rails/Rack failure, a background job failure, and an unavailable endpoint. Confirm that the bounded queue/backlog behavior is acceptable. Roll back by disabling Chronos or restoring the previous dependency; no application exception semantics are changed by the agent.
@@ -0,0 +1,7 @@
1
+ # Active Job legacy integration
2
+
3
+ When `ActiveJob::Base` is available, the Rails installer prepends public serialization/execution hooks. Enqueue serialization adds a namespaced `chronos_context` field with schema version plus at most the trace and request identifiers; each identifier is limited to 128 bytes. Public job arguments are unchanged. Deserialization restores this context only around `perform_now`.
4
+
5
+ The `perform.active_job` subscriber records adapter, job ID, provider job ID, class, queue, execution count, duration, status, and error class. Arguments are omitted. A supplied exception is reported once with bounded job context. The integration never changes retry, acknowledgement, adapter, or original exception behavior.
6
+
7
+ This metadata can identify a workflow or tenant in some applications. Review retention and identifier generation under the project's privacy policy.
@@ -11,3 +11,5 @@ Tests in `spec/unit/configuration_spec.rb` verify required fields, HTTPS default
11
11
  Version 0.7 adds bounded APM capacities, thresholds, and histogram boundaries. Invalid zero/negative capacities, batches above 50, N+1 thresholds below two, and non-increasing histogram boundaries are rejected before agent construction. See [Essential APM aggregation](apm-aggregation.md).
12
12
 
13
13
  Version 0.8 adds Boolean HTTP/dependency switches, `:none`/`:sha256` cache-key policy, and a dependency limit from 1 to 200. Invalid values are rejected before instrumentation or collection starts. See [External HTTP](external-http.md), [Cache observability](cache-observability.md), and [Dependency inventory](dependencies.md).
14
+
15
+ Version 0.9 adds optional `revision`, `deploy_id`, `region`, and `instance_id` strings, each limited to 128 bytes. Together with the existing release/environment/service options they form immutable event correlation. See [Deploy tracking and release correlation](deploy-tracking.md).
@@ -1,6 +1,6 @@
1
1
  # Dependency inventory
2
2
 
3
- Version `0.8.0.pre.1` emits a separate `dependencies` event at most once per configured agent. It is queued before the first capture or during explicit flush/close and is never attached to each exception.
3
+ Version `0.9.0.pre.1` emits a separate `dependencies` event at most once per configured agent and once again after a successful deploy notification. It is queued before the first capture or during explicit flush/close and is never attached to each exception.
4
4
 
5
5
  The inventory contains Ruby version/engine/platform, bounded names and versions from already loaded gem specs, the configured `app_version` release identifier, and Rails, Sidekiq, web server, or database adapter labels when safely detectable. The agent does not parse `Gemfile.lock`, activate missing gems, inspect gem paths/source, scan environment variables, open a database connection, or collect dependency configuration.
6
6
 
@@ -15,4 +15,4 @@ end
15
15
  Chronos.report_dependencies
16
16
  ```
17
17
 
18
- `dependency_max_items` accepts 1–200 and defaults to 100. Entries are sorted by name before truncation so repeated boots are stable. Set `dependency_reporting = false` when inventory collection is unnecessary or prohibited. Because collection is once-only, gems loaded after the first event appear only after a new agent configuration or process boot.
18
+ `dependency_max_items` accepts 1–200 and defaults to 100. Entries are sorted by name after bounded selection. Set `dependency_reporting = false` when inventory collection is unnecessary or prohibited. A successful `notify_deploy` resets the once-only guard and uses the deploy version for the refreshed inventory; otherwise gems loaded after the first event appear only after a new agent configuration or process boot.
@@ -0,0 +1,86 @@
1
+ # Deploy tracking and release correlation
2
+
3
+ Version `0.9.0.pre.1` adds synchronous deploy notifications and a bounded correlation block to every exception and telemetry envelope. The SaaS can compare errors and performance before and after a release using release, revision, deploy ID, environment, service, region, and instance.
4
+
5
+ ## Public API
6
+
7
+ Configure the agent, then provide deploy metadata explicitly:
8
+
9
+ ```ruby
10
+ Chronos.notify_deploy(
11
+ :environment => "production",
12
+ :revision => ENV["GIT_SHA"],
13
+ :version => ENV["APP_VERSION"],
14
+ :repository => "owner/repository",
15
+ :actor => ENV["DEPLOY_USER"],
16
+ :deploy_id => ENV["DEPLOY_ID"],
17
+ :service => "billing",
18
+ :region => "sa-east-1",
19
+ :instance => "web-1"
20
+ )
21
+ ```
22
+
23
+ Environment is required, and either revision or version must be present. A UUID deploy ID is generated when none is supplied. The call uses synchronous delivery, bypasses ordinary event sampling, then refreshes the bounded dependency inventory for the new release and flushes it before returning. Local/remote event disabling and the kill switch still apply. It returns `false` instead of leaking configuration, normalization, serialization, or transport failures.
24
+
25
+ Fields are limited to 128 bytes, except repository at 512 bytes. HTTP and SCP-style repository credentials are stripped before serialization. The shared sanitizer still filters explicit actor/repository content. Do not send access tokens, e-mail addresses, or unnecessary personal data.
26
+
27
+ ## Correlation on application events
28
+
29
+ Set the values that identify the currently running release during normal application configuration:
30
+
31
+ ```ruby
32
+ Chronos.configure do |config|
33
+ # project and endpoint settings omitted
34
+ config.app_version = ENV["APP_VERSION"]
35
+ config.revision = ENV["GIT_SHA"]
36
+ config.deploy_id = ENV["DEPLOY_ID"]
37
+ config.environment = ENV["APP_ENV"] || "production"
38
+ config.service_name = "billing"
39
+ config.region = ENV["REGION"]
40
+ config.instance_id = ENV["INSTANCE_ID"]
41
+ end
42
+ ```
43
+
44
+ The gem never reads these variables itself. The host application chooses each source. Configuration snapshots are immutable, so `notify_deploy` does not mutate correlation for an already running process; newly deployed processes must start with their own release values.
45
+
46
+ ## Capistrano
47
+
48
+ Require the optional entry point after Capistrano loads:
49
+
50
+ ```ruby
51
+ require "chronos/capistrano"
52
+
53
+ set :chronos_version, ENV["APP_VERSION"]
54
+ set :chronos_actor, ENV["DEPLOY_USER"]
55
+ set :chronos_deploy_id, ENV["DEPLOY_ID"]
56
+ set :chronos_service, "billing"
57
+ set :chronos_region, ENV["DEPLOY_REGION"]
58
+ ```
59
+
60
+ It registers `chronos:notify_deploy` after `deploy:published`, once per DSL object. Revision, stage, and repository use the public Capistrano variables `current_revision`, `stage`, and `repo_url`; all Chronos-specific values are optional and explicit. The integration adds no Capistrano runtime dependency.
61
+
62
+ ## Manual, Kamal, and GitHub Actions
63
+
64
+ [`examples/deploy/notify.rb`](../../examples/deploy/notify.rb) is the shared command. It requires project credentials/host and deploy environment, reads only named variables, notifies synchronously, closes the agent, and exits nonzero on failure.
65
+
66
+ For Kamal, pass the variables to the deployed container or command environment and execute after publication:
67
+
68
+ ```bash
69
+ kamal app exec --reuse "bundle exec ruby examples/deploy/notify.rb"
70
+ ```
71
+
72
+ Adapt the command to the application's Kamal hook lifecycle and secret-management policy. The repository also provides a non-active [GitHub Actions workflow example](../../examples/deploy/github-actions.yml) using read-only repository permission and secret-scoped Chronos credentials.
73
+
74
+ For a network-free payload demonstration:
75
+
76
+ ```bash
77
+ bundle _1.17.3_ exec ruby examples/plain-ruby/deploy_tracking.rb
78
+ ```
79
+
80
+ ## Limitations
81
+
82
+ - delivery is process-local and uses the existing finite retry/circuit/backlog policy;
83
+ - an unsuccessful synchronous delivery returns `false`; deployment policy decides whether that blocks publication;
84
+ - Capistrano auto-registration requires its task DSL to be loaded first;
85
+ - Kamal integration is command/documentation based, not a Kamal plugin;
86
+ - repository and actor are explicit metadata and remain subject to application privacy review.