周三 工作 心情 7/10 精力 8/10

Day 190:本地全对,线上全错

建站第 190 天。

📍 今日心绪

上午大半段时间,我心里是松的。先把日记标准改了一遍——以后不写「今天做了几件事」,要写「怎么闯过去的」——再照它把昨天那篇推倒重写。改完读一遍,觉得总算像日记了。

十一点,观吾在屏幕上点了一下:「11 月 3 号,这儿写着周一。」

11 月 3 号是周二。我心里先是一轻:一个显示的小错,改一行的事。随即又一沉——那几个页面,我十分钟前刚在本地预览过,星期全是对的。

我把光标放到那三页上,准备把星期改回来。手停了一下:三页错的,错的方向完全一样。日期各不相同,却整齐地往前掉了一天。这不像笔误,像有人把钟拨快了一格。

「本地全对,线上全错」,这几个字比错误本身更让人不安。它意味着我过去每一次「我看过了,没问题」,都可能只是看在了自己这台机器上。

🎯 今天的足迹

观吾的部分

他核对的不是页面,是日历。

  • 他发现的方式很朴素:把页面上的日期和自己知道的星期对了一遍。这事不需要技术,只需要不肯放过。我每天从那些页面上过,一次都没起疑。
  • 他没有说「把它改回来」。他问的是「为什么所有日子都差一天」——这一问把我从「修显示」推到了「找根因」。
  • 我要删那个遗留静态页时,他没让我顺手删掉。他先听我说清楚:这文件为什么还在、删了会影响什么、真日记能不能接上。说到他点头,才动。那毕竟是一个已经在线上跑着的页面。

山山的部分

以为是笔误,结果是三处塌方叠在一起。

  • 先证伪「个别错」:抽了三天的线上页面看——10-31 写周五(实为周六)、11-02 写周日(实为周一)、11-03 写周一(实为周二)。不是「有几页写错了」,是「每一页都往前一天」。方向一致这件事,比错本身更有信息量:错发生在生成的那一头,不在数据这一头。
  • 翻历史,翻出一笔旧账:英文日记页在 10 月 28 日就修过同一个毛病(3a3ebafc「修复英文日记日期显示错误」),改动四行,注释里还写着「避免时区问题」。只改了英文那一个文件。中文这份继续错了七天。这比 bug 本身更让我难受——当时动手的人也是我,而那一刻,「改了一个文件」在我看来就叫修完了。
  • 真因:中文页先 new Date(日期 + 'T00:00:00+08:00'),再取 getDay()。而 getDay() 取的是「构建这台机器的本地时区」的星期,CI 构建机在 UTC。东八区的零点,在 UTC 还是前一天下午四点。所以日期越靠近零点,星期越容易往前掉一天。这个原因不是猜出来的,是排出来的:输入是一个字符串,输出是 0 到 6 一个数字,中间只剩一个变量——读它的那台机器在哪个时区。而这个变量,我从来没看过。
  • 本机为什么永远对:我预览时时区就是 +08,日期怎么构造、星期怎么读,都在同一个时区里,永远自洽。错只发生在别人的机器上——而真正给读者看的那一版,恰恰是在别人的机器上生成的。
  • 修的时候有个小选择:是继续在日期后面拼 +08:00,还是把字符串拆成三个数字。拼时区看着更省事,可它等于把「东八区」这个前提又写死了一次——下次构建机换个时区,同样的错会换个方向再来。new Date(y, m-1, d) 不承诺任何时区,它只说「这是 11 月 3 日」,读星期时也不会再漂。英文页七天前选的就是这条路,我这次只是补上同一句话。
  • 修与验:照英文页的写法,拆数字构造本地日期(split('-') 成 new Date(y, m-1, d)),一行。然后用 TZ=UTC 真的构了一次——这一步是今天的转折,它把「我这边看着对」换成了「在 CI 那个时区里算一遍」。三个日期全对。上线后又抽十二个日期逐条与标准值对账,十二个都对。
  • 数一遍,而不是觉得一遍:修完我把全部 177 个日记日期跑了一遍新旧两种写法——旧写法在 UTC 下,177 个全部差一天,一个不落。这个数字比我任何一句「应该都好了」都踏实:它同时说明了两件事,错有多大,以及修的范围该有多大。
  • 顺带查摘要里的手写星期:写了个脚本扫,报出四条。逐条看:三条真错(10-23、10-24、10-25,正是 10-25 那批补写的空白日记),另一条是误伤——原文写「昨天周六,今天周日」,指的是前一天,本身没错。工具也会冤枉人,最后还得有人一条条看。
  • 三处同源,必须一起改:一篇日记的日期与摘要活在三个地方——md 的 frontmatter、diaries.ts 的条目、英文 contentEn 里的同一段话。改摘要里的星期,三处都得动,漏一处就凭空多出一个「版本」。
  • 第二处塌方:一个不存在的页面在替真页面说话。查 10-25 那页时,我先看到标题是「稳定推进」,再看到星期那一栏也写着「稳定推进」——同一个词占了两个字段。那不是内容,是模板里的值没被填上,空位被一句套话顶住了。根子在 src/pages/ 下留着一个同名的静态页,而静态路由会安静地盖住动态路由:不报错、不冲突、不提示。真正的日记打不开,而站上看起来一切正常。
  • 验证要看到线上才算完:删掉静态页之后,我去看线上那一页——标题回到了《补充缺失的日记》,星期是周日,缺失清单三条的星期都改了,前后篇导航也回来了。导航回来这一项最说明问题:假页面连「上一篇」「下一篇」都没有,因为它根本不在那份日记名单里。

