Repository navigation
✨ Persist tracking consent for crash recovery - #233
rgaignault wants to merge 6 commits into
Conversation
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
Stale comment
PR Review — Quality: 5.0 / 5 · Review load: Focused (~30min–1h)
Approve. Pending context stays in memory, refusal restores the last authorized snapshot, and a grant writes that history with the refused interval left empty. Existing session, view, and customer-context storage is unchanged on this branch.
Customer impact: Low —
DiskValueHistorystill records session, view, and customer context on every change. Nothing callsContextHistoryFactory, so this history is written only after a later change constructs it.
Concern Consent transitions, refusal rollback, and restart Risky Ordered JSON disk writes Routine Quality — 5.0: The transitions are correct: leaving
grantedcloses the active entry and snapshots it before a pending value is reopened in memory, and refusal puts that snapshot back. Tests match the risk — same-timestamp refusal and grant, restart with the previous process's value closed, collector ordering, and a serialization failure isolated to one history — andDiskStoragecovers ordered writes and a failed write. The architecture section states this contract. The design holds up: one factory subscription updates every history before later collectors run, which is the boundary session and view wiring can build on.Review load — Focused (~30min–1h): The risky read is the consent state machine and what survives refusal or restart. The disk queue is a short routine piece in the same style as
DiskValueHistory. Both sit in✨ Add consent-aware context history.Sent by Cursor Automation: electron-sdk reviews
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0e26c0c4b2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
PR Review — Quality: 5.0 / 5 · Review load: Focused (~30–45min)
This is a correct, well-tested slice, and I would merge it as-is. TrackingConsentHistory keeps undecided changes in memory, writes them on grant, and on refusal restores the last authorized snapshot, including the same-timestamp and previous-process cases. ContextHistoryFactory applies that transition for every history before a later subscriber runs. GitLab e2e and integration were still running when I posted. Approve.
Customer impact: Low — init still records session, view, and customer context through DiskValueHistory. These types affect disk and events only once a later change constructs ContextHistoryFactory.
| Concern | |
|---|---|
| Consent-aware context history (transitions, snapshot persistence, subscription order) | Risky |
Quality — 5.0: The transition rules match the consent model in the description and in docs/ARCHITECTURE.md: a refusal leaves the refused interval empty, a grant keeps the latest configured value for the new period, and a restart leaves the previous process out of the current context. The factory specs cover grant, refusal, same-timestamp boundaries, a consent change during load, and a serialization failure on one history while another still commits; DiskStorage covers ordered snapshots and a failed write. The split is sound: DiskStorage is only a JSON queue, TimeStampValueHistory stays the interval index, and the factory owns the single consent subscription so a collector cannot observe a half-applied transition.
Review load — Focused (~30–45min): One risky boundary: which intervals are authorized, which stay in memory, and the guarantee that every history has applied the transition before a collector callback. The write queue and replaceEntries belong to that same behavior. The one commit carries the whole boundary.
Sent by Cursor Automation: electron-sdk reviews
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 290b119a21
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d5cbbf1c77
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Looking at what we want to do and the existing patterns in the code base, I would expect:
- TrackingConsentManager gains a contextHistory to store the consent states by timestamp
- A hook is added to add a consent check at assembly based on the event start time, consistent with how we add the attributes on the crash
If it is not that simple, could we still go into that direction and see what needs to be adjusted to support this use case?
Persist the consent history like the session and view histories, and discard RUM events whose start time falls in a refused or unknown period. A pending period takes the decision that ended it, and a period left undecided by the previous process counts as refused. Recovered crashes no longer need a dedicated check or storage override: they are stored according to the current consent like other events.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ab08ef25ea
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const history = await DiskValueHistory.init<TrackingConsent>({ | ||
| filePath: path.join(app.getPath('userData'), TRACKING_CONSENT_HISTORY_FILE_NAME), | ||
| expireDelay: SESSION_TIME_OUT_DELAY, | ||
| }); |
There was a problem hiding this comment.
Treat malformed consent history as absent
When _dd_tracking_consent_history contains syntactically valid JSON such as [null], this new call reaches DiskValueHistory.init(), whose restore loop dereferences entry.endTime outside its read/parse try block (src/tools/DiskValueHistory.ts:49-55). The resulting exception rejects the top-level SDK init() instead of falling back to an empty consent history. The current revision therefore retains the earlier malformed-history failure through the newly introduced DiskValueHistory path even though the intermediate TrackingConsentHistory implementation is gone; validate restored entries or catch restoration errors before constructing the manager.
Useful? React with 👍 / 👎.
| return consent === 'granted' || consent === 'pending' ? SKIPPED : DISCARDED; | ||
| }); | ||
|
|
||
| return manager; |
There was a problem hiding this comment.
Await the initial consent snapshot before returning
On a fresh launch, constructing the manager only queues the initial consent snapshot through DiskValueHistory.add(); this method returns before its fs.writeFile promise settles, and init() provides no flush before returning. If the native process crashes shortly after the SDK reports successful initialization, the history file can still be missing or incomplete, so the next launch finds no consent interval covering that crash and discards the recovered report. Await the initial snapshot before completing initialization so the crash-recovery feature is effective immediately.
Useful? React with 👍 / 👎.
| hooks.registerRum(({ startTime }) => { | ||
| // Events of an undecided pending period are held by the batch storage until its decision. | ||
| const consent = manager.getDecisionAt(startTime); | ||
| return consent === 'granted' || consent === 'pending' ? SKIPPED : DISCARDED; |
There was a problem hiding this comment.
Rotate pre-init renderer views when consent history starts
When the Browser RUM SDK is already running in a window before a deferred main-process init(), the active renderer view keeps a date from before this manager was created. RendererPipeline passes that unchanged date as startTime for every later update of the view, so this callback finds no covering consent entry and discards every update even after initialization; meanwhile post-init actions and errors can still be uploaded with that view ID, leaving them attached to a view document that never arrives until navigation or session renewal creates a new view. The documented pre-init bridge supports such existing windows, so initialization needs to rotate/rebase their active views or otherwise establish a consent boundary they can use.
Useful? React with 👍 / 👎.


Motivation
A crash is reported at the next launch, with the session, view and customer context saved before it happened. That context does not show whether the crash was captured with consent, so a crash from a refused or undecided period could be sent once tracking is granted again. Part of RUM-15526.
Changes
TrackingConsentManagerstores its timestamped history in aDiskValueHistory, like the session and view histories.pendingperiod takes the decision that ended it; events of a period still undecided are left to the batch storage.pendingperiod left undecided by the previous process is recorded as refused, as its pending batches are deleted at startup.Consent changes are still written asynchronously: a crash right after a refusal, before it reaches disk, is accepted at the next launch.
Test instructions
yarn vitest runyarn tsc -p src --noEmityarn test:e2e: the crash scenarios cover restart recovery with the defaultgrantedconsent.Checklist