tool-stewardship

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

tool-stewardship — consult first, write last, document always

tool-stewardship — 先查阅,后编写,始终记录

A research program in which agents do much of the work accumulates capability only if someone makes it accumulate. Code gets written constantly; the question is whether the tenth problem starts where the ninth finished or starts from zero. Left to defaults it starts from zero: each session writes a script, solves its problem, and exits, and everything the script learned leaves with the context that held it. A shared toolkit converts that loss into compounding — but only under habits that do not happen on their own: consult before writing, improve in place rather than copy, document the day you build, retire what has been superseded. This file is those habits as procedure.
The economics are lopsided. Consulting an index costs minutes; rebuilding an instrument costs hours, and the rebuild is usually worse, because the existing tool embodies fixes for failures its author already hit and a fresh script embodies none. A tool that has survived many problems carries their corrections; new code carries only its author's foresight. The same asymmetry is why patching beats forking: a fork stops inheriting the moment it is copied, so every later correction to the original must be rediscovered in the fork, usually by getting a wrong answer first. And documentation is same-day work because the author is the only person who knows what the tool assumes, and only briefly. A page written a week later records the memory of an intention; a page written the day of the build records the fact of a behavior.
在一个由 Agent 完成大部分工作的研究项目中,能力只有在有人确保其持续累积时,才会真正不断积累。代码被不断编写;关键问题是:第十个问题应当从第九个问题的终点继续,还是从零开始。若放任这种默认情况,第十个问题就会从零开始:每个会话都编写一个脚本、解决自己的问题,然后退出,脚本学到的一切也都随着承载它的上下文一同消失。共享工具包能把这种损失转化为复利——但前提是养成那些不会自行发生的习惯:编写前先查阅,在原地改进而不是复制,构建当天完成记录,淘汰已被替代的工具。本文件将这些习惯转化为可执行的流程。
这种投入产出极不对称。查阅索引只需几分钟;重建一个工具却要数小时,而且重建结果通常更差,因为现有工具包含其作者曾经遇到失败后做出的修复,而新脚本对此一无所获。一个经受许多问题考验的工具承载着这些修正;新代码只承载作者当时的预见。同样的不对称也解释了为什么修补优于分叉:分叉一旦被复制出来便停止继承,此后原工具的每一次修正都必须在分叉中重新发现,而且通常要先得到一个错误答案才能发现。文档必须当天完成,因为作者是唯一知道工具采用了哪些假设的人,而且这种了解只会短暂存在。一周后写下的页面记录的是对最初意图的记忆;构建当天写下的页面记录的则是实际行为的事实。

Procedure

流程

Before writing any code

编写任何代码之前

  1. Search the index by capability, not by name. You are looking for "something that fits a rate to a time-stamped log," not for a title you half-remember. Read past the one-line summaries: a near-miss matters, because a near-miss plus a patch is the usual right answer.
  2. Read the candidate's page in full. The page says when the tool applies and what test its output must pass. Skimming the page and then "verifying" by eyeballing one output is how the wrong tool gets trusted.
  3. Run it on a trivial case with a known answer before running it on your problem. This costs a minute and catches both your misreading of the interface and any rot in the tool itself.
  4. Climb the decision ladder in order: use as-is → patch or extend → wrap → write new. Writing new code obliges you to state, in one written sentence, which existing tools you checked and why each falls short. If you cannot write that sentence, you have not consulted; go back to step 1.
  1. 按能力而非名称搜索索引。 你要找的是“能把某个速率拟合到带时间戳日志上的东西”,而不是一个你只记得一半的标题。不要止步于一行摘要:近似匹配很重要,因为“近似匹配 + 修补”通常才是正确答案。
  2. 完整阅读候选工具的页面。 页面会说明工具何时适用,以及其输出必须通过什么测试。浏览页面后仅凭肉眼检查一个输出就进行“验证”,正是错误工具被信任的原因。
  3. 先在一个答案已知且简单的案例上运行它,再将其用于你的问题。 这只需要一分钟,却能同时发现你对接口的理解错误和工具本身可能已经出现的腐坏。
  4. 按顺序攀登决策阶梯: 原样使用 → 修补或扩展 → 封装 → 编写新工具。编写新代码时,必须用一句书面陈述说明你检查过哪些现有工具,以及每个工具为何无法满足需求。如果连这句话都写不出来,就说明你还没有完成查阅;请返回第 1 步。

When patching an existing tool

修补现有工具时

  1. Patch the upstream copy, in place. Never a private copy in your working directory — the point is that the next user inherits the fix.
  2. Preserve the interface, or migrate every caller in the same change. Search for the call sites first. A changed output format with an unmigrated caller produces wrong numbers that still parse (see the catalogue).
  3. Re-run the tool's known-answer tests, plus the case that motivated the patch. Then add the motivating case to the tests — it is the one input class the tests demonstrably lacked.
  4. Log the change the same day: date, what changed, why, and what a user of yesterday's version would see differently. The log lives where the next user will look, and the tool's page is updated whenever the meaning of the output moved. An undocumented upgrade is indistinguishable from a regression.
  1. 在原地修补上游副本。 绝不要在工作目录中保留私人副本——这样下一位用户才能继承这项修复。
  2. 保持接口不变,或者在同一次变更中迁移所有调用方。 先搜索调用点。输出格式发生变化而调用方未迁移,会产生仍可成功解析的错误数字(见目录)。
  3. 重新运行工具的已知答案测试,以及触发此次修补的案例。 然后把触发修补的案例加入测试,因为它是测试显然缺少的那一类输入。
  4. 当天记录变更: 日期、变更内容、变更原因,以及用户使用昨天的版本时会看到哪些不同。记录应存放在下一位用户会查找的位置;当输出含义发生变化时,还要更新工具的页面。未记录的升级与回归问题无法区分。

When new code is justified

新代码确有必要时

  1. Prove it on known answers before the real problem. New code earns trust the way a new instrument does: by getting right the cases where right is checkable.
  2. Decide, honestly, whether it outlives the problem. If yes: name it, move it into the toolkit tree rather than leaving it beside the run that spawned it, write the four-question page below, and add the index row — all the day it is built, because tomorrow you will be inside the next problem and the day after you will not remember the preconditions.
  3. If it is genuinely one-shot, say so in a comment at the top of the file, so a later reader knows it was left unregistered on purpose. Be suspicious of that verdict, though: "one-shot" is usually a failure to imagine the next problem, and the catalogue below is full of one-shot scripts that got rebuilt monthly.
  1. 先在答案已知的案例上证明其正确性,再处理真实问题。 新代码应当像一件新工具那样获得信任:在结果可以核验的案例上给出正确答案。
  2. 诚实判断它是否会比当前问题活得更久。 如果会:为它命名,将它移入工具包目录树,而不是留在产生它的运行目录旁;编写下面的四问页面,并添加索引行——所有这些都要在构建当天完成,因为明天你会投入下一个问题,后天便不再记得这些前提条件。
  3. 如果它确实仅供一次性使用,请在文件顶部的注释中说明这一点,让后来的读者知道它是有意不登记的。不过,要警惕这种判断:“一次性使用”通常意味着没有设想下一个问题,而下面的目录中满是一些每月都会被重新构建的一次性脚本。

The four-question page

四问页面

Every tool's page answers four questions for a reader who has never seen the tool:
  1. What it does — one plain paragraph.
  2. When to reach for it — the symptom or task that should route here, and the neighboring tool that covers the adjacent case, so the reader can see the boundary.
  3. What its output means — units, conventions, and what failure looks like as distinct from success. A tool whose failure output resembles its success output needs that fact stated in bold.
  4. What test its answer must pass before anyone believes it — the known-answer case, the cross-check against an independent route, whatever the acceptance criterion is.
A tool missing any of the four is not finished, however well it runs. Example of a complete entry:
undefined
每个工具的页面都要向从未见过该工具的读者回答四个问题:
  1. 它做什么 —— 用一个直白的段落说明。
  2. 何时使用它 —— 描述应当转到这里处理的症状或任务,并指出覆盖相邻场景的邻近工具,让读者看清边界。
  3. 其输出意味着什么 —— 说明单位、约定,以及失败与成功有何区别。如果工具的失败输出与成功输出相似,必须用粗体明确说明这一事实。
  4. 在任何人相信其答案之前,答案必须通过什么测试 —— 可以是已知答案案例、与独立路径的交叉核验,或任何其他验收标准。
缺少其中任何一项,工具都尚未完成,无论它运行得多么正常。完整条目的示例:
undefined

ratefit — runtime projection from a partial log

ratefit — runtime projection from a partial log

Fits a rate to a job's own time-stamped log and projects completion. When to reach for it: before extending any running job, or when deciding whether a projected run fits a time budget. Not for jobs whose per-item cost grows with the item index — no tool covers those yet; measure directly. Output: projected finish time plus a fit residual. A residual above the printed threshold means the rate is unstable and the projection is VOID, not merely approximate. Believe it when: the projection from the first half of a finished job's log matches that job's actual finish.

A reader of that block can decide whether to use the tool, use it, and distrust it correctly — without opening the source.
Fits a rate to a job's own time-stamped log and projects completion. When to reach for it: before extending any running job, or when deciding whether a projected run fits a time budget. Not for jobs whose per-item cost grows with the item index — no tool covers those yet; measure directly. Output: projected finish time plus a fit residual. A residual above the printed threshold means the rate is unstable and the projection is VOID, not merely approximate. Believe it when: the projection from the first half of a finished job's log matches that job's actual finish.

读完该段落的读者无需打开源代码,就能判断该工具是否适用、如何使用,以及何时应正确地对其保持不信任。

Retiring duplicates

淘汰重复工具

When two tools overlap, merge into the stronger one and port whatever cases only the weaker handled; the weaker tool's tests are the checklist for the port. Then delete the loser and leave a one-line pointer at its old name and its old index row ("superseded by X, date"), because habits and links keep pointing at dead names for months. Never leave both live "for safety" — every future reader then re-litigates the choice, and some choose wrong.
当两个工具的功能重叠时,将它们合并到更强大的那个工具中,并移植仅由较弱工具处理的案例;较弱工具的测试就是移植工作的检查清单。然后删除被淘汰的工具,并在其旧名称和旧索引行处留下一行指针(“已由 X 替代,日期”),因为习惯和链接会在几个月里一直指向失效的名称。绝不要为了“稳妥”而让两者继续有效——这样每位后续读者都会重新争论应该选择哪个,而且有些人会选错。

Failure-mode catalogue

失败模式目录

These are the classes the discipline exists to prevent. Each recurs wherever the procedure is skipped.
  • Parallel half-tools. Two sessions each need most of the same instrument and each writes its own; each handles the failure cases its own problem hit, and neither inherits the other's. Result: two tools, each incomplete in a different way, with disjoint bugs — and every later user must discover which crash they are going to get.
  • The vanishing script. A script solves the problem and stays, unnamed, in the run directory. A month later the same problem is solved again from scratch, slightly differently, with a fresh set of bugs, and the second author never learns the first version existed.
  • The drifting fork. A copy taken "just to change one flag" stops inheriting; upstream later fixes a correctness bug; the fork keeps the bug and returns silently different answers, discovered only when the two are compared by accident.
  • The unregistered capability. Built, tested, even documented in its own directory — but no index row. Searching agents conclude the capability does not exist and rebuild it. The entire loss traces to one missing line.
  • The author-facing page. The documentation explains how the tool works inside and says nothing about when to reach for it or what the output means. The next agent reads the page and still cannot decide, so they write their own.
  • The unlogged upgrade. Behavior changed; nothing was recorded. The next user's results shift with no way to tell fix from regression, so the tool — rather than the change — loses their trust.
  • Silent-caller breakage. A patch changes the output format; an unmigrated caller parses the old format and receives values that still parse. Nothing crashes. The wrong numbers travel.
  • The shadow fork. A modified copy quietly becomes the version everyone actually runs while the index still points at the original. Every property documented about the tool is now a property of the wrong file.
  • Documentation from memory. The page gets written a week after the tool, reconstructing intent. The one precondition that mattered — the input convention, the case the tool must never be fed — is exactly what the author no longer remembers.
  • The undead duplicate. A tool superseded by a better one is never retired. Someone finds it in the index, uses it, and gets the answer the replacement was built to correct.
