oh-my-muse/docs/agent-specs/2026-06-07-P1R7dMarketSourceOwnerPropagation审阅版.md

13 KiB
Raw Blame History

P1R7d Market Source Owner Propagation 审阅版

结论

推荐进入 P1R-7d但第一切片只覆盖 Market governance / source status 的用户可见通知,不覆盖 purchase、install、handoff、Account projection 同步或目标 owner 授权消费。

推荐方案:

  1. 选择 AdminMarketGovernanceServiceImpl 已落库的 muse_market_governance_action / muse_market_source_status_event 作为 P1R-7d 第一批 source fact。
  2. 新增 Market 本域 Events publish outbox / worker调用 EventsPublishApi,发布 Events 已声明的 notification/governance_action
  3. 不复用 MarketAccountProjectionOutboxService 作为 Events publish outbox它只表达 Market -> Member Account 投影同步状态。
  4. 不修改 OpenAPI、scanner 或 coverage report不推进 Events / P1R-7 / Market completed。
flowchart LR
    Admin["Admin governance command<br/>delist / recall"] --> Fact["Market source fact<br/>governance_action / source_status_event"]
    Fact --> Outbox["Market events publish outbox<br/>queued / running / retryable / published / dead_letter"]
    Outbox --> Worker["Market worker<br/>claim + retry + audit log"]
    Worker --> Api["EventsPublishApi<br/>events-api only"]
    Api --> Unified[("muse_unified_event<br/>notification / governance_action")]
    Unified --> SSE["/app-api/muse/events<br/>publisher visible"]

本审阅版不实现代码,只冻结目标、非目标、取舍、影响范围、风险和验收标准。执行版、实现和提交必须在本审阅版 fresh spec review + fresh quality review 双 PASS 后再继续。

已验证事实

工作区与状态

  • 正确 worktree/Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0
  • 分支:dev/1.0.0
  • 当前本地与 origin/dev/1.0.0 对齐到 e55618f test(p1r): 收口 Knowledge 事件传播真实链路门禁
  • 受保护文件 diff 为空:
    • 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
    • docs/superpowers/reports/p1r-api-coverage.json
    • docs/superpowers/reports/p1r-api-coverage.md

全局 P1R-7 边界

  • P1R-7 全局审阅版建议阶段:
    • P1R-7bAI terminal event。
    • P1R-7cKnowledge source status / projection event。
    • P1R-7dMarket lifecycle / account projection / governance event。
    • P1R-7 completed approval 必须另起任务并由用户单独批准。
  • P1R-7 全局执行版要求每个 owner 都必须 fresh implementer + fresh spec review + fresh quality / feasibility review。
  • 全局合同要求 source owner 只能依赖 muse-module-events-apiEvents server 不得反向依赖 AI / Knowledge / Market / Member / Content server。
  • 当前 coverage summary 仍是 completedOperations=100needsVerificationOperations=133incompleteOperations=0genericPersistenceOperations=0ssePlaceholderOperations=0
  • Events streamEvents 与 Market 32 operations 均仍为 dedicated / needs_verification

Events 可复用合同

  • EventsPublishReqDTO 已包含 commandIdtenantIdownerUserIdsourceOwnersourceTypesourceIdsourceRevisioneventTyperesourceTyperesourceIdpayloadSummaryemittedAt
  • EventsPublishServiceImpl 先按 commandId 回放,再按 source tuple 回放。
  • EventsPublishServiceImpl 已声明事件类型包含 notification
  • Events OpenAPI 的 SSENotificationEvent.data.type 已包含 governance_action
  • UnifiedEventMapper.selectVisibleEventsForOwner 只返回 accepted、同租户、同 owner、未删除、已到 visible time 的事件。

