# Goofish Login UX, Browser Lock, and Partial-Result Recovery — 2026-05 ## What happened During a Goofish/Xianyu search task, a temporary helper opened a direct Taobao unified-login URL and sent its screenshot as a "real login QR". BOSS correctly objected that it looked like a Taobao login page and not the expected Xianyu entry. Goofish web login is backed by Alibaba/Taobao account infrastructure, so `login.taobao.com` can be normal after following the Goofish login flow. However, for BOSS UX, do **not** present a direct Taobao URL/screenshot as if it were the Xianyu login entry. ## Preferred login workflow 1. Start/keep the dashboard service. 2. Open `https://www.goofish.com/` in the persistent Playwright profile (`browser-data/`). 3. Let BOSS interact with the visible browser window and click the Goofish page's own login/modal/QR controls. 4. If a screenshot is needed, label it accurately: "Goofish page login/modal; may redirect to Taobao unified login". 5. After BOSS says login is done, close any temporary helper Chromium using the same profile before running task automation. 6. Verify with `GET /api/login/status` against a real search page, not homepage only. ## Pitfall: ProcessSingleton / SingletonLock If a temp QR/login helper is still using `browser-data/`, later dashboard/API/task runs may fail with: ```text browserType.launchPersistentContext: Failed to create a ProcessSingleton for your profile directory ... browser-data/SingletonLock: File exists (17) ``` Safe recovery used in this session: ```bash cd /Users/chick/.Hermes/workspace/research/xianyu-hunter pkill -f 'xianyu_goofish_login_entry_tmp.mjs|xianyu_qr_login_tmp.mjs' || true pkill -f 'Google Chrome for Testing.*xianyu-hunter/browser-data' || true sleep 2 for p in $(lsof -tiTCP:3000 -sTCP:LISTEN 2>/dev/null); do kill "$p" 2>/dev/null || true; done sleep 1 PORT=3000 node server.mjs ``` Then verify: ```bash curl -sS -m 60 http://127.0.0.1:3000/api/login/status | python3 -m json.tool ``` A good result includes `loggedIn: true`, `loginWall: false`, nonzero `cookieCount`, and product cards on a search URL. ## Partial-result recovery If a run is interrupted during `fine_filter`, `tools/hermes_report.mjs` may report `候选 0` because it only sees `fineFiltered`. Do not conclude there were no products. Inspect `data/tasks.json` and mine `products.coarseFiltered` or `products.raw` directly. Example used for E3-1245v3: ```bash python3 - <<'PY' import json,re from pathlib import Path p=Path('data/tasks.json') data=json.loads(p.read_text()) t=[x for x in data if x.get('id')==''][0] items=t.get('products',{}).get('coarseFiltered',[]) or t.get('products',{}).get('raw',[]) def price_num(v): m=re.search(r'(\d+(?:\.\d+)?)', str(v or '').replace(',','')) return float(m.group(1)) if m else None for it in items: title=(it.get('title') or '').lower().replace('-',' ') text=' '.join(str(it.get(k,'')) for k in ['title','description','detailDescription']).lower() if '1245' in title and 'v3' in title and not any(w in text for w in ['回收','求购','主板','套装','整机','散热','维修','不包含 cpu']): print(it.get('price') or it.get('detailPrice'), it.get('location') or it.get('sellerLocation'), it.get('title'), it.get('href') or it.get('url')) PY ``` ## Presentation guidance When reporting results to BOSS: - State the live status first (login ok, task id, counts raw/coarse/fine, whether run completed or was interrupted). - If a report says 0 candidates but raw/coarse has data, explicitly explain that this is a stage/report limitation. - Rank candidates by closeness to budget and risk, and call out exclusions (e.g. "不包含 CPU", "不能进系统", "回收", "主板套装").