ba-auto-daily/plan.md

109 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 (implemented 2026-08-14): `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").
**Fix:** `detector.py` gained an optional `image=` parameter on `region_contains_color`/`read_int_on_heart_badge` (default `None`, so every other caller — `shop_utils.py`, `story_sweep.py`, `story_sweep_hard.py`, `cafe.py` — is unaffected) plus a `capture_screen()` helper. `lesson.py`'s `_scan_open_grid_cells` now takes one screenshot per region and threads it through all 27 checkmark/OCR reads instead of each one re-capturing. Pure efficiency fix — the detection logic itself (color masking thresholds, heart-badge OCR contamination handling) is untouched.
**Scope respected:** `_run_queue`'s actual ticket-spending clicks (`lesson.py:306`+) still take a fresh screenshot per check, exactly as before — batching only applies to the pure-read scan phase.
**Live-verified 2026-08-21** against a full week of real `daily` cron runs (2026-08-15 through 2026-08-21, 14 runs, all exit 0, zero `[lesson]` warnings/errors). Full 12-region scan phase now consistently takes ~3m27s, down from the ~7m2s baseline — a ~51% cut, exactly from removing the redundant per-cell `scrot` calls (per-region time dropped from ~30-38s to ~17-18s).
### Finding 1b (implemented 2026-08-14): stop scanning once triples alone cover the ticket count
Added alongside Finding 1: `_scan_all_regions` now takes `tickets` and tracks a running triple count, breaking out of the region loop once `triple_count >= tickets`. This is provably behavior-preserving, not just a heuristic: `_build_priority_queue` never reorders within a tier (triples/doubles stay in scan order) and `_run_queue` stops the instant tickets hit 0, so once enough triples are found, any cell in an unscanned region could only ever land after the ticket budget is already exhausted — `_run_queue` would never reach it either way. The queue actually executed is identical to a full scan's; only the number of regions looked at changes. When tickets exceed available triples, the condition never fires and behavior is unchanged (full scan, as today). One cosmetic side effect: the "N triple(s), M double(s), K single(s)" summary log line under-reports M/K when this fires, since those regions were never examined — expected, not a bug.
**Live-verified 2026-08-21**, same week of runs: fired correctly on 2 of 7 ticket-available days (2026-08-18: 7 triples found by region 9/12, skipped the remaining 3; 2026-08-21: 7 triples by region 10/12, skipped 2), and correctly stayed a full 12-region scan on the other 5 days where triples never reached the ticket count. Combined with Finding 1, total `lesson` task duration (start to `Done.`) ranged 5m6s-6m41s across the week, down from the 9m50s baseline.
### 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.