跳到正文
← 返回博客
BUILD LOG / 构建日志

让错误 Markdown 在发布前失败

从 front matter、策展引用到 featured 数量,记录哪些内容错误已经硬失败,哪些曾经只是静默退化。

一篇正文完整的 Markdown,可能只因为头部写成下面这样,就不应该进入发布集合:

kind: note
accent: green
featured: "yes"

这三个值都能被当成普通文本读出来,却不满足当前博客的数据契约。问题如果一直拖到页面生成以后才暴露,作者看到的往往不是“第几篇文章的哪个字段错了”,而是缺少索引、错误筛选或不完整订阅。

这篇文章只区分三件事:当前已经硬失败的契约、曾经会静默退化的路径,以及仍然需要人工判断的内容质量。

内容链路有四个责任层

Markdown source
→ typed content index
→ repository / curation
→ static pages and feeds

Markdown 是作者维护的事实来源。生成脚本解析元数据和正文,产出类型化文章索引;内容仓库再组织 Start Here、系列、About 代表作、搜索和相关推荐;Next.js 最后生成文章 HTML、元数据、RSS 与 Sitemap。

四层不能维护同一份重复真相:

  • 标题和摘要只写在 Markdown,不在策展配置里复制;
  • 生成索引只由脚本产生,不手工修改;
  • 策展只保存 slug 与顺序;
  • out/ 是构建产物,不是内容源。

这样出现漂移时,才知道应该在哪一层失败。

front matter 已经是硬契约

当前生成器会直接拒绝:

输入问题当前行为
缺少必填字段生成失败并指出文件与字段
未知或重复字段生成失败
非法日期、kind 或 accent生成失败
非布尔 featured生成失败
空 tags 或非法标签值生成失败
非小写 kebab-case 文件名生成失败
重复 slug生成失败

这不是“建议以后严格校验”,而是当前内容生成阶段已经执行的检查。

生成器仍然故意不判断文章观点是否成立、系列是否真正推进同一个问题。这类判断没有稳定的机器 oracle,应该留给编辑审阅。严格 schema 的目标是阻止确定性错误,不是让作者为了过门禁填出形式正确的空话。

一个被 slice 掩盖的策展错误

策展引用已经有明确失败入口。Start Here、About 和系列按 slug 解析文章,目标不存在时会抛错;相关推荐也会排除当前文章本身。

但首页代表作曾经使用另一种行为:

筛选 featured=true
→ slice(0, 3)
→ 渲染首页

如果第四篇文章被标为 featured,页面仍能正常构建,只是多出的代表作被静默截断。这种“看起来没坏”的退化比明确报错更难发现,因为内容源和最终页面都各自像是合理的。

本轮把规则前移到了内容生成阶段:featured 必须恰好为三篇,否则直接失败。首页仍保留容量限制,但它不再承担发现内容错误的职责。

契约当前失败位置还需要什么
front matter 合法内容生成器已实现
策展 slug 存在仓库解析 / 构建已实现
featured 恰好三篇内容生成器与测试本轮补齐
相关推荐不包含自身仓库逻辑与测试已实现
系列是否推进同一问题人工编辑审阅不能只靠代码

这和《一条被 continue 绕过的 Kill 条件检查》是同一种教训:规则写下来了还不够,必须检查它真正位于哪条控制流上。

RSS、Sitemap 与隐私分别能证明什么

当前测试会确认每篇文章进入 RSS 和 Sitemap,About 也出现在 Sitemap 中;公开内容对象还会检查手机号、简历私有字段、内部仓库标识和本地来源路径。

这些测试能够证明被列出的确定性契约,没有证明所有上下文敏感信息都安全。一个看似普通的业务 ID、脱敏不完整的请求样本或能够反推出客户的信息,仍然需要人工审阅。

同样,RSS 项数一致只说明文章集合对齐,不说明摘要写得好;Sitemap 有 URL 也不证明页面中的论点可信。内容基础设施负责“正确发布了哪一批文字”,不能替文章完成事实核查。

静态导出的完成证据

当前发布链按下面的顺序收敛:

generate content
→ lint / typecheck / test
→ static build
→ upload to staging
→ verify per-file hashes
→ atomic directory switch
→ retain rollback copy

这里能够确认的是:构建产物经过文件数、文章数、RSS、Sitemap、隐私模式和 SHA-256 核对,切换前保留完整备份与快速回滚目录。

这不等于已经证明任何条件下都零停机,也不意味着正则扫描能够识别全部隐私风险。部署流程提供的是可重复检查与可回退路径,不是绝对保证。

失败报告应该指向编辑动作

一个对作者有用的内容报告,至少要按层输出:

frontmatter   fields and enums valid
curation      every slug resolved
featured      exactly 3
routes         every article exported
feeds          RSS / Sitemap aligned
privacy        no deterministic hit

每项失败都应指向文章、字段或引用,避免作者在长构建日志里猜原因。当前项目已经分别通过生成器、仓库测试和静态构建覆盖这些层;上下文隐私和系列质量继续由人工负责。

Markdown 写完只是源文件状态。只有它进入正确的类型索引、策展关系、静态页面和发布集合,才完成这次内容变更。