deckhearth/.convoys/scanner-desktop-layout/brief-5-batch-identify-helper.md
varutasu 938c161a26
feat(scanner): add desktop workstation layout (#165)
Give /scanner a md+ camera, live match inspector, and history strip
(with device picker, batch scan, and tips) without regressing the
mobile immersive checkout.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-15 17:21:23 -05:00

3 KiB

convoy brief_number depends_on recommended_model model_tier files cross_brief_commitments
scanner-desktop-layout 5
composer-2.5-fast fast
lib/scanner-batch-identify.js
test/lib/scanner-batch-identify.test.js
brief description
6 Brief 6 calls `runSequentialGalleryIdentify(files, identifyFn, options)` from the Batch Scan multi-file picker. On per-file failure Brief 6 enqueues a queue row with `identifyFailed: true` and `identifyError` message; cancel via `cancelRef.current = true` keeps completed rows (IA-locked).

Brief 5: Sequential batch identify helper

Goal (1 sentence)

Add a small library helper that runs identifyFromGalleryFile sequentially over multiple files with progress, cancel, and per-file failure continuation.

Files in scope (do not edit anything else)

  • lib/scanner-batch-identify.js
  • test/lib/scanner-batch-identify.test.js

Conventions to follow

  • No new API routes — caller passes identifyFn (Brief 6 binds identification.identifyFromGalleryFile).
  • Sequential only — one await identifyFn(file) at a time; no Promise.all.
  • Respect identify rate limits implicitly (sequential pacing).
  • Pure JS module — no React.

Implementation shape

/**
 * @typedef {{ current: number, total: number, file: File }} BatchProgress
 */

export async function runSequentialGalleryIdentify(files, identifyFn, options = {}) {
  const {
    onProgress,
    onFileSuccess,
    onFileError,
    cancelRef = { current: false },
  } = options;

  const list = Array.from(files || []);
  const total = list.length;
  const results = [];

  for (let i = 0; i < list.length; i++) {
    if (cancelRef.current) break;
    const file = list[i];
    onProgress?.({ current: i + 1, total, file });

    try {
      await identifyFn(file);
      results.push({ file, ok: true });
      onFileSuccess?.({ file, index: i });
    } catch (error) {
      results.push({ file, ok: false, error });
      onFileError?.({ file, index: i, error });
      // continue — IA forbids stopping the batch
    }
  }

  return { results, cancelled: cancelRef.current };
}

identifyFn may not throw today — helper still catches for forward-compat. If identifyFromGalleryFile only reports via console, Brief 6 may wrap it to throw on hard failures.

Acceptance criteria

  • Processes files one-at-a-time in order
  • onProgress fires before each file with { current, total, file }
  • cancelRef.current = true stops remaining files but returns partial results
  • Per-file errors invoke onFileError and continue loop
  • tests cover success path, mid-batch cancel, and error continuation
  • no scope expansion (do not edit files outside files: above)

Rationale (≤3 sentences)

Batch Scan (C1) needs orchestration without touching use-scanner-identification.js identify logic. A 60-line pure helper is testable and keeps the page brief focused on UI wiring. Sequential execution avoids Gemini rate-limit storms explicitly forbidden in scope.