Backlog
:::info Copied from the repository
This page is app.gap.Tsum/BACKLOG.md, copied in by the site's sync step. Edit it there; edits here are lost at the next sync.
:::
All potential changes which would improve the script will be documented in this file.
Bugs
- On some devices, after game play, rubies are spent when "Magic Time" is offered (reported by TAR). Happened on real phones without "Special screen ratio" (with video evidence) and Nox (not recorded, config details currently unknown).
- Harden auto start. Clicking the daily banners too fast or while loading can make the game stuck.
- The board stops fingerprinting under a burst skill's full-screen animation and under the mid-round level-up banner, so the play loop plays blind through them. Needs captures of those moments before it can be fixed; the development tools'
OBSCURED_BOARD.mdis the handover. The cost when it happens is not a wrong page but a stopped one: once the debounce runs out the loop hands over toconfirmGameOver, which neither scans nor taps, so an overlay lasting to time-up costs every second after it.play.gameOver'shudLostMsis how long that was. The fever and closing-seconds cases are closed. - The detection suite misses all four
TsumTsumStorePageframes: probe 4 ofTsumTsum2025StorePage(570,910) reads diff 31 against threshold 30 on every one -- a hair past the line, so either the threshold was cut too tight or the panel colour drifted. One re-measure in the studio settles which. - Coronation Day Elsa's row sweep is unverified as a whole (2026-09-13): its pieces are -- chains planned over three rows link (
coronation_elsa_6.mp4), the ice reads through the frozen box and the whitelist, the break and the bomb pop land -- but no recording yet shows the sweep running chain after chain for a full window. Readskill.elsa.donefirst:chainsshould be six or more a window andicedLasta pile, andstarvedLookshigh means the rows ran out or the ice read is off. Also unmeasured: whether many small bands beat one late chain (a first chain 10-12s in with nothing frozen before it took most of the board), and the exact close of the window past the 1.5s lead-in. - Coronation Day Elsa's round-over gate is unverified on a device (2026-09-15):
elsaRoundOverwas written offoption_menu.mp4and a cv2 replay of the scan, not a log. On the next run readskill.elsa.roundOver-- it should appear only on a window the round's timer cuts short, andskill.elsa.doneon such a window should carryroundOver: trueand no closing break -- and check no healthy window pays for it:looksandchainsper window should be unchanged, since the check runs only on a starved look. - Coronation Day Elsa's frozen tsums take colour slots among the
uniqueTsumCount - 1scanBoardQuickkeeps -- one per ice shade -- so a pass that starts on an iced board is read short of real colours. It costs chains, not correctness. Fixing it means teaching the scan about clusters it should not count, which is a change every skill shares. - Coronation Day Elsa's ice-alike ranges and kind-read verdict are unverified on a device (2026-09-26). On a pale-blue lineup, breaks between windows (
skill.elsa.burstoutside a window) should be near zero, andskill.elsa.iceAlikeshows each learned range.kindChains+kindLiftsper window should fall from 9-15 (mui0gs7xco) while dead chains do not rise; a clean read (everydropsunder 25) now clears its colour.kind.dropMax25 held on device: same kind <= ~20, other kinds 30-200. - Coronation Day Elsa's mid-window bubble pops are unverified on a device (2026-09-25). If bubbles still stand,
skill.elsa.passsays which cause:bubbles> 0 afterpoppedmeans ones on ice (bubbleIceGap0.6, reasoned) or pastbubblePopRounds; bubbles on video but never in the log mean the scan misses them -- Gaston's second Hough pass over the bottom band (gastonBubbles) is the known fix for rim bubbles. - Coronation Day Elsa's window timings are only partly measured:
iceFormMsand the frozen colour box come off recordings, butleadInMs,burstTailMs,postBurstSettleMsandsettledFraction/settleRetryMs(the mid-fall gate) are reasoned.skill.elsa.done'sicedLastnear zero with several chains drawn is the premature-pop signature. base_coinscan still go empty on a round whose only readable-looking frames came mid-payout: of the sixunread-baseshots pulled off MuMu on 2026-08-28, five were the '5' digit misreading (fixed in 0.4 by recutting the template) and the sixth was a "LAST BONUS" frame with the level-up panel still fading in, where failing safe is right. Worth revisiting only if the column keeps gapping now that the '5' reads.
Screen interactions that bypass the page router
Every screen interaction should be anchored to an explicit page, so that no tap
is aimed at a screen nobody confirmed was there. These are the places that are
not, worst first. The root cause is shared: NavPlans (src/data.ts) has four
destinations, so gPages.navigate() can only be asked for those four -- any task
that needs to get somewhere deeper has to hand-drive, and the hand-driven part is
where the blind taps are.
Each of these needs captures of the screens before it can be fixed; that is the gating cost, not the code.
The fix for the root cause is a routing graph, not more destinations. Declare
the page-to-page edges the navigate band already implements one subscription at a
time -- plus the anchors (mail, tsums, home) which are edges in the Page
table already -- and let navigate() find a path over them instead of accepting
only the five names in NavPlans. Used forward like this, a missing edge means
"no route", which is a loud failure; the same graph used backwards, to constrain
what the next page can be, produces a spurious Unknown instead and was turned
down for good (PAGE_DISPATCH.md § The sitemap says why a map, not a filter).
The observed graph in docs/transitions.json is what such a table would be
checked against -- an edge nobody has ever been seen to take, or a transition
seen that the table does not admit.
Most of that now exists. PageRoutes and AnchorRoutes (src/data.ts) are
the edge table, every edge tagged with how far it is to be believed, and
forecastPath (src/forecast.ts) already finds a route over them, and the
detection suite's self-test cross-checks them against the observed ledger. The
blind fallback is gone: nav.move.exit presses a page's back only where its
PageRoutes row says that is a way out, and a page with no row makes
navigate() say nav.noRoute rather than tap. What is still open is the
consumer: navigate() does not walk the graph, it takes the NavPlans via
hop, and most exit rows name no destination. The remaining work is to give the
rows a to somebody can justify, then have navigate() walk them.
skipAd(src/mail.ts) -- three bare coordinates with 4s/4s/2s sleeps and no probe of any kind, crossing three screens that have no names.taskReceiveOneItem(src/mail.ts) -- a parallel recognition system. It is screen-driven, but through per-buttonisSameColorprobes rather thangPages, so none of it is visible to the detection suite: sixButton.*.colorpoints decide what screen it is on andgPagesis called once, whileMailBox,Received,ReceiveHeart,ReceiveSkillTicketandReceivePremiumTicketsit unused. The heart sender was the other half of this and is nowgPages-driven throughout.- The rest of
taskReceiveAllItems(src/mail.ts) -- the hop into the mailbox is a real navigation now (nav.move.toMail+ theMailBoxplan), but the receive-all confirmation and the results panel that follow are still open-loop taps on sleep timing. Needs a frame of each. friendPageGoToSelf(src/hearts.ts) -- two confirmednavigate()hops now, but it still ends on the raw nativetap(0, 0, 20), which bypassests.tapand its coordinate conversion entirely. It is there to move an emulator pointer off the score column that the zero-score check reads.
Deliberately outside the router and to be left alone: src/dialogs.ts (native
Android dialogs are not game screens, and it finds buttons structurally via
uiautomator bounds -- it is entered through PageName.RootDetection, which is
the right seam), the in-round taps (chains, skills, fan, clearAllBubbles, the
skill choreographies -- these run on GamePlaying, which the play loop
re-verifies every iteration), exitUnknownPage (blind by definition, correctly
anchored to PageName.Unknown), and app start/restart.
Features
- Add "Spam skill" option to check for skill after every finished chain instead of every chain batch.
- Skill: Jedi Luke (13 swipes technique)
- Rewrite of Settings UI (became too large as single-page, not dynamic regarding settings like "skill level" of Cinderella)