[BEL] 实现不可变 Event 与永久幂等收据 #17

Closed
opened 2026-08-12 09:53:44 +08:00 by ila · 4 comments
Owner

当前状态:已完成

用户于 2026-08-14 明确验收通过。

基本信息

  • 类型:需求
  • 任务类型:单项目
  • 主项目:Bell
  • 主 agent:Bell agent
  • 所属 Epic:#7
  • 所属 MVP / 版本:#8
  • 阶段:三项目首个独立纵切

依赖与并行

  • 前置工单:#9
  • 是否允许与前置工单并行:是
  • 原因:Event 领域与认证页面可在骨架完成后分别开发;不与 #12 并行写相同路径。

子项目影响

  • 仅影响的子项目 / 交付单元:Bell
  • 是否跨子项目:否
  • 是否修改共享接口或契约:否;唯一事实来源:不适用,本工单只维护 Bell 内部实现
  • write_paths:Bell/server/app/event/**、Bell/server/app/receipt/**、Bell/server/migrations/*event*、Bell/server/migrations/*receipt*、Bell/web/src/views/event/**
  • 各子项目需要执行的验证:仅执行 Bell 后端、前端及 PostgreSQL 测试;Sense/Brain 无需启动或验证

协同接口

  • 生产者:不适用
  • 消费者:不适用
  • 契约/共享事实源:不适用
  • 兼容策略:不适用
  • 被阻塞或需要适配的工单:不适用
  • 集成顺序:不适用

原始需求

  • 来源:用户对话、Epic #7、MVP #8、Product-Requirements、Product-Roadmap、Requirements-Migration-Matrix
  • 提出时间:2026-08-12
  • 关键原话或脱敏摘要:先创建三个项目各自独立任务的全部工单,标题包含项目英文简称;Bell 首个纵切须在 Sense/Brain 不在线时以合成事件完成 Event → Alert → ack → close。

要解决什么

Bell 需要以 (producer_id, source_event_id) 永久稳定地接收入站事实,原始 Event 校验后不可变并保存结构化内容与证据引用;重复请求和跨重启重试必须返回同一收据。

做什么 / 不做什么

  • 做:建立 Bell 内部规范化入站命令、Event/Receipt PostgreSQL 模型与迁移、唯一约束、事务写入、查询/详情能力和幂等/重启测试;Event 页面支持分页查看且明确原始事实不可编辑。
  • 不做:不冻结跨项目 JSON Schema/OpenAPI;不实现正式公网/机器 API 或 producer 发放;不读取外部证据文件;不实现规则、Alert、通知、Outbox;不修改已存 Event。

已确认方案

内部入站端口接收经过适配器规范化的数据。数据库以 (producer_id, source_event_id) 唯一约束作为并发最终防线;首次写入创建不可变 Event 和稳定 Receipt,完全相同的重试返回原收据,键相同但规范化载荷冲突时返回可定位冲突且不改写旧事实。证据只保存安全逻辑引用。

预计修改文件:

  • Bell/server/app/event/**
  • Bell/server/app/receipt/**
  • Bell/server/migrations/*event*
  • Bell/server/migrations/*receipt*
  • Bell/web/src/views/event/**

需求变化记录

日期 变化内容 原因 用户确认
2026-08-12 无 初始建单 是

文档影响

  • 不影响长期文档,原因:不适用
  • 更新项目档案或本地开发与验证
  • 更新架构与代码地图
  • 更新业务规则与术语
  • 更新常见修改或故障排查
  • 更新其他 Wiki 页面:Bell Event/Receipt 数据结构、不可变性和幂等冲突语义

交付文档影响

  • 无交付文档影响,原因:不适用
  • 更新已有交付文档,受众与页面:实施/支持人员,Event 查询和幂等冲突排查
  • 新增交付文档,受众与页面:
  • 需要目标岗位或客户代表验证:否;验证方式:数据库与 API/服务层自动化测试

验收标准

  • 首次规范化输入原子创建 Event 与永久稳定 Receipt
  • 相同 (producer_id, source_event_id)、相同载荷的串行/并发/跨重启重试返回同一 Event 与 Receipt
  • 相同幂等键但不同载荷返回冲突,不修改原 Event
  • Event 字段和证据引用持久化后没有更新/删除业务入口,处置结果不写回 Event
  • Event 列表分页、详情查询和双向导航预留不一次加载全部记录
  • 迁移、唯一约束、事务回滚和 PostgreSQL 重启场景有自动化证据

验证方式

Set-Location Bell/server
go test ./...
Set-Location ../web
pnpm lint
pnpm build:prod

在独立 PostgreSQL 测试库运行迁移,并执行重复、并发冲突、事务失败回滚、服务重启后重试以及 Event 页面分页/只读检查。

未验证边界:Sense/Brain 的正式事件生产、跨项目机器身份、共享事件/证据契约、根级部署与端到端链路不在本工单验证;这些内容留待独立协同工单。

风险和回退

风险:错误幂等设计会丢事件或制造重复,迁移错误会破坏不可变性。回退:在尚无生产数据的 MVP 测试库回退本工单迁移与模块;一旦有真实 Event,不得通过更新/删除历史数据回退,需另建高风险迁移工单。

后续协同需求摘要

生产者:Sense、Brain、第三方事件源;消费者:Bell 入站适配器;目的:冻结外部事件/证据 Schema、错误码、producer identity 与兼容周期;候选事实源:未来 contracts/ 版本化 OpenAPI/JSON Schema;阻塞工单:正式外部接入将在 #本工单后续集成 之外;建议验证:契约测试、身份隔离、重复/冲突/版本兼容与无内部路径泄露。

## 当前状态:已完成 用户于 2026-08-14 明确验收通过。 ## 基本信息 - 类型:需求 - 任务类型:单项目 - 主项目:Bell - 主 agent:Bell agent - 所属 Epic:#7 - 所属 MVP / 版本:#8 - 阶段:三项目首个独立纵切 ## 依赖与并行 - 前置工单:#9 - 是否允许与前置工单并行:是 - 原因:Event 领域与认证页面可在骨架完成后分别开发;不与 #12 并行写相同路径。 ## 子项目影响 - 仅影响的子项目 / 交付单元:Bell - 是否跨子项目:否 - 是否修改共享接口或契约:否;唯一事实来源:不适用,本工单只维护 Bell 内部实现 - write_paths:`Bell/server/app/event/**`、`Bell/server/app/receipt/**`、`Bell/server/migrations/*event*`、`Bell/server/migrations/*receipt*`、`Bell/web/src/views/event/**` - 各子项目需要执行的验证:仅执行 Bell 后端、前端及 PostgreSQL 测试;Sense/Brain 无需启动或验证 ## 协同接口 - 生产者:不适用 - 消费者:不适用 - 契约/共享事实源:不适用 - 兼容策略:不适用 - 被阻塞或需要适配的工单:不适用 - 集成顺序:不适用 ## 原始需求 - 来源:用户对话、Epic #7、MVP #8、Product-Requirements、Product-Roadmap、Requirements-Migration-Matrix - 提出时间:2026-08-12 - 关键原话或脱敏摘要:先创建三个项目各自独立任务的全部工单,标题包含项目英文简称;Bell 首个纵切须在 Sense/Brain 不在线时以合成事件完成 Event → Alert → ack → close。 ## 要解决什么 Bell 需要以 `(producer_id, source_event_id)` 永久稳定地接收入站事实,原始 Event 校验后不可变并保存结构化内容与证据引用;重复请求和跨重启重试必须返回同一收据。 ## 做什么 / 不做什么 - 做:建立 Bell 内部规范化入站命令、Event/Receipt PostgreSQL 模型与迁移、唯一约束、事务写入、查询/详情能力和幂等/重启测试;Event 页面支持分页查看且明确原始事实不可编辑。 - 不做:不冻结跨项目 JSON Schema/OpenAPI;不实现正式公网/机器 API 或 producer 发放;不读取外部证据文件;不实现规则、Alert、通知、Outbox;不修改已存 Event。 ## 已确认方案 内部入站端口接收经过适配器规范化的数据。数据库以 `(producer_id, source_event_id)` 唯一约束作为并发最终防线;首次写入创建不可变 Event 和稳定 Receipt,完全相同的重试返回原收据,键相同但规范化载荷冲突时返回可定位冲突且不改写旧事实。证据只保存安全逻辑引用。 预计修改文件: - `Bell/server/app/event/**` - `Bell/server/app/receipt/**` - `Bell/server/migrations/*event*` - `Bell/server/migrations/*receipt*` - `Bell/web/src/views/event/**` ## 需求变化记录 | 日期 | 变化内容 | 原因 | 用户确认 | |---|---|---|---| | 2026-08-12 | 无 | 初始建单 | 是 | ## 文档影响 - [ ] 不影响长期文档,原因:不适用 - [ ] 更新项目档案或本地开发与验证 - [x] 更新架构与代码地图 - [x] 更新业务规则与术语 - [x] 更新常见修改或故障排查 - [x] 更新其他 Wiki 页面:Bell Event/Receipt 数据结构、不可变性和幂等冲突语义 ## 交付文档影响 - [ ] 无交付文档影响,原因:不适用 - [x] 更新已有交付文档,受众与页面:实施/支持人员,Event 查询和幂等冲突排查 - [ ] 新增交付文档,受众与页面: - [x] 需要目标岗位或客户代表验证:否;验证方式:数据库与 API/服务层自动化测试 ## 验收标准 - [ ] 首次规范化输入原子创建 Event 与永久稳定 Receipt - [ ] 相同 `(producer_id, source_event_id)`、相同载荷的串行/并发/跨重启重试返回同一 Event 与 Receipt - [ ] 相同幂等键但不同载荷返回冲突,不修改原 Event - [ ] Event 字段和证据引用持久化后没有更新/删除业务入口,处置结果不写回 Event - [ ] Event 列表分页、详情查询和双向导航预留不一次加载全部记录 - [ ] 迁移、唯一约束、事务回滚和 PostgreSQL 重启场景有自动化证据 ## 验证方式 ```powershell Set-Location Bell/server go test ./... Set-Location ../web pnpm lint pnpm build:prod ``` 在独立 PostgreSQL 测试库运行迁移,并执行重复、并发冲突、事务失败回滚、服务重启后重试以及 Event 页面分页/只读检查。 未验证边界:Sense/Brain 的正式事件生产、跨项目机器身份、共享事件/证据契约、根级部署与端到端链路不在本工单验证;这些内容留待独立协同工单。 ## 风险和回退 风险:错误幂等设计会丢事件或制造重复,迁移错误会破坏不可变性。回退:在尚无生产数据的 MVP 测试库回退本工单迁移与模块;一旦有真实 Event,不得通过更新/删除历史数据回退,需另建高风险迁移工单。 ## 后续协同需求摘要 生产者:Sense、Brain、第三方事件源;消费者:Bell 入站适配器;目的:冻结外部事件/证据 Schema、错误码、producer identity 与兼容周期;候选事实源:未来 `contracts/` 版本化 OpenAPI/JSON Schema;阻塞工单:正式外部接入将在 #本工单后续集成 之外;建议验证:契约测试、身份隔离、重复/冲突/版本兼容与无内部路径泄露。
ila added the kind/taskpriority/p0project/bellscope/independent labels 2026-08-12 09:58:44 +08:00
Author
Owner

状态:进行中(2026-08-12)

前置 #9 已完成并推送,#12 也已按顺序完成。开始实现 PostgreSQL 原子 Event/Receipt、(producer_id, source_event_id) 永久幂等、载荷冲突拒绝、Event 数据库级不可更新/删除以及分页查询;写入限于 Bell/**。

## 状态:进行中(2026-08-12) 前置 #9 已完成并推送,#12 也已按顺序完成。开始实现 PostgreSQL 原子 Event/Receipt、`(producer_id, source_event_id)` 永久幂等、载荷冲突拒绝、Event 数据库级不可更新/删除以及分页查询;写入限于 `Bell/**`。
Author
Owner

实施完成,进入连续依赖验证

  • 实现提交:64a1d82(已推送)
  • PostgreSQL 实测 16 个并发重试:Event ID 与 Receipt ID 均稳定唯一
  • 相同幂等键不同载荷:明确冲突且旧 Event 未改变
  • 连接池关闭/重开后重试:仍返回原 Event/Receipt
  • Event/Receipt UPDATE:数据库触发器拒绝
  • 安全证据引用校验、分页列表、详情查询:通过
  • Go 全量测试(含 PostgreSQL 集成)、前端 lint/build、差异检查:通过

#18 的真实依赖是复用稳定 Event/Receipt 入站服务,现已满足,继续实施仅限开发测试的合成入口。

## 实施完成,进入连续依赖验证 - 实现提交:`64a1d82`(已推送) - PostgreSQL 实测 16 个并发重试:Event ID 与 Receipt ID 均稳定唯一 - 相同幂等键不同载荷:明确冲突且旧 Event 未改变 - 连接池关闭/重开后重试:仍返回原 Event/Receipt - Event/Receipt UPDATE:数据库触发器拒绝 - 安全证据引用校验、分页列表、详情查询:通过 - Go 全量测试(含 PostgreSQL 集成)、前端 lint/build、差异检查:通过 #18 的真实依赖是复用稳定 Event/Receipt 入站服务,现已满足,继续实施仅限开发测试的合成入口。
Author
Owner

最终证据:待验收

  • 实现提交:64a1d82(PR #35)
  • 长期文档与归档协调:#36 / PR #38
  • Wiki 归档 revision:dab364664ed4
  • 本地只读镜像:docs/task/17-Bell不可变Event与永久幂等收据.md
  • 文档镜像提交:e2a4345、3c245e1
  • 文档验证:36 个 Wiki 映射一致;DevHarness 通过;31 项 unittest 通过;git diff --check 通过

实现、自动测试、Wiki、镜像、提交、推送与 PR 证据已齐。人工验收前本工单保持开启,不关闭、不勾选父工单。

## 最终证据:待验收 - 实现提交:`64a1d82`(PR #35) - 长期文档与归档协调:#36 / PR #38 - Wiki 归档 revision:`dab364664ed4` - 本地只读镜像:`docs/task/17-Bell不可变Event与永久幂等收据.md` - 文档镜像提交:`e2a4345`、`3c245e1` - 文档验证:36 个 Wiki 映射一致;DevHarness 通过;31 项 unittest 通过;`git diff --check` 通过 实现、自动测试、Wiki、镜像、提交、推送与 PR 证据已齐。人工验收前本工单保持开启,不关闭、不勾选父工单。
Author
Owner

用户验收通过(2026-08-14)

用户已明确确认当前未验收工单通过验收。本工单的实现、测试与既有证据按记录接受,Wiki 归档状态已更新为“已完成”(revision 2535dc083740)。该交付属于重建前历史实现;Wiki 归档已完成,代码与原归档镜像继续保留在 explore 追溯。

此验收不改变 #58 的架构决定:旧自研基础框架不会恢复为 dev 基线,Sense/Bell 后续仍分别由 #61/#62 从冻结 GoAdmin 源码重建。

## 用户验收通过(2026-08-14) 用户已明确确认当前未验收工单通过验收。本工单的实现、测试与既有证据按记录接受,Wiki 归档状态已更新为“已完成”(revision `2535dc083740`)。该交付属于重建前历史实现;Wiki 归档已完成,代码与原归档镜像继续保留在 `explore` 追溯。 此验收不改变 #58 的架构决定:旧自研基础框架不会恢复为 `dev` 基线,Sense/Bell 后续仍分别由 #61/#62 从冻结 GoAdmin 源码重建。
ila closed this issue 2026-08-14 10:06:44 +08:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: ila/yovision#17