exis_ray 0.10.0 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 78d2b6cbc5e3da104fee7f3d2f481311acd2da7971d80295edf0bbad6eaab178
4
- data.tar.gz: c54ebfc75e0c5abf640506b97b41b4b86bfe1f05a8d17a2d484941dae0fb21d4
3
+ metadata.gz: 833391532fe44ad6a4014ade7f96f43b8f24b32af0c80764d064a2222c8aca59
4
+ data.tar.gz: 0f49d7c49dcaec8ab49ce992798bc79404c1a457c9531207d807faadaae3a1a2
5
5
  SHA512:
6
- metadata.gz: e6642e744b2b9fc0d798e419664d76ebe2a0beba38722b1db09ac501d408938695990d4d752a0b0bf9cad78aa1a62a3939113e1444a623df890cabb8a4f0ad31
7
- data.tar.gz: e96e7936add04a739ac1f325d1b768437c82381f5252420f2ab0eb72d6ad51e50bc272c7b136e4f1c0096d59f50b4b9fdc227ec05086e374e385ad543d5d47e8
6
+ metadata.gz: d0b580fddcadbe0cfc165d7c3e601c184fe31f504cd68be2cddf44b7a0fb661d398c1170534532115a5cb0b18c1c591a749e08868fd0b767d07b966b0a3c1e39
7
+ data.tar.gz: e29e918ecec0e4e7dd155270978bd8c63bda07d447215811bcd7b6901f36b7748fb9a3cd7a2fbe18938c572620e95a9f6305cc3b8805d06011b9f49911499b79
data/AGENTS.md ADDED
@@ -0,0 +1,238 @@
1
+ # ExisRay — Project Intelligence
2
+
3
+ > Fuente de verdad del repositorio. Reglas, convenciones, estructura, entorno y
4
+ > arquitectura viven acá. `CLAUDE.md` queda reservado para notas específicas de
5
+ > Claude Code. Si una regla aplica a cualquier agente, vive en este archivo.
6
+
7
+ ## ¿Qué es ExisRay?
8
+
9
+ ExisRay es la capa de observabilidad y trazabilidad distribuida del ecosistema Wispro. Se integra con Rails para emitir logs estructurados en JSON, propagar trace context entre servicios (HTTP, Sidekiq, RabbitMQ), y mantener identidad de negocio (user_id, isp_id, correlation_id) en cada línea de log.
10
+
11
+ El estándar de logging que implementa está definido en `skill/SKILL.md` (API, arquitectura, reglas generales) y `skill/references/standard.md` (Data First, mapeo OpenTelemetry, ciclo de vida). Son la fuente de verdad — cualquier duda sobre formato, campos, o semántica de niveles se resuelve ahí.
12
+
13
+ ## Documentación
14
+
15
+ - **Para humanos**: `docs/` + `README.md`. Ver README para índice.
16
+ - **Para agentes AI**: `skill/SKILL.md` + `skill/references/`. Es la skill empaquetada que otros proyectos consumen via `wispro-agent sync`.
17
+ - **Nunca referenciar `skill/` desde `docs/` o `README.md`** — son audiencias distintas.
18
+
19
+ ## Mapa de conocimiento (cómo leer la doc de este repo)
20
+
21
+ - **Tu conocimiento = la UNIÓN de este repo + sus asociados.** No termina en el `docs/<capa>/` local: incluye la doc de los servicios/gemas de `skills.yml`. Un flujo que cruza servicios (e2e) **no vive como doc estática** en ningún repo — se compone on-demand recorriendo el grafo (RFC-021): seguí las anclas hasta los repos asociados y unificá.
22
+ - **Entrá por** [`skill/SKILL.md`](skill/SKILL.md) — índice de agente; resume el contrato y linkea el detalle.
23
+ - **Cobertura de capas de este repo** (gema de observabilidad, sin DB, instrumenta al host):
24
+
25
+ | capa | RFC | estado | artefacto / motivo |
26
+ |---|---|---|---|
27
+ | comportamiento | RFC-007 | **presente** | [`docs/behavior/behavior.md`](docs/behavior/behavior.md) — parcial incremental |
28
+ | glosario | RFC-009 | **presente** | [`docs/glossary/glossary.md`](docs/glossary/glossary.md) — sembrado, acreta |
29
+ | test | RFC-013 | **presente** | [`docs/test/testing.md`](docs/test/testing.md) — piloto RFC-013 |
30
+ | configuración | RFC-012 | **presente** | [`docs/config/configuracion.md`](docs/config/configuracion.md) — inventario base; enriquecimiento §f pendiente |
31
+ | datos | RFC-002 | `n/a` | gema sin DB (sin `db/schema.rb`) |
32
+ | operaciones | RFC-003 | `n/a` | no expone superficie propia (HTTP/CLI/eventos) — instrumenta al host |
33
+ | dependencias consumidas | RFC-018 | `n/a` | inyecta hooks de tracing, no consume servicios |
34
+ | eventos | RFC-005 | `n/a` | no produce eventos propios; propaga trace en mensajes ajenos |
35
+ | interfaz | RFC-004 | **presente** | [`docs/interface/interface.md`](docs/interface/interface.md) — superficie pública consumer-facing |
36
+ | topología | RFC-006 | **pendiente** | deps + adapters Sidekiq/BugBunny/Faraday/ActiveResource |
37
+ | release | RFC-014 | **pendiente** | `version.rb` + `CHANGELOG.md` + `.github/workflows/release.yml` (tag `v*` → RubyGems) |
38
+ | errores | RFC-020 | **pendiente** | excepciones de validación de config en el Railtie |
39
+
40
+ - **Navegar una ancla cross-repo:** tomá la key de servicio en `skills.yml` (`services.<dep>.repo`) → ese repo es checkout hermano local o alcanzable por GitHub MCP. La doc de los asociados ES parte de tu conocimiento accesible.
41
+
42
+ ## Convenciones del framework
43
+
44
+ - Este repo **consume skills del framework** declaradas en `skills.yml` (manifiesto raíz). Ese archivo enumera los MCPs y las skills que el repo trae al contexto del agente.
45
+ - Las skills sincronizadas en `.agents/skills/` traen **conocimiento de dependencias**. **Leer la skill de una dependencia ANTES de responder sobre ella.**
46
+ - El sync de skills lo hace el CLI: `wispro-agent sync`.
47
+
48
+ ## Knowledge Base
49
+
50
+ - Las skills en `.agents/skills/` incluyen conocimiento de dependencias.
51
+ - Leer la skill de una dependencia ANTES de responder sobre ella.
52
+ - Rebuild / sincronización: `wispro-agent sync`.
53
+
54
+ ### Entorno
55
+
56
+ - Versión de Ruby: leer `.ruby-version`
57
+ - Versión de Rails y gemas: leer `Gemfile.lock`
58
+ - Gestor de Ruby: chruby (no usar rvm ni rbenv)
59
+ - Package manager: Bundler
60
+
61
+ ### RuboCop
62
+
63
+ - Usamos rubocop-rails-omakase como base.
64
+ - Correr `bundle exec rubocop -a` antes de commitear.
65
+ - No deshabilitar cops sin justificación en el PR.
66
+
67
+ ### YARD
68
+
69
+ - Documentación incremental: si tocás un método, documentalo con YARD.
70
+ - Consultar la skill `yard` para tags y tipos correctos.
71
+ - Verificar cobertura: `bundle exec yard stats --list-undoc`
72
+
73
+ ### Testing
74
+
75
+ - Framework: RSpec
76
+ - Correr: `bundle exec rspec`
77
+ - Todo código nuevo debe tener tests.
78
+
79
+ ### Releases o Nuevas versiones
80
+
81
+ - Usar `/gem-release` para publicar nuevas versiones.
82
+ - El GitHub Action publica a RubyGems automáticamente al pushear un tag `v*`.
83
+
84
+ ---
85
+
86
+ ## Arquitectura & Componentes
87
+
88
+ ### Core
89
+
90
+ - **`ExisRay::Tracer`** — Contexto de trazabilidad distribuida (AWS X-Ray). Extiende `ActiveSupport::CurrentAttributes` para thread-safety. Campos: `trace_id`, `root_id`, `self_id`, `source`, `created_at`, `request_id`, `sidekiq_job`, `task`.
91
+ - **`ExisRay::JsonFormatter`** — Formateador global. Acepta Hash, KV strings (`key=value`) y texto libre. Inyecta automáticamente el contexto del Tracer y del Current en cada línea. Castea valores numéricos y filtra claves sensibles.
92
+ - **`ExisRay::Current`** — Contexto de negocio (user_id, isp_id, correlation_id). Clase abstracta — la app host la subclasifica.
93
+ - **`ExisRay::Reporter`** — Wrapper de Sentry. Clase abstracta — la app host la subclasifica.
94
+ - **`ExisRay::Configuration`** — Configuración global con defaults para AWS X-Ray.
95
+
96
+ ### Integraciones HTTP
97
+
98
+ - **`ExisRay::HttpMiddleware`** — Rack middleware. Hidrata el Tracer con el header entrante. Se inserta automáticamente después de `ActionDispatch::RequestId`.
99
+ - **`ExisRay::LogSubscriber`** — Logger nativo de requests HTTP. Reemplaza Lograge. Solo activo con `json_logs: true`.
100
+ - **`ExisRay::FaradayMiddleware`** — Inyecta `propagation_trace_header` en requests salientes via Faraday.
101
+ - **`ExisRay::ActiveResourceInstrumentation`** — Ídem para ActiveResource.
102
+
103
+ ### Integraciones Sidekiq
104
+
105
+ - **`ExisRay::Sidekiq::ClientMiddleware`** — Inyecta `exis_ray_trace` en el payload del job antes de encolarlo.
106
+ - **`ExisRay::Sidekiq::ServerMiddleware`** — Hidrata el Tracer al inicio de cada job. Genera root_id nuevo si el job no trae trace.
107
+
108
+ ### Integraciones BugBunny (RabbitMQ)
109
+
110
+ - **`ExisRay::BugBunny::PublisherTracing`** — Middleware para `BugBunny::Client`/`BugBunny::Resource`. Inyecta `propagation_trace_header` en cada mensaje publicado.
111
+ - **`ExisRay::BugBunny::ConsumerTracingMiddleware`** — Consumer middleware. Corre antes de todos los logs internos de BugBunny. Hidrata el Tracer desde el header AMQP entrante o genera root_id nuevo.
112
+ - **Railtie hooks** — `rpc_reply_headers` inyecta el trace actualizado en el reply del consumer. `on_rpc_reply` hidrata el Tracer en el thread del publisher al recibir la respuesta.
113
+
114
+ ### Procesos en Background
115
+
116
+ - **`ExisRay::TaskMonitor`** — Lifecycle manager para Rake/Cron. Genera root_id, loguea `task_started`/`task_finished` con `duration_s` y `status`.
117
+
118
+ ---
119
+
120
+ ## Métodos Clave
121
+
122
+ ```ruby
123
+ # Hidratar el Tracer (HTTP, Sidekiq, BugBunny consumer)
124
+ ExisRay::Tracer.hydrate(trace_id: header_string, source: 'http')
125
+
126
+ # Sincronizar correlation_id al Current configurado
127
+ ExisRay.sync_correlation_id
128
+
129
+ # Generar header de propagación para el siguiente servicio
130
+ ExisRay::Tracer.generate_trace_header
131
+ # => "Root=1-abc123-...;Self=...;CalledFrom=wispro_agent;TotalTimeSoFar=42ms"
132
+
133
+ # Acceder a la configuración
134
+ ExisRay.configuration.propagation_trace_header # => 'X-Amzn-Trace-Id'
135
+ ExisRay.configuration.json_logs? # => true/false
136
+ ```
137
+
138
+ ---
139
+
140
+ ## Campos Auto-Inyectados
141
+
142
+ `JsonFormatter` inyecta estos campos automáticamente. **Nunca** incluirlos manualmente en logs:
143
+
144
+ | Campo | Condición |
145
+ |:------|:----------|
146
+ | `time` | Siempre |
147
+ | `level` | Siempre |
148
+ | `severity_number` | Siempre (OTel: DEBUG=5, INFO=9, WARN=13, ERROR=17, FATAL=21) |
149
+ | `service` | Siempre |
150
+ | `service_version` | Siempre (de `config.version` o `config.x.version`) |
151
+ | `deployment_environment` | Siempre (de `Rails.env`) |
152
+ | `request_id` | Cuando `Tracer.request_id` está presente (independiente de root_id) |
153
+ | `root_id` | Cuando hay trace context activo |
154
+ | `trace_id` | Cuando hay trace context activo |
155
+ | `source` | Cuando hay trace context activo (HTTP siempre genera root fresco si no llega header) |
156
+ | `correlation_id` | Cuando `Current.correlation_id` está presente |
157
+ | `user_id` | Cuando `Current.user_id` está presente |
158
+ | `isp_id` | Cuando `Current.isp_id` está presente |
159
+ | `Current.log_fields` (cualquier key) | Si la subclass overrideó el hook (default `{}`) |
160
+ | `sidekiq_job` | Solo en procesos Sidekiq |
161
+ | `task` | Solo en procesos TaskMonitor |
162
+ | `tags` | Solo si hay Rails tagged logging activo |
163
+
164
+ ---
165
+
166
+ ## Reglas de Ejecución
167
+
168
+ ### Logging
169
+
170
+ - Todo log interno usa KV strings: `component=exis_ray event=algo`
171
+ - `component` siempre en `snake_case`
172
+ - DEBUG siempre en block form: `logger.debug { "k=#{v}" }`
173
+ - Nunca `Kernel#warn` ni `$stderr`
174
+ - Toda operación de logging envuelta en `rescue StandardError`
175
+ - Duraciones con `Process.clock_gettime(Process::CLOCK_MONOTONIC)`, nunca `Time.now`
176
+
177
+ ### Seguridad
178
+
179
+ - Claves sensibles (`password|pass|passwd|secret|token|api_key|auth`) → `[FILTERED]`
180
+ - Nunca loguear PII. Solo `user_id`, `isp_id`
181
+
182
+ ### Source válidos
183
+
184
+ `http` | `sidekiq` | `task` | `system`
185
+
186
+ ### Propagación de headers
187
+
188
+ - **Entrante HTTP:** `trace_header` (formato Rack: `HTTP_X_AMZN_TRACE_ID`) — solo en `HttpMiddleware`
189
+ - **Saliente (todos los transportes):** `propagation_trace_header` (formato HTTP: `X-Amzn-Trace-Id`)
190
+
191
+ ### Prohibiciones
192
+
193
+ - No Lograge — reemplazado por `LogSubscriber`
194
+ - No loguear manualmente: `time`, `level`, `service`, `source`, `root_id`, `trace_id`, `correlation_id`, `sidekiq_job`, `task`
195
+
196
+ ---
197
+
198
+ ## Compatibilidad Rails
199
+
200
+ - **Reloading:** Usar `cache_classes?` helper (verifica `respond_to?(:enable_reloading)`) para Rails 7.1+
201
+ - **Notifications:** Rails 7.1+ usa `all_listeners_for`, Rails 6/7.0 usa `listeners_for` — siempre usar `respond_to?` guards
202
+ - **Soporte:** Rails 6, 7 y 8
203
+
204
+ ---
205
+
206
+ ## Integración Automática (Railtie)
207
+
208
+ El `Railtie` en `after_initialize` detecta y auto-instrumenta sin intervención del desarrollador:
209
+
210
+ | Gema detectada | Qué hace |
211
+ |:---------------|:---------|
212
+ | `BugBunny` | Registra `ConsumerTracingMiddleware` y los hooks RPC (`PublisherTracing` va en el cliente, manual) |
213
+ | `Sidekiq` | Registra client + server middleware |
214
+ | `ActiveResource` | Prepend de `ActiveResourceInstrumentation` |
215
+ | `Faraday` | Disponible como middleware opcional |
216
+
217
+ ---
218
+
219
+ ## Configuración Mínima
220
+
221
+ ```ruby
222
+ # config/initializers/exis_ray.rb
223
+ ExisRay.configure do |config|
224
+ config.log_format = :json # :text por defecto
225
+ config.trace_header = 'HTTP_X_AMZN_TRACE_ID'
226
+ config.propagation_trace_header = 'X-Amzn-Trace-Id'
227
+ config.current_class = 'Current'
228
+ config.reporter_class = 'Reporter'
229
+ config.emit_legacy_exception_keys = true # default true; pasar a false cuando consumers usen exception.*
230
+ end
231
+
232
+ # BugBunny publisher — debe agregarse manualmente al cliente
233
+ BugBunny::Client.new(pool: pool) do |stack|
234
+ stack.use ExisRay::BugBunny::PublisherTracing
235
+ end
236
+ ```
237
+
238
+ ---
data/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## [0.11.1] - 2026-06-29
2
+
3
+ ### Documentación
4
+ - **Capa `config` (RFC-012)**: nuevo `docs/config/configuracion.md` — inventario base (10 opciones de `ExisRay.configure` + `HOSTNAME` + inyecciones del Railtie al host §i + gemas configuradas §j) y enriquecimiento semántico §f (categoría · failure-mode · side-effect · scope-override · business-reason por var, 11/11), §g ramificadores y §h threading. — @gedera
5
+ - **Capa `interface` (RFC-004)**: nuevo `docs/interface/interface.md` — superficie Ruby pública consumer-facing (símbolo · tipo · firma · nota), cerrando la coexistencia transitoria del contrato embebido en `skill/SKILL.md`. — @gedera
6
+ - **Capa `test` (RFC-013)**: `docs/test/testing.md` — piloto del artefacto de test (suites RSpec, fixtures, coverage); status RFC-013 `accepted`. — @gedera
7
+ - **Mapa de conocimiento (RFC-008 r2)** en `AGENTS.md`: tabla de cobertura de las 12 capas (presente / n/a / pendiente). `skill/SKILL.md` y `README.md` recompuestos indexando las capas nuevas; SKILL re-anclado a v0.11.1. Sin cambios de código (`lib/` intacto). — @gedera
8
+
9
+ ## [0.11.0] - 2026-05-26
10
+
11
+ ### Nuevas funcionalidades
12
+ - **`config.emit_legacy_exception_keys`** (#15): nuevo flag de `Configuration` (default `true`) que controla la emisión de las keys legacy `error_class`/`error_message` junto a `exception.type`/`exception.message`. Bajado a `false`, `ExisRay::LogSubscriber` (logs HTTP) y `ExisRay::TaskMonitor` (logs de tasks) emiten solo las keys OTel v1.0 (`exception.*`), reduciendo bytes y ruido downstream cuando los consumers (dashboards, alertas, queries) ya migraron. Mantiene `true` como default durante la ventana de transición — se flipea a `false` en v0.12.0 y se remueve el flag en v1.0 cuando los legacy se eliminen definitivamente.
13
+ - **`url.path` (OTel v1.0) + `config.emit_legacy_path_key`** (#15): `ExisRay::LogSubscriber` empieza a emitir `url.path` (nombre canónico OTel) en todos los logs HTTP. El alias legacy `path` se sigue emitiendo durante la ventana de transición y queda gateado por `config.emit_legacy_path_key` (default `true`). Cuando los consumers (queries, dashboards, alertas) hayan migrado a `url.path`, bajar el flag a `false` para suprimir el alias. Se flipea a `false` en v0.12.0 y se remueve el flag en v1.0.
14
+ - **Doc: `url.path` vs `http_route` no se deduplican** (#15): el caso reportado de "valores idénticos en endpoints estáticos" no es un bug — `url.path` es la URL **concreta** (alta cardinalidad), `http_route` es el **template** (baja cardinalidad). Cumplen roles distintos en dashboards/queries downstream; siguen emitiéndose siempre los dos. Documentado en `README.md` y `skill/SKILL.md` (subsección "Migración OTel — `path` → `url.path`" + nota explicativa de la coexistencia semántica).
15
+
1
16
  ## [0.10.0] - 2026-05-25
2
17
 
3
18
  ### Documentación
data/CLAUDE.md CHANGED
@@ -1,189 +1,15 @@
1
- # ExisRay Project Intelligence
1
+ # Claude Code Notes
2
2
 
3
- ## ¿Qué es ExisRay?
3
+ ## Fuente de verdad del repositorio
4
4
 
5
- ExisRay es la capa de observabilidad y trazabilidad distribuida del ecosistema Wispro. Se integra con Rails para emitir logs estructurados en JSON, propagar trace context entre servicios (HTTP, Sidekiq, RabbitMQ), y mantener identidad de negocio (user_id, isp_id, correlation_id) en cada línea de log.
5
+ Las reglas, convenciones, estructura y contexto del proyecto viven en `AGENTS.md`.
6
6
 
7
- El estándar de logging que implementa está definido en `skill/SKILL.md` (API, arquitectura, reglas generales) y `skill/references/standard.md` (Data First, mapeo OpenTelemetry, ciclo de vida). Son la fuente de verdad — cualquier duda sobre formato, campos, o semántica de niveles se resuelve ahí.
7
+ - Leer `AGENTS.md` antes de hacer cambios.
8
+ - Tratar `AGENTS.md` como fuente de verdad para identidad, estructura, documentación, convenciones del framework, entorno, y arquitectura.
8
9
 
9
- ## Documentación
10
+ ## Propósito de este archivo
10
11
 
11
- - **Para humanos**: `docs/` (5 archivos) + `README.md`. Ver README para índice.
12
- - **Para agentes AI**: `skill/SKILL.md` + `skill/references/`. Es la skill empaquetada que otros proyectos consumen via `skill-manager sync`.
13
- - **Nunca referenciar `skill/` desde `docs/` o `README.md`** — son audiencias distintas.
12
+ `CLAUDE.md` queda reservado para instrucciones o notas específicas de Claude Code.
14
13
 
15
- ## Knowledge Base
16
- - Las skills en `.agents/skills/` incluyen conocimiento de dependencias.
17
- - Leer la skill de una dependencia ANTES de responder sobre ella.
18
- - Rebuild: `ruby .agents/skills/skill-manager/scripts/sync.rb`
19
-
20
- ### Entorno
21
- - Versión de Ruby: leer `.ruby-version`
22
- - Versión de Rails y gemas: leer `Gemfile.lock`
23
- - Gestor de Ruby: chruby (no usar rvm ni rbenv)
24
- - Package manager: Bundler
25
-
26
- ### RuboCop
27
- - Usamos rubocop-rails-omakase como base.
28
- - Correr `bundle exec rubocop -a` antes de commitear.
29
- - No deshabilitar cops sin justificación en el PR.
30
-
31
- ### YARD
32
- - Documentación incremental: si tocás un método, documentalo con YARD.
33
- - Consultar la skill `yard` para tags y tipos correctos.
34
- - Verificar cobertura: `bundle exec yard stats --list-undoc`
35
-
36
- ### Testing
37
- - Framework: RSpec
38
- - Correr: `bundle exec rspec`
39
- - Todo código nuevo debe tener tests.
40
-
41
- ### Releases o Nuevas versiones
42
- - Usar `/gem-release` para publicar nuevas versiones.
43
- - El GitHub Action publica a RubyGems automáticamente al pushear un tag `v*`.
44
-
45
- ---
46
-
47
- ## Arquitectura & Componentes
48
-
49
- ### Core
50
- - **`ExisRay::Tracer`** — Contexto de trazabilidad distribuida (AWS X-Ray). Extiende `ActiveSupport::CurrentAttributes` para thread-safety. Campos: `trace_id`, `root_id`, `self_id`, `source`, `created_at`, `request_id`, `sidekiq_job`, `task`.
51
- - **`ExisRay::JsonFormatter`** — Formateador global. Acepta Hash, KV strings (`key=value`) y texto libre. Inyecta automáticamente el contexto del Tracer y del Current en cada línea. Castea valores numéricos y filtra claves sensibles.
52
- - **`ExisRay::Current`** — Contexto de negocio (user_id, isp_id, correlation_id). Clase abstracta — la app host la subclasifica.
53
- - **`ExisRay::Reporter`** — Wrapper de Sentry. Clase abstracta — la app host la subclasifica.
54
- - **`ExisRay::Configuration`** — Configuración global con defaults para AWS X-Ray.
55
-
56
- ### Integraciones HTTP
57
- - **`ExisRay::HttpMiddleware`** — Rack middleware. Hidrata el Tracer con el header entrante. Se inserta automáticamente después de `ActionDispatch::RequestId`.
58
- - **`ExisRay::LogSubscriber`** — Logger nativo de requests HTTP. Reemplaza Lograge. Solo activo con `json_logs: true`.
59
- - **`ExisRay::FaradayMiddleware`** — Inyecta `propagation_trace_header` en requests salientes via Faraday.
60
- - **`ExisRay::ActiveResourceInstrumentation`** — Ídem para ActiveResource.
61
-
62
- ### Integraciones Sidekiq
63
- - **`ExisRay::Sidekiq::ClientMiddleware`** — Inyecta `exis_ray_trace` en el payload del job antes de encolarlo.
64
- - **`ExisRay::Sidekiq::ServerMiddleware`** — Hidrata el Tracer al inicio de cada job. Genera root_id nuevo si el job no trae trace.
65
-
66
- ### Integraciones BugBunny (RabbitMQ)
67
- - **`ExisRay::BugBunny::PublisherTracing`** — Middleware para `BugBunny::Client`/`BugBunny::Resource`. Inyecta `propagation_trace_header` en cada mensaje publicado.
68
- - **`ExisRay::BugBunny::ConsumerTracingMiddleware`** — Consumer middleware. Corre antes de todos los logs internos de BugBunny. Hidrata el Tracer desde el header AMQP entrante o genera root_id nuevo.
69
- - **Railtie hooks** — `rpc_reply_headers` inyecta el trace actualizado en el reply del consumer. `on_rpc_reply` hidrata el Tracer en el thread del publisher al recibir la respuesta.
70
-
71
- ### Procesos en Background
72
- - **`ExisRay::TaskMonitor`** — Lifecycle manager para Rake/Cron. Genera root_id, loguea `task_started`/`task_finished` con `duration_s` y `status`.
73
-
74
- ---
75
-
76
- ## Métodos Clave
77
-
78
- ```ruby
79
- # Hidratar el Tracer (HTTP, Sidekiq, BugBunny consumer)
80
- ExisRay::Tracer.hydrate(trace_id: header_string, source: 'http')
81
-
82
- # Sincronizar correlation_id al Current configurado
83
- ExisRay.sync_correlation_id
84
-
85
- # Generar header de propagación para el siguiente servicio
86
- ExisRay::Tracer.generate_trace_header
87
- # => "Root=1-abc123-...;Self=...;CalledFrom=wispro_agent;TotalTimeSoFar=42ms"
88
-
89
- # Acceder a la configuración
90
- ExisRay.configuration.propagation_trace_header # => 'X-Amzn-Trace-Id'
91
- ExisRay.configuration.json_logs? # => true/false
92
- ```
93
-
94
- ---
95
-
96
- ## Campos Auto-Inyectados
97
-
98
- `JsonFormatter` inyecta estos campos automáticamente. **Nunca** incluirlos manualmente en logs:
99
-
100
- | Campo | Condición |
101
- |:------|:----------|
102
- | `time` | Siempre |
103
- | `level` | Siempre |
104
- | `severity_number` | Siempre (OTel: DEBUG=5, INFO=9, WARN=13, ERROR=17, FATAL=21) |
105
- | `service` | Siempre |
106
- | `service_version` | Siempre (de `config.version` o `config.x.version`) |
107
- | `deployment_environment` | Siempre (de `Rails.env`) |
108
- | `request_id` | Cuando `Tracer.request_id` está presente (independiente de root_id) |
109
- | `root_id` | Cuando hay trace context activo |
110
- | `trace_id` | Cuando hay trace context activo |
111
- | `source` | Cuando hay trace context activo (HTTP siempre genera root fresco si no llega header) |
112
- | `correlation_id` | Cuando `Current.correlation_id` está presente |
113
- | `user_id` | Cuando `Current.user_id` está presente |
114
- | `isp_id` | Cuando `Current.isp_id` está presente |
115
- | `Current.log_fields` (cualquier key) | Si la subclass overrideó el hook (default `{}`) |
116
- | `sidekiq_job` | Solo en procesos Sidekiq |
117
- | `task` | Solo en procesos TaskMonitor |
118
- | `tags` | Solo si hay Rails tagged logging activo |
119
-
120
- ---
121
-
122
- ## Reglas de Ejecución
123
-
124
- ### Logging
125
- - Todo log interno usa KV strings: `component=exis_ray event=algo`
126
- - `component` siempre en `snake_case`
127
- - DEBUG siempre en block form: `logger.debug { "k=#{v}" }`
128
- - Nunca `Kernel#warn` ni `$stderr`
129
- - Toda operación de logging envuelta en `rescue StandardError`
130
- - Duraciones con `Process.clock_gettime(Process::CLOCK_MONOTONIC)`, nunca `Time.now`
131
-
132
- ### Seguridad
133
- - Claves sensibles (`password|pass|passwd|secret|token|api_key|auth`) → `[FILTERED]`
134
- - Nunca loguear PII. Solo `user_id`, `isp_id`
135
-
136
- ### Source válidos
137
- `http` | `sidekiq` | `task` | `system`
138
-
139
- ### Propagación de headers
140
- - **Entrante HTTP:** `trace_header` (formato Rack: `HTTP_X_AMZN_TRACE_ID`) — solo en `HttpMiddleware`
141
- - **Saliente (todos los transportes):** `propagation_trace_header` (formato HTTP: `X-Amzn-Trace-Id`)
142
-
143
- ### Prohibiciones
144
- - No Lograge — reemplazado por `LogSubscriber`
145
- - No loguear manualmente: `time`, `level`, `service`, `source`, `root_id`, `trace_id`, `correlation_id`, `sidekiq_job`, `task`
146
- - No referenciar `.gemini/` — obsoleto
147
-
148
- ---
149
-
150
- ## Compatibilidad Rails
151
-
152
- - **Reloading:** Usar `cache_classes?` helper (verifica `respond_to?(:enable_reloading)`) para Rails 7.1+
153
- - **Notifications:** Rails 7.1+ usa `all_listeners_for`, Rails 6/7.0 usa `listeners_for` — siempre usar `respond_to?` guards
154
- - **Soporte:** Rails 6, 7 y 8
155
-
156
- ---
157
-
158
- ## Integración Automática (Railtie)
159
-
160
- El `Railtie` en `after_initialize` detecta y auto-instrumenta sin intervención del desarrollador:
161
-
162
- | Gema detectada | Qué hace |
163
- |:---------------|:---------|
164
- | `BugBunny` | Registra `PublisherTracing` no — ese va en el cliente. Registra `ConsumerTracingMiddleware` y los hooks RPC |
165
- | `Sidekiq` | Registra client + server middleware |
166
- | `ActiveResource` | Prepend de `ActiveResourceInstrumentation` |
167
- | `Faraday` | Disponible como middleware opcional |
168
-
169
- ---
170
-
171
- ## Configuración Mínima
172
-
173
- ```ruby
174
- # config/initializers/exis_ray.rb
175
- ExisRay.configure do |config|
176
- config.log_format = :json # :text por defecto
177
- config.trace_header = 'HTTP_X_AMZN_TRACE_ID'
178
- config.propagation_trace_header = 'X-Amzn-Trace-Id'
179
- config.current_class = 'Current'
180
- config.reporter_class = 'Reporter'
181
- end
182
-
183
- # BugBunny publisher — debe agregarse manualmente al cliente
184
- BugBunny::Client.new(pool: pool) do |stack|
185
- stack.use ExisRay::BugBunny::PublisherTracing
186
- end
187
- ```
188
-
189
- ---
14
+ - No duplicar aquí reglas generales del repositorio.
15
+ - Si una regla aplica a cualquier agente, moverla a `AGENTS.md`.
data/README.md CHANGED
@@ -64,10 +64,13 @@ Artefactos de detalle (RFC-008 — el contrato y el significado viven acá; este
64
64
  |:-----|:----------|:-------|
65
65
  | Comportamiento | [`docs/behavior/behavior.md`](docs/behavior/behavior.md) — secuencias de hidratación de trace por entrypoint y emisión en logs | parcial, incremental por PR |
66
66
  | Glosario | [`docs/glossary/glossary.md`](docs/glossary/glossary.md) — lenguaje ubicuo (`root_id`, `trace_id`, `source`, `request_id`, `entrypoint`, ...) | sembrado inicial, acreta |
67
- | Datos | — | n/a (gema sin DB) |
68
- | Operaciones · Interfaz · Topología | | F2 `dev-structure`, no implementado |
67
+ | Configuración | [`docs/config/configuracion.md`](docs/config/configuracion.md) opciones de `ExisRay.configure`, `HOSTNAME` e inyecciones del Railtie al host | inventario base + enriquecimiento §f |
68
+ | Test | [`docs/test/testing.md`](docs/test/testing.md) suites RSpec, fixtures y coverage | piloto RFC-013 |
69
+ | Interfaz | [`docs/interface/interface.md`](docs/interface/interface.md) — superficie Ruby pública (símbolo · tipo · firma) | completa (consumer-facing) |
70
+ | Datos · Operaciones · Eventos · Consumidas | — | n/a (gema sin DB, no expone superficie propia ni consume servicios) |
71
+ | Topología · Release · Errores | — | pendiente (ver mapa de cobertura en `AGENTS.md`) |
69
72
 
70
- > **Coexistencia transitoria (RFC-008 §2):** las secciones _Cómo funciona_, _Campos auto-inyectados_ y _Referencia del Tracer_ de este README contienen contrato/arquitectura cuyo destino estructural (`docs/interface`, `docs/topology`) es **F2 no implementado**. Permanecen embebidas hasta que esas capas existan; el significado y las secuencias ya migraron a `docs/glossary` y `docs/behavior` y se referencian desde acá.
73
+ > **Nota:** las secciones _Cómo funciona_, _Campos auto-inyectados_ y _Referencia del Tracer_ de este README son material humano de onboarding; el contrato formal de la superficie pública vive en [`docs/interface`](docs/interface/interface.md), el significado y las secuencias en `docs/glossary` y `docs/behavior`.
71
74
 
72
75
  ## Instalación
73
76
 
@@ -370,8 +373,9 @@ config.logger.formatter = ExisRay::JsonFormatter
370
373
  | `component` | String | Siempre `"exis_ray"` |
371
374
  | `event` | String | Siempre `"http_request"` |
372
375
  | `method` | String | Verbo HTTP |
373
- | `path` | String | URL concreta del request |
374
- | `http_route` | String | Template (ej: `/users/:id`). Baja cardinalidad para dashboards |
376
+ | `url.path` | String | URL concreta del request (OTel v1.0). Siempre presente |
377
+ | `path` | String | Alias legacy de `url.path`. Solo si `config.emit_legacy_path_key` (default `true`, deprecado) |
378
+ | `http_route` | String | Template (ej: `/users/:id`). Baja cardinalidad para dashboards. En endpoints sin params coincide en valor con `url.path` — la dupe es semánticamente esperada (concrete vs template) |
375
379
  | `format` | Symbol/String | `html`, `json`, etc. |
376
380
  | `controller` | String | Class name del controller |
377
381
  | `action` | String | Nombre del action |
@@ -382,11 +386,37 @@ config.logger.formatter = ExisRay::JsonFormatter
382
386
  | `db_runtime_s` | Float\|nil | Solo si ActiveRecord lo reporta |
383
387
  | `user_agent_original` | String | Header `User-Agent` |
384
388
  | `server_address` | String | Hostname sin puerto del header `Host` |
385
- | `error_class`, `error_message` | String | Solo en fallo (legacy) |
389
+ | `error_class`, `error_message` | String | Solo en fallo y si `config.emit_legacy_exception_keys` (default `true`, deprecadas) |
386
390
  | `exception.type`, `exception.message`, `exception.stacktrace` | String | Solo en fallo (OTel; stack limitado a 20 líneas) |
387
391
 
388
392
  Severity del log: `ERROR` si `http_status >= 500`, sino `INFO`.
389
393
 
394
+ ### Migración OTel — `error_class`/`error_message` → `exception.*`
395
+
396
+ Durante la ventana de transición OTel v1.0, `LogSubscriber` y `TaskMonitor` emiten ambos sets de keys en cada log de error. Cuando todos los consumers (dashboards, queries, alertas) hayan migrado a `exception.type`/`exception.message`/`exception.stacktrace`, desactivar los legacy:
397
+
398
+ ```ruby
399
+ ExisRay.configure do |c|
400
+ c.emit_legacy_exception_keys = false # default: true
401
+ end
402
+ ```
403
+
404
+ Roadmap: default `false` en v0.12.0; flag y legacy keys removidos en v1.0.
405
+
406
+ ### Migración OTel — `path` → `url.path`
407
+
408
+ `LogSubscriber` emite `url.path` (nombre OTel v1.0) en todos los logs HTTP. Durante la ventana de transición emite también `path` (alias legacy Wispro). Cuando las queries/dashboards/alertas migren a `url.path`, desactivar el legacy:
409
+
410
+ ```ruby
411
+ ExisRay.configure do |c|
412
+ c.emit_legacy_path_key = false # default: true
413
+ end
414
+ ```
415
+
416
+ Roadmap: default `false` en v0.12.0; flag y key `path` removidos en v1.0.
417
+
418
+ > **Sobre `url.path` vs `http_route`:** son semánticamente distintos — `url.path` es la URL **concreta** (alta cardinalidad, ej. `/users/42`), `http_route` es el **template** matcheado (baja cardinalidad, ej. `/users/:id`). En endpoints sin params coinciden en valor (ej. `/up`), pero ambos se siguen emitiendo porque cumplen roles distintos en dashboards/queries downstream. La dupe en valor es esperada, no es un bug.
419
+
390
420
  ### Filtrado de claves sensibles
391
421
 
392
422
  Las claves que matcheen `/password|pass|passwd|secret|token|api_key|auth/i` se reemplazan automáticamente por `[FILTERED]`, tanto en strings KV como en Hashes (incluyendo anidados).