Skip to content

docs: config-resolution 示例给出并不存在的 email provider(console / mailhog)与 fromAddress 键 #5105

Closed

Description

@os-zhuang

在做 #5087 时路过发现,与该 issue 无关,单独记录。

现状

content/docs/protocol/kernel/config-resolution.mdx(「Example 3: Development Overrides」,约 802-827 行)的示例写着:

  • email: { provider: 'sendgrid', fromAddress: 'noreply@company.com' }
  • 开发覆盖:email: { provider: 'console' }
  • 以及 OS_EMAIL_PROVIDER=mailhog

这三处都不对应任何真实配置面:

影响(观察类)

纯文档面。这一页讲的是配置层叠机制,示例只是载体,今天不会有人因为它而线上出故障;但复制粘贴的作者(尤其 AI 作者)会得到一份跑不起来的 email 配置,而错误要到运行时才出现。按 Prime Directive #10「never advertise a capability the runtime doesn't deliver」记录。

建议

把示例换成真实存在的键与取值(例如生产 provider: 'resend' + defaultFrom,开发覆盖 provider: 'log',env 覆盖 OS_EMAIL_PROVIDER=log),或改用与 email 无关的、机制上等价的示例。属纯文档 PR,不要挂在代码 PR 上。

Activity

  1. self-assigned this
    on Aug 4, 2026
  2. os-zhuang commented on Aug 4, 2026

    @os-zhuang
    ContributorAuthor

    认领:PM 循环第 2 轮(邮件线专项)
    会话:session_017MCKJaEomEqg4tvz4SzdNd
    分支:claude/issue-5105-config-resolution-email-example
    Worktree:objectstack-issue-5105
    域:domain:devx(落地 content/docs/**)
    文件面:content/docs/protocol/kernel/config-resolution.mdx(单文件;越界即停,报告说明)

    分诊:由 finding 晋级为可派发。理由是它虽属观察类(纯文档、今天不会导致线上故障),但正好落在本轮邮件线的作用面上,而且性质是 Prime Directive #10 的「advertise a capability the runtime doesn't deliver」——示例里的 provider: 'console' / OS_EMAIL_PROVIDER=mailhog / fromAddress 三处都不对应任何真实配置面,复制粘贴的作者(尤其 AI 作者)会得到一份运行时才报错的配置。晋级而非继续持有,是因为修法明确、单文件、与在飞的任何单都不撞。

    与 #5087 的时序:不设 Blocked-by。示例应当换成今天就成立的取值(resend + defaultFrom,开发覆盖 log),不要写 smtp——那要等 #5104 把 smtp 加进 EmailProviderSchema 之后才是真的。这样本单与 #5087 / #5104 三者互不阻塞。


    Generated by Claude Code

  3. os-zhuang commented on Aug 4, 2026

    @os-zhuang
    ContributorAuthor

    复核结论:ACCEPT —— PR #5113,转 ready 并入合并队列。

    CI 在 head 1674f72b 上 19 个 check run 全部 success 或 skipped,无失败。

    复核的核心不是「改了没有」,而是示例现在是不是真的,所以逐条对着 origin/main 的 packages/spec/src/system/email-config.zod.ts 核了:

    • EmailAddressConfigSchema 确为 { name?: string, address: string().email() } —— 示例写的 defaultFrom: { name: 'Acme', address: 'noreply@company.com' } 形状完全对上,原来那个 fromAddress 字符串键确实不存在;
    • apiKey、defaultFrom、retries 都是 EmailServiceConfigSchema 的真实键;
    • EmailProviderSchema 仍是 z.enum(['log','resend','postmark']) —— 示例选的 resend 在枚举内,而 sendgrid / console / mailhog 一个都不在。

    两处超出「逐字替换」的改动我都认可:

    1. 生产段补上 apiKey。这是 dev 自己加的判断,是对的:非 log 的 provider 缺 key 时 serve.ts 会 warning 并回落 LogTransport,示例不写它等于示范一份「看着配好了、其实没发出去」的配置——正是本单要消灭的那个形态换个方向再犯。
    2. env 层补 OS_EMAIL_FROM。派发词要求「取值修对了但不能把层叠机制讲丢」,而开发段已经选了 log,env 若只写 OS_EMAIL_PROVIDER=log 这一层就退化成无效果示例。改用本页 §Merge Strategies 自己教的「对象深合并、原始值替换」补全语义,层叠要点比改之前更完整。

    刻意没写 smtp —— 这是派发时明确要求的:EmailProviderSchema 现在仍是三值枚举,加 smtp 是 #5104 的活、尚未落地,此刻写进文档就是把本单刚修掉的 declared ≠ implemented 重新引入一遍。#5104 落地后这一页要不要提 SMTP,归那一单自己判断。

    未加 {/* os:check */} 的理由也成立:该代码块把 shell 赋值行混在 typescript 围栏里,本就不可编译,加标记只会让 check:skill-examples 变红;让它可编译需要重写整块,超出本单范围。


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions