Skip to content

[Draft] Update 3x pixel-firing logic to more closely match broken site prompt #5862

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 5 commits into
base: develop
Choose a base branch
from

Conversation

laghee
Copy link
Collaborator

@laghee laghee commented Apr 4, 2025

Task/Issue URL: https://app.asana.com/0/72649045549333/1209712075249435/f

Description

We decided in https://app.asana.com/0/1205142657210376/1209698956036733 that we would prefer the separate 3x pixel to fire for distinct 3-refresh groupings in the chosen time period as opposed to 3 refreshes that fall into a sliding window of time to more closely match the breakage prompt trigger.

Steps to test this PR

NB: Logic is currently patched to delay 7 seconds between accepted prompts & stop prompting with 3+ dismissals within the past 30 min.

Feature 1

  • Go to a site
  • Refresh 3 times
  • Verify that RELOAD-2X and RELOAD-3X pixels fire
  • Dismiss prompt
  • Refresh 3 times, pause for at least 20 seconds, then refresh 3 times again
  • Verify that RELOAD-2X and RELOAD-3X fire twice

@laghee laghee requested a review from CrisBarreiro April 4, 2025 13:47
@CrisBarreiro
Copy link
Contributor

@laghee, If I understand correctly, the logic to reset refresh count is not affected (reset once 3x or more refreshes), however, if the user refreshes 4x, we'd only send the 2x once. Not sure if that's expected / what iOS does in that case

}
pixel.fire(AppPixelName.RELOAD_THREE_TIMES_WITHIN_20_SECONDS)
Timber.d("KateTest--> should show bc 3 refreshes")
site?.let { brokenSitePrompt.shouldShowBrokenSitePrompt(it.url) } ?: false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess null site here is an edge case here, so probably fine if pixel and prompt fall out of sync

}

val dismissStreakResetDays = brokenSiteReportRepository.getDismissStreakResetDays().toLong()
val dismissalCount = brokenSiteReportRepository.getDismissalCountBetween(
currentTimestamp.minusDays(dismissStreakResetDays),
currentTimestamp.minusMinutes(dismissStreakResetDays),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Careful to revert this later


return dismissalCount < brokenSiteReportRepository.getMaxDismissStreak()
}

override suspend fun ctaShown() {
val currentTimestamp = currentTimeProvider.localDateTimeNow()
val newNextShownDate = currentTimestamp.plusDays(brokenSiteReportRepository.getCoolDownDays())
val newNextShownDate = currentTimestamp.plusSeconds(brokenSiteReportRepository.getCoolDownDays())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same

@@ -3946,6 +3952,31 @@ class BrowserTabViewModel @Inject constructor(
newTabPixels.get().fireNewTabDisplayed()
}

private suspend fun shouldPromptForBrokenSiteReport(): Boolean {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the method name, it's not obvious what it does

@@ -468,6 +469,7 @@ class BrowserTabViewModel @Inject constructor(
private val defaultBrowserPromptsExperiment: DefaultBrowserPromptsExperiment,
private val swipingTabsFeature: SwipingTabsFeatureProvider,
private val visualDesignExperimentDataStore: VisualDesignExperimentDataStore,
private val blockListPixelsPlugin: BlockListPixelsPlugin,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think this is needed anymore

pixel.fire(CustomTabPixelNames.CUSTOM_TABS_MENU_REFRESH)
}

private fun sendTimeBasedPixels() {
override fun sendBreakageRefreshPixels(patternsDetected: Set<Int>) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would call this method something like onRefreshPatternDetected, the fact that internally we send a pixel or do something else is irrelevant to the caller so I wouldn't be that specific.

@@ -3946,6 +3950,16 @@ class BrowserTabViewModel @Inject constructor(
newTabPixels.get().fireNewTabDisplayed()
}

private suspend fun shouldShowPromptForBrokenSiteReport(): Boolean {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is called right before refreshCta and the value it sends is used in the CtaViewModel so why not doing it there instead?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. I originally moved it to avoid losing the context for the user refreshes and resetting the count too often, but now that the logic's been altered, that's probably no longer necessary.

val cta = withContext(dispatchers.io()) {
ctaViewModel.refreshCta(
dispatchers.io(),
isBrowserShowing && !isErrorShowing,
siteLiveData.value,
showBrokenSitePrompt,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall I'm struggling with this. I don't fully get why we have pull this out of the CtaViewModel to pass a boolean back to it when within the CtaViewModel we still have access to the BrokenSitePrompt. It seems an unnecessary journey for a value that we can directly get when needed in the CtaViewModel


blockListPixelsPlugin.get2XRefresh()!!.getPixelDefinitions().forEach {
blockListPixelsPlugin.get2XRefresh()?.getPixelDefinitions()?.forEach {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Go back to !! I want this test to fail if get2Refresh returns null and this would bypass it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, unintentional


blockListPixelsPlugin.get3XRefresh()!!.getPixelDefinitions().forEach {
blockListPixelsPlugin.get3XRefresh()?.getPixelDefinitions()?.forEach {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

@@ -143,181 +115,28 @@ class RefreshPixelSenderTest {
}

@Test
fun whenSendMenuRefreshPixelsThenTimeBasedPixelsFired() = runTest {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall a lot of tests have been deleted, are the others covering for the new logic, pixels, etc?


companion object {
private const val TWICE_REFRESH = 2
private const val TWICE_REFRESH_WINDOW = 12L
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this 12 seconds? minutes? Would change the const to TWICE_REFRESH_WINDOW_IN_SECS or whatever the right thing is. Same for thrice.

@@ -59,15 +59,15 @@ interface BrokenSiteReportRepository {

fun resetRefreshCount()
fun addRefresh(url: Uri, localDateTime: LocalDateTime)
fun getAndUpdateUserRefreshesBetween(t1: LocalDateTime, t2: LocalDateTime): Int
fun checkForRefreshPatterns(currentDateTime: LocalDateTime): Set<Int>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would probably rename to getRefreshPatterns rather than check. Check doesn't tell me what is the thing that is checking so a bit confusing. Also, this returns the refresh patterns but they are not associated to any URL so how do you know it's relevant for the current site?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants