docs: define WMS shadow-only safety design

This commit is contained in:
zgw
2026-08-11 16:49:45 +08:00
parent 916ac6bda3
commit 21dcac8932

View File

@@ -0,0 +1,92 @@
# FT546 WMS Shadow-Only Design
## Goal
Create a clean field-test branch directly from `origin/main` that runs the Java storage algorithm only as an observer. The existing Legacy WMS stored procedures remain the sole owners of inbound and outbound decisions and business writes.
## Safety invariants
1. The branch is based on `origin/main` and contains no license, UI, TLS, tidy, replay, PDA, WCS callback, or ACTIVE workflow integration changes.
2. Legacy stored procedures are called exactly once with the same inputs and their return values remain authoritative.
3. Shadow planning runs before the Legacy allocation so it observes the pre-decision state, but it runs in a separate `REQUIRES_NEW` transaction with a configurable timeout.
4. A shadow exception, timeout, missing optional input, missing algorithm object, or comparison logging failure is caught and logged; it cannot skip, replace, roll back, or rewrite the Legacy result.
5. No ACTIVE entry point is exposed by `ruoyi-admin`. Startup rejects any algorithm mode other than `SHADOW` when shadow observation is enabled.
6. Shadow mode writes only `alg.*` read-model and diagnostic objects. It never calls reservation, tidy, deep-workflow, replay, move-completion, or other procedures that write WMS business tables.
7. Shadow observation is disabled by default and must be enabled explicitly in the IDEA Run Configuration.
## Architecture
The existing `fortucky-algorithm` planner and JDBC read model are reused as an internal dependency. A new `ruoyi-admin` shadow adapter owns the integration boundary:
- `ShadowObservationProperties` controls enablement, warehouse fallback, and timeout.
- `ShadowSafetyGuard` validates the effective mode at startup.
- `ShadowPlanningObserver` performs fail-open inbound/outbound planning in an independent transaction and returns an immutable observation token.
- Legacy services invoke the observer immediately before their existing stored procedure, execute the original Legacy code unchanged, then submit the Legacy result for comparison logging.
There are no algorithm controllers, ACTIVE schedulers, workflow callbacks, reservation calls, or changes to the frontend.
## Data flow
### Inbound
1. Load the same inbound job that `origin/main` already loads.
2. Ask the shadow observer to compute a proposed location. Failures become a `shadow planning failed` log entry.
3. Invoke the existing `allotInJobSpace` stored procedure exactly once.
4. Reload and return the Legacy job exactly as `origin/main` does.
5. Log the proposed shadow location beside the Legacy location.
### Outbound
1. Before each existing automatic or manual Legacy allocation call, ask the observer for a plan.
2. Missing project/stock data is recorded as a shadow rejection; it never blocks the Legacy procedure.
3. Invoke the original `autoAllot` or `manualAllot` procedure exactly once.
4. Preserve the original success/warning response construction.
5. Log the shadow status/code beside the Legacy procedure code.
## Transaction and failure isolation
Shadow planning uses `TransactionTemplate` with `PROPAGATION_REQUIRES_NEW`, read-model writes enabled, and a short timeout. The transaction completes or rolls back before Legacy allocation starts, so algorithm locks and rollback state cannot leak into the Legacy transaction. The adapter catches runtime failures at its public boundary and returns an empty observation.
The integration never queries `alg.tidy_mode` and never uses an update lock for admission control.
## Shadow database package
`install-shadow.sql` creates only:
- policy/read-model/diagnostic tables required by inbound and outbound planning;
- read-only views over WMS business data;
- topology, snapshot, lane-state, dirty-lane refresh, and decision-log support;
- three narrowly scoped `dbo` triggers that only enqueue affected lanes into `alg.dirty_lane_queue`;
- initial read-model synchronization.
It excludes tidy, replay, reservation mutation procedures, deep workflow, outbound workflow, WCS completion, PDA callback, and any stored procedure that inserts, updates, or deletes WMS business rows.
`uninstall-shadow.sql` first removes the three `dbo` triggers, then removes only shadow-owned `alg` objects and the `alg` schema. It never modifies WMS business rows. Operators must export `alg.decision_log` before uninstalling.
## Configuration
The IDEA field-test configuration sets:
```text
FORTUCKY_SHADOW_ENABLED=true
FORTUCKY_ALGORITHM_MODE=SHADOW
FORTUCKY_ALGORITHM_DATABASE_WRITES_ENABLED=true
FORTUCKY_ALGORITHM_WAREHOUSE_ID=<field warehouse>
FORTUCKY_SHADOW_TIMEOUT_SECONDS=3
```
Replay variables remain unset. The stable `origin/main` Run Configuration is kept in a separate source directory for immediate rollback.
## Verification
Automated tests prove:
- observer failure still invokes Legacy exactly once;
- missing project/stock input still invokes Legacy exactly once;
- Legacy result and response structure remain authoritative;
- SHADOW configuration rejects ACTIVE mode;
- shadow SQL contains only allow-listed objects and no WMS business-table DML;
- install/uninstall object lists are symmetrical;
- existing project tests and packaging still succeed.
Field verification compares inbound/outbound shadow logs with Legacy results, monitors SQL latency and locks, and stops immediately if normal WMS behavior differs from `origin/main`.