12 KiB
12 KiB
P1R7b Source Owner Propagation 审阅版
结论
推荐进入 P1R-7b,但只进入 source owner propagation 的第一切片,不进入 Events / P1R-7 / Market completed approval。
推荐拆分为:
- P1R-7b:只选择 AI task terminal event 作为第一切片,证明 AI owner 本域事件通过最小 publish outbox / worker 调用
EventsPublishApi,落入muse_unified_event,并可被/app-api/muse/eventsSSE 读到。 - 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.yamldocs/api-contracts/ai/openapi.yamldocs/api-contracts/knowledge/openapi.yamldocs/api-contracts/events/openapi.yamlmuse-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_retryjob,未验证存在 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 分批”的真实最小方案。
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,必须另起审批任务。
- 受保护文件保持无改动。
待确认项
- P1R-7b 第一切片是否确认只选 AI task terminal event,而不是 Market / Knowledge / Member。
- AI terminal event 的最小事件类型是否限定为
done/error,还是允许补一个notification摘要。 - P1R-7b 是否允许新增 AI 本域 publish outbox/job 表或等价状态字段;若不允许,只能做更弱的同步 publish 证明,不建议。
- P1R-7b 的 E2E evidence 是否需要真实 PostgreSQL
_test+ MockMvc/SSE,还是 focused integration test 足够进入下一轮 review。
下一步
- 人类确认本文推荐方案和待确认项。
- 确认后再写执行版计划,路径建议为
docs/agent-specs/2026-06-06-P1R7bSourceOwnerPropagation执行版.md。 - 执行版计划需先过 fresh spec review + fresh quality review;双 PASS 前不实现代码、不跑 full verification。
- 实现阶段只在
/Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0进行,不处理/Users/qingse/Sync/local-git/oh-my-muse残留。