Skip to content

feat(spec)!: 双源 C3 收敛 — 通知语汇归 ./api,./ui 与 ./system 侧死删 (#4610) - #4638

Merged
os-zhuang merged 3 commits into
mainfrom
claude/issue-4610-notification-dual-source
Aug 2, 2026
Merged

feat(spec)!: 双源 C3 收敛 — 通知语汇归 ./api,./ui 与 ./system 侧死删 (#4610)#4638
os-zhuang merged 3 commits into
mainfrom
claude/issue-4610-notification-dual-source

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes#4610

#4535 C 组第三簇。两对同名跨入口分叉,同属通知语汇,一个 PR 处理;dual-source-exports.baseline.json 恰好 28 → 24

判源(三仓 import 语句级扫描:framework + cloud + objectui)

Notification / NotificationSchema(./api./ui)

  • ./ui 侧是 toast/横幅的「通知实例」形状(type/severity/message/duration/actions/position + ARIA),三仓 零 import 站点 —— objectui 的 toaster 从未采用它。
  • ./api 侧是活合同:REST 收件箱行(id/type/title/body/read/data/actionUrl/createdAt),嵌在 ListNotificationsResponseSchema 中,由 /api/v1/notifications 提供、@objectstack/client 实现、contractsInboxNotification 镜像(ADR-0030:铃铛读的就是这个形状)。
  • ./ui 侧死删,./api 成为裸名唯一属主。

NotificationConfig / NotificationConfigSchema(./system./ui)

  • 两侧都是三仓零 import、且未接入任何父 schema。./system 侧那套「统一通知管理协议」(channel + template + recipients + schedule + retryPolicy + tracking)早于 ADR-0030 采纳的投递架构,且宣称了运行时并不兑现的能力(channel 枚举里 push/slack/teams/webhook 死信,Audit: several event/subscription/connector enums are schema-only (declared, no runtime consumer) #3197;schedule/retryPolicy/tracking 无人读取)。./ui 侧是 toaster 全局配置,objectui 从未采用。
  • 两侧都死删,裸名整个退出 spec 导出面。

保留不动

  • ./apiNotification(Schema)NotificationPreferences(Schema):未改,从 ./api 导入的消费者无需迁移。
  • ./ui 的呈现语汇枚举:NotificationTypeSchema / NotificationSeveritySchema / NotificationPositionSchema / NotificationActionSchema(及类型)原样保留。
  • ./systemNotificationChannel(Schema) / EmailTemplate(Schema) / SMSTemplate(Schema) / PushNotification(Schema) / InAppNotification(Schema):未改。

迁移指引(含「api 行是收件箱记录、不是呈现配置」的形状变化提醒、以及 NotificationConfig 的替代路径 —— INotificationService.emitnotify 流程节点 NotifyConfigSchemasys_notification* 平台对象、NotificationPreferences)写在 changeset 里。

验证(本地全绿)

结果
pnpm --filter @objectstack/spec build
check:dual-source-exports✅ 基线 28 → 24(4 行 Notification* 全清)
check:generated✅ 8/8 生成物最新
spec 单测✅ 290 文件 / 7261 用例
全仓 typecheck✅ 122/122

已预合 origin/main 并在合并后重跑上述全部门禁(AGENTS.md §10)。未触碰 content/docs/references/** 以外的文档;content/docs/releases/ 零改动(release notes 走 changeset 中央编译)。


Generated by Claude Code

…Notification(Config) removed, ./system NotificationConfig removed, ./api keeps the bare names (#4610)
The four #4535-C3 baseline rows were the #4411 trap on the notification
vocabulary: Notification(Schema) had a second declaration in ./ui diverging
from ./api, and NotificationConfig(Schema) had two declarations (./system vs
./ui) that shared nothing but the name.
Import-statement-level scan across framework, cloud and objectui:
- ./api Notification(Schema) is the live REST inbox-row contract: embedded in
ListNotificationsResponseSchema, part of NotificationProtocol, implemented
by @objectstack/client, served by the runtime notifications domain, and
mirrored by contracts' InboxNotification (ADR-0030: the bell reads this
shape).
- ./ui Notification(Schema) — a toast/banner instance shape — had zero
importers outside its own unit test; objectui pins only the presentation
enums (NotificationType/Position/ActionSchema), which stay.
- ./system NotificationConfig(Schema) — a channel+template+recipients+
schedule+retryPolicy+tracking wrapper — had zero importers, is wired into
no parent schema, predates ADR-0030's accepted delivery model
(NotificationService.emit / NotifyConfigSchema / sys_* objects), and
advertised unenforced capability (#3197 dead-letter channels).
- ./ui NotificationConfig(Schema) — a toaster global config — had zero
importers.
Disposal (route 1, dead-side delete, v17 major window): the ./ui pair and
BOTH NotificationConfig declarations removed; ./api is the sole owner of the
bare Notification(Schema) names and NotificationConfig left the export
surface entirely. Compile-time pins (typeof import conditional type, #4581
pattern) keep the bare names out of ./ui and ./system; the surviving ./api
declaration is already covered by api/protocol.test.ts.
dual-source-exports.baseline.json: exactly the 4 named rows removed
(28 -> 24). json-schema.manifest: system/NotificationConfig, ui/Notification
and ui/NotificationConfig retired deliberately; their 25 authorable-surface
rows hand-deleted per the #4458/#4568/#4581/#4603 precedent. api-surface +
reference docs regenerated via check:generated --fix (2 proved stale; the
api/notification.mdx page folds into api/protocol.mdx where the declaration
lives). docs-import-surface baseline (#4595): untouched. Changeset:
@objectstack/spec major with FROM -> TO migration lines.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M9uWvoEp9CoLzYjNExj9sL
@vercel

vercelBot commented Aug 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 2, 2026 12:45pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec.

107 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx(via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx(via @objectstack/spec)
  • content/docs/ai/skills.mdx(via @objectstack/spec)
  • content/docs/api/client-sdk.mdx(via @objectstack/spec)
  • content/docs/api/environment-routing.mdx(via @objectstack/spec)
  • content/docs/api/error-catalog.mdx(via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx(via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx(via @objectstack/spec)
  • content/docs/api/index.mdx(via @objectstack/spec)
  • content/docs/automation/approvals.mdx(via @objectstack/spec)
  • content/docs/automation/connectors.mdx(via @objectstack/spec)
  • content/docs/automation/flows.mdx(via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx(via packages/spec)
  • content/docs/automation/hooks.mdx(via @objectstack/spec)
  • content/docs/automation/index.mdx(via @objectstack/spec)
  • content/docs/automation/webhooks.mdx(via @objectstack/spec)
  • content/docs/automation/workflows.mdx(via @objectstack/spec)
  • content/docs/concepts/architecture.mdx(via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx(via packages/spec)
  • content/docs/concepts/index.mdx(via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx(via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx(via packages/spec)
  • content/docs/concepts/north-star.mdx(via packages/spec)
  • content/docs/data-modeling/analytics.mdx(via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx(via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx(via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx(via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx(via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx(via @objectstack/spec)
  • content/docs/data-modeling/index.mdx(via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx(via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx(via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx(via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx(via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx(via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx(via @objectstack/spec)
  • content/docs/deployment/cli.mdx(via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx(via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx(via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx(via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx(via @objectstack/spec)
  • content/docs/getting-started/examples.mdx(via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx(via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx(via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx(via @objectstack/spec)
  • content/docs/kernel/cluster.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx(via packages/spec)
  • content/docs/kernel/index.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx(via packages/spec)
  • content/docs/kernel/services-checklist.mdx(via @objectstack/spec)
  • content/docs/kernel/services.mdx(via @objectstack/spec)
  • content/docs/permissions/authorization.mdx(via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx(via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx(via @objectstack/spec)
  • content/docs/permissions/positions.mdx(via @objectstack/spec)
  • content/docs/permissions/rls.mdx(via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx(via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx(via @objectstack/spec)
  • content/docs/plugins/development.mdx(via @objectstack/spec)
  • content/docs/plugins/index.mdx(via @objectstack/spec)
  • content/docs/plugins/packages.mdx(via @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx(via @objectstack/spec)
  • content/docs/protocol/diagram.mdx(via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/runtime-capabilities.mdx(via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx(via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx(via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx(via @objectstack/spec)
  • content/docs/releases/index.mdx(via @objectstack/spec)
  • content/docs/releases/v12.mdx(via @objectstack/spec)
  • content/docs/releases/v13.mdx(via @objectstack/spec)
  • content/docs/releases/v16.mdx(via @objectstack/spec)
  • content/docs/releases/v17.mdx(via @objectstack/spec)
  • content/docs/releases/v9.mdx(via @objectstack/spec)
  • content/docs/ui/actions.mdx(via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx(via @objectstack/spec)
  • content/docs/ui/dashboards.mdx(via @objectstack/spec)
  • content/docs/ui/forms.mdx(via @objectstack/spec)
  • content/docs/ui/index.mdx(via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx(via @objectstack/spec)
  • content/docs/ui/setup-app.mdx(via @objectstack/spec)
  • content/docs/ui/translations.mdx(via @objectstack/spec)
  • content/docs/ui/views.mdx(via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang enabled auto-merge August 2, 2026 12:41
删除 ./ui 的 Notification / NotificationConfig 两个形状后,台账里
`notification.zod.ts` 那行声明的站点数过期(gate 点名 ledger:454:
declares 3 site(s), found 1)。把它从「3 ea」的合并行拆出单列为 1,
并写明为何掉了两个站点;`ui/` 章节总计 200 → 198 相应收敛。
check:strictness-ledger 恢复绿(67 文件 / 5 目录,站点数与章节总计均衡);
同 job 的其余源码审计(liveness / empty-state / variant-docs /
exported-any / react-declaration-parity / skill-examples)一并复跑通过。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M9uWvoEp9CoLzYjNExj9sL
@os-zhuang
os-zhuang added this pull request to the merge queueAug 2, 2026
Merged via the queue into main with commit 0a936eaAug 2, 2026
22 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-4610-notification-dual-source branch August 2, 2026 13:07
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Aug 3, 2026
…i#4641) (objectstack-ai#4643)
`Session` / `SessionSchema` 各有两处声明,一处在 `api/auth.zod.ts`,一处在
`identity/identity.zod.ts`。消费者拿到哪个形状只取决于 import 路径(objectstack-ai#4411
陷阱),而两者连字段名都不一致 —— 写错的表现是运行时 `undefined`,不是类型
错误。
三仓(framework / cloud / objectui)import 语句级扫描:
- `./api` 侧是活的:形状 `{ id, expiresAt, token?, ipAddress?, userAgent?,
userId }`,被接进 `SessionResponseSchema` —— `AuthEndpointPaths.getSession`
(`/get-session`、`/me`、`/refresh`)的响应体,是真正的 runtime 读取点。
- `./identity` 侧零消费方:形状 `{ id, sessionToken, userId,
activeOrganizationId?, expires, createdAt, updatedAt, ipAddress?, userAgent?,
fingerprint? }`,除自身单测外无任何 importer,未接进任何父 schema。它还偏离
了自己声称描述的那张表 —— **被强制执行**的会话记录是 platform-objects 的
`sys_session` 对象,列名是 `token` / `expires_at`(与 `./api` 一致,而非
`./identity`),且根本没有 `fingerprint`。cloud 侧读 `activeOrganizationId`
走 better-auth 自己的类型,不经 spec。
处置(路线一,死删无消费方一侧,v17 major 窗口):`./identity` 的
`SessionSchema` 与 `Session` 移除,`./api` 成为裸名唯一所有者。
dual-source-exports.baseline.json 恰好删掉指名的 2 行(24 -> 22)。
回归 pin 用**运行时**断言而非 C1/C3 的编译期条件类型 —— 后者在这里是空转:
`packages/spec/tsconfig.json` 排除了 `**/*.test.ts`,vitest 也不做类型检查,
所以那类 pin 不可能失败(已另立 objectstack-ai#4642 记录,影响 objectstack-ai#4581/objectstack-ai#4638 已落地的 pin)。
本 PR 的断言经过 sabotage 验证:把声明加回去,测试立刻红。
连带更新:json-schema.manifest 去掉 identity/Session;authorable-surface 去掉
该 schema 的 10 个 key(整形状移除,同 objectstack-ai#4638 先例);api-surface 重新生成。
reference docs 跟着声明走 —— `Session` 现在文档化在 `references/api/auth`
(真正声明它的模块)上,名字碰撞产生的 `references/api/identity` 页随之消失。
严格性台账 `identity/` 粗粒度行 34 -> 33 并写明掉站点的原因。
docs-import-surface 基线未触发。
Claude-Session: https://claude.ai/code/session_01M9uWvoEp9CoLzYjNExj9sL
Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Aug 3, 2026
…elves (objectstack-ai#4650) (objectstack-ai#4726)
Check (a) reads authorable-surface.json from the commit under check, so
hand-deleting a baseline line deleted the evidence it runs on (objectstack-ai#4638,
objectstack-ai#4643 landed exactly that way; objectstack-ai#4662 proved the file was hand-edited).
gen:schema / check:authorable-surface now add check (c): every key
present at the merge base with origin/main but absent from this build
must carry one of three in-gate proofs —
1. aged-out tombstone: base entry [RETIRED] + an ADR-0087
conversion/migration registered >= 2 majors ago;
2. def not reachable from the metadata-type roots (2026-08-02 ruling):
BFS over the build's in-memory Zod graph from
BUILTIN_METADATA_TYPE_SCHEMAS + EXTRA_METADATA_TYPE_SCHEMAS, with
derived-clone bridging so .refine()/.extend() copies keep their
originals protected; waives ONLY this file's tombstone requirement;
3. whole def no longer emitted (manifest ratchet / api-surface
jurisdiction).
Anchoring on the merge base (not HEAD) keeps the check alive in CI,
where HEAD is the PR's own commit and a HEAD-relative diff is always
empty. --check further rejects any byte of the file that is not the
generator's output (objectstack-ai#4662 description drift class); write mode
regenerates it. Checks (a0)/(a)/(b) unchanged and pinned by tests.
Fixesobjectstack-ai#4650
Claude-Session: https://claude.ai/code/session_0176qgxgCXTJCUv4YFLtusP9
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationprotocol:systemprotocol:uisize/lteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

spec 双源清账 C3:通知语汇 Notification(Schema)(./api ≠ ./ui)+ NotificationConfig(Schema)(./system ≠ ./ui)—— 4 条,单 PR

2 participants

@os-zhuang@claude