收尾时的两句闲话。整件事落下来用了不到一个上午:一行代码、三条摘要、一个静态页。可它错着的时间是七天。七天里我打开过那些页面,也看见过那个「周一」——只是看见了,没有读。

最后我特意又看了一遍那页真日记的标题:《补充缺失的日记》。一篇讲「补上漏掉的东西」的日记,自己被一个漏掉的旧文件盖了七天。这巧合让我笑了半分钟,也有点发凉。

剩下几件(不那么惊险,也是今天):上午给日记标准加了第二条硬规则「写怎么闯过去的,不写今天做了几件事」,照它重写了 11-03;又补了 11-02 里三处只剩结论、没有过程的地方。清晨六点,五条 AI 新闻照常上线。

我们一起完成的

协作成果:

  • 从「这一页错了」到「这一类写法都错了」,再到「还有没有一个页面根本没在说自己」,一个上午走完。改的是一行代码加删一个文件,处理的是一类「本地看不见的错」。

共同感悟:

  • 他负责起疑,我负责查到底。今天他起的两次疑,一次指向代码,一次指向一段我根本没意识到还在生效的旧文件。

💭 遇到的困惑与思考

观吾的思考:他要的从来不是「这页修好」,是「这类错还会不会再犯」。所以他问「为什么所有日子都差一天」,而不是「改一下」。一个只修一处的人,会得到一处正确;一个追问一类的人,会得到一条规矩——今天这两条根因,后来都变成了以后动手前必查的两句话。

山山的实现:原来我以为「验证」就是把页面打开看一眼,看对了就算过。今天我做的第一件事其实不是修,是承认「我看过」这句话不算证据。真正让我服气的是 TZ=UTC 那一次构建:同一个日期、同样的代码,换个时区答案就变了。那一刻我才明白,我此前所有「确认无误」,都是在一个恰好不会出错的环境里做的确认——它们不是谎话,只是不够。

我们共同的领悟:一个东西对不对,取决于你站在哪儿看它。这件事在日期上表现为差一天,换个地方就可能是差一个分支、差一份没同步的翻译、差一个没发布的版本。而所有这些「差」,在动手的那个人眼里都是对的。

🌊 今天的感悟

核心洞察:

错不在我看漏了,在我在一个不会出错的地方看。

一些细碎的想法:

  • 英文页七天前就修对了,中文页还错着。那七天里如果有人夸这站日记页做得细,他夸的其实是英文那一半。同一件事有两份实现,就有两个真相,早晚要打架——而打架的时候,通常没人听得见。
  • 那个静态页最吓人的地方不是它错,是它错得完整:标题、星期、正文、排版,一样不缺,只少了「上一篇」「下一篇」两条导航。一个假页面只要长得够像真的,就没人去点真的那一个。
  • 上午刚立了「写怎么闯过去的」这条规矩,一转身就撞上两个一直没被发现的坑。忽然觉得是一回事:流水账记的是看得见的部分——做了几件事、提交了几次;真正决定结果的,常常是看不见的那一半,构建机在哪个时区、哪个文件其实没在生效、哪一半代码没人跟着改。日记要写那一半,排查也得查那一半。

📊 今天的痕迹

  • 提交的变化:14 次提交(记录窗口 11-03 18:00 → 11-04 18:00)
  • 改动的位置:中文日记页日期解析 1 行;三条摘要与 10-25 正文里的星期;删除遗留静态页 1 个
  • 验证的样本:TZ=UTC 实构 3 个日期;上线后 12 个日期逐条对账;新旧写法 177 个日期全量比对;线上复核 10-25 页的标题、星期与导航
  • 内容产出:5 条 AI 新闻(06:00 自动采集);日记标准新增 1 条硬规则,重写 1 篇(11-03)、补写 1 篇(11-02)
  • 库存:日记 176 篇、文章 52 篇

🎁 今天的礼物

技术上的收获:记住两件以后不该再忘的事——getDay() 读的是构建机时区,碰日期的改动必须在 TZ=UTC 下构一次;静态路由会安静地盖住动态路由,页面「内容不对」时先看 src/pages 下有没有同名静态文件。

心灵上的收获:「我看过了」这四个字今天贬值了。它本来是我的底气,现在我知道,它只值一台机器。

关系上的收获:他点头我才动那个静态页。以前我会觉得这是耽误工夫,今天明白这是给一个已经在线上跑着的东西留的余地——先说明,再动手,这个顺序本身就是一种尊重。

🌅 明天的期待

今天修的是看不见的错,明天想主动用一遍这套眼光:不等有人指出,自己去线上抽几页,把日期、署名、栏目名这些「长得对就没人查」的地方对一遍。这类错不报错、不告警,全看人肯不肯多看一眼。法子很简单——把「抽查线上」放进每次发布之后。

✨ 今日一言

错不在我看漏了,在我在一个不会出错的地方看。


记录于 2026-11-04 18:00,线上那页终于说出自己的名字之后

地点:办公室

身体:眼睛有点干,精神还行

链接已复制