Market 当前事实模型

  • AdminMarketGovernanceServiceImpl.delistAsset 在治理命令成功后写入 muse_market_governance_action,字段包括 actionIdpreviewIdassetIdactorUserIdownerUserIdactionTypecommandIdrequestHashstatusrevisionactionSnapshotreason
  • AdminMarketGovernanceServiceImpl.recallAsset 在治理命令成功后写入 muse_market_governance_action,并额外写入 muse_market_source_status_event,其中 sourceStatus 固定为合同状态如 recalledneeds_recheck 只写入 actionPolicy/recheckReasons
  • MuseMarketGovernanceActionMapper 支持按 tenant + asset 查询最新或列表,但没有 publish claim / retry / dead_letter 语义。
  • MuseMarketSourceStatusEventMapper 支持按 sourceEventId 或 tenant + asset 查询最新,但没有 publish claim / retry / dead_letter 语义。
  • MarketAccountProjectionOutboxServiceImpl 只有 recordSynced / recordBlocked,职责是 Market -> Member Account projection 同步状态;当前没有领取 retryable outbox、重试成功、dead_letter 或 replay worker。
  • MarketAccountProjectionProvider 明确把 Account 查询读模型写入 member 表,失败时记录 Market 侧 blocked outbox 后抛错,防止伪成功。
  • MarketHandoffServiceImpl 保存 handoff token hash 和生命周期状态,但 token 明文只在创建响应中返回;后续 P1R-7d 第一切片不发布 handoff token 或授权详情。

推断

  • Market P1R-7d 第一切片应优先选择 governance/source status而不是 purchase/install/handoff。原因是 governance/source status 已有明确 publisher owner、source fact、actionId/sourceEventId 和安全摘要空间,且用户需要实时知道资产被下架或召回。
  • 直接复用 muse_market_account_projection 作为 Events publish outbox 会混淆职责:它记录 Account 投影同步,不记录 Events publish claim、lease、retry、published event 或 dead_letter。
  • notification/governance_action 已在 Events 合同内,可避免本阶段修改 OpenAPI。
  • recall 比 delist 更适合作为第一条 source status 证据,因为它同时写 governance action 和 source status blocked 事实;但执行版仍可把 delist 作为同一事件族的正向治理通知。

假设

  • P1R-7d 允许在 Market owner 内新增独立 Events publish outbox 表或等价状态表。
  • P1R-7d 允许 muse-module-market-server 新增对 muse-module-events-api 的直接依赖,但不允许依赖 muse-module-events-server
  • Market publisher 是第一批通知的 ownerUserIdadmin 操作者只作为 actorUserId 写入 Market fact / 安全摘要,不作为 SSE 可见 owner。
  • notification/governance_action 的 payload 最小字段可以收敛为 typemessage、可选 resourceReftimestamp,不需要新增 OpenAPI 字段。

目标

  1. 证明 Market source owner 的真实治理事实可以通过 Market 本域 publish outbox / worker 发布到 Events。
  2. 让发布者用户可以通过统一 SSE 看到自己的资产治理通知。
  3. 建立 Market 与 Events 的单向依赖证据Market server 依赖 events-api不依赖 events-serverEvents server 不反向依赖 Market server。
  4. 为后续 Market source propagation / Account projection / handoff 事件扩展保留清晰边界。

非目标

  1. 不把 Market 32 operations 从 needs_verification 推进到 completed
  2. 不修改 Market / Events OpenAPI。
  3. 不修改 coverage scanner 或 coverage report。
  4. 不把 purchase、install、license、handoff token、authorization snapshot 或 Account projection 同步纳入第一切片。
  5. 不把 muse_market_account_projection 复用为 Events publish outbox。
  6. 不发布授权快照、安装详情、handoff token、目标 owner 私有事实、治理 preview 原始 riskSummary、管理员内部备注原文或完整 actionSnapshot。
  7. 不让 Events server 查询 Market 表。

推荐方案

事件选择

第一批只允许:

Market source fact 触发入口 Events eventType notification type SSE owner
muse_market_governance_action(actionType=delist) adminDelistAsset notification governance_action asset.publisherId
muse_market_governance_action(actionType=recall) adminRecallAsset notification governance_action asset.publisherId
muse_market_source_status_event(sourceStatus=recalled) adminRecallAsset notification governance_action event.ownerUserId

不把 previewGovernanceImpact 发布到 SSE。preview 只是管理员决策前的影响预览,不是用户必须实时感知的终态事实。

Payload allowlist

第一批 payload 只允许:

{
  "type": "governance_action",
  "message": "资产治理状态已更新",
  "resourceRef": {
    "resourceType": "market_asset",
    "resourceId": 1001
  },
  "timestamp": "2026-06-07T12:00:00"
}

