现象
订阅页把频道列为“文章更新 / 项目动态 / 踩坑记录 / 全部内容”,页脚也引导读者“不想用邮箱可以走 RSS”。然而检查 RSS 输出时发现:rss.xml 和 feed.json 的 items 只来自 getPublishedPosts(),完全不含已发布的踩坑——尽管踩坑数量当时已远不止零。一个明确承诺了“多渠道内容”的订阅入口,背后却只有一条内容管道。
根因
这是典型的“多数据源契约漂移”:
rss.xml.ts与feed.json.ts各自独立遍历posts集合(历史原因,文章最早存在);- 订阅频道列表定义在另一处(前端硬编码
channels); - 没有任何机制保证“频道承诺 ⊆ Feed 实际覆盖”。
两边各自演进,契约悄悄错位——单测不会报,页面不会坏,只有用户发现“订阅了踩坑却一条都收不到”。
修复
统一两个 Feed 生成器的数据源为“全部公开内容”:合并 posts + pitfalls,按 updatedAt ?? publishedAt 排序。RSS 条目 <link> 指向 /pitfalls/<slug>,<category> 用标签。修复后条目从 17 增至 22。
教训
- “频道”是一个对用户的承诺,要么 Feed 包含它,要么订阅页删掉它——两者不一致比只做一个更糟。
- 多数据源 Feed 应该由一个共享选择器导出(例如
getPublicFeedEntries()),避免每个协议文件手写一次。 - 契约检查最好变成自动化:订阅页的
channels与 Feed 实际覆盖的类型集合应在构建期做一次一致性扫描(本项目把 Feed 纳入 release-gate 的产物检查项,后续可加这一步断言)。