# TASK-003 — Emulator basket worker

**Status:** In progress (code complete; manual spike + Ops migrate on Docker pending)
**Branch:** feature/TASK-003-emulator-worker
**Started:** 2026-10-06
**Last updated:** 2026-10-12

## Goal
Per-user Android emulators (Sixty60, PnP ASAP, Woolworths) provisioned from a golden image; in-app setup wizard; after Paystack checkout a Python worker builds retailer baskets via uiautomator2 (Phase 1 stops at cart, no retailer payment).

## Acceptance criteria
- [x] Golden AVD created; spike doc + manual Play Store gate documented
- [x] Ops: migrations, customer + worker APIs, order enqueue hook (migrate not run locally — Docker off)
- [x] `emulator_worker/` poll loop, jobs, drivers, pytest
- [x] Flutter `/setup` wizard + order basket status
- [x] `flutter test` + pytest green; PHPUnit pending Docker

## Files touched
| File | Notes |
|------|-------|
| `emulator_worker/drivers/sixty60.py` | Real selectors, live-verified |
| `emulator_worker/drivers/pnp_asap.py`, `woolworths.py`, `ui.py`, `creds.py` | PnP/Woolworths drivers + shared UI helpers |
| baskit_ops migration `2026-10-06-140000_AddEmulatorLoginSecrets.php` | One-shot encrypted login secrets |
| `lib/features/setup/setup_stores_step.dart`, `emulator_status.dart`, `api_client.dart` | Per-retailer connect forms |
| `emulator_worker/**` | Python worker package |
| `lib/features/setup/*` | Setup wizard |
| `lib/models/emulator_status.dart` | Status models |
| `lib/core/api_client.dart` | Emulator + basket APIs |
| `lib/main.dart` | Deferred `/setup` route |
| `test/api_client_emulator_test.dart` | API client tests |
| `test/setup_model_test.dart` | SetupModel tests |
| `test/setup_flow_test.dart` | Store step widget tests |
| `docs/emulator_spike.md` | Host + AVD spike |
| `scope/Task_emulator_worker.md` | Scope + test cases |
| `scope/email/Task_emulator_worker.md` | Stakeholder email |
| `docs/CHANGELOG.md`, `docs/NewKnowledgeBase.md`, `README.md` | Docs |
| baskit_ops (sibling) | Migration, services, routes, PHPUnit tests |

## Decisions
- 2026-10-06 — Poll-based worker (not DB push) — laptop behind NAT.
- 2026-10-06 — Phase 1 basket-only; PAYMENT_WORDS guard in drivers.

## Session log
### 2026-10-06 — Cursor
- Did: Step 0 branch + task file; implementing build spec.
- Commits: (pending)

### 2026-10-06 — Cursor (continued)
- Did: Ops schema/API/hook in baskit_ops; emulator_worker + Flutter wizard; fixed emulator API tests; setup model/flow tests; scope + CHANGELOG + README + NewKnowledgeBase; 67 flutter tests + 5 pytest passed.
- Broke / deferred: Docker down — no `php spark migrate` or PHPUnit; Step 1 manual Play Store + uiautomator2 proof; full E2E + TestSprite.
- Commits: (pending)

### 2026-10-06 — Cursor (device spike)
- Did: verified package names for all 3 apps; GPS geo-fix after boot; logged in to Sixty60 on a golden clone (phone → OTP → DOB → home); replaced placeholder selectors in `drivers/sixty60.py`; live-tested ensure_logged_in / clear / search / add ×2 / read basket / clear on the clone (R57.98 → R0.00). Never touched Checkout.
- Broke / deferred: Sixty60 asks DOB after OTP on a new device — not wired through wizard/Ops (driver raises `dob_required`). PnP + Woolworths selectors still placeholders. Docker still down.
- Commits: (pending)

### 2026-10-06 — Cursor (PnP + Woolworths + wiring)
- Did: PnP + Woolworths device spikes (login, search, cart); standalone `pnp_asap.py` / `woolworths.py` + `drivers/ui.py` + `LoginCreds`; Sixty60 DOB via wizard one-shot secret; Ops migration `login_secret` / `login_email`; Flutter per-retailer forms; 7 pytest (non-live) + setup Flutter tests green.
- Broke / deferred: Docker still down (migrate + PHPUnit + TestSprite E2E); golden AVD reset; clone `baskit_u9001` still holds sessions.
- Commits: (pending)

### 2026-10-12 — Cursor (TASK-006 split)
- Did: Worker extracted to [overdrive/emulator_worker](https://bitbucket.org/overdrive/emulator_worker); baskit_app docs updated; `emulator_worker/` removed here.
- Broke / deferred: E2E still blocked on dedicated host + Ops migrate (unchanged).

## Next steps
1. Start Docker → `php spark migrate` in baskit_ops (includes `2026-10-06-140000_AddEmulatorLoginSecrets`) → PHPUnit.
2. Deploy worker from `emulator_worker` repo on dedicated host; Ops `WORKER_ALLOWED_IPS` + `EMULATOR_WORKER_KEY`.
3. Run worker + Flutter full E2E (setup all 3 stores, Paystack test order, basket status).
4. Reset `baskit_golden` to clean first-launch; retire test clone when E2E passes.
5. Rotate retailer test password (was shared in chat during spike).

## Open questions
- Retailer ToS / emulator detection — report to stakeholders before production use.
