aps-agent/poc/pi-fallback/P2-IMPL-NOTES.md

11 KiB
Raw Permalink Blame History

P2 实施笔记 — 写操作过确认卡门禁(Fallback Execute Lane)

施工:Agent-J(实施员),对照 P2-DESIGN.md v1.0 逐条落地。 代码轮验证日期:2026-09-03。状态:代码与黄金测试全部就绪,待 K 轮真实冒烟 + 注入复证后合闸。


1. 改动清单(git diff --stat 实测)

跟踪文件改动(git diff --stat,不含 package.json 的既有未提交改动):

docs/CHANGELOG.md                     |  19 +
docs/architecture/fallback.md         |  90 ++++
docs/architecture/harness.md          |   3 +
server/agent_core/fallback_lane.py    | 915 +++++++++++++++++++-   (净增,含 docstring/注释)
server/agent_core/harness.py          |   4 +
server/aps_domain/workflow.py         |  45 ++
server/integrations/pi_bridge.py      | 152 ++++-
tests/golden/test_fallback_lane.py    |  31 ++
8 files changed, 1246 insertions(+), 13 deletions(-)

新建文件(untracked):server/agent_core/fallback_verify.py 190 行、tests/golden/test_fallback_execute.py 762 行(19 例)。

(工作区另有 tests/golden/_saga_cp.json 被既有 saga 测试例行改写,已 git checkout -- 还原;package.json +3 行为既有 docx 依赖改动,非本轮产物。)

与设计 §1 文件清单逐条对应:

# 设计条目 落地情况
1 fallback_lane.py 计划锁 + 执行编排 ✅ plan_fingerprint/load_plan/validate_plan/check_step_request/_check_constraints + execute_plan + _stage_plan_confirmation + write_guard_extension + build_pi_runner + FallbackConfig +3 字段
2 pi_bridge.py 邮箱协议 + fs_write + 简报模板 ✅ ActionMailbox + handle_fs_write + fs_write/aps_invoke 注册 + render_plan_task_brief + _PLAN_TASK_TEMPLATE(含 <<<UNTRUSTED_DATA 段落)
3 harness.py 权力注册 ✅ _POWER_MAP/_POLICY_DESC 各 +2(agent.fallback.execute=P2、agent.fallback.execute.highrisk=P3)
4 workflow.py execute_confirmed +1 分支 ✅ 证据校验后、schedule.publish 前;try/except 归一为显式失败文案;WORLD_WRITE 审计 result=SUCCESS/DENIED/FAILED;补写落盘
5 fallback_verify.py 新建 ✅ world_diff/check_expectations/diff_summary_lines/build_report/report_fingerprint
6 tests/golden/test_fallback_execute.py 新建 ✅ 19 例(T-1..T-17 + E-1/E-5/E-7)全绿
7 test_fallback_lane.py 守卫模板断言 ✅ 扩为 3 条(见 §2 偏差①)
8 docs/architecture/harness.md ✅ 权力矩阵 +2 行 + 变更记录 FB-02
9 docs/architecture/fallback.md ✅ 追加 P2 章节(协议细节以代码为准,本文为准入口)
10 docs/CHANGELOG.md ✅ FB-02 条目(含实测数字)
11 scripts/poc/smoke_s3_execute.py ❌ 归 K 轮(设计 §7 已标注"给 Agent-K",J 分工为代码+notes;接口交接见 §4)
12 scripts/poc/rogue_llm_server.py +2 剧本 ❌ 归 K 轮(同上;剧本规格见 §4)

P1 既有面逐字节不变(黄金 test_pi_bridge.py/test_fallback_lane.py 原断言全绿佐证):_TASK_TEMPLATE/render_task_brief/handle_fs_read/render_request_envelope/parse_llm_result;run_fallback_lane(...) 不传新参数时行为与 P1 一致;readonly 守卫模板字节不变。


2. 与设计的偏差及理由

