feat(spec)!: 通知模板孤儿语汇退役 —— ./system 不再导出 EmailTemplate/SMSTemplate/PushNotification/InAppNotification (#4616) - #4809
Conversation
…./system (#4616) ADR-0049 enforce-or-remove, resolved by REMOVE in the v17 breaking window. `EmailTemplateSchema`, `SMSTemplateSchema`, `PushNotificationSchema` and `InAppNotificationSchema` (+ their four type aliases) existed ONLY as the member shapes of the `NotificationConfigSchema.template` union that #4610 (#4535 C3) deleted. Since then they have been reachable from no parent schema and from no metadata-type root — declared delivery capability the runtime never read. Three-repo consumer review (objectstack, cloud @ 5df2c69, objectui @ 785b8a5), by bare name rather than by import statement — which is what changed the answer: - SMSTemplate / PushNotification / InAppNotification: zero references outside their own declaration, their own unit tests and the generated artifacts. - EmailTemplateSchema: NOT consumer-free. objectui's metadata-admin registers it as the client-side validator for the `email_template` kind through a DYNAMIC import (app-shell/src/views/metadata-admin/clientValidation.ts:89), which an import-statement scan cannot see. That registration is itself the bug: the canonical schema for the kind is `EmailTemplateDefinitionSchema`, and validating an authored definition against the legacy shape reports its real keys as missing — the same defect spec 7.1.0 fixed on the framework side when it demoted `EmailTemplateSchema` to "an inline sub-shape inside `Notification`". Filed separately; removing the legacy export turns that silent mis-validation into a compile error at the one site that needs it. - ui `NotificationSeveritySchema`: REFUTED. The issue proposed retiring it in the same sweep on the premise that objectui pins only Type/Position/Action. objectui re-exports the type (packages/types), consumes it in core/src/protocols/NotificationProtocol.ts, pins the schema name in packages/types/src/__tests__/spec-ui-schema-reexports.test.ts, and types two severity->tone maps as Record<NotificationSeverityLevel, ...> precisely so a new spec severity fails type-check downstream. It is untouched, and the pin below asserts it stays ./ui-owned so the claim is not re-litigated. Route: whole-def removal (#4650 route 3), not a `retiredKey()` tombstone — a tombstone lives on a surviving schema's shape and none survives here. gen:schema adjudicates the four defs itself ("def no longer emitted by this build; whole-schema removals are adjudicated by json-schema.manifest.json and check:api-surface"), which is why the 22 authorable-surface lines and the 4 manifest keys are deleted in this commit. No ADR-0087 D2 conversion, deliberately: a conversion rewrites authored or stored sources, and no metadata document was ever parsed against these defs, so `os migrate meta` would have nothing to match — same disposition as #4610 in this module, and as #4767/#4783. Also corrects `kernel/metadata-plugin.zod.ts`'s `email_template` comment, which named `EmailTemplateSchema` where the registry resolves `EmailTemplateDefinitionSchema`. That one parenthetical is the documented source of the confusion, including objectui's. The pin is a TypeScript compiler-API test over the package.json exports map (all 16 entries), asserting each removed name has ZERO holders anywhere — not merely that ./system omits it — with anti-vacuity guards on entry resolution and surface size. #4642 established that the conditional-type pin #4610 left here is a no-op (tsconfig excludes **/*.test.ts), so it is folded in rather than left as a gate that cannot fail. Co-Authored-By: Claude <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📓 Docs Drift CheckThis PR changes 1 package(s): 107 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
activationEvents 声明四仓零 reader —— declared-but-unenforced,且 studio 侧 z.string() 零校验
#4657
…rename must not ride out on this branch `git merge origin/main` brought in #4789 (kernel PackageDependencySchema -> ResolvedPackageDependencySchema, dual-source C7), which touches the same three generated artifacts this branch does. The merge reported NO conflicts and left NO conflict markers, and it was wrong in all three: api-surface.json re-added `PackageDependency (type)` + `PackageDependencySchema (const)` and dropped `ResolvedPackageDependency(Schema)` authorable-surface.json re-added the 4 `kernel/PackageDependency:*` lines and dropped the 4 `kernel/ResolvedPackageDependency:*` ones json-schema.manifest.json re-added `kernel/PackageDependency` and dropped `kernel/ResolvedPackageDependency` json-schema.manifest.json is routed to the `merge=os-regen` driver, which defers rather than regenerates, so nothing textual signals this — the C17/C10 silent revert, reproduced. `git merge-tree` does not run external merge drivers and so cannot see it either. Resolved the way #4783 did, without any textual merge: reset all three (plus api-surface-signatures.json) to origin/main, re-applied ONLY this PR's own deletion to the two hand-ratcheted files, then re-ran the generators over the merged source. The 22 authorable-surface lines and 4 manifest keys are once again deliberate deletions, now anchored at merge base ffab803, which gen:schema re-proved under #4650 route 3 ("def no longer emitted by this build"). Delta vs origin/main is now pure deletion in all three, with #4789's rename intact: api-surface.json -8 (4 const + 4 type), 0 insertions authorable-surface.json -22 lines, 0 insertions json-schema.manifest.json -4 keys, 0 insertions check:dual-source-exports reports 0 accepted dual-source (#4789's shrink to [] survives; this branch does not carry it back to 2). renamed-defs.ts is byte-identical to main and keeps all 6 entries including #4789's. Co-Authored-By: Claude <noreply@anthropic.com>
已合入 #4789,三张 ratchet 按 #4783 干净路线重做 —— 静默回退实测复现了,不是理论风险分支已推到 0. 先说结论:你警告的那个形态,这次是实测的,不是推测
三张全部是 #4789 改名成果被整体吞掉。 补一个佐证:按你的路线修完后 commit, 1. 处置:零文本合并
2. 逐条核对读数(你要的四项)①
② 零新增。键存在性抽查: ③
三张表的 numstat,一目了然: ④ 未发生冲突,无需二选一。6 条: 3. 全量复跑(合并后)
4. 期间 main 又前进了两次,都已合入你看到的 tip 是
分支当前 tip 等你 un-draft + 入队。 Generated by Claude Code |
Fixes #4616
ADR-0049 enforce-or-remove,在 v17 破坏窗口内按「移除」处置。
EmailTemplateSchema/SMSTemplateSchema/PushNotificationSchema/InAppNotificationSchema及其四个类型别名,只作为NotificationConfigSchema.template联合的成员形状存在过;#4610(#4535 C3)删掉那个联合之后,它们从任何父 schema、任何 metadata-type 根都不可达 —— 声明了 runtime 从不读取的投递能力。一、消费方复核(三仓):立单前提被证伪了一处半,结论反而更稳
复核方式与立单时不同:按裸名扫描,而不是按 import 语句扫描。这一处差别改变了答案。
仓库版本:objectstack
main、cloud5df2c69、objectui785b8a5。SMSTemplate(Schema)PushNotification(Schema)InAppNotification(Schema)EmailTemplateSchemapackages/app-shell/src/views/metadata-admin/clientValidation.ts:89NotificationSeveritySchema1.1
EmailTemplateSchema有一个消费方 —— 而它本身就是缺陷objectui 的 metadata-admin 客户端草稿校验,把
email_template这个 kind 注册到了被降级的遗留 schema:这是动态 import + 属性访问,立单时的 import 语句级扫描看不见它 —— 这正是 skill §1「build 才是裁判,台账只是输入」那一条要防的形态。
但它不是「保留理由」,恰恰相反:该 kind 的规范 schema 是
EmailTemplateDefinitionSchema(BUILTIN_METADATA_TYPE_SCHEMAS解析的就是它),两者形状不相交(idvsname+locale;body+bodyTypevsbodyHtml/bodyText)。结果是一份合法草稿在 Studio 里被报id/body缺失,而它真正的键因非 strict 被静默剥离。这与 spec 7.1.0 在框架侧修过的是同一个缺陷 —— 当时 changelog 原文说,注册遗留 schema「which is why all the new fields (
name,label,category,locale,bodyHtml,bodyText, …) were reported as 'declared in form layout but missing from schema'」,框架侧改指到了 Definition,objectui 侧从未跟进。按 issue 自己的判据(待决项 2:「若某渠道实现确要用 spec 级模板 shape 校验,应先有消费方 PR 再谈保留」),一个误接的站点不构成消费方。移除是更正确的处置:它把静默错校验变成恰好落在需要修改的那一行上的编译错误。已按 Prime Directive #10 单独立案 #4807(未指派),不在本 PR 内修。
1.2 ui
NotificationSeveritySchema:立单正文的顺带处置建议被证伪issue 说「objectui 只 pin 了 Type/Position/Action 三个枚举」。实查为假,objectui 有四处消费:
packages/types/src/index.tsre-export 该 类型;packages/core/src/protocols/NotificationProtocol.ts消费该类型;packages/types/src/__tests__/spec-ui-schema-reexports.test.tspin 了该 schema 名;packages/components/src/notifications/severity.ts与app-shell/src/chrome/notificationToast.tsx把 severity→tone 映射写成Record<NotificationSeverityLevel, …>,注释明写「so a new severity in the specNotificationSeveritySchemafails type-check here until it has a tone」。它是活的,本 PR 一个字节都不动
packages/spec/src/ui/。 为免下次审计照着 issue 正文再来一遍,pin 测试里加了一条断言:NotificationSeveritySchema/NotificationSeverity必须仍由./ui独占持有(sabotage S3 实测会红,见下)。1.3 短信 / 邮件功能不受影响(维护者质询的复核)
自行 import 级复核确认 PM 结论:
service-messaging/src/sms-channel.ts按(topic, 'sms', locale)读sys_notification_template行,provider 侧是service-sms里阿里云预注册的TemplateCode;邮件走EmailTemplateDefinitionSchema→sys_email_template。三条链路都不经过本 PR 移除的任何 schema。service-messaging/service-sms/plugin-email三个包的测试全绿(见下)。二、退役形态:#4650 路径 3(整 def 消失),不是
retiredKey()墓碑判据不是照搬先例,而是门禁实跑输出。
retiredKey()墓碑必须挂在一个存活的 schema 形状上;这里四个 def 整体消失,没有形状可挂。gen:schema自己给出了裁定:所以
authorable-surface.json的 22 行与json-schema.manifest.json的 4 个键是在本 PR 内刻意删除的(C10/C16/C3 谱系),删除由 #4650 route 3 自证。中途 gate 两次拦下并给出正确路径,都在预期内:先是 manifest ratchet(「4 previously published schema(s) disappeared」),再是 check (a)(「22 authorable key(s) disappeared from the contract」)。三、ADR-0087 conversion:逐条评估后不需要,三种先例对照
os migrate meta有东西可改写computeSurfaceReachability的 BFS 证明了这一点,门禁也据此放行展开:D2 conversion 改写的是作者源或已存
sys_metadata行。没有任何 metadata 文档曾按这四个 def 解析过,所以os migrate meta无匹配目标,注册一条只会得到一个永远不触发的 walker 和一个必须与全表 disjoint 的 fixture。D3semantic[]是给「响应面上、无源可改写」的 key 用的(EnhancedApiError.fieldErrors是范例),这四个也从不在响应面上。#4610 在同一个文件做同样的事时同样未注册 conversion。破坏面因此纯粹是 TypeScript 导出面:changeset 承载 FROM → TO,
api-surface.json承载机器可读的删除记录。四、changeset 定级:
major(据 #4535 §5 逐条自证,不照抄别簇)@objectstack/spec/system取这八个名字的消费方编译失败;objectuiclientValidation.ts:89就是一个现存实例。NotificationChannelSchema逐字节未变。→
@objectstack/spec: major。changeset 逐个给出 FROM → TO,并明写EmailTemplateDefinitionSchema是形状变更而非改名(键名映射列了表),以及另外三个「无替代品、也不需要替代品」各自的真实机制。五、pin:TypeScript compiler API 符号身份解析 + 4 组 sabotage 实跑
pin 写在
packages/spec/src/system/notification.test.ts:package.json的exports读出全部 16 个 TS 入口,新增入口无法悄悄逃逸;././system/./ui/./contracts/./api;入口数 > 10;每个 module symbol 必须解析成功;./system> 400、./ui> 200、./contracts> 100 个导出;holdersOf(name)恒等于[](而非「./system不含它」),所以从任何别的入口顶名 re-export 同样会红;存活侧则断言精确持有者集合与声明出处(NotificationChannel=['./contracts','./system']且两者共享同一声明)。顺带把 #4610 留下的
typeof import条件类型 pin 折叠进来 —— #4642 已确认那种 pin 在本包是空转(tsconfig.jsonexclude 了**/*.test.ts,vitest 从不开typecheck),留着是一个不可能失败的门禁。sabotage 实跑证据
notification.zod.ts复活SMSTemplateSchema声明AssertionError: SMSTemplateSchema must not be exported by any entry point: expected [ { sub: './system', …(1) } ] to deeply equal [](compiler-API + runtime 两条都红)./contracts顶名导出EmailTemplateSchema(./system仍不导出)AssertionError: EmailTemplateSchema must not be exported by any entry point: expected [ { sub: './contracts', …(1) } ] to deeply equal []—— 注意 runtime 那条保持绿(它只探./system/./ui),正好证明 compiler-API pin 才是这条路线上承重的那个NotificationSeveritySchemaAssertionError: NotificationSeveritySchema is LIVE in objectui — must stay ./ui-owned: expected [] to deeply equal [ './ui' ]./systembarrel 清空AssertionError: ./system must export a non-trivial surface: expected 0 to be greater than 400—— 在任何not.toContain之前就拦下,证明断言不会因解析失败而空过四次 sabotage 后全部还原,工作树干净。
六、顺带修正的混淆源头
packages/spec/src/kernel/metadata-plugin.zod.ts:116原本写着'email_template', // Outbound email templates (EmailTemplateSchema)—— 括号里指错了声明(注册表解析的是EmailTemplateDefinitionSchema)。这一条括号正是维护者本次质疑、以及 objectui 误接的共同源头,改正并留了说明。同时在notification.zod.ts留下按渠道展开的「真正在投递的是什么」注释块,免得下一位读者再推导一遍。七、验证(全部实跑)
check:generatedcheck:authorable-surfacecheck:api-surface./system精确 −8 行:4 const + 4 type,零新增)check:dual-source-exportscheck:liveness/check:empty-state/check:variant-docs/check:strictness-ledger/check:exported-any/check:react-declaration-parity/check:skill-examplessystem/不在 strictness ledger 的 5 个受治理目录内,故无台账行需要改;ui 侧未触碰,ui/的 198 计数不变)pnpm --filter @objectstack/spec testpnpm --filter @objectstack/spec typecheckpnpm typecheckpnpm buildpnpm check:i18nextract failed是 stale-dist 陷阱,全仓 build 后转绿service-sms28、service-messaging160、plugin-email76,全通过content/docs/releases/未触碰。content/docs/references/system/notification.mdx由gen:docs重生成(自动生成物)。八、合并前状态
已
git merge origin/main(⛔ 未 rebase、未 force-push)。进来的 3 个提交(#4799 / #4798 / #4794)完全不触碰packages/spec,四张 ratchet 也都没动;合并后重跑 spec build +check:generated(8/8)+ 源码审计组 + spec test/typecheck,全绿。相对origin/main的 ratchet delta 精确为本 PR 的一处改动:入队请排在 C7 #4789 之后(文件不相交,可并行实施,但按 PM 指定的顺序落地)。draft / ready 与合并归 PM,本 PR 不 auto-merge。
九、范围外发现
email_template草稿。含 repro、形状对照表、一行修复与「为何 v17 前修掉即可」的时序说明。Generated by Claude Code