# 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: ```java 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: ```bash 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: ```sql 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: ```bash mvn -pl fortucky-algorithm -Dtest=SqlServerMigrationScriptTest test ``` Expected: PASS with all install/diagnostics/uninstall assertions green. - [ ] **Step 5: Commit only migration files** ```bash 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: ```java 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: ```bash 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: ```java 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** ```bash mvn -pl ruoyi-admin -Dtest='TidyModeServiceTest,ExecutionAdmissionServiceTest,WmsAlgorithmMapperRegistrationTest' test ``` Expected: PASS. - [ ] **Step 5: Commit exact mode files** ```bash 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: ```java doThrow(new ExecutionBlockedByTidyModeException("TIDY_ACTIVE")) .when(admission).assertAllowed("01", ExecutionWorkType.OUTBOUND); assertThatThrownBy(() -> service.allocateProject(stockout, detail)) .isInstanceOf(ExecutionBlockedByTidyModeException.class); verifyNoInteractions(facade, stockoutMapper, workflowCoordinator); ``` Run: ```bash 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** ```bash mvn -pl ruoyi-admin -Dtest='WmsInboundAllocationServiceTest,InboundAllocationTransactionTest,WmsOutboundAllocationServiceTest,OutboundWorkflowTransactionTest,PersistentOutboundWorkflowCoordinatorTest,AlgorithmShadowConfigurationTest' test ``` Expected: PASS. - [ ] **Step 5: Commit allocation gate changes** ```bash 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 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. ```java when(mode.status("01")).thenReturn(normal); when(mapper.countActiveBusinessExecution("01")).thenReturn(1); scheduler.scanAutomatic(); verifyNoInteractions(coordinator); ``` Run: ```bash 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: ```yaml 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** ```bash 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** ```bash 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: ```java 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`. ```java 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: ```bash 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: ```java 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** ```bash 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** ```bash 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 tidyVehicleSnapshot()`. - WMS consumes: `List fetch()`. - Produces: nested `TidyVehicleCapacity.CapacityResult` and `CapacityResult calculate(List vehicles, int activeManualWorkflows, Set assignedManualVehicleIds)`, where `newSlots=max(0,effectiveCapacity-activeManualWorkflows)`. - [ ] **Step 1: Write capacity and mode-recovery tests** Use exactly these semantics: ```java 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`: ```java 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: ```bash 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** ```bash 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** ```java 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: ```bash 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 `` 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** ```bash 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** ```bash 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: ```powershell 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`: ```sql 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: ```powershell $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** ```powershell 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** ```bash 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-/*` - 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** ```bash 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** ```powershell pwsh -File .\tools\history-replay\Invoke-Ft546TidyBatchReplay.ps1 -ConfirmReplay ``` Expected acceptance: ```text 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** ```bash 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.