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

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 实现、contracts 的 InboxNotification 镜像(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 导出面。

保留不动

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

迁移指引(含「api 行是收件箱记录、不是呈现配置」的形状变化提醒、以及 NotificationConfig 的替代路径 —— INotificationService.emit、notify 流程节点 NotifyConfigSchema、sys_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

claude added 2 commits August 2, 2026 11:18
…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

vercel Bot commented Aug 2, 2026 •

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 2, 2026 12:45pm

Request Review

@github-actions

github-actions Bot commented Aug 2, 2026

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 queue Aug 2, 2026
Merged via the queue into main with commit 0a936ea Aug 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.

Fixes objectstack-ai#4650


Claude-Session: https://claude.ai/code/session_0176qgxgCXTJCUv4YFLtusP9

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/l tests tooling

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