Files
BIPMaterialManager/docs/plans/2026-04-17-cleaner-video-recording-design.md

10 KiB

Cleaner Video Recording Design

Date: 2026-04-17

Summary

Add an optional video recording capability to the Cleaner execution flow. When enabled, the system records the ERP detail-page handling process for each order and stores videos under logs/clearner-video-records/<batchId>/. Videos are retained only for orders whose final persisted status is not success; videos for successful orders, including orders that failed initially but succeeded after retry, are deleted automatically.

This design is based on the current Cleaner architecture:

  • The execution setting panel already exposes Cleaner-only settings in CleanerExecutionBar.
  • processConcurrency is already persisted through window.electron.config.updateCleaner(...) into config.yaml.
  • Cleaner history is already persisted per batchId + attemptNumber + orderNumber in CleanerOrderHistory.
  • Each order detail is handled in a separate Playwright popup page, which matches the requirement of "one order, one video file" at the page level.

Goals

  • Add a new execution setting to control whether Cleaner records videos.
  • Persist that setting using the same config path as processConcurrency.
  • Save videos under logs/clearner-video-records/<batchId>/.
  • Use order number as the logical file name.
  • Keep all videos for orders whose final order history status is non-success.
  • Delete videos for orders whose final order history status is success.
  • Preserve multiple videos for the same order when retry attempts also fail, using an incrementing suffix.

Non-Goals

  • No video playback UI in the current PRD scope.
  • No database schema change is required if file retention is derived from existing Cleaner history state.
  • No cross-run deduplication is required because batchId already isolates one execution.

Current Code Facts

Execution Settings

  • CleanerPage.tsx reads execution settings from useCleaner().
  • CleanerExecutionBar.tsx already renders:
    • dryRun
    • headless
    • processConcurrency
  • useCleaner.ts persists processConcurrency through window.electron.config.updateCleaner({ processConcurrency }).
  • config:getCleaner / config:updateCleaner are already exposed through IPC and stored in config.yaml.

Cleaner Runtime

  • CleanerApplicationService.runCleaner(...) creates a batchId, inserts execution history, runs Cleaner, then calls saveAttemptToDatabase(...).
  • saveAttemptToDatabase(...) writes per-order final state through historyDao.updateOrderStatus(...).
  • Order status currently resolves to:
    • success when detail.errors.length === 0
    • failed when detail.errors.length > 0
    • erp_not_found when detail.notFound === true
  • Retry success is recorded via RetrySuccess = 1, but the order Status still becomes success.

Retry Model

  • Inner retry: failed orders are retried inside the same execution attempt by CleanerService.retryFailedOrders(...).
  • Outer retry: when the whole run crashes, CleanerApplicationService creates attempt 2 and writes a second set of CleanerExecution and CleanerOrderHistory records.
  • Therefore the natural identity for one recorded video is:
    • batchId
    • attemptNumber
    • orderNumber
    • retry sequence within the same attempt, if multiple failed recordings must be kept

Product Rules

User-Facing Behavior

  • Add a new toggle in 执行设置: 录制处理视频.
  • Default value: false.
  • Persist the value in Cleaner config, same as processConcurrency.
  • When disabled, Cleaner behavior is unchanged.
  • When enabled, the system records the per-order ERP detail-page process.

Storage Rules

  • Root path: logs/clearner-video-records/<batchId>/
  • One execution batch corresponds to one directory.
  • The logical base name is the order number.
  • If the same order has multiple retained failed runs in the same batch, append a numeric suffix:
    • SC20260101000123.webm
    • SC20260101000123__2.webm
    • SC20260101000123__3.webm
  • File extension should follow the actual Playwright video output format.

Retention Rules

  • If final persisted order status is success, delete all videos for that order in the current batch and current attempt chain.
  • If an order fails once and then succeeds on retry, do not keep any video for that order.
  • If an order fails and all retries fail, keep every recorded video for that order.
  • If an order resolves to a non-success terminal status such as failed or erp_not_found, keep the video.
  • If recording setup fails, Cleaner execution must continue; recording is diagnostic, not blocking.

Config Changes

Add a new Cleaner config field:

cleaner: {
  queryBatchSize: number
  processConcurrency: number
  recordVideo: boolean
}

Required touch points:

  • src/main/types/config.schema.ts
  • src/main/services/config/config-manager.ts default config
  • src/preload/index.d.ts
  • src/preload/api/materials.ts
  • renderer Cleaner config loader / updater

Input Flow

Pass recordVideo from renderer to main:

