149 lines
12 KiB
Markdown
149 lines
12 KiB
Markdown
# P1R7b Source Owner Propagation 审阅版
|
||
|
||
## 结论
|
||
|
||
推荐进入 P1R-7b,但只进入 source owner propagation 的第一切片,不进入 Events / P1R-7 / Market completed approval。
|
||
|
||
推荐拆分为:
|
||
|
||
1. P1R-7b:只选择 AI task terminal event 作为第一切片,证明 AI owner 本域事件通过最小 publish outbox / worker 调用 `EventsPublishApi`,落入 `muse_unified_event`,并可被 `/app-api/muse/events` SSE 读到。
|
||
2. P1R-7c 或后续:再评估 Knowledge、Market、Member(Account) 的 source owner propagation,不在 P1R-7b 同时改造多个 owner。
|
||
|
||
P1R-7b 最多补齐 source owner propagation 的 `needs_verification` 证据;不得自动把 Events、总 P1R-7 或 Market 32 operations 标为 `completed`。
|
||
|
||
## 已验证事实
|
||
|
||
- 正确工作区已核验为 `/Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0`,`git log -1 --oneline` 为 `fa29753 test(p1r): 收口 Events SSE 门禁`。
|
||
- P1R-7a 推送后正确 worktree 曾核验为干净;本文档写入后当前 live `git status --short` 显示 `?? docs/agent-specs/`。后续执行版和实现前必须重新记录 live dirty baseline。受保护文件无改动:
|
||
- `docs/api-contracts/market/openapi.yaml`
|
||
- `docs/api-contracts/ai/openapi.yaml`
|
||
- `docs/api-contracts/knowledge/openapi.yaml`
|
||
- `docs/api-contracts/events/openapi.yaml`
|
||
- `muse-cloud/scripts/p1r-audit-api-coverage.py`
|
||
- coverage 当前为 `completed=100`、`needsVerification=133`、`incomplete=0`、`genericPersistence=0`、`ssePlaceholder=0`。
|
||
- Events 当前唯一 operation:`streamEvents GET /app-api/muse/events = dedicated / needs_verification`。
|
||
- Market 当前 32 operations 均仍为 `dedicated / needs_verification`。
|
||
- P1R-7a 收口文档明确:P1R-7a 未接入 source owner propagation,未运行 source owner publish tests。
|
||
- `muse-module-events-api` 已存在 `EventsPublishApi.publish(EventsPublishReqDTO)`;Events server 已有 `muse_unified_event` 投影、幂等回查、payload 脱敏、`accepted/rejected/blocked` 状态和可见事件查询。
|
||
- 当前 AI 有 `muse_ai_task_event`、task event replay mapper、`MuseAiRuntimeJobDispatcher`、`MuseAiJobMapper.claimNextQueuedRuntimeJob()`;但 AI runtime job 只领取 `ai_task_runtime`,AI source event retry 只提交 `source_event_retry` job,未验证存在 Events publish worker。
|
||
- 当前 Knowledge 有 `muse_knowledge_source_event` 和 `muse_knowledge_projection_task`;`MuseKnowledgeSourceEventService` 同步更新 projection 后把 task 直接写为 `completed`,注释说明避免制造无执行者的 queued task。
|
||
- 当前 Market 有 `MarketAccountProjectionOutboxService`,但接口只有 `recordSynced` / `recordBlocked`,用于 Market 写 member Account projection 的同步状态;未发现 claim/retry/dead-letter/replay worker。
|
||
- 当前 Member(Account) 有 `AccountIntegrationCallDO`、`MemberSecurityEventDO` 和安全事件脱敏转换;mapper 只支持查询,不支持 publish outbox claim 或补偿状态转换。
|
||
|
||
## 推断
|
||
|
||
- AI 是 P1R-7b 第一切片的最小风险 owner:它已有 owner-visible task terminal event、runtime job、sequence/replay 和 focused test 基础,新增 Events publish outbox/worker 的范围最小。
|
||
- Market 虽然有 outbox 命名和状态字段,但当前职责是 Account 投影同步记录,不是通用 Events publish 补偿队列;直接复用会混淆职责。
|
||
- Knowledge 和 Member(Account) 要进入统一事件传播,都需要先补本域 publish outbox/worker 语义;放入 P1R-7b 会扩大 blast radius。
|
||
- 如果 P1R-7b 同时拉 AI、Knowledge、Market、Member(Account),大概率会变成跨 owner 队列重构,不符合“真实最小”的阶段目标。
|
||
|
||
## 假设
|
||
|
||
- P1R-7b 允许在 AI owner 内新增最小 Events publish outbox/worker 结构,但仍不得修改 OpenAPI、scanner 或 coverage 口径。
|
||
- P1R-7b 的 source owner publish tests 可以优先使用 focused unit / integration tests 证明发布、失败、重试、幂等和 SSE 可见性,不要求一次性覆盖所有业务 owner。
|
||
- 当前代码结构中的 Events API 依赖方向会保持:source owner 可以依赖 `muse-module-events-api`,但 Events server 不反向依赖 AI / Knowledge / Market / Member server。
|
||
|
||
## 目标
|
||
|
||
- 证明至少一个真实 source owner 能把本域事实传播到统一 Events 投影。
|
||
- 第一切片只覆盖 AI task terminal event 的 `done` / `error` 或等价最小可公开事件。
|
||
- 建立 source owner 本域 outbox/job 到 `EventsPublishApi` 的可追踪链路。
|
||
- 产出 publish tests 和最小 E2E evidence,证明 source owner -> Events -> `muse_unified_event` -> SSE stream 的链路可验证。
|
||
- 保持 `streamEvents` 和相关 owner 状态在 `needs_verification` 证据推进层,不做 completed approval。
|
||
|
||
## 非目标
|
||
|
||
- 不实现代码;本文档只做人类审阅版设计。
|
||
- 不修改任何 OpenAPI 合同。
|
||
- 不修改 coverage scanner 或通过 scanner 改口径掩盖缺口。
|
||
- 不修改 coverage JSON / Markdown,不标 `completed`。
|
||
- 不把 P1R-7b 扩大成总 P1R-7 End-to-End Acceptance。
|
||
- 不把 Market 32 operations 从 `needs_verification` 推进到 `completed`。
|
||
- 不同时改造 AI、Knowledge、Market、Member(Account) 四个 owner。
|
||
- 不清理、不回退、不修复错误 checkout `/Users/qingse/Sync/local-git/oh-my-muse` 的任何残留。
|
||
|
||
## 推荐方案
|
||
|
||
采用“AI first slice + 后续 owner 分批”的真实最小方案。
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
Owner["AI source owner<br/>task terminal fact"] --> Outbox["AI local publish outbox/job<br/>queued/running/failed/dead_letter"]
|
||
Outbox --> Worker["AI publish worker<br/>retry + idempotency"]
|
||
Worker --> Api["EventsPublishApi<br/>events-api only"]
|
||
Api --> Store[("muse_unified_event<br/>accepted/rejected/blocked")]
|
||
Store --> Query["Events visible query<br/>tenant + ownerUserId + sequence"]
|
||
Query --> SSE["/app-api/muse/events<br/>SSE stream"]
|
||
```
|
||
|
||
推荐 P1R-7b 第一切片边界:
|
||
|
||
- Source owner:AI。
|
||
- Source fact:AI task terminal event,优先选择已可公开、已持久化、已有 ownerUserId 和 sequence 的 done/error 事实。
|
||
- Publish mode:AI 本域 outbox/job 异步调用 `EventsPublishApi`,不在业务事务内阻塞等待 Events 成功。
|
||
- Idempotency:使用 AI 本域 command/source tuple 映射 Events `commandId` 和 `(sourceOwner, sourceType, sourceId, sourceRevision, eventType)`。
|
||
- Failure:Events 临时失败时 AI 业务事实仍保留,outbox 保持可重试;达到上限后进入阻塞或 dead-letter 等价状态。
|
||
- SSE evidence:只证明 accepted 事件进入 `muse_unified_event` 后能被当前用户 SSE 可见查询读到。
|
||
|
||
后续切片:
|
||
|
||
- P1R-7c:Knowledge source/projection event publish outbox。
|
||
- P1R-7d:Market governance / Account projection 相关事件,需先拆清 Account 投影 outbox 与 Events publish outbox 职责。
|
||
- P1R-7e:Member(Account) 安全/额度通知,需先冻结脱敏 payload contract。
|
||
|
||
## 候选 source owner 分级
|
||
|
||
| 分级 | Owner | 结论 | 主要证据 |
|
||
|---|---|---|---|
|
||
| 第一切片 | AI | 推荐 P1R-7b 先做 | 已有 task event、runtime job、ownerUserId、sequence/replay 基础;缺口集中在 Events publish outbox/worker |
|
||
| 后续高优先 | Knowledge | 放入 P1R-7c | 有 source event/projection 事实,但 projection task 当前同步完成,不是可执行补偿队列 |
|
||
| 后续中优先 | Market | 放入后续 | 有 Account projection outbox 状态记录,但职责是 Market -> Member Account 投影同步,不是 Events publish worker |
|
||
| 后续中优先 | Member(Account) | 放入后续 | 有安全事件和脱敏转换,但缺少 publish outbox/job/retry/dead-letter 入口 |
|
||
|
||
## 关键取舍
|
||
|
||
- 选择 AI,不选择 Market:Market outbox 名称容易误导,但当前没有 claim/retry/dead-letter/replay worker;AI 的 task terminal event 更接近可公开事件源。
|
||
- 做一个 owner,不做四个 owner:source owner propagation 的核心风险在失败补偿和幂等;先用单 owner 打穿链路,比并行堆多个半成品更可审核。
|
||
- 新增本域 publish outbox,不把 runtime job 当 Events publish 队列:AI runtime job 职责是执行 New-API task;混用会污染任务语义和重试策略。
|
||
- 保持 Events API 单向依赖:source owner 依赖 events-api;Events server 不读取 source owner 表,不反向依赖 source owner server。
|
||
- 只推进证据,不推进 completed:P1R-7b 是 source propagation evidence 阶段,不是审批阶段。
|
||
|
||
## 影响范围
|
||
|
||
- 直接影响:AI owner 的 task terminal event 发布路径、Events publish API 调用、`muse_unified_event` 投影可见性、SSE focused evidence。
|
||
- 间接影响:P1R-7 completed approval 的后续证据链更完整,但不会自动改变 completed 状态。
|
||
- 不影响:OpenAPI 合同、scanner 规则、Market coverage 状态、错误 checkout `/Users/qingse/Sync/local-git/oh-my-muse`。
|
||
|
||
## 风险与兼容性
|
||
|
||
- 幂等风险:同一 AI task terminal event 重试不能生成多条 unified event;必须用 command/source tuple 双重幂等验证。
|
||
- 事务风险:AI 业务事实不能因为 Events 暂时不可用而回滚;publish outbox 必须承载失败补偿。
|
||
- 敏感信息风险:AI payload 只能发布 OpenAPI 允许的 done/error 摘要,不能透传 provider raw body、prompt、token、授权头或私有上下文。
|
||
- 顺序风险:AI task sequence 与 Events 全局 sequence 是不同序列;文档和测试必须明确映射,不得混用 cursor。
|
||
- 兼容性风险:新增 AI -> events-api 依赖可以接受;不得新增 AI -> events-server 依赖,也不得新增 Events server -> AI server 依赖。
|
||
- 状态风险:P1R-7b evidence 可能让 Events 更接近 completion,但没有用户明确 approval 前不得改 coverage completed。
|
||
|
||
## 验收标准
|
||
|
||
- 有只读 preflight 证明 worktree、HEAD、coverage 和 protected files 状态。
|
||
- AI 第一切片 source fact、outbox/job、publish worker、EventsPublishApi、`muse_unified_event` 和 SSE 可见查询形成闭环证据。
|
||
- Publish tests 至少覆盖成功发布、重复发布幂等、EventsPublishApi 临时失败后 outbox 可重试、非法/敏感 payload 不进入可见 SSE、dead-letter 或等价阻塞状态。
|
||
- E2E evidence 至少证明 AI terminal fact 发布后,`muse_unified_event` 有 accepted 记录,并能被 `/app-api/muse/events` 当前用户 SSE 读到。
|
||
- 依赖方向测试证明 Events server 不依赖 AI / Knowledge / Market / Member server,AI 只依赖 `muse-module-events-api`。
|
||
- coverage 仍不标 completed;若需要 completed approval,必须另起审批任务。
|
||
- 受保护文件保持无改动。
|
||
|
||
## 待确认项
|
||
|
||
1. P1R-7b 第一切片是否确认只选 AI task terminal event,而不是 Market / Knowledge / Member。
|
||
2. AI terminal event 的最小事件类型是否限定为 `done` / `error`,还是允许补一个 `notification` 摘要。
|
||
3. P1R-7b 是否允许新增 AI 本域 publish outbox/job 表或等价状态字段;若不允许,只能做更弱的同步 publish 证明,不建议。
|
||
4. P1R-7b 的 E2E evidence 是否需要真实 PostgreSQL `_test` + MockMvc/SSE,还是 focused integration test 足够进入下一轮 review。
|
||
|
||
## 下一步
|
||
|
||
1. 人类确认本文推荐方案和待确认项。
|
||
2. 确认后再写执行版计划,路径建议为 `docs/agent-specs/2026-06-06-P1R7bSourceOwnerPropagation执行版.md`。
|
||
3. 执行版计划需先过 fresh spec review + fresh quality review;双 PASS 前不实现代码、不跑 full verification。
|
||
4. 实现阶段只在 `/Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0` 进行,不处理 `/Users/qingse/Sync/local-git/oh-my-muse` 残留。
|