test(ft546): verify read-only shadow operation
This commit is contained in:
252
docs/runbooks/ft546-realtime-shadow-runbook.md
Normal file
252
docs/runbooks/ft546-realtime-shadow-runbook.md
Normal file
@@ -0,0 +1,252 @@
|
||||
# FT546 实时只读影子运行手册
|
||||
|
||||
## 1. 适用范围
|
||||
|
||||
本手册只用于运行独立的 `ruoyi-wcs-shadow` 进程,采集新调度算法的只读影子证据。
|
||||
|
||||
- 现场 `LEGACY` WCS 始终是唯一生产调度者、PLC 写入者和 WMS 回调者。
|
||||
- 本阶段不切换 `STANDARD`,不允许 shadow 连接 PLC/WMS,也不允许写生产业务表。
|
||||
- 停止或移除 shadow 进程就是本阶段的回滚;不得停止或切换稳定 WCS。
|
||||
- 本地自动化测试不能替代 SQL Server、网络隔离或现场观察门禁。
|
||||
|
||||
## 2. 当前验证边界
|
||||
|
||||
| 门禁 | 当前状态 | 允许的结论 |
|
||||
| --- | --- | --- |
|
||||
| Java 单元、Spring 上下文、H2 E2E | 可在本地执行 | 代码级只读链路和协议证据可验证 |
|
||||
| PowerShell 脚本生命周期 | 可用无网络 sleeper jar 本地执行 | 确认、哈希、PID 精确启停和离线导出逻辑可验证 |
|
||||
| SQL Server 集成 | `NOT_RUN` | 不得宣称数据库集成或现场就绪 |
|
||||
| PLC/WMS 网络 deny | `NOT_RUN` | 必须由目标 shadow 主机的新鲜审计报告证明 |
|
||||
| HIL 与现场影子窗口 | `NOT_RUN` | 不得部署或开始采集 |
|
||||
|
||||
`application-shadow-local.yml` 是外部配置模板,不是可直接运行的 H2 profile。H2 仍是 test-scope 依赖,且测试资源不会进入打包 jar;没有审批过的独立 SQL Server 环境时,不运行 jar 本地 smoke。
|
||||
|
||||
当前 `shadow_hold_history` 能跨重启恢复 wait edge 和连续 HOLD 计数,测试覆盖第三次相同 HOLD 后计数为 3。生产调度内核尚无消费该计数并触发 reroute 的策略,因此不得把“计数恢复”报告成“第三次 HOLD 已重规划”。该语义应在取得影子证据并明确路线/阻塞资源状态后单独设计。
|
||||
|
||||
## 3. 前置条件
|
||||
|
||||
开始任何现场操作前,逐项确认:
|
||||
|
||||
1. 稳定 WCS 健康,实际制品、配置、PID、命令行和监听端口可读取。
|
||||
2. source 登录只能读取 `shadow_ro.*` 批准视图,无生产表 `INSERT`、`UPDATE`、`DELETE`、`EXECUTE`、`ALTER`、`CONTROL` 或所有权权限。
|
||||
3. evidence 数据库与 source 数据库物理分离,evidence 登录只在 evidence 数据库具备所需写权限。
|
||||
4. shadow 部署目录、日志目录、端口和 PID 文件均与稳定 WCS 分离。
|
||||
5. shadow 主机到 PLC 写端点和生产 WMS 回调端点已在网络层拒绝,并生成不超过 60 分钟的 JSON 审计报告。
|
||||
6. 已约定生产 DB 延迟、shadow CPU/内存、source lag 和 evidence 磁盘阈值。
|
||||
7. 已准备立即停止 shadow 的值守人员;不安排任何稳定 WCS 切换动作。
|
||||
|
||||
权限报告最小结构:
|
||||
|
||||
```json
|
||||
{
|
||||
"generatedAtUtc": "2026-08-14T10:00:00Z",
|
||||
"status": "PASS",
|
||||
"source": {
|
||||
"server": "source-host",
|
||||
"database": "FT546-wcs",
|
||||
"login": "ft546_shadow_reader",
|
||||
"approvedViewsReadable": true,
|
||||
"productionWritePermissionCount": 0
|
||||
},
|
||||
"evidence": {
|
||||
"server": "evidence-host",
|
||||
"database": "FT546-shadow",
|
||||
"login": "ft546_shadow_writer",
|
||||
"requiredWritesGranted": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
网络 deny 报告最小结构:
|
||||
|
||||
```json
|
||||
{
|
||||
"generatedAtUtc": "2026-08-14T10:00:00Z",
|
||||
"status": "PASS",
|
||||
"plcEgressDenied": true,
|
||||
"wmsEgressDenied": true
|
||||
}
|
||||
```
|
||||
|
||||
报告必须来自已批准环境的实际检查。不得手工伪造 `PASS`。
|
||||
|
||||
## 4. 构建与本地验证
|
||||
|
||||
在隔离工作树执行:
|
||||
|
||||
```powershell
|
||||
mvn clean test
|
||||
mvn -pl ruoyi-wcs-shadow -am -DskipTests package
|
||||
powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass `
|
||||
-File .\tools\shadow\tests\Test-Ft546ShadowScripts.ps1
|
||||
```
|
||||
|
||||
打包后确认 shadow jar 不含 H2 或测试 profile:
|
||||
|
||||
```powershell
|
||||
jar tf .\ruoyi-wcs-shadow\target\ruoyi-wcs-shadow-3.8.9.jar |
|
||||
Select-String 'h2|application-shadow-test|application-shadow-local'
|
||||
```
|
||||
|
||||
预期没有匹配项。该检查证明打包边界,不证明现场可运行。
|
||||
|
||||
## 5. 捕获稳定 WCS 基线
|
||||
|
||||
使用现场实际路径和 PID,不用 Git 分支或远端引用代替已部署制品:
|
||||
|
||||
```powershell
|
||||
.\tools\shadow\Capture-StableWcsManifest.ps1 `
|
||||
-StableArtifact 'D:\wcs-stable\ruoyi-admin.jar' `
|
||||
-StablePid 1234 `
|
||||
-Configuration 'D:\wcs-stable\application.yml' `
|
||||
-OutputJson 'D:\shadow-evidence\stable-manifest.json'
|
||||
```
|
||||
|
||||
归档输出 JSON。确认其中的 artifact/config SHA-256、PID、启动时间、命令行和监听端口与现场一致。
|
||||
|
||||
## 6. 准备 shadow 目录和配置
|
||||
|
||||
将打包的 shadow jar 和一份外部 site 配置放在独立部署目录。配置只允许以下网络相关内容:
|
||||
|
||||
- loopback 状态端点;
|
||||
- source SQL Server 只读连接;
|
||||
- 独立 evidence SQL Server 写连接。
|
||||
|
||||
配置不得包含 PLC IP/port 或 WMS URL。密码使用受控环境变量或主机密钥设施,不写入 Git、预检 JSON、PID 文件或命令行。
|
||||
|
||||
`Start-Ft546Shadow.ps1` 会从成功预检向进程注入 artifact/config SHA-256、source server/database、loopback address/port 和磁盘阈值,供应用内 startup gate 复核。
|
||||
|
||||
## 7. 运行预检
|
||||
|
||||
```powershell
|
||||
.\tools\shadow\Test-Ft546ShadowPreflight.ps1 `
|
||||
-StableManifest 'D:\shadow-evidence\stable-manifest.json' `
|
||||
-ShadowArtifact 'D:\ft546-shadow\ruoyi-wcs-shadow.jar' `
|
||||
-Config 'D:\ft546-shadow\application-shadow-site.yml' `
|
||||
-DeploymentDirectory 'D:\ft546-shadow' `
|
||||
-PermissionReport 'D:\shadow-evidence\permission-report.json' `
|
||||
-NetworkDenyReport 'D:\shadow-evidence\network-deny-report.json' `
|
||||
-StatusUri 'http://127.0.0.1:18091/shadow/status' `
|
||||
-MinimumFreeBytes 10737418240 `
|
||||
-OutputJson 'D:\shadow-evidence\shadow-preflight.json'
|
||||
```
|
||||
|
||||
预检会失败关闭并留下 JSON,检查内容包括:
|
||||
|
||||
- 稳定 PID 健康且 artifact/config 哈希未变;
|
||||
- shadow jar/config 位于独立部署目录;
|
||||
- YAML 中 source/evidence server、database、username 与权限报告一致;
|
||||
- source/evidence 数据库不同;
|
||||
- 权限和网络 deny 报告为新鲜 `PASS`;
|
||||
- 状态端点为 loopback,端口不与稳定 WCS 冲突;
|
||||
- 配置无 PLC/WMS 端点;
|
||||
- evidence 磁盘空间达到阈值;
|
||||
- shadow 部署目录中不存在当前 `shadow.pid.json`。即使其中记录的进程已退出,陈旧 PID 文件也会使预检失败;必须先核验并按停机/归档流程处理,禁止覆盖后启动。
|
||||
|
||||
任何一项失败都不得启动。
|
||||
|
||||
### 7.1 处理陈旧 PID 记录
|
||||
|
||||
不得删除或覆盖 `shadow.pid.json`。先读取其中的 `pid`:如果该 PID 仍存在,只能执行第 10 节的 `Stop-Ft546Shadow.ps1`,由脚本校验启动时间、Java 可执行文件、shadow jar 哈希和 `-jar` 命令行;校验不一致时停止操作并升级处理。
|
||||
|
||||
只有在 `Get-Process` 连续两次(间隔至少 5 秒)均确认该 PID 不存在后,才可由两名复核人员将原记录改名为 `shadow.stale.<UTC timestamp>.json`。变更单必须保留原记录 SHA-256、两次查询输出、归档路径、操作者和复核人。归档后重新执行完整预检,旧的预检 JSON 不得复用。
|
||||
|
||||
## 8. 启动与初始观察
|
||||
|
||||
只有经过双人复核的成功预检才能启动:
|
||||
|
||||
```powershell
|
||||
$started = .\tools\shadow\Start-Ft546Shadow.ps1 `
|
||||
-ConfirmReadOnlyShadow `
|
||||
-PreflightJson 'D:\shadow-evidence\shadow-preflight.json'
|
||||
|
||||
$started
|
||||
Invoke-RestMethod 'http://127.0.0.1:18091/shadow/status'
|
||||
```
|
||||
|
||||
启动后立即重新核对:
|
||||
|
||||
1. 稳定 PID、制品哈希、健康状态和 PLC writer 所有权均未变化。
|
||||
2. shadow PID 与稳定 PID 不同;PID 文件位于 shadow 部署目录。
|
||||
3. shadow 只监听预检中的 loopback 端口。
|
||||
4. source 审计只有批准视图的 `SELECT`;生产业务表写审计为零。
|
||||
5. PLC/WMS 网络监控没有 shadow 连接尝试。
|
||||
|
||||
先以低频轮询观察 15 分钟。只有稳定 WCS 指标不变、source 查询延迟在阈值内、source lag 正常、evidence 持续增长且磁盘安全时,才可延长观察窗口。
|
||||
|
||||
`STARTING` 表示尚无完整 cycle;`READY` 表示最近 cycle 完成;`DEGRADED` 必须按 reason code 调查。证据存储失败或碰撞会永久停止该进程继续读取,需停止并保留现场。
|
||||
|
||||
## 9. 立即停止条件
|
||||
|
||||
出现任一条件,立即停止 shadow,不等待当前观察窗口结束:
|
||||
|
||||
- 稳定 WCS 健康、CPU、内存、线程、PID 或 PLC writer 所有权变化;
|
||||
- 生产 DB 延迟超过约定阈值,或出现锁等待/连接池压力;
|
||||
- source 权限、数据库身份或批准视图发生变化;
|
||||
- source lag 超出事实新鲜度,或连续 query timeout;
|
||||
- 任意 PLC/WMS 连接尝试或任意生产表写审计;
|
||||
- evidence 磁盘低于阈值、写失败、哈希碰撞或 evidence backlog 异常;
|
||||
- shadow CPU/内存超过约定上限;
|
||||
- 状态为 `DEGRADED` 且原因不能立即解释为短暂 source 故障。
|
||||
|
||||
## 10. 精确停止与回滚
|
||||
|
||||
```powershell
|
||||
.\tools\shadow\Stop-Ft546Shadow.ps1 `
|
||||
-PidFile 'D:\ft546-shadow\shadow.pid.json'
|
||||
```
|
||||
|
||||
停止脚本只接受该 PID 文件记录的进程,并逐项验证 PID、启动时间、Java 可执行文件、shadow jar 哈希和 `-jar` 命令行。任何不一致都拒绝停止,不会按 `java` 进程名批量查杀。成功后 PID 记录改名归档为 `shadow.stopped.<timestamp>.json`。
|
||||
|
||||
回滚完成条件:shadow PID 不存在,稳定 PID/健康/PLC 所有权保持原值,网络与数据库审计无 shadow 副作用。稳定 WCS 从未停止或切换。
|
||||
|
||||
## 11. 导出证据
|
||||
|
||||
现场 SQL Server 模式使用集成认证,或把 SQL 密码短暂放入当前进程环境变量 `FT546_SHADOW_EVIDENCE_PASSWORD`:
|
||||
|
||||
```powershell
|
||||
.\tools\shadow\Export-Ft546ShadowEvidence.ps1 `
|
||||
-EvidenceServer 'evidence-host' `
|
||||
-EvidenceDatabase 'FT546-shadow' `
|
||||
-EvidenceUsername 'ft546_shadow_writer' `
|
||||
-RunId '00000000-0000-0000-0000-000000000000' `
|
||||
-OutputDirectory 'D:\shadow-evidence\export-20260814'
|
||||
```
|
||||
|
||||
离线复核模式接受已审批工具生成的快照目录:
|
||||
|
||||
```powershell
|
||||
.\tools\shadow\Export-Ft546ShadowEvidence.ps1 `
|
||||
-SnapshotDirectory 'D:\shadow-evidence\approved-snapshot' `
|
||||
-RunId '00000000-0000-0000-0000-000000000000' `
|
||||
-OutputDirectory 'D:\shadow-evidence\export-20260814'
|
||||
```
|
||||
|
||||
输出固定包含:
|
||||
|
||||
- `cycles.csv`、`cycles.json`;
|
||||
- `protocol-differences.csv`;
|
||||
- `algorithm-differences.csv`;
|
||||
- `insufficient-facts.csv`;
|
||||
- `startup-checks.json`;
|
||||
- `manifest.json`、`manifest.sha256`。
|
||||
|
||||
校验:
|
||||
|
||||
```powershell
|
||||
$expected = (Get-Content 'D:\shadow-evidence\export-20260814\manifest.sha256').Split()[0]
|
||||
$actual = (Get-FileHash 'D:\shadow-evidence\export-20260814\manifest.json' -Algorithm SHA256).Hash.ToLowerInvariant()
|
||||
if ($expected -ne $actual) { throw 'EVIDENCE_MANIFEST_HASH_MISMATCH' }
|
||||
```
|
||||
|
||||
将稳定 manifest、preflight JSON、权限报告、网络 deny 报告、启动/停止 PID 记录、状态响应、现场监控截图和导出目录作为同一批次归档。
|
||||
|
||||
## 12. 禁止事项
|
||||
|
||||
- 不在生产数据库内创建 evidence schema 代替独立 evidence 数据库。
|
||||
- 不给 source 登录任何生产写权限。
|
||||
- 不把 `ruoyi-admin` 以 `SHADOW` 模式启动。
|
||||
- 不允许 shadow 配置 PLC/WMS endpoint。
|
||||
- 不用宽泛 Java 进程查杀命令代替 `Stop-Ft546Shadow.ps1`。
|
||||
- 不因为本地/H2 测试通过就跳过 SQL Server、网络或现场门禁。
|
||||
- 不把本阶段结果解释为 `STANDARD` 上线许可。
|
||||
Reference in New Issue
Block a user