Files
FT546MWS/docs/superpowers/plans/2026-07-22-ft546-tidy-and-batch-replay.md

45 KiB

FT546 Tidy Workflow and Historical Batch Replay Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Add persisted automatic/manual tidy execution with exclusive manual mode, then prove inbound, outbound, relocation, and tidy correctness by replaying site history through simulated PDA/WCS interfaces.

Architecture: Keep TidyPlanner pure in fortucky-algorithm and add WMS-specific persistence/orchestration under ruoyi-admin/com/ruoyi/algorithm/wms/tidy. SQL Server is authoritative for mode, queues, workflows, callback events, and locks; all legacy and algorithm allocation routes pass through one admission service. WCS exposes a read-only vehicle snapshot, while a run-scoped simulator and PowerShell harness drive the development-database replay and reconciliation.

Tech Stack: Java 17, Spring Boot, Spring transactions/scheduling, MyBatis, SQL Server, JUnit 5, Mockito, AssertJ, Vue 2 + Element UI, Node.js built-in HTTP server, PowerShell 7/System.Data.SqlClient.

Global Constraints

  • Work in D:/workSpace/PROJECT_SPACE/FT546/FT546MWS/FT546MWS for WMS and D:/workSpace/PROJECT_SPACE/FT546/FT546-WCS for WCS; both are dirty repositories, so never revert or stage unrelated changes.
  • Preserve the fortucky-algorithm module boundary and the configured WMS primary DataSource/PlatformTransactionManager.
  • Keep the normal deployment default FORTUCKY_ALGORITHM_MODE=SHADOW; only the confirmed development database may use the run-scoped replay override.
  • Automatic tidy runs only in NORMAL, never alongside inbound/outbound/outbound-relocation work, and has a global maximum of one active workflow.
  • Manual mode follows NORMAL -> ENTERING_TIDY -> TIDY_ACTIVE -> EXITING_TIDY -> NORMAL; business documents remain accepted but execution allocation is blocked outside NORMAL.
  • Manual capacity is online + healthy + (idle or already assigned to manual tidy) minus active manual workflows; safety predicates and resource locks override capacity filling.
  • Every move job with in_or_out=28 must resolve to exactly one origin: AUTO_TIDY, MANUAL_TIDY, or OUTBOUND_RELOCATION.
  • Do not delete or mutate imported finish tables. Before live replay, create and verify a new restorable backup after migrations; restore it after evidence generation.
  • Implement every production change test-first and commit only exact task paths.

File Structure

WMS algorithm and persistence

  • Modify fortucky-algorithm/src/main/resources/db/sqlserver/install.sql: idempotent outbound/tidy schema, queue handoff, resource locking, and sequence synchronization procedures.
  • Modify fortucky-algorithm/src/main/resources/db/sqlserver/diagnostics.sql: mode/workflow/queue/origin/lock integrity diagnostics.
  • Modify fortucky-algorithm/src/main/resources/db/sqlserver/uninstall.sql: reverse only new algorithm objects in dependency order.
  • Modify fortucky-algorithm/src/test/java/com/ruoyi/algorithm/repository/SqlServerMigrationScriptTest.java: migration contract tests.
  • Modify fortucky-algorithm/src/main/java/com/ruoyi/algorithm/integration/AlgorithmProperties.java: tidy scan/reconcile/lease and WCS snapshot URL configuration.
  • Modify fortucky-algorithm/src/main/java/com/ruoyi/algorithm/integration/SchedulingFacade.java: expose planTidy without adding WMS persistence to the algorithm module.

WMS tidy runtime

  • Create ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyEffectiveState.java: persisted mode enum.
  • Create ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyOrigin.java: job/workflow origin enum.
  • Create ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/ExecutionWorkType.java: gate input enum.
  • Create ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyModeSnapshot.java: immutable status DTO.
  • Create ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyWorkflowState.java: mapper projection for workflow/step state.
  • Create ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/VehicleSnapshot.java: per-vehicle WCS contract.
  • Create ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyVehicleCapacity.java: capacity calculation.
  • Create ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyModeService.java: switch transitions and startup reconciliation.
  • Create ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/ExecutionAdmissionService.java: shared business/tidy admission gate.
  • Create ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/ExecutionBlockedByTidyModeException.java: stable blocked-allocation exception.
  • Create ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyWorkflowStarter.java: scheduler-to-coordinator boundary.
  • Create ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/WcsTaskState.java: restart-reconciliation WCS task state.
  • Create ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyWorkflowTransaction.java: transactional claim, job creation, callback, recovery, and release.
  • Create ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyWorkflowCoordinator.java: automatic singleton and manual capacity filling.
  • Create ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyScheduler.java: 10-minute automatic scan and short mode reconciliation.
  • Create ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/WcsVehicleSnapshotClient.java: production WCS snapshot adapter.
  • Create ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/ReplayExecutionGuard.java: validates a run-scoped ACTIVE process against DB_NAME() before writes.
  • Modify ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/WmsAlgorithmMapper.java and ruoyi-admin/src/main/resources/mapper/algorithm/WmsAlgorithmMapper.xml: all tidy SQL operations and origin queries.
  • Modify ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/WmsInboundAllocationService.java and WmsOutboundAllocationService.java: shared gate before algorithm and legacy paths.
  • Modify ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/OutboundWorkflowTransaction.java: origin linkage and shared resource admission.
  • Modify ruoyi-admin/src/main/java/com/ruoyi/api/service/impl/ToWmsServiceImpl.java: route idempotent job-finish callbacks to outbound then tidy coordinators.

WCS capacity endpoint

  • Create FT546-WCS/ruoyi-admin/src/main/java/com/ruoyi/api/domain/wcs2wms/SrgvVehicleSnapshot.java: read-only transport DTO.
  • Modify FT546-WCS/ruoyi-admin/src/main/java/com/ruoyi/api/controller/Wcs2WmsController.java: POST /wcs2Wms/api/tidyVehicleSnapshot.
  • Modify FT546-WCS/ruoyi-admin/src/main/java/com/ruoyi/api/service/IApiService.java and impl/ApiServiceImpl.java: derive online/healthy/idle state from device_srgv.

