aps-agent/poc/pi-fallback/P3-VALIDATION.md

176 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 段仅为修复前现场。