ba-auto-daily/plan.md
Nik Afiq 68a7ed2529 feat: cafe lowest-affection invite for room 2, exit_game AP-left-unspent alert, login window-flicker fix
- cafe.py: room 2 now invites the lowest-affection candidate instead of
  highest (room 1 unchanged), plus OCR'd invited-student name logging
- exit_game.py: alert (AP_ALERT: log tag, picked up by ba_cron_run.sh's
  Discord alerting) if AP is still unspent above threshold when the game
  closes
- login.py: re-check window_exists() after the stabilization wait to catch
  a startup window-flicker race that could crash a run
- config.py/mapping.md: supporting constants and reference-mapping updates

Also rewrites plan.md: retires the phase-by-phase changelog (now fully
superseded by CLAUDE.md's own documentation) down to forward-looking
backlog items, and adds a performance-improvement plan from a cron-log
time analysis (lesson.py's per-cell screenshot redundancy, event_sweep's
multi-call design).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 19:28:59 +09:00

8.7 KiB
Raw Blame History

ba-auto-daily implementation plan

Personal Blue Archive JP daily-automation project. CLAUDE.md is the authoritative, actively-maintained reference for architecture, deployment, conventions, and the incident history behind current design decisions — read it first. This file is intentionally scoped to forward-looking work only: the not-yet-implemented backlog and active improvement plans. It no longer carries a phase-by-phase changelog; that history (30+ phases of live-testing retrospectives) has been retired now that every feature it covered has shipped and CLAUDE.md's "Existing features" section carries the load-bearing lessons from it.

The reference implementation lives at ~/repo/baas-reference/ (read-only — study and adapt, never edit). See ba_auto/reference_notes/mapping.md for the current, maintained local-feature → reference-module mapping table.

Currently implemented (for context, not a todo list)

login, mailbox, cafe, stamina, gem_shop, circle, battle_pass, story_sweep/story_sweep_force, story_sweep_hard/story_sweep_hard_force, event_sweep, shop_common, shop_tactical, lesson, arena, bounty, scrimmage, exit_game — see ba_daily.py's TASKS dict for the exact CLI surface and CLAUDE.md's "Existing features" section for behavior/known gaps.

Backlog — not yet implemented

Commissions (Base Defense + Item Retrieval)

Reference: ~/repo/baas-reference/module/clear_special_task_power.py Local target: ba_auto/tasks/commission.py

Two sub-dungeons. OCR: port the reference's approach if it uses OCR here — do not default to a fixed-target workaround just to avoid OCR (see CLAUDE.md's OCR policy).

Crafting

Reference: ~/repo/baas-reference/module/create.py Local target: ba_auto/tasks/crafting.py

Very complex — material selection, priority lists, rarity tiers, stepper/quantity UI, filtering/sorting, OCR-like decision points. Do not start until there's a concrete need; this is the most complex remaining reference module.

Momo Talk

Reference: ~/repo/baas-reference/module/momo_talk.py Local target: ba_auto/tasks/momo_talk.py

Runs on a different cadence from daily reset, which is why it's still worth doing despite being low-value. Likely no OCR — mostly state scanning and click flow.

Main story push (new-stage clearing, not sweeping)

Reference: ~/repo/baas-reference/module/main_story.py, ~/repo/baas-reference/module/explore_tasks/explore_task.py

Distinct from story_sweep/story_sweep_hard (which only re-sweep already-cleared stages). Low priority — full grid-mode support needs a lot of per-stage scripting; a simple auto-fight-only mode could be a smaller first cut. No reusable auto-fight primitive exists yet — arena.py implements its battle-commit/result-detection inline rather than as a shared module, so this would either need extracting that or building fresh.

Group Story / Mini Story

Reference: ~/repo/baas-reference/module/group_story.py, ~/repo/baas-reference/module/mini_story.py

Convenience only, low priority.

Event content beyond the AP sweep panel

event_sweep.py already covers the sweep panel for a currently-running event (see CLAUDE.md). Still not built: explore_activity_story/explore_activity_mission/explore_activity_challenge (walking the event's map / fighting stages manually — only needed for a stage that hasn't been SSS-cleared yet) and exchange_reward (the reward-exchange shop). Event-specific content expires, so any calibration work here (stage-count, row positions) is only valid for whichever event is running at the time.

Daily Free Power

Reference: ~/repo/baas-reference/module/collect_daily_free_power.py

Deliberately deferred, not merely unstarted — its entry point is a real-money purchase menu, and automating it needs explicit user confirmation before any implementation attempt.

