aps-agent/poc/pi-fallback/GOAL-P1.md

74 lines
12 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.

# GOAL:Pi Agent 兜底能力 · P1 只读兜底进产品路径(多 agent 协同 · 第二轮)
> 本文件是本轮协同的唯一权威协调板。每位 agent 开工前必读;完成后在文末留言板交接。
> P0 已 GO(见本目录 NOTES-pi-runtime / NOTES-architecture / NOTES-validation)。
## 本轮目标(P1 出口标准)
按根目录《Pi-Agent兜底能力详细方案》§6 P1:S1(意图未识别的只读类兜底)/S5(自由分析)进产品路径——
用户在对话里说了一句产品功能覆盖不了的话,不再只得到话术,而是得到**一份 Pi 真实产出的分析成果**(草稿语义,只读,不写世界)。
具体交付(全部产品代码,可测试、可开关、可审计):
1. `server/agent_core/fallback_lane.py`(moduleId: core-fallback-lane,可重生 ✅):兜底编排器——触发判定、任务简报、拉起 Pi headless、三重熔断、环境清洗、run 目录管理(`~/.aps/fallback/<runId>/` 或 server/data/fallback/)、成败按 stopReason;
2. `server/integrations/pi_bridge.py`(moduleId: integ-pi-bridge):围墙内工具桥——P1 阶段只暴露**只读工具**(fs_read 限 run 目录、aps 只读查询),callId 凭证 + calls.jsonl 落盘 + 报告凭证校验;
3. Harness 登记:`_POWER_MAP` 新增 `"agent.fallback.propose": "P1"`;harness.md 权力矩阵同轮更新;
4. FF-01 开关:`FEATURE_CATALOG` 新增 `"fallback": "智能兜底(Pi Agent)"`,**默认语义=配置缺失即全开,但本功能要求默认关**——需要在 feature_flags 语义内特殊处理(设计员给出方案:如 fallback 键缺失时默认 false,与其余键 fail-open 相反,并在端点响应中显式标注);
5. 接线:`workflow.py` unknown/assistant.reply 分支 → 开关开 且 意图未识别 → 走 fallback propose(**同步超时保护,不得拖死聊天**;失败显式回退原话术);
6. 黄金测试:`tests/golden/test_fallback_lane.py`——开关关=原行为不变;开关开=propose 路径触发(注入 fake runner,确定性);未登记意图仍拒绝;审计落链;熔断触发显式失败;凭证校验拦截伪造;
7. 文档同轮:docs/architecture/harness.md、docs/CHANGELOG.md、新增 docs/architecture/fallback.md。
## 硬约束(全员遵守)
- 工作区根:当前仓库根目录;Python 一律 `.venv\Scripts\python.exe`;
- **不 git commit / push**(等用户授权);改动最小化,不顺手重构;
- 修改 harness.py / workflow.py / feature_flags.py 前必须先查调用方(rg 或 GitNexus),把爆炸半径写进交接记录;
- 遵守 PROJECT_OPERATING_RULES:失败显式、无隐式副作用、P1 草稿语义不得写主干、不引入 mock 进产品路径(fake runner 只允许在测试注入);
- Pi runtime 定位:P1 复用 poc/pi-fallback/runtime/ 的安装,产品化打包(桌面 sidecar)留到后续阶段,但代码里路径解析要可配置;
- 黄金测试必须确定性:不依赖真实 LLM/网络(用注入 fake runner;rogue_llm_server 模式可选用)。
- 模型端点配置:复用 .env 现有 key(不得打印/落盘),模型名要协商(P0 踩过 404 坑:先 GET /models 或配置化)。
## 角色分工
| 角色 | 任务 | 输出 |
|------|------|------|
| Agent-D 设计员 | 读现状代码,产出 P1 文件级详细设计(接口签名、接线点、开关语义方案、风险点) | `P1-DESIGN.md` |
| Agent-E 实施员 | 按 P1-DESIGN 实现全部产品代码改动 | 代码 + `P1-IMPL-NOTES.md` |
| Agent-F 测试文档员 | 黄金测试 + 文档同轮 + focused/全量验证 | 测试 + 文档 + `P1-VALIDATION.md` |
## 协同留言板
(格式:`[角色] 时间 — 结论/交接物/给下一位的话`)
[Agent-D 设计员] 2026-09-02 — 设计完成,交接物 `poc/pi-fallback/P1-DESIGN.md`(8 节:变更清单表 / fallback_lane 与 pi_bridge 全量接口签名 / workflow 接线片段(现状+改法对照)/ 默认关方案 / run 目录与 APS_FALLBACK_* 配置 / 13 例确定性测试矩阵 / 爆炸半径 / P1 边界外清单)。
- **「默认关」一句话**:feature_flags 内新增 `_DEFAULT_OFF_KEYS={"fallback"}`——文件缺失/损坏/未配置/非 bool 时 fallback 默认 False(其余键保持 fail-open),返回体加 `defaultOff` 字段显式标注;`fallback_feature_enabled()` 直接消费 load_feature_flags 单一事实源,不另起解析。
- **风险最高点**:feature_flags 默认关会打破两条既有黄金测试(test_feature_flags.py 的 all-enabled 断言 ×2),必须同轮修(改法已写进设计 §6.0);其次是 workflow 聊天热路径接线(MED,缓解:开关默认关 + propose_reply 绝不抛异常 + 90s 硬熔断)。
- **关键现状核实**(施工前必读设计 §0):真实聊天到兜底分支时 name 几乎总是 `assistant.reply`(intent.py:948 把 unknown/低置信改写掉了);`IntentResult.intent` 是封闭 Literal——**不要**构造 `IntentResult("agent.fallback.propose")`,它只是 _POWER_MAP 动作名;聊天路径 handle_intent 已在线程池跑,同步+90s 上限方案成立,无需异步机制。
- 爆炸半径已 rg 盘点(设计 §7):harness.py=LOW(纯追加)、workflow.py=MED、feature_flags.py=MED。gateway/app.py / tool_runtime.py / contracts.py **零改动**。
- 给 Agent-E:照 §2 签名施工,fake runner 注入点是 `propose_reply(..., runner=..., config=...)`;P0 代码只作参照不重用(不 import poc)。给 Agent-F:测试矩阵 §6 逐例可断言行已写明,test_feature_flags.py 两条旧断言的同轮修法也在 §6。
[Agent-E 实施员] 2026-09-02 — P1 产品代码施工完成,交接物 `P1-IMPL-NOTES.md`(改动清单 / 8 条与设计的偏差及理由 / 自验命令与数字 / 6 条遗留)。
- **改动 7 文件**:新建 fallback_lane.py(809 行)/ pi_bridge.py(259 行)/ test_fallback_lane.py(13 例全确定性);修改 harness.py(+2 纯追加)/ feature_flags.py(_DEFAULT_OFF_KEYS 默认关 + defaultOff 标注)/ workflow.py(+8 接线,开关关时原路径逐字节不变)/ test_feature_flags.py。
- **自验**:fallback+feature_flags 19 passed;受影响回归(contract_sync/assistant/guidance/folder_pack/tool_runtime/gov_api + 聊天网关门禁切片)102 passed;ruff 新增文件全绿、修改文件零新增告警。未 commit。
- **偏差要点**:test_feature_flags 实际修了三条(设计漏列 corrupt_json 那条);result.json 改在 propose_reply 收尾落盘(含 citation_check);unavailable 不建 run 目录;新增空报告防御与 pi→桥工具名映射(不加映射则每次工具调用都误抛 ToolBridgeViolation)。全部理由见 NOTES §2。
- **给 Agent-F**:① 文档同轮未做(harness.md 权力矩阵追加 agent.fallback.propose 行——harness.py 里有同步铁律注释;新建 docs/architecture/fallback.md;CHANGELOG);② 全量 tests/golden 我 300s 没跑完,请用长窗口补跑;③ 真实 pi 端到端冒烟未做(本轮全 fake runner),有 key 环境时按 P0 方法补;④ 既有 test_preference_features.py 日期炸弹失败与本轮无关(已核实零 diff),别误归为回归;⑤ 已知张力:真实 pi 无法获知桥侧 callId,引用即 forged_citation——测试断言时以 fake runner 为准。
[Agent-F 测试文档员] 2026-09-02 — P1 收尾完成,交接物 `poc/pi-fallback/P1-VALIDATION.md`(改动清单 / 真实验证数字 / 张力处置 / 未验证清单)。
- **文档同轮 ✅**:harness.md 权力矩阵追加 `agent.fallback.propose`(P1)行 + `/api/features` 条目补 `defaultOff` 语义 + 变更记录加 FB-01 行;新建 `docs/architecture/fallback.md`(含凭证语义已知限制节)并登记进 architecture/README.md 索引;CHANGELOG 新增 2026-09-02「FB-01 智能兜底 P1(只读)」(体例照 FF-01)。
- **设计张力处置(遗留 #2)✅ 最小方案**:只改 `pi_bridge._TASK_TEMPLATE`——撤销「引用必须标注 callId」(真实 pi 不可获知围墙外事后签发的凭证),改为「不得编造,出现不存在的编号即判伪造成果整轮失败」;`validate_report_citations` 硬失败不动,`test_forged_callid_rejected` 继续绿(伪造可识别性质保持)。不选 warning 降级(会破安全断言)。
- **全量验证 ✅ 真实数字**:全量黄金 4 批 **1084 passed / 1 failed**(唯一失败 = test_preference_features 日期炸弹,git 零 diff 核实与本轮无关,未顺手修);fallback+feature_flags **19 passed**;受影响切片 13 文件 **83 passed**;文档/端点门禁 **20 passed**(doc_drift 文档改动后复跑 5 passed);ruff `All checks passed!`。
- **仍未验证**:真实 pi 端到端冒烟(无 key 环境);其余遗留见 P1-VALIDATION §4。**P1 出口标准 7 项交付全部落地,建议本轮 GO**,等用户授权后再 commit。
[Agent-G 冒烟员] 2026-09-02 — 真实端到端冒烟完成,交接物 `poc/pi-fallback/P1-SMOKE.md`(七判据逐条 / 真实回复摘录 / 两轮 run 目录 / 失败根因)。**结论:原样代码 NO-GO,一行修复后 GO**。
- **抓到唯一产品 bug(fake runner 结构性盲区)**:`fallback_lane.py` `_GUARD_TS_TEMPLATE` 注释行 `{ block: true, reason }` 未转义 → `write_guard_extension` 的 str.format 必抛 `KeyError: ' block'`,真实 runner 100% 失败(显式归并 harness_error,用户侧回退话术正常)。修法=注释行花括号双写,一行。**未自行改产品代码**;诊断轮用进程内 shim 做等价单行修正后同口令全绿(真实 kimi-k2.6,stopReason=stop,steps=2,34.9s,citation valid,审计 SUCCESS 落租户世界哈希链),可预判修复即解锁。
- **环境坑(建议项)**:本机 PATH 的 `node` 优先命中 node.CMD 垫片 → 真实 runner 起不来(cmd 引号炸);`APS_FALLBACK_NODE` 指向真实 node.exe 即绕过,建议产品侧 Windows 优先解析 node.exe。
- 判据 1/2/5/6/7 PASS;3/4 原样 FAIL、单行修复后 PASS(证据:`smoke/results*.json`、`reply2.txt`、site2 run 目录)。现场隔离全程成立(server/data 零污染,git+mtime 双证)。
- 遗留:主线 LLM 404 降级路径是本次触发前提,主线正常时的意图落点未验证;建议为模板 format 补一条轻量断言防回归。
[Agent-H 修复员] 2026-09-02 — Bug A/B 修复 + 复证完成,**P1 最终 GO**。交接物:`P1-SMOKE.md` §7(修复后复证全记录,七判据全 PASS 真实数字)。
- **Bug A 修复**:`_GUARD_TS_TEMPLATE` 注释行 `{ block: true, reason }` 双写转义(1 行);全文核查该文件仅此一处 format 模板、无同类残留。爆炸半径 rg 盘点 LOW(write_guard_extension/build_pi_runner 调用方仅 fallback_lane 自身,poc 同名函数是独立副本)。
- **坑 B 产品化**:新增 `_resolve_node()`——`APS_FALLBACK_NODE` 最高优先级;默认 "node" 且 Windows 时 `which("node.exe")` 优先于 `which("node")`(避开 node.CMD 垫片)。复跑冒烟未设 `APS_FALLBACK_NODE` 即通(orchestrator.log 实证 `node_bin='node'` 自动命中真实 node.exe);解析顺序已写进 `docs/architecture/fallback.md` 配置小节。
- **防回归**:`test_write_guard_extension_real_template_format`(真实 format + 守卫文件含字面量 `{ block: true`),fake runner 盲区有网。
- **验证数字**:fallback+feature_flags **20 passed**(1.41s);ruff 两文件 `All checks passed!`;真实冒烟复跑 run **fb-20260902-075907-3af703**(真实 kimi-k2.6,stopReason=stop,steps=2,13.0s,calls 2 签 2 完,citation valid,审计 SUCCESS 落租户世界哈希链连续,端口释放零残留、server/data 零污染)。本轮租户世界首访空快照,Pi 如实报「0 订单 0 物料」不编造——真实产出力证。
- 未 commit/push(等授权)。遗留不变:主线 LLM 正常时的意图落点待验证(P1-SMOKE §6.3)。