fix(cafe): resolve invite ticket cooldown misread as list opened, preventing cascading errors

This commit is contained in:
Nik Afiq 2026-07-14 22:57:32 +09:00
parent e814b3d803
commit a0e1965353
3 changed files with 53 additions and 1 deletions

File diff suppressed because one or more lines are too long

View File

@ -24,6 +24,20 @@ had just taken the account's highest-affection students -- then invited
row 3 cleanly. Both newly-invited students were immediately patted row 3 cleanly. Both newly-invited students were immediately patted
successfully in the same run, income was claimed, and the task returned successfully in the same run, income was claimed, and the task returned
cleanly to the true home screen with no warnings anywhere in the log. cleanly to the true home screen with no warnings anywhere in the log.
A follow-up real-usage bug (2026-07-14, reported with a screenshot after
the ticket used above went on cooldown): _open_invite_list originally
verified only "did the header stop reading as a plain subscreen", which
is also true when the ticket is on cooldown and the click raises a
"通知" notice ("待機時間が経過した後に、再度招待することができます。")
directly instead of opening the list -- misread as "list opened", it then
sent _ensure_invite_sort/_try_invite_row's row/sort-control coordinates
into a dialog that has none of them, repeatedly. Fixed by checking
navigation.is_modal_open (a real dialog's darker dim) before the
list-opened check: a dialog appearing before any row was clicked can only
mean the ticket click itself raised one directly, so this now dismisses
it via SWEEP_CONFIRM_BUTTON and returns False (skip invite this room)
instead of proceeding.
""" """
from ba_auto import detector, navigation from ba_auto import detector, navigation
@ -159,9 +173,37 @@ def _open_invite_list(driver, config):
# list-with-no-nested-dialog state actually produces (confirmed live: # list-with-no-nested-dialog state actually produces (confirmed live:
# MODAL_DIM_PROBE read (252,145,165) with just the list open, which # MODAL_DIM_PROBE read (252,145,165) with just the list open, which
# fails is_modal_open's all-channels-under-150 check). # fails is_modal_open's all-channels-under-150 check).
#
# But that same "not on subscreen" reading is also produced by a
# completely different case: when the ticket is on cooldown, clicking
# the icon does NOT open the list at all -- it raises a "通知" dialog
# directly ("待機時間が経過した後に、再度招待することができます。",
# confirmed live 2026-07-14 via a real user report + screenshot) with
# the same dimming. The original version of this check couldn't tell
# the two apart and treated the cooldown notice as "list opened",
# which then sent _ensure_invite_sort/_try_invite_row's fixed row/
# sort-control coordinates into a dialog that doesn't have any of
# them -- exactly the "keep pressing the invite when it's not
# available and causing this popup and fail" the user reported.
#
# A real dialog (navigation.is_modal_open, which needs the DARKER
# reading a nested "通知" card produces, not just the list's own lighter
# dim) can only legitimately appear here if the ticket click itself
# opened one directly -- the list view has no dialog on top of it yet
# at this point, since no row has been clicked. So checking
# is_modal_open first, before the list-opened check, cleanly
# distinguishes "cooldown notice fired instead of the list" from "the
# list opened normally" and lets this dismiss the notice safely rather
# than misreading it as success.
for attempt in range(1, ROOM_OPEN_RETRIES + 1): for attempt in range(1, ROOM_OPEN_RETRIES + 1):
driver.click(*config.CAFE_INVITE_TICKET_ICON) driver.click(*config.CAFE_INVITE_TICKET_ICON)
driver.wait(2) driver.wait(2)
if navigation.is_modal_open(driver):
title = detector.read_text(config.CAFE_INVITE_DIALOG_TITLE_RECT, psm=6, lang="jpn")
print(f"[cafe] invite ticket click opened a dialog instead of the list (title: '{title}') -- likely on cooldown, treating invitation as unavailable")
driver.click(*config.SWEEP_CONFIRM_BUTTON)
driver.wait(1)
return False
if not navigation.is_on_subscreen(driver): if not navigation.is_on_subscreen(driver):
return True return True
print(f"[cafe] invitation ticket list not detected after click (attempt {attempt}/{ROOM_OPEN_RETRIES})") print(f"[cafe] invitation ticket list not detected after click (attempt {attempt}/{ROOM_OPEN_RETRIES})")

10
plan.md
View File

@ -334,6 +334,16 @@ Live-calibrated on nik-gpu (free — panning and patting don't spend a limited r
**Confirmed live with real game-state changes** (patting affects real affection, though it's a free, repeatable daily action, not a limited resource like the invite ticket): a full `cafe` run patted a real sparkle in room 2 (`score=0.997`) specifically after panning to an extreme — the sparkle would not necessarily have been visible from the room's default load position — while room 1 found nothing in either view that run (expected: sparkles are on a per-student cooldown, most checks legitimately find nothing). The task completed cleanly end-to-end (both rooms' invite-then-farm sequence, income claimed, confirmed clean return to home) with no warnings anywhere in the log. **Confirmed live with real game-state changes** (patting affects real affection, though it's a free, repeatable daily action, not a limited resource like the invite ticket): a full `cafe` run patted a real sparkle in room 2 (`score=0.997`) specifically after panning to an extreme — the sparkle would not necessarily have been visible from the room's default load position — while room 1 found nothing in either view that run (expected: sparkles are on a per-student cooldown, most checks legitimately find nothing). The task completed cleanly end-to-end (both rooms' invite-then-farm sequence, income claimed, confirmed clean return to home) with no warnings anywhere in the log.
#### Phase 6 follow-up #4: invite ticket cooldown misread as "list opened" (2026-07-14)
Real-usage bug report with a screenshot, filed once the account's invite ticket (spent twice during follow-up #2's live test, same day) went on cooldown: "I have problem with the script keep pressing the invite when it's not available and causing this popup and fail." The screenshot showed a "通知" dialog reading "待機時間が経過した後に、再度招待することができます。" ("you can invite again after the wait time passes") with a single OK/Enter button, no cancel.
Root cause: `_open_invite_list`'s check (`not navigation.is_on_subscreen(driver)`, added in follow-up #2 above) verifies only "something opened that dims the header" — true for the real MomoTalk list AND for this cooldown notice alike, since both dim `SUBSCREEN_HEADER_PROBE` the same way. It returned `True` (list opened) for the cooldown case too, so `_invite_student` proceeded straight into `_ensure_invite_sort`/`_try_invite_row`'s fixed sort-dropdown/row coordinates — none of which exist on this small single-button dialog — causing the cascading wrong clicks and failure the user reported.
Fix: check `navigation.is_modal_open` (the darker "real dialog" reading, not the list's own lighter dim) immediately after the ticket-icon click, before the list-opened check. A dialog appearing at this exact point can only mean the click itself raised one directly — no row has been clicked yet, so the normal per-row invite-confirm dialog can't be it. When detected, `_open_invite_list` now OCRs the title for logging, dismisses via the shared `SWEEP_CONFIRM_BUTTON` (same "通知" component position reused throughout this project), and returns `False` — which `_invite_student`'s existing (unchanged) fallback already handles correctly: skip the invite, log it, move on to farming.
**Confirmed live** (`live-test-runner` agent, real `cafe` run with the ticket confirmed still on cooldown for both rooms): both rooms logged `invite ticket click opened a dialog instead of the list (title: '...') -- likely on cooldown, treating invitation as unavailable` immediately, no cascading errors or misclicks followed, and the task proceeded normally to farming/income-claim and ended cleanly (exit 0, true home screen confirmed via screenshot). OCR of the dialog title came back noisy (`'通和 X'` instead of `'通知'`) but this doesn't matter — the fix's branch doesn't depend on the title text, only on `is_modal_open` firing before any row was clicked.
### Phase 7: setup.sh update ### Phase 7: setup.sh update
**Status: Done — `setup.sh` deploys `ba_daily.py` and `ba_auto/`.** `scripts/ba_dailies_legacy.sh` and `scripts/detect_and_click.py` were deleted once mailbox and cafe both migrated off them (Phases 56); `setup.sh` no longer references either. **Status: Done — `setup.sh` deploys `ba_daily.py` and `ba_auto/`.** `scripts/ba_dailies_legacy.sh` and `scripts/detect_and_click.py` were deleted once mailbox and cafe both migrated off them (Phases 56); `setup.sh` no longer references either.