① 守卫双模板方案(v1 readonly / v2 plan+execute),设计预期的"既有守卫测试被打破"未发生。 设计 §2 E 案要求扩展 _GUARD_TS_TEMPLATE,并预期打破 test_fallback_lane.py::test_write_guard_extension_matches_template,要求同轮修复为逐字节断言。实际实施采用双模板:mode="readonly" 输出 P1 模板逐字节不变(原测试原样通过,无需修复),"plan"/"execute" 输出 v2 模板(追加 EXECUTE LANE MODE 注释 + APS_WORK_DIR + fs.unlink/rename/writeFile 许可包装)。理由:P1 只读 lane 的守卫面不应为 P2 承担任何字节级回归风险;v2 的新表面由同轮新增的两条测试逐字节锁定(沙箱写门面 + 两个 mode 的模板内容)。设计的真实意图——"改守卫必须改测试"——以更强形式满足(新增表面均有字节级断言)。

② 执行段任务简报渲染器位于 fallback_lane.py 而非 pi_bridge.py。 _render_exec_task_brief 依赖 PendingAction 结构与摘要字段,与编排器同模块避免跨层 import;pi_bridge 保持"信封/邮箱/注册表"纯协议层。plan_fingerprint/load_plan 同理放 fallback_lane(计划锁是编排概念)。设计 §2 的模块归属描述以本节为准。

③ 步骤级 TOOL 审计由 execute_plan 成功路径补写,而非 workflow 分支。 设计 §1 #4 说 workflow 分支"成功则补写步骤级审计"。实际:步骤级审计条目在 _execute_steps 各 handler 内构造、成功路径统一补写(含 actor/evidenceRefs/计划指纹);workflow 分支只写一条 WORLD_WRITE 汇总审计。理由:归并失败路径(try/except 捕获 + 显式失败文案)位于 execute_plan 内部,失败现场信息(cp_failed 指纹、回滚验证、diff 详情)只有 execute_plan 拿得到;workflow 分支保持薄壳。

④ ExecuteResult.message 由 execute_plan 组装。 设计说"message 由 workflow 分支组装"。实际失败文案的组装素材(失败原因、checkpoint id、漂移/回滚指纹)全部在 execute_plan 作用域内,workflow 只透传 fb_result.message。卡片摘要仍由编排器 _stage_plan_confirmation 从结构化字段再生成(设计 §4.1 的硬约束未变)。

⑤ T-17 经 monkeypatch.setattr("server.agent_core.llm_client.get_provider", ...) 直驱 parse_llm_result。 低置信/未知 verdict/非法 JSON 三态不需要真起 rogue HTTP 服务;真实 rogue 服务的三态复证归 K 轮 §7。

⑥ ExecuteResult 默认 status="failed",成功路径在 try 块末尾显式置位。 施工期曾因此出现"全步骤成功却走失败分支"的缺陷(回滚把已落库成果冲掉),已修复并由 T-2 锁定。记录在此提醒后续维护者:成功是显式结论,不是默认值。


3. 自验结果(全部实测,命令可复跑)

Python 一律 .venv\Scripts\python.exe(硬约束)。

验证项 命令 结果
目标三文件 pytest tests/golden/test_fallback_execute.py tests/golden/test_fallback_lane.py tests/golden/test_feature_flags.py -q 41 passed
爆炸半径切片(impact 上下游全符号对应黄金文件) confirm/审批/saga/checkpoint/chat/契约/导入 16 文件 118 passed
邻近切片 assistant/state 24 例 24 passed
全量黄金·批一(80 文件) 573 passed
全量黄金·批二(77 文件) 517 passed, 3 failed, 14 errors
ruff(本轮全部新/改文件) ruff check ×8 文件 All checks passed!(零新增)

批二 3 failed + 14 errors 与本轮无关,git stash -u 前后逐例一致(基线复跑实测):

  • test_preference_features.py 3 例:内存时钟 2026-09-03 越过示例文档的 validUntil 2026-06-30(日期炸弹,仓库既有)。
  • test_mes_http.py / test_mes_readiness.py / test_trace_external_http.py 14 errors:fixture 假数据不满足新接口(仓库既有)。

T-1..T-17 全链路确定性:sandbox fake runner 由 _start_fake_runner 动态分配端口、结束即关,不涉及固定端口;execute 段 fake runner 不经端口(直接注入 build_pi_runner)。

