176 lines
16 KiB
Markdown
176 lines
16 KiB
Markdown
|
|
# P3-VALIDATION — 高风险场景 S4/S6/S7 + 白名单治理 最终验证报告
|
|||
|
|
|
|||
|
|
> 验证员:Agent-N · 日期:2026-09-04 · 协调板:`GOAL-P3.md`
|
|||
|
|
> 硬约束遵守:未 git commit/push;Python 一律 `.venv\Scripts\python.exe`;LLM key 只经
|
|||
|
|
> server 子进程 env 从 .env 流入(不读不打印不落盘,kimi-k2.6);server 起杀单命令内完成、
|
|||
|
|
> 超时保护、收尾无残留;临时 APS_HOME 零污染 `server/data/`(git status 双冒烟后均 clean);
|
|||
|
|
> `_saga_cp.json` 每次跑测后 `git checkout --` 还原;既有失败一律 stash 基线对照核实。
|
|||
|
|
> 本轮未修改任何产品代码文件。
|
|||
|
|
>
|
|||
|
|
> **缺陷修复复证:Agent-O · 2026-09-04(§7)——FB-03-BUG-1 已修复并复证,
|
|||
|
|
> S6 冒烟复跑 24/24,P3 判定转 GO。**
|
|||
|
|
|
|||
|
|
## 0. TL;DR —— **P3 判定:GO(FB-03-BUG-1 修复复证通过,§7)**
|
|||
|
|
|
|||
|
|
~~条件 NO-GO~~ → **GO**。修复前轮次记录:治理面(白名单 fail-closed、角色门禁、
|
|||
|
|
逐笔卡、双人链、对账、审计、脱敏、攻击面)**全部验证通过**;但 S6 冒烟抓到一个
|
|||
|
|
golden 层物理摸不到的**段 C 产品缺陷**(下述,已修复):
|
|||
|
|
|
|||
|
|
> **FB-03-BUG-1:S6 补录写在真实 MES 断连下 100% 失败回滚。**
|
|||
|
|
> `mes.apply_report`(mes.py:1543)在本地落账**之前**无条件
|
|||
|
|
> `client.post_report()` 同步推送 MES;断连注入(设计 §0.8 官方手法:
|
|||
|
|
> `MES_HTTP_BASE_URL` 指不可达地址)下 MesHttpError 上抛 → execute_plan 步骤异常 →
|
|||
|
|
> 整体失败回滚。即「断连补录」场景在其定义的真实条件下,补录动作物理不可用。
|
|||
|
|
> golden 层全部经 MockMesClient(post_report 永远成功)+ monkeypatch seam,
|
|||
|
|
> 结构上摸不到此路径——与 P1 冒烟 Bug A 同类的「只有真实子进程能暴露」缺陷。
|
|||
|
|
> **这是设计层语义缺口(补录应本地落账 + 待同步标记,还是同步推送容忍失败),
|
|||
|
|
> 非一行笔误,按硬验证约束未自行修复,留待设计/实施轮决策。**
|
|||
|
|
|
|||
|
|
治理机制在失败面前全部正常工作(显式失败文案 + 自动回滚 + 失败现场快照 + 审计齐全)
|
|||
|
|
——缺陷不扩面、不破窗,但段 C 主链路不通,故判条件 NO-GO。
|
|||
|
|
|
|||
|
|
## 1. 全量回归(分批,真实数字)
|
|||
|
|
|
|||
|
|
| 项 | 数字 | 说明 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| golden 全量(191 文件逐跑,可续跑驱动器 `regression_driver.py`) | **1501 passed / 18 failed / 10 errors / 0 skipped / 0 超时** | 结果落盘 `regression_results.jsonl`(191 条逐文件记录) |
|
|||
|
|
| stash 基线对照(9 个失败文件在 HEAD 复跑) | **9/9 文件失败形态逐例一致** | `regression_baseline.jsonl`;全部为既有失败(native sidecar 探测环境依赖 11 例:desktop_sidecar/shadow_price/sobol;folder_schedule 系列 6 例;mes_http 8 errors + mes_readiness 2+4 + trace_external_http 2 errors 等 MES/HTTP fixture 既有失败),**与 P3 零相关** |
|
|||
|
|
| 四文件联合(highrisk+execute+lane+feature_flags) | **65 passed**(复跑确认) | 与 M 自验一致 |
|
|||
|
|
| 攻击专项并入后五文件联合 | **72 passed** | 无跨文件污染 |
|
|||
|
|
| 文档门禁(doc_drift/registry/contract_sync/openapi_schema) | **25 passed** | 与 P2 口径一致 |
|
|||
|
|
| ruff | M 的 8 文件 **59 = 59 零新增**(与 HEAD 多重集比对复算一致);本轮新增文件(攻击测试/驱动器/冒烟脚本)修复后攻击测试与驱动器零违规,冒烟脚本 9/7 条 ≤ s3 先例 11 条同款模式 | — |
|
|||
|
|
|
|||
|
|
**异常观察(如实登记,非 P3 引入)**:`test_cp_engine.py::test_cp_infeasible_solver_meta_
|
|||
|
|
exposes_native_assumption_core` 在大组合批(20 文件同进程、高负载)中 FAILED 一次,
|
|||
|
|
单独跑与 13 文件组合复跑均 PASS(161 passed),未再复现;断言内容是 native 求解器
|
|||
|
|
IIS 标志,P3 不触碰求解器路径,判为负载敏感的既有偶发。
|
|||
|
|
|
|||
|
|
## 2. 偏差⑦⑧ 攻击面专项(确定性测试层)
|
|||
|
|
|
|||
|
|
新建 `tests/golden/test_fallback_p3_attack.py`(7 例,全部确定性,fake runner 零网络):
|
|||
|
|
**7 passed**;并入联合 **72 passed**;ruff 零违规。
|
|||
|
|
|
|||
|
|
| # | 用例 | 攻击面 | 结果 |
|
|||
|
|
|---|------|--------|------|
|
|||
|
|
| A-7-1 | 第二张卡信封完整 + 乱序审批(先批第二张) | 偏差⑦核心回归:修复前第二张卡 100% 信封自破 | **PASS**:两卡 `verify_confirmation_envelope` 均过,乱序双批全成功落账 |
|
|||
|
|
| A-7-2 | 伪造指纹推进(直改 beforeFingerprint 落盘,不重算信封) | 旧卡伪造 | **PASS**:信封「完整性校验失败」→ 执行拒绝,零写入 |
|
|||
|
|
| A-7-3 | 篡改冻结参数(progressPct 80→100 落盘) | 参数伪造 | **PASS**:paramsHash「参数摘要不一致」→ 拒绝,未按篡改值落账 |
|
|||
|
|
| A-7-4 | 重放已执行确认卡(同 confirmId 二次 confirm) | 重放 | **PASS**:「该确认卡已失效」,未重复落账,成功总账仅 1 条 |
|
|||
|
|
| B-8-1 | 双 run 交叉:执行 run A 第一笔 | 偏差⑧边界:跨 run 卡不得被重锚 | **PASS**:A 兄弟卡重锚后可批;run B 卡指纹停留原值 → 漂移检测拦截(DENIED 审计在链) |
|
|||
|
|
| B-8-2 | 重锚后审批窗口内制造非兄弟业务改动 | 偏差⑧核心攻击:非兄弟改动借重锚混过检测 | **PASS**:被漂移检测拦下,第二笔未落账,第一笔不受影响 |
|
|||
|
|
| B-8-3 | 篡改非兄弟卡 runId 蹭重锚(落盘) | 伪造兄弟 | **PASS**:重锚按匹配条件推进了它(机制如实运作),但 paramsHash 破损 → 信封层物理拒绝;真兄弟卡不受影响 |
|
|||
|
|
|
|||
|
|
**附带发现(防御纵深,如实登记)**:审批仓 `transaction()` 每次从磁盘 `_refresh()`,
|
|||
|
|
**纯内存篡改(不落盘)会在 decide 前被刷新抹掉**——本轮首轮攻击测试按内存篡改构造时
|
|||
|
|
三例「攻击」被该机制自动中和(攻击测试改写为落盘篡改后才构成真实攻击面)。内存→盘
|
|||
|
|
的信任方向正确(decide 信盘不信内存)。
|
|||
|
|
|
|||
|
|
## 3. S6 真实冒烟(`smoke/smoke_s6_reconcile.py`,五阶段分跑)
|
|||
|
|
|
|||
|
|
真实 server + 真实 Pi + 真实 kimi-k2.6 + 真实 MES HTTP 适配器(断连 = 未监听端口;
|
|||
|
|
恢复 = 冒烟内嵌最小假 MES HTTP 服务,真实协议在环)。现场 `smoke/site4/` 保留供查验;
|
|||
|
|
结构化结果 `smoke/s6_results.json`;原始 SSE/回复/server 日志同目录。
|
|||
|
|
**总计 19/24 PASS**,5 个失败全部同源(FB-03-BUG-1)。
|
|||
|
|
|
|||
|
|
| # | 验收点 | 结果 | 证据 |
|
|||
|
|
|---|--------|------|------|
|
|||
|
|
| A | 断连注入 | **PASS** | readiness probe `connectivity=failed` + `MES_HTTP_CONNECT_FAILED`(注:本机系统代理会劫持 httpx 本地请求包装成 UPSTREAM_ERROR,冒烟环境层 NO_PROXY 修正后如实呈现 CONNECT_FAILED) |
|
|||
|
|
| B | 断连前现场 | **PASS** | 种子 2 张已下发工单 + mesLinks ×2 + 车间导出 CSV(watcher 投 inbox) |
|
|||
|
|
| C | 断连对话 → S6 兜底 | **PASS ×3** | intent=assistant.reply;inbox/integration-status.md 含 connectivity=failed + 「未连接」;**真实 Pi 产出 scenario=S6 计划 2 步**(frozen、mes.report、正确 woId 9001/9002、进度 100/60 与 CSV 一致) |
|
|||
|
|
| D1/D2 | 逐笔卡 + 机器再生成摘要 | **PASS ×2** | blocks 2 张卡 == 清单 2 项;摘要含「工单 woId=」「计划指纹 sha256:」全结构化 |
|
|||
|
|
| D3–D6 | 逐笔批准落账 | **FAIL ×4(FB-03-BUG-1)** | 两笔均「兜底执行失败(MesHttpError: [MES_HTTP_TIMEOUT] POST /work-orders/EXT-xxxx/reports (HTTP 504)),已自动回滚……你的数据未留下任何变更。失败现场已存档」——**断连下 post_report 必抛 → 回滚**。治理面工作正常:显式失败 + 回滚 + cp_before ×2/失败现场 ×2 建档 |
|
|||
|
|
| G1 | 断连期审计链 | **FAIL(同源)** | chain.ok=True、stage=2 齐全;exec SUCCESS=0(执行未成功,属缺陷表现而非审计缺陷) |
|
|||
|
|
| E | 恢复注入 | **PASS** | 假 MES 上线后 probe `connectivity=ok` |
|
|||
|
|
| F1–F6 | 对账协议全链 | **PASS ×6** | 回复「对账域 2 项:一致 1 / 漂移 1 / 单边缺失 0」;报告 `| EXT-1001 | 9001 | MATCH |` / `| EXT-1002 | 9002 | DRIFT | progressPct 本地=0 外部=40`;manifest 2 份外部原文 sha256 全部应验;ALGO_RUN 审计 rationale 含 manifestSha256=23695eed8c5c…、match=1/drift=1;**对账纯读**(前后世界指纹 a16ed9e60dfc 相等);外部原文含 UNTRUSTED 包裹与漂移值(真实 HTTP 适配器在环的直接证据) |
|
|||
|
|
| 附带 | probe 仍 failed 的如实回复 | **PASS(首轮假 MES 句柄笔误时实测到)** | 「MES 连接尚未恢复(探测结果:failed),对账未执行……你的数据未被改动」——H-17 语义真实链路复证 |
|
|||
|
|
| G | 对照组:删白名单重发补录 | **PASS** | S6 卡 = 0、工单表逐行一致(白名单缺失 → 分类降级 P1/P2 路径,S6 入口物理关闭) |
|
|||
|
|
| H | 收尾 | **PASS** | 双端口释放、pi 零残留、`git status server/data` clean |
|
|||
|
|
|
|||
|
|
冒烟脚本自身修复(环境层,非产品):假 MES handler `add_header`→`send_header` 笔误一处
|
|||
|
|
(我写的设施代码,按约束修复并在此登记)。
|
|||
|
|
|
|||
|
|
## 4. S7 只读诊断冒烟(`smoke/smoke_s7_ops.py`)
|
|||
|
|
|
|||
|
|
**12/12 全 PASS。** 现场 `smoke/site5/` 保留;结果 `smoke/s7_results.json`。
|
|||
|
|
|
|||
|
|
| # | 验收点 | 结果 | 证据 |
|
|||
|
|
|---|--------|------|------|
|
|||
|
|
| A | ops 身份诊断(APS_AUTH_ENABLED=0 → bypass 角色含 admin ∈ S7.roles) | **PASS ×4** | intent=assistant.reply;inbox/ops/ 四文件齐;**脱敏生效**:预埋 `token=abc123secretTOKEN99` 与 `api_key=<24位>` 在 logs-tail.md 中呈 `***REDACTED***`、敏感串零泄漏;config-snapshot 含 features 全文 + 白名单裁决投影 |
|
|||
|
|
| B | P1 草稿语义 + 只读 | **PASS ×3** | 回复「[智能兜底 · 草稿] run fb-20260904-024511-116d11」+ 真实诊断报告(引用脱敏后日志行 `token=***`/`api_key=***` 列表格化异常项);世界指纹前后相等(050c1c6c087e);calls.jsonl 10 行(fs_read 围墙内读取,零新工具) |
|
|||
|
|
| C | 非 ops 对照(desktop planner 身份同口令) | **PASS** | **物理不可见**:零新增 run 目录、回复走原话术(「我暂未识别到……对应的明确业务目标」),连入口存在都无从得知 |
|
|||
|
|
| D | config.apply 双人审批链 | **PASS(黄金覆盖登记)** | H-20 确定性全覆盖(PARTIALLY_APPROVED → SOD_DENIED → 异人二批 → executionGrant → 原子替换 + .bak + 双人审计),冒烟层不重复,覆盖关系已登记 `s7_results.json.acceptD` |
|
|||
|
|
| H | 收尾 | **PASS** | 端口释放、pi 零残留、git clean |
|
|||
|
|
|
|||
|
|
## 5. GOAL-P3 出口标准 8 项逐条
|
|||
|
|
|
|||
|
|
| # | 出口标准 | 结论 | 依据 |
|
|||
|
|
|---|----------|------|------|
|
|||
|
|
| 1 | P3 白名单机制(fail-closed;改白名单 = P2 确认卡) | **PASS** | H-1..H-9/H-21 全绿;冒烟对照组 G 实测「文件缺失 → S6 入口物理关闭」;A-7-2/7-3 伪造篡改被拒 |
|
|||
|
|
| 2 | S4 缺算法沙盒试排(草稿不碰主干) | **PASS(golden 层)** | H-10..H-12:沙盒执行前后指纹相等 + 零 WORLD_WRITE 物理断言 + 写意图混入/expected 越界拒绝;S4 真实冒烟不在设计 §9 范围(见 §6 遗留) |
|
|||
|
|
| 3 | S6 集成故障补录与恢复后对账 | ~~段 A/B/D PASS;段 C FAIL(FB-03-BUG-1)~~ → **PASS(§7 复证)** | 修复前:冒烟 C/D1/D2/E/F 全过;D3–D6 实测断连下补录写必败回滚(同步 post_report 语义缺口)。修复后:段 C D3–D6/G1 全绿,S6 冒烟 24/24 |
|
|||
|
|
| 4 | S7 运维诊断入口(角色专属、只读、审计可回放) | **PASS** | H-18..H-20 + 冒烟 12/12(脱敏实测、非 ops 物理不可见实测、双人链 golden 锁定) |
|
|||
|
|
| 5 | 角色门禁(复用 auth,不新造权限模型) | **PASS** | server/auth 零改动;bypass(admin)/desktop(planner) 双身份实测闸 1.5 双向行为正确 |
|
|||
|
|
| 6 | 黄金测试确定性 | **PASS** | 21/21 + 攻击专项 7/7 + 联合 72/72,全部 fake runner 零网络 |
|
|||
|
|
| 7 | 真实冒烟(S6 全链 / S7 只读) | ~~S6 19/24(段 C 缺陷);S7 12/12~~ → **S6 24/24(§7 复跑);S7 12/12** | §3/§4/§7 逐条证据 |
|
|||
|
|
| 8 | 文档同轮(fallback.md / harness.md / CHANGELOG) | **PASS** | 文档门禁 25 passed;CHANGELOG FB-03 条目本轮已补真实验证数字 |
|
|||
|
|
|
|||
|
|
**总结论(历史现场,保留时序):P3 条件 NO-GO(Agent-N 判定)。**
|
|||
|
|
解除条件 = FB-03-BUG-1 修复(段 C 补录写在断连下可落账,例如本地落账 + PENDING_SYNC
|
|||
|
|
待同步标记、恢复后由对账/重放闭环)+ 本冒烟 outage 阶段 D3–D6/G1 复跑转绿。该条件
|
|||
|
|
已由 Agent-O 修复并复证,最终判定转 GO,见 §7;本节保留为修复前记录,不构成当前结论。
|
|||
|
|
|
|||
|
|
## 6. 未验证清单与遗留(如实登记)
|
|||
|
|
|
|||
|
|
1. **S4 真实冒烟未做**——设计 §9 只要求 S6/S7 两个冒烟;S4 沙盒链路真实 Pi 端到端
|
|||
|
|
(真实沙盒函数 + 指纹断言)未在真实子进程下验证,golden H-10..H-12 已确定性锁定。
|
|||
|
|
2. **S6 段 C 修复后的复跑**——缺陷修复轮需重跑 `smoke_s6_reconcile.py` 全五阶段
|
|||
|
|
(现场构造全自动,直接可复跑)。
|
|||
|
|
3. **WMS 侧补录**——设计 §11.10 明确边界外,本轮未覆盖。
|
|||
|
|
4. **cp_engine 组合模式偶发**(§1 异常观察)——未复现,建议观察不阻断。
|
|||
|
|
5. **maxItemsPerRun 截断的真实冒烟**——golden H-14 锁定,真实层只测了 2 笔(未超上限)。
|
|||
|
|
6. 验证设施产物(非产品):`regression_driver.py` / `regression_results.jsonl` /
|
|||
|
|
`regression_baseline.jsonl` / `smoke/smoke_s6_reconcile.py` / `smoke/smoke_s7_ops.py` /
|
|||
|
|
`smoke/site4` / `smoke/site5` / 各 `s6_*`/`s7_*` 结果与日志文件,全部保留供查验。
|
|||
|
|
|
|||
|
|
## 7. FB-03-BUG-1 修复复证(Agent-O 收口 · 主管复核记录)
|
|||
|
|
|
|||
|
|
> Agent-O:2026-09-04 · 收口:P3 出口标准第 3/7 项转 PASS,NO-GO 解除。
|
|||
|
|
> 完整改动与验证记录见 `docs/CHANGELOG.md` 顶部「FB-03-BUG-1 修复」条目;
|
|||
|
|
> 主管在 P4 轮复核时未重跑真实子进程冒烟,按该条目、源码差异与冒烟结果文件收口。
|
|||
|
|
|
|||
|
|
### 7.1 修复语义
|
|||
|
|
|
|||
|
|
`mes.apply_report` 新增 keyword-only `offline_booking=False`(默认在线路径语义逐字节不变);
|
|||
|
|
`fallback_lane` 在 S6 补录步要求 params 显式声明 `offlineBooking: true`,并在**出卡闸与执行端
|
|||
|
|
两处实时探测** `_probe_mes_connectivity() == "failed"`。显式声明 + 断连事实双成立后,
|
|||
|
|
`apply_report(offline_booking=True)` 跳过同步 `post_report`,本地落账并打
|
|||
|
|
`syncStatus=PENDING_SYNC` 标记;确认卡摘要明示离线落账待同步。恢复后对账报告识别并呈现
|
|||
|
|
待同步记录。自动补推仍为后续轮次边界。
|
|||
|
|
|
|||
|
|
### 7.2 确定性复证
|
|||
|
|
|
|||
|
|
新建 `tests/golden/test_fallback_offline_booking.py` 6 例全确定性:
|
|||
|
|
|
|||
|
|
- O-1 离线成功(`post_report` 零调用 + PENDING_SYNC + 卡摘要明示)
|
|||
|
|
- O-2 在线路径不变(镜像报工 +1、无 syncStatus、零探测副作用)
|
|||
|
|
- O-3 出卡闸在线声明 offlineBooking 拒绝
|
|||
|
|
- O-4 执行端审批窗口内 MES 恢复 → 熔断回滚
|
|||
|
|
- O-5 PENDING_SYNC 对账呈现
|
|||
|
|
- O-6 非 bool 形态拒绝
|
|||
|
|
|
|||
|
|
实测 **6 passed**;与 highrisk/execute/lane/feature_flags/attack 联合 **78 passed**;
|
|||
|
|
文档门禁 **25 passed**;ruff 与 HEAD 基线多重集比对零新增。
|
|||
|
|
|
|||
|
|
### 7.3 真实 S6 冒烟复跑(Agent-O 记录)
|
|||
|
|
|
|||
|
|
`smoke_s6_reconcile.py` 五阶段复跑 **24/24 PASS**(修复前 19/24)。段 C D3–D6/G1 全部转绿:
|
|||
|
|
真实 Pi 按新简报协议声明 offlineBooking,两笔断连补录本地落账成功,审计与 mesLinks 打
|
|||
|
|
PENDING_SYNC,恢复后对账如实呈现待同步 2 笔。现场证据保留在
|
|||
|
|
`poc/pi-fallback/smoke/s6_results.json`(checks D3/D4/D5/D6/G1 均 ok,reconcile 含
|
|||
|
|
PENDING_SYNC 2 笔与 manifest sha256)。S7 冒烟维持 12/12。
|
|||
|
|
|
|||
|
|
### 7.4 收口结论
|
|||
|
|
|
|||
|
|
出口标准第 3 项 **PASS(§7)**、第 7 项 **S6 24/24 / S7 12/12**;**P3 判定 GO**。
|
|||
|
|
头部 TL;DR、§5 出口标准表与本节一致;§5 历史 NO-GO 段仅为修复前现场。
|