Operator control

  • Create ruoyi-admin/src/main/java/com/ruoyi/algorithm/controller/TidyControlController.java: authenticated status and switch API.
  • Create ruoyi-admin/src/main/java/com/ruoyi/algorithm/controller/TidyModeRequest.java: switch request DTO.
  • Create ruoyi-ui/src/api/algorithm/tidy.js: status/switch calls.
  • Create ruoyi-ui/src/views/algorithm/tidy/index.vue: compact operational status and switch page.
  • Create sql/algorithm_tidy_menu.sql: idempotent dynamic menu and permissions.

Replay and evidence

  • Create tools/history-replay/simulators/ft546-wcs-simulator.mjs: three-vehicle WCS snapshot/task simulator with controllable failures.
  • Create tools/history-replay/sql/select-batch-fixtures.sql: deterministic eligible history and mapping decisions.
  • Create tools/history-replay/sql/reconcile-tidy-batch.sql: per-run inventory, cargo-space, workflow, origin, and lock evidence.
  • Create tools/history-replay/Invoke-Ft546TidyBatchReplay.ps1: backup, migration, fixture execution, HTTP simulation, reconciliation, reports, and restore.
  • Modify tools/history-replay/README.md: exact preflight/run/resume commands and artifact contract.

Task 1: Add Idempotent SQL Server Tidy Schema

Files:

  • Modify: fortucky-algorithm/src/test/java/com/ruoyi/algorithm/repository/SqlServerMigrationScriptTest.java
  • Modify: fortucky-algorithm/src/main/resources/db/sqlserver/install.sql
  • Modify: fortucky-algorithm/src/main/resources/db/sqlserver/diagnostics.sql
  • Modify: fortucky-algorithm/src/main/resources/db/sqlserver/uninstall.sql

Interfaces:

  • Produces: alg.tidy_mode, alg.tidy_lane_queue, alg.tidy_workflow, alg.tidy_step, alg.tidy_space_lock, alg.tidy_callback_event.

  • Produces: alg.usp_claim_tidy_lane, alg.usp_release_tidy_lane, alg.usp_sync_replay_sequences.

  • Preserves: existing alg.dirty_lane_queue as the rebuild queue and hands rebuilt lanes to alg.tidy_lane_queue only after successful rebuild.

  • Step 1: Extend migration contract tests and verify red

Add assertions that require these exact fragments:

assertThat(install).contains("CREATE TABLE alg.tidy_mode");
assertThat(install).contains("CREATE TABLE alg.tidy_lane_queue");
assertThat(install).contains("CREATE TABLE alg.tidy_workflow");
assertThat(install).contains("CREATE TABLE alg.tidy_step");
assertThat(install).contains("CREATE TABLE alg.tidy_space_lock");
assertThat(install).contains("CREATE TABLE alg.tidy_callback_event");
assertThat(install).contains("CREATE PROCEDURE alg.usp_claim_tidy_lane");
assertThat(install).contains("sp_getapplock");
assertThat(install).contains("OUTBOUND_RELOCATION");
assertThat(diagnostics).contains("PAUSED_RECOVERY");
assertThat(uninstall).contains("DROP TABLE alg.tidy_mode");

Run:

mvn -pl fortucky-algorithm -Dtest=SqlServerMigrationScriptTest test

Expected: FAIL because tidy objects do not exist.

  • Step 2: Add tables, keys, constraints, and queue handoff

Use these persisted values:

effective_state varchar(24) CHECK (effective_state IN
  ('NORMAL','ENTERING_TIDY','TIDY_ACTIVE','EXITING_TIDY'))
origin varchar(24) CHECK (origin IN ('AUTO_TIDY','MANUAL_TIDY'))
workflow_status varchar(24) CHECK (workflow_status IN
  ('CLAIMED','WAITING_DISPATCH','DISPATCHED','RUNNING','PAUSED_RECOVERY','COMPLETED','CANCELLED_RECONCILED'))
resource_type varchar(8) CHECK (resource_type IN ('SPACE','LANE','FLOOR'))

Create filtered unique indexes for active resources, WCS task IDs, callback event keys, and singleton active automatic workflow. Add origin='OUTBOUND_RELOCATION' to alg.outbound_workflow. At the successful end of alg.usp_refresh_dirty_lanes, MERGE each row from #dirty into alg.tidy_lane_queue, incrementing dirty_version; retain existing catch/requeue behavior.

  • Step 3: Add claim/release and replay-sequence procedures

alg.usp_claim_tidy_lane must claim one PENDING row using UPDLOCK, READPAST, ROWLOCK, ordered by last_dirty_at, warehouse_id, lane_code, and set a lease token/expiry. alg.usp_release_tidy_lane must clear only the claimed version; if a newer version exists, return it to PENDING.

alg.usp_sync_replay_sequences must run under sp_getapplock, compare active and finish tables, and advance bas_job_id/bas_task_no without decreasing them. It must include CK202607210002 as a regression fixture in the SQL test.

  • Step 4: Verify migration scripts

Run:

mvn -pl fortucky-algorithm -Dtest=SqlServerMigrationScriptTest test

Expected: PASS with all install/diagnostics/uninstall assertions green.

  • Step 5: Commit only migration files
git add fortucky-algorithm/src/main/resources/db/sqlserver/install.sql \
  fortucky-algorithm/src/main/resources/db/sqlserver/diagnostics.sql \
  fortucky-algorithm/src/main/resources/db/sqlserver/uninstall.sql \
  fortucky-algorithm/src/test/java/com/ruoyi/algorithm/repository/SqlServerMigrationScriptTest.java
