Skip to content

[FEATURE] 完成 Agent 友好性闭环:有界调用、统一契约、可恢复错误与真实任务验收 #287

Open

Description

@codeasier

目标

把当前已经具备的 CLI、查询语义、Skills 和 installed-wheel 测试,收口成外部 agent 能稳定完成的工作流:发现命令 → 选择正确目标 → 有界查询/聚合 → 识别不完整证据 → 受控失败与恢复 → 输出可复核结论。

本 issue 是这轮 Agent 友好性改造的唯一总跟踪项。以下各阶段、测试与验收均留在本 issue 的 checklist 中,不再拆分新 issue;实现可以分多个可独立审查的 PR,但不以“某个 PR 已合入”替代整体验收。

基线、现有能力与证据边界

审计基线:main@81af6698675efcc0bd63c8b9be0a331b14241f66,2026-11-03 再次核对仍是该提交。

现有能力应保留:13 个模板的参数/输出语义发现、overview、6 个 bundled Skills、只读 SQLite、同事件 allocator gap、峰值 attribution coverage、保守的分页/排名完整性、dataset work/scratch budgets、导入缓存身份及失败回滚。这些是实现能力,不只是文档。

已有证据:

  • main Test run 41329139788 成功,其中 Python 3.13 的 non-nightly coverage、wheel build/audit、Clean-wheel Agent acceptance 成功。
  • Platform run 41329139799 成功。
  • Clean-wheel 走真实公开 CLI、包内 Skill 安装、trusted import/reuse 和两种 dataset 的跨片查询对照;默认 venv 共享系统依赖,不能等同于全新依赖安装。
  • 当前 main 的 2026-11-02/03 scheduled runs 为 cancelled,不能算大型 installed-wheel dataset 与 paired 200-seed 验收通过。
  • 本轮是源码静态审计与既有 CI 核对。下面的数值异常是静态可达发现,本轮未执行复现、UT、build、安装或 live-agent 试验。后续执行记录必须区分 PASSED / FAILED / NOT_RUN / BLOCKED,不得把存在测试文件写成测试通过。

与现有事项的关系

七类差距及静态依据

1. 数值输入仍可逃出机器错误和超时边界

有效单库/设备下,pt-snap query <db> --template-use event --params '{"id":1e309}' --json 的静态路径是默认 json.loads 得到 inf,再由 int(inf) 抛出未归一化的 OverflowError。非零退出不等于返回约定的 INVALID_PARAMETER JSON。

此外,PT_SNAP_QUERY_TIMEOUT=nan 被解释为禁用 timeout,inf 形成永不到期的 deadline;默认序列化可输出严格 JSON 不接受的 Infinity。兼容 dataset admission 的 math.ceil(inf) 还有裸异常路径。

依据:cli.py L757–763、config.py L108–121、timeout L57–77、json_codec L24–45、validation_budget L27–33。

2. 预算可配置,但默认调用仍可能无限输出

query 默认行数与 timeout 无上限,event 默认完整栈,standalone 用 fetchall。dataset 的累计 work budget 不等于 standalone 的内存/输出保护;stack_bytes 仅是每条栈文本字节预算,不是 JSON 响应上限。memory-tree 也没有 agent 用的有界节点/子树接口。

依据:cli.py L585–605、event.yaml L7–84、executor.py L354–375。

3. 真正的 agent 任务成功尚未验证

保存的 baseline、静态 Skill checks、脚本化 installed CLI acceptance 都有价值,但不能证明新 agent 会选择正确命令、恢复错误并给出正确结论。当前 harness 明确 runner_execution_verified:false,最终答复的字面短语检查也不能判断否定关系和事实真伪。

依据:评估说明 L113–145、live runner 未完成 L217–237。

4. 冷启动发现过重,命令契约不完整

capabilities 输出全量模板与 Skills;诊断 Skill 要求完整 catalog,不能只取所需模板。在输出窗口受限的宿主中,恢复只能取齐全部字节、重跑或停止。capabilities 又不描述 report options,仍需解析人类 help。

依据:capability_service L22–37、helper L192–220、output recovery L9–56。

5. JSON 成功形状与执行证据身份不统一

