rails_mind 0.1.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '087e7d8cc40b60a6ed2ab02feb5ffac9f7a6f1592eac30c964b792482630349f'
4
- data.tar.gz: 1f073cdb04f317e08a486b14361f12faf84ebfdd0c785c075436896eecbc720c
3
+ metadata.gz: 819a570e3f4f65e0fb8bae7de68b1a81ee744bccb77349858c640fcc912e95b4
4
+ data.tar.gz: 62df4fca70603e28458d277dcd8d734a5de04af7c514f997e15686122a02dbd2
5
5
  SHA512:
6
- metadata.gz: 95b65914e0d950384712582cb3f4b294e4a04a99ec62c42db53fe2252424932879940997815e7bc3fdaab51689866376cf42a9a3bafb107e2c66e9d335d38adc
7
- data.tar.gz: 848479498910d94b0f73529eacddb16639f8364585dfef7687d4711229a560e6b1a0e25b5654506d69650ff136acb14f5416883b74a44d694708374c875fdd5b
6
+ metadata.gz: 3583084684b6ac4b165864c14fbfe3922fc2f678c8d7aa9383418d95fdc528083bbe2327e5428d167d80e54a28445309eb6243bd3c6c3dac36fc8a67fa9e0630
7
+ data.tar.gz: e968233e4025ce470a83207214ef886032bff662faea00f824f3aceefad55319aa6d3235b62cc16368c5b8ccec7db86a6914ce1d5cb1a5db2c9bb282a543f0f2
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.0 — 2026-10-10
4
+
5
+ - Enable bounded automatic endpoint sampling for routine successful requests, driven by expiring hosted policies. Preserve slow, failed, repeated-query requests and all other signal kinds from SDK sampling.
6
+ - Report eligible request selection and queue losses with immutable IDs and independent acknowledgments, including report-only batches at zero sampling rates. Keep old-server event delivery compatible until a v1 handshake.
7
+ - Add explicit local opt-out, effective request metadata, bounded control parsing, fork resets, and sampling diagnostics. Local opt-out does not disable server-side sampling or quotas.
8
+ - Separate known local drops from unconfirmed delivery; failed responses may follow partial server acceptance.
9
+
10
+ ## 0.2.0 — 2026-10-09
11
+
12
+ - Correlate requests, serialized ActiveJob executions, and mailer attempts with native trace IDs while preserving existing OpenTelemetry context.
13
+ - Observe job enqueue/start, retry/discard, and completion without changing existing job-count semantics; distinguish total queue delay from delay after a scheduled job becomes eligible.
14
+ - Observe Action Mailer processing, ordinary/forced delivery attempts, disabled delivery, callback aborts, and exposed failures. Collect only bounded lifecycle metadata, excluding recipients, subjects, message bodies, attachments, and arguments. Recipient delivery remains unknown.
15
+ - Connect Claude Code and Codex with `rails_mind:agent`, including a write-free preview, preserved existing configuration, and shared agent instructions.
16
+ - Choose an environment-variable API token or a local Rails encrypted-credentials helper; check readiness without displaying the token.
17
+ - Document the full agent handoff: read findings, follow a brief, report a PR, and watch deployment and recurrence in RailsMind.
18
+
3
19
  ## 0.1.0 — 2026-09-25
4
20
 
5
21
  Initial public release of the RailsMind client under the MIT license.
data/CONTRIBUTING.md CHANGED
@@ -6,7 +6,7 @@ sample are maintained separately and remain proprietary.
6
6
 
7
7
  ## Setup
8
8
 
9
- Use Ruby 4.0.6 and Node 22 for the currently verified combination.
9
+ CI uses Ruby 4.0.6 and Node 22. Native workflow tests have also been run locally on Ruby 4.0.7; use the committed lockfile.
10
10
 
11
11
  ```sh
12
12
  git clone https://github.com/cmartyn/rails_mind.git
@@ -37,7 +37,7 @@ read this public repository.
37
37
  ## Packaging and releases
38
38
 
39
39
  `bundle exec ruby script/package_smoke.rb` builds a temporary gem and exercises its
40
- packaged installer and browser files. `bundle exec rake build` writes the gem to
40
+ packaged installer, browser files, and native workflow integrations. `bundle exec rake build` writes the gem to
41
41
  `pkg/`. Neither command publishes anything.
42
42
 
43
43
  Publishing uses [RubyGems trusted publishing](https://guides.rubygems.org/trusted-publishing/)
@@ -66,8 +66,8 @@ customer application.
66
66
  Create an annotated tag matching the gem version and push it:
67
67
 
68
68
  ```sh
69
- git tag -a v0.1.0 -m "Release rails_mind 0.1.0"
70
- git push origin v0.1.0
69
+ git tag -a v0.2.0 -m "Release rails_mind 0.2.0"
70
+ git push origin v0.2.0
71
71
  ```
72
72
 
73
73
  The workflow verifies the tag/version, reruns the Ruby, JavaScript, and package
data/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # RailsMind SDK
2
2
 
3
3
  The MIT-licensed Ruby client for [RailsMind](https://railsmind.com). One bounded
4
- collector for Rails requests, errors, jobs, Ahoy events, Flipper observations,
5
- and selected OpenTelemetry spans. Version 0.1.0 is an early release; see
4
+ collector for Rails requests, errors, jobs, mailer attempts, Ahoy events, Flipper
5
+ observations, and selected OpenTelemetry spans. Version 0.3.0 is an early release; see
6
6
  [compatibility and validation limits](docs/compatibility.md).
7
7
 
8
8
  ```ruby
9
- gem "rails_mind", "~> 0.1.0"
9
+ gem "rails_mind", "~> 0.3.0"
10
10
  ```
11
11
 
12
12
  Install from RubyGems.org and commit your application's `Gemfile.lock` to pin the
@@ -44,8 +44,19 @@ RailsMind.with_context(user_id: current_user.id.to_s, account_id: current_accoun
44
44
  end
45
45
  ```
46
46
 
