fix(shadow): protect observed vehicle traffic

This commit is contained in:
zgw
2026-09-09 15:42:09 +08:00
parent edb13450a6
commit 4408958443
12 changed files with 545 additions and 4 deletions

View File

@@ -0,0 +1,30 @@
# FT546 影子版本:动态占用修复
本次源码版本标签:`ft546-shadow-20260909-observed-traffic-v1`。
## 修复内容
- 每次影子快照额外记录车辆当前站点、忙碌车辆的 PLC path,以及已下发活动队列的 path_info。
- 直线段按现场地图逐格展开,同时保护节点和边资源;路径缺失、非法、跨层或与当前位置断开时,对该车所在楼层保守保持占用约束。
- 观察约束只用于本轮影子判断,不写入、不释放持久化预约;车辆自己的当前位置不会阻止自己离开。
- 已观察车辆在下一完整批次缺失时,本轮停止预测,避免把数据缺失误判成道路释放。
- 避让路线如果穿过观察约束,转换为 `HOLD / OBSERVED_TRAFFIC_CONFLICT`,不能用避让绕过现场车辆。
## 验证结果
本地离线验证覆盖 28 个测试:调度核心、影子占用边界、延迟比较和现场 50 份输入重放均通过。50 份原始输入哈希均保持一致;三组已知风险任务 501、60935、31372 在不带观察约束的反事实中可放行,带观察约束时分别被车辆 2/3、3、3 阻挡。该重放没有重建历史预约账本,也没有连接或修改现场数据库。
## 避让点结论
现场正式 mapper 只把 `remark='cache'` 的点作为缓存候选,并排除当前车辆站点;`BaseSRgvThread` 还按 `cargo_place_site` 查询任务占用。只读地图核验显示:
- 1–7 层 `050201/050301`、`050202/050302` … `050207/050307`,8 层 `050308/050408` 是明确 cache 点;
- `0502xx` 在导出地图上通常只有一个通行邻接,不满足当前安全点至少两个邻接的约束;
- `0503xx` 和 8 层 cache 点虽然通常有两个邻接,但属于通道割点,停放可能切断通道;1 层 `050201` 在 50 份样本中还出现过 18 次车辆占用,`050301` 出现过 4 次,并有活动任务目标;
- `050101`、`070101` 是业务货位,`070301`、`090301` 是 `outCache`,均不作为候选。
因此 `safe-wait-sites` 和 `safe-yield-sites` 仍保持空配置。当前没有证据允许自动启用某个避让点;若现场确认某点可以停放,需同时确认占用语义、回退路线、非割点通道和 PLC/WMS 业务互斥后再单独配置。
## 现场动作
用户停止影子程序后,在本地工作树编译并启动新源码,核对 `/shadow/status` 的 `runtimeIdentity.buildId` 为上述标签、启动检查全部 PASS。不要停止正式 WCS,不要执行生产库 SQL。先运行观察,后续再用新日志评估。

View File

@@ -0,0 +1,20 @@
# Shadow observed traffic repair
**Goal:** Prevent shadow predictions from crossing observed vehicle positions and issued routes. Production SQL and runtime are out of scope.
**Architecture:** Add immutable, per-snapshot resource owners, separate from the persisted prediction ledger. Existing DispatchSnapshot constructors supply an empty map. Only the shadow assembler supplies observed owners. The coordinator checks before reservation and also checks proposed yield routes. Unknown moving paths block their floor; missing previously observed vehicles reject the snapshot.
## Work and verification
- [x] Reproduce with ShadowObservedTrafficTest: 8 tests, 5 expected assertion failures; baseline reactor passes.
- [ ] Add snapshot overload accepting Map<String, Set<String>> observedResourceOwners; defensively copy and validate against topology resources.
- [ ] Add ShadowObservedTrafficProjector.project(batch, topology); project current sites, expand orthogonal live paths through all map nodes/edges, include active issued queue routes; ignore finished queue history. Keep an in-process high-water vehicle roster and reject missing/contradictory vehicle facts.
- [ ] Coordinator checks other owners before DeadlockGuard reservation; convert conflicting yield into HOLD, without writing observations to the ledger.
- [ ] Run `mvn -o -pl ruoyi-wcs-shadow -am -Dtest=ShadowObservedTrafficTest -Dsurefire.failIfNoSpecifiedTests=false test`; expand boundary tests and run the full reactor.
- [ ] Replay the three captured risk cases with real assembler/coordinator; retain input hashes and clearly distinguish this replay from reconstruction of the historical ledger.
- [ ] Review cache points against formal mapper rules and map geometry. Document candidate points only; keep safe-wait/yield configuration empty.
- [ ] Review diff, update build identity and repair notes, deliver source without deploying or restarting either field application.
## Safety constraints
No production database writes, no PLC/WMS calls, no remote update/restart. Do not relax allowSend eligibility or release persisted UNKNOWN/OCCUPIED reservations. Old shared dispatch constructors retain existing behavior. A complete source read is not a PLC-atomic observation; this repair is for shadow validation, not approval of production takeover.