e11y 0.2.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +130 -10
- data/CHANGELOG.md +80 -1
- data/CLAUDE.md +168 -0
- data/CONTRIBUTING.md +640 -0
- data/README.md +165 -701
- data/RELEASE.md +41 -12
- data/Rakefile +249 -57
- data/config/README.md +1 -1
- data/config/loki-local-config.yaml +12 -0
- data/config/otel-collector-config.yaml +44 -0
- data/cucumber.yml +1 -0
- data/docker-compose.yml +18 -2
- data/docs/ADAPTERS.md +76 -0
- data/docs/ADAPTIVE_SAMPLING.md +59 -0
- data/docs/COMPARISON.md +104 -0
- data/docs/CONFIGURATION.md +52 -0
- data/docs/DISTRIBUTED_TRACING.md +44 -0
- data/docs/LIMITATIONS.md +13 -0
- data/docs/METRICS_DSL.md +84 -0
- data/docs/PERFORMANCE.md +60 -0
- data/docs/PII_FILTERING.md +40 -0
- data/docs/PRESETS.md +65 -0
- data/docs/QUICK-START.md +546 -587
- data/docs/RAILS_INTEGRATION.md +79 -0
- data/docs/SCHEMA_VALIDATION.md +63 -0
- data/docs/SLO-PROMQL-ALERTS.md +161 -0
- data/docs/TESTING.md +69 -0
- data/docs/{ADR-001-architecture.md → architecture/ADR-001-architecture.md} +36 -65
- data/docs/{ADR-002-metrics-yabeda.md → architecture/ADR-002-metrics-yabeda.md} +62 -236
- data/docs/architecture/ADR-003-slo-observability.md +1402 -0
- data/docs/{ADR-004-adapter-architecture.md → architecture/ADR-004-adapter-architecture.md} +163 -146
- data/docs/{ADR-005-tracing-context.md → architecture/ADR-005-tracing-context.md} +10 -9
- data/docs/{ADR-006-security-compliance.md → architecture/ADR-006-security-compliance.md} +184 -191
- data/docs/{ADR-007-opentelemetry-integration.md → architecture/ADR-007-opentelemetry-integration.md} +3 -21
- data/docs/{ADR-008-rails-integration.md → architecture/ADR-008-rails-integration.md} +182 -743
- data/docs/{ADR-009-cost-optimization.md → architecture/ADR-009-cost-optimization.md} +45 -54
- data/docs/architecture/ADR-010-developer-experience.md +522 -0
- data/docs/{ADR-011-testing-strategy.md → architecture/ADR-011-testing-strategy.md} +44 -86
- data/docs/{ADR-012-event-evolution.md → architecture/ADR-012-event-evolution.md} +11 -11
- data/docs/{ADR-013-reliability-error-handling.md → architecture/ADR-013-reliability-error-handling.md} +37 -12
- data/docs/{ADR-014-event-driven-slo.md → architecture/ADR-014-event-driven-slo.md} +12 -24
- data/docs/{ADR-015-middleware-order.md → architecture/ADR-015-middleware-order.md} +43 -59
- data/docs/{ADR-016-self-monitoring-slo.md → architecture/ADR-016-self-monitoring-slo.md} +58 -355
- data/docs/{ADR-017-multi-rails-compatibility.md → architecture/ADR-017-multi-rails-compatibility.md} +4 -11
- data/docs/architecture/ADR-018-memory-optimization.md +366 -0
- data/docs/{ADR-INDEX.md → architecture/ADR-INDEX.md} +11 -6
- data/docs/plans/2026-03-20-browser-overlay-svelte.md +281 -0
- data/docs/{00-ICP-AND-TIMELINE.md → prd/00-ICP-AND-TIMELINE.md} +6 -6
- data/docs/{01-SCALE-REQUIREMENTS.md → prd/01-SCALE-REQUIREMENTS.md} +6 -6
- data/docs/prd/01-overview-vision.md +19 -14
- data/docs/use_cases/README.md +22 -23
- data/docs/use_cases/UC-001-request-scoped-debug-buffering.md +50 -44
- data/docs/use_cases/UC-002-business-event-tracking.md +26 -95
- data/docs/use_cases/UC-003-event-metrics.md +66 -0
- data/docs/use_cases/UC-004-zero-config-slo-tracking.md +33 -684
- data/docs/use_cases/UC-005-sentry-integration.md +13 -15
- data/docs/use_cases/UC-006-trace-context-management.md +30 -28
- data/docs/use_cases/UC-007-pii-filtering.md +35 -87
- data/docs/use_cases/UC-008-opentelemetry-integration.md +51 -89
- data/docs/use_cases/UC-009-multi-service-tracing.md +30 -178
- data/docs/use_cases/UC-010-background-job-tracking.md +24 -91
- data/docs/use_cases/UC-011-rate-limiting.md +95 -168
- data/docs/use_cases/UC-012-audit-trail.md +21 -46
- data/docs/use_cases/UC-013-high-cardinality-protection.md +29 -167
- data/docs/use_cases/UC-014-adaptive-sampling.md +2 -2
- data/docs/use_cases/UC-015-cost-optimization.md +46 -99
- data/docs/use_cases/UC-016-rails-logger-migration.md +39 -213
- data/docs/use_cases/UC-017-local-development.md +203 -777
- data/docs/use_cases/UC-018-testing-events.md +3 -3
- data/docs/use_cases/UC-019-retention-based-routing.md +53 -106
- data/docs/use_cases/UC-020-event-versioning.md +8 -9
- data/docs/use_cases/UC-021-error-handling-retry-dlq.md +18 -22
- data/docs/use_cases/UC-022-event-registry.md +15 -21
- data/docs/use_cases/backlog.md +119 -87
- data/e11y.gemspec +2 -2
- data/gems/e11y-devtools/README.md +158 -0
- data/gems/e11y-devtools/config/routes.rb +15 -0
- data/gems/e11y-devtools/e11y-devtools.gemspec +25 -0
- data/gems/e11y-devtools/exe/e11y +34 -0
- data/gems/e11y-devtools/frontend/.gitignore +24 -0
- data/gems/e11y-devtools/frontend/README.md +51 -0
- data/gems/e11y-devtools/frontend/index.html +14 -0
- data/gems/e11y-devtools/frontend/package-lock.json +3707 -0
- data/gems/e11y-devtools/frontend/package.json +28 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/events/recent.json +4205 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/interactions.json +194 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/0a2e04027cfa22d014bc22e8b27cd913/events.json +86 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/0e1543af6a630fb3af6b52283154b3e0/events.json +169 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/1838b691faa49564f97db8592ff3978d/events.json +78 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/29f198f6588dacffb687777eb5f8f118/events.json +197 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/34bc3c9c0097de28a7a6f99b90a8e7bc/events.json +194 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/3ba6c20d068ab9cee00e51b180e66444/events.json +184 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/435bfd8f17b9009146a79812d7c3726d/events.json +144 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/4c7676e3fe668e99edb2b94d7d5678a9/events.json +222 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/6daf0d47974bedfc55d5de7004a3ea9f/events.json +194 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/8a81ada42834d15f287bb40010043605/events.json +194 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/8c0a98900edaae105469df8daedccf02/events.json +198 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/8e4f645180f8a7d1dce426b07380466b/events.json +222 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/93db346fa5d44a032605a13b627f4b80/events.json +128 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/98ff6146faf7bd9be8bd03a8275817ba/events.json +223 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/9997ddd0247bc7e25f2ca7a5c415c93d/events.json +197 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/99e35f8ef3baedd798cc4fd085980ad9/events.json +194 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/b4f3095c1909924cbc98889a86c83d6d/events.json +131 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/b54b7fc32b7575a7110de809d11ccda0/events.json +128 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/c0b48033fa06746bcc5886745e053cff/events.json +169 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/c44649ac76701b4558927cd2305ab535/events.json +169 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/d601ae3320057580a39dbdac2edfdf4a/events.json +248 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/e67e724bab422d2b52eeb49635e512e1/events.json +194 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/e6c72765a28f158a8485b35fa63f73da/events.json +194 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/f541b87405c9a54819b18ebe529f6419/events.json +194 -0
- data/gems/e11y-devtools/frontend/scripts/generate_mocks.rb +397 -0
- data/gems/e11y-devtools/frontend/src/App.svelte +827 -0
- data/gems/e11y-devtools/frontend/src/components/Fab.svelte +19 -0
- data/gems/e11y-devtools/frontend/src/components/FilterBar.svelte +38 -0
- data/gems/e11y-devtools/frontend/src/components/FullscreenPanel.svelte +82 -0
- data/gems/e11y-devtools/frontend/src/components/InteractionsTimeline.svelte +264 -0
- data/gems/e11y-devtools/frontend/src/components/RecentHistogram.svelte +354 -0
- data/gems/e11y-devtools/frontend/src/lib/api.ts +37 -0
- data/gems/e11y-devtools/frontend/src/lib/eventIdentity.ts +12 -0
- data/gems/e11y-devtools/frontend/src/lib/format.ts +37 -0
- data/gems/e11y-devtools/frontend/src/lib/listFilter.ts +43 -0
- data/gems/e11y-devtools/frontend/src/lib/recentVolume.ts +80 -0
- data/gems/e11y-devtools/frontend/src/lib/router.ts +12 -0
- data/gems/e11y-devtools/frontend/src/lib/transitions.ts +34 -0
- data/gems/e11y-devtools/frontend/src/lib/viewportOrigin.ts +25 -0
- data/gems/e11y-devtools/frontend/src/main.ts +8 -0
- data/gems/e11y-devtools/frontend/src/overlay-entry.ts +24 -0
- data/gems/e11y-devtools/frontend/src/overlay.css +1080 -0
- data/gems/e11y-devtools/frontend/svelte.config.js +2 -0
- data/gems/e11y-devtools/frontend/test_puppeteer.js +41 -0
- data/gems/e11y-devtools/frontend/test_scale.js +3 -0
- data/gems/e11y-devtools/frontend/tsconfig.app.json +21 -0
- data/gems/e11y-devtools/frontend/tsconfig.json +7 -0
- data/gems/e11y-devtools/frontend/tsconfig.node.json +26 -0
- data/gems/e11y-devtools/frontend/vite.config.ts +36 -0
- data/gems/e11y-devtools/lib/e11y/devtools/mcp/server.rb +96 -0
- data/gems/e11y-devtools/lib/e11y/devtools/mcp/tool_base.rb +25 -0
- data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/clear.rb +31 -0
- data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/errors.rb +35 -0
- data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/event_detail.rb +33 -0
- data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/events_by_trace.rb +33 -0
- data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/interactions.rb +40 -0
- data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/recent_events.rb +34 -0
- data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/search.rb +34 -0
- data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/stats.rb +30 -0
- data/gems/e11y-devtools/lib/e11y/devtools/overlay/assets/overlay.js +20 -0
- data/gems/e11y-devtools/lib/e11y/devtools/overlay/controller.rb +94 -0
- data/gems/e11y-devtools/lib/e11y/devtools/overlay/engine.rb +26 -0
- data/gems/e11y-devtools/lib/e11y/devtools/overlay/middleware.rb +80 -0
- data/gems/e11y-devtools/lib/e11y/devtools/overlay/rails_controller.rb +67 -0
- data/gems/e11y-devtools/lib/e11y/devtools/tui/app.rb +262 -0
- data/gems/e11y-devtools/lib/e11y/devtools/tui/grouping.rb +66 -0
- data/gems/e11y-devtools/lib/e11y/devtools/tui/widgets/event_detail.rb +62 -0
- data/gems/e11y-devtools/lib/e11y/devtools/tui/widgets/event_list.rb +70 -0
- data/gems/e11y-devtools/lib/e11y/devtools/tui/widgets/interaction_list.rb +47 -0
- data/gems/e11y-devtools/lib/e11y/devtools/version.rb +8 -0
- data/gems/e11y-devtools/lib/e11y/devtools.rb +13 -0
- data/gems/e11y-devtools/spec/e11y/devtools/mcp/tools_spec.rb +107 -0
- data/gems/e11y-devtools/spec/e11y/devtools/overlay/controller_spec.rb +91 -0
- data/gems/e11y-devtools/spec/e11y/devtools/overlay/middleware_spec.rb +46 -0
- data/gems/e11y-devtools/spec/e11y/devtools/tui/app_spec.rb +85 -0
- data/gems/e11y-devtools/spec/e11y/devtools/tui/grouping_spec.rb +64 -0
- data/gems/e11y-devtools/spec/spec_helper.rb +5 -0
- data/gems/e11y-devtools/spec/tui/widgets/event_list_spec.rb +44 -0
- data/gems/e11y-devtools/spec/tui/widgets/interaction_list_spec.rb +62 -0
- data/lib/e11y/adapters/audit_encrypted.rb +53 -11
- data/lib/e11y/adapters/base.rb +33 -34
- data/lib/e11y/adapters/dev_log/file_store.rb +143 -0
- data/lib/e11y/adapters/dev_log/query.rb +219 -0
- data/lib/e11y/adapters/dev_log.rb +118 -0
- data/lib/e11y/adapters/file.rb +3 -6
- data/lib/e11y/adapters/in_memory.rb +52 -5
- data/lib/e11y/adapters/in_memory_test.rb +29 -0
- data/lib/e11y/adapters/loki.rb +58 -23
- data/lib/e11y/adapters/null.rb +82 -0
- data/lib/e11y/adapters/opentelemetry_collector.rb +183 -0
- data/lib/e11y/adapters/otel_logs.rb +136 -23
- data/lib/e11y/adapters/sentry.rb +4 -7
- data/lib/e11y/adapters/stdout.rb +73 -7
- data/lib/e11y/adapters/yabeda.rb +153 -29
- data/lib/e11y/buffers/adaptive_buffer.rb +3 -17
- data/lib/e11y/buffers/{request_scoped_buffer.rb → ephemeral_buffer.rb} +72 -58
- data/lib/e11y/buffers/ring_buffer.rb +3 -16
- data/lib/e11y/configuration.rb +272 -0
- data/lib/e11y/console.rb +10 -17
- data/lib/e11y/current.rb +53 -1
- data/lib/e11y/debug/pipeline_inspector.rb +96 -0
- data/lib/e11y/documentation/generator.rb +48 -0
- data/lib/e11y/event/base.rb +176 -82
- data/lib/e11y/event/value_sampling_config.rb +1 -5
- data/lib/e11y/events/rails/database/query.rb +1 -4
- data/lib/e11y/events/rails/job/failed.rb +2 -0
- data/lib/e11y/instruments/active_job.rb +44 -12
- data/lib/e11y/instruments/rails_instrumentation.rb +49 -24
- data/lib/e11y/instruments/sidekiq.rb +135 -31
- data/lib/e11y/linters/base.rb +11 -0
- data/lib/e11y/linters/pii/pii_declaration_linter.rb +120 -0
- data/lib/e11y/linters/slo/config_consistency_linter.rb +76 -0
- data/lib/e11y/linters/slo/explicit_declaration_linter.rb +36 -0
- data/lib/e11y/linters/slo/slo_status_from_linter.rb +41 -0
- data/lib/e11y/logger/bridge.rb +26 -7
- data/lib/e11y/metrics/cardinality_protection.rb +10 -15
- data/lib/e11y/metrics/cardinality_tracker.rb +16 -6
- data/lib/e11y/metrics/registry.rb +3 -5
- data/lib/e11y/metrics/test_backend.rb +62 -0
- data/lib/e11y/metrics.rb +56 -10
- data/lib/e11y/middleware/adapter_resolver.rb +40 -0
- data/lib/e11y/middleware/audit_signing.rb +43 -6
- data/lib/e11y/middleware/baggage_protection.rb +75 -0
- data/lib/e11y/middleware/dev_log_source.rb +24 -0
- data/lib/e11y/middleware/event_slo.rb +23 -9
- data/lib/e11y/middleware/otel_span.rb +23 -0
- data/lib/e11y/middleware/pii_filter.rb +104 -75
- data/lib/e11y/middleware/rate_limiting.rb +54 -27
- data/lib/e11y/middleware/request.rb +70 -23
- data/lib/e11y/middleware/routing.rb +78 -21
- data/lib/e11y/middleware/sampling.rb +66 -17
- data/lib/e11y/middleware/self_monitoring_emit.rb +39 -0
- data/lib/e11y/middleware/trace_context.rb +45 -10
- data/lib/e11y/middleware/track_latency.rb +34 -0
- data/lib/e11y/middleware/validation.rb +7 -16
- data/lib/e11y/middleware/versioning.rb +26 -22
- data/lib/e11y/opentelemetry/semantic_conventions.rb +109 -0
- data/lib/e11y/opentelemetry/span_creator.rb +142 -0
- data/lib/e11y/pii/patterns.rb +12 -1
- data/lib/e11y/pipeline/builder.rb +4 -4
- data/lib/e11y/presets/audit_event.rb +13 -2
- data/lib/e11y/railtie.rb +52 -14
- data/lib/e11y/registry.rb +306 -0
- data/lib/e11y/reliability/circuit_breaker.rb +19 -21
- data/lib/e11y/reliability/dlq/base.rb +71 -0
- data/lib/e11y/reliability/dlq/file_adapter.rb +301 -0
- data/lib/e11y/reliability/dlq/file_storage.rb +63 -34
- data/lib/e11y/reliability/dlq/filter.rb +37 -54
- data/lib/e11y/reliability/retry_handler.rb +26 -29
- data/lib/e11y/reliability/retry_rate_limiter.rb +3 -11
- data/lib/e11y/sampling/error_spike_detector.rb +0 -2
- data/lib/e11y/sampling/load_monitor.rb +5 -9
- data/lib/e11y/sampling/stratified_tracker.rb +18 -0
- data/lib/e11y/self_monitoring/buffer_monitor.rb +2 -0
- data/lib/e11y/self_monitoring/performance_monitor.rb +19 -61
- data/lib/e11y/self_monitoring/reliability_monitor.rb +4 -74
- data/lib/e11y/slo/config_loader.rb +40 -0
- data/lib/e11y/slo/config_validator.rb +58 -0
- data/lib/e11y/slo/dashboard_generator.rb +122 -0
- data/lib/e11y/slo/event_driven.rb +8 -0
- data/lib/e11y/slo/tracker.rb +31 -4
- data/lib/e11y/testing/have_tracked_event_matcher.rb +190 -0
- data/lib/e11y/testing/rspec_matchers.rb +21 -0
- data/lib/e11y/testing/snapshot_matcher.rb +86 -0
- data/lib/e11y/trace_context/sampler.rb +35 -0
- data/lib/e11y/tracing/faraday_middleware.rb +31 -0
- data/lib/e11y/tracing/net_http_patch.rb +33 -0
- data/lib/e11y/tracing/propagator.rb +144 -0
- data/lib/e11y/tracing.rb +47 -0
- data/lib/e11y/version.rb +1 -1
- data/lib/e11y/versioning/version_extractor.rb +32 -0
- data/lib/e11y.rb +123 -266
- data/lib/generators/e11y/event/event_generator.rb +22 -0
- data/lib/generators/e11y/event/templates/event.rb.tt +16 -0
- data/lib/generators/e11y/grafana_dashboard/grafana_dashboard_generator.rb +30 -0
- data/lib/generators/e11y/grafana_dashboard/templates/e11y_dashboard.json +81 -0
- data/lib/generators/e11y/install/install_generator.rb +34 -0
- data/lib/generators/e11y/install/templates/e11y.rb +239 -0
- data/lib/generators/e11y/prometheus_alerts/prometheus_alerts_generator.rb +29 -0
- data/lib/generators/e11y/prometheus_alerts/templates/e11y_alerts.yml +28 -0
- data/lib/tasks/e11y_docs.rake +30 -0
- data/lib/tasks/e11y_events.rake +71 -0
- data/lib/tasks/e11y_lint.rake +91 -0
- data/lib/tasks/e11y_slo.rake +29 -0
- metadata +186 -39
- data/docs/ADR-003-slo-observability.md +0 -3337
- data/docs/ADR-010-developer-experience.md +0 -2166
- data/docs/API-REFERENCE-L28.md +0 -914
- data/docs/COMPREHENSIVE-CONFIGURATION.md +0 -2366
- data/docs/CONTRIBUTING.md +0 -312
- data/docs/IMPLEMENTATION_NOTES.md +0 -2804
- data/docs/IMPLEMENTATION_PLAN.md +0 -1971
- data/docs/IMPLEMENTATION_PLAN_ARCHITECTURE.md +0 -586
- data/docs/PLAN.md +0 -148
- data/docs/README.md +0 -296
- data/docs/design/00-memory-optimization.md +0 -593
- data/docs/guides/MIGRATION-L27-L28.md +0 -692
- data/docs/guides/PERFORMANCE-BENCHMARKS.md +0 -434
- data/docs/guides/README.md +0 -44
- data/docs/use_cases/UC-003-pattern-based-metrics.md +0 -1627
- data/lib/e11y/adapters/registry.rb +0 -141
data/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,640 @@
|
|
|
1
|
+
# Contributing to e11y
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in contributing to e11y! This document provides guidelines and best practices for contributing.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Code of Conduct](#code-of-conduct)
|
|
8
|
+
- [Getting Started](#getting-started)
|
|
9
|
+
- [Development Workflow](#development-workflow)
|
|
10
|
+
- [Commit Message Guidelines](#commit-message-guidelines)
|
|
11
|
+
- [Pull Request Process](#pull-request-process)
|
|
12
|
+
- [Testing Guidelines](#testing-guidelines)
|
|
13
|
+
- [Code Style](#code-style)
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Code of Conduct
|
|
18
|
+
|
|
19
|
+
This project follows the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Getting Started
|
|
24
|
+
|
|
25
|
+
### Prerequisites
|
|
26
|
+
|
|
27
|
+
- Ruby 3.2 or 3.3
|
|
28
|
+
- Bundler 2.x
|
|
29
|
+
- Git
|
|
30
|
+
|
|
31
|
+
### Setup
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Clone the repository (fork first on GitHub)
|
|
35
|
+
git clone https://github.com/YOUR_USERNAME/e11y.git
|
|
36
|
+
cd e11y
|
|
37
|
+
|
|
38
|
+
# Run setup script (configures bundle, installs dependencies)
|
|
39
|
+
bin/setup
|
|
40
|
+
|
|
41
|
+
# Run tests
|
|
42
|
+
bundle exec rake spec:unit
|
|
43
|
+
bundle exec rake spec:integration
|
|
44
|
+
bundle exec rake spec:railtie
|
|
45
|
+
|
|
46
|
+
# Check code style
|
|
47
|
+
bundle exec rubocop
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Integration Dependencies (Optional)
|
|
51
|
+
|
|
52
|
+
For integration tests, Rails adapter, or OpenTelemetry:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
bundle install --with integration
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
For Loki/OTel integration tests, start services first:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
docker compose up -d loki otel-collector
|
|
62
|
+
INTEGRATION=true bundle exec rspec spec/integration/
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Development Workflow
|
|
68
|
+
|
|
69
|
+
### 1. Create a Feature Branch
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
git checkout -b feature/your-feature-name
|
|
73
|
+
# or
|
|
74
|
+
git checkout -b fix/your-bug-fix
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Branch Naming Convention:**
|
|
78
|
+
- `feature/` - New features
|
|
79
|
+
- `fix/` - Bug fixes
|
|
80
|
+
- `refactor/` - Code refactoring
|
|
81
|
+
- `test/` - Test improvements
|
|
82
|
+
- `docs/` - Documentation updates
|
|
83
|
+
- `chore/` - Maintenance tasks
|
|
84
|
+
|
|
85
|
+
### 2. Make Your Changes
|
|
86
|
+
|
|
87
|
+
- Write tests first (TDD approach)
|
|
88
|
+
- Ensure all tests pass
|
|
89
|
+
- Follow Ruby style guide (enforced by RuboCop)
|
|
90
|
+
- Add documentation for new features
|
|
91
|
+
- Update CHANGELOG.md
|
|
92
|
+
|
|
93
|
+
### 3. Commit Your Changes
|
|
94
|
+
|
|
95
|
+
Follow [Conventional Commits](#commit-message-guidelines) format:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
git add .
|
|
99
|
+
git commit -m "feat(adapters): add OpenTelemetry logs adapter"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 4. Push and Create PR
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
git push origin feature/your-feature-name
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Then create a Pull Request on GitHub.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Commit Message Guidelines
|
|
113
|
+
|
|
114
|
+
We use [Conventional Commits](https://www.conventionalcommits.org/) for clear and structured commit messages.
|
|
115
|
+
|
|
116
|
+
### Format
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
<type>(<scope>): <subject>
|
|
120
|
+
|
|
121
|
+
<body>
|
|
122
|
+
|
|
123
|
+
<footer>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Type
|
|
127
|
+
|
|
128
|
+
- `feat` - New feature
|
|
129
|
+
- `fix` - Bug fix
|
|
130
|
+
- `docs` - Documentation only
|
|
131
|
+
- `style` - Formatting (no code change)
|
|
132
|
+
- `refactor` - Code refactoring
|
|
133
|
+
- `perf` - Performance improvements
|
|
134
|
+
- `test` - Adding/updating tests
|
|
135
|
+
- `chore` - Maintenance tasks
|
|
136
|
+
- `ci` - CI/CD changes
|
|
137
|
+
|
|
138
|
+
### Scope
|
|
139
|
+
|
|
140
|
+
Component affected (optional but recommended):
|
|
141
|
+
|
|
142
|
+
- `adapters` - Adapters (Loki, Sentry, etc)
|
|
143
|
+
- `buffers` - Buffer implementations
|
|
144
|
+
- `events` - Event classes
|
|
145
|
+
- `instruments` - ActiveJob, Sidekiq, Rails
|
|
146
|
+
- `middleware` - Middleware stack
|
|
147
|
+
- `metrics` - Metrics and cardinality
|
|
148
|
+
- `pipeline` - Event pipeline
|
|
149
|
+
- `reliability` - Circuit breaker, DLQ, retry
|
|
150
|
+
- `sampling` - Sampling strategies
|
|
151
|
+
- `slo` - SLO tracking
|
|
152
|
+
- `rails` - Rails integration
|
|
153
|
+
- `ci` - CI/CD
|
|
154
|
+
- `deps` - Dependencies
|
|
155
|
+
- `docs` - Documentation
|
|
156
|
+
- `test` - Test infrastructure
|
|
157
|
+
- `config` - Configuration
|
|
158
|
+
|
|
159
|
+
### Subject
|
|
160
|
+
|
|
161
|
+
- Use imperative mood: "add" not "added"
|
|
162
|
+
- Don't capitalize first letter
|
|
163
|
+
- No period at the end
|
|
164
|
+
- Maximum 72 characters
|
|
165
|
+
|
|
166
|
+
### Examples
|
|
167
|
+
|
|
168
|
+
**Good Commit Messages:**
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
feat(adapters): add OpenTelemetry logs adapter
|
|
172
|
+
|
|
173
|
+
Implement OTelLogs adapter with:
|
|
174
|
+
- Severity mapping (Ruby Logger → OpenTelemetry)
|
|
175
|
+
- Attribute conversion (tags → log attributes)
|
|
176
|
+
- Trace context propagation
|
|
177
|
+
|
|
178
|
+
Closes #42
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
fix(buffers): prevent memory leak in ring buffer
|
|
183
|
+
|
|
184
|
+
Ring buffer was not releasing old events when capacity reached.
|
|
185
|
+
Added proper cleanup in #push method.
|
|
186
|
+
|
|
187
|
+
Performance impact: minimal (< 1% overhead)
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
refactor(middleware): extract routing logic to separate class
|
|
192
|
+
|
|
193
|
+
Routing logic was embedded in Middleware::Base making it hard to test.
|
|
194
|
+
Extracted to Middleware::Routing for better separation of concerns.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
test(integration): add Rails 8.0 compatibility tests
|
|
199
|
+
|
|
200
|
+
Added test matrix for Ruby 3.2/3.3 × Rails 7.0/7.1/8.0
|
|
201
|
+
All combinations pass except Rails 8.0 exception handling (known issue)
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
docs(readme): update installation instructions
|
|
206
|
+
|
|
207
|
+
Added section on Rails 8.0 compatibility
|
|
208
|
+
Updated gem version requirement to ~> 0.1.1
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
**Bad Commit Messages:**
|
|
212
|
+
|
|
213
|
+
```
|
|
214
|
+
Fix # Too vague, no scope, no description
|
|
215
|
+
Update # Not descriptive
|
|
216
|
+
WIP # Work in progress should not be committed
|
|
217
|
+
Changes # Too generic
|
|
218
|
+
fix: Fix bug # Redundant, should be: fix(scope): describe the bug
|
|
219
|
+
Fixed the thing # Not imperative mood, no scope
|
|
220
|
+
feat: added new feature. # Should be lowercase, no period
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Commit Message Linting
|
|
224
|
+
|
|
225
|
+
We use commitlint to enforce these rules:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
# Install commitlint (one-time setup)
|
|
229
|
+
npm install -g @commitlint/cli @commitlint/config-conventional
|
|
230
|
+
|
|
231
|
+
# Check last commit
|
|
232
|
+
commitlint --from HEAD~1 --to HEAD --verbose
|
|
233
|
+
|
|
234
|
+
# Check all commits in branch
|
|
235
|
+
commitlint --from main --to HEAD --verbose
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## Pull Request Process
|
|
241
|
+
|
|
242
|
+
### Before Creating PR
|
|
243
|
+
|
|
244
|
+
1. **Ensure your branch is up to date:**
|
|
245
|
+
```bash
|
|
246
|
+
git checkout main
|
|
247
|
+
git pull origin main
|
|
248
|
+
git checkout your-branch
|
|
249
|
+
git rebase main
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
2. **Run all tests:**
|
|
253
|
+
```bash
|
|
254
|
+
bundle exec rake spec:unit
|
|
255
|
+
bundle exec rake spec:integration
|
|
256
|
+
bundle exec rake spec:railtie
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
3. **Check code style:**
|
|
260
|
+
```bash
|
|
261
|
+
bundle exec rubocop
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
4. **Verify coverage:**
|
|
265
|
+
```bash
|
|
266
|
+
bundle exec rake spec:coverage
|
|
267
|
+
# Coverage should be ≥95%
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
5. **Update documentation:**
|
|
271
|
+
- Update README.md if needed
|
|
272
|
+
- Add/update CHANGELOG.md
|
|
273
|
+
- Create ADR if making architectural decision
|
|
274
|
+
|
|
275
|
+
### PR Guidelines
|
|
276
|
+
|
|
277
|
+
- **Keep PRs small:** \<500 lines of code
|
|
278
|
+
- **One logical change per PR:** Don't mix refactoring with features
|
|
279
|
+
- **Write descriptive PR title:** Follow Conventional Commits format
|
|
280
|
+
- **Fill out PR template:** Don't skip sections
|
|
281
|
+
- **Self-review:** Read your own PR before requesting review
|
|
282
|
+
- **Add tests:** PRs without tests will not be merged
|
|
283
|
+
- **Update docs:** Update relevant documentation
|
|
284
|
+
|
|
285
|
+
### PR Title Format
|
|
286
|
+
|
|
287
|
+
Same as commit messages:
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
feat(adapters): add OpenTelemetry logs adapter
|
|
291
|
+
fix(buffers): prevent memory leak in ring buffer
|
|
292
|
+
docs(readme): update installation instructions
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### PR Size Guidelines
|
|
296
|
+
|
|
297
|
+
| Lines Changed | Review Time | Merge Probability |
|
|
298
|
+
|---------------|-------------|-------------------|
|
|
299
|
+
| \<100 | 30 min | 95% |
|
|
300
|
+
| 100-300 | 1-2 hours | 85% |
|
|
301
|
+
| 300-500 | 2-4 hours | 70% |
|
|
302
|
+
| \>500 | 4+ hours | 50% |
|
|
303
|
+
|
|
304
|
+
**Recommendation:** Break large PRs into smaller, logical units.
|
|
305
|
+
|
|
306
|
+
### Stacked PRs
|
|
307
|
+
|
|
308
|
+
For large features, use stacked PRs:
|
|
309
|
+
|
|
310
|
+
```
|
|
311
|
+
PR #1: feat(adapters): add OTel base adapter
|
|
312
|
+
└── PR #2: feat(adapters): add OTel logs adapter
|
|
313
|
+
└── PR #3: feat(adapters): add OTel metrics adapter
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Each PR builds on the previous one and can be reviewed independently.
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## Testing Guidelines
|
|
321
|
+
|
|
322
|
+
### Test Organization
|
|
323
|
+
|
|
324
|
+
```
|
|
325
|
+
spec/
|
|
326
|
+
├── e11y/ # Unit tests (fast, isolated)
|
|
327
|
+
├── integration/ # Integration tests (Rails app, adapters)
|
|
328
|
+
└── support/ # Shared test helpers
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### Test Types
|
|
332
|
+
|
|
333
|
+
**Unit Tests** (`spec/e11y/`):
|
|
334
|
+
- Fast (\<10ms each)
|
|
335
|
+
- No external dependencies
|
|
336
|
+
- Test single class/module
|
|
337
|
+
- Use mocks/stubs liberally
|
|
338
|
+
|
|
339
|
+
**Integration Tests** (`spec/integration/`):
|
|
340
|
+
- Slower (50-500ms each)
|
|
341
|
+
- Full Rails app
|
|
342
|
+
- Test component interactions
|
|
343
|
+
- Minimal mocking
|
|
344
|
+
|
|
345
|
+
### Running Tests
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
# All tests
|
|
349
|
+
bundle exec rspec
|
|
350
|
+
|
|
351
|
+
# Unit tests only
|
|
352
|
+
bundle exec rake spec:unit
|
|
353
|
+
|
|
354
|
+
# Integration tests only
|
|
355
|
+
bundle exec rake spec:integration
|
|
356
|
+
|
|
357
|
+
# Specific file
|
|
358
|
+
bundle exec rspec spec/e11y/buffers/ring_buffer_spec.rb
|
|
359
|
+
|
|
360
|
+
# Specific example
|
|
361
|
+
bundle exec rspec spec/e11y/buffers/ring_buffer_spec.rb:42
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Test Coverage
|
|
365
|
+
|
|
366
|
+
We maintain ≥95% test coverage:
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
# Generate coverage report
|
|
370
|
+
bundle exec rake spec:coverage
|
|
371
|
+
|
|
372
|
+
# View report
|
|
373
|
+
open coverage/index.html
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
**Coverage Requirements:**
|
|
377
|
+
- New code: 100% coverage
|
|
378
|
+
- Modified code: Maintain or improve coverage
|
|
379
|
+
- Exceptions: Document in PR why coverage is lower
|
|
380
|
+
|
|
381
|
+
### Writing Good Tests
|
|
382
|
+
|
|
383
|
+
```ruby
|
|
384
|
+
# Good test structure
|
|
385
|
+
RSpec.describe E11y::Buffers::RingBuffer do
|
|
386
|
+
subject(:buffer) { described_class.new(capacity: 3) }
|
|
387
|
+
|
|
388
|
+
describe '#push' do
|
|
389
|
+
context 'when buffer is not full' do
|
|
390
|
+
it 'adds event to buffer' do
|
|
391
|
+
buffer.push(event)
|
|
392
|
+
expect(buffer.size).to eq(1)
|
|
393
|
+
end
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
context 'when buffer is full' do
|
|
397
|
+
before do
|
|
398
|
+
3.times { buffer.push(create_event) }
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
it 'evicts oldest event' do
|
|
402
|
+
oldest_event = buffer.first
|
|
403
|
+
buffer.push(new_event)
|
|
404
|
+
expect(buffer).not_to include(oldest_event)
|
|
405
|
+
end
|
|
406
|
+
end
|
|
407
|
+
end
|
|
408
|
+
end
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
**Test Best Practices:**
|
|
412
|
+
- One assertion per test (when possible)
|
|
413
|
+
- Use descriptive test names
|
|
414
|
+
- Use `let` for shared setup
|
|
415
|
+
- Use `subject` for the object under test
|
|
416
|
+
- Use `before` for common setup
|
|
417
|
+
- Use `context` for different scenarios
|
|
418
|
+
- Test edge cases and error paths
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## Code Style
|
|
423
|
+
|
|
424
|
+
### Ruby Style Guide
|
|
425
|
+
|
|
426
|
+
We follow the [Ruby Style Guide](https://rubystyle.guide/) enforced by RuboCop.
|
|
427
|
+
|
|
428
|
+
### Key Conventions
|
|
429
|
+
|
|
430
|
+
**Naming:**
|
|
431
|
+
```ruby
|
|
432
|
+
# Classes: PascalCase
|
|
433
|
+
class EventProcessor
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
# Methods: snake_case
|
|
437
|
+
def process_event(event)
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
# Constants: SCREAMING_SNAKE_CASE
|
|
441
|
+
MAX_BUFFER_SIZE = 1000
|
|
442
|
+
|
|
443
|
+
# Files: snake_case.rb
|
|
444
|
+
lib/e11y/buffers/ring_buffer.rb
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
**Code Organization:**
|
|
448
|
+
```ruby
|
|
449
|
+
# Order: constants, attributes, initializer, public, protected, private
|
|
450
|
+
class Adapter
|
|
451
|
+
MAX_RETRIES = 3
|
|
452
|
+
|
|
453
|
+
attr_reader :config
|
|
454
|
+
|
|
455
|
+
def initialize(config)
|
|
456
|
+
@config = config
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
def emit(event)
|
|
460
|
+
# public method
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
protected
|
|
464
|
+
|
|
465
|
+
def validate(event)
|
|
466
|
+
# protected method
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
private
|
|
470
|
+
|
|
471
|
+
def internal_method
|
|
472
|
+
# private method
|
|
473
|
+
end
|
|
474
|
+
end
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
**Performance:**
|
|
478
|
+
```ruby
|
|
479
|
+
# Use #each instead of #map when not using return value
|
|
480
|
+
events.each { |event| process(event) }
|
|
481
|
+
|
|
482
|
+
# Use #select instead of #map + #compact
|
|
483
|
+
events.select { |event| event.valid? }
|
|
484
|
+
|
|
485
|
+
# Use ||= for memoization
|
|
486
|
+
def expensive_calculation
|
|
487
|
+
@result ||= perform_calculation
|
|
488
|
+
end
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
### RuboCop
|
|
492
|
+
|
|
493
|
+
```bash
|
|
494
|
+
# Check violations
|
|
495
|
+
bundle exec rubocop
|
|
496
|
+
|
|
497
|
+
# Auto-fix (safe corrections only)
|
|
498
|
+
bundle exec rubocop --auto-correct
|
|
499
|
+
|
|
500
|
+
# Auto-fix (including unsafe corrections)
|
|
501
|
+
bundle exec rubocop --auto-correct-all
|
|
502
|
+
|
|
503
|
+
# Check specific file
|
|
504
|
+
bundle exec rubocop lib/e11y/buffers/ring_buffer.rb
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
### RuboCop Configuration
|
|
508
|
+
|
|
509
|
+
Our RuboCop config (`.rubocop.yml`) enforces:
|
|
510
|
+
- Ruby 3.2+ syntax
|
|
511
|
+
- Max line length: 120 characters
|
|
512
|
+
- Max method length: 25 lines
|
|
513
|
+
- Max class length: 250 lines
|
|
514
|
+
- Max cyclomatic complexity: 10
|
|
515
|
+
|
|
516
|
+
---
|
|
517
|
+
|
|
518
|
+
## Documentation
|
|
519
|
+
|
|
520
|
+
### Project Documentation
|
|
521
|
+
|
|
522
|
+
- [Architecture Decisions (ADRs)](docs/architecture/ADR-INDEX.md)
|
|
523
|
+
- [Quick Start](docs/QUICK-START.md)
|
|
524
|
+
|
|
525
|
+
### Code Documentation
|
|
526
|
+
|
|
527
|
+
Use YARD for documentation:
|
|
528
|
+
|
|
529
|
+
```ruby
|
|
530
|
+
# @param event [E11y::Event::Base] Event to emit
|
|
531
|
+
# @param options [Hash] Additional options
|
|
532
|
+
# @option options [Boolean] :async (false) Emit asynchronously
|
|
533
|
+
# @return [Boolean] true if successful
|
|
534
|
+
# @raise [ArgumentError] if event is invalid
|
|
535
|
+
#
|
|
536
|
+
# @example Emit event synchronously
|
|
537
|
+
# adapter.emit(event)
|
|
538
|
+
#
|
|
539
|
+
# @example Emit event asynchronously
|
|
540
|
+
# adapter.emit(event, async: true)
|
|
541
|
+
def emit(event, options = {})
|
|
542
|
+
# implementation
|
|
543
|
+
end
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
### Inline Comments
|
|
547
|
+
|
|
548
|
+
```ruby
|
|
549
|
+
# Good: Explain WHY, not WHAT
|
|
550
|
+
# Buffer uses ring structure to prevent unbounded growth
|
|
551
|
+
# while maintaining insertion performance O(1)
|
|
552
|
+
buffer = RingBuffer.new(capacity: 1000)
|
|
553
|
+
|
|
554
|
+
# Bad: Obvious comment (don't do this)
|
|
555
|
+
# Create new buffer
|
|
556
|
+
buffer = RingBuffer.new
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
---
|
|
560
|
+
|
|
561
|
+
## Architecture Decision Records (ADRs)
|
|
562
|
+
|
|
563
|
+
For significant architectural decisions, create an ADR in `docs/`:
|
|
564
|
+
|
|
565
|
+
```bash
|
|
566
|
+
# Create new ADR (see docs/architecture/ADR-INDEX.md for numbering)
|
|
567
|
+
# Follow format of existing ADRs (docs/architecture/ADR-001-architecture.md, etc.)
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
**When to create ADR:**
|
|
571
|
+
- Changing core architecture
|
|
572
|
+
- Adding/removing major dependencies
|
|
573
|
+
- Breaking API changes
|
|
574
|
+
- Performance vs maintainability tradeoffs
|
|
575
|
+
|
|
576
|
+
**ADR Template:**
|
|
577
|
+
```markdown
|
|
578
|
+
# ADR-018: Title
|
|
579
|
+
|
|
580
|
+
## Status
|
|
581
|
+
Proposed | Accepted | Deprecated | Superseded by ADR-XXX
|
|
582
|
+
|
|
583
|
+
## Context
|
|
584
|
+
What is the problem we're solving?
|
|
585
|
+
|
|
586
|
+
## Decision
|
|
587
|
+
What did we decide to do?
|
|
588
|
+
|
|
589
|
+
## Consequences
|
|
590
|
+
What are the positive and negative outcomes?
|
|
591
|
+
|
|
592
|
+
## Alternatives Considered
|
|
593
|
+
What other options did we consider?
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
---
|
|
597
|
+
|
|
598
|
+
## Security
|
|
599
|
+
|
|
600
|
+
```bash
|
|
601
|
+
# Check for vulnerable dependencies
|
|
602
|
+
bundle exec bundler-audit check --update
|
|
603
|
+
|
|
604
|
+
# Static security analysis (if Brakeman installed)
|
|
605
|
+
bundle exec brakeman
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
## Reporting Bugs
|
|
609
|
+
|
|
610
|
+
**Before reporting:** Search existing issues, verify bug exists in main.
|
|
611
|
+
|
|
612
|
+
**Bug report template:**
|
|
613
|
+
- Describe the bug
|
|
614
|
+
- Steps to reproduce
|
|
615
|
+
- Expected vs actual behavior
|
|
616
|
+
- Environment (Ruby, E11y, Rails, OS versions)
|
|
617
|
+
|
|
618
|
+
## Suggesting Features
|
|
619
|
+
|
|
620
|
+
**Feature request template:**
|
|
621
|
+
- Problem being solved
|
|
622
|
+
- Proposed solution
|
|
623
|
+
- Alternatives considered
|
|
624
|
+
- Additional context
|
|
625
|
+
|
|
626
|
+
## Getting Help
|
|
627
|
+
|
|
628
|
+
- **Questions:** Open a GitHub Discussion
|
|
629
|
+
- **Bugs:** Open a GitHub Issue
|
|
630
|
+
- **Security:** Private disclosure via GitHub Security Advisories
|
|
631
|
+
|
|
632
|
+
---
|
|
633
|
+
|
|
634
|
+
## License
|
|
635
|
+
|
|
636
|
+
By contributing, you agree that your contributions will be licensed under the MIT License.
|
|
637
|
+
|
|
638
|
+
---
|
|
639
|
+
|
|
640
|
+
Thank you for contributing to e11y! 🎉
|