执行版可以把 message 细化为“资产已下架”或“资产已召回”但不能放入管理员备注原文、治理证据、授权快照、handoff token、target owner 内部细节或错误堆栈。

Outbox 边界

推荐新增独立 Market Events publish outbox

  • source tablemuse_market_governance_action / muse_market_source_status_event
  • source tuplesourceOwner=marketsourceType=market_governance_actionmarket_source_statussourceId=actionId/sourceEventIdsourceRevision=revision
  • commandId稳定短幂等键建议 market_evt:<sha256-32>
  • 状态机:queued/running/retryable/published/dead_letter
  • claim必须原子领取具备 lease / retry / attempt ownership。
  • 终态回写:必须防 stale worker 覆盖新 claim 终态。
  • worker 默认关闭,配置启用后才 claim。

依赖边界

  • Market server 可以依赖 muse-module-events-api
  • Market server 不得依赖 muse-module-events-server
  • Events server 不得依赖 Market server。
  • muse-server 作为装配层可以同时包含 Market server 与 Events server。

关键取舍

  • 选择 governance/source status不选择 Account projection前者是 Market source owner 的用户可见事实;后者是 Account 查询读模型同步状态,复用会制造职责混乱。
  • 选择 publisher 可见,不选择 admin 可见SSE app 侧事件面向资源 owner管理员操作已由管理端审计和治理记录承载。
  • 使用 notification/governance_action,不新增 event typeEvents 合同已经声明该 subtype足够承载第一批摘要。
  • 第一切片不发布 handoffhandoff 涉及 token、授权摘要和目标 owner 消费,泄露面和跨 owner 行为更复杂,应后续单独设计。

影响范围

  • 直接影响:
    • Market governance/source status 事实发布链路。
    • Market server 依赖 events-api。
    • Market 本域 outbox / worker / migration / focused tests。
    • Events unified event focused E2E。
  • 间接影响:
    • P1R-7 completed approval 的证据链更完整。
  • 不影响:
    • OpenAPI 合同。
    • coverage scanner / coverage report。
    • Market 32 operations completion status。
    • Account projection 查询读模型。
    • handoff token 和目标 owner 授权消费。

风险与兼容性

  • 事件重复风险:同一治理动作 replay 不能创建多条 unified event必须用 commandId 与 source tuple 双重幂等。
  • 并发风险worker terminal update 必须绑定本次 claim attempt避免 stale worker 覆盖新 claim。
  • 敏感信息风险:reasonactionSnapshot、preview riskSummary 和 target owner 细节不能进入 payload。
  • 职责混淆风险Account projection outbox 只能继续服务 Account 读模型同步,不参与 Events publish。
  • 可见性风险ownerUserId 必须是 publisher / source fact owner不能使用 adminUserId否则发布者无法通过 app SSE 看到通知。
  • 兼容性:新增 outbox 与 worker 默认关闭,不改变现有 Market API 同步返回语义。

验收标准

审阅版通过后,执行版必须包含:

  1. Market outbox DO / Mapper / Service / Worker / 配置 / V19 migration 的文件边界。
  2. AdminMarketGovernanceServiceImpl 创建 governance/source status fact 后创建 outbox 的事务边界。
  3. payload allowlist 与敏感字段拒绝策略。
  4. worker success / duplicate / retryable / rejected / blocked / dead_letter / stale claim tests。
  5. Market governance source fact -> Market outbox -> worker -> EventsPublishApi -> muse_unified_event -> SSE visible focused E2E。
  6. dependency gateMarket server 有 events-api、无 events-serverEvents server 无 Market server。
  7. V19 SQL 静态 gate 与 Flyway _test
  8. P1R mixed gates 继续确认 Events / AI / Knowledge 已有 source owner gates 不回退Market 仍为 dedicated / needs_verification
  9. coverage scanner 只在 /tmp 隔离副本运行,真实 worktree protected diff 为空。

待确认项

  1. P1R-7d 第一切片是否确认只做 governance/source status而不做 purchase/install/handoff。
  2. notification/governance_action 的 message 是否允许按动作区分为“资产已下架 / 资产已召回”,还是统一为“资产治理状态已更新”。
  3. 如果 recall 同时产生 governance action 和 source status event执行版是否只发布一条 governance action 通知,还是允许两条不同 sourceType 的通知。