test(service-sms): sms settings provider 表 ↔ transports 双向契约测试 (#5773) - #5982
Merged
Merged
Conversation
mail 侧自 #5094 起有一道可执行的闸门把 `mail.manifest.ts` 的 provider 取值与 `EMAIL_TRANSPORT_PROVIDERS` / `makeTransport` 双向锁死;sms 侧一直只是两份独立 维护的字面量「恰好一致」,任一方向漂移都不会有任何东西报警。 PR #5771(#5713)把 sms transports 的词表提成具名导出 `SMS_TRANSPORT_PROVIDERS` 后,原料齐备,本次补上对应的契约测试: - 新增 `packages/services/service-sms/src/sms-manifest-providers.contract.test.ts` —— 两个方向各自独立成 `it`(⊆ 提供了没有 transport 的选项 / ⊇ 有 transport 却 选不到),断言信息点名漂移的具体取值;再叠一层可构建性比对(每个选项都要 `makeSmsTransport` 出正确的 transport 类)以及 `isSmsTransportProvider` 与下拉框 同词表。 - 落点按依赖图判定:测试住 transport owner(`service-sms`),`service-settings` 作 devDependency —— 与 mail 先例(`plugin-email` 持测试)同向,两个方向均不成环。 - `sms.manifest.ts` 的 provider 表处加「a CONTRACT, not a menu of aspirations」注释, 指向这道测试。 - `check-type-check-coverage.mjs` 的 service-sms TEST_DEBT 条目 tests 3 → 4(实测: 解除 exclusion 后错误数仍是 1,新文件本身零类型错误)。 无运行时行为变更,不写 changeset。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015a5qkLzpGXhLL2F5gvJ7dD
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 2 package(s): 8 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
hotlong
marked this pull request as ready for review
August 6, 2026 14:05
This was referenced Aug 6, 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 #5773
mail 侧自 #5094 起有一道可执行的闸门,把
mail.manifest.ts的 provider 取值与EMAIL_TRANSPORT_PROVIDERS/makeTransport双向锁死;sms 侧一直只是两份独立维护的字面量「恰好一致」,任一方向漂移都不会有任何东西报警。PR #5771(#5713)把 sms transports 的词表提成具名导出SMS_TRANSPORT_PROVIDERS之后,写这道测试的原料齐备,本 PR 补上。前提复核(实施前,基于 origin/main
5582e18)正文四条事实全部成立,无一失效:
SMS_TRANSPORT_PROVIDERS = ['log','aliyun','twilio'] as const在transports/index.ts:27,isSmsTransportProvider()在 :38,均经service-sms/src/index.ts:13-14出包;SmsProviderTag由数组派生。sms.manifest.ts的providerselect 仍是三项字面量,未变。sms.manifest.test.ts仍只断言 schema / 权限 / 两个密钥字段,无任何取值集合比对。grep smsSettingsManifest全仓命中只在service-settings包内部,transport 侧无消费者。落点判定(正文列的第一步待决项)
实测两个方向都不成环,所以这不是被依赖图逼出来的选择,而是架构选择:
service-settingsservice-sms选了「测试住
service-sms(transport owner),service-settings作 devDependency」,与 mail 先例同向(plugin-email持mail-manifest-providers.contract.test.ts,service-settings是它的 devDependency,test-only 无运行时边)。理由:service-settings是与具体 provider 无关的 manifest 注册表,它为 mail / sms / storage… 各发一张表;若让它反向 import 每一个 provider 实现,每加一张表就多一条边,注册表逐步变成所有实现的汇聚点。由 provider 自证它满足已发布的契约,箭头才只有一个方向。一条不构成区分度、但值得写明的事实:两侧今天都不会对这个测试文件做类型检查 ——
service-sms有typecheck脚本但 tsconfig 排除了**/*.test.ts(TEST_DEBT 在册),service-settings则根本没有typecheck脚本(DEBT 在册)。所以此项不参与落点判定,由上面的分层理由定。测试内容(两层比对,照 mail 先例)
第一层 —— 集合等价,两个方向各自独立成
it(正文要求「各自变红」),断言信息点名漂移的取值:offers no provider the transports cannot build (⊆)—— 提供了却没有 transport(plugin-email: SendGrid / Amazon SES 设置项同样后端无实现 —— #5087 的同形缺口 #5094 的sendgrid/ses形状)hides no provider the transports can build (⊇)—— 有 transport 却选不到(plugin-email: SendGrid / Amazon SES 设置项同样后端无实现 —— #5087 的同形缺口 #5094 的resend形状)lists each provider exactly once—— 集合等价看不见重复项第二层 —— 可构建性:每个下拉项都要
makeSmsTransport出正确的 transport 类(不是「没抛异常」);再加isSmsTransportProvider与下拉框同词表(#5713 的 CLI 启动期拒收判据必须与 settings 面同一份词表),以及默认值log既在表内又可构建。反向验证(方向先预测,含一次预测落空)
三个探针,每次改完重新 build
service-settings再跑(测试读的是构建产物):sendgrid_sms["sendgrid_sms"]、无 build recipe、predicate 拒收twilio选项twiliotwilio探针 B 首轮预测落空,而且落空是有价值的:多出来的第二条红来自我原先照抄 mail 先例写的三行
expect(byProvider.twilio).toBeInstanceOf(TwilioSmsTransport)—— 那三行把词表在本文件里又抄了第三遍,而这正是本测试存在的理由(「一份字面量可以靠改另一份字面量来『修好』」)。它的副作用是双向的:删一项时重复报红,加一项时反而静默不覆盖(新 provider 没有对应断言行也不会红)。改法:把 build 参数与期望类合并成
PROVIDER_FIXTURES表,并加一条exercises every provider in the vocabulary断言表的键集 ≡SMS_TRANSPORT_PROVIDERS。改完后 B 恰好 1 红(⊇ 点名["twilio"]),A 仍 3 红,C 变成 3 红(新增的 fixture 覆盖断言接住了「加了 provider 没加 fixture」)。该断言刻意写成运行时断言而非
Record< SmsProviderTag, … >类型层穷尽:本包 tsconfig 排除自己的测试文件,类型层写在这里没有任何 tsc program 会求值 —— 就是 #5286 的 phantom check 形状,删掉它每道闸门照样绿。其余改动
sms.manifest.tsprovider 表处加注释(「a CONTRACT, not a menu of aspirations」形),指名执行它的测试文件路径与两个方向。scripts/check-type-check-coverage.mjs的 service-sms TEST_DEBT:tests: 3 → 4。实测(临时解除 exclusion 跑tsc --noEmit)错误数仍是 1(transports.test.ts那条既有 TS2493),新文件本身零类型错误 —— 数在动、错误没动,note 里写明了。验证
逐条枚举
.github/workflows/lint.yml,凡 diff 可能触及的全跑(容器级验证锁 + heap 上限 +--filter范围化):lint/check:nul-bytes/check:type-check-coverage/check:published-files/check:engine-double-contract/check:startup-registry-verdict/check:durability-log-level/check:service-providers/check:adr-anchors/check:doc-authoring/check:i18n/check:i18n-coverage全绿;service-sms+clitypecheck 绿;service-settings15 文件 243 测试、service-sms4 文件 39 测试全绿。(
check:i18n/check:i18n-coverage首轮红是新 worktree 的前置未满足 —— 未构建 CLI、未全量 build,AGENTS.md §9 那一类;补上turbo run build后两者均绿,与本 diff 无关。)⛔ 无 changeset
最终 diff = 新测试 + 一段源码注释 + 一条 devDependency + lockfile + 一个 ledger 计数,不含任何运行时行为变化,按 issue 要求不写空 changeset。已自行打
skip-changeset标签。Generated by Claude Code