工具调用 receipt 纪律:何时记、怎么填、调用率算不算达标(术·语义层,draft)
术-语义层 · 术层 skill 全文
本页是 <code>rules/skills/drafts/workflow_tool_receipt_discipline.md</code> 的逐字投影(仅隐私清洗,零改写)。
时点提示:本页是仓内文件 rules/skills/drafts/workflow_tool_receipt_discipline.md 的逐字投影(仅做隐私清洗:仓库根绝对路径→相对路径、家目录→~/;除此零改写)。若源文件后续有修订,以仓内真源为准。
工具调用 receipt 纪律:何时记、怎么填、调用率算不算达标(术·语义层,draft)
元数据
- 类型:Draft Workflow(术·协议,给
tool_receipts工具配语义层;不替代工具本身) - 适用场景:要让一个确定层工具的真实调用成为可回查的运行证据时——用
tool_receipts的record()记 receipt、用check.py数调用次数之后,怎么判这条 receipt 记得算不算数、这个工具的调用率算不算「稳定被调用」。 - 证据:bounded。done-criteria 对照
tool_receipts的真实 schema(task_id / caller / artifact_paths / exit_code)+ 本轮诊断定出;配套检测器在真实台账(27 条 design_doc_scaffold / report_scaffold receipt)+ 手造仪式性 receipt 上验证过确定性判别与 regulator 可操作性。未跨多个工具长期验证调用率达标线。 - 配套:确定层工具
tool_receipts(record()写台账、check.py数调用,路径查tools/INDEX.md);记录纪律检测器tool_receipts的check_discipline(仪式性 / 自测 receipt 的误差信号)。 - 日期:2026-06-04。
目标(一句话)
tool_receipts 能写一条 receipt,check.py 能数出某工具被调用了几次。但一条 receipt 可以是空壳:task_id 空、artifact_paths 空、或者开发期自测刷出来的。它照样让计数加一,却不代表工具真被用于一件真实工作。光有工具没有协议,结果就是 receipt 写了、却记不算数,「调用率」这个本该回答「工具被稳定真实用起来没」的信号被仪式性 receipt 刷虚。这个协议补的就是这一层:哪些工具该记 receipt、四个字段怎么填才算数、多少调用率算达标,以及用什么机械判据确认一条 receipt 记到位了。
边界(不做什么)
- 不替代
tool_receipts工具。写台账(record()的 flock / 脱敏 / schema 校验)、数调用(check.py)都在工具里,本协议只管「记得算不算数」的语义层。 - 不做运行时强制。E-01 / E-04 / E-05 那套「每进一个 phase 就强制调工具 + hook 调 agent 复查」是运行时层(T661 / T663 / T664,依赖 Phase 5)。本协议是记录纪律和完成判据,不是逼着每次调用都记的运行时钩子。
- 不做 draft→production 晋级判定(
workflow_landing_to_production)。receipt 记到位 ≠ 工具 landed,后者看消费链。 - 检测器(术)住在工具目录里,本协议按名引用、不内联实现。
何时记 receipt
不是每次工具调用都值得记。触发条件(任一成立就该记):
- 这次调用的真实发生需要成为运行证据:落地闸门要回答「这个确定层工具真被调用了没」,receipt 是它的凭据。
- 工具产出了下游要消费的文件(报告 / 设计文档 / MAP),「它真跑了没、产出落在哪」是后续要回查的问题。
- 工具的调用率本身是某个语义层 skill「有没有真被用起来」的信号:被调用就是这个 skill 还活着的证据。
反过来,ls / cat 这种琐碎读取、一条命令就能复验的调用不必记,记了是台账噪声。判据是一句话:这次调用是不是某个「用了没 / 产出在哪」问题的答案。
记的时机固定在进程结束:成功记 exit 0、失败记真实非零退出码,两种都记,一条失败 receipt 同样是信息。接入用 best-effort,try/except 包住 record(),记 receipt 失败绝不改工具主功能的退出码(工具的活不能因为记台账崩掉)。
怎么填(四个字段,填实才算数)
record(tool, args, exit_code, meta) 落进台账的核心字段是 task_id / caller / artifact_paths / exit_code。每一格填实的样子:
- task_id:这次调用服务的真实任务 id(T-id)。从
meta["task_id"]传,或留给record()从环境变量(TODO_ID/TASK_ID/CODEX_TASK_ID)取。空 task_id = 一条回溯不到任何工作的 receipt,数量再多也证明不了工具被用于真实任务。landing-pipeline 的工具调用必须带 T-id。 - caller:真实的调用方,工具名 / session id / agent。空 caller = 看不出谁调的,台账失去问责价值。
- artifact_paths:工具真产出的文件,相对仓库根(
record()会做相对化)。产物类工具记空 artifact_paths,等于无法核验它做了什么;路径要指向真实存在的文件,不是/tmp下的临时件、也不是已经删掉的旧路径。非产物类工具(纯检查器)可以为空,这一格的要求是「声明了就得是真的」,不是「必须有」。 - exit_code:真实结果,不为了好看一律填 0。
调用率达标判据(E-01「稳定被调用」的信号)
「调用率达标」不是「占所有工具调用的百分之多少」。它是一句更具体的话:这个工具在该用到它的真实任务里,留下了真实 receipt。
两个失败模式正对着它:一是工具建好、注册了,但台账里 receipt 为零,这是孤儿(built-but-not-used),正是 landing_gate 盯的消费链病在 receipt 层的样子;二是 receipt 不为零,但全是开发期自测刷的(计数有、真实任务使用为零)。达标的样子是台账里有来自真实任务的 receipt(非空 task_id 配真实 artifact),不止是自测 receipt。
这一判据故意不写成一个魔法数字。绝对调用次数没有跨工具可比的含义,承重的是「有没有真实任务覆盖」,由下面 D4 的第二方判。
完成判据(可机械查,是这个协议的硬核)
判一个工具的 receipt 纪律落实了没,过下面四条,缺一不算落实。前三条确定性可查(检测器的壳承载),第四条要第二方判(检测器的 regulator 承载):
- D1 调用非零:工具至少有下限条 receipt(默认 ≥1,可传期望数)。零 receipt → FLAG 孤儿。确定性可查,包住
check.py的计数。这一条直接挡住「工具建了从没被调用」。 - D2 结构完整:工具的 receipt 里,caller 非空、task_id 非空(可回溯)、schema 必填字段齐。确定性可查,给出每条问题 receipt 的 event_id。这一条挡住空壳 receipt 刷计数。
- D3 artifact 真实存在:声明了 artifact_paths 的 receipt,其路径在磁盘上真存在。确定性
os.path.exists,给 event_id + 缺失路径。挡住「记了个根本不存在的产物」。 - D4 真实使用、非仪式性:receipt 代表真实任务使用,不是自测刷计数。这一条确定性壳判不出(字段都非空、路径都存在,仍可能整批是自测),要 regulator 喂 receipt 判:task_id 像真任务还是
TEST/T999这种占位?artifact 是真交付物还是落在fixtures///tmp?是不是整批挤在同一个自测时间簇里、同一个测试 caller?FLAG 时点名是哪条 event_id、为什么判成仪式性、怎么修。这是「receipt 写了 ≠ 记好」的语义信号。
跑 tool_receipts 的 check_discipline 检测器:D1-D3 出确定性 verdict(零调用 / 空字段 / 缺失 artifact → FLAG,给 event_id),D4 由 regulator 喂台账判仪式性。完成判断不让记 receipt 的 agent 自己勾,过检测器或第二方。
方法论建议(可按情况调整)
- 先接
record()再谈达标:工具没在进程末尾接record(),调用率永远是零,达标无从谈起。接入点是工具主流程结束处,try/except包住、不改主退出码。 - task_id 和 artifact_paths 是 receipt 的全部价值,别图省事留空:一条带真 T-id、真产物路径的 receipt 顶一打空壳。这两格留空,台账就退化成一个无意义的计数器。
- 收口清自测 receipt:开发期 / Codex 自测跑出来的 receipt(
fixtures/或/tmp的 artifact、TEST类 task_id)会污染达标判据,把真实使用刷虚。落地收口时清掉,或在自测阶段用--ledger指向独立台账,不写真实receipts.jsonl。
已知陷阱(来自真实案例)
- T1 仪式性 receipt:为了让
check.py计数加一,记一条 task_id 空、artifact 空或假的 receipt。确定性壳 D1 数得到(计数确实加了),但 D2 / D3 判得出空字段、假路径,D4 判得出整批没有真实任务。修法是把 D2-D4 做成机械门,让「计数加一」不等于「达标」。 - T2 自测污染真实台账:开发期自测把
TESTreceipt 写进真实receipts.jsonl,跟 T758 的 IT-TEST-CODEX 写进真源是同一个模式。收口必核必清,否则达标判据被刷虚还浑然不觉。 - T3 把「记了」当「稳定被调用」:一条 receipt 不等于工具被稳定用起来。达标看的是真实任务覆盖(D1 非零 + D4 真实),不是单次记录成功。
- T4 不信 builder 自报检测器:检测器实现交出去后,它自己报 PASS 不作数。亲自重跑确定性 exit + 亲读代码确认壳真扫了字段、regulator 真隔离(forbidden-read 成立),再用一个 builder 没写过的 held-out 场景独立核 regulator(同
workflow_design_doc_protocolT4、workflow_complexity_drift_detectionT5)。
输出规格
- 台账落在
tool_receipts固定路径contexts/tool_receipts/receipts.jsonl(工具写,本协议不另起平行台账)。 - 记录纪律检测器
tools/tool_receipts/check_discipline.py(路径查tools/INDEX.md):输入--tool <name>(复用check.py的过滤语义,可加--task/--since),确定性出 D1-D3(零调用 / 空字段 / 缺失 artifact → 给 event_id),regulator 喂台账判 D4 仪式性 / 自测。 - regulator 后端按名引用
cli_agent路由,拿不到 verdict 时 UNKNOWN 一律当 FLAG(失败安全)。
跨域根与联系
- 确定层有机械完成信号、语义层没有,agent 在没有外部误差信号时滑向有信号的一侧(receipt 的计数是信号、receipt 的质量不是):来自本轮诊断
adhoc_jobs/landing_requirement_decomposition_20260531/meta_analysis_20260604/DIAGNOSIS_order_intake_insight.md,诊断把tool_receipts点名为三个只建了确定层、没建语义层的脚手架之一。 - 完成判断要可操作(点名哪条 event_id 为什么不算数,不是「记得不够好」)+ 由第二方判:来自可验证 checkpoint 实验 + 开环控制(执行者不能当自己的 oracle)。
- 配合:检测器有效性标准 →
workflow_complexity_drift_detection(V1–V6);产物是否真 landed(receipt 是landing_gateC1 运行证据的一种来源,但 receipt 记到位 ≠ landed,landed 看四条件消费链)→workflow_landing_to_production;遇阻判断 →workflow_manage_unexpected;报告写作 →workflow_report_writing_matrix。