24 KiB
Dense Outbound Relocation And Dispatch 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 durable WCS outbound retry compensation, dense-lane outermost enforcement, automatic/manual same-floor relocation, and dense-lane outbound workflows without changing existing inbound or non-dense outbound behavior.
Architecture: Keep mydo_job as the business record and add a one-to-one wcs_job_dispatch outbox record. Route every outbound push through a single dispatch service that atomically claims attempts and calls a dense-lane eligibility service before selecting a type-specific WCS endpoint. Build relocation and lane-outbound workflows on shared dense-lane queries so automatic allocation, scheduled retry, manual push, location outbound, KPI relocation, and lane outbound enforce the same rules.
Tech Stack: Java 17, Spring Boot, MyBatis XML, SQL Server, Quartz through RuoYi sys_job, JUnit 5/Mockito/AssertJ, Vue 2, Element UI, Maven 3.9.11, npm.
Global Constraints
- Preserve current RuoYi controller/domain/mapper/service/service.impl layering and naming style.
- Do not alter the existing inbound WCS pull flow or non-03 warehouse outbound allocation semantics.
- Apply dense-lane rules only to warehouse
03cargo spaces with non-emptygroup_coding. in_or_out=23is relocation and usesutil_serial_task '23'.- Automatic WCS retries run at most five times after the initial failed call.
- Relocation source and destination must be in the same warehouse and same floor, but different channel groups.
- All WCS dispatch entry points must enforce current outermost eligibility immediately before the HTTP call.
- Use
D:\BDevTools\maven\apache-maven-3.9.11\bin\mvn.cmdfor Maven commands. - Use repeatable SQL Server migration statements; do not delete existing business data.
Task 1: Dispatch Outbox Schema And Persistence
Files:
- Create:
sql/20260716_dense_outbound_relocation_dispatch.sql - Create:
ruoyi-admin/src/main/java/com/ruoyi/out/dispatch/domain/WcsJobDispatch.java - Create:
ruoyi-admin/src/main/java/com/ruoyi/out/dispatch/mapper/WcsJobDispatchMapper.java - Create:
ruoyi-admin/src/main/resources/mapper/out/WcsJobDispatchMapper.xml - Create:
ruoyi-admin/src/test/java/com/ruoyi/out/dispatch/mapper/WcsJobDispatchMapperSqlTest.java - Modify:
ruoyi-admin/src/main/java/com/ruoyi/in/job/domain/MydoJob.java - Modify:
ruoyi-admin/src/main/resources/mapper/in/MydoJobMapper.xml
Interfaces:
-
Produces:
WcsJobDispatchMapper.insertIfAbsent(String jobId),selectByJobId(String jobId),selectRetryCandidates(Date now, int limit),claimForSend(Map<String,Object>),markBlocked(Map),markRetryWait(Map),markSuccess(Map), andmarkExhausted(Map). -
Produces: non-persistent
MydoJob.dispatchStatus,autoRetryCount,manualRetryCount, andlastDispatchErrorpopulated by list/detail queries. -
Step 1: Write the failing mapper structure test
Create a JUnit test that reads the mapper XML and migration and asserts the six statuses, the retry-count predicate, atomic SENDING claim, dispatch join aliases, ID 23 seed, Quartz invocation, menu permissions, and repeatable IF NOT EXISTS guards.
assertThat(mapperXml)
.contains("dispatch_status = 'SENDING'")
.contains("auto_retry_count < 5")
.contains("last_dispatch_error");
assertThat(migration)
.contains("wcs_job_dispatch")
.contains("wcsOutboundRetryTask.retryFailedJobs")
.contains("out:denseLaneOutbound:generate");
- Step 2: Run the focused test and verify RED
Run:
& 'D:\BDevTools\maven\apache-maven-3.9.11\bin\mvn.cmd' -pl ruoyi-admin -Dtest=WcsJobDispatchMapperSqlTest test
Expected: FAIL because the mapper and migration do not exist.
- Step 3: Implement the migration, domain, mapper, XML, and job query join
Use exact dispatch constants PENDING, SENDING, BLOCKED, RETRY_WAIT, SUCCESS, EXHAUSTED. The migration creates the table and indexes, inserts task type 23 only when absent, inserts the non-concurrent one-minute Quartz row, and inserts/updates the lane-outbound menu and three permissions. claimForSend must update exactly one eligible row and increment either auto_retry_count or manual_retry_count based on a parameter.
- Step 4: Run the focused test and verify GREEN
Run the command from Step 2. Expected: PASS.
- Step 5: Commit
git add sql/20260716_dense_outbound_relocation_dispatch.sql ruoyi-admin/src/main/java/com/ruoyi/out/dispatch ruoyi-admin/src/main/resources/mapper/out/WcsJobDispatchMapper.xml ruoyi-admin/src/main/java/com/ruoyi/in/job/domain/MydoJob.java ruoyi-admin/src/main/resources/mapper/in/MydoJobMapper.xml ruoyi-admin/src/test/java/com/ruoyi/out/dispatch/mapper/WcsJobDispatchMapperSqlTest.java
git commit -m "feat: add WCS dispatch outbox"
Task 2: WCS Routing And Durable Dispatch Service
Files:
- Create:
ruoyi-admin/src/main/java/com/ruoyi/out/dispatch/service/IOutboundDispatchService.java - Create:
ruoyi-admin/src/main/java/com/ruoyi/out/dispatch/service/impl/OutboundDispatchServiceImpl.java - Create:
ruoyi-admin/src/main/java/com/ruoyi/out/dispatch/domain/DispatchTrigger.java - Create:
ruoyi-admin/src/main/java/com/ruoyi/out/dispatch/task/WcsOutboundRetryTask.java - Create:
ruoyi-admin/src/main/java/com/ruoyi/out/dense/domain/DispatchEligibility.java - Create:
ruoyi-admin/src/main/java/com/ruoyi/out/dense/mapper/DenseLaneMapper.java - Create:
ruoyi-admin/src/main/resources/mapper/out/DenseLaneMapper.xml - Create:
ruoyi-admin/src/main/java/com/ruoyi/out/dense/service/IDenseLaneService.java - Create:
ruoyi-admin/src/main/java/com/ruoyi/out/dense/service/impl/DenseLaneServiceImpl.java - Create:
ruoyi-admin/src/test/java/com/ruoyi/out/dispatch/service/impl/OutboundDispatchServiceImplTest.java - Modify:
ruoyi-admin/src/main/java/com/ruoyi/api/client/WcsClient.java - Modify:
ruoyi-admin/src/main/resources/application.yml - Modify:
ruoyi-admin/src/main/java/com/ruoyi/in/job/service/IMydoJobService.java - Modify:
ruoyi-admin/src/main/java/com/ruoyi/in/job/service/impl/MydoJobServiceImpl.java - Modify:
ruoyi-admin/src/main/java/com/ruoyi/out/job/controller/OutMydoJobController.java
Interfaces:
-
Produces:
AjaxResult dispatch(String jobId, DispatchTrigger trigger)where trigger isINITIAL,AUTO_RETRY, orMANUAL. -
Produces:
int retryFailedJobs()for Quartz. -
Produces:
WcsClient.sendOutboundTask(MydoJob),sendLocationOutboundTask(MydoJob), andsendRelocationTask(MydoJob). -
Step 1: Write failing service tests
Cover initial failure with count 0, five auto retries then exhausted, manual send past exhaustion, successful status/phase update, atomic claim rejection, and route selection for types 20, 21, and 23. Mock only mapper and WCS boundaries; assert real service decisions.
assertThat(service.dispatch("CK1", DispatchTrigger.INITIAL).isSuccess()).isTrue();
verify(dispatchMapper).markRetryWait(argThat(m -> Integer.valueOf(0).equals(m.get("autoRetryCount"))));
verify(wcsClient).sendRelocationTask(jobOfType(23L));
- Step 2: Run the tests and verify RED
& 'D:\BDevTools\maven\apache-maven-3.9.11\bin\mvn.cmd' -pl ruoyi-admin -Dtest=OutboundDispatchServiceImplTest test
Expected: FAIL because the dispatch API and WCS methods do not exist.
- Step 3: Implement dispatch state transitions, the minimal dense eligibility guard, and WCS routes
The service creates the outbox row if absent, delegates dense eligibility to IDenseLaneService, claims SENDING, calls the type route, records failures without throwing away the business job, and updates mydo_job.status='3', execution_phase='1', start_time only after success. The minimal dense mapper answers whether the job source is the current outermost occupied cargo position; non-03 or non-dense jobs are immediately eligible. Add PUT /out/job/pushWcs/{jobId} as the manual trigger backed by this service. Configure:
sendRetrieveTask: ${WCS_OUTBOUND_PATH:/wcs/api/receiveWmsOutJob}
sendLocationOutboundTask: ${WCS_LOCATION_OUTBOUND_PATH:/wcs/api/receiveWmsLocationOutJob}
sendRelocationTask: ${WCS_RELOCATION_PATH:/wcs/api/receiveWmsMoveJob}
- Step 4: Run the tests and verify GREEN
Run Step 2. Expected: PASS.
- Step 5: Commit
git add ruoyi-admin/src/main/java/com/ruoyi/out/dispatch ruoyi-admin/src/main/java/com/ruoyi/api/client/WcsClient.java ruoyi-admin/src/main/resources/application.yml ruoyi-admin/src/main/java/com/ruoyi/in/job ruoyi-admin/src/main/java/com/ruoyi/out/job/controller/OutMydoJobController.java ruoyi-admin/src/test/java/com/ruoyi/out/dispatch/service/impl/OutboundDispatchServiceImplTest.java
git commit -m "feat: add outbound WCS retry dispatch"
Task 3: Dense Lane Geometry And Eligibility
Files:
- Create:
ruoyi-admin/src/main/java/com/ruoyi/out/dense/domain/DenseLanePosition.java - Create:
ruoyi-admin/src/main/java/com/ruoyi/out/dense/domain/DenseRelocationCandidate.java - Modify:
ruoyi-admin/src/main/java/com/ruoyi/out/dense/mapper/DenseLaneMapper.java - Modify:
ruoyi-admin/src/main/resources/mapper/out/DenseLaneMapper.xml - Modify:
ruoyi-admin/src/main/java/com/ruoyi/out/dense/service/IDenseLaneService.java - Modify:
ruoyi-admin/src/main/java/com/ruoyi/out/dense/service/impl/DenseLaneServiceImpl.java - Create:
ruoyi-admin/src/test/java/com/ruoyi/out/dense/service/impl/DenseLaneServiceImplTest.java - Create:
ruoyi-admin/src/test/java/com/ruoyi/out/dense/mapper/DenseLaneMapperSqlTest.java
Interfaces:
-
Produces:
DispatchEligibility checkDispatchEligibility(MydoJob job). -
Produces:
List<DenseLanePosition> selectBlockersForUpdate(String cargoSpaceId)ordered outer-to-inner. -
Produces:
BasCargoSpace selectRelocationTargetForUpdate(RelocationTargetQuery query). -
Produces: lane summary, tray preview, and inventory detail queries consumed by Tasks 6 and 7.
-
Step 1: Write failing direction and SQL tests
Assert direction 1 treats the maximum occupied column as outermost, direction 2 treats the minimum as outermost, direction 3 uses nearest boundary, non-03 jobs bypass the rule, blockers exclude trays already covered by active outbound jobs, and destination SQL enforces same floor and different group_coding.
- Step 2: Run focused tests and verify RED
& 'D:\BDevTools\maven\apache-maven-3.9.11\bin\mvn.cmd' -pl ruoyi-admin -Dtest=DenseLaneServiceImplTest,DenseLaneMapperSqlTest test
Expected: FAIL because dense-lane classes do not exist.
- Step 3: Implement pure ordering helpers and locked mapper queries
Centralize direction ordering in one service. SQL uses UPDLOCK,HOLDLOCK for blocker/destination selection, treats cargo statuses 2/3/4 with tray codes as occupied, excludes active jobs for destination reservations, and joins stock profiles used by current inbound rules.
- Step 4: Run tests and verify GREEN
Run Step 2. Expected: PASS.
- Step 5: Commit
git add ruoyi-admin/src/main/java/com/ruoyi/out/dense ruoyi-admin/src/main/resources/mapper/out/DenseLaneMapper.xml ruoyi-admin/src/test/java/com/ruoyi/out/dense
git commit -m "feat: enforce dense lane outermost order"
Task 4: Relocation Job Generation And Completion
Files:
- Create:
ruoyi-admin/src/main/java/com/ruoyi/out/relocation/domain/RelocationGenerateRequest.java - Create:
ruoyi-admin/src/main/java/com/ruoyi/out/relocation/domain/RelocationPreview.java - Create:
ruoyi-admin/src/main/java/com/ruoyi/out/relocation/mapper/RelocationJobMapper.java - Create:
ruoyi-admin/src/main/resources/mapper/out/RelocationJobMapper.xml - Create:
ruoyi-admin/src/main/java/com/ruoyi/out/relocation/service/IRelocationJobService.java - Create:
ruoyi-admin/src/main/java/com/ruoyi/out/relocation/service/impl/RelocationJobServiceImpl.java - Create:
ruoyi-admin/src/main/java/com/ruoyi/out/relocation/controller/RelocationJobController.java - Create:
ruoyi-admin/src/test/java/com/ruoyi/out/relocation/service/impl/RelocationJobServiceImplTest.java - Modify:
ruoyi-admin/src/main/java/com/ruoyi/api/controller/ExternalApiController.java
Interfaces:
-
Produces:
List<String> createBlockerRelocations(String blockedJobId). -
Produces:
RelocationPreview preview(RelocationGenerateRequest request)andList<String> generate(RelocationGenerateRequest request). -
Produces:
AjaxResult completeFromWcs(String jobId). -
Step 1: Write failing relocation tests
Cover type 23/task sequence, one main job per tray, one detail per stock detail, same-floor/different-lane rejection, source status 4/target status 3 reservation, all-or-nothing capacity validation, completion inventory move, cargo status swap, archive, duplicate callback, and dispatch wake-up after commit.
- Step 2: Run test and verify RED
& 'D:\BDevTools\maven\apache-maven-3.9.11\bin\mvn.cmd' -pl ruoyi-admin -Dtest=RelocationJobServiceImplTest test
Expected: FAIL because relocation service does not exist.
- Step 3: Implement transactional generation and completion
Use @Transactional(rollbackFor = Exception.class). Generate blockers outer-to-inner, reserve all destinations before inserting jobs, copy stock trace fields into job details, and create dispatch rows. On completion, lock and validate active type 23, update every bas_stock row for the tray, switch cargo statuses, archive job/detail with explicit column lists, delete active rows, then dispatch the next eligible source-lane job after commit.
- Step 4: Route WCS completion by type
In ExternalApiController.completeOutbound, type 23 calls relocationJobService.completeFromWcs; all other outbound types keep current phase-5/PDA behavior.
- Step 5: Run tests and verify GREEN
Run Step 2. Expected: PASS.
- Step 6: Commit
git add ruoyi-admin/src/main/java/com/ruoyi/out/relocation ruoyi-admin/src/main/resources/mapper/out/RelocationJobMapper.xml ruoyi-admin/src/main/java/com/ruoyi/api/controller/ExternalApiController.java ruoyi-admin/src/test/java/com/ruoyi/out/relocation
git commit -m "feat: add dense warehouse relocation jobs"
Task 5: Integrate Existing Outbound Allocation And Location Outbound
Files:
- Modify:
ruoyi-admin/src/main/java/com/ruoyi/out/stockout/service/impl/OutStockoutServiceImpl.java - Modify:
ruoyi-admin/src/main/java/com/ruoyi/out/location/service/impl/LocationOutboundServiceImpl.java - Modify:
ruoyi-admin/src/test/java/com/ruoyi/out/stockout/service/impl/OutStockoutServiceImplTest.java - Modify:
ruoyi-admin/src/test/java/com/ruoyi/out/location/service/impl/LocationOutboundServiceImplTest.java
Interfaces:
-
Consumes: relocation blocker generation and unified dispatch from Tasks 2 and 4.
-
Produces: allocation responses that distinguish dispatched, queued-for-retry, and blocked-by-relocation jobs.
-
Step 1: Add failing integration-unit tests
Assert auto/manual allocation no longer calls MydoJobService.pushOutJobToWcs, specified stock allocation creates blocker relocations before dispatch, normal non-03 allocation dispatches directly, location outbound creates relocations for non-outbound full blockers, and WCS failure returns business success with compensation message.
- Step 2: Run tests and verify RED
& 'D:\BDevTools\maven\apache-maven-3.9.11\bin\mvn.cmd' -pl ruoyi-admin -Dtest=OutStockoutServiceImplTest,LocationOutboundServiceImplTest test
- Step 3: Replace direct push calls with prepare-and-dispatch orchestration
After each successful database allocation, call blocker generation for the selected job, create dispatch rows for every new job, and dispatch only currently eligible jobs. Keep existing non-dense procedure behavior and stock-status filters unchanged.
- Step 4: Run tests and verify GREEN
Run Step 2. Expected: PASS.
- Step 5: Commit
git add ruoyi-admin/src/main/java/com/ruoyi/out/stockout/service/impl/OutStockoutServiceImpl.java ruoyi-admin/src/main/java/com/ruoyi/out/location/service/impl/LocationOutboundServiceImpl.java ruoyi-admin/src/test/java/com/ruoyi/out/stockout ruoyi-admin/src/test/java/com/ruoyi/out/location
git commit -m "feat: prepare dense blockers during outbound allocation"
Task 6: KPI Dense Plan Manual Relocation
Files:
- Modify:
ruoyi-admin/src/main/java/com/ruoyi/kpi/controller/KpiController.java - Modify:
ruoyi-admin/src/main/java/com/ruoyi/kpi/service/KpiService.java - Modify:
ruoyi-admin/src/main/java/com/ruoyi/kpi/service/impl/KpiServiceImpl.java - Modify:
ruoyi-ui/src/api/kpi/kpi.js - Modify:
ruoyi-ui/src/views/kpi/plan/index.vue - Modify:
ruoyi-ui/src/views/kpi/plan/components/DenseCargoSpaceMap.vue - Create:
ruoyi-admin/src/test/java/com/ruoyi/kpi/service/impl/KpiDenseRelocationServiceTest.java
Interfaces:
-
Produces:
GET /kpi/denseRelocation/options,POST /kpi/denseRelocation/preview, andPOST /kpi/denseRelocation/generate. -
Step 1: Write failing controller/service tests
Assert only warehouse 03 is accepted, target lane floor equals source/current floor, options require sufficient compatible capacity, preview returns exact outer trays and inventory totals, and generate revalidates state.
- Step 2: Run Java tests and verify RED
& 'D:\BDevTools\maven\apache-maven-3.9.11\bin\mvn.cmd' -pl ruoyi-admin -Dtest=KpiDenseRelocationServiceTest test
- Step 3: Implement backend endpoints and existing-style UI
Add a compact “指定移库” button to the dense toolbar. Use an Element UI dialog with source lane, numeric tray count, target lane, and a fixed-height preview table. Do not add decorative cards or alter map dimensions. Refresh map data after successful generation.
- Step 4: Run Java tests and production UI build
& 'D:\BDevTools\maven\apache-maven-3.9.11\bin\mvn.cmd' -pl ruoyi-admin -Dtest=KpiDenseRelocationServiceTest test
Set-Location ruoyi-ui
npm run build:prod
Expected: tests PASS and Vue build exits 0.
- Step 5: Commit
git add ruoyi-admin/src/main/java/com/ruoyi/kpi ruoyi-admin/src/test/java/com/ruoyi/kpi ruoyi-ui/src/api/kpi/kpi.js ruoyi-ui/src/views/kpi/plan
git commit -m "feat: add KPI dense lane relocation"
Task 7: Dense Lane Outbound Menu And Workflow
Files:
- Create:
ruoyi-admin/src/main/java/com/ruoyi/out/dense/controller/DenseLaneOutboundController.java - Create:
ruoyi-admin/src/main/java/com/ruoyi/out/dense/domain/DenseLaneOutboundQuery.java - Create:
ruoyi-admin/src/main/java/com/ruoyi/out/dense/domain/DenseLaneOutboundRequest.java - Create:
ruoyi-admin/src/main/java/com/ruoyi/out/dense/domain/DenseLaneSummary.java - Create:
ruoyi-admin/src/main/java/com/ruoyi/out/dense/service/IDenseLaneOutboundService.java - Create:
ruoyi-admin/src/main/java/com/ruoyi/out/dense/service/impl/DenseLaneOutboundServiceImpl.java - Create:
ruoyi-ui/src/api/out/denseLaneOutbound.js - Create:
ruoyi-ui/src/views/out/denseLaneOutbound/index.vue - Create:
ruoyi-admin/src/test/java/com/ruoyi/out/dense/service/impl/DenseLaneOutboundServiceImplTest.java
Interfaces:
-
Produces:
GET /out/denseLaneOutbound/list,GET /out/denseLaneOutbound/preview, andPOST /out/denseLaneOutbound/generate. -
Step 1: Write failing service tests
Assert list groups only full 03 dense lanes, totals all stock details per tray, preview selects exactly outermost N unreserved trays, quantity over capacity fails, stale preview fails generation, exit compatibility is validated, and every generated type-20 job contains the selected tray's complete inventory details.
- Step 2: Run tests and verify RED
& 'D:\BDevTools\maven\apache-maven-3.9.11\bin\mvn.cmd' -pl ruoyi-admin -Dtest=DenseLaneOutboundServiceImplTest test
- Step 3: Implement backend and menu page
Use the migration permissions from Task 1. The page displays group code, area, row, floor, full/available tray counts, total stock, current outer tray, and expandable inventory details. Generation dialog uses an integer stepper, exit selector, and preview table showing exact trays and quantities.
- Step 4: Verify tests and UI build
Run Task 6 Step 4 with DenseLaneOutboundServiceImplTest. Expected: PASS and build exit 0.
- Step 5: Commit
git add ruoyi-admin/src/main/java/com/ruoyi/out/dense ruoyi-admin/src/test/java/com/ruoyi/out/dense ruoyi-ui/src/api/out/denseLaneOutbound.js ruoyi-ui/src/views/out/denseLaneOutbound sql/20260716_dense_outbound_relocation_dispatch.sql
git commit -m "feat: add dense lane outbound workflow"
Task 8: Outbound Job Management Dispatch UI
Files:
- Modify:
ruoyi-ui/src/api/out/job.js - Modify:
ruoyi-ui/src/views/out/job/index.vue - Modify:
sql/20260716_dense_outbound_relocation_dispatch.sql - Create:
ruoyi-admin/src/test/java/com/ruoyi/out/job/controller/OutMydoJobDispatchControllerTest.java
Interfaces:
-
Consumes: dispatch fields and
PUT /out/job/pushWcs/{jobId}. -
Step 1: Write failing controller permission/state test
Assert the endpoint requires out:job:pushWcs, delegates with MANUAL, rejects completed jobs, and returns blocked reason without calling WCS when a dense job is not outermost.
- Step 2: Run test and verify RED
& 'D:\BDevTools\maven\apache-maven-3.9.11\bin\mvn.cmd' -pl ruoyi-admin -Dtest=OutMydoJobDispatchControllerTest test
- Step 3: Implement UI columns and manual action
Add WCS status, automatic retry count, and last-error tooltip columns. Use the existing send icon button with tooltip “手动下发 WCS”, permission out:job:pushWcs, and a confirmation message containing attempts and last error. Show it for pending, retry-wait, exhausted, and blocked active jobs; backend remains authoritative.
- Step 4: Verify controller and UI build
Run Step 2 and npm run build:prod. Expected: PASS and build exit 0.
- Step 5: Commit
git add ruoyi-admin/src/test/java/com/ruoyi/out/job ruoyi-ui/src/api/out/job.js ruoyi-ui/src/views/out/job/index.vue sql/20260716_dense_outbound_relocation_dispatch.sql
git commit -m "feat: add manual WCS dispatch action"
Task 9: Full Regression, Migration, And Runtime Scenarios
Files:
- Create:
docs/testing/2026-07-16-dense-outbound-relocation-dispatch-report.md
Interfaces:
-
Verifies all interfaces produced above as one workflow.
-
Step 1: Run all backend tests
& 'D:\BDevTools\maven\apache-maven-3.9.11\bin\mvn.cmd' -pl ruoyi-admin -am test
Expected: BUILD SUCCESS with zero test failures.
- Step 2: Run backend package and frontend production build
& 'D:\BDevTools\maven\apache-maven-3.9.11\bin\mvn.cmd' clean package -DskipTests
Set-Location ruoyi-ui
npm run build:prod
Expected: both commands exit 0.
- Step 3: Apply migration to the configured disposable/local database
Execute sql/20260716_dense_outbound_relocation_dispatch.sql twice. Expected: both runs succeed, one task type 23 row, one Quartz task, one menu, three button permissions, and no duplicate indexes.
- Step 4: Run runtime integration scenarios
Verify with controlled WCS mock responses: initial failure plus five retries reaches exhausted; manual recovery succeeds; direction-1 and direction-2 lanes reject inner jobs; blocker relocation completes source/target inventory atomically; location outbound creates blockers; KPI manual relocation stays same-floor; lane outbound selects exactly outer N; non-03 outbound remains direct.
- Step 5: Verify UI with Playwright screenshots
Check outbound job management, KPI relocation dialog, and dense lane outbound page at desktop and mobile/narrow viewports. Verify no overlap, clipped button text, blank table, or broken dialog sizing.
- Step 6: Write the report and run requirement audit
Record commands, counts, screenshots, created job IDs, retry transitions, relocation source/target IDs, lane outbound selections, and residual risks. Map each of the six user requirements to direct evidence.
- Step 7: Commit the verification report
git add docs/testing/2026-07-16-dense-outbound-relocation-dispatch-report.md
git commit -m "test: verify dense outbound dispatch workflows"