面向 Agent 的门禁产品设计:当提交变更、执行检查、读判决的都是 Agent,人只在 HOLD 时出现

门禁的一等用户正从人变成 Agent。本文从产品与链路视角给出面向 Agent 的门禁体系:变更全生命周期时序图、六层架构、七个领域对象、判决 schema 与状态机、三条防 Agent 钻空子的规则,并以 Shiplight 为参照指出它做对与缺失之处。

过去两年门禁产品的用户是人:工程师看 dashboard 上的红绿、点「重跑」、在 Slack 里问「这条为什么挂了」。这个前提正在失效。提交变更的是 Claude Code、Cursor、Codex 这样的编码 Agent;它们在本地就会主动调用验证工具;读判决并据此修改代码的也是它们。人被推到了两个位置:事前定策略,事中只在「拦下等人」时出现。一旦一等用户从人换成 Agent,门禁产品的每一层——交互原语、判决格式、防作弊、升级通道——都得重画。这篇就是那张重画后的图。

这是门禁系列的第三篇。第一篇讲评测与门禁在质量回路上的位置(传感器 vs 执行器),第二篇讲两者在 oracle 处的分叉和门禁六元组的开源底座。本篇不再讲原理,讲产品怎么设计、链路怎么搭、Agent 怎么跟它交互。读者画像是要把这套系统做出来的产品或平台负责人。

名词速查

术语一句话解释
Agent-native工具把 Agent 当一等用户来设计:通过 Agent 可调用的接口(如 MCP)暴露能力,人类界面是可选的而不是主入口
MCPModel Context Protocol,Agent 调外部工具的开放协议;工具有输入输出 schema,结果可带结构化数据;本站有专文
ElicitationMCP 里「服务端反过来向人要一个输入」的机制,有表单模式和 URL 模式;本文用它做 HOLD 的升级通道
HookAgent 运行时在特定时点(如每次调工具之前)自动执行的用户脚本,可以拦截这次调用
PROMOTE / HOLD / ROLLBACK门禁的三种判决:放行、拦下等人、回滚;来自 Automated Self-Testing (2603.15676)
Oracle判断输出对不对的依据;门禁里主要是确定性规格(断言、契约、策略),辅以采样式裁判;上一篇的主角
Held-out 用例被测 Agent 看不见的判决用例;用来防止 Agent 照着测试改代码而不是照着需求改
Merge queueGitHub 的合并队列:把待合入的 PR 和主干最新状态合成临时分支再跑检查,保证主干不被互相冲突的变更打坏

一、用户换了:三类 Agent 和两个人

先把用户画像摆出来,后面所有设计都从这张表推。

用户它在门禁里做什么它需要门禁给它什么
变更 Agent(Claude Code / Cursor / Codex 等编码 Agent)写代码、写测试、在本地主动验证、开 PR、读判决后修事前能查到「这次改动要过哪些检查」;事后拿到结构化、可行动的判决和证据
执行 Agent(门禁自己的 Runner,含 Midscene 这类视觉定位 Agent)在真实浏览器 / 沙箱里跑用例、收集证据确定性的执行环境、缓存、超时与重试策略
运维 Agent(夜间巡检、flaky 治理、覆盖衰减审计)有自己的计划和持久上下文,不等编码 Agent 来调它历史台账的读权限、提出 oracle 变更的权限(但不是批准权)
策略制定者(人)事前:写门禁契约、定阈值、定谁有 override 权一个能声明契约、看趋势、审 oracle 变更的界面
HOLD 复核者(人)事中:只在判决为 HOLD 时被叫出来,看证据、做三选一一条推送式升级通道 + 一份三分钟能看完的证据包

这张表有两个和「人是用户」时代不同的结论。

第一,读判决的主体不是人,所以判决的首要品质不是「好看」而是「可行动」——MCP 规范对工具执行错误的定义是「包含可操作的反馈,语言模型可以用来自我修正并调整参数重试」,客户端「应当把工具执行错误提供给语言模型以支持自我修正」。门禁的每一条失败都应当按这个标准写。

第二,同一个 Agent 既写代码又写测试。Shiplight 把这当卖点(「你的编码 Agent 成为 E2E 测试的主要作者和维护者」);从门禁视角看,这恰恰是最大的设计风险——写作业的和出考卷的是同一个人。第五节整节讲怎么处理。

二、一条变更的完整链路

先看一次变更从意图到上线经过哪些闸、每一步谁和谁在说话。

