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 freezes 73-82% of a board by burst time, not all of it: after ~4 bands the survivors are too scattered to chain, even with the rescans handing wrongly-quarantined tsums back. Measured on synthetic boards, not a device. The lever is candidate generation --
calculatePathsreturns only the longest chain per colour component, soelsaNextChainchooses from a handful; proposing chains by endpoint separation, or by which band offset they would draw, would give it something better to choose from. - 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 window timings are unmeasured:
CoronationElsaConfig.leadInMs,chainSettleMs,postBurstSettleMs,burstTailMs/passMinMs(the closing burst's tap time and the least room worth a fresh pass),settledFraction/settleRetryMs(the mid-fall gate), theearlyBurstthresholds,bandHalfWidth/avoidHalfWidth(the two bounds read off a blurred mask, so bounded rather than measured), and whether the game starts the window at the activation tap or when the animation ends.skill.elsa.passcarries the per-chain coverage the model claimed, the quarantined count and the mid-fall waits, andskill.elsa.donethe chain and aimed-tap totals --icedLastnear zero with several chains drawn is the premature-pop signature, andplayedOut: falseon every window says the board never runs dry before the clock, which is what a device run would be read against. 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)