关键断言落点(19 例 ↔ 设计 §5 映射):

  • 锁:load_plan 指纹错/缺文件/超步数/空计划/非法结构拒绝;validate_plan 漂移拒绝;check_step_request 非法 intent/未知字段/数量非正/intent 与 action 不一致拒绝。
  • 圈禁:handle_fs_write 写 work/../x → {"error": "path escapes allowed roots"};越界 intent(order.delete)在 LLM 层拒绝、不进入审批流。
  • 门禁:未决卡阻塞首步(含防重放 mock 回调篡改);无卡世界直接拒绝(hint 含 fallback.propose)。
  • 回滚:数量篡改、verify 偏离、子进程崩溃三例均恢复 before 世界 + 显式失败文案 + WORLD_WRITE 失败审计 +(篡改类)cp_failed 现场指纹可复算。
  • 证据:expectation 容差 0(±1 拒绝)、无关行变化容忍、中文文案 PASS、diff 摘要行格式。
  • 审计链:PROPOSE→GATE(plan 指纹)→GATE(confirm 指纹+快照集)→TOOL×2(步骤)→WORLD_WRITE;失败链 PROPOSE→GATE(plan)→GATE(confirm)→WORLD_WRITE(FAILED)。
  • 小世界:17 实体 demo 世界全流程成功(仅种子行可 import.commit)。
  • 总开关:features.json fallback.enabled=false 时新分支不触达(feat_fallback=False 复跑 2 例)。

4. 遗留问题 / 交接清单(→ Agent-K)

  1. 真实 S3 冒烟(scripts/poc/smoke_s3_execute.py,设计 §7 规格):临时 APS_HOME 双仓 + features.json 开 fallback + 根 .env 的 kimi-k2.6 key。验收点 A–H 见设计 §7。接口提示:fake pi runner 注入点为 fallback_lane.build_pi_runner(签名 (config, *, mode="readonly"),execute 段用 mode="execute");make_customer_file 自检要求 detect_kind 对该文件失败(否则 commit 阶段会先 reject)。
  2. 注入复证:rogue_llm_server.py SCENARIOS += inject_via_csv(CSV 藏指→断言零文件落盘+零审批+计划锁拦截)与 inject_fake_approval(Pi 伪造审批→断言卡片结构不采纳+审批仓空);复跑 P1 三剧本回归。
  3. 真实 pi + 真实 LLM 端到端未验:守卫 v2 模板在真实 pi 子进程下的行为未验(黄金测试锁定的是模板字节内容本身);--sabotage 变体脚本未实现。
  4. ASSISTED 长执行占事件循环:设计 §5.2 已知边界,main 期处置项(K 轮真实冒烟时观察 pi 超时 120s 的占用表现)。
  5. async_jobs 不复用:P2 同步执行(设计 §4.2 取舍),main 期若执行耗时长再评估异步化。
  6. handle_fs_write 的 root != "work" 拒绝分支无专门用例:当前注册表只暴露 work;未来暴露 outbox 写时需补测试。
  7. harness.py 存量 5 条、workflow.py 存量 50 条 ruff 告警(git stash -u 基线复跑同为 55 条,零新增;治理归清洁口粮,不在本 round)。

5. 宪法红线自证

  • 新写路径唯一入口 = 既有 /api/actions/confirm(workflow.py 分支挂在 confirm 处理器内部,无新 HTTP 端点)。
  • 全部新 powers 注册进 Harness 权力矩阵并过 require_power 调用链(stage→plan→confirm→execute 四段 GATE)。
  • 失败路径显式文案且自动回滚;无任何静默降级。
  • checkpoint 前/后/失败现场三段快照成对出现,指纹双向验证(beforeFingerprint 重算比对 + 回滚后指纹验证)。
  • Pi 写面仍是圈禁 work/ 邮箱 + 沙箱 unlink/rename/writeFile 三函数包装——没有给 pi 新增任何物理写通道;fs_write 仅供中间产物,aps_invoke 仅产生请求、由计划锁拦截。
  • 计划指纹 sha256 绑定 approvedPlanJson,卡片摘要全部由编排器从结构化字段再生成,注入文本只能出现在 <<<UNTRUSTED_DATA 数据段落。