fix(event_sweep): improve event badge handling by removing dot-clicking and immediate badge clicks after home navigation
This commit is contained in:
parent
a86003cf66
commit
fd9828a746
@ -229,24 +229,20 @@ STORY_SWEEP_ROTATION_COUNT = "max"
|
|||||||
# no fixed click here is guaranteed to hit the right content on the first
|
# no fixed click here is guaranteed to hit the right content on the first
|
||||||
# try. Back-button navigation now goes through navigation.return_to_home's
|
# try. Back-button navigation now goes through navigation.return_to_home's
|
||||||
# shared BACK_BUTTON constant instead of a dedicated config entry here.
|
# shared BACK_BUTTON constant instead of a dedicated config entry here.
|
||||||
|
#
|
||||||
|
# EVENT_BADGE_DOT_X/_Y (the carousel's own pagination dots) removed
|
||||||
|
# 2026-07-13 per explicit user direction/correction: the dots don't
|
||||||
|
# reliably do anything ("it will click on the button under the event. The
|
||||||
|
# button does nothing"), and the earlier "wait long enough for the slow
|
||||||
|
# auto-rotate timer to land on the correct event" theory had the mechanism
|
||||||
|
# backwards -- the current/ongoing event is the carousel's DEFAULT item
|
||||||
|
# right when the home screen is reached, and it rotates away again within
|
||||||
|
# a short window afterward. event_sweep.py's run() now clicks the badge
|
||||||
|
# immediately after navigation.return_to_home confirms home, with no
|
||||||
|
# artificial wait in between, instead of trying to force a specific
|
||||||
|
# carousel page.
|
||||||
EVENT_BADGE_ICON = (1787, 300)
|
EVENT_BADGE_ICON = (1787, 300)
|
||||||
|
|
||||||
# The badge carousel's own small pagination dots, directly below the
|
|
||||||
# thumbnail -- confirmed LIVE CLICKABLE and immediately switch which item
|
|
||||||
# the badge shows, rather than waiting for the carousel's own auto-rotate
|
|
||||||
# timer (observed to be slow enough that a fixed page could still be
|
|
||||||
# showing 20-30+ seconds later, well past this task's retry window). Pixel-
|
|
||||||
# scanned live: with 2 known carousel items, the dots sit ~14px apart
|
|
||||||
# starting at x=1780; clicking the leftmost one deterministically selected
|
|
||||||
# the current running event over an old event's leftover reward-claim
|
|
||||||
# reminder. event_sweep.py clicks a specific dot BEFORE each badge-open
|
|
||||||
# attempt (cycling through positions across its outer retry loop) instead
|
|
||||||
# of repeatedly clicking the ambiguous badge and hoping the timer has
|
|
||||||
# moved on. Clicking a dot position that doesn't exist (beyond however many
|
|
||||||
# items are actually queued) is a harmless no-op click on plain background.
|
|
||||||
EVENT_BADGE_DOT_Y = 400
|
|
||||||
EVENT_BADGE_DOT_X = (1780, 1794, 1808)
|
|
||||||
|
|
||||||
# A finished event's Quest tab shows plain "イベント期間が終了しました。"
|
# A finished event's Quest tab shows plain "イベント期間が終了しました。"
|
||||||
# (event period has ended) text instead of any stage-row cards. This rect
|
# (event period has ended) text instead of any stage-row cards. This rect
|
||||||
# and the lang="jpn" OCR read against it are LIVE-CONFIRMED both ways
|
# and the lang="jpn" OCR read against it are LIVE-CONFIRMED both ways
|
||||||
|
|||||||
@ -248,8 +248,53 @@ against this larger region. _watch_sweep_result also gained a third
|
|||||||
_is_ticket_purchase_prompt fix) as a second, independent safety layer: if
|
_is_ticket_purchase_prompt fix) as a second, independent safety layer: if
|
||||||
a purchase prompt is ever reached here anyway, it's recognized and
|
a purchase prompt is ever reached here anyway, it's recognized and
|
||||||
cancelled explicitly by _sweep_target rather than left to the blind color
|
cancelled explicitly by _sweep_target rather than left to the blind color
|
||||||
search. Not yet re-confirmed live -- deployed but no fresh real sweep run
|
search. Confirmed live the very next real run: a real MAX sweep of stage
|
||||||
since.
|
12 completed and correctly logged "result: swept" (not
|
||||||
|
"unrecognized_state") for the first time.
|
||||||
|
|
||||||
|
That same live run surfaced a separate, real bug in the wrong-page
|
||||||
|
recovery path, reported directly by the user along with the fix: "when
|
||||||
|
landed on wrong event page, it will click on the button(?) under the
|
||||||
|
event. The button does nothing. Fastest way is to click event right away
|
||||||
|
when get to home after returning, since ongoing event will always be on
|
||||||
|
top by default, then scrolled away automatically after few ms." This
|
||||||
|
overturns follow-up #5's own theory (the carousel's auto-rotate timer is
|
||||||
|
SLOW, so waiting longer would eventually land on the correct event) --
|
||||||
|
the true mechanism is the opposite: the current event is the carousel's
|
||||||
|
DEFAULT item immediately after the home screen is reached, and it
|
||||||
|
auto-rotates away again quickly, so the fix is to click the badge as fast
|
||||||
|
as possible after confirming home, not to wait for a slow timer to cycle
|
||||||
|
around. The carousel's own pagination dots (EVENT_BADGE_DOT_X/_Y,
|
||||||
|
originally added in follow-up #4 to "force" a specific page) don't
|
||||||
|
reliably do anything either, per the user's own report, and calling them
|
||||||
|
before every badge-click attempt was actively counterproductive -- extra
|
||||||
|
clicks and waits that only pushed the badge-click further past the
|
||||||
|
correct-by-default window. **Fix**: `_select_badge_page`/dot-clicking
|
||||||
|
removed entirely; `_open_event_screen` no longer takes a `dot_index` and
|
||||||
|
just clicks the badge directly; `run()`'s retry loop no longer waits
|
||||||
|
`WRONG_PAGE_RETRY_WAIT` (12s, now removed) between `navigation.
|
||||||
|
return_to_home` and the next `_open_event_screen` call -- it retries
|
||||||
|
immediately.
|
||||||
|
|
||||||
|
The report this fix is based on was the STILL-OLD dot-click/12s-wait
|
||||||
|
design (the same run that confirmed the `_watch_sweep_result` fix above):
|
||||||
|
it hit `wrong_page` on attempts 1-3 (all rows `None`, finished-event text
|
||||||
|
confirmed each time) and only succeeded on attempt 4, after 3 full 12s
|
||||||
|
waits -- the user's diagnosis of *why* it eventually worked (not because
|
||||||
|
the dots did anything, but because returning home and simply trying again
|
||||||
|
naturally re-lands on the correct default item) is what this fix acts on,
|
||||||
|
not a live test of the fix itself.
|
||||||
|
|
||||||
|
Confirmed live at zero AP cost immediately after deploying: 3 separate
|
||||||
|
trials of `navigation.return_to_home` -> `_open_event_screen` (no dot
|
||||||
|
click, no wait) -> checking `_is_finished_event_page`/reading the stage
|
||||||
|
rows, all 3 landed on the correct current event on the very first attempt
|
||||||
|
(`finished_page=False`, all 5 rows read their correct stage numbers,
|
||||||
|
target stage 12 found at row 1055) -- no `wrong_page` outcome at all
|
||||||
|
across all 3 trials. This confirms the navigation half of the fix
|
||||||
|
directly; the full sweep-and-result path wasn't re-exercised in this same
|
||||||
|
check (that needs spending real AP, deferred pending the user's own next
|
||||||
|
real run).
|
||||||
"""
|
"""
|
||||||
import datetime
|
import datetime
|
||||||
import os
|
import os
|
||||||
@ -262,7 +307,6 @@ POST_SWEEP_DISMISS_ROUNDS = 14
|
|||||||
MAX_BUTTON_RETRIES = 3
|
MAX_BUTTON_RETRIES = 3
|
||||||
MODAL_CLOSE_RETRIES = 3
|
MODAL_CLOSE_RETRIES = 3
|
||||||
WRONG_PAGE_RETRIES = 6
|
WRONG_PAGE_RETRIES = 6
|
||||||
WRONG_PAGE_RETRY_WAIT = 12
|
|
||||||
STAGE_ENTER_RETRIES = 3
|
STAGE_ENTER_RETRIES = 3
|
||||||
STAGE_ROW_SCAN_ATTEMPTS = 9
|
STAGE_ROW_SCAN_ATTEMPTS = 9
|
||||||
STAGE_ROW_SCAN_RETRY_WAIT = 2.5
|
STAGE_ROW_SCAN_RETRY_WAIT = 2.5
|
||||||
@ -305,22 +349,18 @@ def _count_raised_above_one(driver, config):
|
|||||||
return (max(r, g, b) - min(r, g, b)) > 40
|
return (max(r, g, b) - min(r, g, b)) > 40
|
||||||
|
|
||||||
|
|
||||||
def _select_badge_page(driver, config, dot_index):
|
def _open_event_screen(driver, config):
|
||||||
dot_xs = config.EVENT_BADGE_DOT_X
|
# Per explicit user direction (2026-07-13), superseding the dot-click
|
||||||
if dot_index >= len(dot_xs):
|
# approach: the carousel's pagination dots don't reliably do anything
|
||||||
return # no more known dot positions -- fall through to a bare badge click
|
# ("it will click on the button under the event. The button does
|
||||||
driver.click(dot_xs[dot_index], config.EVENT_BADGE_DOT_Y)
|
# nothing"), and the earlier "wait long enough for the slow auto-rotate
|
||||||
driver.wait(0.5)
|
# timer to cycle back to the correct event" theory had it backwards --
|
||||||
|
# the current/ongoing event is the DEFAULT item shown the moment the
|
||||||
|
# home screen is reached, and it auto-rotates AWAY within a very short
|
||||||
def _open_event_screen(driver, config, dot_index=0):
|
# window afterward. The fix is to click the badge as immediately as
|
||||||
# Force the carousel to a specific known page before clicking into it,
|
# possible after confirming home, not to wait -- see run()'s own retry
|
||||||
# rather than clicking the ambiguous badge directly and hoping it
|
# loop, which no longer inserts a wait between navigation.return_to_home
|
||||||
# currently shows the right event (see config.py's EVENT_BADGE_DOT_*
|
# and the next _open_event_screen call for exactly this reason.
|
||||||
# comment -- confirmed live the auto-rotate timer is far slower than
|
|
||||||
# this task's retry window).
|
|
||||||
_select_badge_page(driver, config, dot_index)
|
|
||||||
|
|
||||||
for attempt in range(1, OPEN_RETRIES + 1):
|
for attempt in range(1, OPEN_RETRIES + 1):
|
||||||
driver.click(*config.EVENT_BADGE_ICON)
|
driver.click(*config.EVENT_BADGE_ICON)
|
||||||
driver.wait(2)
|
driver.wait(2)
|
||||||
@ -615,18 +655,20 @@ def run(driver, config):
|
|||||||
|
|
||||||
outcome = None
|
outcome = None
|
||||||
for attempt in range(1, WRONG_PAGE_RETRIES + 1):
|
for attempt in range(1, WRONG_PAGE_RETRIES + 1):
|
||||||
dot_index = attempt - 1
|
# No wait between reaching home and clicking the badge -- see
|
||||||
if not _open_event_screen(driver, config, dot_index):
|
# _open_event_screen's own docstring for why: the current event is
|
||||||
print(f"[event_sweep] could not confirm event screen is open (attempt {attempt}/{WRONG_PAGE_RETRIES}, badge page {dot_index})")
|
# the carousel's default item right after landing on home, and it
|
||||||
navigation.return_to_home(driver)
|
# rotates away quickly, so any delay here (the original design
|
||||||
driver.wait(WRONG_PAGE_RETRY_WAIT)
|
# waited WRONG_PAGE_RETRY_WAIT=12s, exactly backwards) just means
|
||||||
|
# missing the correct item before the click even happens.
|
||||||
|
navigation.return_to_home(driver)
|
||||||
|
if not _open_event_screen(driver, config):
|
||||||
|
print(f"[event_sweep] could not confirm event screen is open (attempt {attempt}/{WRONG_PAGE_RETRIES})")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
outcome = _sweep_target(driver, config, stage, count)
|
outcome = _sweep_target(driver, config, stage, count)
|
||||||
if outcome == "wrong_page":
|
if outcome == "wrong_page":
|
||||||
print(f"[event_sweep] landed on the wrong event page (attempt {attempt}/{WRONG_PAGE_RETRIES}, badge page {dot_index}) -- returning home to retry")
|
print(f"[event_sweep] landed on the wrong event page (attempt {attempt}/{WRONG_PAGE_RETRIES}) -- retrying immediately")
|
||||||
navigation.return_to_home(driver)
|
|
||||||
driver.wait(WRONG_PAGE_RETRY_WAIT)
|
|
||||||
continue
|
continue
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
|
|||||||
14
plan.md
14
plan.md
@ -592,7 +592,19 @@ Follow-up #6's x-narrowing (1000-1300) turned out to not be the whole fix. Root
|
|||||||
|
|
||||||
**Fixed by porting bounty.py's own resolution directly**: (1) `EVENT_SWEEP_RESULT_BUTTON_REGION`'s y1 shifted 700→730 (15px clear of the button's measured 715 edge), kept wide through y2=1050 to still cover a possible SKIP-then-OK sequence's ~120px spread since this event's own SKIP button was never individually measured; (2) `detector.find_color_centroid`'s `min_pixels` parameter applied here too via a new `EVENT_SWEEP_RESULT_BUTTON_MIN_PIXELS` (3000, carried over from `BOUNTY_RESULT_BUTTON_MIN_PIXELS` by analogy — same shared UI component, though this region is somewhat larger so it may need its own tuning); (3) `_watch_sweep_result` gained a third `ends` condition on `_is_ap_purchase_prompt` (mirroring bounty's `_is_ticket_purchase_prompt` fix) as an independent safety layer.
|
**Fixed by porting bounty.py's own resolution directly**: (1) `EVENT_SWEEP_RESULT_BUTTON_REGION`'s y1 shifted 700→730 (15px clear of the button's measured 715 edge), kept wide through y2=1050 to still cover a possible SKIP-then-OK sequence's ~120px spread since this event's own SKIP button was never individually measured; (2) `detector.find_color_centroid`'s `min_pixels` parameter applied here too via a new `EVENT_SWEEP_RESULT_BUTTON_MIN_PIXELS` (3000, carried over from `BOUNTY_RESULT_BUTTON_MIN_PIXELS` by analogy — same shared UI component, though this region is somewhat larger so it may need its own tuning); (3) `_watch_sweep_result` gained a third `ends` condition on `_is_ap_purchase_prompt` (mirroring bounty's `_is_ticket_purchase_prompt` fix) as an independent safety layer.
|
||||||
|
|
||||||
**Confirmed live at zero AP cost**: opened the real stage-12 modal (view only, no count raised, no sweep confirmed) and directly compared `_find_result_button` against the OLD region (falsely matched `(1226, 707)`, sitting right on 掃討開始's own corner) vs. the NEW region+min_pixels (correctly returned `None` on the same resting screen). **Not yet re-confirmed with a fresh full real sweep** reaching an actual `"swept"` log — that requires spending real AP again, deferred pending the user's go-ahead.
|
**Confirmed live at zero AP cost**: opened the real stage-12 modal (view only, no count raised, no sweep confirmed) and directly compared `_find_result_button` against the OLD region (falsely matched `(1226, 707)`, sitting right on 掃討開始's own corner) vs. the NEW region+min_pixels (correctly returned `None` on the same resting screen).
|
||||||
|
|
||||||
|
**Confirmed live with a real full sweep** (the user's next run, same day): a real MAX sweep of stage 12 completed and logged `result: swept` for the first time ever — not `unrecognized_state`. The fix is fully validated.
|
||||||
|
|
||||||
|
#### Phase 14 follow-up #8: badge-carousel dots don't work — click immediately after reaching home instead of waiting (2026-07-13)
|
||||||
|
|
||||||
|
**Reported** in the same real run that confirmed follow-up #7: the wrong-page retry loop hit `wrong_page` on attempts 1-3 (all 5 rows `None`, finished-event text confirmed each time) before finally succeeding on attempt 4. The user's own diagnosis, with the fix already specified: "When landed on wrong event page, it will click on the button(?) under the event. The button does nothing. Fastest way is to click event right away when get to home after returning, since ongoing event will always be on top by default, then scrolled away automatically after few ms."
|
||||||
|
|
||||||
|
This overturns follow-up #5's own theory. That fix assumed the carousel's auto-rotate timer was SLOW, so waiting longer (`WRONG_PAGE_RETRIES`/`_WAIT` widened 3×3s → 6×12s) would eventually land on the correct event — and it also assumed the carousel's pagination dots (added in follow-up #4) reliably forced a specific page. Per the user's direct correction, neither is right: the dots don't reliably do anything, and the real mechanism is the *opposite* of "wait for the slow timer" — the current/ongoing event is the carousel's DEFAULT item the moment the home screen is reached, and it rotates away again quickly. The fix is to click the badge as fast as possible after confirming home, not to wait.
|
||||||
|
|
||||||
|
**Fix**: `_select_badge_page`/dot-clicking removed entirely (`_open_event_screen` no longer takes a `dot_index`); `run()`'s retry loop no longer waits `WRONG_PAGE_RETRY_WAIT` (12s, now deleted) between `navigation.return_to_home` and the next `_open_event_screen` call — it retries immediately. `config.EVENT_BADGE_DOT_X`/`_Y` removed as dead code.
|
||||||
|
|
||||||
|
**Confirmed live at zero AP cost**: 3 separate trials of `return_to_home` → `_open_event_screen` (no dot, no wait) → checking `_is_finished_event_page`/reading the stage rows, run immediately after deploying. All 3 landed on the correct current event on the very first attempt — no `wrong_page` outcome at all across any trial (previously, the same account's badge was landing wrong 3 times out of 4 attempts with the old design). The full sweep-and-result path through this navigation wasn't re-exercised in the same check (that needs spending real AP) — deferred to the user's next real run.
|
||||||
|
|
||||||
### Phase 15: Bounty
|
### Phase 15: Bounty
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user