Repository navigation
[No QA] feat: size tiers for account-size Sentry tags, add transactions_count and db_size tags - #102197
Conversation
|
@MelvinBot review |
|
🤖 Nice cleanup — the single border table is the right shape, and your claim about the new tags reaching child spans checks out: One thing I'd fix before this leaves draft, one question, two nits. 1. A 4th border silently emits
|
…ween db size tests
|
@MelvinBot review |
|
🤖 Both fixes in Re-checked:
Only Leftover: the transactions guard is the odd one out
if (!value && !session?.email) {It only bails when both are falsy. Half of that is deliberate and the comment explains it: no Low stakes, and I'd call it a consistency wart rather than a bug: on sign-out Splitting the guard keeps the intended behavior and makes the deliberate part obvious: if (!session?.email) {
return;
}
// An account can have zero transactions, which Onyx delivers as undefined. Count it as 0 so the zero cohort stays in the data.
const transactionsCount = Object.keys(value ?? {}).length;Since it predates this PR, equally fine to leave it and let the four callbacks get cleaned up together later. Next Steps: Reply with |
|
@MelvinBot Leaving the && on purpose. At cold start the transaction collection can hydrate before the session key and nothing re-fires the callback once the session arrives, so requiring the session here would drop transactions_count for the whole session on those starts (reports and personal details already have that gap). The value in that window is the same device's cached collection, so the count is right. Sign-out still bails because Onyx.clear empties both |
|
🤖 Agreed, keep the
Optional: add half a line to the comment at |
|
@aimane-chnaif Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppAndroid: mWeb ChromeiOS: HybridAppiOS: mWeb SafariMacOS: Chrome / Safariweb1.movweb2.mov |
|
🤖 Looks good to me. Since my last review,
All CI checks pass except |
|
🤖 Code quality is good. The code is small, typed, and well tested. I have one suggestion and one nit, and neither blocks the PR. 1. Each tag key is written twice per call. All five call sites pass the same tag to All five call sites
2. Nit: move the hydration comment and fix its comma splice. The comment at |
|
🤖 I found one likely regression. It is small. Nothing in the repo reads the old tag values, and CI is green. A zero-transaction account can keep the previous account's
|
mountiny
left a comment
There was a problem hiding this comment.
Thanks! looks good to me
|
🚧 mountiny has triggered a test Expensify/App build. You can view the workflow run here. |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
|
|
🚀 Deployed to staging by https://github.com/mountiny in version: 9.5.2-0 🚀
|
|
No help site update needed: this PR only changes internal Sentry telemetry tags (account-size tiers), so users won't see any change in the app. |
|
🚀 Deployed to production by https://github.com/Julesssss in version: 9.5.2-4 🚀
Bundle Size Analysis (Sentry): |
Explanation of Change
This is step 2 of the account-size telemetry work from the linked issue. Step 1 (#99068) added the exact values as numeric span attributes (
reports_count_raw,transactions_count_raw,personal_details_count_raw,policies_count_raw,db_size_bytes,db_size_source) and left the bucketed tags untouched on purpose. The idea was to pick the new borders from real production data instead of guessing them. We now have three weeks of that data (7-day windows, all platforms, ~210K users a week with the attributes, adoption 90-100% per platform). This PR turns it into tags that a dashboard can group by.What this PR does
1-small,2-medium,3-large,4-xlarge. The borders sit where production latency actually bends, not at round numbers or quantiles. The numeric prefix is there because Sentry sorts tag values alphabetically and we want them in size order. The ranges are not part of the value, so if we ever move a border the dashboard history stays in one piece.reports_count,personal_details_count,policies_count) and only changes their values. No dashboard or alert uses them today, so nothing breaks and we don't need_v2keys. Any saved filter on the old strings would stop matching, there just isn't one. Old values (0-60,61-300, ...) and new values (1-small, ...) never overlap. Filtering on the tier values or onrelease:>=<this release>separates them, and the old values die out on their own as clients update (web the same day, native roughly a week to 90%).transactions_countanddb_size, with the same tier scheme. They carry information the report count doesn't. Search cost follows transactions, not reports, anddb_sizekeeps growing where the count tags flatten out.getAccountSizeTier(tag, value). The borders live next to it in one table keyed by tag, so changing a border is a one-line change.Proposed tiers
Borders are inclusive upper bounds. Each user is counted once, in the highest tier their spans reached during the last 7 days (Sep 16-23, production, all platforms, ~210K users with the attributes).
reports_count1-small2-medium3-large4-xlargetransactions_count1-small2-medium3-large4-xlargepersonal_details_count1-small2-medium3-largepolicies_count1-small2-medium3-large4-xlargedb_size1-small2-medium3-large4-xlargeReports and transactions use the same ladder so the two tags read the same way. They still select different users: about three quarters of the accounts that are large by transactions are only medium by reports. Personal details gets three tiers because its latency curve only bends once, around 1 000.
What the data says
These are the findings from three weeks of production spans (p50 and p95 per slice, all platforms together and each platform separately). Each one either fixed a border or decided which tags stay.
Changes in this PR
CONST.TELEMETRY.TAGSgetsTRANSACTIONS_COUNT(transactions_count) andDB_SIZE(db_size).copyTagsToChildSpanscopiesObject.values(CONST.TELEMETRY.TAGS), so both new tags reach child spans without extra wiring.CONST.TELEMETRY.SIZE_TIERholds the four tag values (1-small,2-medium,3-large,4-xlarge).src/libs/telemetry/accountSizeTier.tswithgetAccountSizeTier(tag, value)and a private border table, one array per tag. This is the only place where a range is written down. Borders are inclusive upper bounds. Two borders give three tiers (personal details), three borders give four. A tag without an entry in the table does not compile. It replacesbucketReportCountandbucketPolicyCountinTelemetrySynchronizer, both removed.TelemetrySynchronizersetsreports_count,personal_details_countandpolicies_countthroughgetAccountSizeTierin the same callbacks that register the raw attributes. It also starts settingtransactions_countnext totransactions_count_raw. An account with zero transactions gets1-small.databaseSizeTrackersetsdb_sizewherever it setsdb_size_bytes: for the value persisted from the previous session (applied at startup, so the startup span already has the tier) and after every new measurement. Anunavailablemeasurement sets no tag, same as the attribute.db_sizethat window is longer, until the next account's first measurement, because the persisted size is wiped on sign-out.accountSizeTierTestchecks 0, every border and every border plus one for every tag, the two-border ladder and the alphabetical order of the values. The existing raw-count tests inTelemetrySynchronizerTestnow also assert the tier tag.databaseSizeTrackerTestasserts the tag for the persisted value at startup, for the first measurement and for a re-measurement that crosses the 20 MB border.Fixed Issues
$ #98432
PROPOSAL: #98432
Tests
npx jest tests/unit/accountSizeTierTest.ts tests/unit/TelemetrySynchronizerTest.ts tests/unit/databaseSizeTrackerTest.tsand verify all tests pass.reports_count,transactions_count,personal_details_countandpolicies_counttags with one of the values1-small,2-medium,3-large,4-xlarge, and that each tag matches its*_count_rawattribute against the borders insrc/libs/telemetry/accountSizeTier.ts.db_sizenext todb_size_bytes.db_size(from the persisted measurement).Offline tests
Tag values come from local Onyx data and local storage size, so nothing changes offline. Verify the app behaves normally offline and no errors appear in the console.
QA Steps
No user-facing changes. Telemetry only. Validated by the unit tests and by the tag values showing up in Sentry after deploy.
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectionAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
No visible changes, telemetry only. Verified on web with the Sentry debug transport: outgoing transactions and their child spans carry all five tier tags and each tag matches its raw attribute (for example 716 reports ->
3-large, 4.4 MB ->1-small).Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari