# 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
32 dedicated / needs_verification"] --> Exec["执行版
锁定第一批 4 个 operation"] Exec --> Review["fresh execution spec/scope review
fresh execution quality/feasibility review"] Review --> Approval{"用户明确批准
4 ops / operation-level / OpenAPI commandId / allowed diff"} Approval -->|否| Stay["保持当前 coverage
233/127/106"] Approval -->|是| Red["TDD RED
先改 Market/Coverage/legacy gates
旧 report 必须失败"] Red --> Green["TDD GREEN
Market OpenAPI commandId + scanner operation allowlist + regenerate report"] Green --> Verify["focused + P1R mixed + Flyway _test
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。 实现完成条件必须等用户批准后另行满足,不由本执行版写入自动成立。