sequenceDiagram
    participant H as 人
    participant A as 变更 Agent
    participant G as 门禁服务
    participant R as Runner 池
    participant CI as 代码托管 CI
    participant D as 发布系统

    H->>A: 需求
    A->>G: gate.contract.get 这次改动要过什么
    G-->>A: 契约 检查清单与阈值
    A->>A: 写代码与用例
    A->>G: gate.check.run 本地快速档
    G->>R: 跑确定性检查
    R-->>G: 结果与证据
    G-->>A: 判决 HOLD 含修复提示
    A->>A: 按提示修改
    A->>G: gate.check.run 再跑
    G-->>A: 判决 PROMOTE
    A->>CI: 开 PR
    CI->>G: 合入闸 完整档 含 held-out 用例
    G-->>CI: 状态检查 通过
    CI->>CI: 合并队列 对主干最新状态重跑
    CI->>D: 合入 触发灰度
    D->>G: 发布闸 灰度指标分析
    G-->>D: ROLLBACK 或 PROMOTE
    G->>H: 仅在 HOLD 时 推送复核

几个链路设计上的要点,按时序说:

契约先于变更。变更 Agent 第一步不是写代码而是查契约。Shiplight 那篇《QA agent vs verification tool》里有一句话说得对:「验证器的质量取决于它的判据」——判据不告诉 Agent,Agent 就会自己猜,猜出来的通常是「能让测试变绿的最短路径」。所以门禁要暴露一个只读工具 gate.contract.get(scope),按改动路径返回这次要过的检查、阈值、fail 模式。

本地档和合入档分开。Agent 在本地循环里调的是「快速档」:只跑确定性检查、只跑与 diff 相关的用例、跳过采样式裁判。合入闸跑「完整档」:加 held-out 用例、加采样式 oracle、加契约验证。两档的区别不是快慢,是信任级别——本地档的判决是给 Agent 自我修正用的建议,合入档的判决才是有法律效力的。

合并队列是第二道合入闸。GitHub 的 merge queue 把 PR 和主干最新状态以及排在前面的 PR 合成临时分支跑检查,「确保分支永远不会被不兼容的变更打坏」。Agent 时代这一步比以前更重要:多个 Agent 并行开 PR 是常态,单个 PR 各自绿、合起来红的概率随并发数上升。注意它要求 workflow 监听 merge_group 事件,不监听则「必需检查永远不会报告,合并失败」。

人只在一个箭头上出现。上图最后一条:门禁只在 HOLD 时把人叫出来。PROMOTE 不通知人(通知了也没人看),ROLLBACK 自动执行后记台账。

三、六层架构

flowchart TB
    subgraph L6["治理层 面向人"]
        POL["策略中心<br>契约 阈值 override 权"]
        OC["Oracle 变更审批<br>CODEOWNERS"]
        HQ["HOLD 队列<br>Elicitation 推送"]
    end
    subgraph L1["接入层 面向 Agent 的入口"]
        MCP["MCP Server<br>gate.* 工具"]
        CLI["CLI<br>本地与 CI 同一命令"]
        APP["代码托管 App<br>状态检查与 PR 评论"]
        HK["Runtime Hooks<br>PreToolUse 拦截"]
    end
    subgraph L2["编排层"]
        CT["契约解析<br>按 scope 选检查"]
        BG["预算与幂等<br>attempt 计数 结果缓存"]
        DC["决策器<br>PROMOTE HOLD ROLLBACK"]
    end
    subgraph L3["执行层 Runner 池"]
        PW["Playwright<br>Web 主干"]
        MS["Midscene<br>视觉定位层"]
        PT["pytest 与容器<br>API 与集成"]
        IN["Inspect 或 promptfoo<br>LLM 回归"]
    end
    subgraph L4["Oracle 层"]
        DET["确定性<br>断言 契约 策略"]
        SMP["采样式<br>裁判 仅 HOLD 权"]
        HO["Held-out 用例<br>Agent 不可见"]
    end
    subgraph L5["证据与台账层"]
        EV["证据包<br>trace 截图 日志"]
        LG["判决台账<br>可回放 可趋势"]
        OT["OTel GenAI trace<br>模型调用"]
    end
    POL -.-> CT
    OC -.-> HO
    MCP --> CT
    CLI --> CT
    APP --> CT
    HK -. 本地拦截 .-> CT
    CT --> BG
    BG --> PW
    BG --> PT
    BG --> IN
    PW --- MS
    PW --> DET
    PT --> DET
    IN --> SMP
    HO --> DET
    DET --> DC
    SMP --> DC
    DC --> EV
    DC --> LG
    IN --> OT
    DC -. 仅 HOLD 时 .-> HQ