这些正是此纪律要防止的问题类型。只要跳过流程,它们就会反复出现。
  • 并行的半成品工具。 两个会话各自需要同一个工具的大部分功能,于是分别编写自己的实现;每个实现只处理自己的问题所触发的失败情况,彼此也无法继承对方的改进。结果就是两个工具各自以不同方式不完整,漏洞也互不相交——以后每个用户都得先弄清自己会撞上哪一种崩溃。
  • 消失的脚本。 一个脚本解决问题后仍留在运行目录中,没有名称。一个月后,同一个问题被略微不同地从头解决,并产生一组全新的错误,而第二位作者始终不知道第一个版本曾经存在。
  • 漂移的分叉。 一份仅仅为了“修改一个标志”而复制的代码会停止继承上游改进;上游后来修复了正确性缺陷,分叉却保留该缺陷,并悄悄返回略有差异的答案,只有偶然对比两者时才会被发现。
  • 未登记的能力。 能力已经构建、测试,甚至在自己的目录中完成文档,却没有对应的索引行。搜索工具库的 Agent 会据此认定该能力不存在,并重新构建。全部损失都源于缺少的一行记录。
  • 面向作者的页面。 文档只解释工具内部如何工作,却完全没有说明何时该使用它或输出意味着什么。下一位 Agent 读完页面仍无法作出决定,于是编写自己的工具。
  • 未记录的升级。 行为发生了变化,却没有留下任何记录。下一位用户的结果随之改变,却无法区分这是修复还是回归,最终失去信任的会是工具本身,而不是某次变更。
  • 静默的调用方故障。 修补改变了输出格式,未迁移的调用方仍按旧格式解析,并获得仍可成功解析的值。没有任何程序崩溃,但错误数字会继续传播。
  • 影子分叉。 一份修改后的副本悄悄成为所有人实际运行的版本,而索引仍指向原始版本。此时,文档中关于该工具的每一项属性,实际上都变成了对错误文件的描述。
  • 凭记忆编写文档。 工具完成一周后才编写页面,文档只是对最初意图的重建。那个至关重要的前提条件——输入约定,或工具绝不能接收的案例——恰恰是作者已经无法记起的内容。
  • 不死的重复工具。 被更优工具替代的工具从未被淘汰。有人从索引中找到它并加以使用,从而得到替代工具本应纠正的答案。

Checklist

检查清单

Before writing code:
  • Index searched by capability; the nearest tool's page read in full.
  • One sentence written stating why no existing tool, or a patch to one, covers the need — or the ladder stopped before "write new."
Before the session ends, for any tool created or changed:
  • Change logged, dated, with what a user of the old version would see differently.
  • Four-question page written or updated — does the stated meaning of the output still match?
  • Index row added or updated.
  • Known-answer test exists and passed; the motivating case added to the tests.
  • Every caller of a changed interface migrated.
  • Overlapping tools merged; superseded names carry pointers.
  • Nothing capability-bearing left behind in the working directory.
编写代码之前:
  • 已按能力搜索索引;并完整阅读最接近工具的页面。
  • 已写下一句话,说明为何现有工具或对现有工具的修补都无法满足需求——或者决策阶梯在“编写新工具”之前就已停止。
对于本次会话创建或修改的任何工具,在会话结束之前:
  • 已记录并注明日期的变更,包括旧版本用户会看到哪些不同。
  • 已编写或更新四问页面——页面所述的输出含义是否仍然一致?
  • 已添加或更新索引行。
  • 已知答案测试已经存在并通过;触发修补的案例也已加入测试。
  • 接口发生变更时,所有调用方均已迁移。
  • 功能重叠的工具已合并;被替代的名称均保留有指向新工具的指针。
  • 工作目录中没有遗留任何承载可复用能力的内容。