docs(p1r): 补齐 Market 真实 API 规格计划

This commit is contained in:
zizi 2026-06-03 15:56:53 +08:00
parent 1f0b18534c
commit f02defd367
3 changed files with 1120 additions and 0 deletions

View File

@ -0,0 +1,221 @@
# P1R6 Market 规格计划
日期2026-06-03
## 背景
本次进入 P1R-6 Market Real API 的规格、计划和 review gate 阶段只完成事实盘点、规格、执行计划、review 修订和阶段留痕,不进入代码实现。
真实工作面:
```text
/Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0
```
分支:
```text
dev/1.0.0
```
开始前已执行:
```bash
git status --short --branch
git log --oneline -5
git pull --ff-only origin dev/1.0.0
```
结果:
```text
## dev/1.0.0...origin/dev/1.0.0
48c750b test(p1r): 补齐 AI 与 Knowledge 外部端到端验收
Already up to date.
```
## 已验证事实
当前 coverage summary
```text
completedOperations 100
needsVerificationOperations 100
incompleteOperations 33
genericPersistenceOperations 32
ssePlaceholderOperations 1
```
当前按域状态:
```text
account 33 dedicated / needs_verification
ai 41 dedicated / completed
content 51 dedicated / needs_verification
events 1 sse_placeholder / incomplete
knowledge 59 dedicated / completed
market 32 generic_persistence / incomplete
meta 16 dedicated / needs_verification
```
Market 32 个 operation 当前全部为:
```text
generic_persistence / incomplete
```
当前 Market 实现事实:
- `docs/api-contracts/market/openapi.yaml` 声明 32 个 Market operation。
- `muse-module-market-server` 当前合同入口仍是 `AdminMuseMarketContractController``AppMuseMarketContractController`
- 当前 Market 合同入口统一委托 `MuseContractPersistenceService`,不能作为真实 API 完成证据。
- `muse-module-market-server` 当前只依赖 `muse-module-market-api`、security、mybatis。
- `muse-server` 当前同时装配 `muse-module-market-server``muse-module-member-server`
- `muse-module-member-server` 已有 `MarketAccountProjectionFacade`、默认 fail-closed `UnavailableMarketAccountProjectionFacade``muse_account_record_projection` DO/Mapper 和 V11 DDL。
当前 DDL 事实:
- V6 已有 Market 初始资产、版本、安装、发布申请、申诉和 handoff 表。
- V8 已有 workflow task、favorite、purchase 表。
- V11 已有 Account 查询读模型 `muse_account_record_projection`
- P1R-5 已使用 V14P1R-6 如新增迁移,推荐使用 `V15__extend_market_real_api_schema.sql`
## 本阶段产物
- 规格:`docs/superpowers/specs/2026-06-03-P1R-6-market-real-api-design.md`
- 计划:`docs/superpowers/plans/2026-06-03-P1R-6-market-real-api.md`
- 留痕:`docs/memorys/2026-06-03-P1R6Market规格计划.md`
## Review 结果
本阶段按要求执行 fresh review gate。
Spec compliance review
```text
PASS_WITH_WARNINGS
```
已修复首轮阻塞点:
- 计划开头错误写成只允许执行 `Task 1-12`,但正文实际包含 Task 13。已修为 `Task 1-13`
Spec review 非阻塞提醒:
- handoff token 业务状态里的 `completed` 不能和 coverage `completionStatus=completed` 混淆。计划已补充消歧说明。
Quality / feasibility review
```text
PASS_WITH_WARNINGS
```
已修复阻塞点:
- Task 5 不再要求 Market 模块另建同名 `MarketAccountProjectionFacade` / `UnavailableMarketAccountProjectionFacade`
- 已明确 P1R-6 Account 投影采用最小可执行接线方案:`muse-module-market-server` 显式依赖 `muse-module-member-server`,复用 member 侧既有 `MarketAccountProjectionFacade``AccountRecordProjectionDO``AccountRecordProjectionMapper`
- 已明确 `muse_market_account_projection` 只表达 Market 侧 projection sync / outbox 状态,不是 Account 查询读模型。
- 已明确 Account 查询读模型只能是 V11 已有 `muse_account_record_projection`
- 已要求实现阶段用 Maven reactor 或 dependency-tree 验证不形成 Maven 循环,并用 Spring context 测试证明真实 provider 替换默认 unavailable bean。
Quality review 非阻塞提醒:
- 当前 worktree 仍有 P1R-4 / P1R-5 coverage/test/script 未提交 diffP1R-6 spec/plan/memory 也是未跟踪文件。进入 P1R-6 实现前必须先提交或明确保留这些 diff避免阶段混账。
## 关键设计结论
- P1R-6 目标状态只能是 `dedicated / needs_verification`,不能写成 `completed`
- Market owner 是 `muse-module-market`负责市场来源侧事实、授权、安装、handoff、发布、治理和申诉。
- Market 不直接写 AI / Knowledge / Content canonical facts。
- 购买只产生授权,不等于安装;安装只进入账户可用列表,不等于绑定目标 owner。
- Account 只消费 Market 写入的投影Account 查询读模型为 `muse_account_record_projection`
- `needs_recheck` 不能作为 Market `SourceStatus` 值,只能表达为 action policy / recheck reasons。
- P1R-7 统一 Events SSE 不属于 P1R-6。
- 不修改 `docs/api-contracts/market/openapi.yaml`,不修改 scanner 掩盖缺口。
## 验证命令与结果
coverage audit
```bash
python3 muse-cloud/scripts/p1r-audit-api-coverage.py --check
```
结果:
```text
Generated docs/superpowers/reports/p1r-api-coverage.json
Generated docs/superpowers/reports/p1r-api-coverage.md
```
coverage 对账:
```bash
jq -r '.summary | [.completedOperations,.needsVerificationOperations,.incompleteOperations,.genericPersistenceOperations,.ssePlaceholderOperations] | @tsv' docs/superpowers/reports/p1r-api-coverage.json
jq -r '.operations[] | select(.domain == "market") | [.implementationStatus,.completionStatus] | @tsv' docs/superpowers/reports/p1r-api-coverage.json | sort | uniq -c
```
结果:
```text
100 100 33 32 1
32 generic_persistence incomplete
```
文档结构检查:
```bash
python3 - <<'PY'
import re, pathlib
plan=pathlib.Path('docs/superpowers/plans/2026-06-03-P1R-6-market-real-api.md').read_text()
spec=pathlib.Path('docs/superpowers/specs/2026-06-03-P1R-6-market-real-api-design.md').read_text()
print('plan_tasks', re.findall(r'^## Task (\d+):', plan, re.M))
print('spec_operation_rows', len(re.findall(r'^\| `[^`]+` \| (GET|POST|DELETE|PUT|PATCH) \| `/', spec, re.M)))
print('plan_operation_lines', len(re.findall(r'^[A-Za-z].+ (GET|POST|DELETE|PUT|PATCH) /', plan, re.M)))
PY
```
结果:
```text
plan_tasks ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13']
spec_operation_rows 32
plan_operation_lines 32
```
diff hygiene
```bash
git diff --check
```
结果:无输出。
OpenAPI diff 检查:
```bash
git status --short -- docs/api-contracts/market/openapi.yaml docs/api-contracts/ai/openapi.yaml docs/api-contracts/knowledge/openapi.yaml
```
结果:无输出。
## 当前阶段边界
本阶段只完成 P1R-6 规格、计划、review 修订和 memory 留痕,没有实现代码。
当前不应把任何 Market operation 标为 `completed`
## 下一步
进入 P1R-6 实现前必须先处理工作面:
1. 提交或明确保留 P1R-4 / P1R-5 coverage completed 推进 diff。
2. 提交或明确保留 P1R-6 spec / plan / memory 文档 diff。
3. 再按 `docs/superpowers/plans/2026-06-03-P1R-6-market-real-api.md` Task 1-13 执行。
实现阶段执行规则:
- 同一实现 Task 内复用最近 implementer。
- 新 Task 才 fresh implementer。
- 每个 Task 完成后仍必须 fresh spec review 和 fresh quality / feasibility review。
- review 结论不能替代真实运行态验收或 coverage `completed` 批准。

View File

@ -0,0 +1,534 @@
# P1R-6 Market Real API Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use `superpowers:subagent-driven-development` to implement this plan task-by-task. `superpowers:executing-plans` is acceptable only when subagents are unavailable. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 将 Market 32 个 operation 从 `generic_persistence / incomplete` 推进到专用 Market Controller / Service / DTO / DAL / DDL / 测试可验收的 `dedicated / needs_verification`
**Architecture:** 以 `muse-module-market` 为 owner新增 Market 合同专用 app/admin 入口和应用服务。Market 只持有来源侧市场事实、授权摘要、安装、handoff、发布审核和治理状态AI / Knowledge / Content 目标 owner 事实必须通过各自 owner 完成Market 不直接写入。Account 只消费 Market 写入 `muse_account_record_projection` 的投影,并通过 member 模块既有 `MarketAccountProjectionFacade` 判断投影是否可用,不成为 Market 的运行时代码 owner。
**Tech Stack:** Java 21、Spring Boot、Yudao `CommonResult<T>`、Spring Security `@PreAuthorize`、MyBatis Plus、PostgreSQL/Flyway、JUnit 5、Mockito/MockMvc、P1R coverage JSON。
**Implementation Status:** 本文件是 P1R-6 规格计划阶段产物review gate 待执行;当前不进入实现代码。收到“进入 P1R-6 实现阶段”后才允许按 Task 1-13 执行。
---
## 0. 执行边界
- 工作目录:`/Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0`
- 分支:`dev/1.0.0`
- 不在 `/Users/qingse/Sync/local-git/oh-my-muse` 的其他 checkout 上写阶段文档或实现代码。
- 不修改 `docs/api-contracts/market/openapi.yaml`
- 不修改 `docs/api-contracts/ai/openapi.yaml``docs/api-contracts/knowledge/openapi.yaml`
- 不修改 `muse-cloud/scripts/**` 把 Market 伪装成 `completed`
- 不破坏 AI 41、Knowledge 59 当前 `dedicated / completed`
- 不破坏 Content 51、Meta 16、Account 33 当前 `dedicated / needs_verification`
- 不把 Market operation 标为 `completed`
- 不跨入 P1R-7 统一 `/app-api/muse/events`
- 如果新增或修改 DDL阶段收口前必须在同一 PostgreSQL 实例的 `_test` 数据库跑真实 Flyway。
## 1. 当前事实盘点
Market operation 清单:
```text
listMarketplaceAssets GET /app-api/muse/marketplace/assets
listMarketplaceCategories GET /app-api/muse/marketplace/categories
listMarketplaceRecommendations GET /app-api/muse/marketplace/recommendations
getMarketplaceAsset GET /app-api/muse/marketplace/assets/{assetId}
favoriteAsset POST /app-api/muse/marketplace/assets/{assetId}/favorite
unfavoriteAsset DELETE /app-api/muse/marketplace/assets/{assetId}/favorite
purchaseAsset POST /app-api/muse/marketplace/assets/{assetId}/purchase
installMarketplaceAsset POST /app-api/muse/marketplace/assets/{assetId}/install
createBindPrecheck POST /app-api/muse/marketplace/assets/{assetId}/bind-precheck
createMarketplaceHandoff POST /app-api/muse/marketplace/handoffs
getHandoffStatus GET /app-api/muse/marketplace/handoffs/{handoffToken}
cancelHandoff POST /app-api/muse/marketplace/handoffs/{handoffToken}/cancel
savePublishDraft POST /app-api/muse/marketplace/publish-drafts
runPublishCheck POST /app-api/muse/marketplace/publish-drafts/{draftId}/checks
submitPublishRequest POST /app-api/muse/marketplace/publish-requests
withdrawPublishRequest POST /app-api/muse/marketplace/publish-requests/{requestId}/withdraw
listMyPublishRecords GET /app-api/muse/marketplace/my-publish-records
getGovernanceImpact GET /app-api/muse/marketplace/assets/{assetId}/governance-impact
submitAppeal POST /app-api/muse/marketplace/appeals
supplementAppeal POST /app-api/muse/marketplace/appeals/{appealId}/supplements
withdrawAppeal POST /app-api/muse/marketplace/appeals/{appealId}/withdraw
adminListMarketAssets GET /admin-api/muse/market/assets
adminGetMarketAsset GET /admin-api/muse/market/assets/{assetId}
adminPreviewGovernanceImpact POST /admin-api/muse/market/assets/{assetId}/governance-impact
adminDelistAsset POST /admin-api/muse/market/assets/{assetId}/delist
adminRecallAsset POST /admin-api/muse/market/assets/{assetId}/recall
adminListPublishRequests GET /admin-api/muse/market/publish-requests
adminApprovePublishRequest POST /admin-api/muse/market/publish-requests/{requestId}/approve
adminRejectPublishRequest POST /admin-api/muse/market/publish-requests/{requestId}/reject
adminListAppeals GET /admin-api/muse/market/appeals
adminGetAppeal GET /admin-api/muse/market/appeals/{appealId}
adminResolveAppeal POST /admin-api/muse/market/appeals/{appealId}/resolve
```
全部 32 个当前状态均为 `generic_persistence / incomplete`,当前实现 owner 是 `AdminMuseMarketContractController` / `AppMuseMarketContractController` + `MuseContractPersistenceService`
## 2. 子代理执行规则
同一实现 Task 内,复用最近一次负责该任务的 implementer只有进入新的实现 Task 时,才启用 fresh implementer。
每个实现 Task 完成后必须两轮 fresh review
1. spec compliance review检查是否符合 `docs/superpowers/specs/2026-06-03-P1R-6-market-real-api-design.md` 和本计划。
2. quality / feasibility review检查最小改动、可维护性、测试质量、外部 owner 失败路径、无脚本掩盖。
review 未通过不能进入下一 Task。review 修复仍属于同一实现 Task复用最近 implementer重新 review 必须 fresh reviewer。
## Task 1: Preflight 与覆盖基线冻结
**Files:**
- Read: `docs/superpowers/reports/p1r-api-coverage.json`
- Read: `docs/superpowers/reports/p1r-api-coverage.md`
- Read: `docs/api-contracts/market/openapi.yaml`
- Read: `muse-cloud/muse-module-market/**`
- Read: `muse-cloud/sql/muse/**`
- Read: `docs/memorys/2026-06-03-P1R4P1R5完成状态推进.md`
- [ ] **Step 1: 核实工作面**
Run:
```bash
git status --short --branch
```
Expected:
```text
## dev/1.0.0...origin/dev/1.0.0
```
进入实现前P1R-4 / P1R-5 coverage 状态推进和 P1R-6 spec/plan 必须已提交,或明确作为唯一待提交文档/coverage diff 存在。不得混入其它代码 diff。
- [ ] **Step 2: 统计 Market operation 状态**
Run:
```bash
jq -r '.operations[] | select(.domain == "market") | [.implementationStatus,.completionStatus] | @tsv' docs/superpowers/reports/p1r-api-coverage.json | sort | uniq -c
```
Expected:
```text
32 generic_persistence incomplete
```
- [ ] **Step 3: 冻结 operation 清单**
Run:
```bash
jq -r '.operations[] | select(.domain == "market") | [.operationId,.method,.path,.implementationStatus,.completionStatus] | @tsv' docs/superpowers/reports/p1r-api-coverage.json
```
Expected: 输出 32 行,且 operationId 与本计划第 1 节一致。
- [ ] **Step 4: 检查禁止修改面**
Run:
```bash
git status --short -- docs/api-contracts/market/openapi.yaml docs/api-contracts/ai/openapi.yaml docs/api-contracts/knowledge/openapi.yaml muse-cloud/scripts
```
Expected: 无输出;如果存在 P1R-4 / P1R-5 coverage 脚本已批准改动,必须在进入 P1R-6 实现前先提交。
## Task 2: Market 基础设施与 V15 DDL
**Files:**
- Modify: `muse-cloud/muse-module-market/muse-module-market-server/pom.xml`
- Create/Modify: `muse-cloud/muse-module-market/muse-module-market-api/src/main/java/cn/iocoder/muse/module/market/enums/ErrorCodeConstants.java`
- Create: `muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/domain/muse/*.java`
- Create: `muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/application/muse/*.java`
- Create: `muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/dal/dataobject/muse/*.java`
- Create: `muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/dal/mysql/muse/*.java`
- Create: `muse-cloud/sql/muse/V15__extend_market_real_api_schema.sql`
- Create: `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rMarketMigrationSqlTest.java`
- [ ] **Step 1: 确认 Market server 模块依赖**
确认或补齐 validation、web、security、mybatis、test 依赖。P1R-6 Account 投影采用最小可执行接线方案:`muse-module-market-server` 显式依赖 `muse-module-member-server`,复用 member 侧既有 `MarketAccountProjectionFacade``AccountRecordProjectionDO``AccountRecordProjectionMapper`。当前 `member-server` 不依赖 `market-server`,该依赖方向不得形成 Maven 循环;实现时必须用 Maven reactor 或 dependency-tree 验证。不要引入 AI / Knowledge / Content 作为强 owner 依赖;跨 owner 能力通过本模块 facade 明确隔离。
- [ ] **Step 2: 增加 Market 错误码**
至少覆盖:
- `MARKET_API_VERSION_UNSUPPORTED`
- `MARKET_COMMAND_ID_REQUIRED`
- `MARKET_COMMAND_ID_CONFLICT`
- `MARKET_ASSET_NOT_EXISTS`
- `MARKET_ASSET_NOT_LISTED`
- `MARKET_ASSET_GOVERNANCE_BLOCKED`
- `MARKET_LICENSE_NOT_EXISTS`
- `MARKET_LICENSE_NOT_PURCHASABLE`
- `MARKET_INSTALL_NOT_EXISTS`
- `MARKET_INSTALL_NOT_BINDABLE`
- `MARKET_HANDOFF_NOT_EXISTS`
- `MARKET_HANDOFF_EXPIRED`
- `MARKET_HANDOFF_NOT_CANCELLABLE`
- `MARKET_PUBLISH_DRAFT_NOT_EXISTS`
- `MARKET_PUBLISH_CHECK_NOT_EXISTS`
- `MARKET_PUBLISH_CHECK_EXPIRED`
- `MARKET_PUBLISH_REQUEST_NOT_EXISTS`
- `MARKET_PUBLISH_REQUEST_STATUS_CONFLICT`
- `MARKET_GOVERNANCE_PREVIEW_REQUIRED`
- `MARKET_APPEAL_NOT_EXISTS`
- `MARKET_APPEAL_STATUS_CONFLICT`
- `MARKET_TARGET_OWNER_UNAVAILABLE`
- `MARKET_ACCOUNT_PROJECTION_UNAVAILABLE`
- [ ] **Step 3: 编写 V15 迁移**
至少新增或扩展:
- `muse_market_command`
- `muse_market_authorization_snapshot`
- `muse_market_authorization_summary`
- `muse_market_handoff_event`
- `muse_market_publish_draft`
- `muse_market_publish_check`
- `muse_market_review_event`
- `muse_market_governance_preview`
- `muse_market_governance_action`
- `muse_market_governance_impact`
- `muse_market_appeal_material`
- `muse_market_appeal_event`
- `muse_market_account_projection`
- `muse_market_source_status_event`
DDL 必须有 tenant、command、status、revision、audit 时间、必要唯一约束和查询索引。其中 `muse_market_account_projection` 只表达 Market 侧投影同步/outbox 状态,不是 Account 查询读模型Account 查询读模型只能是 V11 已有的 `muse_account_record_projection`
- [ ] **Step 4: DDL 静态测试**
`P1rMarketMigrationSqlTest` 至少验证:
- V15 文件存在。
- 新表名存在。
- `muse_market_command``command_id``request_hash` 和唯一约束。
- handoff token 不以明文作为唯一安全依据,必须存在 token hash 或等价字段。
- governance action / preview / impact 三类事实不被压成一个字段。
## Task 3: Market command、version、owner guard
**Files:**
- Create: `.../domain/muse/MarketApiVersionGuard.java`
- Create: `.../domain/muse/MarketCommandGuard.java`
- Create: `.../domain/muse/MarketOwnerGuard.java`
- Create: `.../application/muse/MarketCommandService.java`
- Create: `.../application/muse/MarketCommandServiceImpl.java`
- Test: `.../application/muse/MarketCommandServiceTest.java`
- [ ] **Step 1: 实现 API version guard**
所有 dedicated Controller 入口必须校验 `X-API-Version`,不支持版本返回业务错误,不进入应用服务写事实。
- [ ] **Step 2: 实现 command 幂等 guard**
相同 command + 相同 request hash 返回已保存结果;相同 command + 不同 request hash 返回冲突。
- [ ] **Step 3: 实现 owner/tenant guard**
App 查询只能看当前用户可见资产、授权、安装、发布记录和申诉。Admin 查询必须保留权限注解,不能用 app user 可见性替代。
## Task 4: 资产发现、分类、推荐、详情、收藏
**Files:**
- Create: `.../controller/app/muse/AppMuseMarketplaceAssetController.java`
- Create: `.../controller/app/muse/vo/*.java`
- Create: `.../application/muse/MarketAssetQueryService.java`
- Create: `.../application/muse/MarketFavoriteService.java`
- Test: `.../controller/app/muse/AppMuseMarketplaceAssetControllerTest.java`
- Test: `.../application/muse/MarketFavoriteServiceTest.java`
- [ ] **Step 1: 实现资产列表、分类、推荐、详情**
读取 Market 资产、版本和展示摘要。无独立推荐数据时可以使用可解释 fallback 排序,但必须在响应摘要中体现来源,不允许 fake 个性化。
- [ ] **Step 2: 实现收藏/取消收藏**
`muse_market_favorite`,保持幂等。取消收藏不能删除审计事实,只能更新状态。
- [ ] **Step 3: 测试合同字段和可见性**
测试覆盖 listed/delisted/recall、当前用户收藏状态、分页结构、未登录和不可见资产。
## Task 5: 授权购买、安装和 Account 投影
**Files:**
- Create: `.../controller/app/muse/AppMuseMarketLicenseController.java`
- Create: `.../application/muse/MarketLicenseService.java`
- Create: `.../application/muse/MarketInstallService.java`
- Create: `.../application/muse/MarketAccountProjectionProvider.java`
- Implement: `cn.iocoder.muse.module.member.application.account.facade.MarketAccountProjectionFacade` provider bean
- Use: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/dataobject/account/AccountRecordProjectionDO.java`
- Use: `muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/dal/mysql/account/AccountRecordProjectionMapper.java`
- Test: `.../application/muse/MarketLicenseServiceTest.java`
- Test: `.../application/muse/MarketInstallServiceTest.java`
- Test: `.../application/muse/MarketAccountProjectionProviderTest.java`
- Test: `muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/application/account/AccountMarketRecordServiceTest.java`
- [ ] **Step 1: 实现 purchaseAsset**
校验资产可获取、许可可用、治理策略允许新获取。写购买/授权快照,并向既有 `muse_account_record_projection` 写入 `purchase` / `license` 投影。重复 command 返回同一授权结果。
- [ ] **Step 2: 实现 installMarketplaceAsset**
安装必须消费有效授权。安装智能体和知识库只进入账户可用列表,并更新 Account `license` 投影状态;不写 AI / Knowledge 目标事实。作品资产不走安装流程。
- [ ] **Step 3: Account projection fail-closed**
不得在 Market 模块另建同名 `MarketAccountProjectionFacade``UnavailableMarketAccountProjectionFacade` 作为运行态契约。Market 必须通过 `market-server -> member-server` 依赖对接 member 模块既有 `cn.iocoder.muse.module.member.application.account.facade.MarketAccountProjectionFacade`,并提供真实 provider bean 替换 member 默认 auto-configuration 注册的 unavailable bean当 Market projection provider 未接入时Account 查询继续 fail-closed当 provider 接入且投影写入成功后,测试必须证明 Account `purchase` / `license` / `publish` 查询不再命中默认 unavailable 实现。投影写入失败时Market 业务事实只能记录为 projection pending / blocked不能伪造成 Account 已同步。
## Task 6: 来源授权摘要与 Handoff
**Files:**
- Create: `.../controller/app/muse/AppMuseMarketHandoffController.java`
- Create: `.../application/muse/MarketHandoffService.java`
- Create: `.../application/muse/facade/MarketTargetOwnerFacade.java`
- Create: `.../application/muse/facade/UnavailableMarketTargetOwnerFacade.java`
- Test: `.../application/muse/MarketHandoffServiceTest.java`
- Test: `.../controller/app/muse/AppMuseMarketHandoffControllerTest.java`
- [ ] **Step 1: 实现 createBindPrecheck**
生成来源侧 authorization summary 和 authorization snapshot。结果不能包含目标 owner precheck ID。
- [ ] **Step 2: 实现 createMarketplaceHandoff**
生成一次性 handoff token、token hash、过期时间和目标页。Market 不消费 token不写目标 owner。
- [ ] **Step 3: 实现 getHandoffStatus / cancelHandoff**
查询不改变状态。取消只能取消 pending / owner_precheck_created 前的 token已 completed、expired、cancelled 不可取消。这里的 `completed` 只表示 handoff token 业务生命周期状态,不等于 coverage `completionStatus=completed`,不得据此推进 Market operation completed。
## Task 7: 发布草稿、发布检查、提交与撤回
**Files:**
- Create: `.../controller/app/muse/AppMuseMarketPublishController.java`
- Create: `.../application/muse/MarketPublishService.java`
- Test: `.../application/muse/MarketPublishServiceTest.java`
- Test: `.../controller/app/muse/AppMuseMarketPublishControllerTest.java`
- [ ] **Step 1: 实现 savePublishDraft**
保存发布材料草稿,不提交审核、不上架。作品资产高阶模式只允许保存为 `read_only_favorite_license`
- [ ] **Step 2: 实现 runPublishCheck**
检查权利、隐私、许可、治理和材料 hash。检查通过只允许 submit不上架。
- [ ] **Step 3: 实现 submitPublishRequest / withdrawPublishRequest / listMyPublishRecords**
提交必须原子消费未过期、匹配草稿版本和材料 hash 的检查结果。撤回只允许非终态申请。
## Task 8: 管理端审核、上架、拒绝
**Files:**
- Create: `.../controller/admin/muse/AdminMuseMarketReviewController.java`
- Create: `.../application/muse/AdminMarketReviewService.java`
- Test: `.../application/muse/AdminMarketReviewServiceTest.java`
- Test: `.../controller/admin/muse/AdminMuseMarketReviewControllerTest.java`
- [ ] **Step 1: 实现 adminListPublishRequests**
支持审核状态、资产类型、风险标签、发布者筛选。
- [ ] **Step 2: 实现 adminApprovePublishRequest**
通过必须消费审核校验结果,写审核事件,更新资产/版本为 listed可见状态必须可查询。
- [ ] **Step 3: 实现 adminRejectPublishRequest**
拒绝必须写理由和证据标签,发布者可后续申诉。终态申请不可重复审核。
## Task 9: 管理端资产治理、下架、召回和影响预览
**Files:**
- Create: `.../controller/admin/muse/AdminMuseMarketAssetController.java`
- Create: `.../application/muse/AdminMarketGovernanceService.java`
- Test: `.../application/muse/AdminMarketGovernanceServiceTest.java`
- Test: `.../controller/admin/muse/AdminMuseMarketAssetControllerTest.java`
- [ ] **Step 1: 实现 adminListMarketAssets / adminGetMarketAsset**
管理端详情必须包含版本、授权、安装、治理和来源摘要。
- [ ] **Step 2: 实现 adminPreviewGovernanceImpact**
生成影响预览覆盖授权、安装、handoff、绑定摘要、运行中任务、Shadow 候选、Knowledge Draft 和导出限制。
- [ ] **Step 3: 实现 adminDelistAsset / adminRecallAsset**
必须消费有效 `impactPreviewId` 和 expectedStatus。召回要写 source status propagation 事实owner facade 不可用时记录 blocked并把需要重验的信息写入 action policy / recheck reasons`needs_recheck` 不能作为 Market `SourceStatus` 值。
## Task 10: 申诉提交、补充、撤回与管理端处理
**Files:**
- Create: `.../controller/app/muse/AppMuseMarketAppealController.java`
- Create: `.../controller/admin/muse/AdminMuseMarketAppealController.java`
- Create: `.../application/muse/MarketAppealService.java`
- Test: `.../application/muse/MarketAppealServiceTest.java`
- Test: `.../controller/app/muse/AppMuseMarketAppealControllerTest.java`
- Test: `.../controller/admin/muse/AdminMuseMarketAppealControllerTest.java`
- [ ] **Step 1: 实现用户端申诉**
提交、补充、撤回必须校验申诉期限、关联关系和 expectedStatus。补充材料保存脱敏摘要不记录密钥或无关正文全文。
- [ ] **Step 2: 实现管理端申诉查询与处理**
只读取申诉材料和发布资产,不读取用户私有副本。恢复上架必须消费治理影响预览。
## Task 11: Retire Market 合同兜底与 coverage gate
**Files:**
- Modify: `muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/admin/AdminMuseMarketContractController.java`
- Modify: `muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/app/AppMuseMarketContractController.java`
- Create: `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rMarketRealApiGateTest.java`
- Create: `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rMarketRouteOwnershipTest.java`
- [ ] **Step 1: 精确退役 32 个 Market 路由兜底**
合同兜底 Controller 不能继续捕获 P1R-6 32 个路由。可以删除或精确避让,但必须由 route ownership test 证明。
- [ ] **Step 2: coverage gate**
`P1rMarketRealApiGateTest` 必须证明:
- Market operation 数量为 32。
- 32 个 operation 全部 `dedicated / needs_verification`
- Market 不包含 `generic_persistence``catch_all``sse_placeholder``missing`
- `completedOperations` 仍为 100。
- AI / Knowledge 仍是 `dedicated / completed`
- Content / Meta / Account 仍是 `dedicated / needs_verification`
- Events P1R-7 `streamEvents` 仍是唯一 SSE placeholder。
- [ ] **Step 3: route ownership gate**
`P1rMarketRouteOwnershipTest` 必须证明 32 个 Market 路由 handler 不属于 `*MarketContractController`,且不调用 `MuseContractPersistenceService`
## Task 12: PostgreSQL / Flyway `_test` 迁移验收
**Files:**
- Create: `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rMarketFlywayMigrationIT.java`
- [ ] **Step 1: 构建 reactor**
Run:
```bash
cd muse-cloud
JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" \
mvn -o clean install -DskipTests -Dspring-boot.repackage.skip=true -pl muse-server -am
```
- [ ] **Step 2: 跑真实 PostgreSQL / Flyway**
Run:
```bash
cd muse-cloud
set -a
. ~/.config/muse-repo/infra.env
set +a
export P1R_FLYWAY_PASSWORD="$MUSE_POSTGRES_PASSWORD"
P1R6_TEST_DB="${P1R6_TEST_DB:-muse_local_p1r6_test}"
JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" \
mvn -o test -pl muse-server \
-Dtest=P1rMarketFlywayMigrationIT \
-Dp1r.flyway.url="jdbc:postgresql://${MUSE_POSTGRES_HOST}:${MUSE_POSTGRES_PORT}/${P1R6_TEST_DB}" \
-Dp1r.flyway.user="$MUSE_POSTGRES_USERNAME" \
-Dp1r.flyway.locations="filesystem:sql/muse"
```
Expected:
```text
migrations_executed >= 15
target_schema_version = 15
flyway_latest = 15:extend market real api schema
```
## Task 13: 最终验证、报告对账与 memory
**Files:**
- Modify: `docs/superpowers/reports/p1r-api-coverage.json`
- Modify: `docs/superpowers/reports/p1r-api-coverage.md`
- Create: `docs/memorys/YYYY-MM-DD-P1R6Market真实API收口.md`
- [ ] **Step 1: 重新生成 coverage**
Run:
```bash
python3 muse-cloud/scripts/p1r-audit-api-coverage.py --check
```
- [ ] **Step 2: 对账 coverage**
Run:
```bash
jq -r '.operations | group_by(.domain)[] | [.[0].domain, (length|tostring), ([group_by(.implementationStatus + "/" + .completionStatus)[] | (.[0].implementationStatus + "/" + .[0].completionStatus + ":" + (length|tostring))] | join(", "))] | @tsv' docs/superpowers/reports/p1r-api-coverage.json
jq -r '.summary | [.completedOperations,.needsVerificationOperations,.incompleteOperations,.genericPersistenceOperations,.ssePlaceholderOperations] | @tsv' docs/superpowers/reports/p1r-api-coverage.json
```
Expected:
```text
market dedicated/needs_verification:32
completedOperations = 100
genericPersistenceOperations = 0
ssePlaceholderOperations = 1
```
- [ ] **Step 3: Maven gate**
Run:
```bash
cd muse-cloud
JAVA_HOME=$(/usr/libexec/java_home -v 21) mvn -pl muse-server -Dtest=P1rApiCoverageReportTest,P1rMarketRealApiGateTest,P1rMarketRouteOwnershipTest,P1rMarketMigrationSqlTest test
```
- [ ] **Step 4: focused tests**
Run the focused Market service/controller tests created in Tasks 3-11.
- [ ] **Step 5: diff hygiene**
Run:
```bash
git diff --check
git status --short -- docs/api-contracts/market/openapi.yaml docs/api-contracts/ai/openapi.yaml docs/api-contracts/knowledge/openapi.yaml
```
Expected: no OpenAPI diff and no whitespace errors.
## 3. Review handoff
完成本计划文档后必须执行两轮 fresh review
1. spec compliance review确认本计划覆盖 `docs/superpowers/specs/2026-06-03-P1R-6-market-real-api-design.md`,没有跨入目标 owner 事实写入。
2. quality / feasibility review确认任务拆分、DDL、测试门禁、失败路径和验证命令足够可执行。
review 通过前不得进入 P1R-6 代码实现。

View File

@ -0,0 +1,365 @@
# P1R-6Market Real API 规格
- 版本v1
- 日期2026-06-03
- 状态review gate 待执行
- 上游规格:`docs/superpowers/specs/2026-05-25-P1R-muse-cloud-real-api-design.md`
- 基线输入:`docs/superpowers/reports/p1r-api-coverage.json`
- 范围:`muse-cloud/muse-module-market/**` 中 Market 专用实现、Market 相关追加迁移、授权/安装/handoff/发布/治理/申诉状态机、P1R-6 覆盖门禁
- 非范围P1R-7 统一 Events SSE、目标 owner 绑定确认、AI / Knowledge / Content canonical 写入、修改 `docs/api-contracts/market/openapi.yaml`、把 Market operation 标为 `completed`
## 1. 结论
P1R-6 的目标不是继续用 `MuseContractPersistenceService` 记录市场合同请求,也不是把 Market 设计成能直接替目标 owner 写入作品、智能体槽位或知识库绑定事实的“中间缝合层”。
本阶段要把 Market 域从“通用持久化可响应”推进到“专用 Market API 可验证”:
1. Market 32 个 operation 当前全部是 `generic_persistence / incomplete`,必须退出通用持久化完成口径。
2. Market owner 落在 `muse-module-market`,负责市场资产、版本、分类/推荐曝光、收藏、购买授权、安装、来源授权摘要、handoff、发布草稿、发布检查、发布申请、管理端审核、下架、召回和申诉。
3. Market 只生成来源侧授权摘要和 handoff token。目标 owner 的预检、确认和事实写入仍由 AI、Knowledge 或 Content 自己完成。
4. 购买只产生授权记录,不等于安装;安装只把资产放入账户可用列表,不等于绑定作品或写目标事实。
5. 作品资产高阶模式默认关闭。未完成 ADR、Schema/API、lineage 和授权快照前,只允许 `read_only_favorite_license`
6. 下架/召回必须形成治理影响预览、状态传播和审计事实,不能只改 `listing_status`
7. P1R-6 实现通过后的覆盖目标只能是 `dedicated / needs_verification`。没有 P1R-7 真实跨域端到端验收前Market 不能写成 `completed`
## 2. 已验证事实
### 2.1 执行工作面
真实工作面:
```text
/Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0
```
当前分支:
```text
dev/1.0.0
```
当前 worktree 已存在 P1R-4 / P1R-5 coverage 状态推进相关未提交 diff。进入 P1R-6 实现前,必须先提交或明确保留这些已验证改动,避免新阶段实现和上一阶段 coverage 收口混在不可追踪状态里。
### 2.2 覆盖矩阵
当前全局 summary
```text
completedOperations 100
needsVerificationOperations 100
incompleteOperations 33
genericPersistenceOperations 32
ssePlaceholderOperations 1
```
按域状态:
```text
account 33 dedicated / needs_verification
ai 41 dedicated / completed
content 51 dedicated / needs_verification
events 1 sse_placeholder / incomplete
knowledge 59 dedicated / completed
market 32 generic_persistence / incomplete
meta 16 dedicated / needs_verification
```
P1R-6 preflight 命令:
```bash
jq -r '.operations[] | select(.domain == "market") | [.operationId,.method,.path,.targetStage,.implementationStatus,.completionStatus] | @tsv' docs/superpowers/reports/p1r-api-coverage.json
```
输出事实32 行,全部为 `P1R-6 Market Real API / generic_persistence / incomplete`
### 2.3 OpenAPI 事实
`docs/api-contracts/market/openapi.yaml` 声明 32 个 Market operation
| 分组 | 数量 | operation |
|---|---:|---|
| 用户端发现 | 4 | `listMarketplaceAssets``listMarketplaceCategories``listMarketplaceRecommendations``getMarketplaceAsset` |
| 收藏 | 2 | `favoriteAsset``unfavoriteAsset` |
| 授权与安装 | 2 | `purchaseAsset``installMarketplaceAsset` |
| Handoff | 4 | `createBindPrecheck``createMarketplaceHandoff``getHandoffStatus``cancelHandoff` |
| 发布 | 5 | `savePublishDraft``runPublishCheck``submitPublishRequest``withdrawPublishRequest``listMyPublishRecords` |
| 用户端治理与申诉 | 4 | `getGovernanceImpact``submitAppeal``supplementAppeal``withdrawAppeal` |
| 管理端资产治理 | 5 | `adminListMarketAssets``adminGetMarketAsset``adminPreviewGovernanceImpact``adminDelistAsset``adminRecallAsset` |
| 管理端发布审核 | 3 | `adminListPublishRequests``adminApprovePublishRequest``adminRejectPublishRequest` |
| 管理端申诉 | 3 | `adminListAppeals``adminGetAppeal``adminResolveAppeal` |
关键合同约束:
1. 所有接口使用 `X-API-Version`
2. 写命令使用 `commandId` 并结合 `expectedStatus` 或检查快照防止盲写。
3. `purchaseAsset` 只获取授权,不安装、不绑定、不写目标 owner。
4. `installMarketplaceAsset` 只写安装事实,不写作品事实。
5. `createBindPrecheck` 只生成来源侧授权摘要和 handoff 准备信息,不生成目标 owner 预检 ID。
6. `createMarketplaceHandoff` 只生成一次性 token 和目标页,不替换绑定、不解绑、不降权、不改作品事实。
7. `runPublishCheck` 只证明草稿可提交审核,不直接上架。
8. `submitPublishRequest` 必须原子消费未过期且匹配草稿 hash 的发布检查结果。
9. `adminDelistAsset` / `adminRecallAsset` 必须绑定治理影响预览,不能盲下架或盲召回。
10. 申诉处理只能读取申诉材料和发布资产,不读取用户私有副本。
### 2.4 当前代码事实
当前 Market 合同入口:
- `muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/admin/AdminMuseMarketContractController.java`
- `muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/app/AppMuseMarketContractController.java`
两个 Controller 都统一委托:
```text
MuseContractPersistenceService.handle(...)
```
当前 `muse-module-market-server` 只有合同 Controller 和 `package-info.java`,没有 Market Application Service、专用 VO/DTO、DO、Mapper、状态机、owner facade 或 P1R-6 gate test。
`muse-server/pom.xml` 已装配:
```text
muse-module-market-server
```
因此 P1R-6 实现应继续在 `muse-module-market-server` 内落 owner不需要新增合同模块或把 Market 逻辑写入 Account、AI、Knowledge 或 Content。
### 2.5 当前 DDL
`muse-cloud/sql/muse/V6__init_market_schema.sql` 已有:
- `muse_market_asset`
- `muse_market_asset_version`
- `muse_market_installation`
- `muse_market_publish_request`
- `muse_market_appeal`
- `muse_market_handoff`
`muse-cloud/sql/muse/V8__add_contract_workflow_and_market_interaction.sql` 已有:
- `muse_domain_workflow_task`
- `muse_market_favorite`
- `muse_market_purchase`
这些表不足以完成 P1R-6
1. 没有 Market 专用 command/requestHash/replay 表。
2. 没有来源侧授权摘要、授权快照、兼容性结果和 handoff 消费状态的独立事实。
3. 没有发布草稿、发布检查、发布检查快照、发布材料 hash、审核校验结果和审核证据记录。
4. 没有治理影响预览、治理动作、治理传播、受影响授权/安装/绑定/任务/候选的可查询结果。
5. 没有申诉补充材料、申诉处理历史、申诉证据脱敏摘要。
6. 没有分类/推荐/曝光读模型或可降级策略。
7. 没有 Account 投影同步状态,无法证明购买、安装、授权能被 Account 查询消费。
P1R-5 已使用 V14P1R-6 如新增迁移,推荐使用:
```text
muse-cloud/sql/muse/V15__extend_market_real_api_schema.sql
```
## 3. 目标
1. 将 Market 32 个 operation 从 `generic_persistence / incomplete` 推进到 `dedicated / needs_verification`
2. 建立 `muse-module-market` 专用 Admin/App Controller、Application Service、VO/DTO、DO、Mapper、Assembler 和 domain guard。
3. 建立 Market command 幂等、API version guard、tenant/user/owner guard、expectedStatus guard。
4. 建立资产、版本、分类、推荐、详情和收藏真实读写模型。
5. 建立购买授权、安装、Account projection 同步状态和授权快照。
6. 建立来源侧 bind precheck、authorization summary、authorization snapshot 和 handoff token 生命周期。
7. 建立发布草稿、发布检查、发布申请、撤回和我的发布记录状态机。
8. 建立管理端审核、下架、召回、治理影响预览和申诉处理状态机。
9. 建立 owner facades明确 Account、AI、Knowledge、Content 不可用时的 fail-closed 边界。
10. 建立 P1R-6 coverage gate防止 Market operation 继续被合同兜底、通用持久化或 `completed` 混淆。
## 4. 非目标
1. 不修改 Market OpenAPI 来适配当前代码。
2. 不修改 scanner 掩盖 Market 仍未 dedicated 的事实。
3. 不把 Market operation 标为 `completed`
4. 不实现 P1R-7 `/app-api/muse/events`
5. 不让 Market 直接写 AI agent slot、Knowledge binding、Content work/block/canonical 事实。
6. 不在 P1R-6 开放作品资产 `full``reference``context_use` 高阶模式。
7. 不把 `MuseContractPersistenceService`、空列表、固定样例或 `muse_domain_workflow_task` 原始行作为完成证据。
8. 不把 Account、AI、Knowledge、Content owner unavailable 伪造成 success。
## 5. Operation 清单与目标 owner
| operationId | Method | Path | 当前状态 | P1R-6 owner | P1R-6 目标 |
|---|---|---|---|---|---|
| `listMarketplaceAssets` | GET | `/app-api/muse/marketplace/assets` | `generic_persistence / incomplete` | Market Asset Query | `dedicated / needs_verification` |
| `listMarketplaceCategories` | GET | `/app-api/muse/marketplace/categories` | `generic_persistence / incomplete` | Market Discovery Query | `dedicated / needs_verification` |
| `listMarketplaceRecommendations` | GET | `/app-api/muse/marketplace/recommendations` | `generic_persistence / incomplete` | Market Discovery Query | `dedicated / needs_verification` |
| `getMarketplaceAsset` | GET | `/app-api/muse/marketplace/assets/{assetId}` | `generic_persistence / incomplete` | Market Asset Query | `dedicated / needs_verification` |
| `favoriteAsset` | POST | `/app-api/muse/marketplace/assets/{assetId}/favorite` | `generic_persistence / incomplete` | Market Favorite Command | `dedicated / needs_verification` |
| `unfavoriteAsset` | DELETE | `/app-api/muse/marketplace/assets/{assetId}/favorite` | `generic_persistence / incomplete` | Market Favorite Command | `dedicated / needs_verification` |
| `purchaseAsset` | POST | `/app-api/muse/marketplace/assets/{assetId}/purchase` | `generic_persistence / incomplete` | Market License Command | `dedicated / needs_verification` |
| `installMarketplaceAsset` | POST | `/app-api/muse/marketplace/assets/{assetId}/install` | `generic_persistence / incomplete` | Market Install Command | `dedicated / needs_verification` |
| `createBindPrecheck` | POST | `/app-api/muse/marketplace/assets/{assetId}/bind-precheck` | `generic_persistence / incomplete` | Market Handoff Source Command | `dedicated / needs_verification` |
| `createMarketplaceHandoff` | POST | `/app-api/muse/marketplace/handoffs` | `generic_persistence / incomplete` | Market Handoff Command | `dedicated / needs_verification` |
| `getHandoffStatus` | GET | `/app-api/muse/marketplace/handoffs/{handoffToken}` | `generic_persistence / incomplete` | Market Handoff Query | `dedicated / needs_verification` |
| `cancelHandoff` | POST | `/app-api/muse/marketplace/handoffs/{handoffToken}/cancel` | `generic_persistence / incomplete` | Market Handoff Command | `dedicated / needs_verification` |
| `savePublishDraft` | POST | `/app-api/muse/marketplace/publish-drafts` | `generic_persistence / incomplete` | Market Publish Draft Command | `dedicated / needs_verification` |
| `runPublishCheck` | POST | `/app-api/muse/marketplace/publish-drafts/{draftId}/checks` | `generic_persistence / incomplete` | Market Publish Check Command | `dedicated / needs_verification` |
| `submitPublishRequest` | POST | `/app-api/muse/marketplace/publish-requests` | `generic_persistence / incomplete` | Market Publish Request Command | `dedicated / needs_verification` |
| `withdrawPublishRequest` | POST | `/app-api/muse/marketplace/publish-requests/{requestId}/withdraw` | `generic_persistence / incomplete` | Market Publish Request Command | `dedicated / needs_verification` |
| `listMyPublishRecords` | GET | `/app-api/muse/marketplace/my-publish-records` | `generic_persistence / incomplete` | Market Publish Query | `dedicated / needs_verification` |
| `getGovernanceImpact` | GET | `/app-api/muse/marketplace/assets/{assetId}/governance-impact` | `generic_persistence / incomplete` | Market Governance Query | `dedicated / needs_verification` |
| `submitAppeal` | POST | `/app-api/muse/marketplace/appeals` | `generic_persistence / incomplete` | Market Appeal Command | `dedicated / needs_verification` |
| `supplementAppeal` | POST | `/app-api/muse/marketplace/appeals/{appealId}/supplements` | `generic_persistence / incomplete` | Market Appeal Command | `dedicated / needs_verification` |
| `withdrawAppeal` | POST | `/app-api/muse/marketplace/appeals/{appealId}/withdraw` | `generic_persistence / incomplete` | Market Appeal Command | `dedicated / needs_verification` |
| `adminListMarketAssets` | GET | `/admin-api/muse/market/assets` | `generic_persistence / incomplete` | Admin Market Asset Query | `dedicated / needs_verification` |
| `adminGetMarketAsset` | GET | `/admin-api/muse/market/assets/{assetId}` | `generic_persistence / incomplete` | Admin Market Asset Query | `dedicated / needs_verification` |
| `adminPreviewGovernanceImpact` | POST | `/admin-api/muse/market/assets/{assetId}/governance-impact` | `generic_persistence / incomplete` | Admin Governance Command | `dedicated / needs_verification` |
| `adminDelistAsset` | POST | `/admin-api/muse/market/assets/{assetId}/delist` | `generic_persistence / incomplete` | Admin Governance Command | `dedicated / needs_verification` |
| `adminRecallAsset` | POST | `/admin-api/muse/market/assets/{assetId}/recall` | `generic_persistence / incomplete` | Admin Governance Command | `dedicated / needs_verification` |
| `adminListPublishRequests` | GET | `/admin-api/muse/market/publish-requests` | `generic_persistence / incomplete` | Admin Publish Review Query | `dedicated / needs_verification` |
| `adminApprovePublishRequest` | POST | `/admin-api/muse/market/publish-requests/{requestId}/approve` | `generic_persistence / incomplete` | Admin Publish Review Command | `dedicated / needs_verification` |
| `adminRejectPublishRequest` | POST | `/admin-api/muse/market/publish-requests/{requestId}/reject` | `generic_persistence / incomplete` | Admin Publish Review Command | `dedicated / needs_verification` |
| `adminListAppeals` | GET | `/admin-api/muse/market/appeals` | `generic_persistence / incomplete` | Admin Appeal Query | `dedicated / needs_verification` |
| `adminGetAppeal` | GET | `/admin-api/muse/market/appeals/{appealId}` | `generic_persistence / incomplete` | Admin Appeal Query | `dedicated / needs_verification` |
| `adminResolveAppeal` | POST | `/admin-api/muse/market/appeals/{appealId}/resolve` | `generic_persistence / incomplete` | Admin Appeal Command | `dedicated / needs_verification` |
## 6. 目标架构
```mermaid
flowchart TD
APP[App Market Controllers] --> SVC[Market Application Services]
ADM[Admin Market Controllers] --> SVC
SVC --> CMD[Market Command Service]
SVC --> ASSET[Asset and Discovery Service]
SVC --> LIC[License and Install Service]
SVC --> HND[Handoff Service]
SVC --> PUB[Publish Service]
SVC --> GOV[Governance Service]
SVC --> APL[Appeal Service]
CMD --> DB[(Market Tables)]
ASSET --> DB
LIC --> DB
HND --> DB
PUB --> DB
GOV --> DB
APL --> DB
LIC --> ACC[Account Projection Facade]
HND --> AI[AI Owner Facade]
HND --> KNO[Knowledge Owner Facade]
HND --> CON[Content Owner Facade]
GOV --> SRC[Source Status Propagation Facades]
```
## 7. 关键设计
### 7.1 Market 是来源授权 owner不是目标事实 owner
Market 只能输出:
- 授权记录。
- 安装记录。
- 来源授权摘要。
- 授权快照。
- handoff token。
- 治理影响和来源状态。
Market 不能直接输出:
- AI agent slot binding。
- Knowledge binding。
- Content work/block/canonical 写入。
- 目标 owner precheck ID。
### 7.2 写命令必须幂等且可审计
所有写命令至少包含:
- `commandId`
- `operationId`
- `requestHash`
- `actorUserId`
- `ownerUserId`
- `targetType`
- `targetId``targetKey`
- `correlationId`
- `status`
- `resultSnapshot`
相同 `commandId` + 相同 `requestHash` 返回同一业务结果;相同 `commandId` + 不同 `requestHash` 必须冲突。
### 7.3 授权、安装和 handoff 不可互相替代
`purchaseAsset`
- 校验资产可获取、许可可用、治理策略允许新获取。
- 写 `muse_market_purchase` 和授权快照。
- 投影给 Account。
- 不安装、不绑定。
`installMarketplaceAsset`
- 消费有效授权。
- 写 `muse_market_installation`
- 不写目标 owner。
- Account 投影采用既有 member owner 契约Market 实现只写 V11 已有 `muse_account_record_projection` 读模型,并提供 member 侧 `MarketAccountProjectionFacade` 的真实 providerMarket 侧追加表只允许表达投影同步/outbox 状态,不能另建第二套 Account 查询读模型。
`createBindPrecheck` / `createMarketplaceHandoff`
- 消费有效安装和来源状态。
- 生成来源侧授权摘要、授权快照和 token。
- 不创建目标 owner 的预检或绑定事实。
### 7.4 发布审核是硬门槛
`savePublishDraft` 只保存草稿。
`runPublishCheck` 只产出有有效期的检查结果。
`submitPublishRequest` 必须消费未过期且匹配草稿版本/材料 hash 的检查结果。
`adminApprovePublishRequest` 才能让资产版本进入上架可见状态。
### 7.5 治理动作必须有影响预览和传播边界
下架和召回前必须生成 `impactPreviewId`,并记录受影响:
- 授权。
- 安装。
- handoff。
- 目标 owner 绑定摘要。
- 运行中任务。
- Shadow 候选。
- Knowledge Draft。
- 导出限制。
传播给 AI、Knowledge、Content、Account 时只能通过 facade 或 projection目标 owner 不可用时必须记录 `blocked`,不能伪造成已传播。需要重验时只能写入 action policy / recheck reasons不能把 `needs_recheck` 写成 Market `SourceStatus`,因为合同内 `SourceStatus` 只表达来源可用性。
### 7.6 申诉只能处理治理事实
申诉处理读取申诉材料、资产、治理动作和发布申请,不读取用户私有副本正文。补充材料必须脱敏,禁止记录密钥或无关正文全文。
## 8. 验收标准
P1R-6 实现阶段完成后,必须满足:
1. Market 32 个 operation 全部为 `dedicated / needs_verification`
2. AI 41 和 Knowledge 59 继续保持 `dedicated / completed`
3. Content 51、Meta 16、Account 33 继续保持 `dedicated / needs_verification`
4. Events 仍只有 P1R-7 `streamEvents``sse_placeholder / incomplete`
5. `completedOperations` 仍为 100除非后续有真实端到端验收证据并获得单独批准。
6. `docs/api-contracts/market/openapi.yaml` 无 diff。
7. `muse-cloud/scripts/p1r-audit-api-coverage.py` 不为 Market 特判 `completed`
8. 若新增 V15必须通过真实 PostgreSQL / Flyway `_test` 迁移验收。
## 9. Review gate 待检查项
Spec review 应重点检查:
1. Market 是否没有越权写 AI / Knowledge / Content 目标事实。
2. 购买、安装、handoff 是否分层清楚。
3. 发布检查、审核和上架是否没有被压扁成一个开关。
4. 下架/召回是否包含影响预览、传播和审计。
5. 申诉是否没有读取私有副本。
Quality review 应重点检查:
1. 是否能按小任务拆实现。
2. 是否有足够的 gate test 和 focused tests。
3. 是否避免大而全抽象。
4. 是否保持 OpenAPI、coverage 和实现三者一致。
5. 是否明确失败、重试、幂等和回滚边界。