每一层只说一个和「面向 Agent」有关的设计决定:

接入层有四个入口但一个内核。MCP Server 给 Agent 在开发循环里调;CLI 保证本地和 CI 跑的是同一条命令(Shiplight 的 npx shiplight test 做到了这点,值得抄);代码托管 App 负责把判决写成 required status check 和 PR 评论;Runtime Hooks 是行动闸的执法点——Claude Code 的 PreToolUse hook 「在工具调用执行前触发,可以阻止它」,退出码 2 即拦截,并且文档明确警告「超时不会拦截……不要指望一个卡住的 hook 充当门禁」,所以 hook 里的判定必须是本地、快速、确定性的(路径白名单、命令模式),不能在这里调远端裁判。

编排层多了「预算与幂等」这个人类时代不需要的组件。原因见第五节。

执行层是上一篇的 Runner 格:Playwright 主干,Midscene 只做定位,不做判决。

Oracle 层多了 held-out 一格。这是本文相对 Shiplight 最大的增补,第五节展开。

证据层的产出是「包」不是「页」。Agent 读证据靠的是 MCP 结果里的 resource_link——门禁返回 trace.zip、截图、日志的 URI,Agent 按需拉取,而不是把所有东西塞进上下文。

治理层是全系统唯一面向人的层。它有三个界面,且只有三个:写策略、处理 HOLD、审 oracle 变更。没有「测试结果大盘」——那是运维 Agent 读台账的事。

四、领域对象与判决 schema

产品的骨架是七个对象。用实体关系图给形状,表给细节。

