fix

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese
Fix the defect in the request that accompanied this invocation (a GitHub issue URL or number, or free text). Not done until every gate below is met and the PR says so.
The task. A GitHub reference →
gh issue view <ref> --json title,body,comments
; quote it. Name the failure in one sentence: what the vendor did, what the code did next. Anything the issue states about the vendor — what it supports, why it fails, what a field means — is a claim, the diagnosis included. No
.veris/run.sh
and no direct-tier
.veris/setup.json
→ stop;
setup
runs first. A
setup.json
with
"tier": "direct"
replaces
run.sh
: run the flow directly against the wired sandbox and read the trace where a gate reads the receipt (direct.md). Sandbox lifecycle and every
/veris/*
call: reference/twin.md.
The diagnosis. Before any sandbox: read the code path the issue names and enumerate every distinct defect that could produce the symptom — the vendor's failures and the repository's own (state lost between requests, a queue, a cache, a race), which no twin can represent. The manual's fault catalog is one hypothesis source, never the selector: the twin confirms a diagnosis chosen from code evidence, it does not choose it.
A run costs roughly turns × context, and every large output stays resident for every turn after it. The expensive mistake is not an extra call; it is pulling a big response into the thread that then has to carry it. So where subagents exist, delegate by default anything that reads wide or returns long — this survey, a full test-suite run, any output past a screenful — and keep the answer, not the transcript. Ask this one for candidate defects, each with its file and line. Read small things inline: a data census, one projected table, a filtered trace.
The boundary. Name where the vendor boundary sits in this task. A defect internal to the repository, with no vendor claim load-bearing: say so, verify by the repository's own test conventions, and spend the twin on one end-to-end confirmation of the changed flow instead of the full gate sequence. That one confirmation is a floor, not a discount: a reduced path that drove nothing through the twin has not spent less — it has left the change unproven, and the flow the issue names is the one it skipped. Spend the full gates where the task rests on what the vendor does — the trigger is the boundary, never self-assessed obviousness.
The base. Before the first edit, pin what the change will be measured against:
sh .veris/bin/record.sh base --task <id> --paths <the files the diagnosis implicates>
. It writes the starting commit into
.veris/tasks/<id>/record.json
, and Gate 4 reads it from there. Without
--paths
it falls back to the whole source tree, which pins far more than the task touches. Do this at the start, not at the gate — a base chosen once the diff exists is chosen by the thing being measured.
修复本次调用附带请求中的缺陷(可以是GitHub issue链接、编号或自由文本)。需满足以下所有验证关卡要求,并在PR中说明,才算完成任务。
任务说明。GitHub参考信息 →
gh issue view <ref> --json title,body,comments
;引用该信息。用一句话描述故障:供应商执行了什么操作,代码后续产生了什么结果。问题中关于供应商的所有表述——它支持的功能、故障原因、字段含义等——均属于声明,包括诊断内容。若不存在
.veris/run.sh
和直接层级的
.veris/setup.json
,则停止操作;需先执行
setup
流程。若
setup.json
中包含
"tier": "direct"
,则替代
run.sh
:直接针对已配置的沙箱执行流程,并在验证关卡读取凭证时查看跟踪日志(direct.md)。沙箱生命周期及所有
/veris/*
调用说明:reference/twin.md
故障诊断。在启动任何沙箱前:梳理问题提及的代码路径,列举所有可能导致该症状的不同缺陷——包括供应商端故障和仓库自身故障(请求间状态丢失、队列问题、缓存问题、竞态条件等),这些故障无法通过twin完全复现。手册中的故障目录仅作为假设来源,而非诊断依据:需基于代码证据选择诊断方向,再通过twin确认,而非由twin直接选择诊断结果。
一次运行的成本大致为轮次×上下文,且每次运行产生的大型输出会在后续所有轮次中保留。 代价高昂的错误并非额外调用,而是将大型响应拉入线程后需要持续携带它。因此,若存在子代理,默认将任何需要读取大量内容或返回长结果的任务委托给子代理——例如本次排查、完整测试套件运行、超过一屏的输出等——仅保留最终结果,而非交互记录。可向子代理询问候选缺陷,每个缺陷需附带对应文件和行号。对于小型内容则直接在线读取:例如数据统计、单个投影表、过滤后的跟踪日志。
边界定义。明确本次任务中的供应商边界。若缺陷为仓库内部问题,且不依赖供应商声明,则需明确说明,按照仓库自身测试规范验证,并仅通过twin对修改后的流程进行一次端到端确认,而非执行完整的验证关卡序列。该确认是最低要求,而非简化流程:若未通过twin执行任何流程,则无法证明修改有效,相当于跳过了问题提及的流程。当任务依赖供应商行为时,需执行完整验证关卡——触发条件为边界因素,而非自我判断的“显而易见”。
基准设置。在首次编辑前,确定修改的衡量基准:
sh .veris/bin/record.sh base --task <id> --paths <诊断涉及的文件>
。该命令会将起始提交写入
.veris/tasks/<id>/record.json
,关卡4将从此文件读取基准。若未指定
--paths
,则默认以整个源码树为基准,这会锁定远超任务涉及范围的内容。需在任务开始时执行此操作,而非在验证关卡时——若在生成差异后再选择基准,会受被测内容影响。

Gate 1 — the failure reproduced before the first source edit

关卡1:在首次修改源代码前复现故障

  1. .veris/NOTES.md
    , if present — what setup and earlier tasks already measured about this environment; do not re-measure it. Append anything measured in this task that outlives it.
  2. create_sandbox
    (MCP), or
    POST ${VERIS_API_BASE:-https://svc.api.veris.ai}/v1/environments/$VERIS_ENVIRONMENT_ID/sandboxes
    with
    {"ttl_minutes":60}
    ; then
    get_sandbox
    until
    status
    is
    ready
    — one sandbox for this whole task; keep its id and each service's
    control_url
    . A sandbox or proxy session kept alive from an earlier run is a net save — reuse it, reading from the ledger what per-run receipt lines would have shown.
  3. GET {control_url}/veris/manual
    — the service's own notes, short, read whole. It is authoritative for exactly these: the statuses and codes a fault may inject, the
    match
    selector keys this service supports, its API versions and selector, and its credential and setup notes. It is not a catalogue of what the service implements, and nothing is — read no coverage claim into what it leaves out. A surface the fix rests on gets one probe, and what a refusal proves is in reference/troubleshooting.md: some settle the question, most do not.
  4. The state. A sandbox boots the environment's default state, and the code path needs rows in it — the customer an invoice references, the account a charge posts to. Take the census first —
    GET {control_url}/veris/data
    with no parameters is every table and its row count in one small response — then read the shape of only the tables that matter:
    sh
    curl --fail-with-body -sS "$CONTROL_URL/veris/schema" |
      jq -e --arg table "$TABLE" \
        '.properties[$table] // error("unknown table: \($table)")'
    A whole schema is far larger than any one task needs; project it.
    GET {control_url}/veris/data?entity_type=<table>
    then shows what is already there; seed what is missing, in the shapes the schema names:
    http
    POST {control_url}/veris/data
    {"data":{"<entity>":[{"<primary-key>":"test-owned-id","<field>":"value"}]}}
    File bytes are not rows: seed the rows first, then post the files through
    /veris/files
    (reference/state.md). Ids come from the sandbox, never guessed and never carried from another sandbox. A call that fails because a row was absent is not the failure the issue describes. The state dies with its sandbox — resetting it, or keeping it: reference/state.md.
  5. Make the failure happen. The vendor will not produce it on demand. A vendor-side defect: arm a
    faults
    row in the shape reference/faults.md gives for what the issue reports. A repository-side defect no fault can produce: reproduce it through the application's own state — and when the twin cannot represent it at all, that report is the Gate-1 outcome, not a reason to switch diagnoses. Either way, drive the repository's own code path — the endpoint, worker or handler the issue names, unchanged — through it under
    .veris/run.sh
    with
    VERIS_SANDBOX_ID
    set to this sandbox (reference/proxy.md).
  6. Read the ledger:
    GET {control_url}/veris/data?entity_type=<table>
    and the trace. An injected fault's exchange is
    tier=fault
    , the traffic around it
    tier=handler
    , and your own
    /veris/*
    calls
    tier=control
    — ask for the tier the evidence is on rather than reading an unfiltered page of your own seeding (reference/troubleshooting.md). Not done with this gate until they show the outcome the issue describes — the duplicate row, the lost write, the wrong state — with ids and counts you can quote.
The order is the evidence. The red run is observed against the repository's unmodified code, before the first source edit; a red produced afterward by stashing the fix satisfies nothing — it can no longer challenge the diagnosis. The PR presents the red and green runs in the order they actually happened.
If the failure will not reproduce, that is the finding: report what the twin did instead, with the trace, and stop before changing code.
  1. 若存在
    .veris/NOTES.md
    ,查看其中关于当前环境已完成的配置和前期任务测量内容;无需重复测量。将本次任务中具有长期价值的测量内容追加到该文件中。
  2. 调用
    create_sandbox
    (MCP),或发送
    POST ${VERIS_API_BASE:-https://svc.api.veris.ai}/v1/environments/$VERIS_ENVIRONMENT_ID/sandboxes
    请求,参数为
    {"ttl_minutes":60}
    ;随后调用
    get_sandbox
    直至
    status
    变为
    ready
    ——整个任务仅使用一个沙箱;保留沙箱ID及各服务的
    control_url
    。若之前运行中已保留沙箱或代理会话,可复用它,从账本中读取原本会显示的每轮凭证行信息。
  3. 调用
    GET {control_url}/veris/manual
    ——读取服务自身的简短说明。该说明仅在以下内容上具有权威性:故障可注入的状态和代码、服务支持的
    match
    选择器键、API版本和选择器、凭证和配置说明。它并非服务实现功能的目录,因此不要对未提及的内容做覆盖性假设。若修复依赖某一接口,需进行一次探测,探测结果的证明力参考reference/troubleshooting.md:部分结果可明确问题,多数无法直接确认。
  4. 环境状态。沙箱启动时使用环境默认状态,而代码路径需要其中存在对应数据行——例如发票关联的客户、费用入账的账户。先执行数据统计——发送无参数的
    GET {control_url}/veris/data
    请求,以获取所有表及其行数的小型响应——然后仅读取相关表的结构:
    sh
    curl --fail-with-body -sS "$CONTROL_URL/veris/schema" |
      jq -e --arg table "$TABLE" \
        '.properties[$table] // error("unknown table: \($table)")'
    完整架构远大于单个任务所需;按需获取即可。调用
    GET {control_url}/veris/data?entity_type=<table>
    可查看已存在的数据;若有缺失,按照架构定义的格式填充:
    http
    POST {control_url}/veris/data
    {"data":{"<entity>":[{"<primary-key>":"test-owned-id","<field>":"value"}]}}
    文件字节不属于数据行:先填充数据行,再通过
    /veris/files
    上传文件(reference/state.md)。ID需从沙箱获取,切勿猜测或从其他沙箱复用。若因数据行缺失导致调用失败,不属于问题描述的故障。状态随沙箱销毁而消失——重置或保留状态的说明:reference/state.md
  5. 复现故障。供应商不会按需生成故障。若为供应商端缺陷:按照reference/faults.md定义的格式添加
    faults
    数据行,以模拟问题报告中的故障。若为仓库端缺陷且无法通过故障注入复现:通过应用自身状态复现——若twin完全无法复现该故障,则此报告即为关卡1的结果,而非更换诊断方向的理由。无论哪种情况,需驱动仓库自身代码路径——即问题提及的端点、工作线程或处理器(未修改状态下)——通过
    .veris/run.sh
    执行,并设置
    VERIS_SANDBOX_ID
    为当前沙箱ID(reference/proxy.md)。
  6. 读取账本:调用
    GET {control_url}/veris/data?entity_type=<table>
    并查看跟踪日志。注入故障的交互标记为
    tier=fault
    ,周边流量标记为
    tier=handler
    ,自身的
    /veris/*
    调用标记为
    tier=control
    ——需根据证据所在层级查询,而非读取包含自身填充数据的未过滤页面(reference/troubleshooting.md)。需在账本和跟踪日志中显示问题描述的结果——例如重复行、丢失写入、错误状态——并附带可引用的ID和计数,才算完成此关卡。
执行顺序即为证据顺序。需在未修改仓库代码的情况下观察到失败运行;若在修复后通过暂存代码复现失败,则不满足要求——此时无法验证诊断结果。PR需按实际执行顺序展示失败和成功运行记录。
若故障无法复现,此即为结论:报告twin的实际执行结果及跟踪日志,停止修改代码。

Gate 2 — the identity the fix rests on

关卡2:修复依赖的标识规则

Before the fix keys, looks up, or dedupes on any field, read that field's rule in
GET {control_url}/veris/schema
(the table's description). A field the vendor accepts twice for distinct records is not an identity; a fix anchored on it trades one failure for another. Name the field the fix rests on, and why it is one, in the PR.
The gate binds on any identity, dedup key or external reference the fix sends across the vendor boundary, however the code got it — computed, copied from an input, reused from an id the caller already carries. Copying does not discharge it: what the value leaves out has no row in the schema to read, and the collision lives there. Prove it against the twin. Vary each component of the identity independently — including an input that omits one — drive them through the same path, and count the rows the vendor stored: distinct inputs must have left distinct records. Fewer is the fix's own defect, caught before it ships. The identity, what you varied and the counts go in the PR beside the field. Questions and their asks: reference/twin.md.
在修复方案使用任何字段作为键、查询依据或去重标准前,调用
GET {control_url}/veris/schema
查看该字段的规则(表描述)。若供应商允许不同记录重复使用同一字段,则该字段不能作为标识;基于此类字段的修复会将一个故障替换为另一个。需在PR中说明修复依赖的字段及其可作为标识的原因。
此关卡适用于修复方案跨供应商边界传递的任何标识、去重键或外部引用,无论代码如何获取该值——计算得到、从输入复制、复用调用方已携带的ID。复制操作无法规避此规则:若值缺失部分信息,架构中无对应行可读取,冲突仍会存在。需通过twin验证。独立改变标识的每个组成部分——包括省略某一部分的输入——并通过同一路径执行,统计供应商存储的行数:不同输入必须生成不同记录。若行数更少,则说明修复自身存在缺陷,需在发布前修复。标识、修改的组成部分及计数需与字段信息一同写入PR。相关问题及查询方式:reference/twin.md

Implement

修复实现

As the repository does it: its test conventions, its coverage gate, nothing pointed at a sandbox, no vendor call changed to make a test pass. The repository's full test gate runs once: backgrounded, no self-imposed timeout, polled to completion, its result read before the PR is written. Never kill a running suite to relaunch it; never report a result that was not read.
按照仓库规范执行:遵循其测试约定、覆盖度要求,无需针对沙箱修改代码,不得为通过测试修改供应商调用逻辑。仓库完整测试套件仅运行一次:后台执行,不设置自定义超时,轮询直至完成,在编写PR前读取结果。切勿终止运行中的测试套件重新启动;切勿报告未读取的结果。

Gate 3 — the same failure, closed, with a receipt

关卡3:同一故障已修复,附带凭证

Re-arm the same fault; drive the same code path through
.veris/run.sh
(same
VERIS_SANDBOX_ID
); read the ledger again. Not done until the receipt shows at least one request to the service from that run and the ledger shows the outcome the fix promises — one row where there were two, the write recovered, the state right. Red before, green after, same flow: that is the proof.
One green proves one path. Before the PR, list every entry point that reaches the lines you changed — grep the changed symbols for their callers, and the constants those callers branch on, out to the endpoints, workers, handlers and jobs that own them — and say which of them this run actually drove. The ones it did not are not covered: they belong under limitations and risks, named, with what a caller reaching the fix that way would still get. A shared helper reached three ways and driven once is a fix for one third of the defect. Callers are not the whole list: a branch that duplicates the behavior rather than calling it — the same response handled, the same request built inline, selected by a mode or type switch — cannot appear in a grep for the symbol you changed. Search for those siblings, name each one you found, and either drive it in the green run or put it under limitations and risks with why it is out of scope. An unexercised sibling reported as covered fails this gate. In a repository large enough that this sweep spans many files, it is worth a subagent where one is available: ask for the entry points, each marked driven or not-driven.
重新注入相同故障;通过
.veris/run.sh
执行同一代码路径(使用相同的
VERIS_SANDBOX_ID
);再次读取账本。需在凭证显示本次运行至少向服务发送一次请求,且账本显示修复承诺的结果——例如两行变为一行、写入已恢复、状态正常——才算完成此关卡。先失败、后成功、同一流程:这就是修复的证明。
一次成功运行仅能证明一条路径。在编写PR前,列出所有可到达修改代码行的入口点——通过grep查找修改符号的调用方,以及这些调用方分支依赖的常量,直至找到对应的端点、工作线程、处理器和任务——并说明本次运行实际驱动了哪些入口点。未驱动的入口点未被覆盖:需归为限制与风险部分,明确说明调用方通过该入口点使用修复时仍会遇到的问题。若一个共享助手有三种调用方式,但仅驱动了一种,则仅修复了三分之一的缺陷。调用方并非全部列表:若存在分支逻辑复制了该行为而非直接调用——例如相同响应处理、相同请求内联构建、通过模式或类型开关选择——则无法通过grep查找修改符号发现这些分支。需搜索此类分支,列出所有找到的分支,要么在成功运行中驱动它们,要么将其归为限制与风险部分并说明超出范围的原因。若未执行的分支被报告为已覆盖,则此关卡不通过。若仓库规模较大,此排查涉及多个文件,可委托子代理(若可用):请求子代理列出所有入口点,并标记已驱动或未驱动。

Gate 4 — the measurements against the diff

关卡4:基于代码差异的测量

Every measurement this task took is one row in the ledger, written when you take it rather than reconstructed at the end — a ledger assembled after the code is a description of the code, not a check on it. Before the PR:
sh .veris/bin/ledger.sh --against-diff --task <id>
— no
--base
: it reads the commit pinned at the start of the task. If it reports the base is unpinned, that is the task's mistake, not the gate's; it does not get a base at gate time.
Each row ends as exactly one of: encoded, naming the changed file and the symbol or decision that honors it; non-load-bearing, carrying a counterfactual — the different value the measurement could have taken without changing what the fix promises; contradicted; or unresolved. The last two are gate failures.
A contradiction is the code's problem, not the report's. Change the code. The row format and the four dispositions are in reference/proof.md;
ledger.sh init
prints the field contract.
本次任务的所有测量内容均需在执行时写入账本,而非在任务结束时重构——若在修改代码后再组装账本,仅能描述代码,无法验证代码。编写PR前执行:
sh .veris/bin/ledger.sh --against-diff --task <id>
——无需指定
--base
:该命令会读取任务开始时锁定的提交。若命令报告基准未锁定,属于任务执行错误,而非关卡问题;此时无法在关卡阶段设置基准。
每一行测量结果最终需归为以下四类之一:已编码,指定修改的文件及遵循该修改的符号或决策;非承重,包含反事实假设——即不改变修复承诺结果的前提下,测量值可能出现的不同情况;矛盾;或未解决。最后两类属于关卡失败。
矛盾属于代码问题,而非报告问题。需修改代码。行格式及四类结果的定义参考reference/proof.md
ledger.sh init
会输出字段约定。

The PR

PR编写

Open a draft as the repository does. Its body has three sections, in the shape of reference/evidence.md: what I verified, and how — the fault armed, the before ledger, the after ledger, the receipt line; what I am assuming rather than verifying, and why that is acceptable; limitations and risks — including what a caller could still do wrong. Every task premise measured false is its own line in the body — the premise, the probe, the answer — and is never restated as fact after that measurement, in prose, code, or a name. Paste the sandbox id. Then
delete_sandbox
(or
DELETE …/sandboxes/<id>
).
When a step needs it: state.md, webhooks.md, trust.md (an SDK refusing the proxy's certificate), troubleshooting.md. Note anything the sandbox got wrong or lacked and give it to the engineer at the end. Ask before sending repository code anywhere new. Never promote a sandbox.
按照仓库规范创建草稿PR。PR正文包含三个部分,格式参考reference/evidence.md已验证内容及方式——注入的故障、修复前账本、修复后账本、凭证行;假设内容及合理性说明限制与风险——包括调用方仍可能出现的错误操作。若任务前提被测量为错误,需在正文中单独列出——前提内容、探测方式、结果——且在测量后不得将其作为事实重述,无论是在 prose、代码还是命名中。粘贴沙箱ID。然后调用
delete_sandbox
(或发送
DELETE …/sandboxes/<id>
请求)。
若步骤需要参考:state.mdwebhooks.mdtrust.md(SDK拒绝代理证书的情况)、troubleshooting.md。记录沙箱存在的错误或缺失功能,在任务结束时告知工程师。向新位置发送仓库代码前需先确认。切勿升级沙箱。