query/capabilities/overview 有 success envelope,metadata 和两个 report 保留旧结构;report 没有 db_path。query 输出的路径又在执行后重新 resolve focus,未直接携带执行时冻结的身份。通用 adapter 要特判,独立保存的 report 也不够自包含。

依据:report 输出、report model L116–134、query 重新 resolve L775–798、旧形状兼容测试 L645–670。

6. 预算失败是安全的,但恢复信息不够机器化

max_work_rows 无效却收到“修改 timeout”的 hint;超预算与 SQL/布局问题都映射为 QUERY_FAILED,资源类型、配置上限和已消耗值只在自然语言中。agent 可能修改错误参数或无限提高限额。这里的问题是分类与恢复,不是现有预算保护失效。

依据:error_codes L85–98、预算失败 L102–121。

7. 大型输入的诊断链仍有功能断点

main 的 dataset support matrix 是 11 个模板,不含 event_frames 和 active_memory_frame_tree_at_event。不能把 standalone memory-tree 或未合 PR269 算作完整分片能力,也不能选一个 shard 冒充全局证据。text overview 仍统一称 cross-slice queries unavailable,与已有全局查询能力矛盾。

依据:dataset_support L5–29、report 路由 L47–68、overview 文本 L959–964。

改造方案与交付顺序

以下是待实现的新接口方案,不是对现有功能的描述。先做兼容性修复与共享 core,再增加新协议/有界入口,最后切换 Skills 和执行真实任务验收。

阶段 A:先修输入与错误边界,不改变合法输入的既有语义

涉及 query/config.py、core/query_service.py、core/validation_budget.py、core/json_codec.py、CLI/API adapters。

  • 在共享数值转换边界归一化 OverflowError;解析运行时 JSON 参数时拒绝 NaN/Infinity 及指数溢出的非有限结果,不能替换为 null、0 或无限值。
  • 1e309 是语法合法 JSON,但超出有限浮点输入域。CLI 同时使用拒绝非标准常量的 parse_constant 和校验有限结果的 parse_float;将解析回调的 ValueError/OverflowError 归一化为参数域错误,不能仅捕获 JSONDecodeError。API 在共享边界做同样检查,无效数值应在数据库 I/O 前失败。
  • 显式 timeout 和环境变量使用同一有限值校验,再应用既有 <=0 禁用规则。保留合法类型转换和有限非正 timeout 的兼容性,不借此把所有参数改成新 strict schema。
  • JSON 输出统一走严格序列化 allow_nan=False,处理其 ValueError,确保序列化错误本身仍是完整错误包、非零退出、无部分成功 stdout。
  • 同时覆盖 json_success/to_jsonable 构包阶段和最终 dumps 阶段,不能只在 _emit_json 外围补 catch。失败包只包含确定可序列化的安全字段,不重新嵌入原始问题对象。
  • 不用宽泛 catch-and-success 掩盖程序错误。预期输入错误要有具体领域错误与 cause;未预期缺陷保留可诊断信息,但不能污染机器协议。

阶段 B:统一错误原因与执行身份

涉及 core/errors.py/error_codes.py/models.py/json_codec.py/query_service.py/report_service.py、focus/context/dataset resolver 与两类 adapters。

  • 给领域错误增加稳定 reason 和结构化 details。至少区分 invalid_numeric、invalid_parameter、unsupported_capability、work_budget_exceeded、scratch_budget_exceeded、timeout、source_changed、output_budget_exceeded、serialization_failed。
  • details 按错误提供 field/resource/limit/consumed;hint 与实际字段一致。
  • 提供枚举化恢复建议:correct_input、narrow_scope、rediscover_target、retry_same_input、increase_specific_limit、none。提高预算仅是建议,不能自动取消上限,不能暗示获得了导入、覆盖文件或其他写入授权。
  • 执行入口只 resolve 一次目标,返回不可变的 execution target。query/report 输出使用该对象,不在执行后重新读 focus。
  • 复合 report 的查询共享已解析目标、deadline 和读取一致性边界;正常并发文件替换/WAL 更新不能混出两代证据。跨调用 continuation 绑定 target generation 与有效参数,检测不一致后明确失效。
  • 标明 identity assurance:源 metadata SHA、实际验证的 dataset fingerprint、文件 generation token 各自证明什么。不能把“元数据记录了源 hash”写成“本次结果已重新做内容级验证”,也不默认每次查询全量 hash 大文件。
  • metadata 缺失的合法 legacy DB 保留明确 unknown provenance 分支,不强制导入;不修改现有 native/compatible 的完整性策略。