git commit -m "feat: add persisted tidy workflow schema"

Task 2: Implement Persisted Mode and Shared Admission

Files:

  • Create: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyEffectiveState.java
  • Create: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/ExecutionWorkType.java
  • Create: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyModeSnapshot.java
  • Create: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyModeService.java
  • Create: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/ExecutionAdmissionService.java
  • Create: ruoyi-admin/src/test/java/com/ruoyi/algorithm/wms/tidy/TidyModeServiceTest.java
  • Create: ruoyi-admin/src/test/java/com/ruoyi/algorithm/wms/tidy/ExecutionAdmissionServiceTest.java
  • Modify: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/WmsAlgorithmMapper.java
  • Modify: ruoyi-admin/src/main/resources/mapper/algorithm/WmsAlgorithmMapper.xml

Interfaces:

  • Produces: TidyModeSnapshot status(String warehouseId).

  • Produces: TidyModeSnapshot requestManualMode(String warehouseId, boolean enabled, String actor).

  • Produces: TidyModeSnapshot reconcile(String warehouseId).

  • Produces: void assertAllowed(String warehouseId, ExecutionWorkType workType).

  • Consumes mapper operations: selectTidyModeForUpdate, setTidyModeRequest, countActiveBusinessExecution, countActiveManualTidy.

  • Step 1: Write failing state-machine and admission tests

Cover the exact table:

assertThat(service.requestManualMode("01", true, "tester").effectiveState())
    .isEqualTo(TidyEffectiveState.ENTERING_TIDY);
when(mapper.countActiveBusinessExecution("01")).thenReturn(0);
assertThat(service.reconcile("01").effectiveState())
    .isEqualTo(TidyEffectiveState.TIDY_ACTIVE);
assertThatThrownBy(() -> gate.assertAllowed("01", ExecutionWorkType.INBOUND))
    .isInstanceOf(ExecutionBlockedByTidyModeException.class);
gate.assertAllowed("01", ExecutionWorkType.MANUAL_TIDY);

Also test idempotent repeated enable/disable, EXITING_TIDY drain, optimistic-version failure, and acceptance of DOCUMENT_RECEIPT in every state.

Run:

mvn -pl ruoyi-admin -Dtest='TidyModeServiceTest,ExecutionAdmissionServiceTest' test

Expected: FAIL because types/services/mappers are missing.

  • Step 2: Add the domain types and service logic

Use this gate contract:

public enum ExecutionWorkType {
    DOCUMENT_RECEIPT, INBOUND, OUTBOUND, OUTBOUND_RELOCATION, AUTO_TIDY, MANUAL_TIDY;

    public boolean allowedIn(TidyEffectiveState state) {
        if (this == DOCUMENT_RECEIPT) return true;
        if (state == TidyEffectiveState.NORMAL) return this != MANUAL_TIDY;
        return state == TidyEffectiveState.TIDY_ACTIVE && this == MANUAL_TIDY;
    }
}

public final class ExecutionAdmissionService {
    private final TidyModeService modeService;

    public ExecutionAdmissionService(TidyModeService modeService) {
        this.modeService = modeService;
    }

    public void assertAllowed(String warehouseId, ExecutionWorkType workType) {
        TidyEffectiveState state = modeService.status(warehouseId).effectiveState();
        if (!workType.allowedIn(state)) {
            throw new ExecutionBlockedByTidyModeException(state.name());
        }
    }
}

NORMAL allows business execution and auto tidy; ENTERING_TIDY and EXITING_TIDY allow only document receipt and drain callbacks; TIDY_ACTIVE allows document receipt, manual tidy, and callbacks. State changes and counts must be read inside the WMS transaction manager.

  • Step 3: Implement mapper state locking and status projection

selectTidyModeForUpdate uses WITH (UPDLOCK,HOLDLOCK). The status projection includes requested switch, effective state, drain count, active tidy count, status reason, version, updater, and timestamp.

  • Step 4: Run focused tests
mvn -pl ruoyi-admin -Dtest='TidyModeServiceTest,ExecutionAdmissionServiceTest,WmsAlgorithmMapperRegistrationTest' test

Expected: PASS.

  • Step 5: Commit exact mode files
git add ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyEffectiveState.java \
  ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/ExecutionWorkType.java \
  ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyModeSnapshot.java \
  ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyModeService.java \
  ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/ExecutionAdmissionService.java \
  ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/ExecutionBlockedByTidyModeException.java \
  ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/WmsAlgorithmMapper.java \
  ruoyi-admin/src/main/resources/mapper/algorithm/WmsAlgorithmMapper.xml \
  ruoyi-admin/src/test/java/com/ruoyi/algorithm/wms/tidy/TidyModeServiceTest.java \
  ruoyi-admin/src/test/java/com/ruoyi/algorithm/wms/tidy/ExecutionAdmissionServiceTest.java
git commit -m "feat: persist tidy mode admission state"

Task 3: Gate Every Inbound and Outbound Allocation Route

Files:

  • Modify: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/WmsInboundAllocationService.java
  • Modify: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/WmsOutboundAllocationService.java
  • Modify: ruoyi-admin/src/test/java/com/ruoyi/algorithm/wms/WmsInboundAllocationServiceTest.java
  • Modify: ruoyi-admin/src/test/java/com/ruoyi/algorithm/wms/WmsOutboundAllocationServiceTest.java
  • Modify: ruoyi-admin/src/test/java/com/ruoyi/algorithm/wms/AlgorithmShadowConfigurationTest.java

Interfaces:

  • Consumes: ExecutionAdmissionService.assertAllowed(warehouseId, INBOUND|OUTBOUND).

  • Guarantees: the gate runs before both SchedulingFacade planning and legacy stored-procedure fallback.

  • Step 1: Add failing router tests

For allocate, reallocate, allocateProject, and allocateExactStock, make the gate throw and verify neither algorithm nor legacy mapper is invoked:

doThrow(new ExecutionBlockedByTidyModeException("TIDY_ACTIVE"))
    .when(admission).assertAllowed("01", ExecutionWorkType.OUTBOUND);
assertThatThrownBy(() -> service.allocateProject(stockout, detail))
    .isInstanceOf(ExecutionBlockedByTidyModeException.class);
verifyNoInteractions(facade, stockoutMapper, workflowCoordinator);

Run:

mvn -pl ruoyi-admin -Dtest='WmsInboundAllocationServiceTest,WmsOutboundAllocationServiceTest' test

Expected: FAIL because constructors and gate calls are absent.

  • Step 2: Inject and call the shared gate

Call the gate once at the top of each shared router after resolving warehouse ID and before any reservation release, planner call, or legacy procedure. Do not add controller-only checks. ToWmsServiceImpl.reMaterial remains covered because it routes through OutStockoutServiceImpl.autoAllot -> WmsOutboundAllocationService.allocateProject.

  • Step 3: Verify callback paths remain admitted

Add tests proving jobFinish, completeInbound, outbound confirmation, and existing in-flight advancement do not call the creation gate. They are drain/recovery operations and must remain executable in non-normal states.

  • Step 4: Run WMS allocation regression
mvn -pl ruoyi-admin -Dtest='WmsInboundAllocationServiceTest,InboundAllocationTransactionTest,WmsOutboundAllocationServiceTest,OutboundWorkflowTransactionTest,PersistentOutboundWorkflowCoordinatorTest,AlgorithmShadowConfigurationTest' test

Expected: PASS.

  • Step 5: Commit allocation gate changes
git add ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/WmsInboundAllocationService.java \
  ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/WmsOutboundAllocationService.java \
  ruoyi-admin/src/test/java/com/ruoyi/algorithm/wms/WmsInboundAllocationServiceTest.java \
  ruoyi-admin/src/test/java/com/ruoyi/algorithm/wms/WmsOutboundAllocationServiceTest.java \
  ruoyi-admin/src/test/java/com/ruoyi/algorithm/wms/AlgorithmShadowConfigurationTest.java
git commit -m "feat: gate allocation during manual tidy"

Task 4: Add Persistent Tidy-Lane Scheduling

Files:

  • Modify: fortucky-algorithm/src/main/java/com/ruoyi/algorithm/integration/AlgorithmProperties.java
  • Modify: fortucky-algorithm/src/main/java/com/ruoyi/algorithm/integration/SchedulingFacade.java
  • Modify: fortucky-algorithm/src/test/java/com/ruoyi/algorithm/integration/AlgorithmConfigurationTest.java
  • Create: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyLaneClaim.java
  • Create: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyWorkflowStarter.java
  • Create: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/ReplayExecutionGuard.java
  • Create: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyScheduler.java
  • Create: ruoyi-admin/src/test/java/com/ruoyi/algorithm/wms/tidy/TidySchedulerTest.java
  • Create: ruoyi-admin/src/test/java/com/ruoyi/algorithm/wms/tidy/ReplayExecutionGuardTest.java
  • Modify: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/WmsAlgorithmMapper.java
  • Modify: ruoyi-admin/src/main/resources/mapper/algorithm/WmsAlgorithmMapper.xml
  • Modify: ruoyi-admin/src/main/resources/application.yml

Interfaces:

  • Produces: TidyPlan SchedulingFacade.planTidy(String warehouseId, Instant now).

  • Produces: Optional<TidyLaneClaim> claimTidyLane(String warehouseId, String owner, Instant expiresAt).

  • Produces: UUID TidyWorkflowStarter.startAutomatic(TidyLaneClaim claim, TidyCandidate candidate) as the scheduler boundary; Task 5 makes the coordinator implement it.

  • Step 1: Add failing scheduler tests

Test these cases explicitly: not NORMAL; active inbound; active outbound relocation; one active tidy; no queue claim; stale candidate; successful single start; lease failure requeues.

when(mode.status("01")).thenReturn(normal);
when(mapper.countActiveBusinessExecution("01")).thenReturn(1);
scheduler.scanAutomatic();
verifyNoInteractions(coordinator);

Run:

mvn -pl fortucky-algorithm -Dtest=AlgorithmConfigurationTest test
mvn -pl ruoyi-admin -Dtest=TidySchedulerTest test

Expected: FAIL because facade/scheduler APIs are absent.

  • Step 2: Expose pure tidy planning and properties

Add properties with these defaults:

