π€ From Claude:
One admin save that touches several records produces several unrelated events. ahoy_events has visit_id, but that's a session, not an action β there is no way to say "these five changes were one save."
A timeline that wants to render "Mae updated this registration" instead of five separate rows needs that grouping, and so does any "undo this action" or "what did that save actually do" view.
Why now rather than later
The column is cheap. The data is not backfillable β every event written before the id exists is permanently ungroupable. This is the same argument that made the capture fixes in #2245 urgent: nothing is lost by shipping the reader later, everything is lost by shipping the writer later.
Sketch
- A per-request uuid (
ApplicationController sets it alongside Current.user), stamped into properties by Analytics::EventBuilder.lifecycle and promoted to a column by the same before_validation hook in config/initializers/ahoy.rb that already promotes resource_type / resource_id.
- Index it, so grouping is a lookup rather than a scan.
- Jobs and rake tasks get their own id per run, which also gives "what did that job change" for free.
Acceptance
- Two records changed in one request share an id; the same records changed in two requests don't.
- The id is queryable as a column, not only inside the JSON payload.
Related: #2351 (many writes produce no event at all β worth fixing first, since an id on nothing is still nothing).
π€ From Claude:
One admin save that touches several records produces several unrelated events.
ahoy_eventshasvisit_id, but that's a session, not an action β there is no way to say "these five changes were one save."A timeline that wants to render "Mae updated this registration" instead of five separate rows needs that grouping, and so does any "undo this action" or "what did that save actually do" view.
Why now rather than later
The column is cheap. The data is not backfillable β every event written before the id exists is permanently ungroupable. This is the same argument that made the capture fixes in #2245 urgent: nothing is lost by shipping the reader later, everything is lost by shipping the writer later.
Sketch
ApplicationControllersets it alongsideCurrent.user), stamped intopropertiesbyAnalytics::EventBuilder.lifecycleand promoted to a column by the samebefore_validationhook inconfig/initializers/ahoy.rbthat already promotesresource_type/resource_id.Acceptance
Related: #2351 (many writes produce no event at all β worth fixing first, since an id on nothing is still nothing).