阶段 C:新增版本化 envelope,保留旧客户端

增加显式 --json-envelope 2,用于机器可读的 query/report/metadata/overview/capabilities 及已有 JSON 命令。旧 --json 的成功字段、错误码及 stdout/stderr 约定继续保持;新代码共享 serializer,不能维护两套产品语义。

v2 的统一字段:

  • schema_version: 2、ok、cli_version、operation;
  • target:resolved path、device、target kind、generation/fingerprint、identity assurance(无目标的 catalog 可为 null);
  • request:有效参数、有效资源/输出限额、semantics version;
  • 成功 data 与 completeness:row/source completeness 分开,保留 has_more、truncated、total_is_exact、coverage 和 denominator,不靠单一布尔值掩盖差异;
  • 失败 error:code/message/hint,以及阶段 B 的 reason/details/recovery。

v1 稳定 coarse code 不必为新 reason 强制改名。v2 错误与成功均有可校验的 schema;字段 optional/null/unknown 的含义要明确。公共 Python API 增加等价 opt-in,不将 CLI 字符串解析当作 API 实现。

阶段 D:有界 agent preset 与可继续取证

为只读 query/report 增加 --profile agent-v1,选择 v2 envelope。建议初始默认值为:100 result rows、10 秒 operation deadline、64 KiB 完整 UTF-8 JSON 响应、每条支持压缩的 callstack 256 字节;首次实现时先用代表性基准确认,再冻结为可发现的 agent-v1 契约。这些草案值不是已经验证的业务 SLA。保留现有 dataset work/scratch 默认上限;Python API 使用不可变的对应 options/profile。

  • 普通模式保持兼容。agent profile 的显式覆盖只能是有限有效值;需要无界行为必须离开该 profile,不能用 -n 0 或非正 timeout 暗中解除其保护。
  • 响应字节数包括完整 envelope,以实际序列化字节计数。最小可容纳 envelope 的预算要预先验证;不得截断 JSON 字节、丢字段或先输出部分数据再报错。
  • 明确拆开执行 deadline、累计 work rows/bytes、scratch pages、returned rows、response bytes、stack bytes。不能声称这些是 RSS 或模型 token 上限。
  • 将 standalone 结果读取纳入可检查的有界路径;显式预算不能只在 dataset 生效。SQL 扫描成本仍用 deadline/合适的 work 计数约束,不能把 LIMIT 宣称为总执行成本上限。
  • 输出截断带 machine-readable continuation 类型与下一步参数,并绑定目标身份和参数:普通分页可继续;top_n 扩大是替换排名窗口,不能当 offset 页累加。
  • frame tree 增加按稳定节点/路径获取子树的有界视图;完整树与部分视图有不同完整性声明,保留父子关系和 inclusive/self 语义。不能只裁剪前 N 行后继续声称完整树。若计算本身超过预算,受控失败,不伪称 streaming。
  • profile 默认值作为版本化契约记录;若真实基准证明要调整,先更新 profile 版本/发布说明和验收基线,不能悄悄改变同名 profile。

阶段 E:渐进发现与 Skill 接入

涉及 capability_service.py、模板 registry/serializer、CLI help、skills/ 及 packaged copies。

新增:

  • capabilities --summary --json-envelope 2:小型索引,列出操作/模板名、协议/profile 版本、读取/写入属性、输入类型与能力边界,不返回全部大 schema。
  • capabilities --template <name> --json-envelope 2:获取所需模板的完整 contract,可重复指定名称。
  • capabilities --command <operation> --json-envelope 2:描述 query/report/import/split/skill 等命令的参数、输出、作用域、side effects 与恢复边界,不只覆盖查询模板。
  • catalog 具有版本与 digest;大 contract 支持有界分段/续取并校验齐全,不能让 summary 代替完整参数/语义合同。

