只推进 Market 4 个 operation-level completed approval,保持 market domain-level allowlist 关闭,并保留剩余 28 个 Market operation 为 needs_verification。
739 lines
34 KiB
Markdown
739 lines
34 KiB
Markdown
# P1R Market Completed Approval 执行版
|
||
|
||
> **For agentic workers:** REQUIRED SUB-SKILL: Use `superpowers:subagent-driven-development` to implement this plan task-by-task after the explicit approval gate. Steps use checkbox syntax for tracking.
|
||
|
||
日期:2026-06-11
|
||
|
||
## 结论
|
||
|
||
本执行版推荐第一轮只做 Market operation-level completed approval,不做 Market domain-level 32/32 completed。
|
||
|
||
第一轮推荐审批 4 个 Marketplace 详情/分类/收藏 operation:
|
||
|
||
```text
|
||
market:getMarketplaceAsset
|
||
market:listMarketplaceCategories
|
||
market:favoriteAsset
|
||
market:unfavoriteAsset
|
||
```
|
||
|
||
审批后目标 coverage summary 为:
|
||
|
||
```text
|
||
total=233
|
||
completed=131
|
||
needsVerification=102
|
||
incomplete=0
|
||
genericPersistence=0
|
||
ssePlaceholder=0
|
||
```
|
||
|
||
Market 域目标状态为:
|
||
|
||
```text
|
||
market total=32
|
||
completed=4
|
||
needsVerification=28
|
||
```
|
||
|
||
本执行版只定义实现前置批准项、允许变更范围、TDD 顺序、验证命令、XML 防空跑和回滚策略。当前不得直接实现,不得修改 OpenAPI、scanner、coverage report、业务实现或 gate test。
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
Current["当前 Market<br/>32 dedicated / needs_verification"] --> Exec["执行版<br/>锁定第一批 4 个 operation"]
|
||
Exec --> Review["fresh execution spec/scope review<br/>fresh execution quality/feasibility review"]
|
||
Review --> Approval{"用户明确批准<br/>4 ops / operation-level / OpenAPI commandId / allowed diff"}
|
||
Approval -->|否| Stay["保持当前 coverage<br/>233/127/106"]
|
||
Approval -->|是| Red["TDD RED<br/>先改 Market/Coverage/legacy gates<br/>旧 report 必须失败"]
|
||
Red --> Green["TDD GREEN<br/>Market OpenAPI commandId + scanner operation allowlist + regenerate report"]
|
||
Green --> Verify["focused + P1R mixed + Flyway _test<br/>XML 防空跑 + allowed/protected diff"]
|
||
Verify --> FreshReview["fresh implementation review"]
|
||
```
|
||
|
||
## 当前事实
|
||
|
||
正确 worktree:
|
||
|
||
```text
|
||
/Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0
|
||
```
|
||
|
||
当前 HEAD:
|
||
|
||
```text
|
||
f18116a test(p1r): 收口 Account 第一批 completed approval 门禁
|
||
```
|
||
|
||
当前 coverage summary:
|
||
|
||
```text
|
||
233 127 106 0 0 0
|
||
```
|
||
|
||
当前 Market 事实:
|
||
|
||
- Market 32 个 operation 全部为 `dedicated / needs_verification`。
|
||
- `APPROVED_COMPLETED_DOMAINS` 当前只包含 `ai`、`knowledge`。
|
||
- `APPROVED_COMPLETED_OPERATIONS` 当前只包含 `events:streamEvents`、Meta 16 个 operation、Account 第一批 10 个 operation。
|
||
- `P1rMarketRealApiGateTest` 当前明确禁止 Market operation 标记为 `completed`。
|
||
- `P1rApiCoverageReportTest` 当前断言 summary `completed=127`,并断言 Market 32 个 operation 继续 `needs_verification`。
|
||
- `P1rEventsRealApiGateTest`、`P1rAiRealApiGateTest`、`P1rKnowledgeRealApiGateTest` 仍硬编码当前 summary 或 Market needs_verification 口径;实现前必须把这些 legacy mixed gate 同步列入单独批准项。
|
||
- `favoriteAsset` / `unfavoriteAsset` 的 Java Controller 和 Service 强制校验 `X-Command-Id`,但 `docs/api-contracts/market/openapi.yaml` 当前未声明该 header,coverage report 因此显示 `requiresCommandId=false`。
|
||
- `listMarketplaceRecommendations` 当前是 `fallback_popular` / `fallback_newest` 可解释排序,不是独立个性化推荐系统读模型。
|
||
|
||
## 执行边界
|
||
|
||
### 必须先获用户明确批准
|
||
|
||
实现前必须同时获得以下 4 项批准:
|
||
|
||
1. 批准第一轮 Market completed operation 精确清单为本执行版列出的 4 个 operation。
|
||
2. 批准只走 operation-level approval,不把 `market` 加入 domain-level completed allowlist。
|
||
3. 批准只在 `docs/api-contracts/market/openapi.yaml` 的 `favoriteAsset` / `unfavoriteAsset` 增加 required `X-Command-Id` header 合同;不修改其它 OpenAPI。
|
||
4. 批准按本执行版修改 scanner、coverage report、Market/Coverage gate、必要 legacy mixed gate、Market focused tests、新增 Market HTTP+DB `_test` IT、Flyway assertion、memory 和 `.agent`。
|
||
|
||
未获 4 项批准前,不得实施本执行版。
|
||
|
||
如果用户不批准第 3 项,必须把 `favoriteAsset` / `unfavoriteAsset` 移出第一批,并重写执行版为纯读候选。
|
||
|
||
`market:listMarketplaceAssets` 与 `market:listMarketplaceRecommendations` 本轮明确不进入 completed approval;前者需要先补 pageNo/pageSize 1..100 边界证据,后者需要先解决 OpenAPI 个性化推荐描述与当前 fallback 排序实现的合同不一致。
|
||
|
||
### 本轮允许变更
|
||
|
||
获批后只允许修改以下路径:
|
||
|
||
- `docs/api-contracts/market/openapi.yaml`,仅限为 `favoriteAsset` / `unfavoriteAsset` 增加 required `X-Command-Id` header。
|
||
- `muse-cloud/scripts/p1r-audit-api-coverage.py`
|
||
- `docs/superpowers/reports/p1r-api-coverage.json`
|
||
- `docs/superpowers/reports/p1r-api-coverage.md`
|
||
- `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rApiCoverageReportTest.java`
|
||
- `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rMarketRealApiGateTest.java`
|
||
- `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rEventsRealApiGateTest.java`
|
||
- `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rAiRealApiGateTest.java`
|
||
- `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rKnowledgeRealApiGateTest.java`
|
||
- `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rMarketDiscoveryFavoriteCompletedApprovalIT.java`,新增 Market 详情/分类/收藏 HTTP + 真实 PostgreSQL `_test` 证据。
|
||
- `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rMarketFlywayMigrationIT.java`,仅限补充 V6/V8/V15 Market 表、索引、约束、trigger 和 favorite 非法 insert/update assertion。
|
||
- `muse-cloud/muse-module-market/muse-module-market-server/src/test/java/cn/iocoder/muse/module/market/controller/app/muse/AppMuseMarketplaceAssetControllerTest.java`
|
||
- `muse-cloud/muse-module-market/muse-module-market-server/src/test/java/cn/iocoder/muse/module/market/application/muse/MarketAssetQueryServiceTest.java`
|
||
- `muse-cloud/muse-module-market/muse-module-market-server/src/test/java/cn/iocoder/muse/module/market/application/muse/MarketFavoriteServiceTest.java`
|
||
- `muse-cloud/muse-module-market/muse-module-market-server/src/test/java/cn/iocoder/muse/module/market/dal/mysql/muse/MuseMarketAssetMapperTest.java`
|
||
- `docs/agent-specs/.agent`
|
||
- `docs/agent-specs/2026-06-11-P1RMarketCompletedApproval审阅版.md`
|
||
- `docs/agent-specs/2026-06-11-P1RMarketCompletedApproval执行版.md`
|
||
- `docs/memorys/2026-06-11-P1RMarket状态推进.md`
|
||
|
||
如 implementation 发现必须修改 Market 业务实现、其它 OpenAPI、数据库迁移、Account/Content/Meta gate 或其它文件,必须停下说明原因并重新取得用户批准。
|
||
|
||
### 本轮禁止变更
|
||
|
||
- 不修改除 `docs/api-contracts/market/openapi.yaml` 之外的 OpenAPI。
|
||
- 不修改 Market 业务实现来掩盖 coverage 缺口。
|
||
- 不新增或修改 Market domain-level completed allowlist。
|
||
- 不推进 Market purchase / install / handoff / governanceImpact。
|
||
- 不推进 Market publish / review / governance 管理切片。
|
||
- 不推进 Market appeals / restore / projection 切片。
|
||
- 不推进 Account remaining 23、Content 或总 P1R completed。
|
||
|
||
## 第一轮审批清单
|
||
|
||
| operation key | Method | Path | 目标状态 | 完成证据边界 |
|
||
|---|---|---|---|---|
|
||
| `market:getMarketplaceAsset` | `GET` | `/app-api/muse/marketplace/assets/{assetId}` | `dedicated / completed` | App 资产详情、可见性、missing/invisible asset 拒绝、license/category/governance status DTO |
|
||
| `market:listMarketplaceCategories` | `GET` | `/app-api/muse/marketplace/categories` | `dedicated / completed` | 分类聚合、fallback recommendation slot、exposure summary unavailable 明示 |
|
||
| `market:favoriteAsset` | `POST` | `/app-api/muse/marketplace/assets/{assetId}/favorite` | `dedicated / completed` | required `X-Command-Id`、登录 owner、可见资产、command replay、favorite active、唯一约束和审计事实 |
|
||
| `market:unfavoriteAsset` | `DELETE` | `/app-api/muse/marketplace/assets/{assetId}/favorite` | `dedicated / completed` | required `X-Command-Id`、登录 owner、可见资产、command replay、favorite inactive、不删除审计事实 |
|
||
|
||
## 保持 needs_verification 的 Market operation
|
||
|
||
以下 28 个 operation 必须保持 `dedicated / needs_verification`:
|
||
|
||
```text
|
||
market:listMarketplaceAssets
|
||
market:listMarketplaceRecommendations
|
||
market:adminListAppeals
|
||
market:adminGetAppeal
|
||
market:adminResolveAppeal
|
||
market:adminListMarketAssets
|
||
market:adminGetMarketAsset
|
||
market:adminDelistAsset
|
||
market:adminPreviewGovernanceImpact
|
||
market:adminRecallAsset
|
||
market:adminListPublishRequests
|
||
market:adminApprovePublishRequest
|
||
market:adminRejectPublishRequest
|
||
market:submitAppeal
|
||
market:supplementAppeal
|
||
market:withdrawAppeal
|
||
market:createBindPrecheck
|
||
market:getGovernanceImpact
|
||
market:installMarketplaceAsset
|
||
market:purchaseAsset
|
||
market:createMarketplaceHandoff
|
||
market:getHandoffStatus
|
||
market:cancelHandoff
|
||
market:listMyPublishRecords
|
||
market:savePublishDraft
|
||
market:runPublishCheck
|
||
market:submitPublishRequest
|
||
market:withdrawPublishRequest
|
||
```
|
||
|
||
保留原因:
|
||
|
||
- `listMarketplaceAssets` 当前缺少 pageNo/pageSize 1..100 边界证据;实现层会透传 pageSize,底层 `PAGE_SIZE_NONE=-1` 可能变成全量查询,不能在未获业务实现批准前标为 completed。
|
||
- `listMarketplaceRecommendations` 当前 OpenAPI 描述是个性化推荐,实际实现是 `fallback_popular` / `fallback_newest` 排序;合同与实现语义不闭合,不能在本轮作为 completed。
|
||
- purchase / install / handoff / governanceImpact 缺目标 owner 消费闭环、Account 读侧 E2E 和跨 owner governance 影响闭环。
|
||
- publish / review / governance 证据较强,但仍需单独执行版冻结 13 个 operation 的审批范围、Events outbox 边界和 fresh completed 级验证。
|
||
- appeals / restore / projection 写入的是申诉审计、治理 action 或 Account projection 子集,不能混成统一 completed 闭环。
|
||
|
||
## 证据矩阵
|
||
|
||
| 证据类型 | 必跑或必查内容 | 目的 |
|
||
|---|---|---|
|
||
| Market focused tests | `AppMuseMarketplaceAssetControllerTest`、`MarketAssetQueryServiceTest`、`MarketFavoriteServiceTest`、`MuseMarketAssetMapperTest` | 证明 4 个 operation 的 HTTP contract、版本头、commandId、owner、可见性、幂等和 favorite active/inactive |
|
||
| Market HTTP+DB `_test` | 新增 `P1rMarketDiscoveryFavoriteCompletedApprovalIT` | 证明 4 个 operation 经 HTTP 入口访问真实 PostgreSQL `_test` 数据,覆盖 detail/category/favorite/unfavorite 的持久化和错误路径 |
|
||
| P1R Market gates | `P1rMarketRealApiGateTest`、`P1rMarketRouteOwnershipTest`、`P1rMarketMigrationSqlTest` | 证明 only 4 Market operation completed,28 个继续 needs_verification,路由仍 dedicated |
|
||
| P1R mixed gates | Coverage、Market、Events、AI、Knowledge、Account、Content、Meta gates | 防止非目标 domain 被连带推进,并同步 legacy summary / Market 状态断言 |
|
||
| Flyway `_test` | `P1rMarketFlywayMigrationIT` fresh rerun | 证明 V1-V15 clean migrate、Market V6/V8/V15 表/索引/约束/trigger、favorite unique/command 约束和非法 insert 拒绝 |
|
||
| Coverage scanner | `python3 muse-cloud/scripts/p1r-audit-api-coverage.py --check` | 证明 scanner/report 与 operation-level allowlist、OpenAPI commandId 口径一致 |
|
||
| XML 防空跑 | 逐个读取 surefire XML,检查 tests、failures、errors、skipped | 防止 Maven 未跑目标类或旧 XML 假绿 |
|
||
| OpenAPI allowed diff | 只允许 `market/openapi.yaml` 增加 favorite/unfavorite required `X-Command-Id` | 修正合同与实现不一致,不扩大其它合同 |
|
||
| Business protected diff | Market 业务实现 staged/unstaged diff 必须为空 | 证明没有通过改实现掩盖 coverage 缺口 |
|
||
| Allowed diff | staged、unstaged、untracked 均必须落在允许清单 | 证明没有顺手扩大 scope |
|
||
|
||
说明:standalone MockMvc、mock Service、mapper focused tests 只能作为支持证据,不能单独支撑 `favoriteAsset` / `unfavoriteAsset` completed。实现阶段必须新增 Market HTTP + 真实 PostgreSQL `_test` harness;若现有 Spring 测试结构无法稳定做到 WebApplicationContext/MockMvc + real mapper + `_test` DB,必须停下修订执行版,不能用 mock 组合替代。
|
||
|
||
## TDD 执行步骤
|
||
|
||
### Task 0:实现前现场确认
|
||
|
||
- [ ] 确认 worktree:
|
||
|
||
```bash
|
||
pwd
|
||
git -c core.quotePath=false status --short --branch
|
||
git log --oneline -5
|
||
jq -r '.summary | [.totalOperations,.completedOperations,.needsVerificationOperations,.incompleteOperations,.genericPersistenceOperations,.ssePlaceholderOperations] | @tsv' docs/superpowers/reports/p1r-api-coverage.json
|
||
```
|
||
|
||
预期:
|
||
|
||
```text
|
||
/Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0
|
||
233 127 106 0 0 0
|
||
```
|
||
|
||
- [ ] 确认 Market 32 个 operation 仍全部是 `dedicated / needs_verification`:
|
||
|
||
```bash
|
||
jq -r '.operations[] | select(.domain=="market") | [.operationId,.implementationStatus,.completionStatus,.requiresCommandId] | @tsv' docs/superpowers/reports/p1r-api-coverage.json
|
||
```
|
||
|
||
- [ ] 确认实施前只有文档 diff,没有 OpenAPI、scanner、coverage report、业务实现 diff:
|
||
|
||
```bash
|
||
git -c core.quotePath=false status --short --branch
|
||
git diff -- docs/api-contracts muse-cloud/scripts/p1r-audit-api-coverage.py docs/superpowers/reports
|
||
git diff -- muse-cloud/muse-module-market/muse-module-market-server/src/main/java
|
||
```
|
||
|
||
### XML 防空跑通用规则
|
||
|
||
除 TDD RED 失败验证外,所有 Maven test 验证命令都必须执行以下规则,不能只读取历史 surefire XML:
|
||
|
||
- 命令前记录 `export RUN_START_EPOCH=$(date +%s)`。
|
||
- 命令前删除本任务要求检查的 `target/surefire-reports/TEST-*.xml`。
|
||
- 命令后逐个确认 XML 存在、`mtime >= RUN_START_EPOCH`、`tests` 不低于本执行版最低值、`failures=0`、`errors=0`、`skipped=0`。
|
||
- 任一 XML 缺失、mtime 早于运行开始时间、tests 低于最低值或存在失败/跳过,都必须视为验证失败。
|
||
|
||
TDD RED 失败验证必须同样删除目标 XML 并记录 `RUN_START_EPOCH`,但 RED 的预期是 Maven 失败;此时只校验失败发生在本次运行窗口内,并人工确认失败点来自本执行版列出的旧 report mismatch,不要求 `failures=0`。
|
||
|
||
推荐校验脚本:
|
||
|
||
```bash
|
||
python3 - <<'PY'
|
||
import os
|
||
import sys
|
||
import xml.etree.ElementTree as ET
|
||
from pathlib import Path
|
||
|
||
run_start = int(os.environ["RUN_START_EPOCH"])
|
||
checks = {
|
||
"muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rApiCoverageReportTest.xml": 6,
|
||
}
|
||
failed = False
|
||
for path_text, min_tests in checks.items():
|
||
path = Path(path_text)
|
||
if not path.exists():
|
||
print(f"MISSING_XML {path}")
|
||
failed = True
|
||
continue
|
||
if int(path.stat().st_mtime) < run_start:
|
||
print(f"STALE_XML {path}")
|
||
failed = True
|
||
continue
|
||
root = ET.parse(path).getroot()
|
||
tests = int(root.attrib.get("tests", "0"))
|
||
failures = int(root.attrib.get("failures", "0"))
|
||
errors = int(root.attrib.get("errors", "0"))
|
||
skipped = int(root.attrib.get("skipped", "0"))
|
||
print(path, tests, failures, errors, skipped)
|
||
if tests < min_tests or failures or errors or skipped:
|
||
failed = True
|
||
if failed:
|
||
sys.exit(1)
|
||
PY
|
||
```
|
||
|
||
执行具体任务时必须把 `checks` 替换成该任务表格内列出的 XML 路径和最低 tests。
|
||
|
||
### Task 1:TDD RED,先改 gate 期望
|
||
|
||
获批后先修改:
|
||
|
||
- `P1rApiCoverageReportTest.java`
|
||
- `P1rMarketRealApiGateTest.java`
|
||
- `P1rEventsRealApiGateTest.java`
|
||
- `P1rAiRealApiGateTest.java`
|
||
- `P1rKnowledgeRealApiGateTest.java`
|
||
|
||
RED 期望:
|
||
|
||
- summary 期望 `completed=131`、`needsVerification=102`,但旧 report 仍是 `127/106`,必须失败。
|
||
- Market 4 个 approved operation 期望 `completed`,但旧 report 仍是 `needs_verification`,必须失败。
|
||
- Market 28 个未批准 operation 继续期望 `needs_verification`,其中必须包含 `listMarketplaceAssets` 与 `listMarketplaceRecommendations`。
|
||
- `favoriteAsset` / `unfavoriteAsset` 期望 `requiresCommandId=true`,但旧 report 仍是 `false`,必须失败。
|
||
|
||
运行:
|
||
|
||
```bash
|
||
cd muse-cloud
|
||
export RUN_START_EPOCH=$(date +%s)
|
||
rm -f \
|
||
muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rApiCoverageReportTest.xml \
|
||
muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rMarketRealApiGateTest.xml \
|
||
muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rEventsRealApiGateTest.xml \
|
||
muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rAiRealApiGateTest.xml \
|
||
muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rKnowledgeRealApiGateTest.xml
|
||
JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" \
|
||
mvn -o test -pl muse-server -am \
|
||
-Dtest=P1rApiCoverageReportTest,P1rMarketRealApiGateTest,P1rEventsRealApiGateTest,P1rAiRealApiGateTest,P1rKnowledgeRealApiGateTest \
|
||
-Dsurefire.failIfNoSpecifiedTests=false
|
||
```
|
||
|
||
预期:至少一个失败点来自旧 report 的 `127/106`、Market 4 个 operation 尚未 completed,或 favorite/unfavorite `requiresCommandId=false`。若直接通过,必须停下排查假绿。
|
||
|
||
### Task 2:OpenAPI commandId 合同修正
|
||
|
||
只修改 `docs/api-contracts/market/openapi.yaml`:
|
||
|
||
- 在 `favoriteAsset` parameters 中追加 required header `X-Command-Id`。
|
||
- 在 `unfavoriteAsset` parameters 中追加 required header `X-Command-Id`。
|
||
- 不修改其它 Market operation。
|
||
- 不修改其它 OpenAPI 文件。
|
||
|
||
推荐写法:
|
||
|
||
```yaml
|
||
- name: X-Command-Id
|
||
in: header
|
||
required: true
|
||
schema:
|
||
type: string
|
||
description: 幂等命令 ID,收藏和取消收藏必须传入。
|
||
```
|
||
|
||
修正后用 scanner 验证 report 中:
|
||
|
||
```text
|
||
market:favoriteAsset requiresCommandId=true
|
||
market:unfavoriteAsset requiresCommandId=true
|
||
```
|
||
|
||
### Task 3:TDD GREEN,最小 scanner/report 状态推进
|
||
|
||
只修改 `muse-cloud/scripts/p1r-audit-api-coverage.py`:
|
||
|
||
- 不修改 `APPROVED_COMPLETED_DOMAINS`。
|
||
- 只向 `APPROVED_COMPLETED_OPERATIONS` 追加 4 个 `market:*` operation key:`market:getMarketplaceAsset`、`market:listMarketplaceCategories`、`market:favoriteAsset`、`market:unfavoriteAsset`。
|
||
- 保持 completed 必须仍是 `dedicated` 的校验。
|
||
|
||
生成 report:
|
||
|
||
```bash
|
||
python3 muse-cloud/scripts/p1r-audit-api-coverage.py --check
|
||
```
|
||
|
||
预期 summary:
|
||
|
||
```text
|
||
total=233
|
||
completed=131
|
||
needsVerification=102
|
||
incomplete=0
|
||
genericPersistence=0
|
||
ssePlaceholder=0
|
||
```
|
||
|
||
预期 Market:
|
||
|
||
```text
|
||
completed=4
|
||
needsVerification=28
|
||
favoriteAsset requiresCommandId=true
|
||
unfavoriteAsset requiresCommandId=true
|
||
```
|
||
|
||
### Task 4:Market focused verification
|
||
|
||
运行 Market 本域 focused tests:
|
||
|
||
```bash
|
||
cd muse-cloud
|
||
export RUN_START_EPOCH=$(date +%s)
|
||
rm -f \
|
||
muse-module-market/muse-module-market-server/target/surefire-reports/TEST-cn.iocoder.muse.module.market.controller.app.muse.AppMuseMarketplaceAssetControllerTest.xml \
|
||
muse-module-market/muse-module-market-server/target/surefire-reports/TEST-cn.iocoder.muse.module.market.application.muse.MarketAssetQueryServiceTest.xml \
|
||
muse-module-market/muse-module-market-server/target/surefire-reports/TEST-cn.iocoder.muse.module.market.application.muse.MarketFavoriteServiceTest.xml \
|
||
muse-module-market/muse-module-market-server/target/surefire-reports/TEST-cn.iocoder.muse.module.market.dal.mysql.muse.MuseMarketAssetMapperTest.xml \
|
||
muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rMarketMigrationSqlTest.xml \
|
||
muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rMarketRouteOwnershipTest.xml \
|
||
muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rMarketRealApiGateTest.xml \
|
||
muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rApiCoverageReportTest.xml
|
||
JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" \
|
||
mvn -o test -pl muse-module-market/muse-module-market-server,muse-server -am \
|
||
-Dtest=AppMuseMarketplaceAssetControllerTest,MarketAssetQueryServiceTest,MarketFavoriteServiceTest,MuseMarketAssetMapperTest,P1rMarketMigrationSqlTest,P1rMarketRouteOwnershipTest,P1rMarketRealApiGateTest,P1rApiCoverageReportTest \
|
||
-Dsurefire.failIfNoSpecifiedTests=false
|
||
```
|
||
|
||
必须读取以下 XML 并检查 `failures=0`、`errors=0`、`skipped=0`:
|
||
|
||
| Test class | 最低 tests |
|
||
|---|---:|
|
||
| `AppMuseMarketplaceAssetControllerTest` | 11 |
|
||
| `MarketAssetQueryServiceTest` | 6 |
|
||
| `MarketFavoriteServiceTest` | 7 |
|
||
| `MuseMarketAssetMapperTest` | 2 |
|
||
| `P1rMarketMigrationSqlTest` | 9 |
|
||
| `P1rMarketRouteOwnershipTest` | 3 |
|
||
| `P1rMarketRealApiGateTest` | 6 |
|
||
| `P1rApiCoverageReportTest` | 6 |
|
||
|
||
必须补齐或确认以下断言:
|
||
|
||
- MockMvc `getMarketplaceAsset` 覆盖 visible asset、missing asset、invisible asset。
|
||
- MockMvc `listMarketplaceCategories` 覆盖分类聚合、fallback slot、exposure summary unavailable。
|
||
- MockMvc 缺少 `X-Command-Id` 的 `favoriteAsset` 返回 `MARKET_COMMAND_ID_REQUIRED`。
|
||
- MockMvc 缺少 `X-Command-Id` 的 `unfavoriteAsset` 返回 `MARKET_COMMAND_ID_REQUIRED`。
|
||
- Service 空白 commandId 的 `favoriteAsset` 返回 `MARKET_COMMAND_ID_REQUIRED`。
|
||
- Service 空白 commandId 的 `unfavoriteAsset` 返回 `MARKET_COMMAND_ID_REQUIRED`。
|
||
- `unfavoriteAsset` 只能把 favorite fact 置为 inactive,不允许 delete。
|
||
- `listMarketplaceAssets` 与 `listMarketplaceRecommendations` 可保留现有回归测试,但不得作为本轮 completed evidence;P1R gate 必须继续断言它们是 `needs_verification`。
|
||
|
||
如测试数量因补断言增加,XML 检查的最低 tests 可高于上表,但不能低于上表。
|
||
|
||
### Task 5:Market HTTP + 真实 PostgreSQL `_test` completed gate
|
||
|
||
新增 `P1rMarketDiscoveryFavoriteCompletedApprovalIT`,使用独立 `_test` 数据库和真实 mapper/service 数据,不能使用生产库或非 `_test` 库:
|
||
|
||
```bash
|
||
source ~/.config/muse-repo/infra.env
|
||
export P1R_FLYWAY_PASSWORD="$MUSE_POSTGRES_PASSWORD"
|
||
export P1R_MARKET_COMPLETED_APPROVAL_TEST_DB=muse_p1r_market_discovery_favorite_completed_approval_test
|
||
|
||
PGPASSWORD="$MUSE_POSTGRES_PASSWORD" psql \
|
||
-h "$MUSE_POSTGRES_HOST" \
|
||
-p "$MUSE_POSTGRES_PORT" \
|
||
-U "$MUSE_POSTGRES_USERNAME" \
|
||
-d postgres \
|
||
-tc "SELECT 1 FROM pg_database WHERE datname = '$P1R_MARKET_COMPLETED_APPROVAL_TEST_DB'" | grep -q 1 || \
|
||
PGPASSWORD="$MUSE_POSTGRES_PASSWORD" psql \
|
||
-h "$MUSE_POSTGRES_HOST" \
|
||
-p "$MUSE_POSTGRES_PORT" \
|
||
-U "$MUSE_POSTGRES_USERNAME" \
|
||
-d postgres \
|
||
-c "CREATE DATABASE $P1R_MARKET_COMPLETED_APPROVAL_TEST_DB"
|
||
|
||
cd muse-cloud
|
||
export RUN_START_EPOCH=$(date +%s)
|
||
rm -f muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rMarketDiscoveryFavoriteCompletedApprovalIT.xml
|
||
JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" \
|
||
mvn -o test -pl muse-server -am \
|
||
-Dtest=P1rMarketDiscoveryFavoriteCompletedApprovalIT \
|
||
-Dflyway.postgresql.transactional.lock=false \
|
||
-Dp1r.flyway.locations=filesystem:sql/muse \
|
||
-Dp1r.flyway.url="jdbc:postgresql://$MUSE_POSTGRES_HOST:$MUSE_POSTGRES_PORT/$P1R_MARKET_COMPLETED_APPROVAL_TEST_DB" \
|
||
-Dp1r.flyway.user="$MUSE_POSTGRES_USERNAME" \
|
||
-Djava.net.useSystemProxies=false \
|
||
-DsocksProxyHost= -DsocksProxyPort= \
|
||
-Dhttp.proxyHost= -Dhttp.proxyPort= \
|
||
-Dhttps.proxyHost= -Dhttps.proxyPort= \
|
||
-Dsurefire.failIfNoSpecifiedTests=false
|
||
```
|
||
|
||
该 IT 必须至少覆盖以下 8 个测试,XML 最低 tests 为 8:
|
||
|
||
| Test class | 最低 tests |
|
||
|---|---:|
|
||
| `P1rMarketDiscoveryFavoriteCompletedApprovalIT` | 8 |
|
||
|
||
必须证明:
|
||
|
||
- `GET /app-api/muse/marketplace/assets/{assetId}` 对 `_test` 库中的 visible listed asset 返回真实详情、版本、license、category、governance status 和 favorite 状态。
|
||
- `GET /app-api/muse/marketplace/assets/{assetId}` 对 missing 或 invisible asset 返回错误,不泄露非公开资产。
|
||
- `GET /app-api/muse/marketplace/categories` 从真实资产/分类数据生成分类聚合,并明确 exposure summary unavailable / fallback slot。
|
||
- `POST /favorite` 缺少 `X-Command-Id` 返回 `MARKET_COMMAND_ID_REQUIRED`;带 commandId 时写入 active favorite fact 和 command fact。
|
||
- 同一 commandId 重放 `POST /favorite` 不产生重复 favorite fact,返回 replay 语义。
|
||
- `DELETE /favorite` 带 commandId 后把 favorite fact 置为 inactive,不物理删除审计事实;同一 commandId 重放不重复写入。
|
||
- `DELETE /favorite` 缺少 `X-Command-Id` 返回 `MARKET_COMMAND_ID_REQUIRED`,且不写 command fact、不改变 favorite fact。
|
||
- `POST /favorite` 和 `DELETE /favorite` 对 missing 或 invisible asset 返回错误,并断言不写 command fact、不写或不改变 favorite fact。
|
||
|
||
该 IT 必须在测试启动时校验库名以 `_test` 结尾;密码只能从 `P1R_MARKET_COMPLETED_PASSWORD`、`P1R_FLYWAY_PASSWORD` 或 `MUSE_POSTGRES_PASSWORD` 环境变量读取,不能通过 JVM system property 传入;测试必须断言拒绝 `p1r.market.completed.password` 或任何 password system property;日志和断言不得输出明文数据库密码。
|
||
|
||
### Task 6:真实 PostgreSQL `_test` Flyway gate
|
||
|
||
fresh rerun `P1rMarketFlywayMigrationIT`。使用独立 `_test` 库,不能使用生产库或非 `_test` 库:
|
||
|
||
```bash
|
||
source ~/.config/muse-repo/infra.env
|
||
export P1R_FLYWAY_PASSWORD="$MUSE_POSTGRES_PASSWORD"
|
||
export P1R_MARKET_TEST_DB=muse_p1r_market_completed_approval_test
|
||
|
||
PGPASSWORD="$MUSE_POSTGRES_PASSWORD" psql \
|
||
-h "$MUSE_POSTGRES_HOST" \
|
||
-p "$MUSE_POSTGRES_PORT" \
|
||
-U "$MUSE_POSTGRES_USERNAME" \
|
||
-d postgres \
|
||
-tc "SELECT 1 FROM pg_database WHERE datname = '$P1R_MARKET_TEST_DB'" | grep -q 1 || \
|
||
PGPASSWORD="$MUSE_POSTGRES_PASSWORD" psql \
|
||
-h "$MUSE_POSTGRES_HOST" \
|
||
-p "$MUSE_POSTGRES_PORT" \
|
||
-U "$MUSE_POSTGRES_USERNAME" \
|
||
-d postgres \
|
||
-c "CREATE DATABASE $P1R_MARKET_TEST_DB"
|
||
|
||
cd muse-cloud
|
||
export RUN_START_EPOCH=$(date +%s)
|
||
rm -f muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rMarketFlywayMigrationIT.xml
|
||
JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" \
|
||
mvn -o test -pl muse-server -am \
|
||
-Dtest=P1rMarketFlywayMigrationIT \
|
||
-Dflyway.postgresql.transactional.lock=false \
|
||
-Dp1r.flyway.locations=filesystem:sql/muse \
|
||
-Dp1r.flyway.url="jdbc:postgresql://$MUSE_POSTGRES_HOST:$MUSE_POSTGRES_PORT/$P1R_MARKET_TEST_DB" \
|
||
-Dp1r.flyway.user="$MUSE_POSTGRES_USERNAME" \
|
||
-Djava.net.useSystemProxies=false \
|
||
-DsocksProxyHost= -DsocksProxyPort= \
|
||
-Dhttp.proxyHost= -Dhttp.proxyPort= \
|
||
-Dhttps.proxyHost= -Dhttps.proxyPort= \
|
||
-Dsurefire.failIfNoSpecifiedTests=false
|
||
```
|
||
|
||
必须检查 XML:
|
||
|
||
| Test class | 最低 tests |
|
||
|---|---:|
|
||
| `P1rMarketFlywayMigrationIT` | 4 |
|
||
|
||
必须在该 IT 内新增或补齐以下 assertion,但不得新增迁移或修改业务实现:
|
||
|
||
- `muse_market_asset`、`muse_market_asset_version`、`muse_market_favorite` 存在。
|
||
- `uk_muse_market_favorite_user_asset`、`uk_muse_market_favorite_command`、`idx_muse_market_favorite_user` 存在。
|
||
- `trg_muse_market_favorite_updated_at` 存在。
|
||
- 同一 `(tenant_id, user_id, asset_id)` 不能重复 active favorite fact。
|
||
- 同一 `(tenant_id, command_id)` 不能重复 command fact。
|
||
- favorite status 更新为 inactive 后 `updated_at` trigger 可执行。
|
||
|
||
### Task 7:P1R mixed gate
|
||
|
||
运行 mixed gates:
|
||
|
||
```bash
|
||
cd muse-cloud
|
||
export RUN_START_EPOCH=$(date +%s)
|
||
rm -f \
|
||
muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rApiCoverageReportTest.xml \
|
||
muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rMarketRealApiGateTest.xml \
|
||
muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rEventsRealApiGateTest.xml \
|
||
muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rAiRealApiGateTest.xml \
|
||
muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rKnowledgeRealApiGateTest.xml \
|
||
muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rAccountRealApiGateTest.xml \
|
||
muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rContentRealApiGateTest.xml \
|
||
muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rMetaRealApiGateTest.xml
|
||
JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" \
|
||
mvn -o test -pl muse-server -am \
|
||
-Dtest=P1rApiCoverageReportTest,P1rMarketRealApiGateTest,P1rEventsRealApiGateTest,P1rAiRealApiGateTest,P1rKnowledgeRealApiGateTest,P1rAccountRealApiGateTest,P1rContentRealApiGateTest,P1rMetaRealApiGateTest \
|
||
-Dsurefire.failIfNoSpecifiedTests=false
|
||
```
|
||
|
||
必须读取以下 XML:
|
||
|
||
| Test class | 最低 tests |
|
||
|---|---:|
|
||
| `P1rApiCoverageReportTest` | 6 |
|
||
| `P1rMarketRealApiGateTest` | 6 |
|
||
| `P1rEventsRealApiGateTest` | 6 |
|
||
| `P1rAiRealApiGateTest` | 7 |
|
||
| `P1rKnowledgeRealApiGateTest` | 8 |
|
||
| `P1rAccountRealApiGateTest` | 4 |
|
||
| `P1rContentRealApiGateTest` | 5 |
|
||
| `P1rMetaRealApiGateTest` | 4 |
|
||
|
||
每个 XML 均必须 `failures=0`、`errors=0`、`skipped=0`。
|
||
|
||
这些 gate 必须共同证明:
|
||
|
||
- summary 只从 `127/106` 推进到 `131/102`。
|
||
- Market 只从 `0/32` 推进到 `4/28`。
|
||
- Account 仍保持 `10 completed / 23 needs_verification`。
|
||
- Content 仍保持 `0 completed / 51 needs_verification`。
|
||
- Meta、AI、Knowledge、Events 状态不变。
|
||
|
||
### Task 8:报告与 diff gate
|
||
|
||
检查 summary:
|
||
|
||
```bash
|
||
jq -r '.summary | [.totalOperations,.completedOperations,.needsVerificationOperations,.incompleteOperations,.genericPersistenceOperations,.ssePlaceholderOperations] | @tsv' docs/superpowers/reports/p1r-api-coverage.json
|
||
```
|
||
|
||
预期:
|
||
|
||
```text
|
||
233 131 102 0 0 0
|
||
```
|
||
|
||
检查 Market 4/28:
|
||
|
||
```bash
|
||
python3 - <<'PY'
|
||
import json
|
||
from collections import Counter
|
||
from pathlib import Path
|
||
data = json.loads(Path("docs/superpowers/reports/p1r-api-coverage.json").read_text())
|
||
counter = Counter(op["completionStatus"] for op in data["operations"] if op["domain"] == "market")
|
||
print(counter)
|
||
for op in data["operations"]:
|
||
if op["domain"] == "market" and op["operationId"] in {"favoriteAsset", "unfavoriteAsset"}:
|
||
print(op["operationId"], op["requiresCommandId"], op["completionStatus"])
|
||
PY
|
||
```
|
||
|
||
预期:
|
||
|
||
```text
|
||
Counter({'needs_verification': 28, 'completed': 4})
|
||
favoriteAsset True completed
|
||
unfavoriteAsset True completed
|
||
```
|
||
|
||
检查 OpenAPI diff 只限 Market:
|
||
|
||
```bash
|
||
git diff --quiet -- docs/api-contracts/account/openapi.yaml docs/api-contracts/ai/openapi.yaml docs/api-contracts/content/openapi.yaml docs/api-contracts/events/openapi.yaml docs/api-contracts/knowledge/openapi.yaml docs/api-contracts/meta/openapi.yaml
|
||
git diff --cached --quiet -- docs/api-contracts/account/openapi.yaml docs/api-contracts/ai/openapi.yaml docs/api-contracts/content/openapi.yaml docs/api-contracts/events/openapi.yaml docs/api-contracts/knowledge/openapi.yaml docs/api-contracts/meta/openapi.yaml
|
||
git diff -- docs/api-contracts/market/openapi.yaml
|
||
```
|
||
|
||
检查 Market 业务实现不被修改:
|
||
|
||
```bash
|
||
git diff --quiet -- muse-cloud/muse-module-market/muse-module-market-server/src/main/java
|
||
git diff --cached --quiet -- muse-cloud/muse-module-market/muse-module-market-server/src/main/java
|
||
```
|
||
|
||
检查 whitespace:
|
||
|
||
```bash
|
||
git diff --check
|
||
```
|
||
|
||
检查 allowed diff:
|
||
|
||
```bash
|
||
git -c core.quotePath=false status --short
|
||
```
|
||
|
||
输出只能包含本执行版允许路径。若出现非批准 OpenAPI、业务实现、迁移或非批准 gate 文件,必须停止。
|
||
|
||
### Task 9:memory 与 `.agent`
|
||
|
||
实现通过后新增:
|
||
|
||
- `docs/memorys/2026-06-11-P1RMarket状态推进.md`
|
||
|
||
内容必须记录:
|
||
|
||
- 批准的 4 个 Market operation。
|
||
- 保持 `needs_verification` 的 28 个 Market operation 及原因,必须点名 `listMarketplaceAssets` 与 `listMarketplaceRecommendations`。
|
||
- OpenAPI commandId 合同修正范围。
|
||
- `listMarketplaceRecommendations` 未进入本轮 completed,原因是个性化推荐 OpenAPI 描述与 fallback 排序实现未闭合。
|
||
- `listMarketplaceAssets` 未进入本轮 completed,原因是 pageNo/pageSize 边界证据未闭合。
|
||
- scanner/report/gate 修改范围。
|
||
- 所有验证命令、结果、XML 计数、Market HTTP+DB `_test` 库名、Flyway `_test` 库名。
|
||
- protected diff 与 allowed diff 结果。
|
||
- 明确说明不代表 Market 32/32 completed,不代表 Account remaining 23 / Content / 总 P1R completed。
|
||
|
||
同时更新 `docs/agent-specs/.agent`,但只能记录事实,不写未验证结论。
|
||
|
||
### Task 10:fresh implementation review
|
||
|
||
实现、验证和文档留痕后,必须派发两类 fresh reviewer:
|
||
|
||
- spec/correctness reviewer:检查 4 个 operation 是否严格匹配本执行版,28 个 operation 是否仍 needs_verification,Market domain allowlist 是否未新增,OpenAPI commandId 修正是否只限 favorite/unfavorite。
|
||
- quality/data-integrity/testing reviewer:检查 scanner/report/gate、legacy mixed gate 同步、HTTP+DB `_test`、XML 防空跑、Flyway `_test`、allowed/protected diff、rollback 是否可靠。
|
||
|
||
双 PASS 前不得提交、push 或宣称 Market completed approval 已收口。
|
||
|
||
## 回滚策略
|
||
|
||
如实现后需要撤回:
|
||
|
||
1. 从 `APPROVED_COMPLETED_OPERATIONS` 移除 4 个 `market:*` key。
|
||
2. 处理 `docs/api-contracts/market/openapi.yaml` 中 favorite/unfavorite 的 required `X-Command-Id` header:
|
||
- 如果用户要求完整撤回本轮合同修正,则移除 header。
|
||
- 如果用户单独决定保留实现与 OpenAPI 一致的 commandId 合同,则保留 header,只撤回 completed approval。
|
||
3. 重新运行:
|
||
|
||
```bash
|
||
python3 muse-cloud/scripts/p1r-audit-api-coverage.py --check
|
||
```
|
||
|
||
4. 恢复 gate 期望。完整撤回 OpenAPI header 时:
|
||
|
||
```text
|
||
summary completed=127
|
||
summary needsVerification=106
|
||
market completed=0
|
||
market needsVerification=32
|
||
favoriteAsset requiresCommandId=false
|
||
unfavoriteAsset requiresCommandId=false
|
||
```
|
||
|
||
如果保留 OpenAPI commandId 合同,则 gate 必须恢复为:
|
||
|
||
```text
|
||
summary completed=127
|
||
summary needsVerification=106
|
||
market completed=0
|
||
market needsVerification=32
|
||
favoriteAsset requiresCommandId=true
|
||
unfavoriteAsset requiresCommandId=true
|
||
```
|
||
|
||
5. 修订本轮 memory 并保留失败原因;除非用户明确要求,不直接删除失败留痕。
|
||
6. 重新运行 Market/P1R focused gates 和 `git diff --check`。
|
||
|
||
## 验收标准
|
||
|
||
执行版本身可以进入实现前批准点的条件:
|
||
|
||
1. 本文件已写入 `docs/agent-specs/2026-06-11-P1RMarketCompletedApproval执行版.md`。
|
||
2. `.agent` 记录执行版当前状态。
|
||
3. `git diff --check` 通过。
|
||
4. OpenAPI、scanner、coverage report、业务实现当前无新增 diff;`market/openapi.yaml` 也必须在用户批准前保持无 diff。
|
||
5. fresh execution spec/scope review PASS。
|
||
6. fresh execution quality/feasibility review PASS。
|
||
|
||
实现完成条件必须等用户批准后另行满足,不由本执行版写入自动成立。
|