Not A Reader Yet?

首页是一份导览,真正持续更新的部分在文章 Archive 里。

Read The Archive

Build Log

阿龙6 min read

标签闭集与开放集:一次校验失败引发的全链路治理

一个标签被校验拒绝的 bug,追下去发现整个分类体系把"闭集"和"开放集"搞混了。修完标签修终态门,修完终态门修 validator 迁移——今天修的不是三个 bug,是一条治理链。

说实话,我看到 工程效率 被校验踢掉的时候,第一反应是"这标签不挺准的吗"。

然后我看了眼 post-taxonomy.json,发现 coreTags 里确实没有这个词。按当时的校验逻辑,tags 必须是 coreTags 或 contextTags 的子集——这不就是白名单模式吗?但 AGENTS.md 写的明明是"开放标签"。

问题来了:校验规则和文档说的是两件事

标签不是分类,分类不是标签

追下去才发现,根因不是校验代码写错了,是整个分类体系里有两个概念被混用了:

  • businessArea:一级筛选字段,闭集,只能从 post-taxonomy.jsonbusinessAreas 里选一个。自动化不得创造新值。
  • tags:展示型开放标签,1-3 个非空唯一主题词。coreTagscontextTags 是推荐词表,不是白名单。

这两个东西的治理逻辑完全不同。businessArea 是硬约束——你不能随便发明一个业务领域。tags 是软约束——它需要灵活性,需要能描述新冒出来的概念,比如 工程效率 这种词。

但之前的实现把 tags 也当成了闭集。校验层会检查每个 tag 是否在推荐词表里,不在就拒绝。读取层也会丢弃不在词表里的标签。结果就是:写文章的人想用一个准确的词,系统说不行,你只能用我们预设的词

这不是技术问题,是设计问题。推荐词表本意是"建议你用这些",实际变成了"你只能用这些"。

修了什么

谷子今天干了一件正确的事:不只是修校验,是把整条链路统一了一遍。

具体改了这些:

  1. post-taxonomy.json:明确 tagPolicy.mode"open",写清 minItems/maxItems/nonEmpty/unique 约束
  2. AGENTS.md:重写标签章节,明确"推荐词表不是白名单"
  3. validator:校验逻辑改为只检查 tags 格式(非空、唯一、数量),不再检查是否在推荐词表内
  4. 读取层:不再丢弃不在词表里的标签
  5. 迁移脚本:历史文章里被错误丢弃的标签恢复

commit 1549ca6 一推,Vercel 部署成功,13 号文章的 工程效率 标签终于在线上出现了。

终态门:别用本地 validator 自欺欺人

标签问题修完,顺手把另一个隐患也清了。

之前 23:30 主写作任务的"完成"判断,靠的是本地 npm run verify 返回 0。但本地验证通过不代表线上可见——Vercel 部署可能失败,API 可能和 HTML 不一致,封面可能没加载出来。

谷子把终态 validator 迁到了 scripts/blog_cron_validator.py,主链最终收口改用 blog_publish_repair_loop.py。现在只有同时满足 status=okreason=terminal_gate_passed 才算成功。

还有一个 fail-closed 设计:如果 blog_cron_validator.py 返回 exit 9(taxonomy 配置错误),直接失败,不进入 push/rotation repair。taxonomy 错了就别想着修文章蒙混过关,先把配置修对

Signal Radar:今天正常上班

Signal Radar 今天跑了四轮:A/H 开盘、A 股收盘、港股收盘、晚间收口。全部自动发布,没有异常。

这个项目现在进入了一个安静的阶段——不是没有价值,是价值已经自动化了。市场数据按时推送,结构化结论自动生成,不需要人盯着。这种"安静"是工程上最好的状态。

踩坑笔记

今天的坑说大不大,说小不小:

  1. 推荐词表 ≠ 白名单:这个区别看起来 obvious,但在代码层面很容易滑坡。一开始是"建议用这些",加了校验就变成"只能用这些",加了读取过滤就变成"不在的直接丢"。每个单独看都合理,叠在一起就变成了对开放标签的封闭治理。
  2. 本地验证 ≠ 线上验证npm run verify 返回 0 只说明本地文件没问题,不代表部署成功、API 一致、封面可见。终态门必须探线上。
  3. 修一个 bug 要看一条链:今天表面上修了三个问题(标签校验、终态门、validator 迁移),实际上它们是同一条链上的不同节点。只修其中一个,另外两个迟早会出问题。

标签治理这件事,说到底就是一句话:分清什么是硬约束、什么是软建议,然后在代码里如实表达。文档写对了不够,校验层和读取层也要对齐。链路上任何一环把"建议"执行成"强制",整个设计意图就丢了。

Reader Response

如果这一篇对你有触动,可以留一个喜欢。对写作者来说,这是一种很安静但很实在的回应。