fix(cli): OS_APP_NAME 压过 config.email.defaultTemplateContext.appName —— 恢复「env 逐项覆盖」契约 (#5448) - #5498
Merged
Merged
Conversation
…ppName (#5448) `resolveEmailCapabilityArg` resolved the email template context's `appName` first and then spread the whole `config.email.defaultTemplateContext` OVER it, so a config that spelled `defaultTemplateContext: { appName: 'Acme Dev' }` made `OS_APP_NAME` silently inert — the one exception to the "env overrides per setting" contract this file states and honours for every other key it reads (apiKey, defaultFrom, retries, queueDelivery, persist, SMTP). Resolve `appName` after the spread instead, keeping the context form IN the chain so a config that spells only that form is not demoted to 'ObjectStack': env > config.email.appName > defaultTemplateContext.appName > config.appName > 'ObjectStack'. Every other context key is untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016FNvXhtSdnEGEfLEsMmvxh
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 21 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
baozhoutao
marked this pull request as ready for review
August 5, 2026 14:23
baozhoutao
enabled auto-merge
August 5, 2026 14:23
Contributor
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 31015247561 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 失败的 job(日志抽取,best effort):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
os-zhuang
pushed a commit
that referenced
this pull request
Aug 5, 2026
#5448 已裁 direction B 并由 PR #5498 落地:`resolveEmailCapabilityArg` 现在把 `appName` 放在 context 展开之后解析,五级链为 `OS_APP_NAME` > `config.email.appName` > `defaultTemplateContext.appName` > 顶层 `appName` > `'ObjectStack'`。本分支上写于旧序之上的三处东西随之收口: - `serve-email-config-parity.contract.test.ts` 那条 pin 原本钉的是旧序 (context.appName 压过 env),现改为钉新序。它保留本文件自己的角度而非 重述 #5498 的用例:配置先过真正的 `EmailServiceConfigSchema.parse()` 再喂 读侧,因此钉住的是 #5307 新加的两个契约键既能存活 parse、又确实落在 schema 文案承诺的档位上。 - `email-config.zod.ts` 中 `appName` / `defaultTemplateContext` 的 TSDoc 与 两处 `.describe()`:旧文案写的是「写在 context 里的 appName 压过 appName 键与 OS_APP_NAME、是否合理 filed as #5448」,该事实已不成立。 `email-config.mdx` 由 `gen:docs` 整体重生成(未手改),9 个 generated 门全绿。 运行时零改动 —— `serve.ts` 未被本次改动触碰。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018fxLGQdatPbBUvCgiVxg6D
This was referenced Aug 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #5448
按分诊裁定取方向 B(env 必须赢)。
问题
packages/cli/src/commands/serve.ts的resolveEmailCapabilityArg里,appName先算,defaultTemplateContext再整体展开覆盖在它上面:于是作者只要写了
defaultTemplateContext: { appName: 'Acme Dev' },OS_APP_NAME就静默失效。这是本文件自述契约(EmailServiceConfigSchema头部 TSDoc 与生成的references/system/email-config页:「OS_EMAIL_*环境变量逐项覆盖」)的唯一例外 ——apiKey/defaultFrom/retries/queueDelivery/persist/ SMTP 一族全都照此执行。后果不是排序细节:一份
objectstack.config.ts部署到多环境时,运维手上唯一的按环境覆盖手段什么都没做,生产发出的品牌邮件仍叫仓库里写死的名字;又因为兜底发件人是从同一个值 slug 化来的,信封上也是no-reply@acme-dev.local。全程无报错无日志。改法
appName改为在展开之后解析,链条为:env.OS_APP_NAME>cfgEmail.appName>cfgEmail.defaultTemplateContext.appName>configAppName>'ObjectStack'按 issue 正文的陷阱注记,
defaultTemplateContext.appName显式留在链条里(排在两个专用来源之后、顶层configAppName之前)。若让它直接输给两个专用来源而消失,「只写了 context.appName」的既有配置会被降级到'ObjectStack'—— 拿一个静默错值换一个更糟的。defaultTemplateContext的其它键行为完全不变:它们没有 env 或专用 config 载体,仍整体展开。只有appName一个键特判,PR 里有一条断言专门钉这一点(含一个故意与本 resolver 读的设置同名的 context 键,证明特判恰好一个键宽)。测试
新增
packages/cli/src/commands/serve-email-appname-precedence.test.ts,12 条:五级链条逐级断言(每级单独缺席时下一级接管)、防降级例(含「只写 context.appName 时 env 仍然覆盖」)、兜底发件人 slug 跟随解析后的appName、显式defaultFrom不受影响、其它 context 键不受影响、无 context 时的形状不变,以及两条 in-process 端到端:把 resolver 的真实输出喂给真的EmailServicePlugin,读回活的EmailService手上的defaultTemplateContext——sendTemplate合并的正是这个对象(plugin 侧send-template.test.ts已钉),所以它拿到什么就是运维的邮件渲染出什么。反向验证(方向先判后跑):预判把
serve.ts改回旧展开顺序应恰好红掉 6 条 —— rung 1/2、防降级例、slug 例、其它键例、第一条端到端;其余 6 条(rung 3/4/5、显式defaultFrom、无 context 形状、第二条端到端)的期望值与旧行为一致,应保持绿。实测完全吻合:Tests 6 failed | 6 passed (12),失败集合与预判集合逐条相同。恢复改动后 12/12 绿。pnpm --filter @objectstack/cli test全包 792 passed (81 files);typecheck干净;node scripts/check-nul-bytes.mjsOK。接受的代价(user-visible)
依赖「context 压 env」现状的既有部署行为会变:该环境的邮件正文、主题与派生兜底发件人会开始使用
OS_APP_NAME的值。恢复旧结果的办法是在该环境取消OS_APP_NAME,或把想要的名字写到config.email.appName。changeset 已写明。维护者若不接受此代价,可否决改方向 A(届时只改 TSDoc 标明例外)。与 #5307 的衔接
#5307 仍未合入
main(分支claude/issue-5307-email-config-keys存在,未合并),其serve-email-config-parity.contract.test.ts与钉现状的spreads defaultTemplateContext OVER the resolved appName, as documented一条不在本 PR 切出的 main 上,按裁定不碰其分支。EmailServiceConfigSchema当前也尚未声明appName/defaultTemplateContext,其头部 TSDoc 的 Resolution order 没有提到本例外(那段例外说明本就属于 #5307 的 PR),因此本 PR 无 spec 侧改动、无生成物重生成。留给 #5307 后合时收口:那条 pin 需改为钉新序,新增的键说明按新序写。本 PR 把新序写进了resolveEmailCapabilityArg自身的 TSDoc。未触碰
persist相关行(#5470 刚落地),未触碰OS_APP_NAME命名(PD #9 债务另议)。🤖 Generated with Claude Code
https://claude.ai/code/session_016FNvXhtSdnEGEfLEsMmvxh
Generated by Claude Code