Skip list

Feature Why skip
Total Assault / Raid Low value and risky to automate. Reference support may be limited/stubbed.
Joint Firing Drill Not worth prioritizing for JP if reference has server-specific limitations.
De-clothes localization toggle CN-only / irrelevant.
Restart / refresh-uiautomator2 Android/ADB backend maintenance, not applicable to PC/Steam/Proton.
Auto-unfriend Risky, low value, destructive.
Daily minigame dispatcher Event-specific and unstable. Handle ad hoc only.

Performance improvement plan (opened 2026-08-14)

Prompted by a request to review real cron run logs (scratchpad/ba_logs/{daily,q4h}.log, pulled from nik-gpu, covering 3 q4h runs + 2 daily runs on 2026-08-14) for where automation time actually goes and what's worth speeding up. Timestamps come from the per-line logging added in the "timestamped log output" work (see git history / CLAUDE.md's log-format notes).

Measured totals

Run Total Notes
q4h #1 (10:00) 9m56s
q4h #2 (13:00) 8m45s
q4h #3 (17:00) 9m13s
daily #1 (03:30) 15m32s
daily #2 (04:30) 27m20s full run, 7 lesson tickets spent

Finding 1 (top priority, not yet implemented): lesson.py re-screenshots per cell instead of per region

In the 27m20s daily run, lesson alone took 9m50s (36% of the run), and ~7 minutes of that is the "scanning all regions" phase — 12 regions × ~30-38s each — that runs before any ticket is spent, just to build the priority queue.

Root cause, confirmed by reading the code: _scan_open_grid_cells (ba_auto/tasks/lesson.py:196) loops 3 rows × 3 cols × 3 slots = 27 cells per region, and _read_slot_affection (lesson.py:185) calls both detector.region_contains_color (checkmark check) and, if not done, detector.read_int_on_heart_badge (OCR). Both independently call driver.read_screenshot(), and read_screenshot() fires a brand-new scrot capture every call (ba_auto/driver.py:97-127) — there's no reuse of a prior frame. That means a single region scan can trigger up to ~50 fresh scrot processes against a screen that hasn't changed at all between them (no clicks happen mid-scan, per _scan_all_regions's own docstring: "a pure read, spends no tickets").

Proposed fix: take one screenshot per region (or even once for the whole scan pass, if nothing changes on-screen until a click happens), decode it once, and pass the decoded image into the per-cell checkmark/OCR reads instead of each one re-capturing. This is a pure efficiency fix — the detection logic itself (color masking thresholds, heart-badge OCR contamination handling) doesn't change at all, so it doesn't touch anything CLAUDE.md's OCR policy cares about. Expected to cut the scan phase from ~7 minutes to well under a minute.

Scope note: _run_queue's actual ticket-spending clicks (lesson.py:306) happen between scans, so only the scan phase's screenshots are provably safe to batch this way — anything read after a click still needs a fresh capture.

Finding 2 (secondary, informational — do not touch without care): event_sweep is called 2-4x per run by design

ba_daily.py's daily preset calls event_sweep four times, q4h twice (ba_daily.py:132-144) — deliberately, per the preset's own comment, "to re-check a rotating target" as AP regenerates from circle/gem_shop/battle_pass claims during the run. Each call that doesn't short-circuit on insufficient AP costs 56s-153s in the logs, mostly navigation to the event badge/page. Total event_sweep cost across a run's multiple calls ranged from ~112s (2 skips + 2 clean 56s sweeps) to ~430s (3 calls, one hitting the slow "wrong page" retry path) in the sampled runs.

This is not recommended as a fix target right now: the retry/settle budget the "wrong page" path uses (badge-carousel navigation, cold-start OCR settle time) was tuned across many rounds of real live-testing failures before it reached its current reliability — shrinking it risks reintroducing missed/silently-failed sweeps, which is a strictly worse outcome than a slow-but-correct run. If run time here ever needs to come down, the safer lever is reducing how many times event_sweep is invoked per run (e.g. consolidating to fewer, better-timed calls once AP-granting tasks have run) rather than shrinking any per-call retry/wait constant.

Other observations (not action items)

  • cafe's pat-loop panning cost (~4-5 min/run) is inherent to the sparkle-hunt approach and matches reference behavior — not a target.
  • shop_common's full-grid OCR name scan costs ~100-120s/run when most/all configured items are sold out — inherent to the OCR-based item-identification fix from the sold-out-reordering incident (see CLAUDE.md's Common Shop notes); not a target without changing correctness guarantees.