Skills 改为“索引 → 当前任务必需 contracts → overview”,允许重用同环境/同 digest 的完整结果。缺失 contract 或目标不匹配仍须停止;不得以减少调用为由猜参数/单位或落到 raw SQL。同步 authored/bundled copies、安装状态、宿主加载说明。磁盘安装与实际加载分别验收。

阶段 F:复用现有 dataset 路线并统一能力说明

  • 在 PR269 实际完成且进入 main 后,将 dataset frame-tree 与新的 bounded view/protocol 接起来,复用已有 source coverage、deadline、取消和跨片来源实现,不另起一套全局聚合。
  • PR269 未完成期间 capability 明确返回 unsupported 及替代的已支持只读分析;不得自动降级为某个 shard 的“全局”结果。
  • 修正 overview/help/README/中英文指南中 blanket “cross-slice unavailable”等不准确描述,全部从实际 support matrix 对齐。
  • parser-v3 consumer/GUI 复用仍走原有独立验收;本 issue 的 CLI/agent 通过不能替代它,也不自动允许重跑 GUI 或修改其他仓库。

阶段 G:真实宿主任务基准,而非重新评分 target records

先提供 runner/adapter、独立 oracle 与一次受控执行计划。真实运行前明确宿主/模型版本、数据来源、网络/凭据使用、调用与成本上限、日志保留和停止条件;只有运行条件及必要授权就绪才执行。本 issue 的创建不代表立即连接模型服务、使用真实用户会话、花费费用或上传快照。

同一已安装 wheel、隔离 HOME/CWD、只读 fixture、清理 focus 环境,覆盖“仅 CLI”和“宿主已实际加载 Skill”两种入口。初始最小矩阵为以下 6 组 × 2 入口 × 3 次独立运行,共 36 轮:

  1. 冷发现/目标选择:单设备、多设备、missing focus,不能猜错 DB/device。
  2. 峰值解释:不同事件的三种峰值、top_n 截断、静态/预存块,数字、分母、coverage 必须正确。
  3. 泄漏辨别:地址复用、pending free、allocator cache,无充分证据不得报 confirmed leak。
  4. 大数据:跨片分页、work/output budget、宿主输出截断,只能完整取证或披露未知。
  5. 错误恢复:错误模板/参数、非有限数值、timeout、预算耗尽,读取真实 stdout/stderr/exit code,并有界恢复。
  6. 重试与身份变化:经单独批准的 synthetic trusted import 重复/失败场景,旧 DB/focus 保留;只读诊断的目标替换/证据世代变化;未批准 pickle/import 应停在边界。

oracle 使用独立手工可核的 fixture 事实与已审查的期望数值,不从候选实现输出生成预期值,也不只检查答复短语。记录真实工具轨迹与最终答复;确定性数字/边界断言配合独立结论复核,区别“可接受的未知”与“错误结论”。

产物至少有 run manifest(commit/wheel hash、Python、host/model、Skill loaded evidence、seed/case/入口、开始/结束/终态)、逐调用 exit/stdout/stderr 与字节量、oracle 判定、失败原因和汇总。日志使用合成/脱敏数据,不提交凭据或原始用户聊天。

验收清单

实现与兼容性

  • A:1e309、NaN、±Infinity 的 JSON/显式参数/环境变量路径均受控;CLI/API 与单库/dataset 一致,stdout 无残留,stderr 严格 JSON,失败退出码非零。
  • A:覆盖 ±1e309、None/空环境变量、显式值优先、正常字符串转数值及有限 0/负值;无效值在 I/O 前失败。成功和失败输出均用拒绝非标准常量的解析器验证,不能用默认 json.loads 接受 Infinity 来判通过。
  • A:有限正常值、既有合法类型转换、普通模式有限非正 timeout 禁用语义不回归;严格 JSON serializer 自身失败也有测试。
  • B:参数 hint 指向正确字段;预算错误提供 reason/resource/limit/consumed;超预算无部分全局成功结果、连接/临时文件正确清理,下一次独立调用可正常执行。
  • B:目标只 resolve 一次;显式路径、环境/project focus、并发替换/WAL 修改和跨页 generation mismatch 有测试;来源证明级别不夸大。
  • C:所有 JSON 命令 v2 成功/失败 schema 校验通过;旧 --json fixtures 和字段兼容测试保留;API/CLI normalized parity 通过。
  • D:agent profile 在单库和 dataset 都执行有限 deadline/row/byte 合同;长 Unicode 栈、单超大行、错误 envelope、tiny budget、精确边界和序列化开销均有回归。
  • D:分页拼接/排名窗口/树子视图分别验证,不将 partial 误报 complete;续取无法跨目标或跨参数误用。
  • E:仅靠已安装 wheel 完成 summary/所需 contract/overview/查询,不读 checkout;完整 contract 与原 registry schema 同源,digest 与续取一致。
  • E:Skills authored/bundled parity、安装与实际宿主加载证据分别通过;失配/旧 Skill/输出截断恢复不绕过预检。
  • F:PR269 对应前置及验收实际完成后,native/compatible/standalone 的共享语义与 source coverage 对照通过;未支持状态仍诚实可发现。

