--- name: scanner-correctness-polish classification: infra-only success_metric: | Mark-Owned is idempotent (in-flight lock per queue row); bulk toolbar no longer uses setTimeout(..., 100); pages/scanner.js imports lib/use-auth not legacy auth-context; POST /api/collections/[identifier]/cards calls logCollectionActivity('card_added', …). skip: - ia - ux - visual - a11y - design status: shipped created: 2026-05-27 --- # Convoy: scanner-correctness-polish **As-shipped:** PR #41 (2026-05-27). Idempotent Mark-Owned, bulk toolbar race fix, `lib/use-auth` import, activity logging. Fix scanner-page correctness bugs without changing UX or visual design. ## Why The scanner audit surfaced non-security bugs that cause duplicate adds, racey bulk actions, a stale auth import, and missing activity logs. These are small fixes with high reliability impact during bulk scanning sessions. ## Scope ### In scope - **`pages/scanner.js`** - Line 8: change import from legacy `lib/auth-context` to `lib/use-auth` (should have been swept by `single-auth-provider`; scanner was missed or regressed). - **Mark-Owned idempotency** — in-flight lock per queue row so double-tap / double-click cannot duplicate POSTs. - **Bulk toolbar** — remove `setTimeout(..., 100)` race; await or use proper batch completion signal. - **`pages/api/collections/[identifier]/cards.js`** — POST handler calls `logCollectionActivity(collectionId, userId, 'card_added', details)` per AGENTS.md convention. ### Out of scope - **Scanner UX redesign** — convoy `redesign-scanner-flow` (#4). - **Copy / vocabulary** — convoy `rename-collections-vocabulary` (#5). - **OCR / identify pipeline** — convoys #2–#3. - **Visual or a11y changes** — none intended; diff should be behavior-only. ## Roles invoked 1. `role-architect` — single brief (lightweight; may be parent-owned given infra-only classification). 2. `role-implementer` — one brief. 3. `role-reviewer` — post-PR only (design + a11y skipped). ## Todos - [ ] Architect: brief-1 with exact line targets - [ ] Fix use-auth import on scanner page - [ ] Add per-row in-flight lock for Mark-Owned - [ ] Replace setTimeout bulk-toolbar pattern - [ ] Wire logCollectionActivity on collection card POST ## Operator action required **None.** ## Multitask dispatch Single brief — no implementer fan-out. **Cross-convoy parallelism:** after #1 merges, run alongside **#2 Brief 1** and **#5 Brief 1** — disjoint files (`pages/scanner.js` vs migrations vs copy sweep). Coordinate if both #6 and #5 touch `pages/scanner.js` (IA should sequence copy sweep after correctness or split files in briefs). Post-PR audit: ``` /multitask role-reviewer ``` Group id: `audit-scanner-correctness-polish-`. ## CI impact | Workflow / job | Behavior | | --- | --- | | `ci.yml` | Standard lint + vitest; no new gates. | | `preview-smoke.yml` | Fires. | | `visual-diff.yml` | **May fire** if `pages/scanner.js` changes — behavior-only diff should not move pixels; baseline swallow if triggered. | ## Known constraints - **`logCollectionActivity` import** — use existing helper from permission-middleware or documented activity module; match sibling handlers. - **No UX copy changes** — button labels stay as-is until #5 (or avoid overlapping scanner.js edits between #5 and #6). ## Acceptance criteria 1. `pages/scanner.js` imports from `lib/use-auth` only. 2. Double-click Mark-Owned produces one POST. 3. Bulk toolbar actions complete without setTimeout race. 4. Collection card POST emits activity log row. 5. Vitest 21/21; lint baseline preserved.