47
+ Requests, ActiveJob executions, and Action Mailer attempts share native trace
48
+ context without requiring OpenTelemetry. Existing OpenTelemetry context stays
49
+ authoritative. Mail observations contain class/action, timing, and attempt
50
+ metadata, never recipients or rendered content; an attempt is not proof of inbox
51
+ delivery. See [workflow observations](docs/sdk.md#jobs-and-mailer-workflows).
52
+
47
53
  See [installation and privacy](docs/sdk.md) and [compatibility](docs/compatibility.md).
48
54
 
55
+ Connect Claude Code or Codex with `bin/rails generate rails_mind:agent --plan`.
56
+ Choose an environment-variable API token or Rails encrypted credentials, then
57
+ follow the [agent setup guide](docs/agents.md) from first connection to a reported
58
+ PR and deployment confirmation. Requires rails_mind 0.2.0 or later.
59
+
49
60
  Tests:
50
61
 
51
62
  ```sh
@@ -56,4 +67,4 @@ bundle exec ruby script/package_smoke.rb
56
67
  ruby script_benchmark.rb
57
68
  ```
58
69
 
59
- Business/request/error events are unsampled, but delivery is best effort. Check `RailsMind.stats` for losses. The SDK does not guarantee durable business-event counts; use a transactional outbox when that is required.
70
+ Automatic endpoint sampling is enabled by default. The hosted policy can reduce routine successful requests while preserving failed, slow, or repeated-query requests and all other signal kinds from sampling. Business/error events remain unsampled; bounded queues and delivery are still best effort. See [sampling and coverage](docs/sdk.md#automatic-endpoint-sampling) and inspect `RailsMind.stats`. Use a transactional outbox when durable business-event delivery is required.
data/docs/agents.md ADDED
@@ -0,0 +1,212 @@
1
+ # Bring your agent aboard
2
+
3
+ RailsMind watches your Rails app. Your coding agent works in the repository you
4
+ already use. Connect them once, then move from a finding to a reviewed fix without
5
+ copying evidence between windows.
6
+
7
+ ```text
8
+ RailsMind spots a problem → your agent proposes a PR → you review and ship
9
+ ↓
10
+ RailsMind watches the deployed fix
11
+ ```
12
+
13
+ Available in rails_mind 0.2.0. The hosted service must support `report_fix` before
14
+ agents can report PRs. Setup is deterministic: it makes no model calls, starts no
15
+ investigation, and does not merge or deploy anything.
16
+
17
+ ## 1. Preview the agent link
18
+
19
+ From your Rails application's checkout:
20
+
21
+ ```sh
22
+ bin/rails generate rails_mind:agent --plan
23
+ bin/rails generate rails_mind:agent
24
+ ```
25
+
26
+ You'll see three stages:
27
+
28
+ ```text
29
+ RailsMind · Agent link
30
+ 1 / 3 · Configure the connection (env)
31
+ 2 / 3 · Give your agent the flight plan
32
+ 3 / 3 · Awaiting your signal
33
+ ```
34
+
35
+ The first command writes nothing. The second adds a Claude Code `.mcp.json` entry
36
+ and a marked RailsMind section in `AGENTS.md`. When an existing `CLAUDE.md` needs
37
+ an import, it adds one with the correct relative path. Codex configuration is
38
+ printed for you to review and add; the installer never changes global settings.
39
+ Other MCP servers and existing RailsMind entries are preserved, even with
40
+ `--force`. A skipped entry means you may need the proposed manual change shown
41
+ in the output. Review the diff before committing it.
42
+
43
+ The installer uses `https://railsmind.com`; `RAILS_MIND_ENDPOINT` can select another
44
+ hosted installation. It does not create a local MCP server.
45
+
46
+ ## 2. Choose where the API token lives
47
+
48
+ Create a **read,write API token** under RailsMind **Settings → API tokens**. An
49
+ owner or admin creates it; it acts with that person's current organization role.
50
+ A read-only token can explore findings but cannot report fixes. Tokens can be
51
+ revoked on the same page.
52
+
53
+ `RAILS_MIND_KEY` is your environment's **telemetry ingestion key**. It cannot read
54
+ findings or authenticate an agent. The agent uses a separate `rmt_…` API token.
55
+
56
+ ### Environment variable (default)
57
+
58
+ Make `RAILSMIND_API_TOKEN` available to the process running your agent. Keep the
59
+ real value in your local secret settings, outside version control. For Claude
60
+ Code GUI/IDE sessions, its user settings support an `env` entry; a shell export
61
+ alone may not reach an app opened from the desktop.
62
+
63
+ The generated `.mcp.json` contains a variable reference, never the value. A
64
+ project entry can take precedence over an existing user-level entry, so prepare
65
+ the variable before enabling it.
66
+
67
+ For local Codex CLI, IDE and desktop sessions, add the printed configuration to
68
+ `~/.codex/config.toml` (or `$CODEX_HOME/config.toml`):
69
+
70
+ ```toml
71
+ [mcp_servers.railsmind]
72
+ url = "https://railsmind.com/mcp"
73
+ bearer_token_env_var = "RAILSMIND_API_TOKEN"
74
+ ```
75
+
76
+ This one entry can serve multiple repositories in the same RailsMind organization.
77
+
78
+ ### Rails encrypted credentials
79
+
80
+ Prefer to keep this app's API token with its other Rails secrets?
81
+
82
+ ```sh
83
+ bin/rails generate rails_mind:agent --auth=credentials --plan
84
+ bin/rails generate rails_mind:agent --auth=credentials
85
+ bin/rails credentials:edit --environment development
86
+ ```
87
+
88
+ Add through the credentials editor:
89
+
90
+ ```yaml
91
+ rails_mind:
92
+ api_token: rmt_your_token_here
93
+ ```
94
+
95
+ The encrypted file can be committed. Its matching decryption key must remain
96
+ local and ignored by Git. Anyone able to decrypt this credential set can use the
97
+ saved token; choose personal environment-variable tokens when each developer
98
+ needs separate attribution or revocation.
99
+
100
+ Credentials mode generates `bin/rails_mind_mcp_headers`. Claude Code's
101
+ `headersHelper` and Codex's `http_headers_helper` call it to obtain authentication
102
+ headers at connection time. Ruby and the installed bundle must be available to
103
+ the agent. No Rails application boot, database connection or telemetry collection
104
+ is needed. Run this safe readiness check:
105
+
106
+ ```sh
107
+ bin/rails_mind_mcp_headers --environment development --check
108
+ ```
109
+
110
+ It reports readiness without printing the token, and does **not** test network
111
+ access. Without `--check`, stdout contains secret-bearing headers intended only
112
+ for the MCP client. Never paste that output into a chat or issue.
113
+
114
+ By default the helper selects development credentials, falling back to the shared
115
+ Rails credentials file with Rails' normal key-file selection. Choose another
116
+ local credential environment with `--credentials-environment=NAME` on the
117
+ generator. This is separate from the production environment you inspect in
118
+ RailsMind. Initializer-defined custom credential paths are not discovered because
119
+ the app is not booted; pass `--content-path PATH --key-path PATH` in both agents'
120
+ helper commands if needed. Relative paths resolve against the application root.
121
+
122
+ A nonblank `RAILSMIND_API_TOKEN` overrides credentials **when the helper receives
123
+ it**. Claude project helpers may remove credential-named environment variables,
124
+ including that token and `RAILS_MASTER_KEY`; use a local Rails key file in that
125
+ setup. A bad key, missing token or invalid encrypted file produces an error with
126
+ no secret values.
127
+
128
+ For Codex credentials mode, add the printed absolute-path helper command to this
129
+ trusted project's `.codex/config.toml`. Do not put one app's helper in a global
130
+ entry used by unrelated apps. Update the path for a different checkout/worktree.
131
+ Replace an existing bearer-token/static-header setting for that entry; existing
132
+ OAuth authentication can also take precedence. The installer preserves existing
133
+ configuration and shows the replacement to review when switching modes.
134
+
135
+ ## 3. Make contact
136
+
137
+ Restart your agent, trust this checkout, and approve its RailsMind connection.
138
+ Then ask:
139
+
140
+ > List my RailsMind applications and show open findings for this repository.
141
+ > Do not change code yet.
142
+
143
+ Check that the agent selected the correct application and environment. Seeing
144
+ those results confirms access; “configuration prepared” alone does not. If a
145
+ parent `CLAUDE.md`, `AGENTS.override.md`, or managed policy hides this project's
146
+ instructions, import the generated `AGENTS.md` in the effective instruction file.
147
+
148
+ GitHub access is a separate link. Connect the RailsMind GitHub App on the app's
149
+ **Setup** page to attach source to findings and verify PR deployment. The agent
150
+ still uses its own repository/GitHub access to open a PR.
151
+
152
+ ## 4. Give it a finding
153
+
154
+ > Investigate finding 123 for this application in production. Fetch its RailsMind
155
+ > fix brief, reproduce the issue, test a narrow fix, and open a PR. Report the PR
156
+ > to RailsMind with report_fix. Leave merging and deployment to me.
157
+
158
+ The brief contains the evidence and definition of done. Captured application
159
+ data is evidence, not instructions. The agent should explain its changes, tests,
160
+ and whether its report succeeded. If it cannot safely reproduce the issue, it
161
+ should tell you what's missing. If reporting fails, the PR remains useful: retry
162
+ `report_fix` with the finding and PR links rather than marking the finding resolved.
163
+
164
+ ## 5. Watch the fix
165
+
166
+ | What RailsMind shows | What it means |
167
+ | --- | --- |
168
+ | Fix proposed | The agent reported a PR; the finding stays open. |
169
+ | Merged · awaiting release | GitHub says the PR merged; no containing release has been confirmed yet. |
170
+ | Deployed · watching | Telemetry identifies a Git SHA release containing the merge commit. |
171
+ | Resolved · fix observed | The configured quiet period passed after deployment without matching evidence. |
172
+ | Recurred after fix | Matching evidence returned on the deployed/later observed release, or after deployment when a release ID was absent. |
173
+ | PR closed without merging | Report a replacement PR to start another attempt. |
174
+
175
+ Deployment checks require GitHub **Pull requests: read**, **Contents: read**, and
176
+ Git SHA release metadata. RailsMind retries failed checks and displays the reason
177
+ it cannot confirm deployment. Without confirmation the existing quiet-resolution
178
+ rule can still close a finding as **quiet**, which is distinct from **fixed**.
179
+ Quiet telemetry is not proof that every affected path ran; SDK delivery is best
180
+ effort. Release-regression recurrence tracking is not included in this version.
181
+ Reporting the same PR again updates the note without erasing progress. A different
182
+ PR replaces the current attempt. RailsMind does not merge or deploy it.
183
+
184
+ ## When a link needs attention
185
+
186
+ | Symptom | Next step |
187
+ | --- | --- |
188
+ | Server absent | Restart the agent; check project trust, config placement and organization MCP policy. |
189
+ | Missing variable or 401 | Set the API token in the agent process, check revocation and restart. Check whether a project entry overrides an older working entry. |
190
+ | Credential check fails | Confirm the selected file, matching local key and `rails_mind.api_token`. Use `--check`, never paste header output. |
191
+ | Ruby/Bundler not found | Make the app's Ruby and installed bundle available in the agent runtime. |
192
+ | Reads work, report is forbidden | Use read,write scope and a contributing organization role. |
193
+ | report_fix is unknown | The hosted RailsMind deployment needs the agent-loop update. Keep the PR and report it after that update. |
194
+ | PR reported but deployment pending | Check the finding's reason, GitHub permissions, merge state, and release SHA detection. |
195
+ | Another checkout fails | Correct the helper's absolute path and provide that checkout's ignored key file. |
196
+
197
+ ## Supported surfaces and verification limits
198
+
199
+ This integration targets local Claude Code and Codex CLI, IDE and desktop
200
+ sessions using their documented HTTP MCP configurations. Helper configuration
201
+ requires a client version that supports it; use environment-variable mode if it
202
+ doesn't. Neither the local generator nor passing unit tests certifies a particular
203
+ agent installation. Verify the read-only “Make contact” step in each setup.
204
+
205
+ Hosted/cloud and remote executor sessions do not automatically inherit local
206
+ config, Ruby, credentials or keys. Codex documents helpers only for local HTTP
207
+ connections. Use the hosted surface's supported connector/authentication setup;
208
+ do not upload a production Rails decryption key just to make an agent connection.
209
+
210
+ References: [Claude Code MCP](https://code.claude.com/docs/en/mcp),
211
+ [Codex MCP](https://learn.chatgpt.com/docs/extend/mcp), and
212
+ [Rails credentials](https://guides.rubyonrails.org/security.html#custom-credentials).
@@ -38,9 +38,9 @@ node --test javascript/rails_mind.test.js
38
38
  bundle exec ruby script/package_smoke.rb
39
39
  ```
40
40
 
41
- CI runs Ruby 4.0.6 / Rails 8.1.3.1 on Linux, plus browser adapter contract tests
41
+ CI runs Ruby 4.0.6 / the locked Rails 8.1.4 dependencies on Linux, plus browser adapter contract tests
42
42
  on Node 22. The package smoke check builds and installs a gem in a temporary directory, loads that copy,
43
- and runs the installer against its packaged templates and browser adapter.
43
+ and runs the installer and native workflow tests against its packaged files.
44
44
  The sample app remains in the hosted application's repository with its own lockfile.
45
45
 
46
46
  ## 0.1.0 release verification
@@ -64,3 +64,49 @@ and Node 22:
64
64
  These checks cover the client package and its documented integrations locally.
65
65
  They do not certify other browsers, every allowed Ruby/Rails combination,
66
66
  production delivery guarantees, or a deployed customer application's setup.
67
+
68
+ ## 0.2.0 agent setup verification
69
+
70
+ The agent generator and encrypted-credentials helper are tested with Ruby 4.0.7
71
+ and Rails/Active Support 8.1.3.1. Tests cover preview/repeatability, preservation of
72
+ existing MCP and instruction files, shared and environment-specific credentials,
73
+ custom paths, safe diagnostics, environment-variable precedence, and packaged
74
+ files. The helper loads Active Support without initializing the application.
75
+
76
+ Client configuration uses the documented Claude Code `headersHelper` and Codex
77
+ `http_headers_helper` interfaces. These tests do not certify every desktop, IDE,
78
+ cloud or older client version; verify read access in your agent after setup. See
79
+ [agent setup and limitations](agents.md#supported-surfaces-and-verification-limits).
80
+
81
+ ## 0.2.0 workflow observation verification
82
+
83
+ The native context, ActiveJob, and Action Mailer tests run with Ruby 4.0.7,
84
+ Rails/ActiveJob/ActionMailer 8.1.4, and Mail 2.9.1. They cover serialized jobs,
85
+ retries/discards, enqueue aborts/errors, schedule-aware delay, context restoration,
86
+ ordinary/forced mail, disabled transport, hidden/raised transport errors, callback
87
+ aborts/failures, lazy rendering, repeated attempts, existing OpenTelemetry, and
88
+ collector failures. Auxiliary mail sent inside callbacks does not inherit the
89
+ forced ActionMailer attempt. Tests use an in-memory collector and test/failing
90
+ transports; they do not send external email.
91
+
92
+ Older gem-permitted Rails versions remain uncertified. Provider acceptance,
93
+ recipient inbox delivery, direct backend jobs, direct provider HTTP sends, and
94
+ durable workflow completeness are outside this contract. Validate the released
95
+ SDK against your app's queue, callback ordering, and delivery adapter. The hosted
96
+ service exposes bounded workflow metadata and leaves recipient delivery unknown.
97
+
98
+ ## 0.3.0 endpoint sampling verification
99
+
100
+ The Ruby suite passes locally with Ruby 4.0.7 and the locked Rails 8.1.4
101
+ libraries: 105 tests and 1,311 assertions, with no failures or skips. The three
102
+ Node browser-adapter contract tests also pass. These are isolated SDK/library
103
+ tests; they do not boot a Rails application or use a database. CI separately
104
+ runs the packaged-gem installation smoke check on Ruby 4.0.6.
105
+
106
+ Coverage includes protected signals, deterministic shared selection, endpoint
107
+ rates, local opt-out, malformed/expired controls, monotonic expiry, queue loss,
108
+ immutable reports and acknowledgments, quota-response retries, old-server
109
+ fallback, idle zero-rate report refresh, streamed response bounds, batch byte
110
+ limits, and real process fork resets. Fake transports verify the wire contract;
111
+ deployed server policy behavior, cross-process traffic forecasts, and a
112
+ customer app's production overhead require hosted/staging validation.
data/docs/sdk.md CHANGED
@@ -3,13 +3,13 @@
3
3
  The gem is `rails_mind`, namespace `RailsMind`. Install the MIT-licensed client
4
4
  from RubyGems.org and commit the application lockfile to retain the selected
5
5
  version. The hosted RailsMind service is a separate, proprietary application.
6
- Version 0.1.0 is an early release with the [documented compatibility limits](compatibility.md).
6
+ Version 0.3.0 is an early release with the [documented compatibility limits](compatibility.md).
7
7
 
8
8
  ## Install
9
9
 
10
10
  ```ruby
11
11
  # Customer Gemfile
12
- gem "rails_mind", "~> 0.1.0"
12
+ gem "rails_mind", "~> 0.3.0"
13
13
  ```
14
14
 
15
15
  ```sh
@@ -131,7 +131,7 @@ RailsMind.capture_exception(error, handled: true)
131
131
 
132
132
  Context is fiber-local and restored around requests/jobs. `identify` replaces the three identity values, so call it with all available values; passing nil clears that value. Preserve Ahoy's visitor ID when a visitor logs in, and emit `$identify` through Ahoy authentication to connect later events. Account IDs represent the current tenant, never a guessed company from email. Logout/account switching must update identity; a new request starts clean. Historical anonymous events are not rewritten or merged across accounts by the SDK.
133
133
 
134
- ActiveJob serializes only the context identifier allowlist under `rails_mind_context`, then restores it while executing. Arguments are not inspected. This covers GoodJob through ActiveJob; direct Sidekiq jobs require a future explicit integration. Distributed trace propagation belongs to the existing OpenTelemetry library; choose ActiveJob `propagation_style: :child` for a linked trace tree when configuring a new provider.
134
+ ActiveJob serializes only the context identifier allowlist under `rails_mind_context`, then restores it while executing. Arguments are not inspected. This covers GoodJob through ActiveJob; direct Sidekiq jobs require a future explicit integration. Without OpenTelemetry, RailsMind creates a trace ID at a request, job, or mailer boundary and carries it across serialized ActiveJob context. An active OpenTelemetry span remains authoritative. Native IDs correlate observations; they do not invent a distributed parent/child span tree. Cross-service propagation belongs to the existing OpenTelemetry library; choose ActiveJob `propagation_style: :child` for a linked trace tree when configuring a new provider.
135
135
 
136
136
  ## Ahoy
137
137
 
@@ -180,9 +180,124 @@ RailsMind::Integrations::OpenTelemetry.attach!
180
180
 
181
181
  Attachment adds one idempotent processor; it does not replace the global provider, sampler, propagator, instrumentation, or other exporters. Its exporter only sanitizes and enqueues locally; the shared worker performs network I/O. Span context is attached at start so identity survives later export. Known safe attributes are allowlisted. Raw span names, exception span events, HTTP bodies/headers, SQL statements, and bind values are not exported to RailsMind. Existing third-party exporters retain their own behavior and privacy settings. [OpenTelemetry exporters](https://opentelemetry.io/docs/languages/ruby/exporters/).
182
182
 
183
- Request durations/counts and error reports come independently from Rails notifications/error reporting, even when detailed traces are sampled out. Request measurements cover controller actions, not assets/health checks rejected before ActionController or streaming-body completion. Repeated-query evidence contains only normalized-query hashes and counts; it is a suspicion, not proof of an N+1. Hash normalization handles common literals, not every SQL grammar. Use Bullet/Prosopite or an explicit query-bound test in development to verify fixes. No production object scans are installed.
183
+ Request measurements and error reports come independently from Rails notifications/error reporting, even when detailed traces are sampled out. Routine requests separately follow the automatic endpoint sampling policy described below. Request measurements cover controller actions, not assets/health checks rejected before ActionController or streaming-body completion. Repeated-query evidence contains only normalized-query hashes and counts; it is a suspicion, not proof of an N+1. Hash normalization handles common literals, not every SQL grammar. Use Bullet/Prosopite or an explicit query-bound test in development to verify fixes. No production object scans are installed.
184
+
185
+ Full metrics/logs SDK integration is deferred. Hosted request aggregates describe retained events; sampling can bias their distributions. The SDK does not capture application logs.
186
+
187
+ ## Automatic endpoint sampling
188
+
189
+ Version 0.3.0 enables automatic endpoint sampling by default. A compatible hosted
190
+ service supplies environment-wide endpoint rates based on its allowance policy.
191
+ The SDK applies them before queueing, reducing serialization, network, and retained
192
+ event volume. Each process uses the same policy and deterministic event-ID hash;
193
+ there are no independent per-process allowance grants. A server-side tightening
194
+ uses the same selection rule, so the two samplers do not multiply probabilities.
195
+
196
+ Only completed `request` events with status 200–399, a finite duration from zero
197
+ to below 1,000 ms, and fewer than three repeated queries are eligible. Slow,
198
+ failed, unknown-duration, and repeated-query requests remain unsampled, as do
199
+ business events, errors, jobs, mailer observations, visits, flags, checks, and
200
+ OpenTelemetry spans. This preserves their sampling priority, not guaranteed
201
+ delivery: queue bounds, payload limits, outages, and the server's hard daily quota
202
+ still apply. Existing OpenTelemetry samplers remain authoritative; this feature
203
+ does not promise complete distributed traces.
204
+
205
+ To turn off SDK request selection explicitly:
206
+
207
+ ```ruby
208
+ RailsMind.configure do |config|
209
+ config.automatic_sampling = false
210
+ end
211
+ ```
212
+
213
+ The SDK communicates this choice on policy and ingestion requests. The
214
+ environment owner's hosted setting separately controls server-side sampling;
215
+ local opt-out does **not** disable it or bypass the daily quota.
216
+
217
+ The background worker requests `/api/v1/sampling_policy` with the ingest key and
218
+ refreshes at most once per minute after its first request observation, including
219
+ when the current rate is zero. It also receives controls on successful ingestion
220
+ and quota responses. Missing, malformed, or expired policies fall back to rate 1;
221
+ this may exhaust the server allowance during an outage. Expiry uses wall and
222
+ monotonic clocks, with a maximum accepted lifetime of ten minutes. Before a valid
223
+ v1 handshake, old servers and custom transports receive ordinary event-only
224
+ batches and retain normal flush behavior. Forked workers reset queues, policies,
225
+ counters, and report IDs and fetch their own copy of the shared policy.
226
+
227
+ Retained request properties include SDK-owned `rails_mind_sampling` metadata:
228
+ `version`, `policy_id`, effective `rate`, and `state` (`active`, `unavailable`,
229
+ `expired`, `disabled`, or `protected`). This is the SDK selection decision, not
230
+ proof of server acceptance or a complete traffic denominator.
231
+
232
+ At most once per minute per process, the worker freezes an identified report of
233
+ routine eligible observations; an explicit flush may send it sooner. Reports
234
+ contain controller/action names and counts only: `observed`, `retained` (selected
235
+ for enqueue), `sampled_out`, and `queue_dropped` (a subset of retained). They never
236
+ contain event properties or user/account identifiers. Counts are observed after
237
+ validation, redaction, and `before_send`; hooks that suppress events, crashes,
238
+ protected requests, and unknown endpoint names are outside this denominator.
239
+ Retained counts are not accepted counts. The resulting request percentiles and
240
+ rates cannot be treated as an unbiased whole-traffic distribution.
241
+
242
+ Reports have immutable UUIDs/bodies and separate durable acknowledgments. They
243
+ can travel in `events: []` batches without consuming event quota, and an
244
+ acknowledged report does not establish delivery of its accompanying events.
245
+ Counters cover at most 100 endpoint names per window, reports share the normal
246
+ batch byte limit, and each process retains at most five unacknowledged reports.
247
+ Overflows or invalid clock windows mark coverage `limited`; reports older than
248
+ seven days are discarded. This is bounded in-memory observation, not a durable
249
+ request ledger. Unacknowledged reports after a confirmed handshake can cause
250
+ `RailsMind.flush` to return false at its deadline.
251
+
252
+ ## Jobs and mailer workflows
253
+
254
+ With `apm` enabled, the SDK automatically observes installed ActiveJob and Action
255
+ Mailer components. No SMTP-provider integration or OpenTelemetry setup is required.
256
+ It does not change the queue adapter, delivery provider, retry policy, or error
257
+ handling. Both integrations respect `RailsMind.suppress` and the normal collector
258
+ bounds. Request, job, and mailer identity/release context uses the existing core
259
+ fields; job arguments and email contents are never inspected for correlation.
260
+
261
+ The versioned property contract is `schema_version: 1` with `instrumentation`
262
+ equal to `active_job` or `action_mailer`:
263
+
264
+ | Component | Observations | Selected metadata |
265
+ | --- | --- | --- |
266
+ | ActiveJob | `enqueue`, `enqueue_at`, `perform_start`, `perform`, `enqueue_retry`, `retry_stopped`, `discard` | Class, queue, execution count, enqueue/schedule timestamps, queue delays |
267
+ | Action Mailer | `process`, `delivery_attempt_completed`, `delivery_not_observed` | Mailer/action, opaque attempt UUID when available, transport class, ordinary/forced invocation, delivery flags, exposed exception class |
268
+
269
+ New enqueue/start and mailer observations use `span`, so they do not inflate
270
+ business-event counts or the existing `job` execution/retry/discard feed. A
271
+ render-only mailer has a processing observation, not a delivery attempt. The
272
+ attempt UUID groups processing with its delivery invocation; retries create new
273
+ attempt UUIDs while the serialized job retains its correlation identifiers.
274
+
275
+ `queue_delay_ms` measures enqueue to execution start, including intentional
276
+ scheduling. `eligible_queue_delay_ms` subtracts intentional scheduling when the
277
+ required timestamps are available, with a zero floor. Missing timestamps remain
278
+ unknown. Retry handlers keep execution context after normal perform callbacks
279
+ unwind. These notifications are best-effort observations, not a durable queue
280
+ ledger: bulk/direct backend APIs may bypass them, and a missing completion does
281
+ not by itself prove a stuck job.
282
+
283
+ Mailer status describes local evidence. `observed` means the local call or
284
+ notification completed; `disabled` identifies ordinary delivery with
285
+ `perform_deliveries: false`; `error` requires an exposed exception. A callback
286
+ abort or other invocation that never reaches the transport is recorded as
287
+ `delivery_not_observed`, with `aborted`, `error`, or `unknown` as appropriate.
288
+ Forced delivery bypasses normal delivery flags and is observed separately.
289
+ Hidden transport failures (`raise_delivery_errors: false`) can still produce an
290
+ `observed` result. None of these establishes provider acceptance or inbox
291
+ arrival; recipient delivery remains unknown.
292
+
293
+ The SDK excludes recipients, sender addresses, subjects, bodies, attachments,
294
+ message IDs/headers, mailer/job arguments, credentials, and provider responses.
295
+ Only transport class names are selected, never transport settings. Rendering a
296
+ mailer and sending its content through a separate HTTP provider client produces
297
+ only the rendering evidence; add explicit reviewed app events or provider
298
+ callbacks if later delivery facts are needed. Keep real product outcomes such
299
+ as invitation acceptance separate, using explicit events after persistence.
184
300
 
185
- Jobs record duration, failure/retry/discard lifecycle, execution count, queue name, and enqueue-to-start delay where ActiveJob exposes it. Scheduled delay is included in the enqueue-to-start number. Signals do not include arguments. Full metrics/logs SDK integration is deferred; v0.1 computes hosted aggregates from unsampled request events and does not capture application logs.
186
301
 
187
302
  ## Flipper and browser behavior
188
303
 
@@ -200,16 +315,18 @@ Add `<meta name="rails-mind-page" content="Invoices#index">` to supply a stable
200
315
 
201
316
  ## Bounds, privacy, and outages
202
317
 
203
- Defaults are one lazy worker per process, 1,000 queued/in-flight events, 16 KiB per event, at most 100 events and 256 KiB per batch, and a two-second flush interval. Overflow drops the newest event. Retries retain the same encoded bytes/UUIDs; only HTTP 429, 5xx, and transient transport failures retry, at most three retries with bounded backoff. Other 4xx responses drop the batch. Redirects are not followed. Shutdown gets two seconds by default, then discards outstanding telemetry; forks start a fresh child queue rather than resending the parent's buffer.
318
+ Defaults are one lazy worker per process, 1,000 queued/in-flight events, 16 KiB per event, at most 100 events and 256 KiB per batch, and a two-second flush interval. Overflow drops the newest event. Retries retain the same encoded bytes/UUIDs; only HTTP 429, 5xx, and transient transport failures retry, at most three retries with bounded backoff. Other 4xx responses end delivery attempts. A failed response can follow partial server acceptance, so such events are classified as delivery unconfirmed. Redirects are not followed. Shutdown gets two seconds by default, then discards outstanding telemetry; forks start a fresh child queue rather than resending the parent's buffer.
204
319
 
205
320
  ```ruby
206
321
  RailsMind.stats
207
- # => { enqueued:, delivered:, dropped:, retried:, queued:, in_flight:,
208
- # losses: { "event.overflow" => 3, "error.delivery" => 1 } }
322
+ # => { enqueued:, delivered:, dropped:, delivery_unconfirmed:, retried:, queued:, in_flight:,
323
+ # losses: { "event.overflow" => 3, "error.delivery_unconfirmed" => 1 },
324
+ # sampling: { observed:, retained:, sampled_out:, queue_dropped:,
325
+ # unreported:, reports_lost:, pending_reports:, limited:, policy_state:, policy_id: } }
209
326
  RailsMind.flush(timeout: 2)
210
327
  ```
211
328
 
212
- These are per-process counters. The doctor prints them for its process; inspect running app stats through your existing operational tooling. The hosted app does not currently receive loss counters. Request/business/error signals are unsampled, but process crashes, rejected payloads, redaction hooks, exhausted retries, or queue pressure can still undercount. This is best-effort monitoring, not an accounting ledger. A future transactional outbox can provide durable business-event delivery; the current implementation does not claim that guarantee.
329
+ These are per-process counters. `dropped` counts known local discards, such as queue overflow or oversize payloads. `delivery_unconfirmed` counts events whose delivery attempts ended without a success response, including interrupted in-flight batches; some may have been accepted by the server. `delivered` counts submitted events in batches with a successful HTTP response; it does not prove server retention or background processing. The doctor prints stats for its process; inspect running app stats through your existing operational tooling. Only the routine-request report above sends queue-loss observations to the hosted app. All signal kinds can still undercount after crashes, rejected payloads, hooks, or outages. This is best-effort monitoring, not an accounting ledger; use a transactional outbox when durable business-event delivery is required.
213
330
 
214
331
  Redaction occurs before buffering and again after custom `before_send`. Sensitive property names are filtered, nesting/string/collection sizes are capped, emails and common credential forms are scrubbed, exception messages are omitted by default, and backtraces drop machine-home prefixes. Bodies, cookies, credentials, SQL binds, and job arguments are never selected by integrations. Arbitrary user-provided text may contain sensitive content that generic redaction cannot recognize: use small, explicitly reviewed business properties. Opting into exception messages requires reviewing `capture_exception_message` and your custom scrubbing policy.
215
332
 
@@ -223,3 +340,10 @@ This historical check used an internal sample application that is not included
223
340
  in the public client repository. To verify your own installation, follow
224
341
  [Verify the connection](#verify-the-connection). External hosted deployment and
225
342
  published-gem installation remain unverified by that historical check.
343
+
344
+ ## Connect your coding agent
345
+
346
+ Run `bin/rails generate rails_mind:agent --plan` to preview the connection setup.
347
+ The [agent guide](agents.md) covers Claude Code and Codex, environment-variable and
348
+ Rails credentials authentication, safe verification, and the complete fix journey.
349
+ The agent API token is separate from `RAILS_MIND_KEY`, the ingestion key above.