工程与交付

  • 保留原有 overall/独立关键 coverage floors、失败安全断言、provenance、类型门禁,不用 skip/xfail 或降低阈值伪造成功。
  • 常规 pytest、Ruff、Black、basedpyright、diff check 与受影响的属性/CLI/API/JSON suites 在最终 commit 有证据。
  • 最终 wheel 经 audit;现有 clean-wheel acceptance 通过,并用离线 wheelhouse 的非 system-site-packages 环境补充独立依赖安装验收。
  • 影响 dataset/runtime 的变更完成仓库要求的实际 installed-wheel dataset 与 paired 200-seed profile;不能用 nightly skip/cancelled 或另一提交绿色替代。
  • 所有验收绑定 exact commit/wheel;候选后有实质变更则重做受影响 gate,正常合入后核远端与 post-merge CI。
  • 中英文用户指南、协议/profile 迁移说明、错误恢复表和 Skill 文档齐全。

真实 agent 结果

  • 36 轮均确有执行记录;未执行、阻塞、失败必须计入分母并分别报告,不能删失败轮或用 baseline 替代。
  • 合成矩阵中不得出现越权写入、不可信 pickle 导入、混目标证据、错误单位/分母、假完整和无依据 confirmed leak/OOM 结论。
  • 可完成 case 给出 oracle 正确结果;不可完成 case 明确正确 blocker/unknown,并遵守预算,不无限重试。
  • 汇总真实完成率、错误结论率、调用数、输出字节、耗时/token/费用、恢复次数;保存逐 case 结果,不给未运行的成功率。
  • 仅 CLI 与 loaded-Skill 两入口分别达成上述条件;故障修复后重跑失败 case 及受影响回归,最终再执行完整矩阵。
  • 若真实运行条件/预算授权尚未就绪,G 明确 NOT_RUN/BLOCKED,保留 issue 开放,不宣称整个 agent 闭环完成。

非目标、发布边界与风险

  • 不重建 MCP,不以有/无 MCP 作为完成条件;不引入 Meta Mosaic 训练语义、snapshot diff 或新 profiling 产品面。
  • 不改 allocator/replay 的既有数值语义,不强制关闭现有 YAML 扩展兼容;不借此放宽 pickle trust、文件覆盖或导入同意边界。
  • 不要求一次性大重构。推荐按 A → B/C → D/E → F/G 交付;A 可先独立修复,F 等待现有 PR269,G 的 runner/fixture 可先准备,但真实执行按上述条件启动。
  • 小修复和新增 opt-in 协议可以分别发布;发布说明必须区分 shipped、experimental、NOT_RUN,不因部分 PR 合入提前关闭本 issue。
  • 主要风险是旧 JSON 客户端破坏、byte cap 导致隐性 partial、身份校验引入大文件全量扫描、Skill 新旧契约漂移、基准对单一宿主过拟合。通过旧协议快照、明确 completeness/assurance、成本可测的身份方案、wheel/Skill parity 和双入口真实任务记录控制。
  • 本 issue 只跟踪上述改造,不自动安排发布/tag、部署、其他仓库修改、凭据或安全设置变化。关闭前,所有必需 checklist 必须有精确证据证明 PASS,或有明确、已批准的范围决定;仅说明剩余项不能作为关闭依据。阶段 G 缺少真实运行证据时保持开放,不能用“测试很多”或“文档写了 agent-native”替代验收。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions