먼저 밝혀 둘 것이 있다. 2026년 4월에 이 매거진은 강원 화천의 30년차 토마토 농부가 헛간의 노트 서른 권을 한 화면으로 옮긴 이야기를 실었다. 실명과 나이와 지역까지 특정된 인터뷰였다.
이 현장은 특정 농가가 아니다. 그래서 원 인터뷰를 그대로 다시 싣지 않는다. 대신 같은 형태를 처음부터 끝까지 직접 만들었다. 아래의 모든 화면과 숫자는 그렇게 만든 것에서 나온 것이고, 어느 한 농가의 기록은 아니다.
이 구분을 첫 문단에 두는 이유는, 원 글의 논지 전체가 "당신도 된다"는 허락이고 그 허락은 사례의 실재에 얹혀 있기 때문이다. 실재를 확인하지 못한 채 같은 문장을 반복하면 그건 허락이 아니라 광고다.
그래서 이 글이 증명하려는 것은 좁아진다. "어떤 농부가 해냈다"가 아니라, "이런 도구는 이렇게 생겼고 실제로 이만큼 된다" 까지다.
원 글의 심장에 실물이 없었다
원 글의 축은 좋았다. 종이는 적는 데서 멈춘다. 꺼내서 맞춰 보는 일은 사람의 기억과 인내에 맡겨진다. 그런데 같은 칸으로 쌓이면 기록이 물어볼 수 있는 것이 된다.
그 물성 전환은 지금도 맞다고 본다. 문제는 그 글이 그것을 한 번도 보여 주지 않았다는 것이다.
- 그가 실제로 무엇을 말했는지 — 요구 원문 0줄
- 그 말이 어떤 화면 정의가 되었는지 — 정의 발췌 0줄
- 어떤 단계를 거쳐 만들어졌는지 — 제작 과정 0단계
- 노트 서른 권 이관 — "틈틈이 옮기고 있다"는 진술뿐
그리고 글의 백미인 "옮긴 지 18일째 첫 꽃" 이라는 발견도 그랬다. 다섯 해 치 데이터가 쌓여야 성립하는 주장인데, 그 데이터도 그것이 드러난 화면도 없었다.
이번엔 셋을 나란히 둔다. 말한 것 → 정의가 된 것 → 실제로 그려진 것.
말한 것
만들면서 요구를 세 문장으로 적었다. 개발 용어를 쓰지 않았다.
- "작물을 고르면 올해 기록이 죽 뜨게."
- "적는 건 한 손으로 되게."
- "작년은 이맘때 어땠는지 옆에 뜨게."
세 문장이 도구 셋이 됐다.
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」를 한 번 누르면 줄이 하나 는다.

그리고 해를 겹쳐 본 화면.

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.
그리고 검증이 그걸 직접 확인한다. 계산된 값이 소스에 문자열로 들어 있으면 실패시킨다.
AVG=$(grep -o "average from records: [0-9.]*" captures/run.log | awk '{print $4}')
if grep -RIn --exclude-dir=captures -F "$AVG" farm_server/bin farm_log.mbd bundle_host/lib; then
echo " the average $AVG appears literally in the source — it must be computed"
exit 1
fi
통과 로그다.
average 18.2 computed from records, not present in any source file
"기록에서 드러났다"와 "그렇게 적어 뒀다"는 화면에서 똑같이 생겼다. 그래서 구별할 방법을 통과 조건에 넣었다.