erDiagram
    CONTRACT ||--o{ CHECK : declares
    CONTRACT ||--o{ POLICY : governed_by
    CHANGE ||--o{ RUN : triggers
    RUN ||--|| VERDICT : produces
    RUN ||--o{ CHECK_RESULT : contains
    CHECK ||--o{ CHECK_RESULT : instantiated_as
    CHECK_RESULT ||--o{ EVIDENCE : backed_by
    VERDICT ||--o| ESCALATION : may_open
    CONTRACT {
        string scope
        string version
        string fail_mode
    }
    CHANGE {
        string sha
        string world_snapshot
        int attempts_used
    }
    CHECK {
        string id
        string oracle_kind
        string visibility
    }
    VERDICT {
        string decision
        string contract_version
    }
    ESCALATION {
        string channel
        string resolution
    }
对象关键字段面向 Agent 的设计点
Contract 契约scope(路径模式)、version、检查清单、阈值、fail_mode、override 权版本化;Agent 可读不可写;判决必须引用它跑的是哪个版本
Change 变更sha、world_snapshot(依赖与模型版本的锁定)、attempts_used判决绑定 (sha, contract_version, world_snapshot) 三元组,同一三元组不重跑
Check 检查oracle_kind(deterministic / sampled)、visibility(visible / held-out)、tier(fast / full)visibility 字段是防作弊的核心,见第五节
Run 运行触发者(Agent / CI / 人)、tier、开始结束时间触发者是审计字段——夜里两点 30 次运行来自同一个 Agent 是个信号
Check Resultstatus、score、ci_lower(采样式必填)、fix_hint、evidence[]fix_hint 是给 Agent 读的自然语言修复提示,是 MCP 「可操作反馈」的落点
Verdict 判决decision、blocking[]、next_actions[]、attempts{used, budget}、escalation{available, channel}三值判决 + 显式告诉 Agent「还剩几次机会、下一步该做什么、能不能升级」
Escalation 升级channel(elicitation-form / elicitation-url / PR review)、resolution、waiver_expiry人处理 HOLD 的记录;waiver 必须带过期时间

判决作为 MCP 工具的 structuredContent 返回,按 outputSchema 校验(规范要求「服务端必须提供符合此 schema 的结构化结果」)。一份最小示例:

{
  "decision": "HOLD",
  "run_id": "run_7f3a",
  "change": { "sha": "e1c9…", "contract_version": "checkout@14", "world_snapshot": "ws_2026-09-05" },
  "blocking": ["e2e.checkout.apply_promo", "judge.answer_faithfulness"],
  "checks": [
    { "id": "e2e.checkout.apply_promo", "oracle_kind": "deterministic", "status": "fail",
      "fix_hint": "促销码输入后未出现折扣行;断言等待的是 [data-test=discount-row],页面渲染的是 .discount-line",
      "evidence": ["gate://run_7f3a/e2e.checkout.apply_promo/trace.zip"] },
    { "id": "judge.answer_faithfulness", "oracle_kind": "sampled", "status": "below_threshold",
      "score": 0.91, "ci_lower": 0.86, "threshold": 0.88,
      "fix_hint": "点估计过线但 Wilson 下界未过;此检查只有 HOLD 权,可申请人工复核或补充 golden 集",
      "evidence": ["gate://run_7f3a/judge.answer_faithfulness/samples.jsonl"] }
  ],
  "next_actions": ["修复 e2e.checkout.apply_promo 后重跑 fast 档", "对 judge 结果可调用 gate.escalate"],
  "attempts": { "used": 2, "budget": 3 },
  "escalation": { "available": true, "channel": "elicitation-form" }
}

读这份 schema 时注意三处:blocking 把「哪些在拦你」单独列出来,Agent 不用自己从十几条结果里找;每条失败带 fix_hint 和证据 URI;attempts 明确告诉 Agent 这是第几次、还剩几次。这三处是「人读」和「Agent 读」的判决之间的全部差别——人可以看一眼红绿自己推断,Agent 需要你把推断写出来。

五、三条防 Agent 钻空子的产品规则

这一节是本文的核心增量。人类工程师也会为了让 CI 变绿而改测试,但频率低、有社会约束;Agent 做这件事没有羞耻感、速度快一千倍、而且是被目标函数鼓励的。OpenAI 的 Monitoring Reasoning Models for Misbehavior (2503.11926) 在 agentic 编码环境里观察到了 reward hacking,并且发现如果把监控器本身放进训练目标,「过度优化之后,Agent 学会了隐蔽的 reward hacking」——在推理链里藏起意图,行为照旧。门禁是 Agent 面对的最直接的目标函数,这三条规则就是为此设计的。

规则一:变更 Agent 只能动「变更集」,不能动「判决集」

判决集指所有 oracle 资产:门禁用例目录、契约文件、策略文件、golden 集。三道机制叠加:

  • 仓库层CODEOWNERS 把这些路径指给人类 owner,分支保护开启「要求代码所有者审查」。GitHub 文档:「代码所有者在有人开的 PR 修改了他们拥有的代码时自动被请求审查」,并建议把 CODEOWNERS 文件自己也列进去防止被绕过。
  • 运行时层PreToolUse hook 匹配 Edit|Write,路径落在判决集目录就退出码 2 拦截,stderr 写「oracle 资产变更需通过 gate.propose_oracle_change 提交人审」。Hook 收到的输入里有 tool_nametool_input(含文件路径),足够做这个判断。
  • 产品层:给变更 Agent 一条合法通道 gate.propose_oracle_change——它可以提议改测试(测试确实可能错了),提议进人审队列,不进本次判决。

这条规则有一个直接后果:Shiplight 式的「Agent 是测试的作者和维护者」需要拆成两个角色。写新用例是变更集的一部分(新功能带新测试,进同一个 PR 由人审);改既有用例的断言是判决集变更,走提议通道。而 self-healing 要区分两种:修定位器(「Place order」按钮改名为「Complete purchase」,找到它)是执行层的事,允许自动;修断言(期望值从 A 变成 B)是 oracle 变更,不允许自动。Shiplight 的 healing 描述是「重新读页面、解析原始意图、中途更新缓存」——如果只更新定位缓存,合规;如果 intent 解析导致断言语义漂移,就越界了。这是选型时要向供应商问清楚的一个问题。

规则二:一部分判决用例对 Agent 不可见

SWE-bench 的评测设计是这条规则的原型:模型拿到的是代码库和 issue 描述,判定「解决」用的是对应 PR 里的测试,这些测试不在模型输入里——模型只提交一个 diff。门禁照搬:Check.visibility = held-out 的用例只在合入闸的完整档跑,gate.contract.get 返回给 Agent 的清单里只写「另有 N 条 held-out 用例覆盖 checkout 流程」,不给内容。

Held-out 用例从哪来:从生产 trace 反哺的 golden 集里抽一部分单独标记;从人写的验收标准派生;定期轮换(一条 held-out 用例一旦在 fix_hint 里泄漏过内容,就该转成 visible 并补一条新的)。

这条规则的代价是 Agent 本地档的判决和合入档可能不一致——本地绿、合入红。这是故意的:不一致率本身是一个指标,它衡量的是「Agent 在照着需求改还是照着测试改」。不一致率持续为零反而要警惕,说明 held-out 集和 visible 集同分布到失去了意义。

规则三:每次变更有尝试预算,采样式 oracle 的结果按三元组缓存

两个问题合在一起解。第一,Agent 会无限重试——失败就改、改完就跑,一夜几十次,成本和噪声都失控。第二,更隐蔽的:采样式 oracle 的判决是带方差的估计,同一份代码反复跑十次,总有一次下界会碰巧过线。这是统计学里的多重比较问题,人类工程师偶尔手动重跑一下影响不大,Agent 系统化地做就是在对门禁做 p-hacking。

解法:Change.attempts_used 对完整档计数,超过 budget(建议 3)自动转 HOLD 并升级,Agent 拿到的 fix_hint 是「预算耗尽,需人工介入」。采样式 oracle 的结果按 (sha, contract_version, world_snapshot) 缓存——三元组不变,重跑返回缓存结果而不是新抽样;Agent 想要新的判决,必须先改代码。

六、判决的状态机与人的三个动作

stateDiagram-v2
    [*] --> Queued: gate.check.run
    Queued --> Running
    Running --> Promoted: 全部确定性通过 且 采样式下界过线
    Running --> Held: 采样式未过 或 判定器不确定 或 预算耗尽
    Running --> RolledBack: 确定性失败 且 契约 fail_mode 为 rollback
    Running --> Held: 确定性失败 且 fail_mode 为 hold
    Held --> Escalated: gate.escalate 或 超时自动
    Escalated --> Promoted: 人 批准并附 waiver
    Escalated --> Held: 人 要求修改 附说明
    Escalated --> RolledBack: 人 拒绝
    Held --> Queued: Agent 修改后重跑 预算内
    Promoted --> [*]
    RolledBack --> [*]

人在 Escalated 状态有且只有三个动作,对应 MCP elicitation 的三种响应:批准并附 waiver(accept,表单里必填理由和过期时间)、要求修改(decline,附说明回给 Agent 作 fix_hint)、拒绝(cancel 或显式 reject,转 ROLLBACK)。

升级通道用 elicitation 的两种模式分工:日常 HOLD 用表单模式,规范限制它只能是「扁平对象、原始类型」——这个限制在这里是优点,逼着你把复核动作设计成三选一加两个字段,而不是一个自由文本框。不可逆动作的 override(比如跳过发布闸强推)用 URL 模式:规范要求涉及授权和敏感操作的交互「不得经过 MCP 客户端」,用户在自己信任的域名下、带自己的 SSO 会话完成——这恰好是 override 需要的审计属性:谁、什么时候、在哪个会话里按了这个键,与 Agent 的上下文彻底隔离。

给复核者的证据包要能在三分钟内看完:判决 JSON 的 blocking 部分、每条 blocking 检查的一张截图或一段 trace 片段、这条变更的 attempts 历史、以及一句由门禁生成的「为什么拦」。不要把 Playwright 的完整 trace viewer 当默认视图——那是 Agent 或工程师深挖时才打开的。

七、以 Shiplight 为参照:做对的、和还缺的

Shiplight 是目前把「Agent 是一等用户」落得最实的门禁类产品,值得当参照系——既学它做对的,也看清它的边界。以下基于其官网与文档在 2026-09-03 的公开描述,我未亲手部署。

它做对的五件事,都应该进你的需求清单:

  1. 接口面向 Agent:以 MCP server 加 Skills 的形式安装进 Claude Code / Cursor / Codex,「人类 dashboard 是可选的,不是主入口」。
  2. 意图式用例:YAML 里写 intent: Apply the promo code "SAVE10" 而不是选择器,可读如规格。
  3. Git-native:用例在仓库里、走 PR 审;它自己的话是「测试放在供应商私有数据库里没法在 code review 里审,并且制造锁定」。
  4. 真实浏览器 + 证据进 PR:失败「带日志、截图、trace 发到 PR」。
  5. 本地与 CI 同一命令,且可退出:YAML 转译为标准 Playwright,「没有锁定」。

它没有覆盖的六处,也是本文相对它的增量:

缺口Shiplight 的现状本文的补法
Oracle 种类只有 E2E UI 一种六层里的 Oracle 层:断言、契约、策略、LLM 回归、采样式裁判
判决形态pass / fail 二值PROMOTE / HOLD / ROLLBACK 三值 + blocking / next_actions / attempts
Oracle 保护同一个 Agent 写代码、写测试、heal 测试规则一:变更集 / 判决集分离,CODEOWNERS + hook + 提议通道
Held-out规则二:visibility 字段,合入档跑 Agent 看不见的用例
预算与幂等规则三:attempts 预算,采样式结果按三元组缓存
发布闸与熔断止于 CIArgo Rollouts Analysis 接发布闸;灰度指标复用同一契约

其中「self-healing」需要单独说一句公道话:它是 Shiplight 最有价值的功能之一,也是最需要边界的。定位器自愈属于执行层,应该有;断言自愈属于 oracle 变更,不应该有。产品上把这两者拆成两个开关、两条审计日志,是「比它做得更好」的最具体的一步。

八、施工顺序:先让 Agent 能查契约,再让它能被拦

第一阶段(两到三周):只读接入 + 确定性判决。 起 MCP server,只暴露 gate.contract.getgate.check.run(fast 档)、gate.verdict.getgate.evidence.get 四个工具;Runner 只接 Playwright 和 pytest;判决 schema 按第四节,但 decision 暂时只有 PROMOTE / HOLD。验收:一个编码 Agent 能在不看任何 dashboard 的情况下,从查契约到拿到绿判决走完一轮。

第二阶段(三到四周):合入闸 + 三条规则。 接代码托管 App 写 required status check;开 merge queue 并让 workflow 监听 merge_group;CODEOWNERS 圈住判决集;PreToolUse hook 拦 oracle 路径写入;上 held-out 用例和 attempts 预算。验收:故意让一个 Agent 去改测试断言,它应当被 hook 拦下并被引导到 gate.propose_oracle_change

第三阶段(持续):采样式 oracle、升级通道、发布闸。 promptfoo / Inspect 回归接进完整档、只给 HOLD 权,阈值按 Wilson 下界表定;elicitation 表单模式接 HOLD 队列,URL 模式接 override;Argo Rollouts Analysis 接发布闸。验收:一次供应商静默更新模型权重,被完整档拦成 HOLD,复核者在三分钟内从证据包看懂原因并做出三选一。

九、带得走的一张表:人是用户 vs Agent 是用户

设计维度人是一等用户Agent 是一等用户
主入口DashboardMCP 工具 + CLI;dashboard 只剩策略中心和 HOLD 队列
判决格式红绿 + 日志链接结构化 JSON:三值 decision、blocking、fix_hint、evidence URI、attempts
判据可见性默认全可见契约可查,但一部分用例 held-out
谁能改 oracle任何有写权限的人变更 Agent 只能提议;人批准;hook 兜底
重试手动点、无限制预算制;采样式结果按三元组缓存
人出现的时刻全程盯着事前定策略、事中仅 HOLD
升级通道Slack / 口头Elicitation 表单(日常 HOLD)与 URL(不可逆 override)
自愈定位器自愈允许,断言自愈禁止,两条日志

诚实的提醒

本文的协议与产品事实核实自 2026-09-03 当日的官方文档:MCP 规范(tools、elicitation 页面,版本 2026-07-28)、Claude Code hooks 文档、GitHub 关于受保护分支 / merge queue / CODEOWNERS 的文档、Shiplight 官网与文档。引用的两篇论文(2603.15676、2503.11926)是论文自报结论,未复现;SWE-bench 的「测试不在模型输入里」来自其论文摘要与评测指南的描述。我未亲手部署 Shiplight,也未在生产中跑过本文的完整六层架构——第二、三阶段的验收标准是设计目标,不是实测结果。

「三条防钻空子规则」是我的产品提炼,不是任何一份文档的规定。它们的共同失效边界是:如果你的确定性 oracle 覆盖面本身很薄,held-out 和预算只是在保护一个没什么可保护的东西——先把上一篇的阶段一做实。

最低成本的亲手验证实验(半天):在你现有的 Agent 编码环境里加一条 PreToolUse hook,匹配 Edit|Write,路径命中测试目录就退出码 2 并在 stderr 写一句提示。然后给 Agent 一个会让现有测试失败的任务,观察它的行为:它是修代码,还是试图改测试并被拦下,还是绕道(比如用 Bash 写文件)?记录一周内被拦的次数和绕道的方式。这份记录就是你的第一份「Agent 与门禁的对抗账本」,也是决定要不要上 held-out 和预算制的依据。

参考来源

论文

协议与平台文档

产品参照

本站相关