CleanerExecutionBar
  -> useCleaner
  -> runCleanerExecution(...)
  -> window.electron.cleaner.runCleaner(...)
  -> CleanerApplicationService.runCleaner(...)
  -> CleanerService.clean(...)

This allows the run to decide per batch whether recording is enabled.

Recording Strategy

Recommended approach:

  1. Enable Playwright context-level video recording only when recordVideo === true.
  2. Record all popup detail pages created during Cleaner execution.
  3. After each detail page closes, resolve the generated Playwright video file path.
  4. Move or rename that file into logs/<batchId>/ using the order-based naming convention.
  5. Defer final retention cleanup until the order's final persisted result is known.

Reasoning:

  • Current code creates one BrowserContext in ErpAuthService.login().
  • Each order detail is processed in a separate popup Page.
  • Playwright video is page-based under a recorded context, so this aligns with the current "one detail page, one video" architecture.

Inference: This should allow one raw video file per detail popup page without forcing a redesign to one context per order. The implementation still needs a small proof-of-concept to confirm popup-page video behavior in this ERP flow.

Video File Registry

Add an in-memory registry for the current batch, for example:

type CleanerVideoArtifact = {
  batchId: string
  attemptNumber: number
  orderNumber: string
  sequence: number
  tempPath: string
  finalPath: string
}

The registry should support:

  • tracking all videos produced for one order
  • deleting all videos for a finally successful order
  • preserving all videos for a finally failed order
  • handling both inner retry and outer retry attempts cleanly

Retention Timing

Recommended retention point:

  • perform final keep/delete cleanup after saveAttemptToDatabase(...) finishes for the attempt
  • use the same final status logic as historyDao.updateOrderStatus(...)

Why this is safer:

  • it matches the persisted truth used by history UI
  • it avoids deleting a video too early before retry outcome is known
  • it keeps product behavior aligned with your rule: final success means no video retained

Edge Cases

Retry Success

Case:

  • first processing fails and produces video A
  • retry succeeds and produces video B
  • final order status is success

Expected behavior:

  • delete A
  • delete B

Retry Failure

Case:

  • first processing fails and produces video A
  • retry 1 fails and produces video B
  • retry 2 fails and produces video C
  • final order status is failed

Expected behavior:

  • keep A, B, C

ERP Not Found

Case:

  • order query returns no detail page / cannot enter ERP detail page

Expected behavior:

  • if no page exists, there may be no video file to keep
  • final order status remains non-success
  • PRD should accept "no video generated" as valid when the detail page never opened

Outer Retry

Case:

  • attempt 1 crashes mid-run
  • attempt 2 reruns orders

Expected behavior:

  • videos must stay isolated by attemptNumber
  • cleanup must never delete attempt 2 videos because of attempt 1 status, or vice versa

UI Changes

  • In CleanerExecutionBar.tsx, add a new toggle block below 后台模式 (Headless) and above 并行处理数量.
  • Suggested label: 录制处理视频
  • Suggested help text: 为每个订单详情页生成视频,仅保留最终失败订单的视频

Implementation Breakdown

Area Change
Renderer Add recordVideo state, config loading, config persistence, execution payload field
Preload Extend CleanerConfig IPC typing and configApi usage
Main config Add cleaner.recordVideo schema and default value
Cleaner input types Extend CleanerInput with recordVideo?: boolean
ERP auth / browser context Conditionally enable Playwright video recording
Cleaner runtime Capture per-detail-page video artifacts and map them to orderNumber
Application service Run final video retention cleanup after order statuses are persisted
Logging Add diagnostic logs for recording enabled, file move, delete, retention outcome

Open Questions

  1. Should dry-run mode also support video recording? Current recommendation: yes, because dry-run is often used for diagnosis.
  2. Should login page and top-level query popup videos be retained? Current recommendation: no, only order detail page videos participate in naming and retention.
  3. Should we expose retained video paths in operation history UI later? Current recommendation: not in this scope, but keep naming stable to support a future enhancement.

Acceptance Criteria

  • The execution settings panel contains a persistent 录制处理视频 switch.
  • config.yaml stores cleaner.recordVideo.
  • When the switch is off, no video files are generated.
  • When the switch is on, videos are generated under logs/clearner-video-records/<batchId>/.
  • Final successful orders leave no retained video files.
  • Orders that remain failed retain all their recorded videos.
  • Multiple retained videos for the same order are distinguishable by suffix.
  • Recording failures do not interrupt Cleaner execution.