# P1R Market 状态推进 日期:2026-06-11 ## 结论 本轮只推进 Market 第一批 4 个 operation-level completed approval: - `market:getMarketplaceAsset` - `market:listMarketplaceCategories` - `market:favoriteAsset` - `market:unfavoriteAsset` Market 仍不是整域 completed。`listMarketplaceAssets`、`listMarketplaceRecommendations` 以及 purchase/install/handoff/governance/publish/review/appeal/projection 相关 28 个 Market operation 继续 `dedicated/needs_verification`。 本轮未修改 Market 业务实现,未修改数据库迁移,未把 `market` 加入 domain-level completed allowlist。 ## 工作区与基线 工作区: ```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 ``` 实施后 coverage summary: ```text 233 131 102 0 0 0 ``` 实施后 Market 状态: ```text completed=4 needs_verification=28 ``` ## 允许变更与实际变更 OpenAPI 只修改: - `docs/api-contracts/market/openapi.yaml` 变更内容只是在: - `POST /app-api/muse/marketplace/assets/{assetId}/favorite` - `DELETE /app-api/muse/marketplace/assets/{assetId}/favorite` 增加 required `X-Command-Id` header。原因是 Java Controller / Service 已强制校验 command id,而原 OpenAPI 没有声明,coverage report 因此误显示 `requiresCommandId=false`。 scanner 只修改: - `muse-cloud/scripts/p1r-audit-api-coverage.py` 实际只追加 4 个 operation-level completed key,没有把 `market` 加入 `APPROVED_COMPLETED_DOMAINS`。 coverage report 已重新生成: - `docs/superpowers/reports/p1r-api-coverage.json` - `docs/superpowers/reports/p1r-api-coverage.md` ## TDD 证据 RED 阶段先修改 gate 期望值和 Market operation 断言,在旧 scanner/report 下运行 focused P1R gates,预期失败已出现: - 失败点包括 expected completed=131 but was 127。 - 失败点包括 Market expected 4 completed but was 0。 - 该失败证明 gate 会阻止未获 scanner/report 支撑的 completed 推进。 GREEN 阶段完成 OpenAPI commandId 合同修正、scanner operation-level allowlist、report 重新生成和 focused evidence tests 后,目标验证通过。 ## MockMvc HTTP 入口 + DB 证据 新增: - `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rMarketDiscoveryFavoriteCompletedApprovalIT.java` 验证方式: - 使用 Spring Mock web context + `MockMvc`。 - 使用真实 PostgreSQL `_test` 数据库。 - 使用 Flyway clean/migrate V1-V15。 - 密码只从环境变量读取,禁止通过 JVM system property 传入。 说明:这里的 HTTP 入口证据是执行版要求的 WebApplicationContext + MockMvc 请求路径证据,不是启动真实 socket 端口的 live servlet container 证据。 验证数据库: ```text muse_p1r_market_discovery_favorite_completed_approval_test ``` 通过结果: ```text P1rMarketDiscoveryFavoriteCompletedApprovalIT: tests=9, failures=0, errors=0, skipped=0 ``` 覆盖内容: - 资产详情 happy path。 - missing asset / invisible asset 不泄露详情、不写 command。 - 分类聚合包含 fallback slot 与 unavailable exposure summary。 - favorite 缺少 `X-Command-Id` 不写 DB。 - favorite 写 active favorite 与 command,重复 command 回放不重复写。 - unfavorite 写 inactive,不删除审计事实,重复 command 回放不重复写。 - missing/invisible target 对 favorite/unfavorite 不污染 command/favorite fact。 ## Flyway 证据 增强: - `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rMarketFlywayMigrationIT.java` 验证数据库: ```text muse_p1r_market_completed_approval_test ``` 通过结果: ```text P1rMarketFlywayMigrationIT: tests=4, failures=0, errors=0, skipped=0 ``` 验证内容: - V1-V15 clean migrate。 - `muse_market_favorite` 表存在。 - favorite user/asset/command 相关索引存在。 - `uk_muse_market_favorite_user_asset` 唯一约束存在。 - `trg_muse_market_favorite_updated_at` trigger 存在。 - 同 tenant/user/asset duplicate insert 被 PostgreSQL 唯一约束拒绝,SQLState 为 `23505`。 - 同 tenant/command_id duplicate insert 被 PostgreSQL partial unique index 拒绝,SQLState 为 `23505`。 - favorite status 更新为 `inactive` 时,`trg_muse_market_favorite_updated_at` 会覆盖旧 `update_time`。 额外组合验证: ```text P1rMarketDiscoveryFavoriteCompletedApprovalIT -> P1rMarketFlywayMigrationIT: tests=13, failures=0, errors=0, skipped=0 P1rMarketFlywayMigrationIT -> P1rMarketDiscoveryFavoriteCompletedApprovalIT: tests=13, failures=0, errors=0, skipped=0 ``` 该组合验证使用真实 PostgreSQL `_test` 库: ```text muse_p1r_market_combined_completed_approval_test ``` 组合验证用于证明新增 Discovery IT 与增强 Flyway IT 对 `p1r.flyway.url/user` 的脱敏不会污染同一 Surefire JVM 内其他测试类。曾复现一次失败:Discovery IT 先运行后,Flyway IT 读到脱敏 system property,报缺少原始 `p1r.flyway.url`。修复方式是在 Discovery IT 与 Flyway IT 中都保存原始 `p1r.flyway.url/user`,并在 `@AfterAll` 恢复;随后补充 `-Dsurefire.runOrder=reversealphabetical`,日志确认先跑 Flyway IT、再跑 Discovery IT,合计 13/13 pass。 注意:Surefire XML 的 `` 会记录原始 `p1r.flyway.url` host 与 `p1r.flyway.user`,未发现 password 泄露。raw XML 只能作为本地验证产物,不应直接外发;如需外发测试报告,应先清洗 host/user 或改造为不通过 JVM system property 传递 URL/user。 review 处理: - correctness reviewer 指出的 system property 污染为有效问题,已修复并用双向 combined IT 13/13 pass 关闭。 - data/testing reviewer 提到“真正 HTTP”若理解为 socket 级 live server则当前证据不足。核对执行版后,本轮要求是 WebApplicationContext/MockMvc + real mapper + `_test` DB,不是 live socket server;本文档已把措辞收窄为 MockMvc HTTP 入口,避免过度声明。 - data/testing reviewer 提到 favorite `status` 没有 DB-level CHECK、`asset_id/user_id` 没有 FK。该问题属于后续 schema hardening;本轮执行版明确禁止改迁移,只能在现有 V8/V15 约束上补强 unique/index/trigger 断言,不把它扩成新增迁移。 - 最终 fresh implementation review 已双 PASS:Raman spec/correctness review PASS、Hubble data-integrity/testing review PASS,均无 P0/P1/P2/P3 阻塞项。两名 reviewer 均确认 `market` 未进入 domain-level allowlist、只推进 4 个 `market:*` operation、Market 仍为 4 completed / 28 needs_verification、`listMarketplaceAssets` 与 `listMarketplaceRecommendations` 继续 needs_verification、OpenAPI diff 仅限 favorite/unfavorite required `X-Command-Id`、Market main/java 与 SQL diff 为空、13 个目标 XML 合计 85 tests 且 failures/errors/skipped 均为 0。非阻塞注意事项仍是 raw Surefire XML 暴露 host/user 但不含 password,外发前需清洗。 ## focused gates Market focused verification 通过: ```text AppMuseMarketplaceAssetControllerTest: tests=11, failures=0, errors=0, skipped=0 MarketAssetQueryServiceTest: tests=6, failures=0, errors=0, skipped=0 MarketFavoriteServiceTest: tests=7, failures=0, errors=0, skipped=0 MuseMarketAssetMapperTest: tests=2, failures=0, errors=0, skipped=0 P1rMarketMigrationSqlTest: tests=9, failures=0, errors=0, skipped=0 P1rMarketRouteOwnershipTest: tests=4, failures=0, errors=0, skipped=0 P1rMarketRealApiGateTest: tests=6, failures=0, errors=0, skipped=0 P1rApiCoverageReportTest: tests=6, failures=0, errors=0, skipped=0 ``` 跨域 P1R focused gates 通过: ```text P1rApiCoverageReportTest: tests=6, failures=0, errors=0, skipped=0 P1rMarketRealApiGateTest: tests=6, failures=0, errors=0, skipped=0 P1rEventsRealApiGateTest: tests=6, failures=0, errors=0, skipped=0 P1rAiRealApiGateTest: tests=7, failures=0, errors=0, skipped=0 P1rKnowledgeRealApiGateTest: tests=8, failures=0, errors=0, skipped=0 ``` 合计: ```text P1R mixed gates: 33/33 pass ``` ## scanner 与 diff 证据 scanner: ```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 233 131 102 0 0 0 ``` Market operation 状态确认: ```text getMarketplaceAsset completed false listMarketplaceCategories completed false favoriteAsset completed true unfavoriteAsset completed true listMarketplaceAssets needs_verification false listMarketplaceRecommendations needs_verification false ``` diff check: ```text git diff --check: pass ``` OpenAPI diff: ```text docs/api-contracts/market/openapi.yaml ``` 仅包含 favorite/unfavorite 两个 operation 的 required `X-Command-Id` header。 ## 后续边界 本轮完成后仍不得宣称: - Market 32/32 completed。 - Content completed。 - Account remaining 23 completed。 - 总 P1R completed。 后续如果继续 Market completed approval,推荐单独处理: 1. `listMarketplaceAssets`:先补 pageNo/pageSize 1..100 边界与防全量查询证据。 2. `listMarketplaceRecommendations`:先解决 OpenAPI 个性化推荐语义与 fallback 排序实现的合同不一致。 3. publish/review/governance 13 个 operation:另写执行版冻结范围、Events outbox 边界和 fresh runtime evidence。 4. purchase/install/handoff/governanceImpact:必须先补目标 owner 消费闭环与 Account 读侧 E2E。 5. appeal/projection:不能把申诉审计、治理 outbox 和 Account projection 混成一个 completed 闭环。