7.4 KiB
7.4 KiB
P1-IMPL-NOTES — P1 只读兜底 · 实施记录(Agent-E)
实施员:Agent-E · 日期:2026-09-02 · 施工图:
P1-DESIGN.md· 协调板:GOAL-P1.md未 git commit / push;全部验证用.venv\Scripts\python.exe。
1. 实际改动清单
| # | 文件 | 新建/修改 | 规模 | 内容 |
|---|---|---|---|---|
| 1 | server/agent_core/fallback_lane.py |
新建 | 809 行 | 兜底编排器(moduleId: core-fallback-lane):FallbackConfig/from_env、fallback_feature_enabled、run 目录三区、build_child_env 环境清洗、kill_process_tree、resolve_model 模型协商(300s 缓存)、_write_models_json(apiKey 只写 env 名引用)、write_guard_extension、build_pi_runner(读线程+queue+心跳+finally 杀树)、_run_events 三重熔断主循环、propose_reply 接线入口(绝不抛出) |
| 2 | server/integrations/pi_bridge.py |
新建 | 259 行 | 工具桥(moduleId: integ-pi-bridge):TOOL_REGISTRY 仅 fs_read/aps_query/report_emit 三个只读项、PiBridge(issue/complete/list/validate_report_citations/handle_fs_read 限 run 目录/export_snapshot 快照制)、_TASK_TEMPLATE + render_task_brief(USER_REQUEST 隔离标记) |
| 3 | server/agent_core/harness.py |
修改 | +2 行 | _POWER_MAP / _POLICY_DESC 各纯追加一行 agent.fallback.propose = P1;未动任何函数 |
| 4 | server/agent_core/feature_flags.py |
修改 | ±33 行 | FEATURE_CATALOG 追加 fallback;新增 _DEFAULT_OFF_KEYS=frozenset({"fallback"});_all_enabled→_default_enabled(设计已授权改名,模块内私有、rg 核实无外部调用方);三处 error 文案改「回退默认值(fallback 默认关,其余默认开)」;返回体追加 defaultOff;头注释语义同步 |
| 5 | server/aps_domain/workflow.py |
修改 | +8/-1 行 | 2875 assistant.reply/unknown 分支按设计 §3.2 原样接线(propose_reply → None 时原路径逐字节不变) |
| 6 | tests/golden/test_feature_flags.py |
修改 | ±20 行 | 三条 all-enabled 断言修复(见偏差 1) |
| 7 | tests/golden/test_fallback_lane.py |
新建 | 323 行 | 设计 §6 测试矩阵 13 例全实现,全部确定性(fake runner 注入 + tmp_path 隔离 + 清 LLM env) |
未动:gateway/app.py、contracts.py、tool_runtime.py、intent.py、assistant.py、sidecar.cjs、poc/(只读参照,零 import)。
2. 与设计的偏差及理由
- test_feature_flags.py 修了三条而非两条(设计 §6.0 只列了两条):
test_corrupt_json_fails_open_with_error同样断言all(enabled),默认关加入后必然打破。设计漏列;改法与其余两条一致(排除 defaultOff 键 + 显式断言 fallback=False)。 result.json落盘位置从_run_events挪到propose_reply:设计的 FallbackOutcome 含citation_check,而凭证校验在编排循环之后做;在 propose_reply 收尾一次性落盘可避免写两次。_run_events仍负责 events.jsonl / orchestrator.log。- unavailable(运行时不可用)路径不建 run 目录:可用性检查在 create_run_dirs 之前,审计 rationale 的 runDir 记
""。理由:最小副作用(没跑起来就不留目录),且设计测试 13 不要求目录。成败判定、审计、失败话术与设计一致。 - 空报告防御:
stopReason=stop但报告体为空时判error:empty_report显式失败(设计未覆盖此边角;不防御会产出空草稿回复,违背诚实原则)。 - pi 工具名 → 桥工具名映射
_PI_TOOL_MAP(read/grep/find/ls → fs_read):设计 §3.5 要求每个 tool_execution_start 签 callId,但 pi 事件流的 toolName 是read等内置名,不在桥注册表;不加映射则每次工具调用都抛 ToolBridgeViolation。映射外工具出现 → ToolBridgeViolation 经主循环归并为harness_error显式失败(设计 stop_reason 集合内)。 write_guard_extension(run_dir)参数名实为 run 目录(设计签名写的run_root语义即此);runId 取自目录名。守卫扩展仅在真实 runner 内生成(fake runner 无 pi 进程可加载它);P1 守卫为 bash/edit/write 全禁(比 P0 模板更紧,无白名单参数)。- 新增两个模块级同步辅助
_append_run_log/_write_result_json:把阻塞文件 IO 移出 async 函数体(ruff ASYNC230)。行为不变。 - pi_bridge 新增公开 helper
render_task_brief()(设计只写了_TASK_TEMPLATE常量):避免跨模块填充私有模板。
3. 自验结果(命令 + 输出摘要)
| 验证 | 命令 | 结果 |
|---|---|---|
| 新增/修改测试 | pytest tests/golden/test_fallback_lane.py tests/golden/test_feature_flags.py -q |
19 passed(13 兜底 + 6 开关) |
| 设计 §7 受影响回归 | pytest test_contract_sync test_assistant test_guidance test_folder_pack test_tool_runtime test_gov_api -q(与上合并跑) |
61 passed |
| 聊天/网关/门禁切片 | pytest test_chat_ensure_session test_closed_loop_gateway test_automation_gateway test_automation_gears test_dialog_clarify test_harness_p3 test_tool_runtime_gateway -q |
41 passed |
| ruff 新增文件 | ruff check fallback_lane.py pi_bridge.py test_fallback_lane.py test_feature_flags.py |
All checks passed!(有意豁免处以 # noqa + 中文理由逐条标注:BLE001/S110/PLW1510 等) |
| ruff 修改文件 | 三个修改文件改动前后告警输出逐行数对比 | 202 == 202,零新增(存量为 round-41 记录的 informational 基线,CI 不阻断) |
| 全量 tests/golden | 尝试过一次 | 300s 超时未跑完(未验证,见遗留) |
爆炸半径复核(施工前已按设计 §7 再核对):_default_enabled 无外部调用方(rg 核实);feature_flags 产品调用方仅 app.py /api/features;handle_intent 调用方开关关时逐字节不变(测试 1 已断言回复 == 原话术、零审计、零目录)。
4. 遗留问题 / 风险
- test_preference_features.py::test_extract_features_from_world 失败 = 既有日期炸弹,与本轮无关:该用例 dueDate 写死 2026-08-03/04,今天 today0=2026-09-02,半周期窗口已过 → urgencyRatio 0.0≠0.5。已核实
server/knowledge/零 diff(git diff --stat HEAD为空)。建议另开轮次修(dueDate 改相对 today 生成)。 - 全量 tests/golden 未跑完(300s 超时);上述受影响切片全绿,但全量回归建议 Agent-F 用更长窗口补跑。
- 真实 pi 链路未实测:本轮全部确定性测试走 fake runner;node/pi/真实 LLM 的端到端冒烟(开关开 + 真实 runner)未做——需要带 key 的环境,建议 Agent-F 或人工按 P0 方法补一次真实冒烟。
- 真实 pi 无法获知桥侧 callId(凭证是编排器事后签发):简报已按设计写入 [callId: ...] 引用格式,但真实 pi 报告若引用 callId 几乎必然 forged_citation 判败;不引用则 valid。这是设计本身的已知张力,P1 保留为边界声明,建议后续阶段明确「真实路径的凭证语义」。
- 文档未动(GOAL 交付 7 归 Agent-F):harness.md 权力矩阵需追加
agent.fallback.propose行(harness.py 内有文档同步铁律注释)、新增 docs/architecture/fallback.md、CHANGELOG 条目。 - 模型协商缓存是进程级单值(
_MODEL_CACHE):多租户/多 base_url 切换需等 300s TTL 或重启;P1 单现场部署语义下可接受。