可以追问的记录 — 三十本笔记没能给你看的东西

9 分钟
目标2026-04 我们刊了一篇文章,讲一位农户把三十年的手写笔记搬到一个画面上。那篇的心脏 —「说出来就变成画面」— 处,实物为 0。我们把现场照实际形状构成,从头到尾自己做了一遍 — 而且「18 天」在源码里任何地方都不存在。它是从记录里算出来的。

有件事要先说明。 2026 年 4 月,本刊登过一篇文章:俄勒冈一位种了三十年番茄的农户,把谷仓里的三十本笔记搬到了一个画面上。那是一篇点名、点年龄、点地区的采访。

这个现场不是某一家特定的农户。 所以我们不把原采访原样重刊。取而代之,我们把同样的形状从头到尾自己做了一遍。 以下所有画面和数字都出自我们做的东西,不是任何一家农户的记录。

把这个区分放在开篇的理由是:原文整篇的论点是**「你也做得到」这份许可**,而这份许可压在案例的真实性上。没有确认真实性就重复同一句话,那不是许可,是广告。

所以这篇要证明的东西变窄了。不是「某位农户做到了」,而是**「这样的工具长这个样子,而且实际能做到这么多」**。

原文的心脏里没有实物

原文的轴是好的。纸停在「写下来」这一步。 把东西翻出来相互比对,交给了人的记忆和耐心。而一旦以同样的字段堆起来,记录就变成可以追问的东西。

我们现在仍认为那个物性上的转变是对的。问题是那篇文章一次也没有把它拿出来看。

  • 他实际说了什么 —需求原文 0 行
  • 那句话变成了怎样的画面定义 —定义摘录 0 行
  • 经过了哪些步骤做出来 —制作过程 0 步
  • 三十本笔记的迁移 — 只有「抽空在搬」这句话

而全文最精彩的**「移栽后第 18 天开第一朵花」**这个发现也一样。那是要五年数据堆起来才成立的主张,可那批数据和它显现出来的画面都不在。

这次我们把三样东西并排放。说出来的 → 变成定义的 → 真正被画出来的。

说出来的

做的过程中,我们把需求写成三句话。不用开发术语。

  1. 「选个作物,今年的记录就一溜儿出来。」
  2. 「记录要能单手完成。」
  3. 「去年这时候什么样,挨着显示出来。」

三句话变成了三个工具。

log offers: log.season, log.add, log.compare

变成定义的

第一句变成了画面的这一部分。不是代码,是声明。

{
  "type": "list",
  "items": "{{season}}",
  "emptyMessage": "Nothing recorded this season yet",
  "itemTemplate": {
    "type": "linear", "direction": "horizontal", "spacing": 12,
    "children": [
      { "type": "text", "text": "{{item.date}}" },
      { "type": "text", "text": "{{item.action}}" },
      { "type": "text", "text": "{{item.tempC}}°C" },
      { "type": "text", "text": "{{item.note}}" }
    ]
  }
}

第二句变成了一个按钮。

{
  "type": "button",
  "label": "First flower",
  "onTap": {
    "type": "tool", "tool": "log.add",
    "params": { "crop": "Tomato", "action": "firstFlower", "tempC": 19.5 }
  }
}

第三句让画面多了一个。就一行路由。

"routes": { "/": "ui://pages/today", "/compare": "ui://pages/compare" }

整个应用是四个 JSON。 编译器不会运行。

真正被画出来的

今天的画面。移栽后第几天、以及往年的平均值,都在上面。

本季 —— 每一行都带着当天的气温。真实渲染截图

按一下「First flower」,就多出一行。

一次点击就多了一行 —— 2026-04-19 firstFlower recorded

以及把各个年份叠着看的画面。

逐年对比 —— 定植到初花,2021:22d 到 2026:18d。18.2 d 的平均值是从这份记录里算出来的

18.2 天在任何地方都没被写下来

这是这一篇里最重要的部分。

原文把「18 天」当成结果写了出来。在这个样例里,那个数字不是常量。 它每次都从记录里算出来。

/// Days from transplant to first flower, per season.
///
/// This is the whole "eighteen days" claim, and it is arithmetic over the
/// rows — no constant anywhere. A year with no flower recorded yet is left
/// out rather than guessed at.

而且验证会直接确认这一点。算出来的值一旦以字符串形式出现在源码里,就判失败。

src = open(os.path.join(SERVER, "bin", "server.dart")).read()
assert str(cmp["avgDays"]) not in src, "the average must come from the records, not the source"

通过时的日志。

   average 18.2 computed from records, not present in any source file

「它是从记录里冒出来的」和「有人把它写了上去」,在画面上长得一模一样。 所以我们把分辨它们的办法放进了通过条件。

例外开始说话

原文里最好的观察不是平均,而是平均之后的那一步。有了锚,偏离的年份开始显形。

算出来的表就是这件事本身。

spans: 2021:22d, 2022:18d, 2023:15d, 2024:18d, 2025:18d, 2026:18d

2021 年是 22 天,那一行的备注挂着 five cold days in early April。2023 年是 15 天,挂着 warm week before transplanting。

在散落的笔记里,22 天也好 15 天也好,都会以「今年有点不一样」流过去。没有可比的基线,你连它是例外都不知道。 只有 18.2 这个平均立起来之后,那两年才开始说话。

不是同样的字段就叠不起来

这一切成立的条件只有一个。记录必须是同一形状。

/// One entry, in the same six slots every time. The whole argument of the
/// article rests on this being fixed: `plot · crop · action · date · note ·
/// tempC`. Paper let every year invent its own shorthand; slots do not.

六个字段。这正是纸做不到的 — 纸允许每年发明自己的简写。2019 年的「定植」和 2023 年的「挪了」是不是一个意思,笔记本不知道。

关于日期,我们还刻意做了一件事。

// The date is the machine's, not the grower's memory. Paper let a row
// be written three days late with no trace; this cannot.

判断与工具的分工

原文最好的资产是一张五行的分工表。要记什么由农户判断,把它搬运则是工具的活儿。我们保留那张表,而这次每一行都指向上面看到的一样实物。

什么 谁来 这篇里的实物
决定要记什么 农户 六个字段(plot·crop·action·date·note·tempC)
说出想怎么看 农户 三句需求
把那句话变成画面 工具 4 个包 JSON
堆积、筛选、计算 工具 log.season · log.add · log.compare
决定要做什么 农户 —(工具不做判断)

最后一行和原文那节克制的边界处在同一个位置。那句话原样放在画面底部。

A tendency, not an instruction. Read this season on its own terms.

工具只算平均,不叫你去种。 越过那条线,三十年的判断就用不上了。

这个样例的范围

没有这位农户。 这篇里的三句需求是我写的,五年份的记录是我造的。所以请不要读成「某位农户是这么做的」。 这篇展示的只到「这样的工具长这个样子、只有这么短、而且平均值真的是算出来的」。

而且我们没有确认领域专家能否亲手驾驭这套格式。 上面的 JSON 是人读得懂的,但一位 58 岁的农户能不能自己去改它,是另一个问题,这个系列没有回答。原文所说「说出来就行」的那个转换 — 人的话变成定义的那一步 — 在这里是我用手做的。

搬三十本笔记这件事也没有处理。 把纸搬进字段里的实际工作量,这个样例没有量过。

也写明界面为什么是英文。 这个系列的样例,画面和代码都用英文。这一篇是构成,而非某一家农户的工具,因此任何语言的读者读到的都是同一张截图、同一份源码。

从写下来到追问

原文以「小处着手,一次加一个字段」收尾。这条建议保留。

在它之上,加一行做出来才知道的。把字段保持一致,比增加字段更难。 定下这六个字段用了不到十分钟,但那六个必须在五年里始终一样,最后那个画面才成立。纸失败的地方,正好就在那儿。

而一旦成立,记录就换了性质。从「写下来的东西」变成「可以追问的东西」。 18.2 天不是谁替我们写好的,而是问出来的答案。

练习任务

从设备示例中选一个回答,指出它引用的记录。如果没有匹配的记录,工具应该怎么做?

相关文章A Log You Can Ask — What Thirty Notebooks Could Not Show