Skip to content

spec 双源 C1:WebhookConfig / WebhookEvent —— ./api ≠ ./integration(4 条,#4535 C 组) #4572

Description

@os-zhuang

父单:#4535(C 组第 1 簇)。packages/spec/dual-source-exports.baseline.json 现存 35 条中的 4 条:

WebhookConfig — [./api (type)] ≠ [./integration (type)]
WebhookConfigSchema — [./api (const)] ≠ [./integration (const)]
WebhookEvent — [./api (type)] ≠ [./integration (type)]
WebhookEventSchema — [./api (const)] ≠ [./integration (const)]

同名 zod schema + 推断类型在 ./api 与 ./integration 各有一份不同声明 —— 消费者拿到哪个形状只取决于 import 路径(#4411 陷阱)。

任务

  1. 先判真源(contract-first):import 语句级扫描三仓(本仓 + cloud + objectui),不要用名字出现次数(spec 同名双源:两个 MetadataWatchEvent 形状不同、分挂两个子路径入口,其中 kernel 版零消费方(ADR-0049 enforce-or-remove) #4411 的教训)。两份声明先 diff:形状差异、语义差异、各自消费方,判定结果写进 PR 正文。
  2. 处置三选一(按 ✅ spec 双源清账主单:基线 52 → 0(2026-08-03 收官)—— #4446 gate 落地后的偿还 worklist #4535 手册):死侧零消费方 ⇒ 直接删(v17 rc 是 major 窗口);两侧都活且同概念 ⇒ 收敛到真源 + 另一侧 re-export(re-export 不会被 gate 报);真是两个概念 ⇒ 改名一侧(先例:[#4535·B] 跨形态同名三条:ShareRecipientType(type≠const)、TransformType(const≠type)、suggestFieldType(双实现 function) #4539 → PR feat(spec)!: 跨形态同名三条收敛 — ShareRecipientType / TransformType / suggestFieldType (#4539) #4571 的 RecordShareRecipientType)。
  3. 收敛 ≠ 无行为变化:若存活形状比被删侧窄/宽,消费方类型会变 —— 逐字段核实并写进 changeset;拿不准的分歧用 @ts-expect-error pin 进测试。

验收

  • 基线恰好 −4(35 → 31):check:dual-source-exports stale 分支点名的即这 4 行,不多删不漏删
  • check:generated 8/8 up to date(api-surface 等经 --fix 定向再生,单独 commit)
  • spec build / typecheck / test 全绿;全仓 pnpm build / pnpm typecheck / pnpm test 全绿
  • changeset:@objectstack/spec major,FROM → TO 迁移行;不改 content/docs/releases/(releases-freeze,见 CLAUDE.md);文档若引用被改名/删除的导出,一并修正
  • 若触及可作者化 metadata key 的形状,回 spec-property-retirement skill 走完整流程
  • 范围外发现按第十条军规立 unassigned issue,不夹带进本 PR

工作方式

专用 worktree(git worktree add ../objectstack-issue-<本单号> -b claude/issue-<本单号>-webhook-dual-source main)→ 实现 → 推分支 → draft PR(正文含逐条判定 + 验证清单)→ 向 PM 返回 JSON 报告。

Activity

  1. self-assigned this
    on Aug 2, 2026
  2. os-zhuang commented on Aug 2, 2026

    @os-zhuang
    ContributorAuthor

    PM 审阅:ACCEPT — PR #4581 转正式并进入合并队列(squash)。

    核验结果:

    1. 死侧判定独立复核通过:在合并前的 main 上全仓 grep,./api 侧 WebhookConfig(Schema) 的裸名引用只有声明文件自身与其单测,确未接线进 RestServerConfigSchema,也无任何 runtime 消费 —— 直接删除(路线 1)成立。kernel 的 EventWebhookConfigSchema 是另一个名字,不受影响。
    2. 改名判定成立:./api 侧 WebhookEvent 是 OpenAPI 3.1 webhook 描述子(z.object),与 ./integration 的 connector 事件枚举(z.enum)是跨形态的两个概念 —— 改名 OpenApiWebhookEvent(Schema) 归入 OpenApi* 家族,OpenApi31ExtensionsSchema.webhooks 同步改引,作者可写形状零变化。./integration 成为裸名唯一属主,config/event 成对语义保留在同一域内。
    3. 基线恰好 −4(35 → 31),不多删不漏删;api-surface −4/+2 与两条处置严格对账;json-schema.manifest 蓄意退休 + 蓄意改名,非静默下架。
    4. 文档收敛干净:误名的自动生成页 references/api/connector.mdx 随再生删除,无残留链接;手写文档与 releases 页零提及这四个名字(定向 grep 核实),107 文件的 drift 播发按惯例以定向检查处置。
    5. 编译期 pin 替代运行时动态 import pin —— 顺带消除了 fix(spec,docs): check-react-blocks-conformance 比的是两份声明,不是声明↔实现 (#4472) #4491 那类 5s 超时抖动,是正确的修法。
    6. 范围外发现 RestServerConfig.openApi31(OpenApi31Extensions / Callback / OpenApiWebhookEvent)declared ≠ enforced:没有任何运行时读取它 —— ADR-0049 enforce-or-remove 候选 #4579(RestServerConfig.openApi31 整块 declared ≠ enforced)按第十条军规立案 unassigned,未夹带。

    验证:spec 287 文件 / 7270 用例全过,全仓 build 71/71、typecheck 122/122、test 132/132。合并后基线余 31,C2(MetadataEvent / MetadataBulkRegisterRequestSchema,./api ≠ ./kernel,3 条)接续派发。


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions