oh-my-muse/docs/agent-specs/2026-06-11-P1RMarketCompletedApproval执行版.md
zizi 00327749a2 test(p1r): 收口 Market 第一批 completed approval 门禁
只推进 Market 4 个 operation-level completed approval,保持 market domain-level allowlist 关闭,并保留剩余 28 个 Market operation 为 needs_verification。
2026-06-11 18:56:54 +08:00

34 KiB
Raw Blame History

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

market:getMarketplaceAsset
market:listMarketplaceCategories
market:favoriteAsset
market:unfavoriteAsset

审批后目标 coverage summary 为:

total=233
completed=131
needsVerification=102
incomplete=0
genericPersistence=0
ssePlaceholder=0

Market 域目标状态为:

market total=32
completed=4
needsVerification=28

本执行版只定义实现前置批准项、允许变更范围、TDD 顺序、验证命令、XML 防空跑和回滚策略。当前不得直接实现,不得修改 OpenAPI、scanner、coverage report、业务实现或 gate test。

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

/Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0

当前 HEAD

f18116a test(p1r): 收口 Account 第一批 completed approval 门禁

当前 coverage summary

233	127	106	0	0	0

当前 Market 事实:

  • Market 32 个 operation 全部为 dedicated / needs_verification
  • APPROVED_COMPLETED_DOMAINS 当前只包含 aiknowledge
  • APPROVED_COMPLETED_OPERATIONS 当前只包含 events:streamEvents、Meta 16 个 operation、Account 第一批 10 个 operation。
  • P1rMarketRealApiGateTest 当前明确禁止 Market operation 标记为 completed
  • P1rApiCoverageReportTest 当前断言 summary completed=127,并断言 Market 32 个 operation 继续 needs_verification
  • P1rEventsRealApiGateTestP1rAiRealApiGateTestP1rKnowledgeRealApiGateTest 仍硬编码当前 summary 或 Market needs_verification 口径;实现前必须把这些 legacy mixed gate 同步列入单独批准项。
  • favoriteAsset / unfavoriteAsset 的 Java Controller 和 Service 强制校验 X-Command-Id,但 docs/api-contracts/market/openapi.yaml 当前未声明该 headercoverage 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.yamlfavoriteAsset / 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:listMarketplaceAssetsmarket: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

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 AppMuseMarketplaceAssetControllerTestMarketAssetQueryServiceTestMarketFavoriteServiceTestMuseMarketAssetMapperTest 证明 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 P1rMarketRealApiGateTestP1rMarketRouteOwnershipTestP1rMarketMigrationSqlTest 证明 only 4 Market operation completed28 个继续 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
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

预期:

/Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0
233	127	106	0	0	0
  • 确认 Market 32 个 operation 仍全部是 dedicated / needs_verification
jq -r '.operations[] | select(.domain=="market") | [.operationId,.implementationStatus,.completionStatus,.requiresCommandId] | @tsv' docs/superpowers/reports/p1r-api-coverage.json
  • 确认实施前只有文档 diff没有 OpenAPI、scanner、coverage report、业务实现 diff
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_EPOCHtests 不低于本执行版最低值、failures=0errors=0skipped=0
  • 任一 XML 缺失、mtime 早于运行开始时间、tests 低于最低值或存在失败/跳过,都必须视为验证失败。

TDD RED 失败验证必须同样删除目标 XML 并记录 RUN_START_EPOCH,但 RED 的预期是 Maven 失败;此时只校验失败发生在本次运行窗口内,并人工确认失败点来自本执行版列出的旧 report mismatch不要求 failures=0

推荐校验脚本:

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 1TDD RED先改 gate 期望

获批后先修改:

  • P1rApiCoverageReportTest.java
  • P1rMarketRealApiGateTest.java
  • P1rEventsRealApiGateTest.java
  • P1rAiRealApiGateTest.java
  • P1rKnowledgeRealApiGateTest.java

RED 期望:

  • summary 期望 completed=131needsVerification=102,但旧 report 仍是 127/106,必须失败。
  • Market 4 个 approved operation 期望 completed,但旧 report 仍是 needs_verification,必须失败。
  • Market 28 个未批准 operation 继续期望 needs_verification,其中必须包含 listMarketplaceAssetslistMarketplaceRecommendations
  • favoriteAsset / unfavoriteAsset 期望 requiresCommandId=true,但旧 report 仍是 false,必须失败。

运行:

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 2OpenAPI commandId 合同修正

只修改 docs/api-contracts/market/openapi.yaml

  • favoriteAsset parameters 中追加 required header X-Command-Id
  • unfavoriteAsset parameters 中追加 required header X-Command-Id
  • 不修改其它 Market operation。
  • 不修改其它 OpenAPI 文件。

推荐写法:

        - name: X-Command-Id
          in: header
          required: true
          schema:
            type: string
          description: 幂等命令 ID收藏和取消收藏必须传入。

修正后用 scanner 验证 report 中:

market:favoriteAsset requiresCommandId=true
market:unfavoriteAsset requiresCommandId=true

Task 3TDD GREEN最小 scanner/report 状态推进

只修改 muse-cloud/scripts/p1r-audit-api-coverage.py

  • 不修改 APPROVED_COMPLETED_DOMAINS
  • 只向 APPROVED_COMPLETED_OPERATIONS 追加 4 个 market:* operation keymarket:getMarketplaceAssetmarket:listMarketplaceCategoriesmarket:favoriteAssetmarket:unfavoriteAsset
  • 保持 completed 必须仍是 dedicated 的校验。

生成 report

python3 muse-cloud/scripts/p1r-audit-api-coverage.py --check

预期 summary

total=233
completed=131
needsVerification=102
incomplete=0
genericPersistence=0
ssePlaceholder=0

预期 Market

completed=4
needsVerification=28
favoriteAsset requiresCommandId=true
unfavoriteAsset requiresCommandId=true

Task 4Market focused verification

运行 Market 本域 focused tests

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=0errors=0skipped=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-IdfavoriteAsset 返回 MARKET_COMMAND_ID_REQUIRED
  • MockMvc 缺少 X-Command-IdunfavoriteAsset 返回 MARKET_COMMAND_ID_REQUIRED
  • Service 空白 commandId 的 favoriteAsset 返回 MARKET_COMMAND_ID_REQUIRED
  • Service 空白 commandId 的 unfavoriteAsset 返回 MARKET_COMMAND_ID_REQUIRED
  • unfavoriteAsset 只能把 favorite fact 置为 inactive不允许 delete。
  • listMarketplaceAssetslistMarketplaceRecommendations 可保留现有回归测试,但不得作为本轮 completed evidenceP1R gate 必须继续断言它们是 needs_verification

如测试数量因补断言增加XML 检查的最低 tests 可高于上表,但不能低于上表。

Task 5Market HTTP + 真实 PostgreSQL _test completed gate

新增 P1rMarketDiscoveryFavoriteCompletedApprovalIT,使用独立 _test 数据库和真实 mapper/service 数据,不能使用生产库或非 _test 库:

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 /favoriteDELETE /favorite 对 missing 或 invisible asset 返回错误,并断言不写 command fact、不写或不改变 favorite fact。

该 IT 必须在测试启动时校验库名以 _test 结尾;密码只能从 P1R_MARKET_COMPLETED_PASSWORDP1R_FLYWAY_PASSWORDMUSE_POSTGRES_PASSWORD 环境变量读取,不能通过 JVM system property 传入;测试必须断言拒绝 p1r.market.completed.password 或任何 password system property日志和断言不得输出明文数据库密码。

Task 6真实 PostgreSQL _test Flyway gate

fresh rerun P1rMarketFlywayMigrationIT。使用独立 _test 库,不能使用生产库或非 _test 库:

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_assetmuse_market_asset_versionmuse_market_favorite 存在。
  • uk_muse_market_favorite_user_assetuk_muse_market_favorite_commandidx_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 7P1R mixed gate

运行 mixed gates

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=0errors=0skipped=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

jq -r '.summary | [.totalOperations,.completedOperations,.needsVerificationOperations,.incompleteOperations,.genericPersistenceOperations,.ssePlaceholderOperations] | @tsv' docs/superpowers/reports/p1r-api-coverage.json

预期:

233	131	102	0	0	0

检查 Market 4/28

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

预期:

Counter({'needs_verification': 28, 'completed': 4})
favoriteAsset True completed
unfavoriteAsset True completed

检查 OpenAPI diff 只限 Market

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 业务实现不被修改:

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

git diff --check

检查 allowed diff

git -c core.quotePath=false status --short

输出只能包含本执行版允许路径。若出现非批准 OpenAPI、业务实现、迁移或非批准 gate 文件,必须停止。

Task 9memory 与 .agent

实现通过后新增:

  • docs/memorys/2026-06-11-P1RMarket状态推进.md

内容必须记录:

  • 批准的 4 个 Market operation。
  • 保持 needs_verification 的 28 个 Market operation 及原因,必须点名 listMarketplaceAssetslistMarketplaceRecommendations
  • 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 10fresh implementation review

实现、验证和文档留痕后,必须派发两类 fresh reviewer

  • spec/correctness reviewer检查 4 个 operation 是否严格匹配本执行版28 个 operation 是否仍 needs_verificationMarket 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. 重新运行:
python3 muse-cloud/scripts/p1r-audit-api-coverage.py --check
  1. 恢复 gate 期望。完整撤回 OpenAPI header 时:
summary completed=127
summary needsVerification=106
market completed=0
market needsVerification=32
favoriteAsset requiresCommandId=false
unfavoriteAsset requiresCommandId=false

如果保留 OpenAPI commandId 合同,则 gate 必须恢复为:

summary completed=127
summary needsVerification=106
market completed=0
market needsVerification=32
favoriteAsset requiresCommandId=true
unfavoriteAsset requiresCommandId=true
  1. 修订本轮 memory 并保留失败原因;除非用户明确要求,不直接删除失败留痕。
  2. 重新运行 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、业务实现当前无新增 diffmarket/openapi.yaml 也必须在用户批准前保持无 diff。
  5. fresh execution spec/scope review PASS。
  6. fresh execution quality/feasibility review PASS。

实现完成条件必须等用户批准后另行满足,不由本执行版写入自动成立。