fortucky:
  algorithm:
    tidy-auto-scan-ms: 600000
    tidy-reconcile-ms: 5000
    tidy-claim-lease-seconds: 60
    tidy-wcs-snapshot-url: ${FORTUCKY_TIDY_WCS_SNAPSHOT_URL:http://localhost:8081/wcs2Wms/api/tidyVehicleSnapshot}
    replay-run-id: ${FT546_REPLAY_RUN_ID:}
    replay-database: ${FT546_REPLAY_DATABASE:}

SchedulingFacade.planTidy may run in SHADOW for diagnostics, but workflow creation still requires the run-scoped write gate and ExecutionWorkType.AUTO_TIDY.

ReplayExecutionGuard runs at application startup. When replay-run-id is nonblank, it requires routing mode ACTIVE, database writes enabled, and mapper selectDatabaseName() exactly equal to replay-database; otherwise startup fails before schedulers or HTTP writers run.

  • Step 3: Implement scheduler and versioned queue mapper

Use @Scheduled(fixedDelayString = "${fortucky.algorithm.tidy-auto-scan-ms:600000}"). Lock/claim the oldest queue row, invoke the planner, select only a candidate touching the claimed lane, and release/requeue using the claim token and dirty version.

  • Step 4: Run planner and scheduler suites
mvn -pl fortucky-algorithm -Dtest='TidyPlannerTest,WarehouseApplicationServiceTest,AlgorithmConfigurationTest' test
mvn -pl ruoyi-admin -Dtest='TidySchedulerTest,ReplayExecutionGuardTest,WmsAlgorithmMapperRegistrationTest' test

Expected: PASS.

  • Step 5: Commit scheduling changes
git add fortucky-algorithm/src/main/java/com/ruoyi/algorithm/integration/AlgorithmProperties.java \
  fortucky-algorithm/src/main/java/com/ruoyi/algorithm/integration/SchedulingFacade.java \
  fortucky-algorithm/src/test/java/com/ruoyi/algorithm/integration/AlgorithmConfigurationTest.java \
  ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyLaneClaim.java \
  ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyWorkflowStarter.java \
  ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/ReplayExecutionGuard.java \
  ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyScheduler.java \
  ruoyi-admin/src/test/java/com/ruoyi/algorithm/wms/tidy/TidySchedulerTest.java \
  ruoyi-admin/src/test/java/com/ruoyi/algorithm/wms/tidy/ReplayExecutionGuardTest.java \
  ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/WmsAlgorithmMapper.java \
  ruoyi-admin/src/main/resources/mapper/algorithm/WmsAlgorithmMapper.xml \
  ruoyi-admin/src/main/resources/application.yml
git commit -m "feat: schedule automatic tidy from dirty lanes"

Task 5: Execute Tidy Through the Existing Move-Job Chain

Files:

  • Create: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyOrigin.java
  • Create: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyWorkflowState.java
  • Create: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/WcsTaskState.java
  • Create: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyWorkflowTransaction.java
  • Create: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyWorkflowCoordinator.java
  • Create: ruoyi-admin/src/test/java/com/ruoyi/algorithm/wms/tidy/TidyWorkflowTransactionTest.java
  • Create: ruoyi-admin/src/test/java/com/ruoyi/algorithm/wms/tidy/TidyWorkflowCoordinatorTest.java
  • Modify: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/WmsAlgorithmMapper.java
  • Modify: ruoyi-admin/src/main/resources/mapper/algorithm/WmsAlgorithmMapper.xml
  • Modify: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/OutboundWorkflowTransaction.java
  • Modify: ruoyi-admin/src/main/java/com/ruoyi/api/service/impl/ToWmsServiceImpl.java

Interfaces:

  • Produces: UUID start(TidyOrigin origin, String warehouseId, TidyCandidate candidate).

  • Produces: boolean onJobFinished(String jobId, String callbackStage).

  • Produces: TidyWorkflowState reconcile(UUID workflowId, WcsTaskState taskState).

  • Implements: UUID TidyWorkflowStarter.startAutomatic(TidyLaneClaim claim, TidyCandidate candidate).

  • Guarantees: one TidyMove becomes one ordered in_or_out=28 job; only the next dependent step is active.

  • Step 1: Add failing workflow transaction tests

Cover: current pallet/space revalidation; transaction-scoped sp_getapplock; disjoint SPACE/LANE/FLOOR resources; ordered multi-move candidate; one job per move; duplicate callback event; out-of-order rejection; terminal release; PAUSED_RECOVERY retained locks.

Define tidy workflow origin narrowly:

public enum TidyOrigin {
    AUTO_TIDY, MANUAL_TIDY
}

Outbound workflows persist the separate constant OUTBOUND_RELOCATION; job-origin queries union the two owning workflow types and never pass that value into TidyWorkflowTransaction.start.

UUID workflow = transaction.start(TidyOrigin.MANUAL_TIDY, "01", candidate);
verify(mapper).insertTidyMoveJob(argThat(step -> step.inOrOut() == 28));
assertThat(transaction.onJobFinished("TIDY-1", "FINISHED")).isTrue();
assertThat(transaction.onJobFinished("TIDY-1", "FINISHED")).isFalse();
verify(mapper, times(1)).completeTidyStep(anyString());

Run:

mvn -pl ruoyi-admin -Dtest='TidyWorkflowTransactionTest,TidyWorkflowCoordinatorTest' test

Expected: FAIL because workflow types/mapper methods are missing.

  • Step 2: Implement transactional workflow creation

Inside one @Transactional method:

admission.assertAllowed(warehouseId,
    origin == TidyOrigin.AUTO_TIDY ? ExecutionWorkType.AUTO_TIDY : ExecutionWorkType.MANUAL_TIDY);
mapper.acquireAlgorithmResourceAppLock(warehouseId, resourceKeys);
mapper.revalidateTidyCandidate(candidate);
mapper.insertTidyWorkflow(...);
mapper.insertTidySteps(...);
mapper.lockTidyResources(...);
mapper.insertTidyMoveJob(firstStep);

Each subsequent callback inserts alg.tidy_callback_event first. A duplicate unique-key event returns the current state without applying inventory/job transitions twice.

  • Step 3: Link outbound relocation origin and callback routing

Persist OUTBOUND_RELOCATION on outbound workflows. Extend job query DTOs by workflow join. In ToWmsServiceImpl.jobFinish, try the existing outbound coordinator first, then the tidy coordinator only when outbound returns noMatch; callbacks for unrelated jobs retain existing behavior.

  • Step 4: Run outbound and tidy workflow regression
mvn -pl ruoyi-admin -Dtest='OutboundWorkflowTransactionTest,PersistentOutboundWorkflowCoordinatorTest,WmsAlgorithmMapperWorkflowSqlTest,TidyWorkflowTransactionTest,TidyWorkflowCoordinatorTest' test

Expected: PASS, including N MOVE_OUT + OUTBOUND + N RESTORE assertions and tidy callback idempotency.

  • Step 5: Commit workflow files
git add ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyOrigin.java \
  ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyWorkflowState.java \
  ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/WcsTaskState.java \
  ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyWorkflowTransaction.java \
  ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyWorkflowCoordinator.java \
  ruoyi-admin/src/test/java/com/ruoyi/algorithm/wms/tidy/TidyWorkflowTransactionTest.java \
  ruoyi-admin/src/test/java/com/ruoyi/algorithm/wms/tidy/TidyWorkflowCoordinatorTest.java \
  ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/WmsAlgorithmMapper.java \
  ruoyi-admin/src/main/resources/mapper/algorithm/WmsAlgorithmMapper.xml \
  ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/OutboundWorkflowTransaction.java \
  ruoyi-admin/src/main/java/com/ruoyi/api/service/impl/ToWmsServiceImpl.java
git commit -m "feat: execute persisted tidy move workflows"

Task 6: Add WCS Vehicle Snapshot and Manual Capacity Filling

Files:

  • Create: D:/workSpace/PROJECT_SPACE/FT546/FT546-WCS/ruoyi-admin/src/main/java/com/ruoyi/api/domain/wcs2wms/SrgvVehicleSnapshot.java
  • Modify: D:/workSpace/PROJECT_SPACE/FT546/FT546-WCS/ruoyi-admin/src/main/java/com/ruoyi/api/controller/Wcs2WmsController.java
  • Modify: D:/workSpace/PROJECT_SPACE/FT546/FT546-WCS/ruoyi-admin/src/main/java/com/ruoyi/api/service/IApiService.java
  • Modify: D:/workSpace/PROJECT_SPACE/FT546/FT546-WCS/ruoyi-admin/src/main/java/com/ruoyi/api/service/impl/ApiServiceImpl.java
  • Create: D:/workSpace/PROJECT_SPACE/FT546/FT546-WCS/ruoyi-admin/src/test/java/com/ruoyi/api/service/ApiServiceVehicleSnapshotTest.java
  • Create: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/VehicleSnapshot.java
  • Create: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyVehicleCapacity.java
  • Create: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/WcsVehicleSnapshotClient.java
  • Create: ruoyi-admin/src/test/java/com/ruoyi/algorithm/wms/tidy/TidyVehicleCapacityTest.java
  • Create: ruoyi-admin/src/test/java/com/ruoyi/algorithm/wms/tidy/TidyModeRecoveryTest.java
  • Modify: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyModeService.java
  • Modify: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyWorkflowCoordinator.java
  • Modify: ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyScheduler.java

Interfaces:

  • WCS produces: List<SrgvVehicleSnapshot> tidyVehicleSnapshot().

  • WMS consumes: List<VehicleSnapshot> fetch().

  • Produces: nested TidyVehicleCapacity.CapacityResult and CapacityResult calculate(List<VehicleSnapshot> vehicles, int activeManualWorkflows, Set<String> assignedManualVehicleIds), where newSlots=max(0,effectiveCapacity-activeManualWorkflows).

  • Step 1: Write capacity and mode-recovery tests

Use exactly these semantics:

VehicleSnapshot healthyIdle = new VehicleSnapshot("1", true, true, true, null);
VehicleSnapshot healthyTidy = new VehicleSnapshot("2", true, true, false, "MANUAL_TIDY");
VehicleSnapshot busyInbound = new VehicleSnapshot("3", true, true, false, "INBOUND");
CapacityResult result = capacity.calculate(
    List.of(healthyIdle, healthyTidy, busyInbound), 1, Set.of("2"));
assertThat(result.effectiveCapacity()).isEqualTo(2);
assertThat(result.newSlots()).isEqualTo(1);

Test ENTERING_TIDY drain to active, continuous replacement, capacity reduction without cancelling running work, switch-off cancellation of undispatched work, restart at all three non-normal checkpoints, and unknown WCS task -> PAUSED_RECOVERY. With three effective vehicles but only two mutually safe candidates, assert two workflows plus status reason NO_SAFE_CANDIDATE; the switch must remain enabled.

  • Step 2: Add the WCS read-only endpoint

Derive fields from device_srgv:

boolean online = "1".equals(device.getAgvStatus());
boolean healthy = online && value(device.getAlarm()) <= 1 && value(device.getErrMsg()) == 0;
boolean idle = healthy && value(device.getTaskNo()) == 0
    && value(device.getLocked()) == 0 && value(device.getChargeFlag()) == 0;

Return stable vehicle ID and current task number/type. Add ApiServiceVehicleSnapshotTest for offline, alarmed, charging, locked, busy, and idle vehicles. Do not write WCS device or queue state from this endpoint.

  • Step 3: Add the WMS client and capacity reconciliation

Use configurable ${fortucky.algorithm.tidy-wcs-snapshot-url:http://localhost:8081/wcs2Wms/api/tidyVehicleSnapshot}. During TIDY_ACTIVE, fill newSlots with mutually disjoint candidates. During EXITING_TIDY, cancel only CLAIMED/WAITING_DISPATCH rows without a WCS task and drain dispatched/running rows.

  • Step 4: Verify WCS and WMS modules

Run:

git -C D:/workSpace/PROJECT_SPACE/FT546/FT546-WCS diff --check
mvn -f D:/workSpace/PROJECT_SPACE/FT546/FT546-WCS/pom.xml -pl ruoyi-admin -am -Dtest=ApiServiceVehicleSnapshotTest test
mvn -pl ruoyi-admin -Dtest='TidyVehicleCapacityTest,TidyModeRecoveryTest,TidyWorkflowCoordinatorTest' test

Expected: both Maven commands PASS.

  • Step 5: Commit exact WCS and WMS capacity files separately
git -C D:/workSpace/PROJECT_SPACE/FT546/FT546-WCS add \
  ruoyi-admin/src/main/java/com/ruoyi/api/domain/wcs2wms/SrgvVehicleSnapshot.java \
  ruoyi-admin/src/main/java/com/ruoyi/api/controller/Wcs2WmsController.java \
  ruoyi-admin/src/main/java/com/ruoyi/api/service/IApiService.java \
  ruoyi-admin/src/main/java/com/ruoyi/api/service/impl/ApiServiceImpl.java \
  ruoyi-admin/src/test/java/com/ruoyi/api/service/ApiServiceVehicleSnapshotTest.java
git -C D:/workSpace/PROJECT_SPACE/FT546/FT546-WCS commit -m "feat: expose tidy vehicle capacity"

git add ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/VehicleSnapshot.java \
  ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyVehicleCapacity.java \
  ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/WcsVehicleSnapshotClient.java \
  ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyModeService.java \
  ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyWorkflowCoordinator.java \
  ruoyi-admin/src/main/java/com/ruoyi/algorithm/wms/tidy/TidyScheduler.java \
  ruoyi-admin/src/test/java/com/ruoyi/algorithm/wms/tidy/TidyVehicleCapacityTest.java \
  ruoyi-admin/src/test/java/com/ruoyi/algorithm/wms/tidy/TidyModeRecoveryTest.java \
  ruoyi-admin/src/test/java/com/ruoyi/algorithm/wms/tidy/TidyWorkflowCoordinatorTest.java
git commit -m "feat: fill manual tidy vehicle capacity"

Task 7: Add Operator Switch and Status Page

Files:

  • Create: ruoyi-admin/src/main/java/com/ruoyi/algorithm/controller/TidyModeRequest.java
  • Create: ruoyi-admin/src/main/java/com/ruoyi/algorithm/controller/TidyControlController.java
  • Create: ruoyi-admin/src/test/java/com/ruoyi/algorithm/controller/TidyControlControllerTest.java
  • Create: ruoyi-ui/src/api/algorithm/tidy.js
  • Create: ruoyi-ui/src/views/algorithm/tidy/index.vue
  • Create: sql/algorithm_tidy_menu.sql

Interfaces:

  • GET /algorithm/tidy/status?warehouseId=01 with permission algorithm:tidy:query.

  • PUT /algorithm/tidy/mode body { "warehouseId": "01", "enabled": true } with permission algorithm:tidy:edit.

  • Step 1: Write failing controller tests

mockMvc.perform(get("/algorithm/tidy/status").param("warehouseId", "01"))
    .andExpect(status().isOk())
    .andExpect(jsonPath("$.data.effectiveState").value("NORMAL"));
mockMvc.perform(put("/algorithm/tidy/mode")
    .contentType(APPLICATION_JSON)
    .content("{\"warehouseId\":\"01\",\"enabled\":true}"))
    .andExpect(status().isOk());
verify(modeService).requestManualMode(eq("01"), eq(true), anyString());

Run:

mvn -pl ruoyi-admin -Dtest=TidyControlControllerTest test

Expected: FAIL because controller is absent.

  • Step 2: Implement secured API and idempotent menu SQL

Controller methods return AjaxResult.success(snapshot) and use @PreAuthorize("@ss.hasPermi('algorithm:tidy:query')") / algorithm:tidy:edit. The menu script uses IF NOT EXISTS by permission string and component algorithm/tidy/index.

  • Step 3: Implement compact operational page

Use <el-switch> with confirmation and rollback on error. Show effective state, requested switch, drain count, active tidy, healthy/available vehicles, candidate count, and last reason. Poll every 5 seconds only while document.visibilityState === 'visible'; clear timer/listener in beforeDestroy.

  • Step 4: Verify backend and frontend build
mvn -pl ruoyi-admin -Dtest=TidyControlControllerTest test
npm --prefix ruoyi-ui run build:prod

Expected: controller PASS and Vue production build exits 0.

  • Step 5: Browser-check the page

Start WMS and UI, then use Playwright at desktop 1440x900 and mobile 390x844. Verify switch confirmation, failed-switch rollback, polling, no overlapping text, and status updates through ENTERING_TIDY/TIDY_ACTIVE/EXITING_TIDY.

  • Step 6: Commit UI/control files
git add ruoyi-admin/src/main/java/com/ruoyi/algorithm/controller/TidyModeRequest.java \
  ruoyi-admin/src/main/java/com/ruoyi/algorithm/controller/TidyControlController.java \
  ruoyi-admin/src/test/java/com/ruoyi/algorithm/controller/TidyControlControllerTest.java \
  ruoyi-ui/src/api/algorithm/tidy.js ruoyi-ui/src/views/algorithm/tidy/index.vue \
  sql/algorithm_tidy_menu.sql
git commit -m "feat: add manual tidy control page"

Task 8: Build Deterministic PDA/WCS Batch Replay Harness

Files:

  • Create: tools/history-replay/simulators/ft546-wcs-simulator.mjs
  • Create: tools/history-replay/sql/select-batch-fixtures.sql
  • Create: tools/history-replay/sql/reconcile-tidy-batch.sql
  • Create: tools/history-replay/Invoke-Ft546TidyBatchReplay.ps1
  • Create: tools/history-replay/tests/Invoke-Ft546TidyBatchReplay.Tests.ps1
  • Modify: tools/history-replay/README.md

Interfaces:

  • Simulator: POST /wcs2Wms/api/tidyVehicleSnapshot, /receiveInMydoJob, /receiveOutMydoJob, /sim/vehicles, /sim/complete, /sim/unknown-task.

  • Runner: -PreflightOnly, -ConfirmReplay, -KeepFailedState, -WmsBaseUrl, -SimulatorPort.

  • Outputs: inbound-reconciliation.csv, outbound-reconciliation.csv, tidy-reconciliation.csv, events.json, report.md.

  • Step 1: Write failing Pester/static harness tests

Require source hashes/counts, closed warehouse mapping, orphan exclusion, deterministic ordering, 100/300 inbound boundary, 4x25 outbound strata, at least 50 planner-selected cases, callback duplication/out-of-order cases, backup verification, run-scoped override removal, and final restore proof.

Run:

Invoke-Pester .\tools\history-replay\tests\Invoke-Ft546TidyBatchReplay.Tests.ps1 -Output Detailed

Expected: FAIL because runner/simulator/queries do not exist.

  • Step 2: Implement deterministic fixture SQL

Eligibility must be expressed in SQL and returned with mapping_decision:

CASE
  WHEN NULLIF(LTRIM(RTRIM(source_warehouse)), '') IS NULL THEN 'MAP_BLANK_TO_01'
  WHEN source_warehouse = '07' THEN 'MAP_07_TO_01'
  WHEN source_warehouse = '01' THEN 'KEEP_01'
  ELSE 'UNSUPPORTED_SOURCE_WAREHOUSE'
END

Order by completion time, document ID, detail ID. Exclude CKD202605140015-1. Never update finish rows.

  • Step 3: Implement WCS simulator and event journal

Use Node built-in http; default to three online healthy idle vehicles. Every received task and callback gets an immutable sequence number and timestamp. /sim/unknown-task makes the next WMS recovery lookup return unknown without deleting the journal.

  • Step 4: Implement guarded replay orchestration

Reuse the existing System.Data.SqlClient helpers and exact six source-count checks. Flow: preflight -> install migration -> COPY_ONLY, CHECKSUM backup -> RESTORE VERIFYONLY -> sequence sync -> create run ID -> start simulator -> start an isolated WMS process -> inbound HTTP loop -> outbound just-in-time strata loop -> automatic tidy cases -> manual three-vehicle/capacity/restart cases -> reconcile -> write artifacts -> stop writers -> restore backup -> verify baseline.

The isolated WMS process receives these process-local values and uses a non-conflicting HTTP port:

$env:FORTUCKY_ALGORITHM_MODE = 'ACTIVE'
$env:FORTUCKY_ALGORITHM_DATABASE_WRITES = 'true'
$env:FT546_REPLAY_RUN_ID = $runId
$env:FT546_REPLAY_DATABASE = 'FT546-wms'
$env:FORTUCKY_TIDY_WCS_SNAPSHOT_URL = "http://127.0.0.1:$SimulatorPort/wcs2Wms/api/tidyVehicleSnapshot"

Before starting Java, the runner proves the resolved JDBC database is exactly FT546-wms, no unrelated active work exists, and every generated business identifier carries $runId. A finally block stops only the process IDs it started and removes these environment values; the normal deployment configuration remains SHADOW.

Every HTTP call records request, response code/body, and related DB snapshot. A mismatch marks the run failed but does not remove its row. -KeepFailedState skips restore only when explicitly supplied for debugging and prints the verified backup path prominently.

  • Step 5: Run harness tests and preflight
Invoke-Pester .\tools\history-replay\tests\Invoke-Ft546TidyBatchReplay.Tests.ps1 -Output Detailed
pwsh -File .\tools\history-replay\Invoke-Ft546TidyBatchReplay.ps1 -PreflightOnly

Expected: Pester PASS; preflight prints target FT546-wms, source counts/hashes, topology count, active-work count, migration status, and no mutations.

  • Step 6: Commit replay tooling
git add tools/history-replay/simulators/ft546-wcs-simulator.mjs \
  tools/history-replay/sql/select-batch-fixtures.sql \
  tools/history-replay/sql/reconcile-tidy-batch.sql \
  tools/history-replay/Invoke-Ft546TidyBatchReplay.ps1 \
  tools/history-replay/tests/Invoke-Ft546TidyBatchReplay.Tests.ps1 \
  tools/history-replay/README.md
git commit -m "test: add historical tidy batch replay harness"

Task 9: Run Full Regression and Development-Database Replay

Files:

  • Generate only: outputs/ft546-tidy-batch-replay-<run-id>/*
  • Update if defects are found: only the owning task files and their tests.

Interfaces:

  • Consumes all preceding tasks.

  • Produces the final pass/fail evidence and restores the imported-history baseline.

  • Step 1: Run all automated Java and frontend checks

mvn -pl fortucky-algorithm,ruoyi-admin -am test
mvn test
mvn package -DskipTests
npm --prefix ruoyi-ui run build:prod
mvn -f D:/workSpace/PROJECT_SPACE/FT546/FT546-WCS/pom.xml -pl ruoyi-admin -am test

Expected: all commands exit 0; record exact test totals and package SHA-256 values in report.md.

  • Step 2: Run SQL diagnostics before destructive replay

Execute install.sql and diagnostics.sql against the confirmed development FT546-wms. Stop on any active job/workflow, orphan lock, invalid topology, wrong database identity, unsupported source count, or failed backup verification.

  • Step 3: Execute the full replay
pwsh -File .\tools\history-replay\Invoke-Ft546TidyBatchReplay.ps1 -ConfirmReplay

Expected acceptance:

Inbound attempted >= 100, mismatches = 0
Outbound successful = 100 (0 blockers=25, 1=25, 2=25, 3+=25)
Planner-selected outbound >= 50
Automatic tidy max concurrency = 1
Manual tidy capacity: 3 -> refill -> 2 -> no unsafe overfill
Duplicate callback side effects = 0
Restart checkpoints = 4/4 passed
Unexpected PAUSED_RECOVERY = 0
Restore verification = PASS
  • Step 4: Investigate failures test-first and rerun from restored baseline

For each failing reconciliation row, first add the smallest reproducing unit/integration test to the owning task, observe red, implement the fix, run focused green, then rerun the full automated suite and replay. Never patch database evidence manually.

  • Step 5: Verify final artifacts and clean runtime processes

Confirm all five artifact files exist and contain the run ID, source mapping, per-row evidence, failures (including zero-count sections), backup path, restore counts, and database fingerprint. Stop WMS, simulator, and temporary Redis processes started by the run; do not stop unrelated user processes.

  • Step 6: Commit only defect fixes and final documentation
git status --short
git diff --check

Do not commit outputs/ unless the repository's existing policy tracks test evidence. Report WMS and WCS commit IDs, test totals, replay run ID, artifact path, and restored database counts.