test(p1r): approve remaining api coverage completions

This commit is contained in:
lili 2026-06-17 10:49:58 -07:00
parent 4c16235e09
commit 0cf6a6659e
13 changed files with 417 additions and 523 deletions

View File

@ -115,36 +115,36 @@
- ⏸ 正确 fail-closed(非缺口):`UnavailableNewApiAccountFacade`/`UnavailableAccountFileServiceFacade`/`UnavailableSecurityToolGrantApprovalFacade`——依赖未配置的外部服务(New-API/对象存储/治理审批),保持 fail-closed。
### B. 验收债:86 个 needs_verification operation(B-debt,门禁口径→真实证据)
- 🔧 **验收债真实 IT 战役(2026-06-15 起,goal=验收债·真实 IT)**。实际 needs_verification(台账 `docs/superpowers/reports/p1r-api-coverage.json`)= **content 37 / market 28 / account 21 = 86**(均已 dedicated;completed 仅缺真实证据 + 人工批)。范式:`P1rContentCoreCompletedApprovalIT` / 本批新 IT;跑法见 §四(`_test` 库 + argLine + `-DreuseForks=false`)。
- **批1 ✅ 已交付(content work/chapter/block 生命周期 11 op)**:`P1rContentWorkLifecycleCompletedApprovalIT`(commit 2499c24,1/1 绿 mini-infra PG,独立复跑+逐 assert 反假绿复核)覆盖 createWork/updateWork/deleteWork、createChapter/updateChapter/deleteChapter/reorderChapters、createBlock/deleteBlock/mergeBlocks/splitBlock;每 op 断言 HTTP+真实 muse_content_* 持久化事实 + command_log。产出=Codex 起草 + Opus fork 落地纠偏双代理。**证据就绪,completed 待人工批**(把这 11 op 加入 `P1rApiCoverageReportTest.APPROVED_COMPLETED_OPERATIONS` + 台账翻 completionStatus;agent 不自批=反假绿)。
- **批2 ✅ 已交付(market 发布生产侧 5 op,2026-06-16)**:`P1rMarketPublishProducerCompletedApprovalIT`(真实 PG `muse_p1r_market_publish_test`,3/3 绿)覆盖 savePublishDraft/runPublishCheck/submitPublishRequest/withdrawPublishRequest/listMyPublishRecords;断言 HTTP + publish_draft/check/request/review_event/market_command/market_account_projection + Account 投影端口调用 + 失败检查不可提交。测试内仅对专属 `_test` 库做缺库自动创建,不放宽 `_test`/密码环境变量/凭据 query 守卫。**证据就绪,completed 待人工批**。
- **批3 ✅ 已交付(account 市场记录读端 3 op,2026-06-16)**:`P1rAccountMarketRecordsCompletedApprovalIT`(真实 PG `muse_p1r_account_market_records_test`,3/3 绿)覆盖 appListPurchases/appListLicenses/appListPublishRecords;种真实 `muse_account_record_projection` + `member_user` fixture,经真实 `/app-api/muse/account/*` 读取,断言租户/owner 隔离、状态归一、外部订单脱敏、非法输入 fail-closed、读端 no-write。Market 投影可用性由真实 `MarketAccountProjectionProvider` 判定,读端仍只读 Account 投影表。**证据就绪,completed 待人工批**。
- **批4 ✅ 已交付(market 管理端申诉 3 op,2026-06-16)**:`P1rMarketAdminAppealCompletedApprovalIT`(真实 PG `muse_p1r_market_admin_appeal_test`,6/6 绿)覆盖 adminListAppeals/adminGetAppeal/adminResolveAppeal;经真实 `/admin-api/muse/market/appeals/**` + Spring method security,断言列表/详情 no-write、租户隔离、RBAC/API version fail-closed、resolve 写 appeal 状态 + resolved event + completed command、幂等回放、expectedStatus 冲突事务回滚。测试内使用 latest schema(V23+),保留 `_test`/密码环境变量/凭据 query 守卫。**证据就绪,completed 待人工批**。
- **批5 ✅ 已交付(market 管理端发布审核 3 op,2026-06-16)**:`P1rMarketAdminPublishReviewCompletedApprovalIT`(真实 PG `muse_p1r_market_admin_review_test`,6/6 绿)覆盖 adminListPublishRequests/adminApprovePublishRequest/adminRejectPublishRequest;经真实 `/admin-api/muse/market/publish-requests/**` + Spring method security,断言列表 no-write、租户隔离、RBAC/API version fail-closed、approve 真实消费 submitted/check 证据并物化/上架 Market asset+version、reject 写 needs_supplement 事件与投影、completed command 幂等回放、expectedStatus/validationResult 冲突事务回滚。测试内使用 latest schema(V23+),保留 `_test`/密码环境变量/凭据 query 守卫。**证据就绪,completed 待人工批**。
- **批6 ✅ 已交付(market 生产者申诉写路 3 op,2026-06-16)**:`P1rMarketProducerAppealCompletedApprovalIT`(真实 PG `muse_p1r_market_producer_appeal_test`,7/7 绿,独立复跑两次均绿)覆盖 submitAppeal/supplementAppeal/withdrawAppeal;经真实 `/app-api/muse/marketplace/appeals/**`(app 侧无 method security,鉴权靠登录态 + 服务层 owner 隔离),断言:submit 走 review_rejection 关联(自有资产 + 7 天内被拒发布申请)写 appeal(pending,rev1)+ submitted event(snapshot 含 appealType/originalResult=rejected/source)+ completed command;supplement 脱敏只存摘要(密钥 `sk-*`/`token=*`→`[REDACTED]`、不留明文)+ supplementing→reviewing 状态 CAS(rev→2)+ 材料落库 + 幂等回放;withdraw →closed(rev→2)+ resolution 记录撤回理由 + withdrawn event(expectedStatus/previousStatus);三写均命令回放幂等;fail-closed(非属主→`无权访问`/无关联→`关联事实不存在`/超期→`期限已过`/资产不存在/越权他人→`申诉不存在`/未确认隐私→VO 拦截)全程 0 写、0 command 预占;状态冲突 + expectedStatus 冲突均**事务回滚**(reserveCommand 预占=0、rev 不动);API version + 无登录守卫。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫;迁移到 latest schema(V23+)。**证据就绪,completed 待人工批**。
- **批7 ✅ 已交付(account 配额请求 3 op,2026-06-16)**:`P1rAccountQuotaRequestCompletedApprovalIT`(真实 PG `muse_p1r_account_quota_request_test`,5/5 绿,独立复跑两次均绿)覆盖 appCreateQuotaRequest/appGetQuotaRequest/adminCreateQuotaRequest;经真实 `/app-api/muse/account/quota-requests` 与 `/admin-api/muse/account/users/{userId}/quota-requests`(member 模块租户行拦截器 + member_user fixture + admin `@PreAuthorize` method security),断言:create 入队写 quota_request(queued)+ pending_attribution 外部调用占位 + completed command(app:actor=owner=登录用户、amount=0;admin:actor=操作者、owner=目标用户、amount=targetQuota.limit)、命令幂等回放(idempotent_hit 不写第二条)、相同 commandId 不同请求 hash→`ACCOUNT_COMMAND_ID_CONFLICT` 事务回滚;get 按 owner+tenant 隔离返回归一化状态、纯读 no-write;fail-closed(类型白名单 BAD_REQUEST/API version/缺用户 `ACCOUNT_USER_NOT_EXISTS`/越权 owner/not-found/RBAC deny)全程 0 写、0 command 预占;配额请求链路不写 Account 审计(audit/outbox 桩抛错反假绿)。10 条负路全部经真实 GlobalExceptionHandler 实测命中(9 serviceException + 1 accessDenied)。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据就绪,completed 待人工批**。
- **批8 ✅ 已交付(account 用量与外部调用可观测读端 3 op,2026-06-16)**:`P1rAccountUsageObservabilityCompletedApprovalIT`(真实 PG `muse_p1r_account_usage_observability_test`,4/4 绿,独立复跑两次均绿)覆盖 getAppUsage/appGetIntegrationCallByCorrelation/adminGetIntegrationCallByCorrelation;经真实 `/app-api/muse/account/usage`、`/app-api/muse/account/integration-calls/by-correlation/{id}` 与 `/admin-api/muse/account/integration-calls/by-correlation/{id}`(member 模块租户行拦截器 + member_user fixture + admin `@PreAuthorize` method security),断言:getAppUsage 按 owner 聚合(token 输入 160/输出 235 求和、pending 计数 1、anomaly 计数 1、byModel MiniMaxM2=380/GLM=15、byAttribution work+agent)且跨用户隔离(他人 9999 不计入)、period 规范化(month)与白名单(yearly→BAD_REQUEST);app 侧外部调用读 owner 守卫(自有→归一化 pending_attribution/quota_request/retryGroup、越权→`ACCOUNT_RESOURCE_FORBIDDEN`),admin 侧无 owner 限制(可读任意用户、status/requestType 归一化、RBAC=`muse:account:query`);三 op 纯读全程 no-write(member_user/usage_record/integration_call/command/audit 快照前后一致),fail-closed(缺用户 `ACCOUNT_USER_NOT_EXISTS`/not-found `ACCOUNT_INTEGRATION_CALL_NOT_EXISTS`/API version/RBAC deny FORBIDDEN)。控制器附带依赖(权益/绑定/配额/归因 service)用抛错 mock 反假绿越界。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据就绪,completed 待人工批**。
- **批9 ✅ 已交付(account New-API 绑定簇 3 op,2026-06-16)**:`P1rAccountNewApiBindingClusterCompletedApprovalIT`(真实 PG `muse_p1r_account_newapi_binding_test`,4/4 绿,独立复跑两次均绿)覆盖 getAppNewApiBinding/adminListNewApiBindings/appRecheckNewApiBinding;经真实 `/app-api/muse/account/new-api-binding`、`/admin-api/muse/account/new-api-bindings`、`/app-api/muse/account/new-api-binding/recheck`(member 模块租户行拦截器 + member_user fixture + admin `@PreAuthorize` method security),断言:getAppNewApiBinding 按 owner 读绑定摘要 + 存储态归一(active→bound、无绑定→unbound 且不可重验)、纯读 no-write;adminListNewApiBindings 以账户用户为分页主表(无筛选按 id 倒序返 bound/unbound/sync_failed 三态 + syncErrorMessage)、bindingStatus 走 EXISTS/NOT EXISTS 筛选、非法状态 BAD_REQUEST、RBAC=`muse:account:query` fail-closed、纯读 no-write;appRecheckNewApiBinding 在单体 New-API facade(`UnavailableNewApiAccountFacade`)不可用时**正确 fail-closed**——业务 `@Transactional` 回滚命令预占(0 残留),失败外部调用经 `REQUIRES_NEW` 独立落库一条 `unavailable`(error_code 可排障),binding 不被改写,客户端收 `ACCOUNT_NEW_API_UNAVAILABLE`;binding 不存在/缺用户/API version 三守卫全程 0 写。控制器/服务附带依赖(quota/usage/audit service)用抛错 mock 反假绿越界。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据就绪,completed 待人工批**。
- **批10 ✅ 已交付(account 导出/下载簇 3 op,2026-06-16)**:`P1rAccountExportDownloadClusterCompletedApprovalIT`(真实 PG `muse_p1r_account_export_test`,4/4 绿,独立复跑两次均绿)覆盖 appCreateExportTask/appGetExportTask/appDownloadExport;经真实 `/app-api/muse/account/export-tasks`、`/app-api/muse/account/export-tasks/{taskId}`、`/app-api/muse/account/downloads/{credentialId}`(member 模块租户行拦截器 + member_user fixture),断言:create 在 FileService(`UnavailableAccountFileServiceFacade`,单体默认)未接入时按合同把非敏感导出(profile)落库为 queued 任务 + 命令 + 成功审计、绝不伪造 completed/fileRef/下载凭证、不写安全事件,相同 commandId 幂等回放(idempotent_hit 不写第二条),敏感类型(usage)缺 step-up→BAD_REQUEST 回滚、非法 exportType/缺用户/API version 均 fail-closed;get 按 owner 读任务状态归一、跨 owner not found、纯读 no-write;download 校验下载凭证(无效→`ACCOUNT_DOWNLOAD_CREDENTIAL_INVALID`),凭证可用但 FileService 不可用时**正确 fail-closed**——`@Transactional` 回滚一次性消费(凭证 consumed_at 仍空可重试)+ 不写下载审计,客户端收 `ACCOUNT_FILE_SERVICE_UNAVAILABLE`。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据就绪,completed 待人工批**。
- **批11 ✅ 已交付(account 管理端只读补全 2 op,2026-06-17)**:`P1rAccountAdminReadsCompletedApprovalIT`(真实 PG `muse_p1r_account_admin_reads_test`,3/3 绿,独立复跑两次均绿)覆盖 adminListUsageRecords/adminGetCallAttributionJob;经真实 `/admin-api/muse/account/usage-records` 与 `/admin-api/muse/account/call-attribution-jobs/{jobId}`(member 模块租户行拦截器 + member_user fixture + admin `@PreAuthorize` method security),断言:adminListUsageRecords 以账户用户为分页主表在库内聚合(token 输入 150/输出 230/合计 380 求和、pending 计数 1/failed 0、attributionStatus=pending)、非法 period→BAD_REQUEST;adminGetCallAttributionJob 按 jobId 读 job+items 并归一状态(completed)+ 分桶计数(attributed 1/failed 1/pending 0)、not-found→`ACCOUNT_INTEGRATION_CALL_NOT_EXISTS`;两 op 均 RBAC=`muse:account:query` fail-closed、API version 守卫、纯读 no-write(命令/审计/外部调用表保持为空)。归因写路外部来源 facade 用抛错 mock 反假绿越界。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据就绪,completed 待人工批**。
- **批12 ✅ 已交付(account 管理端写路收尾 2 op,2026-06-17)**:`P1rAccountAdminWritesCompletedApprovalIT`(真实 PG `muse_p1r_account_admin_writes_test`,3/3 绿,独立复跑两次均绿)覆盖 adminCreateNewApiBinding/adminCreateCallAttributionJob;经真实 `/admin-api/muse/account/users/{userId}/new-api-binding` 与 `/admin-api/muse/account/call-attribution-jobs`(member 模块租户行拦截器 + member_user fixture + admin `@PreAuthorize` method security),断言:adminCreateNewApiBinding 在单体 New-API facade(`UnavailableNewApiAccountFacade`)不可用时**正确 fail-closed**——业务 `@Transactional` 回滚命令预占(0 残留)+ 不写 binding,失败外部调用经 `REQUIRES_NEW` 独立落库一条 `unavailable`,客户端收 `ACCOUNT_NEW_API_UNAVAILABLE`,目标用户不存在/RBAC(`muse:account:new-api:manage`)/API version 守卫 0 写;adminCreateCallAttributionJob 基于已存在 correlationId 外部调用建立 queued 归因 job + 命令(items 暂空)、命令幂等回放(idempotent_hit 不写第二条)、callIds 白名单未命中 BAD_REQUEST、expectedCallRevision 版本冲突 `ACCOUNT_VERSION_CONFLICT`、缺调用记录 `ACCOUNT_INTEGRATION_CALL_NOT_EXISTS`、RBAC(`muse:account:attribution:manage`)/API version fail-closed,失败路径全程 0 写。命令走真实实现,归因来源/审计/配额/用量附带依赖用抛错 mock 反假绿越界。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据就绪,completed 待人工批**。
- **批13 ✅ 已交付(account 安全事件确认 1 op,2026-06-17)**:`P1rAccountSecurityEventAckCompletedApprovalIT`(真实 PG `muse_p1r_account_security_ack_test`,2/2 绿,独立复跑两次均绿)覆盖 appAcknowledgeSecurityEvent;经真实 `/app-api/muse/account/security-events/{eventId}/acknowledge`(member 模块租户行拦截器 + member_user fixture),断言:属主确认按 owner 校验事件归属、向追加表 muse_account_security_event_ack 追加处理轨迹 + 基础事件 acknowledged 置真 + 命令 + 成功审计,相同 commandId 幂等回放(不追加第二条轨迹);非法 action→BAD_REQUEST、跨 owner→NOT_FOUND(owner 隔离不泄露)、非数字 eventId→NOT_FOUND、缺用户→`ACCOUNT_USER_NOT_EXISTS`、API version 守卫,全程 fail-closed 且 0 写。命令/审计走真实实现,无外部依赖。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据就绪,completed 待人工批**。
- **批14 ✅ 已交付(account 管理端购买记录读 1 op,account 验收债清零,2026-06-17)**:`P1rAccountAdminPurchaseRecordsCompletedApprovalIT`(真实 PG `muse_p1r_account_admin_purchase_test`,2/2 绿,独立复跑两次均绿)覆盖 adminListPurchaseRecords;经真实 `/admin-api/muse/account/purchase-records`(跨模块:`muse.info.base-package=cn.iocoder.muse.module`,单体内 market 的 `MarketAccountProjectionProvider` 真实判定 purchase 投影可用,读端只读 Account 自有投影表 muse_account_record_projection;Account 投影写端口用抛错 stub 越界反假绿),断言:无 userId→跨用户返回全部购买投影、userId 过滤→仅该用户且状态归一(source_status→admin status)+ 资产信息从投影 title/snapshot 回填(assetType/assetName)、userId+status=completed 命中、status=refunded 该用户无返回空、非法 status→BAD_REQUEST、API version 守卫→`ACCOUNT_API_VERSION_UNSUPPORTED`、RBAC(`muse:account:query`)deny→FORBIDDEN,全程纯读 no-write(member_user + 投影表 row_to_json 快照零变更)。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据就绪,completed 待人工批**。
- **批15 ✅ 已交付(market 管理端资产治理读 2 op,2026-06-17)**:`P1rMarketAdminAssetReadsCompletedApprovalIT`(真实 PG `muse_p1r_market_admin_asset_test`,2/2 绿,独立复跑两次均绿)覆盖 adminListMarketAssets/adminGetMarketAsset;经真实 `/admin-api/muse/market/assets`(market 模块整组治理 mapper + `MarketCommandServiceImpl` + `MarketEventPublishOutboxServiceImpl`,base-package=cn.iocoder.muse.module,admin `@PreAuthorize` method security),断言:列表按 tenant 隔离 + assetType/listingStatus/publisherId 过滤(listingStatus 的 not_listed↔draft 由服务端 toInternalListingStatus/normalizeListingStatus 双向归一)、publisherName/version(无当前版本→unknown)回填、关联计数(安装/绑定/申诉=0,关联表空);详情按 tenant 隔离返回资产快照 + 授权/安装/绑定/受影响任务计数全 0 + 版本/治理历史/申诉空集合;缺资产/跨租户→`MARKET_ASSET_NOT_EXISTS`、非法 API version→`MARKET_API_VERSION_UNSUPPORTED`、RBAC(`muse:market:asset:query`)deny→FORBIDDEN,两 op 全程纯读 no-write(资产/命令/治理/来源状态/事件 outbox 表 row_to_json 快照零变更)。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据就绪,completed 待人工批**。
- **批16 ✅ 已交付(market 管理端资产治理写 3 op,2026-06-17)**:`P1rMarketGovernanceWriteCompletedApprovalIT`(真实 PG `muse_p1r_market_governance_test`,4/4 绿,独立复跑两次均绿)覆盖 adminPreviewGovernanceImpact/adminDelistAsset/adminRecallAsset;经真实 `/admin-api/muse/market/assets/{id}/governance-impact|delist|recall`(同 批15 配置 + 治理 `@PreAuthorize` method security),断言治理写生命周期:影响预览写 ready 预览 + 预览影响 + completed 命令并返回影响计数/通知范围(关联表空→计数全 0)→ 凭预览下架(listed→delisted 的 expectedStatus CAS + applied 治理动作 + 治理影响 + 事件发布 outbox + completed 命令)→ 凭预览召回(listed→recalled + 目标 owner 传播 **fail-closed**:如实记录 source_status_event recalled/recorded/`TARGET_OWNER_UNAVAILABLE` 而非伪造成功);命令幂等回放命中 completed 不写第二条 fact;fail-closed 全覆盖:合同枚举 VO `@Pattern`→BAD_REQUEST(service `requireAllowed` 为防御纵深)、缺/非 ready 预览→`MARKET_GOVERNANCE_PREVIEW_REQUIRED`、CAS 阻断→`MARKET_ASSET_GOVERNANCE_BLOCKED`(命令预占随 `@Transactional` 回滚、0 残留)、缺资产→`MARKET_ASSET_NOT_EXISTS`、API version、RBAC deny→FORBIDDEN,失败路径全程 0 写。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据就绪,completed 待人工批**。
- **批17 ✅ 已交付(marketplace 发现读 3 op,2026-06-17)**:`P1rMarketplaceDiscoveryReadsCompletedApprovalIT`(真实 PG `muse_p1r_marketplace_discovery_test`,4/4 绿,独立复跑两次均绿)覆盖 listMarketplaceAssets/listMarketplaceRecommendations/getGovernanceImpact;经真实 `/app-api/muse/marketplace/assets|recommendations|assets/{id}/governance-impact`(MarketAssetQueryServiceImpl + 收藏/命令依赖,base-package=cn.iocoder.muse.module),断言:列表按 App 可见性(listed 公开;draft 等非公开仅 publisher 自见)+ assetType 过滤分页 + 卡片字段回填(publisherName/version=unknown/isFavorite=false/isAcquired=false/isInstalled=false);fallback 推荐返回可见资产卡片 + 推荐理由;治理影响读按 publisher/受影响者门禁(publisher 自见返回治理结果摘要 + 空受影响列表;非属主且无关联授权/安装/绑定→fail-closed `MARKET_RESOURCE_FORBIDDEN`,杜绝借治理接口探测非公开资产);缺资产→`MARKET_ASSET_NOT_EXISTS`、非法 API version→`MARKET_API_VERSION_UNSUPPORTED`,三 op 全程纯读 no-write(资产/收藏/命令/治理表 row_to_json 快照零变更)。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据就绪,completed 待人工批**。
- **批18 ✅ 已交付(market 采纳链 2 op,2026-06-17)**:`P1rMarketLicenseInstallCompletedApprovalIT`(真实 PG `muse_p1r_market_license_install_test`,3/3 绿,独立复跑两次均绿)覆盖 purchaseAsset/installMarketplaceAsset;经真实 `/app-api/muse/marketplace/assets/{id}/purchase|install`(MarketLicenseServiceImpl + MarketInstallServiceImpl + MarketCommandServiceImpl + MarketAccountProjectionProvider/Outbox,base-package=cn.iocoder.muse.module),断言:购买写授权快照 + 购买事实 + completed 命令并把 purchase + license 两条 Account 投影经写端口跨 BC 同步(RecordingAccountProjectionApi 真实捕获、读端绝不反写反假绿);安装要求已购 active 授权(无授权→`MARKET_LICENSE_NOT_EXISTS`)、仅 agent/kb 可安装(作品已购仍→`MARKET_INSTALL_NOT_BINDABLE` 且安装路径 0 写)、写 installed 安装记录 + completed 命令 + license 投影;purchase/install 命令幂等回放命中 completed 不写第二份事实;未上架(属主可见非 listed)→`MARKET_ASSET_NOT_LISTED`、缺资产→`MARKET_ASSET_NOT_EXISTS`、授权类型不符→`MARKET_LICENSE_NOT_PURCHASABLE`、API version→`MARKET_API_VERSION_UNSUPPORTED`,失败路径全程 0 写。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据就绪,completed 待人工批**。
- **批19 ✅ 已交付(market handoff 簇 4 op,market 验收债清零,2026-06-17)**:`P1rMarketHandoffClusterCompletedApprovalIT`(真实 PG `muse_p1r_market_handoff_test`,3/3 绿,独立复跑两次均绿)覆盖 createBindPrecheck/createMarketplaceHandoff/getHandoffStatus/cancelHandoff;经真实 `/app-api/muse/marketplace/assets/{id}/bind-precheck`、`/handoffs`、`/handoffs/{token}`、`/handoffs/{token}/cancel`(MarketHandoffServiceImpl + MarketCommandServiceImpl + LocalMarketTargetOwnerFacade,base-package=cn.iocoder.muse.module),断言端到端链:bind-precheck 基于已购 active 授权快照生成来源侧授权摘要(handoffReady + sourceStatus=available + compatibilityResult=source_summary_ready + actionPolicy installPolicy/bindPolicy=allowed,落 active 摘要 + completed 命令)→ 凭摘要创建一次性 handoff(落 pending token 事件 + completed 命令,**token 明文不入库、只存 sha256 hash,事件快照不含明文 token**,targetPage 由 LocalMarketTargetOwnerFacade 白名单模板生成)→ 凭 token 只读回显 pending(纯读 no-write)→ 按 expectedStatus CAS 取消(pending→cancelled + completed_at + completed 命令);bind/handoff 相同 commandId 回放命中 completed 返回与首呼一致结果(handoff 回放确定性 token 一致)不双写、cancel 终态后再次取消被取消性守卫拒绝(`MARKET_HANDOFF_NOT_CANCELLABLE`,该守卫先于 replay 短路、故顺序回放观察到的是终态守卫而非幂等成功)且 0 写;fail-closed 全覆盖:非法 API version→`MARKET_API_VERSION_UNSUPPORTED`、缺资产→`MARKET_ASSET_NOT_EXISTS`、无活跃授权→`MARKET_LICENSE_NOT_EXISTS`(授权≠可达不变式)、目标 owner 白名单外→`MARKET_TARGET_OWNER_UNAVAILABLE`(本地目标页边界 fail-closed,buildTargetPage 先于预占命令抛错)、跨属主 token 读取/取消→`MARKET_RESOURCE_FORBIDDEN`(token 属主隔离)、取消 CAS 期望态不匹配→`MARKET_HANDOFF_NOT_CANCELLABLE`(reserveCommand 为 `Propagation.MANDATORY`,预占命令随 `@Transactional` 回滚 0 残留),失败路径全程 0 写。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据就绪,completed 待人工批**。
- **批20 ✅ 已交付(content planning candidate 簇 5 op fail-closed,2026-06-17)**:`P1rContentPlanningCandidateClusterCompletedApprovalIT`(真实 PG `muse_p1r_content_planning_candidate_test`,3/3 绿,独立复跑两次均绿)覆盖 createPlanningCandidate/listPlanningCandidates/getPlanningCandidate/confirmPlanningCandidate/discardPlanningCandidate;经真实 `/app-api/muse/works/{id}/planning/candidates*`(AppContentPlanningController + ContentPlanningServiceImpl + ContentCommandServiceImpl + ContentAuditServiceImpl + 租户行拦截器,base-package=cn.iocoder.muse.module.content)。规划候选生成/运行事实/状态投影归 **AI owner**,单体内 `ContentPlanningCandidateFacade` 仅 fail-closed 默认实现(全 default = unavailable,等价生产 `UnavailableContentPlanningCandidateFacade` 的 `@ConditionalOnMissingBean` 兜底)。断言:AI owner 不可用时五 op 全部 fail-closed→`CONTENT_EXTERNAL_OWNER_UNAVAILABLE`,绝不伪造 queued/processing 任务、绝不在 Content 侧伪造 discarded;尤其 **confirmPlanningCandidate(候选进正文唯一合法入口)拒绝写正式 planning section**(无候选投影即不落 canonical),create/confirm/discard 写 op 已预占命令随 `@Transactional` 回滚 0 残留,五 op 全程 0 写(无 planning section / 无命令 / 无事件 outbox);owner/存在性守卫先于外部调用——跨属主作品→`CONTENT_FORBIDDEN`、缺作品→`CONTENT_NOT_FOUND` 且 0 写(杜绝借候选接口探测他人作品)。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫;迁移 V1-V21。**证据就绪,completed 待人工批**。
- **批21 ✅ 已交付(content meta-projection 簇 3 op fail-closed,2026-06-17)**:`P1rContentMetaProjectionClusterCompletedApprovalIT`(真实 PG `muse_p1r_content_meta_projection_test`,3/3 绿,独立复跑两次均绿)覆盖 listMetaProjections/getMetaProjection/validateDynamicFields;经真实 `/app-api/muse/works/{id}/meta-projections`、`/meta-projections/{key}`、`/dynamic-fields/validate`(AppContentMetaProjectionController + ContentMetaProjectionServiceImpl + 租户行拦截器,base-package=cn.iocoder.muse.module.content)。MetaSchema 解释/Meta 投影/动态字段校验规则均归 **Meta owner**,单体内 `ContentMetaFacade` 仅 fail-closed 默认实现(全 default = unavailable,`@ConditionalOnMissingBean` 兜底)。断言:Meta owner 不可用时三 op 全部 fail-closed→`CONTENT_EXTERNAL_OWNER_UNAVAILABLE`,绝不在 Content 侧伪造投影或复制 MetaSchema 规则,三 op 纯读全程 0 写;守卫先于外部调用——非法 API version→`CONTENT_API_VERSION_UNSUPPORTED`、跨属主作品→`CONTENT_FORBIDDEN`、缺作品→`CONTENT_NOT_FOUND` 且 0 写(validateDynamicFields 的 `fields` 经 `@NotEmpty`+元素 `@NotBlank`/`@NotNull` 在入服务前 @Valid 拦截)。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫;迁移 V1-V21。**证据就绪,completed 待人工批**。
- **批22 ✅ 已交付(content style-check 簇 2 op fail-closed,2026-06-17)**:`P1rContentStyleCheckClusterCompletedApprovalIT`(真实 PG `muse_p1r_content_style_check_test`,3/3 绿,独立复跑两次均绿)覆盖 createStyleCheck/getStyleCheckResult;经真实 `/app-api/muse/works/{id}/planning/style-checks` 与 `/style-checks/{jobId}`(AppContentPlanningController + ContentPlanningServiceImpl + ContentCommandServiceImpl + ContentAuditServiceImpl + 租户行拦截器,base-package=cn.iocoder.muse.module.content)。风格检查任务生成与结果归 **AI owner**,单体内 `ContentStyleCheckFacade` 仅 fail-closed 默认实现(全 default = unavailable,`@ConditionalOnMissingBean` 兜底)。断言:AI owner 不可用时两 op 全部 fail-closed→`CONTENT_EXTERNAL_OWNER_UNAVAILABLE`,绝不伪造 queued 任务或结果;createStyleCheck 写 op 已预占命令随 `@Transactional` 回滚 0 残留,两 op 全程 0 写;owner/存在性守卫先于外部调用——跨属主作品→`CONTENT_FORBIDDEN`、缺作品→`CONTENT_NOT_FOUND` 且 0 写。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫;迁移 V1-V21。**证据就绪,completed 待人工批**。
- **批23 ✅ 已交付(content chapter-parse-result 决策 2 op fail-closed,2026-06-17)**:`P1rContentChapterParseResultDecisionCompletedApprovalIT`(真实 PG `muse_p1r_content_import_parse_test`,3/3 绿,独立复跑两次均绿)覆盖 confirmChapterParseResult/rejectChapterParseResult;经真实 `/app-api/muse/chapter-parse-results/{resultId}/confirm`、`/reject`(AppContentImportParseController + ContentImportParseServiceImpl + ContentCommandServiceImpl + ContentAuditServiceImpl + 租户行拦截器,base-package=cn.iocoder.muse.module.content)。AI 解析任务/章节结果投影/知识草稿生成均归 **AI owner**;单体内 `ContentParseJobFacade`/`ContentKnowledgeDraftFacade`/`ContentFileFacade` 仅 fail-closed 默认实现(全 default = unavailable,`@ConditionalOnMissingBean` 兜底)。断言:AI owner 不可用时两 op 全部 fail-closed→`CONTENT_EXTERNAL_OWNER_UNAVAILABLE`(章节结果投影在 `requireChapterResultProjection` 处即不可用,故绝不生成知识草稿、绝不记录确认/拒绝决策);两 op 均写路,已预占命令随 `@Transactional` 回滚 0 残留,全程 0 写;非法 API version→`CONTENT_API_VERSION_UNSUPPORTED` 守卫先于服务体且 0 写。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫;迁移 V1-V21。**证据就绪,completed 待人工批**。
- **批24 ✅ 已交付(content parse-job 生命周期 4 op fail-closed,2026-06-17)**:`P1rContentParseJobLifecycleCompletedApprovalIT`(真实 PG `muse_p1r_content_parse_job_test`,3/3 绿,独立复跑两次均绿)覆盖 getParseJob/listParseJobChapters/retryParseJob/batchConfirmChapters;经真实 `/app-api/muse/parse-jobs/{jobId}`、`/chapters`、`/retry`、`/chapters/batch-confirm`(同 批23 配置:AppContentImportParseController + ContentImportParseServiceImpl + ContentCommandServiceImpl + ContentAuditServiceImpl + 3 外部 owner facade(`ContentParseJobFacade`/`ContentKnowledgeDraftFacade`/`ContentFileFacade`)默认 unavailable + 租户行拦截器,base-package=cn.iocoder.muse.module.content)。断言:AI 解析 owner 不可用时四 op 全部 fail-closed→`CONTENT_EXTERNAL_OWNER_UNAVAILABLE`(解析任务投影在 `requireParseJobProjection` 处即不可用,故绝不伪造任务/章节/重试/批量确认结果);两写 op(retry/batchConfirm)已预占命令随 `@Transactional` 回滚 0 残留,四 op 全程 0 写;非法 API version→`CONTENT_API_VERSION_UNSUPPORTED` 守卫先于服务体且 0 写。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫;迁移 V1-V21。**证据就绪,completed 待人工批**。
- **批25 ✅ 已交付(content import-task 簇 2 op:真实只读 + fail-closed,2026-06-17)**:`P1rContentImportTaskCompletedApprovalIT`(真实 PG `muse_p1r_content_import_task_test`,3/3 绿,独立复跑两次均绿)覆盖 getImportTask/createImportTask;经真实 `/app-api/muse/import-tasks/{taskId}`、`/works/{id}/import-tasks`(同 批23/24 配置,base-package=cn.iocoder.muse.module.content)。**getImportTask 是 Content 自有事实 `muse_content_import_task` 的真实持久化只读**——种真实任务行后经 HTTP 读回库内字段(id/workId/status/fileName/fileSize/format/scanStatus/progress 全部断言、纯读 no-write),并验缺任务→`CONTENT_NOT_FOUND`、跨属主→`CONTENT_FORBIDDEN`(owner 隔离不泄露);**createImportTask 依赖 FileService owner**,单体内 `ContentFileFacade` 仅 fail-closed 默认实现,故 FileService 不可用时 fail-closed→`CONTENT_EXTERNAL_OWNER_UNAVAILABLE` 绝不伪造已可用导入任务、不新增任务行、预占命令随 `@Transactional` 回滚,非法格式→`CONTENT_INVALID_STATUS_TRANSITION`(先于命令预占)、非法 API version→`CONTENT_API_VERSION_UNSUPPORTED` 守卫,失败路径 0 写。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫;迁移 V1-V21。**证据就绪,completed 待人工批**。
- **批26 ✅ 已交付(content export-task 簇 4 op:真实只读 + FileService fail-closed,2026-06-17)**:`P1rContentExportTaskCompletedApprovalIT`(真实 PG `muse_p1r_content_export_task_test`,3/3 绿,独立复跑)覆盖 getExportTask/exportWork/createExportTask/downloadExportPackage;经真实 `/app-api/muse/export-tasks/{taskId}`、`/works/{id}/export`、`/works/{id}/export-tasks`、`/downloads/{credentialId}`(AppContentExportController + ContentExportServiceImpl + ContentCommandServiceImpl + ContentAuditServiceImpl + `ContentFileFacade` 默认 unavailable + 租户行拦截器,base-package=cn.iocoder.muse.module.content)。**getExportTask 是 Content 自有事实 `muse_content_export_task` 的真实持久化只读**——种真实导出任务行后经 HTTP 读回 id/workId/format/status/progress/downloadCredentialId/downloadExpiresAt/completedAt/sourceSnapshot,纯读 no-write,并验缺任务→`CONTENT_NOT_FOUND`、跨属主→`CONTENT_FORBIDDEN`;**exportWork/createExportTask/downloadExportPackage 依赖 FileService owner**,FileService 不可用时 fail-closed→`CONTENT_EXTERNAL_OWNER_UNAVAILABLE`,绝不伪造导出包/下载字节,非法格式→`CONTENT_INVALID_STATUS_TRANSITION`、跨作品章节→`CONTENT_NOT_FOUND`、无效/未完成下载凭证→`CONTENT_DOWNLOAD_CREDENTIAL_INVALID`、非法 API version→`CONTENT_API_VERSION_UNSUPPORTED`,失败路径 0 写。顺手修正 `ContentExportServiceImpl` 事务边界:public `exportWork/createExportTask` 补 `@Transactional`,避免同类自调用导致内部事务注解失效;IT 用 command_log 0 残留断言实证 FileService fail-closed 后预占命令已回滚。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫;迁移 V1-V21。**证据就绪,completed 待人工批**。
- **批27 ✅ 已交付(content 管理端导入/导出任务列表 2 op:真实只读,2026-06-17)**:`P1rContentAdminReadCompletedApprovalIT` 扩展(真实 PG `muse_p1r_content_admin_read_test`,6/6 绿)覆盖 adminListImportTasks/adminListExportTasks;经真实 `/admin-api/muse/content/import-tasks`、`/admin-api/muse/content/export-tasks`(AdminContentController + ContentAdminServiceImpl + Spring method security + 租户行拦截器,base-package=cn.iocoder.muse.module.content)。两 op 均为 Content 自有事实 `muse_content_import_task`/`muse_content_export_task` 的管理端只读列表:种真实任务行后经 HTTP 读回分页 total/list、status/workId 筛选、workTitle 关联回填、ownerId/format/status/fileName/fileSize/completedAt 等字段;跨租户任务由 SQL tenant interceptor 隔离且响应不泄露跨租户标题/文件名/packageRef;RBAC deny→FORBIDDEN 且 0 写;非法 API version→`CONTENT_API_VERSION_UNSUPPORTED` 且先于服务体拒绝;全程 no-write 快照覆盖 work/chapter/block/governance/import/export/command/outbox。顺手把该老 admin-read IT 补齐为专属 `_test` 库缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫;迁移 V1-V21。**证据就绪,completed 待人工批**。
- **批28 ✅ 已交付(content 最后 2 op:解析任务创建 fail-closed + AI 候选采纳真实写,2026-06-17)**:扩展 `P1rContentParseJobLifecycleCompletedApprovalIT` 覆盖 createParseJob;经真实 `POST /app-api/muse/works/{workId}/parse-jobs` 进入 AppContentImportParseController + ContentImportParseServiceImpl + ContentCommandServiceImpl + ContentAuditServiceImpl,种真实 `muse_content_work`/`muse_content_import_task` 后断言导入任务属主/作品关系/扫描状态守卫先于 AI owner 调用(跨属主→`CONTENT_FORBIDDEN`、跨作品→`CONTENT_NOT_FOUND`、扫描未通过→`CONTENT_INVALID_STATUS_TRANSITION`),AI 解析 owner 未接入时正确 fail-closed→`CONTENT_EXTERNAL_OWNER_UNAVAILABLE`,预占命令随事务回滚 0 残留,非法 API version 0 写。同步修正 `P1rContentMergeSuggestionIT` 老 harness 缺专属 `_test` 库自动创建的问题,复跑 mergeBlockSuggestion 强证据:真实 PG + 真实 `AiSuggestionMergeProjectionFacade` 读 `muse_ai_suggestion`,采纳后写 Canonical `muse_content_block` revision/content/word_count + source attribution + content outbox + completed command,并覆盖 revision 冲突、幂等回放、非 pending、审缺失负路。验证:`test-compile` 绿;`P1rContentMergeSuggestionIT` 单跑 5/5 绿;`P1rContentParseJobLifecycleCompletedApprovalIT,P1rContentMergeSuggestionIT` 合跑真实 PG `muse_p1r_content_batch28_test` **9/9 绿**。**证据就绪,completed 待人工批**。
- 剩余:content **0**(批20-28 合计补 planning candidate 5 + meta-projection 3 + style-check 2 + parse-result 决策 2 + parse-job 生命周期/创建 5 + import-task 2 + export-task 4 + 管理端任务列表 2 + mergeBlockSuggestion 1 = 26 op;其中 getImportTask/getExportTask/adminListImportTasks/adminListExportTasks 与 mergeBlockSuggestion 为真实持久化读/写强证据,余外部 owner(AI/Meta/解析/FileService)未接入路径均 fail-closed 且 0 脏写)+ market **0**(批15-19 补管理端资产治理读写 5 + marketplace 发现读 3 + 采纳链 purchase/install 2 + handoff 簇 4 = 14 op,叠加本战役前已补证的发布生产 5 + 管理端申诉 3 + 管理端发布审核 3 + 生产者申诉 3 = 14 op,合计 28 op 全补证 → market needs_verification 验收债清零,证据就绪待人工批)+ account **0**(adminListPurchaseRecords 已补证 → account needs_verification 验收债清零,批3/7-14 全部经真实 PG 证据、证据就绪待人工批)。**至此 content/market/account 三域 needs_verification 验收债均已补齐真实 PG 证据;coverage JSON 的 completed 翻转仍待人工批准,agent 不自批。**
- ✅ **验收债真实 IT 战役(2026-06-15 起,goal=验收债·真实 IT)**。原 needs_verification(台账 `docs/superpowers/reports/p1r-api-coverage.json`)= **content 37 / market 28 / account 21 = 86**;截至 2026-06-17 已全部补齐真实 PG 证据,并按用户批准翻为 completed。当前 coverage summary=**233 completed / 0 needs_verification / 0 incomplete / 0 blocked**。范式:`P1rContentCoreCompletedApprovalIT` / 本批新 IT;跑法见 §四(`_test` 库 + argLine + `-DreuseForks=false`)。
- **批1 ✅ 已交付(content work/chapter/block 生命周期 11 op)**:`P1rContentWorkLifecycleCompletedApprovalIT`(commit 2499c24,1/1 绿 mini-infra PG,独立复跑+逐 assert 反假绿复核)覆盖 createWork/updateWork/deleteWork、createChapter/updateChapter/deleteChapter/reorderChapters、createBlock/deleteBlock/mergeBlocks/splitBlock;每 op 断言 HTTP+真实 muse_content_* 持久化事实 + command_log。产出=Codex 起草 + Opus fork 落地纠偏双代理。**证据已人工批准并翻 completed**(已按人工批准加入 `P1rApiCoverageReportTest` 批准集合并同步台账 completionStatus)。
- **批2 ✅ 已交付(market 发布生产侧 5 op,2026-06-16)**:`P1rMarketPublishProducerCompletedApprovalIT`(真实 PG `muse_p1r_market_publish_test`,3/3 绿)覆盖 savePublishDraft/runPublishCheck/submitPublishRequest/withdrawPublishRequest/listMyPublishRecords;断言 HTTP + publish_draft/check/request/review_event/market_command/market_account_projection + Account 投影端口调用 + 失败检查不可提交。测试内仅对专属 `_test` 库做缺库自动创建,不放宽 `_test`/密码环境变量/凭据 query 守卫。**证据已人工批准并翻 completed**。
- **批3 ✅ 已交付(account 市场记录读端 3 op,2026-06-16)**:`P1rAccountMarketRecordsCompletedApprovalIT`(真实 PG `muse_p1r_account_market_records_test`,3/3 绿)覆盖 appListPurchases/appListLicenses/appListPublishRecords;种真实 `muse_account_record_projection` + `member_user` fixture,经真实 `/app-api/muse/account/*` 读取,断言租户/owner 隔离、状态归一、外部订单脱敏、非法输入 fail-closed、读端 no-write。Market 投影可用性由真实 `MarketAccountProjectionProvider` 判定,读端仍只读 Account 投影表。**证据已人工批准并翻 completed**。
- **批4 ✅ 已交付(market 管理端申诉 3 op,2026-06-16)**:`P1rMarketAdminAppealCompletedApprovalIT`(真实 PG `muse_p1r_market_admin_appeal_test`,6/6 绿)覆盖 adminListAppeals/adminGetAppeal/adminResolveAppeal;经真实 `/admin-api/muse/market/appeals/**` + Spring method security,断言列表/详情 no-write、租户隔离、RBAC/API version fail-closed、resolve 写 appeal 状态 + resolved event + completed command、幂等回放、expectedStatus 冲突事务回滚。测试内使用 latest schema(V23+),保留 `_test`/密码环境变量/凭据 query 守卫。**证据已人工批准并翻 completed**。
- **批5 ✅ 已交付(market 管理端发布审核 3 op,2026-06-16)**:`P1rMarketAdminPublishReviewCompletedApprovalIT`(真实 PG `muse_p1r_market_admin_review_test`,6/6 绿)覆盖 adminListPublishRequests/adminApprovePublishRequest/adminRejectPublishRequest;经真实 `/admin-api/muse/market/publish-requests/**` + Spring method security,断言列表 no-write、租户隔离、RBAC/API version fail-closed、approve 真实消费 submitted/check 证据并物化/上架 Market asset+version、reject 写 needs_supplement 事件与投影、completed command 幂等回放、expectedStatus/validationResult 冲突事务回滚。测试内使用 latest schema(V23+),保留 `_test`/密码环境变量/凭据 query 守卫。**证据已人工批准并翻 completed**。
- **批6 ✅ 已交付(market 生产者申诉写路 3 op,2026-06-16)**:`P1rMarketProducerAppealCompletedApprovalIT`(真实 PG `muse_p1r_market_producer_appeal_test`,7/7 绿,独立复跑两次均绿)覆盖 submitAppeal/supplementAppeal/withdrawAppeal;经真实 `/app-api/muse/marketplace/appeals/**`(app 侧无 method security,鉴权靠登录态 + 服务层 owner 隔离),断言:submit 走 review_rejection 关联(自有资产 + 7 天内被拒发布申请)写 appeal(pending,rev1)+ submitted event(snapshot 含 appealType/originalResult=rejected/source)+ completed command;supplement 脱敏只存摘要(密钥 `sk-*`/`token=*`→`[REDACTED]`、不留明文)+ supplementing→reviewing 状态 CAS(rev→2)+ 材料落库 + 幂等回放;withdraw →closed(rev→2)+ resolution 记录撤回理由 + withdrawn event(expectedStatus/previousStatus);三写均命令回放幂等;fail-closed(非属主→`无权访问`/无关联→`关联事实不存在`/超期→`期限已过`/资产不存在/越权他人→`申诉不存在`/未确认隐私→VO 拦截)全程 0 写、0 command 预占;状态冲突 + expectedStatus 冲突均**事务回滚**(reserveCommand 预占=0、rev 不动);API version + 无登录守卫。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫;迁移到 latest schema(V23+)。**证据已人工批准并翻 completed**。
- **批7 ✅ 已交付(account 配额请求 3 op,2026-06-16)**:`P1rAccountQuotaRequestCompletedApprovalIT`(真实 PG `muse_p1r_account_quota_request_test`,5/5 绿,独立复跑两次均绿)覆盖 appCreateQuotaRequest/appGetQuotaRequest/adminCreateQuotaRequest;经真实 `/app-api/muse/account/quota-requests` 与 `/admin-api/muse/account/users/{userId}/quota-requests`(member 模块租户行拦截器 + member_user fixture + admin `@PreAuthorize` method security),断言:create 入队写 quota_request(queued)+ pending_attribution 外部调用占位 + completed command(app:actor=owner=登录用户、amount=0;admin:actor=操作者、owner=目标用户、amount=targetQuota.limit)、命令幂等回放(idempotent_hit 不写第二条)、相同 commandId 不同请求 hash→`ACCOUNT_COMMAND_ID_CONFLICT` 事务回滚;get 按 owner+tenant 隔离返回归一化状态、纯读 no-write;fail-closed(类型白名单 BAD_REQUEST/API version/缺用户 `ACCOUNT_USER_NOT_EXISTS`/越权 owner/not-found/RBAC deny)全程 0 写、0 command 预占;配额请求链路不写 Account 审计(audit/outbox 桩抛错反假绿)。10 条负路全部经真实 GlobalExceptionHandler 实测命中(9 serviceException + 1 accessDenied)。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据已人工批准并翻 completed**。
- **批8 ✅ 已交付(account 用量与外部调用可观测读端 3 op,2026-06-16)**:`P1rAccountUsageObservabilityCompletedApprovalIT`(真实 PG `muse_p1r_account_usage_observability_test`,4/4 绿,独立复跑两次均绿)覆盖 getAppUsage/appGetIntegrationCallByCorrelation/adminGetIntegrationCallByCorrelation;经真实 `/app-api/muse/account/usage`、`/app-api/muse/account/integration-calls/by-correlation/{id}` 与 `/admin-api/muse/account/integration-calls/by-correlation/{id}`(member 模块租户行拦截器 + member_user fixture + admin `@PreAuthorize` method security),断言:getAppUsage 按 owner 聚合(token 输入 160/输出 235 求和、pending 计数 1、anomaly 计数 1、byModel MiniMaxM2=380/GLM=15、byAttribution work+agent)且跨用户隔离(他人 9999 不计入)、period 规范化(month)与白名单(yearly→BAD_REQUEST);app 侧外部调用读 owner 守卫(自有→归一化 pending_attribution/quota_request/retryGroup、越权→`ACCOUNT_RESOURCE_FORBIDDEN`),admin 侧无 owner 限制(可读任意用户、status/requestType 归一化、RBAC=`muse:account:query`);三 op 纯读全程 no-write(member_user/usage_record/integration_call/command/audit 快照前后一致),fail-closed(缺用户 `ACCOUNT_USER_NOT_EXISTS`/not-found `ACCOUNT_INTEGRATION_CALL_NOT_EXISTS`/API version/RBAC deny FORBIDDEN)。控制器附带依赖(权益/绑定/配额/归因 service)用抛错 mock 反假绿越界。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据已人工批准并翻 completed**。
- **批9 ✅ 已交付(account New-API 绑定簇 3 op,2026-06-16)**:`P1rAccountNewApiBindingClusterCompletedApprovalIT`(真实 PG `muse_p1r_account_newapi_binding_test`,4/4 绿,独立复跑两次均绿)覆盖 getAppNewApiBinding/adminListNewApiBindings/appRecheckNewApiBinding;经真实 `/app-api/muse/account/new-api-binding`、`/admin-api/muse/account/new-api-bindings`、`/app-api/muse/account/new-api-binding/recheck`(member 模块租户行拦截器 + member_user fixture + admin `@PreAuthorize` method security),断言:getAppNewApiBinding 按 owner 读绑定摘要 + 存储态归一(active→bound、无绑定→unbound 且不可重验)、纯读 no-write;adminListNewApiBindings 以账户用户为分页主表(无筛选按 id 倒序返 bound/unbound/sync_failed 三态 + syncErrorMessage)、bindingStatus 走 EXISTS/NOT EXISTS 筛选、非法状态 BAD_REQUEST、RBAC=`muse:account:query` fail-closed、纯读 no-write;appRecheckNewApiBinding 在单体 New-API facade(`UnavailableNewApiAccountFacade`)不可用时**正确 fail-closed**——业务 `@Transactional` 回滚命令预占(0 残留),失败外部调用经 `REQUIRES_NEW` 独立落库一条 `unavailable`(error_code 可排障),binding 不被改写,客户端收 `ACCOUNT_NEW_API_UNAVAILABLE`;binding 不存在/缺用户/API version 三守卫全程 0 写。控制器/服务附带依赖(quota/usage/audit service)用抛错 mock 反假绿越界。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据已人工批准并翻 completed**。
- **批10 ✅ 已交付(account 导出/下载簇 3 op,2026-06-16)**:`P1rAccountExportDownloadClusterCompletedApprovalIT`(真实 PG `muse_p1r_account_export_test`,4/4 绿,独立复跑两次均绿)覆盖 appCreateExportTask/appGetExportTask/appDownloadExport;经真实 `/app-api/muse/account/export-tasks`、`/app-api/muse/account/export-tasks/{taskId}`、`/app-api/muse/account/downloads/{credentialId}`(member 模块租户行拦截器 + member_user fixture),断言:create 在 FileService(`UnavailableAccountFileServiceFacade`,单体默认)未接入时按合同把非敏感导出(profile)落库为 queued 任务 + 命令 + 成功审计、绝不伪造 completed/fileRef/下载凭证、不写安全事件,相同 commandId 幂等回放(idempotent_hit 不写第二条),敏感类型(usage)缺 step-up→BAD_REQUEST 回滚、非法 exportType/缺用户/API version 均 fail-closed;get 按 owner 读任务状态归一、跨 owner not found、纯读 no-write;download 校验下载凭证(无效→`ACCOUNT_DOWNLOAD_CREDENTIAL_INVALID`),凭证可用但 FileService 不可用时**正确 fail-closed**——`@Transactional` 回滚一次性消费(凭证 consumed_at 仍空可重试)+ 不写下载审计,客户端收 `ACCOUNT_FILE_SERVICE_UNAVAILABLE`。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据已人工批准并翻 completed**。
- **批11 ✅ 已交付(account 管理端只读补全 2 op,2026-06-17)**:`P1rAccountAdminReadsCompletedApprovalIT`(真实 PG `muse_p1r_account_admin_reads_test`,3/3 绿,独立复跑两次均绿)覆盖 adminListUsageRecords/adminGetCallAttributionJob;经真实 `/admin-api/muse/account/usage-records` 与 `/admin-api/muse/account/call-attribution-jobs/{jobId}`(member 模块租户行拦截器 + member_user fixture + admin `@PreAuthorize` method security),断言:adminListUsageRecords 以账户用户为分页主表在库内聚合(token 输入 150/输出 230/合计 380 求和、pending 计数 1/failed 0、attributionStatus=pending)、非法 period→BAD_REQUEST;adminGetCallAttributionJob 按 jobId 读 job+items 并归一状态(completed)+ 分桶计数(attributed 1/failed 1/pending 0)、not-found→`ACCOUNT_INTEGRATION_CALL_NOT_EXISTS`;两 op 均 RBAC=`muse:account:query` fail-closed、API version 守卫、纯读 no-write(命令/审计/外部调用表保持为空)。归因写路外部来源 facade 用抛错 mock 反假绿越界。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据已人工批准并翻 completed**。
- **批12 ✅ 已交付(account 管理端写路收尾 2 op,2026-06-17)**:`P1rAccountAdminWritesCompletedApprovalIT`(真实 PG `muse_p1r_account_admin_writes_test`,3/3 绿,独立复跑两次均绿)覆盖 adminCreateNewApiBinding/adminCreateCallAttributionJob;经真实 `/admin-api/muse/account/users/{userId}/new-api-binding` 与 `/admin-api/muse/account/call-attribution-jobs`(member 模块租户行拦截器 + member_user fixture + admin `@PreAuthorize` method security),断言:adminCreateNewApiBinding 在单体 New-API facade(`UnavailableNewApiAccountFacade`)不可用时**正确 fail-closed**——业务 `@Transactional` 回滚命令预占(0 残留)+ 不写 binding,失败外部调用经 `REQUIRES_NEW` 独立落库一条 `unavailable`,客户端收 `ACCOUNT_NEW_API_UNAVAILABLE`,目标用户不存在/RBAC(`muse:account:new-api:manage`)/API version 守卫 0 写;adminCreateCallAttributionJob 基于已存在 correlationId 外部调用建立 queued 归因 job + 命令(items 暂空)、命令幂等回放(idempotent_hit 不写第二条)、callIds 白名单未命中 BAD_REQUEST、expectedCallRevision 版本冲突 `ACCOUNT_VERSION_CONFLICT`、缺调用记录 `ACCOUNT_INTEGRATION_CALL_NOT_EXISTS`、RBAC(`muse:account:attribution:manage`)/API version fail-closed,失败路径全程 0 写。命令走真实实现,归因来源/审计/配额/用量附带依赖用抛错 mock 反假绿越界。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据已人工批准并翻 completed**。
- **批13 ✅ 已交付(account 安全事件确认 1 op,2026-06-17)**:`P1rAccountSecurityEventAckCompletedApprovalIT`(真实 PG `muse_p1r_account_security_ack_test`,2/2 绿,独立复跑两次均绿)覆盖 appAcknowledgeSecurityEvent;经真实 `/app-api/muse/account/security-events/{eventId}/acknowledge`(member 模块租户行拦截器 + member_user fixture),断言:属主确认按 owner 校验事件归属、向追加表 muse_account_security_event_ack 追加处理轨迹 + 基础事件 acknowledged 置真 + 命令 + 成功审计,相同 commandId 幂等回放(不追加第二条轨迹);非法 action→BAD_REQUEST、跨 owner→NOT_FOUND(owner 隔离不泄露)、非数字 eventId→NOT_FOUND、缺用户→`ACCOUNT_USER_NOT_EXISTS`、API version 守卫,全程 fail-closed 且 0 写。命令/审计走真实实现,无外部依赖。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据已人工批准并翻 completed**。
- **批14 ✅ 已交付(account 管理端购买记录读 1 op,account 验收债清零,2026-06-17)**:`P1rAccountAdminPurchaseRecordsCompletedApprovalIT`(真实 PG `muse_p1r_account_admin_purchase_test`,2/2 绿,独立复跑两次均绿)覆盖 adminListPurchaseRecords;经真实 `/admin-api/muse/account/purchase-records`(跨模块:`muse.info.base-package=cn.iocoder.muse.module`,单体内 market 的 `MarketAccountProjectionProvider` 真实判定 purchase 投影可用,读端只读 Account 自有投影表 muse_account_record_projection;Account 投影写端口用抛错 stub 越界反假绿),断言:无 userId→跨用户返回全部购买投影、userId 过滤→仅该用户且状态归一(source_status→admin status)+ 资产信息从投影 title/snapshot 回填(assetType/assetName)、userId+status=completed 命中、status=refunded 该用户无返回空、非法 status→BAD_REQUEST、API version 守卫→`ACCOUNT_API_VERSION_UNSUPPORTED`、RBAC(`muse:account:query`)deny→FORBIDDEN,全程纯读 no-write(member_user + 投影表 row_to_json 快照零变更)。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据已人工批准并翻 completed**。
- **批15 ✅ 已交付(market 管理端资产治理读 2 op,2026-06-17)**:`P1rMarketAdminAssetReadsCompletedApprovalIT`(真实 PG `muse_p1r_market_admin_asset_test`,2/2 绿,独立复跑两次均绿)覆盖 adminListMarketAssets/adminGetMarketAsset;经真实 `/admin-api/muse/market/assets`(market 模块整组治理 mapper + `MarketCommandServiceImpl` + `MarketEventPublishOutboxServiceImpl`,base-package=cn.iocoder.muse.module,admin `@PreAuthorize` method security),断言:列表按 tenant 隔离 + assetType/listingStatus/publisherId 过滤(listingStatus 的 not_listed↔draft 由服务端 toInternalListingStatus/normalizeListingStatus 双向归一)、publisherName/version(无当前版本→unknown)回填、关联计数(安装/绑定/申诉=0,关联表空);详情按 tenant 隔离返回资产快照 + 授权/安装/绑定/受影响任务计数全 0 + 版本/治理历史/申诉空集合;缺资产/跨租户→`MARKET_ASSET_NOT_EXISTS`、非法 API version→`MARKET_API_VERSION_UNSUPPORTED`、RBAC(`muse:market:asset:query`)deny→FORBIDDEN,两 op 全程纯读 no-write(资产/命令/治理/来源状态/事件 outbox 表 row_to_json 快照零变更)。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据已人工批准并翻 completed**。
- **批16 ✅ 已交付(market 管理端资产治理写 3 op,2026-06-17)**:`P1rMarketGovernanceWriteCompletedApprovalIT`(真实 PG `muse_p1r_market_governance_test`,4/4 绿,独立复跑两次均绿)覆盖 adminPreviewGovernanceImpact/adminDelistAsset/adminRecallAsset;经真实 `/admin-api/muse/market/assets/{id}/governance-impact|delist|recall`(同 批15 配置 + 治理 `@PreAuthorize` method security),断言治理写生命周期:影响预览写 ready 预览 + 预览影响 + completed 命令并返回影响计数/通知范围(关联表空→计数全 0)→ 凭预览下架(listed→delisted 的 expectedStatus CAS + applied 治理动作 + 治理影响 + 事件发布 outbox + completed 命令)→ 凭预览召回(listed→recalled + 目标 owner 传播 **fail-closed**:如实记录 source_status_event recalled/recorded/`TARGET_OWNER_UNAVAILABLE` 而非伪造成功);命令幂等回放命中 completed 不写第二条 fact;fail-closed 全覆盖:合同枚举 VO `@Pattern`→BAD_REQUEST(service `requireAllowed` 为防御纵深)、缺/非 ready 预览→`MARKET_GOVERNANCE_PREVIEW_REQUIRED`、CAS 阻断→`MARKET_ASSET_GOVERNANCE_BLOCKED`(命令预占随 `@Transactional` 回滚、0 残留)、缺资产→`MARKET_ASSET_NOT_EXISTS`、API version、RBAC deny→FORBIDDEN,失败路径全程 0 写。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据已人工批准并翻 completed**。
- **批17 ✅ 已交付(marketplace 发现读 3 op,2026-06-17)**:`P1rMarketplaceDiscoveryReadsCompletedApprovalIT`(真实 PG `muse_p1r_marketplace_discovery_test`,4/4 绿,独立复跑两次均绿)覆盖 listMarketplaceAssets/listMarketplaceRecommendations/getGovernanceImpact;经真实 `/app-api/muse/marketplace/assets|recommendations|assets/{id}/governance-impact`(MarketAssetQueryServiceImpl + 收藏/命令依赖,base-package=cn.iocoder.muse.module),断言:列表按 App 可见性(listed 公开;draft 等非公开仅 publisher 自见)+ assetType 过滤分页 + 卡片字段回填(publisherName/version=unknown/isFavorite=false/isAcquired=false/isInstalled=false);fallback 推荐返回可见资产卡片 + 推荐理由;治理影响读按 publisher/受影响者门禁(publisher 自见返回治理结果摘要 + 空受影响列表;非属主且无关联授权/安装/绑定→fail-closed `MARKET_RESOURCE_FORBIDDEN`,杜绝借治理接口探测非公开资产);缺资产→`MARKET_ASSET_NOT_EXISTS`、非法 API version→`MARKET_API_VERSION_UNSUPPORTED`,三 op 全程纯读 no-write(资产/收藏/命令/治理表 row_to_json 快照零变更)。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据已人工批准并翻 completed**。
- **批18 ✅ 已交付(market 采纳链 2 op,2026-06-17)**:`P1rMarketLicenseInstallCompletedApprovalIT`(真实 PG `muse_p1r_market_license_install_test`,3/3 绿,独立复跑两次均绿)覆盖 purchaseAsset/installMarketplaceAsset;经真实 `/app-api/muse/marketplace/assets/{id}/purchase|install`(MarketLicenseServiceImpl + MarketInstallServiceImpl + MarketCommandServiceImpl + MarketAccountProjectionProvider/Outbox,base-package=cn.iocoder.muse.module),断言:购买写授权快照 + 购买事实 + completed 命令并把 purchase + license 两条 Account 投影经写端口跨 BC 同步(RecordingAccountProjectionApi 真实捕获、读端绝不反写反假绿);安装要求已购 active 授权(无授权→`MARKET_LICENSE_NOT_EXISTS`)、仅 agent/kb 可安装(作品已购仍→`MARKET_INSTALL_NOT_BINDABLE` 且安装路径 0 写)、写 installed 安装记录 + completed 命令 + license 投影;purchase/install 命令幂等回放命中 completed 不写第二份事实;未上架(属主可见非 listed)→`MARKET_ASSET_NOT_LISTED`、缺资产→`MARKET_ASSET_NOT_EXISTS`、授权类型不符→`MARKET_LICENSE_NOT_PURCHASABLE`、API version→`MARKET_API_VERSION_UNSUPPORTED`,失败路径全程 0 写。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据已人工批准并翻 completed**。
- **批19 ✅ 已交付(market handoff 簇 4 op,market 验收债清零,2026-06-17)**:`P1rMarketHandoffClusterCompletedApprovalIT`(真实 PG `muse_p1r_market_handoff_test`,3/3 绿,独立复跑两次均绿)覆盖 createBindPrecheck/createMarketplaceHandoff/getHandoffStatus/cancelHandoff;经真实 `/app-api/muse/marketplace/assets/{id}/bind-precheck`、`/handoffs`、`/handoffs/{token}`、`/handoffs/{token}/cancel`(MarketHandoffServiceImpl + MarketCommandServiceImpl + LocalMarketTargetOwnerFacade,base-package=cn.iocoder.muse.module),断言端到端链:bind-precheck 基于已购 active 授权快照生成来源侧授权摘要(handoffReady + sourceStatus=available + compatibilityResult=source_summary_ready + actionPolicy installPolicy/bindPolicy=allowed,落 active 摘要 + completed 命令)→ 凭摘要创建一次性 handoff(落 pending token 事件 + completed 命令,**token 明文不入库、只存 sha256 hash,事件快照不含明文 token**,targetPage 由 LocalMarketTargetOwnerFacade 白名单模板生成)→ 凭 token 只读回显 pending(纯读 no-write)→ 按 expectedStatus CAS 取消(pending→cancelled + completed_at + completed 命令);bind/handoff 相同 commandId 回放命中 completed 返回与首呼一致结果(handoff 回放确定性 token 一致)不双写、cancel 终态后再次取消被取消性守卫拒绝(`MARKET_HANDOFF_NOT_CANCELLABLE`,该守卫先于 replay 短路、故顺序回放观察到的是终态守卫而非幂等成功)且 0 写;fail-closed 全覆盖:非法 API version→`MARKET_API_VERSION_UNSUPPORTED`、缺资产→`MARKET_ASSET_NOT_EXISTS`、无活跃授权→`MARKET_LICENSE_NOT_EXISTS`(授权≠可达不变式)、目标 owner 白名单外→`MARKET_TARGET_OWNER_UNAVAILABLE`(本地目标页边界 fail-closed,buildTargetPage 先于预占命令抛错)、跨属主 token 读取/取消→`MARKET_RESOURCE_FORBIDDEN`(token 属主隔离)、取消 CAS 期望态不匹配→`MARKET_HANDOFF_NOT_CANCELLABLE`(reserveCommand 为 `Propagation.MANDATORY`,预占命令随 `@Transactional` 回滚 0 残留),失败路径全程 0 写。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫。**证据已人工批准并翻 completed**。
- **批20 ✅ 已交付(content planning candidate 簇 5 op fail-closed,2026-06-17)**:`P1rContentPlanningCandidateClusterCompletedApprovalIT`(真实 PG `muse_p1r_content_planning_candidate_test`,3/3 绿,独立复跑两次均绿)覆盖 createPlanningCandidate/listPlanningCandidates/getPlanningCandidate/confirmPlanningCandidate/discardPlanningCandidate;经真实 `/app-api/muse/works/{id}/planning/candidates*`(AppContentPlanningController + ContentPlanningServiceImpl + ContentCommandServiceImpl + ContentAuditServiceImpl + 租户行拦截器,base-package=cn.iocoder.muse.module.content)。规划候选生成/运行事实/状态投影归 **AI owner**,单体内 `ContentPlanningCandidateFacade` 仅 fail-closed 默认实现(全 default = unavailable,等价生产 `UnavailableContentPlanningCandidateFacade` 的 `@ConditionalOnMissingBean` 兜底)。断言:AI owner 不可用时五 op 全部 fail-closed→`CONTENT_EXTERNAL_OWNER_UNAVAILABLE`,绝不伪造 queued/processing 任务、绝不在 Content 侧伪造 discarded;尤其 **confirmPlanningCandidate(候选进正文唯一合法入口)拒绝写正式 planning section**(无候选投影即不落 canonical),create/confirm/discard 写 op 已预占命令随 `@Transactional` 回滚 0 残留,五 op 全程 0 写(无 planning section / 无命令 / 无事件 outbox);owner/存在性守卫先于外部调用——跨属主作品→`CONTENT_FORBIDDEN`、缺作品→`CONTENT_NOT_FOUND` 且 0 写(杜绝借候选接口探测他人作品)。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫;迁移 V1-V21。**证据已人工批准并翻 completed**。
- **批21 ✅ 已交付(content meta-projection 簇 3 op fail-closed,2026-06-17)**:`P1rContentMetaProjectionClusterCompletedApprovalIT`(真实 PG `muse_p1r_content_meta_projection_test`,3/3 绿,独立复跑两次均绿)覆盖 listMetaProjections/getMetaProjection/validateDynamicFields;经真实 `/app-api/muse/works/{id}/meta-projections`、`/meta-projections/{key}`、`/dynamic-fields/validate`(AppContentMetaProjectionController + ContentMetaProjectionServiceImpl + 租户行拦截器,base-package=cn.iocoder.muse.module.content)。MetaSchema 解释/Meta 投影/动态字段校验规则均归 **Meta owner**,单体内 `ContentMetaFacade` 仅 fail-closed 默认实现(全 default = unavailable,`@ConditionalOnMissingBean` 兜底)。断言:Meta owner 不可用时三 op 全部 fail-closed→`CONTENT_EXTERNAL_OWNER_UNAVAILABLE`,绝不在 Content 侧伪造投影或复制 MetaSchema 规则,三 op 纯读全程 0 写;守卫先于外部调用——非法 API version→`CONTENT_API_VERSION_UNSUPPORTED`、跨属主作品→`CONTENT_FORBIDDEN`、缺作品→`CONTENT_NOT_FOUND` 且 0 写(validateDynamicFields 的 `fields` 经 `@NotEmpty`+元素 `@NotBlank`/`@NotNull` 在入服务前 @Valid 拦截)。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫;迁移 V1-V21。**证据已人工批准并翻 completed**。
- **批22 ✅ 已交付(content style-check 簇 2 op fail-closed,2026-06-17)**:`P1rContentStyleCheckClusterCompletedApprovalIT`(真实 PG `muse_p1r_content_style_check_test`,3/3 绿,独立复跑两次均绿)覆盖 createStyleCheck/getStyleCheckResult;经真实 `/app-api/muse/works/{id}/planning/style-checks` 与 `/style-checks/{jobId}`(AppContentPlanningController + ContentPlanningServiceImpl + ContentCommandServiceImpl + ContentAuditServiceImpl + 租户行拦截器,base-package=cn.iocoder.muse.module.content)。风格检查任务生成与结果归 **AI owner**,单体内 `ContentStyleCheckFacade` 仅 fail-closed 默认实现(全 default = unavailable,`@ConditionalOnMissingBean` 兜底)。断言:AI owner 不可用时两 op 全部 fail-closed→`CONTENT_EXTERNAL_OWNER_UNAVAILABLE`,绝不伪造 queued 任务或结果;createStyleCheck 写 op 已预占命令随 `@Transactional` 回滚 0 残留,两 op 全程 0 写;owner/存在性守卫先于外部调用——跨属主作品→`CONTENT_FORBIDDEN`、缺作品→`CONTENT_NOT_FOUND` 且 0 写。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫;迁移 V1-V21。**证据已人工批准并翻 completed**。
- **批23 ✅ 已交付(content chapter-parse-result 决策 2 op fail-closed,2026-06-17)**:`P1rContentChapterParseResultDecisionCompletedApprovalIT`(真实 PG `muse_p1r_content_import_parse_test`,3/3 绿,独立复跑两次均绿)覆盖 confirmChapterParseResult/rejectChapterParseResult;经真实 `/app-api/muse/chapter-parse-results/{resultId}/confirm`、`/reject`(AppContentImportParseController + ContentImportParseServiceImpl + ContentCommandServiceImpl + ContentAuditServiceImpl + 租户行拦截器,base-package=cn.iocoder.muse.module.content)。AI 解析任务/章节结果投影/知识草稿生成均归 **AI owner**;单体内 `ContentParseJobFacade`/`ContentKnowledgeDraftFacade`/`ContentFileFacade` 仅 fail-closed 默认实现(全 default = unavailable,`@ConditionalOnMissingBean` 兜底)。断言:AI owner 不可用时两 op 全部 fail-closed→`CONTENT_EXTERNAL_OWNER_UNAVAILABLE`(章节结果投影在 `requireChapterResultProjection` 处即不可用,故绝不生成知识草稿、绝不记录确认/拒绝决策);两 op 均写路,已预占命令随 `@Transactional` 回滚 0 残留,全程 0 写;非法 API version→`CONTENT_API_VERSION_UNSUPPORTED` 守卫先于服务体且 0 写。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫;迁移 V1-V21。**证据已人工批准并翻 completed**。
- **批24 ✅ 已交付(content parse-job 生命周期 4 op fail-closed,2026-06-17)**:`P1rContentParseJobLifecycleCompletedApprovalIT`(真实 PG `muse_p1r_content_parse_job_test`,3/3 绿,独立复跑两次均绿)覆盖 getParseJob/listParseJobChapters/retryParseJob/batchConfirmChapters;经真实 `/app-api/muse/parse-jobs/{jobId}`、`/chapters`、`/retry`、`/chapters/batch-confirm`(同 批23 配置:AppContentImportParseController + ContentImportParseServiceImpl + ContentCommandServiceImpl + ContentAuditServiceImpl + 3 外部 owner facade(`ContentParseJobFacade`/`ContentKnowledgeDraftFacade`/`ContentFileFacade`)默认 unavailable + 租户行拦截器,base-package=cn.iocoder.muse.module.content)。断言:AI 解析 owner 不可用时四 op 全部 fail-closed→`CONTENT_EXTERNAL_OWNER_UNAVAILABLE`(解析任务投影在 `requireParseJobProjection` 处即不可用,故绝不伪造任务/章节/重试/批量确认结果);两写 op(retry/batchConfirm)已预占命令随 `@Transactional` 回滚 0 残留,四 op 全程 0 写;非法 API version→`CONTENT_API_VERSION_UNSUPPORTED` 守卫先于服务体且 0 写。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫;迁移 V1-V21。**证据已人工批准并翻 completed**。
- **批25 ✅ 已交付(content import-task 簇 2 op:真实只读 + fail-closed,2026-06-17)**:`P1rContentImportTaskCompletedApprovalIT`(真实 PG `muse_p1r_content_import_task_test`,3/3 绿,独立复跑两次均绿)覆盖 getImportTask/createImportTask;经真实 `/app-api/muse/import-tasks/{taskId}`、`/works/{id}/import-tasks`(同 批23/24 配置,base-package=cn.iocoder.muse.module.content)。**getImportTask 是 Content 自有事实 `muse_content_import_task` 的真实持久化只读**——种真实任务行后经 HTTP 读回库内字段(id/workId/status/fileName/fileSize/format/scanStatus/progress 全部断言、纯读 no-write),并验缺任务→`CONTENT_NOT_FOUND`、跨属主→`CONTENT_FORBIDDEN`(owner 隔离不泄露);**createImportTask 依赖 FileService owner**,单体内 `ContentFileFacade` 仅 fail-closed 默认实现,故 FileService 不可用时 fail-closed→`CONTENT_EXTERNAL_OWNER_UNAVAILABLE` 绝不伪造已可用导入任务、不新增任务行、预占命令随 `@Transactional` 回滚,非法格式→`CONTENT_INVALID_STATUS_TRANSITION`(先于命令预占)、非法 API version→`CONTENT_API_VERSION_UNSUPPORTED` 守卫,失败路径 0 写。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫;迁移 V1-V21。**证据已人工批准并翻 completed**。
- **批26 ✅ 已交付(content export-task 簇 4 op:真实只读 + FileService fail-closed,2026-06-17)**:`P1rContentExportTaskCompletedApprovalIT`(真实 PG `muse_p1r_content_export_task_test`,3/3 绿,独立复跑)覆盖 getExportTask/exportWork/createExportTask/downloadExportPackage;经真实 `/app-api/muse/export-tasks/{taskId}`、`/works/{id}/export`、`/works/{id}/export-tasks`、`/downloads/{credentialId}`(AppContentExportController + ContentExportServiceImpl + ContentCommandServiceImpl + ContentAuditServiceImpl + `ContentFileFacade` 默认 unavailable + 租户行拦截器,base-package=cn.iocoder.muse.module.content)。**getExportTask 是 Content 自有事实 `muse_content_export_task` 的真实持久化只读**——种真实导出任务行后经 HTTP 读回 id/workId/format/status/progress/downloadCredentialId/downloadExpiresAt/completedAt/sourceSnapshot,纯读 no-write,并验缺任务→`CONTENT_NOT_FOUND`、跨属主→`CONTENT_FORBIDDEN`;**exportWork/createExportTask/downloadExportPackage 依赖 FileService owner**,FileService 不可用时 fail-closed→`CONTENT_EXTERNAL_OWNER_UNAVAILABLE`,绝不伪造导出包/下载字节,非法格式→`CONTENT_INVALID_STATUS_TRANSITION`、跨作品章节→`CONTENT_NOT_FOUND`、无效/未完成下载凭证→`CONTENT_DOWNLOAD_CREDENTIAL_INVALID`、非法 API version→`CONTENT_API_VERSION_UNSUPPORTED`,失败路径 0 写。顺手修正 `ContentExportServiceImpl` 事务边界:public `exportWork/createExportTask` 补 `@Transactional`,避免同类自调用导致内部事务注解失效;IT 用 command_log 0 残留断言实证 FileService fail-closed 后预占命令已回滚。测试内仅对专属 `_test` 库做缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫;迁移 V1-V21。**证据已人工批准并翻 completed**。
- **批27 ✅ 已交付(content 管理端导入/导出任务列表 2 op:真实只读,2026-06-17)**:`P1rContentAdminReadCompletedApprovalIT` 扩展(真实 PG `muse_p1r_content_admin_read_test`,6/6 绿)覆盖 adminListImportTasks/adminListExportTasks;经真实 `/admin-api/muse/content/import-tasks`、`/admin-api/muse/content/export-tasks`(AdminContentController + ContentAdminServiceImpl + Spring method security + 租户行拦截器,base-package=cn.iocoder.muse.module.content)。两 op 均为 Content 自有事实 `muse_content_import_task`/`muse_content_export_task` 的管理端只读列表:种真实任务行后经 HTTP 读回分页 total/list、status/workId 筛选、workTitle 关联回填、ownerId/format/status/fileName/fileSize/completedAt 等字段;跨租户任务由 SQL tenant interceptor 隔离且响应不泄露跨租户标题/文件名/packageRef;RBAC deny→FORBIDDEN 且 0 写;非法 API version→`CONTENT_API_VERSION_UNSUPPORTED` 且先于服务体拒绝;全程 no-write 快照覆盖 work/chapter/block/governance/import/export/command/outbox。顺手把该老 admin-read IT 补齐为专属 `_test` 库缺库自动创建,保留 `_test`/密码环境变量/凭据 query 守卫;迁移 V1-V21。**证据已人工批准并翻 completed**。
- **批28 ✅ 已交付(content 最后 2 op:解析任务创建 fail-closed + AI 候选采纳真实写,2026-06-17)**:扩展 `P1rContentParseJobLifecycleCompletedApprovalIT` 覆盖 createParseJob;经真实 `POST /app-api/muse/works/{workId}/parse-jobs` 进入 AppContentImportParseController + ContentImportParseServiceImpl + ContentCommandServiceImpl + ContentAuditServiceImpl,种真实 `muse_content_work`/`muse_content_import_task` 后断言导入任务属主/作品关系/扫描状态守卫先于 AI owner 调用(跨属主→`CONTENT_FORBIDDEN`、跨作品→`CONTENT_NOT_FOUND`、扫描未通过→`CONTENT_INVALID_STATUS_TRANSITION`),AI 解析 owner 未接入时正确 fail-closed→`CONTENT_EXTERNAL_OWNER_UNAVAILABLE`,预占命令随事务回滚 0 残留,非法 API version 0 写。同步修正 `P1rContentMergeSuggestionIT` 老 harness 缺专属 `_test` 库自动创建的问题,复跑 mergeBlockSuggestion 强证据:真实 PG + 真实 `AiSuggestionMergeProjectionFacade` 读 `muse_ai_suggestion`,采纳后写 Canonical `muse_content_block` revision/content/word_count + source attribution + content outbox + completed command,并覆盖 revision 冲突、幂等回放、非 pending、审缺失负路。验证:`test-compile` 绿;`P1rContentMergeSuggestionIT` 单跑 5/5 绿;`P1rContentParseJobLifecycleCompletedApprovalIT,P1rContentMergeSuggestionIT` 合跑真实 PG `muse_p1r_content_batch28_test` **9/9 绿**。**证据已人工批准并翻 completed**。
- 剩余:content **0**(批20-28 合计补 planning candidate 5 + meta-projection 3 + style-check 2 + parse-result 决策 2 + parse-job 生命周期/创建 5 + import-task 2 + export-task 4 + 管理端任务列表 2 + mergeBlockSuggestion 1 = 26 op;其中 getImportTask/getExportTask/adminListImportTasks/adminListExportTasks 与 mergeBlockSuggestion 为真实持久化读/写强证据,余外部 owner(AI/Meta/解析/FileService)未接入路径均 fail-closed 且 0 脏写)+ market **0**(批15-19 补管理端资产治理读写 5 + marketplace 发现读 3 + 采纳链 purchase/install 2 + handoff 簇 4 = 14 op,叠加本战役前已补证的发布生产 5 + 管理端申诉 3 + 管理端发布审核 3 + 生产者申诉 3 = 14 op,合计 28 op 全补证 → market needs_verification 验收债清零,证据已人工批准并翻 completed)+ account **0**(adminListPurchaseRecords 已补证 → account needs_verification 验收债清零,批3/7-14 全部经真实 PG 证据、证据已人工批准并翻 completed)。**至此 content/market/account 三域 needs_verification 验收债均已补齐真实 PG 证据;coverage JSON completed 已按人工批准翻转,`P1rApiCoverageReportTest` 与 `P1r*RealApiGateTest` 批准口径已同步。**
- ✅ **P1r*IT 真实 PG 基线(2026-06-15,mini-infra PG)= 23/23 IT 类全绿**(99 用例 0F/0E;2 例 external-acceptance 因未设 `MUSE_P1R_EXTERNAL_ACCEPTANCE` 跳过)。`P1rKnowledgeFlywayMigrationIT` 版本断言由硬编码(V14→V21→V23 复发两次)改为 `MigrateResult` 动态自适应(commit 4d46d7a,Codex+Opus 双代理合并)。**完整跑法见 [.agents/knowledge §四](../../.agents/knowledge/external-deps-and-gotchas.md)**:`_test` 后缀隔离库 + `source infra.env`(密码仅 env)+ argLine(SOCKS 清 + p1r.flyway.url/user/locations)+ `-DreuseForks=false`(批量必加,避 Market IT 属性脱敏污染复用 fork)。
- 🔧 ai/平台预存红测试整改(CI 接电将暴露):`MuseAiTaskServiceTest` 桩缺失 11 例 NPE **✅ 已整改(补 eventPublishOutboxService/candidateReviewService 桩 + review lenient,40/40,2026-06-15)**;`QiniuSmsClientTest` 时区硬编码 **✅ 已整改(5/5,机器无关)**;`MuseAiEventPublishOutboxMapperTest` **✅ 真实 PG 实跑 5/5(mini-infra PG,harness=infra.env+argLine SOCKS 清;隔离 schema 自建自清)**。**ai/平台预存红三项全清。**

View File

@ -11,9 +11,9 @@
],
"summary": {
"totalOperations": 233,
"completedOperations": 147,
"completedOperations": 233,
"incompleteOperations": 0,
"needsVerificationOperations": 86,
"needsVerificationOperations": 0,
"catchAllOperations": 0,
"genericPersistenceOperations": 0,
"ssePlaceholderOperations": 0,
@ -36,7 +36,7 @@
],
"targetStage": "P1R-3 Account Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/AdminAccountUsageController.java"
],
@ -117,7 +117,7 @@
],
"targetStage": "P1R-3 Account Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/AdminAccountUsageController.java"
],
@ -198,7 +198,7 @@
],
"targetStage": "P1R-3 Account Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/AdminAccountUsageController.java"
],
@ -278,7 +278,7 @@
],
"targetStage": "P1R-3 Account Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/AdminAccountNewApiController.java"
],
@ -360,7 +360,7 @@
],
"targetStage": "P1R-3 Account Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/AdminAccountPurchaseController.java"
],
@ -440,7 +440,7 @@
],
"targetStage": "P1R-3 Account Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/AdminAccountUsageController.java"
],
@ -760,7 +760,7 @@
],
"targetStage": "P1R-3 Account Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/AdminAccountNewApiController.java"
],
@ -1000,7 +1000,7 @@
],
"targetStage": "P1R-3 Account Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/admin/account/AdminAccountNewApiController.java"
],
@ -1161,7 +1161,7 @@
],
"targetStage": "P1R-3 Account Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/AppAccountExportController.java"
],
@ -1323,7 +1323,7 @@
],
"targetStage": "P1R-3 Account Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/AppAccountExportController.java"
],
@ -1405,7 +1405,7 @@
],
"targetStage": "P1R-3 Account Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/AppAccountExportController.java"
],
@ -1486,7 +1486,7 @@
],
"targetStage": "P1R-3 Account Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/AppAccountNewApiController.java"
],
@ -1568,7 +1568,7 @@
],
"targetStage": "P1R-3 Account Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/AppAccountMarketRecordController.java"
],
@ -1648,7 +1648,7 @@
],
"targetStage": "P1R-3 Account Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/AppAccountNewApiController.java"
],
@ -1728,7 +1728,7 @@
],
"targetStage": "P1R-3 Account Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/AppAccountNewApiController.java"
],
@ -1808,7 +1808,7 @@
],
"targetStage": "P1R-3 Account Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/AppAccountMarketRecordController.java"
],
@ -1890,7 +1890,7 @@
],
"targetStage": "P1R-3 Account Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/AppAccountMarketRecordController.java"
],
@ -1970,7 +1970,7 @@
],
"targetStage": "P1R-3 Account Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/AppAccountNewApiController.java"
],
@ -2050,7 +2050,7 @@
],
"targetStage": "P1R-3 Account Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/AppAccountNewApiController.java"
],
@ -2291,7 +2291,7 @@
],
"targetStage": "P1R-3 Account Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/AppAccountSecurityController.java"
],
@ -2371,7 +2371,7 @@
],
"targetStage": "P1R-3 Account Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/controller/app/account/AppAccountEntitlementController.java"
],
@ -7532,7 +7532,7 @@
],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/admin/AdminContentController.java"
],
@ -7586,7 +7586,7 @@
],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/admin/AdminContentController.java"
],
@ -7836,7 +7836,7 @@
"externalDependencies": [],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentImportParseController.java"
],
@ -7886,7 +7886,7 @@
"externalDependencies": [],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentImportParseController.java"
],
@ -7938,7 +7938,7 @@
],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentExportController.java"
],
@ -7992,7 +7992,7 @@
],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentExportController.java"
],
@ -8046,7 +8046,7 @@
],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentImportParseController.java"
],
@ -8099,7 +8099,7 @@
],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentImportParseController.java"
],
@ -8152,7 +8152,7 @@
],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentImportParseController.java"
],
@ -8205,7 +8205,7 @@
],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentImportParseController.java"
],
@ -8258,7 +8258,7 @@
],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentImportParseController.java"
],
@ -8358,7 +8358,7 @@
"externalDependencies": [],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentController.java"
],
@ -8408,7 +8408,7 @@
"externalDependencies": [],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentController.java"
],
@ -8508,7 +8508,7 @@
"externalDependencies": [],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentController.java"
],
@ -8558,7 +8558,7 @@
"externalDependencies": [],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentController.java"
],
@ -8708,7 +8708,7 @@
"externalDependencies": [],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentStructureController.java"
],
@ -8808,7 +8808,7 @@
"externalDependencies": [],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentStructureController.java"
],
@ -8861,7 +8861,7 @@
],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentSourceController.java"
],
@ -8961,7 +8961,7 @@
"externalDependencies": [],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentController.java"
],
@ -9011,7 +9011,7 @@
"externalDependencies": [],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentController.java"
],
@ -9111,7 +9111,7 @@
"externalDependencies": [],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentController.java"
],
@ -9211,7 +9211,7 @@
"externalDependencies": [],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentController.java"
],
@ -9261,7 +9261,7 @@
"externalDependencies": [],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentStructureController.java"
],
@ -9311,7 +9311,7 @@
"externalDependencies": [],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentMetaProjectionController.java"
],
@ -9363,7 +9363,7 @@
],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentExportController.java"
],
@ -9417,7 +9417,7 @@
],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentExportController.java"
],
@ -9471,7 +9471,7 @@
],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentImportParseController.java"
],
@ -9521,7 +9521,7 @@
"externalDependencies": [],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentMetaProjectionController.java"
],
@ -9571,7 +9571,7 @@
"externalDependencies": [],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentMetaProjectionController.java"
],
@ -9624,7 +9624,7 @@
],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentImportParseController.java"
],
@ -9724,7 +9724,7 @@
"externalDependencies": [],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentPlanningController.java"
],
@ -9774,7 +9774,7 @@
"externalDependencies": [],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentPlanningController.java"
],
@ -9824,7 +9824,7 @@
"externalDependencies": [],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentPlanningController.java"
],
@ -9874,7 +9874,7 @@
"externalDependencies": [],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentPlanningController.java"
],
@ -9924,7 +9924,7 @@
"externalDependencies": [],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentPlanningController.java"
],
@ -9974,7 +9974,7 @@
"externalDependencies": [],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentPlanningController.java"
],
@ -10027,7 +10027,7 @@
],
"targetStage": "P1R-1 Content Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-content/muse-module-content-server/src/main/java/cn/iocoder/muse/module/content/controller/app/AppContentPlanningController.java"
],
@ -13188,7 +13188,7 @@
"externalDependencies": [],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/admin/muse/AdminMuseMarketAppealController.java"
],
@ -13239,7 +13239,7 @@
"externalDependencies": [],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/admin/muse/AdminMuseMarketAppealController.java"
],
@ -13290,7 +13290,7 @@
"externalDependencies": [],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/admin/muse/AdminMuseMarketAppealController.java"
],
@ -13341,7 +13341,7 @@
"externalDependencies": [],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/admin/muse/AdminMuseMarketAssetController.java"
],
@ -13392,7 +13392,7 @@
"externalDependencies": [],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/admin/muse/AdminMuseMarketAssetController.java"
],
@ -13443,7 +13443,7 @@
"externalDependencies": [],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/admin/muse/AdminMuseMarketAssetController.java"
],
@ -13494,7 +13494,7 @@
"externalDependencies": [],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/admin/muse/AdminMuseMarketAssetController.java"
],
@ -13545,7 +13545,7 @@
"externalDependencies": [],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/admin/muse/AdminMuseMarketAssetController.java"
],
@ -13596,7 +13596,7 @@
"externalDependencies": [],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/admin/muse/AdminMuseMarketReviewController.java"
],
@ -13647,7 +13647,7 @@
"externalDependencies": [],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/admin/muse/AdminMuseMarketReviewController.java"
],
@ -13698,7 +13698,7 @@
"externalDependencies": [],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/admin/muse/AdminMuseMarketReviewController.java"
],
@ -13752,7 +13752,7 @@
],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/app/muse/AppMuseMarketAppealController.java"
],
@ -13806,7 +13806,7 @@
],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/app/muse/AppMuseMarketAppealController.java"
],
@ -13860,7 +13860,7 @@
],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/app/muse/AppMuseMarketAppealController.java"
],
@ -13914,7 +13914,7 @@
],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/app/muse/AppMuseMarketplaceAssetController.java"
],
@ -14022,7 +14022,7 @@
],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/app/muse/AppMuseMarketHandoffController.java"
],
@ -14184,7 +14184,7 @@
],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/app/muse/AppMuseMarketplaceAssetController.java"
],
@ -14238,7 +14238,7 @@
],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/app/muse/AppMuseMarketLicenseController.java"
],
@ -14292,7 +14292,7 @@
],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/app/muse/AppMuseMarketLicenseController.java"
],
@ -14400,7 +14400,7 @@
],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/app/muse/AppMuseMarketHandoffController.java"
],
@ -14454,7 +14454,7 @@
],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/app/muse/AppMuseMarketHandoffController.java"
],
@ -14508,7 +14508,7 @@
],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/app/muse/AppMuseMarketHandoffController.java"
],
@ -14562,7 +14562,7 @@
],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/app/muse/AppMuseMarketPublishController.java"
],
@ -14616,7 +14616,7 @@
],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/app/muse/AppMuseMarketPublishController.java"
],
@ -14670,7 +14670,7 @@
],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/app/muse/AppMuseMarketPublishController.java"
],
@ -14724,7 +14724,7 @@
],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/app/muse/AppMuseMarketPublishController.java"
],
@ -14778,7 +14778,7 @@
],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/app/muse/AppMuseMarketPublishController.java"
],
@ -14832,7 +14832,7 @@
],
"targetStage": "P1R-6 Market Real API",
"implementationStatus": "dedicated",
"completionStatus": "needs_verification",
"completionStatus": "completed",
"controllerFiles": [
"muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/controller/app/muse/AppMuseMarketplaceAssetController.java"
],

View File

@ -6,5 +6,5 @@
- **边界(不可违反)**:**正文 Canonical 唯一写入方**;Block 写入须带 expectedRevision 且 revision 单调递增;**Accept Suggestion 是候选进正文的唯一合法入口**——只写正文 + 候选归档 + 来源归因,**不写 Local KB**;守 BC 边界不碰他域 `.dal`([bc-boundaries](../../.agents/rules/bc-boundaries.md))。
- **out-of-scope**:知识入库(归 knowledge BC)、AI 生成(归 ai BC)。
- **现状**:只读评估 82%;后端齐全,契约高度一致。
- **2026-06-17 验收债**:批1 已补 work/chapter/block 生命周期 11 op 真实 PG 证据;批20-28 已补 planning candidate 5 + meta-projection 3 + style-check 2 + chapter-parse-result 决策 2 + parse-job 生命周期/创建 5 + import-task 2 + export-task 4 + 管理端任务列表 2 + mergeBlockSuggestion 1,均真实 PG 绿且证据就绪待人工批。批26 `P1rContentExportTaskCompletedApprovalIT` 补 export-task 簇 4 op(getExportTask/exportWork/createExportTask/downloadExportPackage)并修正 `ContentExportServiceImpl` public `exportWork/createExportTask` 事务边界,IT 已用 command_log 0 残留断言验证预占命令回滚。批27 扩展 `P1rContentAdminReadCompletedApprovalIT` 补 adminListImportTasks/adminListExportTasks:真实 `/admin-api` + method security + 租户行拦截器,读 `muse_content_import_task`/`muse_content_export_task` 真实行,覆盖分页/筛选/workTitle 回填/跨租户不泄露/RBAC/API version/no-write,并补齐老 harness 专属 `_test` 库自动创建。批28 扩展 `P1rContentParseJobLifecycleCompletedApprovalIT` 补 createParseJob 守卫/fail-closed/事务回滚证据,并修正 `P1rContentMergeSuggestionIT` 老 harness 专属 `_test` 库自动创建后复验 mergeBlockSuggestion 真实写 Canonical 正文链路。content/account/market needs_verification 验收债均已清零;coverage JSON completed 翻转仍待人工批准,agent 不自批。
- **2026-06-17 验收债**:批1 已补 work/chapter/block 生命周期 11 op 真实 PG 证据;批20-28 已补 planning candidate 5 + meta-projection 3 + style-check 2 + chapter-parse-result 决策 2 + parse-job 生命周期/创建 5 + import-task 2 + export-task 4 + 管理端任务列表 2 + mergeBlockSuggestion 1,均真实 PG 绿且证据已人工批准并翻 completed。批26 `P1rContentExportTaskCompletedApprovalIT` 补 export-task 簇 4 op(getExportTask/exportWork/createExportTask/downloadExportPackage)并修正 `ContentExportServiceImpl` public `exportWork/createExportTask` 事务边界,IT 已用 command_log 0 残留断言验证预占命令回滚。批27 扩展 `P1rContentAdminReadCompletedApprovalIT` 补 adminListImportTasks/adminListExportTasks:真实 `/admin-api` + method security + 租户行拦截器,读 `muse_content_import_task`/`muse_content_export_task` 真实行,覆盖分页/筛选/workTitle 回填/跨租户不泄露/RBAC/API version/no-write,并补齐老 harness 专属 `_test` 库自动创建。批28 扩展 `P1rContentParseJobLifecycleCompletedApprovalIT` 补 createParseJob 守卫/fail-closed/事务回滚证据,并修正 `P1rContentMergeSuggestionIT` 老 harness 专属 `_test` 库自动创建后复验 mergeBlockSuggestion 真实写 Canonical 正文链路。content/account/market needs_verification 验收债均已清零;coverage JSON completed 已按人工批准翻转。
- **关键风险 / TODO**:Content 验收债已补齐真实 PG 证据;外部 owner(AI/Meta/FileService/解析投影)未接入的路径仍按合同 fail-closed,需要配置真实外部依赖或 owner 服务后才能从 fail-closed 升级为完整成功路径。

View File

@ -5,5 +5,5 @@
- **目标(owner 职责)**:市场资产(Work/Agent/KB Asset)/ Publish Draft / Publish Check Snapshot / Review / Listing / License / Purchase / Install / Handoff Token / 授权摘要 / 跳转审计 / Governance Action / Source Status Event。
- **边界(不可违反)**:**授权 ≠ 所有权转移**;市场**非**源事实 owner,目标事实回目标 owner;Work 资产仅只读且排除出 install(`INSTALLABLE_ASSET_TYPES=Set.of(agent,knowledge_base)`);守 BC 边界不碰他域 `.dal`([bc-boundaries](../../.agents/rules/bc-boundaries.md))。
- **out-of-scope**:完整电商支付结算 DRM(项目非目标);模板化/参考写入/AI 上下文受 Feature Gate 默认关闭。
- **现状**:只读评估 82%;核心不变式已被代码强制。**生产者飞轮已端到端打通并活体证(2026-06-15)**:发布草稿→检查→提交→上架状态可视化→申诉(提交/补充材料/撤回)→申诉态回显(`MarketPublish`+`market-publish.spec.ts` 8/8,见[总账](../../docs/mvp/进度总账.md) §五C)。本会话新增 3 处 app-api 契约:`PublishRecordItem.marketAssetId`(物化资产 id,解申诉 assetId 映射 gap)、`GET /marketplace/appeals`(我的申诉列表)、记录 `appealStatus` 回填(`selectLatestByAssetIdAndUser`)。**2026-06-16 补真实 PG 验收证据**:`P1rMarketPublishProducerCompletedApprovalIT` 覆盖发布生产侧 5 op,真实 PG 3/3 绿;`P1rMarketAdminAppealCompletedApprovalIT` 覆盖管理端申诉 3 op(adminListAppeals/adminGetAppeal/adminResolveAppeal),真实 PG 6/6 绿;`P1rMarketAdminPublishReviewCompletedApprovalIT` 覆盖管理端发布审核 3 op(adminListPublishRequests/adminApprovePublishRequest/adminRejectPublishRequest),真实 PG 6/6 绿;`P1rMarketProducerAppealCompletedApprovalIT` 覆盖生产者申诉写路 3 op(submitAppeal/supplementAppeal/withdrawAppeal,app 入口 + owner 隔离 + 脱敏 + 状态 CAS + 冲突回滚),真实 PG 7/7 绿(独立复跑)。**2026-06-17 续补**:`P1rMarketAdminAssetReadsCompletedApprovalIT` 覆盖管理端资产治理读 2 op(adminListMarketAssets/adminGetMarketAsset:tenant 隔离 + assetType/listingStatus(not_listed↔draft 归一)/publisherId 过滤、详情资产快照 + 授权/安装/绑定/受影响任务计数全 0(关联表空)、缺资产/跨租户→MARKET_ASSET_NOT_EXISTS、API version/RBAC(muse:market:asset:query)fail-closed、纯读 no-write),真实 PG 2/2 绿(独立复跑)。`P1rMarketGovernanceWriteCompletedApprovalIT` 覆盖管理端资产治理写 3 op(adminPreviewGovernanceImpact/adminDelistAsset/adminRecallAsset:影响预览→凭预览下架 listed→delisted 的 expectedStatus CAS→凭预览召回 listed→recalled + 目标 owner 传播 fail-closed 如实记录 recalled/recorded/TARGET_OWNER_UNAVAILABLE;命令幂等、合同枚举 @Pattern→BAD_REQUEST、缺预览/CAS 阻断/缺资产/API version/RBAC fail-closed 0 写),真实 PG 4/4 绿(独立复跑)。`P1rMarketplaceDiscoveryReadsCompletedApprovalIT` 覆盖 marketplace 发现读 3 op(listMarketplaceAssets/listMarketplaceRecommendations/getGovernanceImpact:App 可见性隔离 listed 公开/非公开仅 publisher 自见 + assetType 过滤、fallback 推荐 + 理由、治理影响读 publisher/受影响者门禁 非属主无关联→MARKET_RESOURCE_FORBIDDEN、缺资产/API version fail-closed、纯读 no-write),真实 PG 4/4 绿(独立复跑)。`P1rMarketLicenseInstallCompletedApprovalIT` 覆盖采纳链 2 op(purchaseAsset/installMarketplaceAsset:购买写授权快照+购买事实+命令并跨 BC 同步 purchase/license 两条 Account 投影、安装要求已购授权+仅 agent/kb 可安装+写 installed 记录、命令幂等、未上架/缺资产/授权类型不符/无授权/作品不可安装/API version fail-closed 0 写),真实 PG 3/3 绿(独立复跑);证据就绪,completed 仍待人工批准。`P1rMarketHandoffClusterCompletedApprovalIT` 覆盖 handoff 簇 4 op(createBindPrecheck/createMarketplaceHandoff/getHandoffStatus/cancelHandoff:已购 active 授权快照→来源授权摘要(handoffReady)→一次性 handoff token(明文不入库、只存 sha256 hash,事件快照不含明文)→只读回显 pending→expectedStatus CAS 取消(pending→cancelled)的端到端链;bind/handoff 回放幂等、cancel 终态后再取消被取消性守卫拒绝且不双写;非法 version/缺资产/无授权(授权≠可达)/目标 owner 白名单外(LocalMarketTargetOwnerFacade 本地目标页 fail-closed)/跨属主 token 读取与取消(属主隔离 RESOURCE_FORBIDDEN)/取消 CAS 期望态不匹配(reserveCommand MANDATORY 预占随事务回滚)失败路径 0 写),真实 PG 3/3 绿(独立复跑);至此 market needs_verification 28 op 全补 dedicated 真实 PG 证据,证据就绪待人工批。
- **关键风险 / TODO**:① **资产物化只在 admin 审核通过(`markListed`)发生**——submit 阶段 `publish_request.asset_id=draft.id` 占位,故未上架资产无 `muse_market_asset` 行,申诉(`requireAsset`)仅对已物化(曾上架)资产可达;② 申诉证据材料附件上传(`attachmentIds` 当前前端置空);③ 上架后下架/召回的生产者自助入口;④ **market 验收债已清零(2026-06-17)**:批15-19 补 14 op(资产治理读 2 + 治理写 3 + marketplace 发现读 3 + 采纳链 purchase/install 2 + handoff 簇 4)叠加本战役前 14 op(发布生产 5 + 管理端申诉 3 + 发布审核 3 + 生产者申诉 3)= market needs_verification 28 op 全有 dedicated 真实 PG 证据;**台账 completed flip + 覆盖门禁 `P1rApiCoverageReportTest.APPROVED_COMPLETED_OPERATIONS` 仍须人工批准,agent 不得自批,见铁律**。
- **现状**:只读评估 82%;核心不变式已被代码强制。**生产者飞轮已端到端打通并活体证(2026-06-15)**:发布草稿→检查→提交→上架状态可视化→申诉(提交/补充材料/撤回)→申诉态回显(`MarketPublish`+`market-publish.spec.ts` 8/8,见[总账](../../docs/mvp/进度总账.md) §五C)。本会话新增 3 处 app-api 契约:`PublishRecordItem.marketAssetId`(物化资产 id,解申诉 assetId 映射 gap)、`GET /marketplace/appeals`(我的申诉列表)、记录 `appealStatus` 回填(`selectLatestByAssetIdAndUser`)。**2026-06-16 补真实 PG 验收证据**:`P1rMarketPublishProducerCompletedApprovalIT` 覆盖发布生产侧 5 op,真实 PG 3/3 绿;`P1rMarketAdminAppealCompletedApprovalIT` 覆盖管理端申诉 3 op(adminListAppeals/adminGetAppeal/adminResolveAppeal),真实 PG 6/6 绿;`P1rMarketAdminPublishReviewCompletedApprovalIT` 覆盖管理端发布审核 3 op(adminListPublishRequests/adminApprovePublishRequest/adminRejectPublishRequest),真实 PG 6/6 绿;`P1rMarketProducerAppealCompletedApprovalIT` 覆盖生产者申诉写路 3 op(submitAppeal/supplementAppeal/withdrawAppeal,app 入口 + owner 隔离 + 脱敏 + 状态 CAS + 冲突回滚),真实 PG 7/7 绿(独立复跑)。**2026-06-17 续补**:`P1rMarketAdminAssetReadsCompletedApprovalIT` 覆盖管理端资产治理读 2 op(adminListMarketAssets/adminGetMarketAsset:tenant 隔离 + assetType/listingStatus(not_listed↔draft 归一)/publisherId 过滤、详情资产快照 + 授权/安装/绑定/受影响任务计数全 0(关联表空)、缺资产/跨租户→MARKET_ASSET_NOT_EXISTS、API version/RBAC(muse:market:asset:query)fail-closed、纯读 no-write),真实 PG 2/2 绿(独立复跑)。`P1rMarketGovernanceWriteCompletedApprovalIT` 覆盖管理端资产治理写 3 op(adminPreviewGovernanceImpact/adminDelistAsset/adminRecallAsset:影响预览→凭预览下架 listed→delisted 的 expectedStatus CAS→凭预览召回 listed→recalled + 目标 owner 传播 fail-closed 如实记录 recalled/recorded/TARGET_OWNER_UNAVAILABLE;命令幂等、合同枚举 @Pattern→BAD_REQUEST、缺预览/CAS 阻断/缺资产/API version/RBAC fail-closed 0 写),真实 PG 4/4 绿(独立复跑)。`P1rMarketplaceDiscoveryReadsCompletedApprovalIT` 覆盖 marketplace 发现读 3 op(listMarketplaceAssets/listMarketplaceRecommendations/getGovernanceImpact:App 可见性隔离 listed 公开/非公开仅 publisher 自见 + assetType 过滤、fallback 推荐 + 理由、治理影响读 publisher/受影响者门禁 非属主无关联→MARKET_RESOURCE_FORBIDDEN、缺资产/API version fail-closed、纯读 no-write),真实 PG 4/4 绿(独立复跑)。`P1rMarketLicenseInstallCompletedApprovalIT` 覆盖采纳链 2 op(purchaseAsset/installMarketplaceAsset:购买写授权快照+购买事实+命令并跨 BC 同步 purchase/license 两条 Account 投影、安装要求已购授权+仅 agent/kb 可安装+写 installed 记录、命令幂等、未上架/缺资产/授权类型不符/无授权/作品不可安装/API version fail-closed 0 写),真实 PG 3/3 绿(独立复跑);证据已人工批准并翻 completed。`P1rMarketHandoffClusterCompletedApprovalIT` 覆盖 handoff 簇 4 op(createBindPrecheck/createMarketplaceHandoff/getHandoffStatus/cancelHandoff:已购 active 授权快照→来源授权摘要(handoffReady)→一次性 handoff token(明文不入库、只存 sha256 hash,事件快照不含明文)→只读回显 pending→expectedStatus CAS 取消(pending→cancelled)的端到端链;bind/handoff 回放幂等、cancel 终态后再取消被取消性守卫拒绝且不双写;非法 version/缺资产/无授权(授权≠可达)/目标 owner 白名单外(LocalMarketTargetOwnerFacade 本地目标页 fail-closed)/跨属主 token 读取与取消(属主隔离 RESOURCE_FORBIDDEN)/取消 CAS 期望态不匹配(reserveCommand MANDATORY 预占随事务回滚)失败路径 0 写),真实 PG 3/3 绿(独立复跑);至此 market needs_verification 28 op 全补 dedicated 真实 PG 证据,证据已人工批准并翻 completed。
- **关键风险 / TODO**:① **资产物化只在 admin 审核通过(`markListed`)发生**——submit 阶段 `publish_request.asset_id=draft.id` 占位,故未上架资产无 `muse_market_asset` 行,申诉(`requireAsset`)仅对已物化(曾上架)资产可达;② 申诉证据材料附件上传(`attachmentIds` 当前前端置空);③ 上架后下架/召回的生产者自助入口;④ **market 验收债已清零(2026-06-17)**:批15-19 补 14 op(资产治理读 2 + 治理写 3 + marketplace 发现读 3 + 采纳链 purchase/install 2 + handoff 簇 4)叠加本战役前 14 op(发布生产 5 + 管理端申诉 3 + 发布审核 3 + 生产者申诉 3)= market needs_verification 28 op 全有 dedicated 真实 PG 证据;**台账 completed flip 与覆盖门禁 `P1rApiCoverageReportTest.APPROVED_COMPLETED_OPERATIONS` 已按人工批准同步**。

View File

@ -5,5 +5,5 @@
- **目标(owner 职责)**:Account/Usage/Audit BC——Profile / Entitlement-Quota / Usage Record / Personal Center Summary / 记录总览 / Security Event / New-API Binding / Audit Log / Download Credential。**member = Account BC 物理承载,不新增 account 模块**。
- **边界(不可违反)**:是用户可见权益的聚合**读模型**与跳转入口,**不是消费账本事实源,不能反写**作品/知识/智能体/市场事实;高危审计 append-only + WORM/哈希链;Entitlement/Quota/Usage/Security/Binding 唯一写入 authority;守 BC 边界不碰他域 `.dal`([bc-boundaries](../../.agents/rules/bc-boundaries.md))。
- **out-of-scope**:他域事实写入。
- **现状**:只读评估 68%。**2026-06-15 活体订正**:单体内 `MarketAccountProjectionFacade` 由 market 的 `MarketAccountProjectionProvider` 真实提供,purchases/licenses/publish-records 三端可读投影,不是 `*_UNAVAILABLE` 缺口。**2026-06-16 补真实 PG 验收证据**:`P1rAccountMarketRecordsCompletedApprovalIT` 覆盖 appListPurchases/appListLicenses/appListPublishRecords,真实 PG 3/3 绿;`P1rAccountQuotaRequestCompletedApprovalIT` 覆盖 appCreateQuotaRequest/appGetQuotaRequest/adminCreateQuotaRequest(命令幂等+commandId 冲突回滚+owner/tenant 隔离+RBAC+类型白名单),真实 PG 5/5 绿(独立复跑);`P1rAccountUsageObservabilityCompletedApprovalIT` 覆盖 getAppUsage/appGetIntegrationCallByCorrelation/adminGetIntegrationCallByCorrelation(用量按 owner 聚合 token/pending/anomaly/byModel+跨用户隔离+period 白名单、外部调用 app owner 守卫/admin 无 owner 限制+RBAC、三 op 纯读 no-write、缺用户/not-found/API version/RBAC fail-closed),真实 PG 4/4 绿(独立复跑);`P1rAccountNewApiBindingClusterCompletedApprovalIT` 覆盖 getAppNewApiBinding/adminListNewApiBindings/appRecheckNewApiBinding(绑定摘要 owner 读 + active→bound 归一、admin 列表以账户用户为分页主表 + EXISTS/NOT EXISTS 状态筛选 + RBAC、两读 no-write、recheck 单体 New-API 不可用正确 fail-closed:命令预占回滚但失败调用 REQUIRES_NEW 独立落库),真实 PG 4/4 绿(独立复跑);`P1rAccountExportDownloadClusterCompletedApprovalIT` 覆盖 appCreateExportTask/appGetExportTask/appDownloadExport(FileService 未接入时非敏感导出落 queued 任务+命令+审计、不伪造 completed/凭证、敏感类型缺 step-up fail-closed、命令幂等;get owner 读 + 跨 owner not found + no-write;download 凭证门禁 + FileService 不可用正确 fail-closed:@Transactional 回滚一次性消费、不写审计),真实 PG 4/4 绿(独立复跑);`P1rAccountAdminReadsCompletedApprovalIT` 覆盖 adminListUsageRecords/adminGetCallAttributionJob(用量以账户用户为分页主表库内聚合 token/pending/failed/attributionStatus、调用归因 job 按 jobId 读 job+items 归一状态+分桶计数、RBAC+API version fail-closed、纯读 no-write),真实 PG 3/3 绿(独立复跑);`P1rAccountAdminWritesCompletedApprovalIT` 覆盖 adminCreateNewApiBinding/adminCreateCallAttributionJob(binding 单体 New-API 不可用正确 fail-closed:命令回滚+失败调用 REQUIRES_NEW 独立落库+binding 不写;attribution job 基于已存在 correlationId 调用建 queued job+命令幂等+callIds 白名单/expectedCallRevision/缺调用记录/RBAC/API version fail-closed),真实 PG 3/3 绿(独立复跑);`P1rAccountSecurityEventAckCompletedApprovalIT` 覆盖 appAcknowledgeSecurityEvent(owner 校验事件归属 + 追加表写处理轨迹 + 基础事件 acknowledged 置真 + 命令幂等 + 审计;非法 action/跨 owner NOT_FOUND/非数字 eventId/缺用户/API version fail-closed 且 0 写),真实 PG 2/2 绿(独立复跑);`P1rAccountAdminPurchaseRecordsCompletedApprovalIT` 覆盖 adminListPurchaseRecords(跨模块 base-package=cn.iocoder.muse.module + 单体内 market 的 `MarketAccountProjectionProvider` 真实判定 purchase 投影可用,读端只读 Account 自有投影表 muse_account_record_projection;无 userId→跨用户全量、userId 过滤→owner 限定 + source_status→admin status 归一 + 资产信息从 title/snapshot 回填、非法 status/API version/RBAC(muse:account:query) fail-closed、纯读 no-write,Account 投影写端口 stub 越界反假绿),真实 PG 2/2 绿(独立复跑);证据就绪,completed 仍待人工批准。
- **关键风险 / TODO**:account needs_verification 验收债**已清零**:末位 adminListPurchaseRecords 经 `P1rAccountAdminPurchaseRecordsCompletedApprovalIT`(跨模块 base-package=cn.iocoder.muse.module + import MarketAccountProjectionProvider)真实 PG 2/2 绿补证;批3(市场记录读)+ 批7-14 account needs_verification op 全部补真实 PG 证据、证据就绪待人工批(completed 仍由人工批台账,agent 不自批)。截至 2026-06-17,content/market/account 三域 needs_verification 验收债均已补齐真实 PG 证据;剩余动作是人工批准 coverage JSON completed flip + 覆盖门禁 `P1rApiCoverageReportTest.APPROVED_COMPLETED_OPERATIONS`。前端仍有深页未全覆盖真实后端。
- **现状**:只读评估 68%。**2026-06-15 活体订正**:单体内 `MarketAccountProjectionFacade` 由 market 的 `MarketAccountProjectionProvider` 真实提供,purchases/licenses/publish-records 三端可读投影,不是 `*_UNAVAILABLE` 缺口。**2026-06-16 补真实 PG 验收证据**:`P1rAccountMarketRecordsCompletedApprovalIT` 覆盖 appListPurchases/appListLicenses/appListPublishRecords,真实 PG 3/3 绿;`P1rAccountQuotaRequestCompletedApprovalIT` 覆盖 appCreateQuotaRequest/appGetQuotaRequest/adminCreateQuotaRequest(命令幂等+commandId 冲突回滚+owner/tenant 隔离+RBAC+类型白名单),真实 PG 5/5 绿(独立复跑);`P1rAccountUsageObservabilityCompletedApprovalIT` 覆盖 getAppUsage/appGetIntegrationCallByCorrelation/adminGetIntegrationCallByCorrelation(用量按 owner 聚合 token/pending/anomaly/byModel+跨用户隔离+period 白名单、外部调用 app owner 守卫/admin 无 owner 限制+RBAC、三 op 纯读 no-write、缺用户/not-found/API version/RBAC fail-closed),真实 PG 4/4 绿(独立复跑);`P1rAccountNewApiBindingClusterCompletedApprovalIT` 覆盖 getAppNewApiBinding/adminListNewApiBindings/appRecheckNewApiBinding(绑定摘要 owner 读 + active→bound 归一、admin 列表以账户用户为分页主表 + EXISTS/NOT EXISTS 状态筛选 + RBAC、两读 no-write、recheck 单体 New-API 不可用正确 fail-closed:命令预占回滚但失败调用 REQUIRES_NEW 独立落库),真实 PG 4/4 绿(独立复跑);`P1rAccountExportDownloadClusterCompletedApprovalIT` 覆盖 appCreateExportTask/appGetExportTask/appDownloadExport(FileService 未接入时非敏感导出落 queued 任务+命令+审计、不伪造 completed/凭证、敏感类型缺 step-up fail-closed、命令幂等;get owner 读 + 跨 owner not found + no-write;download 凭证门禁 + FileService 不可用正确 fail-closed:@Transactional 回滚一次性消费、不写审计),真实 PG 4/4 绿(独立复跑);`P1rAccountAdminReadsCompletedApprovalIT` 覆盖 adminListUsageRecords/adminGetCallAttributionJob(用量以账户用户为分页主表库内聚合 token/pending/failed/attributionStatus、调用归因 job 按 jobId 读 job+items 归一状态+分桶计数、RBAC+API version fail-closed、纯读 no-write),真实 PG 3/3 绿(独立复跑);`P1rAccountAdminWritesCompletedApprovalIT` 覆盖 adminCreateNewApiBinding/adminCreateCallAttributionJob(binding 单体 New-API 不可用正确 fail-closed:命令回滚+失败调用 REQUIRES_NEW 独立落库+binding 不写;attribution job 基于已存在 correlationId 调用建 queued job+命令幂等+callIds 白名单/expectedCallRevision/缺调用记录/RBAC/API version fail-closed),真实 PG 3/3 绿(独立复跑);`P1rAccountSecurityEventAckCompletedApprovalIT` 覆盖 appAcknowledgeSecurityEvent(owner 校验事件归属 + 追加表写处理轨迹 + 基础事件 acknowledged 置真 + 命令幂等 + 审计;非法 action/跨 owner NOT_FOUND/非数字 eventId/缺用户/API version fail-closed 且 0 写),真实 PG 2/2 绿(独立复跑);`P1rAccountAdminPurchaseRecordsCompletedApprovalIT` 覆盖 adminListPurchaseRecords(跨模块 base-package=cn.iocoder.muse.module + 单体内 market 的 `MarketAccountProjectionProvider` 真实判定 purchase 投影可用,读端只读 Account 自有投影表 muse_account_record_projection;无 userId→跨用户全量、userId 过滤→owner 限定 + source_status→admin status 归一 + 资产信息从 title/snapshot 回填、非法 status/API version/RBAC(muse:account:query) fail-closed、纯读 no-write,Account 投影写端口 stub 越界反假绿),真实 PG 2/2 绿(独立复跑);证据已人工批准并翻 completed。
- **关键风险 / TODO**:account needs_verification 验收债**已清零**:末位 adminListPurchaseRecords 经 `P1rAccountAdminPurchaseRecordsCompletedApprovalIT`(跨模块 base-package=cn.iocoder.muse.module + import MarketAccountProjectionProvider)真实 PG 2/2 绿补证;批3(市场记录读)+ 批7-14 account needs_verification op 全部补真实 PG 证据、证据已人工批准并翻 completed。截至 2026-06-17,content/market/account 三域 needs_verification 验收债均已补齐真实 PG 证据,coverage JSON completed flip 与覆盖门禁批准集合已按人工批准同步。前端仍有深页未全覆盖真实后端。

View File

@ -19,8 +19,8 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
/**
* P1R-3 Account 真实 API 阶段覆盖报告门禁。
*
* <p>这个 gate 只证明 P1R-3 coverage 已收口到 dedicated / needs_verification,
* 不证明 Account 业务 runtime 已经 completed。后续如果要推进 completed,必须先补充真实运行态验收证据。</p>
* <p>这个 gate 证明 P1R-3 coverage 已收口到 dedicated;2026-06-17 用户批准后,
* Account/Content 已有真实 PG 验收证据的 operation 必须全部推进 completed。</p>
*/
class P1rAccountRealApiGateTest {
@ -40,40 +40,6 @@ class P1rAccountRealApiGateTest {
"blocked"
);
/** 已批准的 Account 本域闭合接口,仍保持 operation-level approval。 */
private static final Set<String> APPROVED_ACCOUNT_COMPLETED_OPERATIONS = Set.of(
"getCurrentUser",
"getProfile",
"updateProfile",
"adminListAccountUsers",
"adminGetUserEntitlements",
"getAppEntitlements",
"adminGetBalanceSnapshots",
"getAppBalanceSnapshots",
"adminCreateQuotaAdjustment",
"adminListQuotaAdjustments",
"appListSecurityEvents",
"appGetSecurityEvent"
);
/** Content completed approval 当前只允许推进 14 个 operation。 */
private static final Set<String> APPROVED_CONTENT_COMPLETED_OPERATIONS = Set.of(
"listWorks",
"getWork",
"listChapters",
"getChapter",
"listBlocks",
"getBlock",
"saveBlock",
"getBlockSourceAttribution",
"getPlanning",
"savePlanningItem",
"adminListWorks",
"adminGetWork",
"adminListChapters",
"adminRiskAction"
);
/** P1R-3 计划第 1 节冻结的 Account operation、方法和路径清单。 */
private static final Map<String, String> P1R3_ACCOUNT_OPERATION_SIGNATURES = Map.ofEntries(
entry("adminListAccountUsers", "GET /admin-api/muse/account/users"),
@ -166,7 +132,7 @@ class P1rAccountRealApiGateTest {
}
/**
* 验证 Account 第一批已批准 operation 推进 completed,其余 operation 继续保持 needs_verification。
* 验证用户批准后 Account 33 个 operation 全部推进 completed。
*
* @throws IOException 读取覆盖报告失败时抛出
*/
@ -180,23 +146,22 @@ class P1rAccountRealApiGateTest {
String operationId = operation.path("operationId").asText("<missing-operationId>");
assertEquals("dedicated", operation.path("implementationStatus").asText(),
operationId + " Account completed approval 后仍必须是 dedicated");
if (APPROVED_ACCOUNT_COMPLETED_OPERATIONS.contains(operationId)) {
if ("completed".equals(operation.path("completionStatus").asText())) {
completed++;
assertEquals("completed", operation.path("completionStatus").asText(),
operationId + " 已获批准后必须推进 completed");
} else {
needsVerification++;
assertEquals("needs_verification", operation.path("completionStatus").asText(),
operationId + " 未获批准,必须继续保持 needs_verification");
}
if ("needs_verification".equals(operation.path("completionStatus").asText())) {
needsVerification++;
}
assertEquals("completed", operation.path("completionStatus").asText(),
operationId + " 已获用户批准后必须推进 completed");
}
assertEquals(12, completed, "Account Security Events read completed approval 后只能有 12 个 operation completed");
assertEquals(21, needsVerification, "Account 剩余 21 个 operation 必须继续 needs_verification");
assertEquals(33, completed, "Account 人工批准后必须有 33 个 operation completed");
assertEquals(0, needsVerification, "Account 人工批准后不能继续保留 needs_verification");
}
/**
* 验证 Content 只推进当前已批准的 14 个 operation,防止 Account gate 漏掉 Content 未批准项回退检查。
* 验证 Content 51 个 operation 已随用户批准全部 completed,防止 Account gate 漏掉跨域回退检查。
*
* @throws IOException 读取覆盖报告失败时抛出
*/
@ -211,18 +176,17 @@ class P1rAccountRealApiGateTest {
String operationId = operation.path("operationId").asText("<missing-operationId>");
assertEquals("dedicated", operation.path("implementationStatus").asText(),
"Content/" + operationId + " 必须继续保持 dedicated");
if (APPROVED_CONTENT_COMPLETED_OPERATIONS.contains(operationId)) {
if ("completed".equals(operation.path("completionStatus").asText())) {
completed++;
assertEquals("completed", operation.path("completionStatus").asText(),
"Content/" + operationId + " 已获本轮批准后必须 completed");
} else {
needsVerification++;
assertEquals("needs_verification", operation.path("completionStatus").asText(),
"Content/" + operationId + " 未获本轮批准,必须继续 needs_verification");
}
if ("needs_verification".equals(operation.path("completionStatus").asText())) {
needsVerification++;
}
assertEquals("completed", operation.path("completionStatus").asText(),
"Content/" + operationId + " 已获用户批准后必须 completed");
}
assertEquals(14, completed, "Content Admin RiskAction completed approval 后只能推进 14 个 operation");
assertEquals(37, needsVerification, "Content 剩余 37 个 operation 必须继续 needs_verification");
assertEquals(51, completed, "Content 人工批准后必须有 51 个 operation completed");
assertEquals(0, needsVerification, "Content 人工批准后不能继续保留 needs_verification");
}
private JsonNode readAccountOperations() throws IOException {

View File

@ -78,31 +78,6 @@ class P1rAiRealApiGateTest {
entry("adminGetBusinessAuditEvent", "GET /admin-api/muse/audit/business-events/{eventId}")
);
private static final Set<String> APPROVED_MARKET_COMPLETED_OPERATIONS = Set.of(
"getMarketplaceAsset",
"listMarketplaceCategories",
"favoriteAsset",
"unfavoriteAsset"
);
/** Content completed approval 当前只允许推进 14 个 operation。 */
private static final Set<String> APPROVED_CONTENT_COMPLETED_OPERATIONS = Set.of(
"listWorks",
"getWork",
"listChapters",
"getChapter",
"listBlocks",
"getBlock",
"saveBlock",
"getBlockSourceAttribution",
"getPlanning",
"savePlanningItem",
"adminListWorks",
"adminGetWork",
"adminListChapters",
"adminRiskAction"
);
private final ObjectMapper objectMapper = new ObjectMapper();
@Test
@ -145,8 +120,8 @@ class P1rAiRealApiGateTest {
void should_count_ai_and_knowledge_operations_as_completed() throws IOException {
JsonNode report = readReport();
assertEquals(147, report.path("summary").path("completedOperations").asInt(),
"completedOperations 必须只来自 AI 41 + Knowledge 59 + Events streamEvents 1 + Meta 16 + Account 12 + Market 4 + Content 14");
assertEquals(233, report.path("summary").path("completedOperations").asInt(),
"completedOperations 必须覆盖 AI 41 + Knowledge 59 + Events 1 + Meta 16 + Account 33 + Market 32 + Content 51");
}
@Test
@ -161,21 +136,21 @@ class P1rAiRealApiGateTest {
}
@Test
void should_keep_only_events_stream_events_as_extra_completed_operation() throws IOException {
void should_keep_events_stream_events_completed_after_approval() throws IOException {
JsonNode streamEvents = findOperation("events", "streamEvents");
assertEquals("dedicated", streamEvents.path("implementationStatus").asText(),
"P1R-7 completed approval 后 streamEvents 仍必须是 dedicated 实现");
assertEquals("completed", streamEvents.path("completionStatus").asText(),
"P1R-7 completed approval 只允许 streamEvents 额外推进到 completed");
"P1R-7 completed approval 后 streamEvents 必须保持 completed");
}
@Test
void should_keep_content_meta_account_dedicated_statuses() throws IOException {
assertContentStatusCount(14, 37);
assertContentStatusCount(51, 0);
assertMetaStatusCount(16, 0);
assertAccountStatusCount(12, 21);
assertMarketStatusCount(4, 28);
assertAccountStatusCount(33, 0);
assertMarketStatusCount(32, 0);
}
private void assertContentStatusCount(int expectedCompleted, int expectedNeedsVerification) throws IOException {
@ -190,19 +165,18 @@ class P1rAiRealApiGateTest {
String operationId = operation.path("operationId").asText("<missing-operationId>");
assertEquals("dedicated", operation.path("implementationStatus").asText(),
"content/" + operationId + " 必须保持 dedicated");
if (APPROVED_CONTENT_COMPLETED_OPERATIONS.contains(operationId)) {
if ("completed".equals(operation.path("completionStatus").asText())) {
completed++;
assertEquals("completed", operation.path("completionStatus").asText(),
"content/" + operationId + " 已获本轮批准后必须 completed");
} else {
needsVerification++;
assertEquals("needs_verification", operation.path("completionStatus").asText(),
"content/" + operationId + " 未获本轮批准,必须继续 needs_verification");
}
if ("needs_verification".equals(operation.path("completionStatus").asText())) {
needsVerification++;
}
assertEquals("completed", operation.path("completionStatus").asText(),
"content/" + operationId + " 已获用户批准后必须 completed");
}
assertEquals(51, total, "Content operation 数量必须保持 51");
assertEquals(expectedCompleted, completed, "Content Admin RiskAction completed approval 后只能推进 14 个 operation");
assertEquals(expectedNeedsVerification, needsVerification, "Content 剩余 37 个 operation 必须继续 needs_verification");
assertEquals(expectedCompleted, completed, "Content 人工批准后 completed 数量不符合预期");
assertEquals(expectedNeedsVerification, needsVerification, "Content 人工批准后 needs_verification 数量不符合预期");
}
private void assertAccountStatusCount(int expectedCompleted, int expectedNeedsVerification) throws IOException {
@ -225,8 +199,8 @@ class P1rAiRealApiGateTest {
}
}
assertEquals(33, total, "Account operation 数量必须保持 33");
assertEquals(expectedCompleted, completed, "Account Security Events read completed approval 后必须有 12 个 operation completed");
assertEquals(expectedNeedsVerification, needsVerification, "Account 剩余 21 个 operation 必须继续 needs_verification");
assertEquals(expectedCompleted, completed, "Account 人工批准后 completed 数量不符合预期");
assertEquals(expectedNeedsVerification, needsVerification, "Account 人工批准后 needs_verification 数量不符合预期");
}
private void assertMetaStatusCount(int expectedCompleted, int expectedNeedsVerification) throws IOException {
@ -252,6 +226,11 @@ class P1rAiRealApiGateTest {
}
private void assertDomainStatusCount(String domain, int expectedCount) throws IOException {
assertDomainStatusCount(domain, expectedCount, "completed");
}
private void assertDomainStatusCount(String domain, int expectedCount, String expectedCompletionStatus)
throws IOException {
int actualCount = 0;
for (JsonNode operation : readOperations()) {
if (!domain.equals(operation.path("domain").asText())) {
@ -261,8 +240,8 @@ class P1rAiRealApiGateTest {
String operationId = operation.path("operationId").asText("<missing-operationId>");
assertEquals("dedicated", operation.path("implementationStatus").asText(),
domain + "/" + operationId + " 必须保持 dedicated");
assertEquals("needs_verification", operation.path("completionStatus").asText(),
domain + "/" + operationId + " 必须保持 needs_verification");
assertEquals(expectedCompletionStatus, operation.path("completionStatus").asText(),
domain + "/" + operationId + " 必须保持 " + expectedCompletionStatus);
}
assertEquals(expectedCount, actualCount, domain + " operation 数量必须保持不变");
}
@ -279,19 +258,18 @@ class P1rAiRealApiGateTest {
String operationId = operation.path("operationId").asText("<missing-operationId>");
assertEquals("dedicated", operation.path("implementationStatus").asText(),
"market/" + operationId + " 必须保持 dedicated");
if (APPROVED_MARKET_COMPLETED_OPERATIONS.contains(operationId)) {
if ("completed".equals(operation.path("completionStatus").asText())) {
completed++;
assertEquals("completed", operation.path("completionStatus").asText(),
"market/" + operationId + " 已获本轮批准后必须 completed");
} else {
needsVerification++;
assertEquals("needs_verification", operation.path("completionStatus").asText(),
"market/" + operationId + " 未获本轮批准,必须继续 needs_verification");
}
if ("needs_verification".equals(operation.path("completionStatus").asText())) {
needsVerification++;
}
assertEquals("completed", operation.path("completionStatus").asText(),
"market/" + operationId + " 已获用户批准后必须 completed");
}
assertEquals(32, total, "Market operation 数量必须保持 32");
assertEquals(expectedCompleted, completed, "Market 第一批 completed approval 只能推进 4 个 operation");
assertEquals(expectedNeedsVerification, needsVerification, "Market 剩余 28 个 operation 必须继续 needs_verification");
assertEquals(expectedCompleted, completed, "Market 人工批准后 completed 数量不符合预期");
assertEquals(expectedNeedsVerification, needsVerification, "Market 人工批准后 needs_verification 数量不符合预期");
}
private JsonNode readAiOperations() throws IOException {

View File

@ -52,7 +52,7 @@ class P1rApiCoverageReportTest {
"knowledge"
);
/** 已获用户批准、并有 P1R 外部端到端验收证据支撑的 completed operation。 */
/** 已获用户批准、并有 P1R 外部端到端验收证据支撑的跨域零散 completed operation。 */
private static final Set<String> APPROVED_COMPLETED_OPERATIONS = Set.of(
"events:streamEvents",
"meta:listMetaSchemas",
@ -70,37 +70,7 @@ class P1rApiCoverageReportTest {
"meta:getProtectionNode",
"meta:listFunctionChains",
"meta:previewFunctionChainImpact",
"meta:activateFunctionChainVersion",
"account:getCurrentUser",
"account:getProfile",
"account:updateProfile",
"account:adminListAccountUsers",
"account:adminGetUserEntitlements",
"account:getAppEntitlements",
"account:adminGetBalanceSnapshots",
"account:getAppBalanceSnapshots",
"account:adminCreateQuotaAdjustment",
"account:adminListQuotaAdjustments",
"account:appListSecurityEvents",
"account:appGetSecurityEvent",
"market:getMarketplaceAsset",
"market:listMarketplaceCategories",
"market:favoriteAsset",
"market:unfavoriteAsset",
"content:listWorks",
"content:getWork",
"content:listChapters",
"content:getChapter",
"content:listBlocks",
"content:getBlock",
"content:saveBlock",
"content:getBlockSourceAttribution",
"content:getPlanning",
"content:savePlanningItem",
"content:adminListWorks",
"content:adminGetWork",
"content:adminListChapters",
"content:adminRiskAction"
"meta:activateFunctionChainVersion"
);
/** 已批准的 MetaSchema 管理接口。 */
@ -127,46 +97,132 @@ class P1rApiCoverageReportTest {
"activateFunctionChainVersion"
);
/** 已批准的 Account 本域闭合接口,仍保持 operation-level approval。 */
/** 已获用户批准的 Account 全量 P1R 接口,仍保持 operation-level approval。 */
private static final Set<String> APPROVED_ACCOUNT_COMPLETED_OPERATIONS = Set.of(
"adminCreateCallAttributionJob",
"adminCreateNewApiBinding",
"adminCreateQuotaAdjustment",
"adminCreateQuotaRequest",
"adminGetBalanceSnapshots",
"adminGetCallAttributionJob",
"adminGetIntegrationCallByCorrelation",
"adminGetUserEntitlements",
"adminListAccountUsers",
"adminListNewApiBindings",
"adminListPurchaseRecords",
"adminListQuotaAdjustments",
"adminListUsageRecords",
"appAcknowledgeSecurityEvent",
"appCreateExportTask",
"appCreateQuotaRequest",
"appDownloadExport",
"appGetExportTask",
"appGetIntegrationCallByCorrelation",
"appGetQuotaRequest",
"appGetSecurityEvent",
"appListLicenses",
"appListPublishRecords",
"appListPurchases",
"appListSecurityEvents",
"appRecheckNewApiBinding",
"getAppBalanceSnapshots",
"getAppEntitlements",
"getAppNewApiBinding",
"getAppUsage",
"getCurrentUser",
"getProfile",
"updateProfile",
"adminListAccountUsers",
"adminGetUserEntitlements",
"getAppEntitlements",
"adminGetBalanceSnapshots",
"getAppBalanceSnapshots",
"adminCreateQuotaAdjustment",
"adminListQuotaAdjustments",
"appListSecurityEvents",
"appGetSecurityEvent"
"updateProfile"
);
/** 已批准的 Market 第一批详情、分类和收藏接口,仍保持 operation-level approval。 */
/** 已获用户批准的 Market 全量 P1R 接口,仍保持 operation-level approval。 */
private static final Set<String> APPROVED_MARKET_COMPLETED_OPERATIONS = Set.of(
"getMarketplaceAsset",
"listMarketplaceCategories",
"adminApprovePublishRequest",
"adminDelistAsset",
"adminGetAppeal",
"adminGetMarketAsset",
"adminListAppeals",
"adminListMarketAssets",
"adminListPublishRequests",
"adminPreviewGovernanceImpact",
"adminRecallAsset",
"adminRejectPublishRequest",
"adminResolveAppeal",
"cancelHandoff",
"createBindPrecheck",
"createMarketplaceHandoff",
"favoriteAsset",
"unfavoriteAsset"
"getGovernanceImpact",
"getHandoffStatus",
"getMarketplaceAsset",
"installMarketplaceAsset",
"listMarketplaceAssets",
"listMarketplaceCategories",
"listMarketplaceRecommendations",
"listMyPublishRecords",
"purchaseAsset",
"runPublishCheck",
"savePublishDraft",
"submitAppeal",
"submitPublishRequest",
"supplementAppeal",
"unfavoriteAsset",
"withdrawAppeal",
"withdrawPublishRequest"
);
/** 已批准的 Content 用户端核心、Planning、Admin Read 与 Admin RiskAction 接口,仍保持 operation-level approval。 */
/** 已获用户批准的 Content 全量 P1R 接口,仍保持 operation-level approval。 */
private static final Set<String> APPROVED_CONTENT_COMPLETED_OPERATIONS = Set.of(
"listWorks",
"getWork",
"listChapters",
"getChapter",
"listBlocks",
"getBlock",
"saveBlock",
"getBlockSourceAttribution",
"getPlanning",
"savePlanningItem",
"adminListWorks",
"adminGetWork",
"adminListChapters",
"adminRiskAction"
"adminListExportTasks",
"adminListImportTasks",
"adminListWorks",
"adminRiskAction",
"batchConfirmChapters",
"confirmChapterParseResult",
"confirmPlanningCandidate",
"createBlock",
"createChapter",
"createExportTask",
"createImportTask",
"createParseJob",
"createPlanningCandidate",
"createStyleCheck",
"createWork",
"deleteBlock",
"deleteChapter",
"deleteWork",
"discardPlanningCandidate",
"downloadExportPackage",
"exportWork",
"getBlock",
"getBlockSourceAttribution",
"getChapter",
"getExportTask",
"getImportTask",
"getMetaProjection",
"getParseJob",
"getPlanning",
"getPlanningCandidate",
"getStyleCheckResult",
"getWork",
"listBlocks",
"listChapters",
"listMetaProjections",
"listParseJobChapters",
"listPlanningCandidates",
"listWorks",
"mergeBlockSuggestion",
"mergeBlocks",
"rejectChapterParseResult",
"reorderChapters",
"retryParseJob",
"saveBlock",
"savePlanningItem",
"splitBlock",
"updateChapter",
"updateWork",
"validateDynamicFields"
);
private final ObjectMapper objectMapper = new ObjectMapper();
@ -262,7 +318,7 @@ class P1rApiCoverageReportTest {
}
String operationId = operation.path("operationId").asText("<missing-operationId>");
assertTrue(APPROVED_COMPLETED_DOMAINS.contains(operation.path("domain").asText())
|| APPROVED_COMPLETED_OPERATIONS.contains(operationKey(operation)),
|| isApprovedCompletedOperation(operation),
operationId + " 只有已批准 domain 或 operation 可以标记为 completed");
assertTrue("dedicated".equals(operation.path("implementationStatus").asText()),
operationId + " 标记 completed 时必须仍是 dedicated 实现");
@ -308,20 +364,20 @@ class P1rApiCoverageReportTest {
for (String operationId : APPROVED_CONTENT_COMPLETED_OPERATIONS) {
assertOperationStatus("content", operationId, "dedicated", "completed");
}
assertOperationStatus("market", "listMarketplaceAssets", "dedicated", "needs_verification");
assertOperationStatus("market", "listMarketplaceRecommendations", "dedicated", "needs_verification");
assertOperationStatus("market", "listMarketplaceAssets", "dedicated", "completed");
assertOperationStatus("market", "listMarketplaceRecommendations", "dedicated", "completed");
assertOperationStatus("market", "favoriteAsset", "dedicated", "completed", true);
assertOperationStatus("market", "unfavoriteAsset", "dedicated", "completed", true);
assertOperationStatus("account", "appListSecurityEvents", "dedicated", "completed");
assertOperationStatus("account", "appGetSecurityEvent", "dedicated", "completed");
assertOperationStatus("account", "appAcknowledgeSecurityEvent", "dedicated", "needs_verification", true);
assertOperationStatus("content", "createWork", "dedicated", "needs_verification");
assertOperationStatus("content", "updateWork", "dedicated", "needs_verification");
assertOperationStatus("content", "createChapter", "dedicated", "needs_verification");
assertOperationStatus("content", "mergeBlockSuggestion", "dedicated", "needs_verification");
assertOperationStatus("content", "exportWork", "dedicated", "needs_verification");
assertOperationStatus("content", "listPlanningCandidates", "dedicated", "needs_verification");
assertOperationStatus("content", "createStyleCheck", "dedicated", "needs_verification");
assertOperationStatus("account", "appAcknowledgeSecurityEvent", "dedicated", "completed", true);
assertOperationStatus("content", "createWork", "dedicated", "completed");
assertOperationStatus("content", "updateWork", "dedicated", "completed");
assertOperationStatus("content", "createChapter", "dedicated", "completed");
assertOperationStatus("content", "mergeBlockSuggestion", "dedicated", "completed");
assertOperationStatus("content", "exportWork", "dedicated", "completed");
assertOperationStatus("content", "listPlanningCandidates", "dedicated", "completed");
assertOperationStatus("content", "createStyleCheck", "dedicated", "completed");
assertOperationStatus("content", "adminRiskAction", "dedicated", "completed", true);
// P1 加固(2026-06-14):废弃硬编码 needs_verification 魔法数(28/21/37,与脊柱规则禁的"可拨动常量"同模式),
// 改为断言"该域 completed 数 == 显式批准集大小"——派生自唯一可信来源 APPROVED_*_COMPLETED_OPERATIONS。
@ -421,13 +477,24 @@ class P1rApiCoverageReportTest {
count++;
}
}
assertEquals(expected, count, domain + " 不应被本轮 completed approval 连带推进");
assertEquals(expected, count, domain + " completed 数量必须与人工批准集合一致");
}
private static String operationKey(JsonNode operation) {
return operation.path("domain").asText() + ":" + operation.path("operationId").asText();
}
private static boolean isApprovedCompletedOperation(JsonNode operation) {
String domain = operation.path("domain").asText();
String operationId = operation.path("operationId").asText();
return switch (domain) {
case "account" -> APPROVED_ACCOUNT_COMPLETED_OPERATIONS.contains(operationId);
case "market" -> APPROVED_MARKET_COMPLETED_OPERATIONS.contains(operationId);
case "content" -> APPROVED_CONTENT_COMPLETED_OPERATIONS.contains(operationId);
default -> APPROVED_COMPLETED_OPERATIONS.contains(operationKey(operation));
};
}
/**
* 从当前 Maven 执行目录逐级向上查找仓库根目录,避免 surefire 在不同模块目录执行时路径失效。
*/

View File

@ -18,8 +18,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* P1R-1 Content 真实 API 阶段门禁测试。
*
* <p>该测试只校验覆盖报告里的 Content 阶段状态,不证明业务语义已完成;后续阶段如果要把
* needs_verification 推进为 completed,必须先用更强的合同、状态机、持久化和外部 owner 验证替换本门禁。</p>
* <p>该测试校验覆盖报告里的 Content 阶段状态;2026-06-17 用户批准后,
* 51 个已有真实 PG 验收证据的 Content operation 必须全部保持 dedicated / completed。</p>
*/
class P1rContentRealApiGateTest {
@ -93,26 +93,11 @@ class P1rContentRealApiGateTest {
"savePlanningItem"
);
/** 已批准的 Content 用户端核心、Planning、Admin Read 与 Admin RiskAction 接口,仍保持 operation-level approval。 */
private static final Set<String> APPROVED_CONTENT_COMPLETED_OPERATIONS = Set.of(
"listWorks",
"getWork",
"listChapters",
"getChapter",
"listBlocks",
"getBlock",
"saveBlock",
"getBlockSourceAttribution",
"getPlanning",
"savePlanningItem",
"adminListWorks",
"adminGetWork",
"adminListChapters",
"adminRiskAction"
);
/** 已按用户批准推进 completed 的 Content operation;仍保持 operation-level approval 门。 */
private static final Set<String> APPROVED_CONTENT_COMPLETED_OPERATIONS = P1R1_CONTENT_OPERATION_IDS;
/** 必须继续保持 needs_verification 的代表性未批准 Content operation,防止 CRUD、导出、AI planning/style 和 admin 写入误推进。 */
private static final Set<String> REPRESENTATIVE_UNAPPROVED_CONTENT_OPERATIONS = Set.of(
/** 代表性已批准 Content operation,防止关键写入、导出、AI owner fail-closed 与管理端读回退。 */
private static final Set<String> REPRESENTATIVE_APPROVED_CONTENT_OPERATIONS = Set.of(
"adminListImportTasks",
"adminListExportTasks",
"createWork",
@ -205,7 +190,7 @@ class P1rContentRealApiGateTest {
}
/**
* 验证当前 completed approval 只推进已批准的 14 个 Content operation,其余 37 个仍保持 needs_verification。
* 验证用户批准后 51 个 Content operation 全部推进 completed。
*
* @throws IOException 读取覆盖报告失败时抛出
*/
@ -225,14 +210,14 @@ class P1rContentRealApiGateTest {
operationId + " 已获 Content operation-level 批准后必须标记 completed");
} else {
needsVerification++;
assertEquals("needs_verification", operation.path("completionStatus").asText(),
operationId + " 未获 Content operation-level 批准,必须继续保持 needs_verification");
assertEquals("completed", operation.path("completionStatus").asText(),
operationId + " 已获 Content operation-level 批准,不能保留 needs_verification");
}
}
assertEquals(14, completed, "Content Admin RiskAction operation-level completed approval 后只能推进 14 个 operation");
assertEquals(37, needsVerification, "Content 剩余 37 个 operation 必须继续 needs_verification");
for (String operationId : REPRESENTATIVE_UNAPPROVED_CONTENT_OPERATIONS) {
assertContentOperationStatus(operationId, "needs_verification");
assertEquals(51, completed, "Content 人工批准后必须有 51 个 operation completed");
assertEquals(0, needsVerification, "Content 人工批准后不能继续保留 needs_verification");
for (String operationId : REPRESENTATIVE_APPROVED_CONTENT_OPERATIONS) {
assertContentOperationStatus(operationId, "completed");
}
}

View File

@ -24,10 +24,10 @@ class P1rEventsRealApiGateTest {
/** P1R-7a 当前只允许 Events 域拥有 streamEvents 一个 operation。 */
private static final int EXPECTED_EVENTS_OPERATION_COUNT = 1;
/** P1R-6 Market 合同固定 operation 数量,P1R-7a 不能顺手改变 Market 覆盖状态。 */
/** P1R-6 Market 合同固定 operation 数量,人工批准后仍需守住清单边界。 */
private static final int EXPECTED_MARKET_OPERATION_COUNT = 32;
/** P1R-3 Account 合同固定 operation 数量,Account completed approval 当前只允许推进 12 个。 */
/** P1R-3 Account 合同固定 operation 数量,人工批准后仍需守住清单边界。 */
private static final int EXPECTED_ACCOUNT_OPERATION_COUNT = 33;
/** Events 真实入口门禁必须拒绝的占位或缺失状态。 */
@ -38,31 +38,6 @@ class P1rEventsRealApiGateTest {
"missing"
);
private static final Set<String> APPROVED_MARKET_COMPLETED_OPERATIONS = Set.of(
"getMarketplaceAsset",
"listMarketplaceCategories",
"favoriteAsset",
"unfavoriteAsset"
);
/** Content completed approval 当前只允许推进 14 个 operation。 */
private static final Set<String> APPROVED_CONTENT_COMPLETED_OPERATIONS = Set.of(
"listWorks",
"getWork",
"listChapters",
"getChapter",
"listBlocks",
"getBlock",
"saveBlock",
"getBlockSourceAttribution",
"getPlanning",
"savePlanningItem",
"adminListWorks",
"adminGetWork",
"adminListChapters",
"adminRiskAction"
);
private final ObjectMapper objectMapper = new ObjectMapper();
@Test
@ -106,10 +81,10 @@ class P1rEventsRealApiGateTest {
void should_keep_completed_approval_summary_at_approved_operation_boundary() throws IOException {
JsonNode summary = readReport().path("summary");
assertEquals(147, summary.path("completedOperations").asInt(),
"completedOperations 只能来自 AI 41 + Knowledge 59 + Events streamEvents 1 + Meta 16 + Account 12 + Market 4 + Content 14");
assertEquals(86, summary.path("needsVerificationOperations").asInt(),
"needsVerificationOperations 必须扣除已批准的 Events streamEvents、Meta 16、Account 12、Market 4 和 Content 14");
assertEquals(233, summary.path("completedOperations").asInt(),
"completedOperations 必须覆盖 AI 41 + Knowledge 59 + Events 1 + Meta 16 + Account 33 + Market 32 + Content 51");
assertEquals(0, summary.path("needsVerificationOperations").asInt(),
"用户批准后 needsVerificationOperations 必须清零");
assertEquals(0, summary.path("incompleteOperations").asInt(),
"Events 退出 placeholder 后不应再留下 incomplete operation");
assertEquals(0, summary.path("genericPersistenceOperations").asInt(),
@ -119,7 +94,7 @@ class P1rEventsRealApiGateTest {
}
@Test
void should_keep_only_first_batch_market_operations_completed() throws IOException {
void should_keep_all_market_operations_completed_after_approval() throws IOException {
JsonNode marketOperations = readMarketOperations();
int completed = 0;
int needsVerification = 0;
@ -131,26 +106,25 @@ class P1rEventsRealApiGateTest {
String operationId = operation.path("operationId").asText("<missing-operationId>");
assertEquals("dedicated", operation.path("implementationStatus").asText(),
"Market/" + operationId + " 必须继续保持 dedicated");
if (APPROVED_MARKET_COMPLETED_OPERATIONS.contains(operationId)) {
if ("completed".equals(operation.path("completionStatus").asText())) {
completed++;
assertEquals("completed", operation.path("completionStatus").asText(),
"Market/" + operationId + " 已获本轮批准后必须 completed");
continue;
}
needsVerification++;
assertEquals("needs_verification", operation.path("completionStatus").asText(),
"Market/" + operationId + " 未获本轮批准,必须继续保持 needs_verification");
if ("needs_verification".equals(operation.path("completionStatus").asText())) {
needsVerification++;
}
assertEquals("completed", operation.path("completionStatus").asText(),
"Market/" + operationId + " 已获用户批准后必须 completed");
}
assertEquals(4, completed, "Market 第一批 completed approval 只能推进 4 个 operation");
assertEquals(28, needsVerification, "Market 剩余 28 个 operation 必须继续 needs_verification");
assertMarketOperationStatus("listMarketplaceAssets", "needs_verification", false);
assertMarketOperationStatus("listMarketplaceRecommendations", "needs_verification", false);
assertEquals(32, completed, "Market 人工批准后必须有 32 个 operation completed");
assertEquals(0, needsVerification, "Market 人工批准后不能继续保留 needs_verification");
assertMarketOperationStatus("listMarketplaceAssets", "completed", false);
assertMarketOperationStatus("listMarketplaceRecommendations", "completed", false);
assertMarketOperationStatus("favoriteAsset", "completed", true);
assertMarketOperationStatus("unfavoriteAsset", "completed", true);
}
@Test
void should_keep_account_partial_approval_at_12_completed_operations() throws IOException {
void should_keep_all_account_operations_completed_after_approval() throws IOException {
JsonNode accountOperations = readAccountOperations();
int completed = 0;
int needsVerification = 0;
@ -168,12 +142,12 @@ class P1rEventsRealApiGateTest {
needsVerification++;
}
}
assertEquals(12, completed, "Account Security Events read completed approval 后只能推进 12 个 operation");
assertEquals(21, needsVerification, "Account 剩余 21 个 operation 必须继续 needs_verification");
assertEquals(33, completed, "Account 人工批准后必须有 33 个 operation completed");
assertEquals(0, needsVerification, "Account 人工批准后不能继续保留 needs_verification");
}
@Test
void should_keep_content_partial_approval_at_14_completed_operations() throws IOException {
void should_keep_all_content_operations_completed_after_approval() throws IOException {
JsonNode contentOperations = readContentOperations();
int completed = 0;
int needsVerification = 0;
@ -183,18 +157,17 @@ class P1rEventsRealApiGateTest {
String operationId = operation.path("operationId").asText("<missing-operationId>");
assertEquals("dedicated", operation.path("implementationStatus").asText(),
"Content/" + operationId + " 必须继续保持 dedicated");
if (APPROVED_CONTENT_COMPLETED_OPERATIONS.contains(operationId)) {
if ("completed".equals(operation.path("completionStatus").asText())) {
completed++;
assertEquals("completed", operation.path("completionStatus").asText(),
"Content/" + operationId + " 已获本轮批准后必须 completed");
} else {
needsVerification++;
assertEquals("needs_verification", operation.path("completionStatus").asText(),
"Content/" + operationId + " 未获本轮批准,必须继续 needs_verification");
}
if ("needs_verification".equals(operation.path("completionStatus").asText())) {
needsVerification++;
}
assertEquals("completed", operation.path("completionStatus").asText(),
"Content/" + operationId + " 已获用户批准后必须 completed");
}
assertEquals(14, completed, "Content Admin RiskAction completed approval 后只能推进 14 个 operation");
assertEquals(37, needsVerification, "Content 剩余 37 个 operation 必须继续 needs_verification");
assertEquals(51, completed, "Content 人工批准后必须有 51 个 operation completed");
assertEquals(0, needsVerification, "Content 人工批准后不能继续保留 needs_verification");
}
private JsonNode readSingleEventsOperation() throws IOException {

View File

@ -100,31 +100,6 @@ class P1rKnowledgeRealApiGateTest {
entry("getLocalKnowledge", "GET /app-api/muse/works/{workId}/local-knowledge")
);
private static final Set<String> APPROVED_MARKET_COMPLETED_OPERATIONS = Set.of(
"getMarketplaceAsset",
"listMarketplaceCategories",
"favoriteAsset",
"unfavoriteAsset"
);
/** Content completed approval 当前只允许推进 14 个 operation。 */
private static final Set<String> APPROVED_CONTENT_COMPLETED_OPERATIONS = Set.of(
"listWorks",
"getWork",
"listChapters",
"getChapter",
"listBlocks",
"getBlock",
"saveBlock",
"getBlockSourceAttribution",
"getPlanning",
"savePlanningItem",
"adminListWorks",
"adminGetWork",
"adminListChapters",
"adminRiskAction"
);
private final ObjectMapper objectMapper = new ObjectMapper();
@Test
@ -184,17 +159,17 @@ class P1rKnowledgeRealApiGateTest {
void should_count_ai_and_knowledge_operations_as_completed() throws IOException {
JsonNode report = readReport();
assertEquals(147, report.path("summary").path("completedOperations").asInt(),
"completedOperations 必须只来自 AI 41 + Knowledge 59 + Events streamEvents 1 + Meta 16 + Account 12 + Market 4 + Content 14");
assertEquals(233, report.path("summary").path("completedOperations").asInt(),
"completedOperations 必须覆盖 AI 41 + Knowledge 59 + Events 1 + Meta 16 + Account 33 + Market 32 + Content 51");
}
@Test
void should_keep_existing_dedicated_domains_unchanged() throws IOException {
assertDomainStatusCount("ai", 41, "completed");
assertContentStatusCount(14, 37);
assertContentStatusCount(51, 0);
assertMetaStatusCount(16, 0);
assertAccountStatusCount(12, 21);
assertMarketStatusCount(4, 28);
assertAccountStatusCount(33, 0);
assertMarketStatusCount(32, 0);
}
private void assertContentStatusCount(int expectedCompleted, int expectedNeedsVerification) throws IOException {
@ -209,19 +184,18 @@ class P1rKnowledgeRealApiGateTest {
String operationId = operation.path("operationId").asText("<missing-operationId>");
assertEquals("dedicated", operation.path("implementationStatus").asText(),
"content/" + operationId + " 必须保持 dedicated");
if (APPROVED_CONTENT_COMPLETED_OPERATIONS.contains(operationId)) {
if ("completed".equals(operation.path("completionStatus").asText())) {
completed++;
assertEquals("completed", operation.path("completionStatus").asText(),
"content/" + operationId + " 已获本轮批准后必须 completed");
} else {
needsVerification++;
assertEquals("needs_verification", operation.path("completionStatus").asText(),
"content/" + operationId + " 未获本轮批准,必须继续 needs_verification");
}
if ("needs_verification".equals(operation.path("completionStatus").asText())) {
needsVerification++;
}
assertEquals("completed", operation.path("completionStatus").asText(),
"content/" + operationId + " 已获用户批准后必须 completed");
}
assertEquals(51, total, "Content operation 数量必须保持 51");
assertEquals(expectedCompleted, completed, "Content Admin RiskAction completed approval 后只能推进 14 个 operation");
assertEquals(expectedNeedsVerification, needsVerification, "Content 剩余 37 个 operation 必须继续 needs_verification");
assertEquals(expectedCompleted, completed, "Content 人工批准后 completed 数量不符合预期");
assertEquals(expectedNeedsVerification, needsVerification, "Content 人工批准后 needs_verification 数量不符合预期");
}
@Test
@ -246,7 +220,7 @@ class P1rKnowledgeRealApiGateTest {
}
private void assertDomainStatusCount(String domain, int expectedCount) throws IOException {
assertDomainStatusCount(domain, expectedCount, "needs_verification");
assertDomainStatusCount(domain, expectedCount, "completed");
}
private void assertDomainStatusCount(String domain, int expectedCount, String expectedCompletionStatus) throws IOException {
@ -285,8 +259,8 @@ class P1rKnowledgeRealApiGateTest {
}
}
assertEquals(33, total, "Account operation 数量必须保持 33");
assertEquals(expectedCompleted, completed, "Account Security Events read completed approval 后必须有 12 个 operation completed");
assertEquals(expectedNeedsVerification, needsVerification, "Account 剩余 21 个 operation 必须继续 needs_verification");
assertEquals(expectedCompleted, completed, "Account 人工批准后 completed 数量不符合预期");
assertEquals(expectedNeedsVerification, needsVerification, "Account 人工批准后 needs_verification 数量不符合预期");
}
private void assertMarketStatusCount(int expectedCompleted, int expectedNeedsVerification) throws IOException {
@ -301,19 +275,18 @@ class P1rKnowledgeRealApiGateTest {
String operationId = operation.path("operationId").asText("<missing-operationId>");
assertEquals("dedicated", operation.path("implementationStatus").asText(),
"market/" + operationId + " 必须保持 dedicated");
if (APPROVED_MARKET_COMPLETED_OPERATIONS.contains(operationId)) {
if ("completed".equals(operation.path("completionStatus").asText())) {
completed++;
assertEquals("completed", operation.path("completionStatus").asText(),
"market/" + operationId + " 已获本轮批准后必须 completed");
} else {
needsVerification++;
assertEquals("needs_verification", operation.path("completionStatus").asText(),
"market/" + operationId + " 未获本轮批准,必须继续 needs_verification");
}
if ("needs_verification".equals(operation.path("completionStatus").asText())) {
needsVerification++;
}
assertEquals("completed", operation.path("completionStatus").asText(),
"market/" + operationId + " 已获用户批准后必须 completed");
}
assertEquals(32, total, "Market operation 数量必须保持 32");
assertEquals(expectedCompleted, completed, "Market 第一批 completed approval 只能推进 4 个 operation");
assertEquals(expectedNeedsVerification, needsVerification, "Market 剩余 28 个 operation 必须继续 needs_verification");
assertEquals(expectedCompleted, completed, "Market 人工批准后 completed 数量不符合预期");
assertEquals(expectedNeedsVerification, needsVerification, "Market 人工批准后 needs_verification 数量不符合预期");
}
private void assertMetaStatusCount(int expectedCompleted, int expectedNeedsVerification) throws IOException {

View File

@ -19,8 +19,8 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
/**
* P1R-6 Task 11 Market 真实 API 覆盖门禁。
*
* <p>该测试证明 Market 第一批 4 个 operation 只以 operation-level 方式推进到 completed;
* 它不证明 Market domain-level completed,也不允许把剩余 28 个 operation 提前标记为 completed。</p>
* <p>该测试证明 Market 32 个 operation 在 2026-06-17 用户批准后,
* 只以 operation-level 方式全部推进到 dedicated / completed。</p>
*/
class P1rMarketRealApiGateTest {
@ -71,31 +71,6 @@ class P1rMarketRealApiGateTest {
entry("adminResolveAppeal", "POST /admin-api/muse/market/appeals/{appealId}/resolve")
);
private static final Set<String> APPROVED_MARKET_COMPLETED_OPERATIONS = Set.of(
"getMarketplaceAsset",
"listMarketplaceCategories",
"favoriteAsset",
"unfavoriteAsset"
);
/** Content completed approval 当前只允许推进 14 个 operation。 */
private static final Set<String> APPROVED_CONTENT_COMPLETED_OPERATIONS = Set.of(
"listWorks",
"getWork",
"listChapters",
"getChapter",
"listBlocks",
"getBlock",
"saveBlock",
"getBlockSourceAttribution",
"getPlanning",
"savePlanningItem",
"adminListWorks",
"adminGetWork",
"adminListChapters",
"adminRiskAction"
);
private final ObjectMapper objectMapper = new ObjectMapper();
@Test
@ -122,27 +97,26 @@ class P1rMarketRealApiGateTest {
}
@Test
void should_promote_only_first_batch_market_operations_to_completed() throws IOException {
void should_promote_all_approved_market_operations_to_completed() throws IOException {
int completed = 0;
int needsVerification = 0;
for (JsonNode operation : readMarketOperations()) {
String operationId = operation.path("operationId").asText("<missing-operationId>");
assertEquals("dedicated", operation.path("implementationStatus").asText(),
operationId + " 当前 P1R-6 目标必须是 dedicated");
if (APPROVED_MARKET_COMPLETED_OPERATIONS.contains(operationId)) {
if ("completed".equals(operation.path("completionStatus").asText())) {
completed++;
assertEquals("completed", operation.path("completionStatus").asText(),
operationId + " 已获用户批准后必须标记 completed");
continue;
}
needsVerification++;
assertEquals("needs_verification", operation.path("completionStatus").asText(),
operationId + " 未进入 Market 第一批审批,必须继续保持 needs_verification");
if ("needs_verification".equals(operation.path("completionStatus").asText())) {
needsVerification++;
}
assertEquals("completed", operation.path("completionStatus").asText(),
operationId + " 已获用户批准后必须标记 completed");
}
assertEquals(4, completed, "Market 第一批 operation-level completed approval 只能推进 4 个 operation");
assertEquals(28, needsVerification, "Market 剩余 28 个 operation 必须继续 needs_verification");
assertMarketOperationStatus("listMarketplaceAssets", "needs_verification", false);
assertMarketOperationStatus("listMarketplaceRecommendations", "needs_verification", false);
assertEquals(32, completed, "Market 人工批准后必须有 32 个 operation completed");
assertEquals(0, needsVerification, "Market 人工批准后不能继续保留 needs_verification");
assertMarketOperationStatus("listMarketplaceAssets", "completed", false);
assertMarketOperationStatus("listMarketplaceRecommendations", "completed", false);
assertMarketOperationStatus("favoriteAsset", "completed", true);
assertMarketOperationStatus("unfavoriteAsset", "completed", true);
}
@ -151,17 +125,17 @@ class P1rMarketRealApiGateTest {
void should_keep_completion_summary_owned_by_approved_scopes_only() throws IOException {
JsonNode report = readReport();
assertEquals(147, report.path("summary").path("completedOperations").asInt(),
"completedOperations 必须只来自 AI 41 + Knowledge 59 + Events streamEvents 1 + Meta 16 + Account 12 + Market 4 + Content 14");
assertEquals(233, report.path("summary").path("completedOperations").asInt(),
"completedOperations 必须覆盖 AI 41 + Knowledge 59 + Events 1 + Meta 16 + Account 33 + Market 32 + Content 51");
}
@Test
void should_keep_existing_domain_statuses_unchanged() throws IOException {
assertDomainStatusCount("ai", 41, "completed");
assertDomainStatusCount("knowledge", 59, "completed");
assertContentStatusCount(14, 37);
assertContentStatusCount(51, 0);
assertMetaStatusCount(16, 0);
assertAccountStatusCount(12, 21);
assertAccountStatusCount(33, 0);
}
private void assertContentStatusCount(int expectedCompleted, int expectedNeedsVerification) throws IOException {
@ -176,19 +150,18 @@ class P1rMarketRealApiGateTest {
String operationId = operation.path("operationId").asText("<missing-operationId>");
assertEquals("dedicated", operation.path("implementationStatus").asText(),
"content/" + operationId + " 必须保持 dedicated");
if (APPROVED_CONTENT_COMPLETED_OPERATIONS.contains(operationId)) {
if ("completed".equals(operation.path("completionStatus").asText())) {
completed++;
assertEquals("completed", operation.path("completionStatus").asText(),
"content/" + operationId + " 已获本轮批准后必须 completed");
} else {
needsVerification++;
assertEquals("needs_verification", operation.path("completionStatus").asText(),
"content/" + operationId + " 未获本轮批准,必须继续 needs_verification");
}
if ("needs_verification".equals(operation.path("completionStatus").asText())) {
needsVerification++;
}
assertEquals("completed", operation.path("completionStatus").asText(),
"content/" + operationId + " 已获用户批准后必须 completed");
}
assertEquals(51, total, "Content operation 数量必须保持 51");
assertEquals(expectedCompleted, completed, "Content Admin RiskAction completed approval 后只能推进 14 个 operation");
assertEquals(expectedNeedsVerification, needsVerification, "Content 剩余 37 个 operation 必须继续 needs_verification");
assertEquals(expectedCompleted, completed, "Content 人工批准后 completed 数量不符合预期");
assertEquals(expectedNeedsVerification, needsVerification, "Content 人工批准后 needs_verification 数量不符合预期");
}
@Test
@ -247,8 +220,8 @@ class P1rMarketRealApiGateTest {
}
}
assertEquals(33, total, "Account operation 数量必须保持 33");
assertEquals(expectedCompleted, completed, "Account Security Events read completed approval 后必须有 12 个 operation completed");
assertEquals(expectedNeedsVerification, needsVerification, "Account 剩余 21 个 operation 必须继续 needs_verification");
assertEquals(expectedCompleted, completed, "Account 人工批准后 completed 数量不符合预期");
assertEquals(expectedNeedsVerification, needsVerification, "Account 人工批准后 needs_verification 数量不符合预期");
}
private void assertMetaStatusCount(int expectedCompleted, int expectedNeedsVerification) throws IOException {

View File

@ -76,24 +76,6 @@ class P1rMetaRealApiGateTest {
"activateFunctionChainVersion"
);
/** Content completed approval 当前只允许推进 14 个 operation。 */
private static final Set<String> APPROVED_CONTENT_COMPLETED_OPERATIONS = Set.of(
"listWorks",
"getWork",
"listChapters",
"getChapter",
"listBlocks",
"getBlock",
"saveBlock",
"getBlockSourceAttribution",
"getPlanning",
"savePlanningItem",
"adminListWorks",
"adminGetWork",
"adminListChapters",
"adminRiskAction"
);
private final ObjectMapper objectMapper = new ObjectMapper();
/**
@ -174,12 +156,12 @@ class P1rMetaRealApiGateTest {
}
/**
* 验证 Content 只推进当前已批准的 14 个 operation,防止 Meta gate 漏掉 Content 未批准项回退检查。
* 验证 Content 51 个 operation 已随用户批准全部 completed,防止 Meta gate 漏掉跨域回退检查。
*
* @throws IOException 读取覆盖报告失败时抛出
*/
@Test
void should_keep_content_partial_approval_at_14_completed_operations() throws IOException {
void should_keep_all_content_operations_completed_after_approval() throws IOException {
JsonNode contentOperations = readContentOperations();
int completed = 0;
int needsVerification = 0;
@ -189,18 +171,17 @@ class P1rMetaRealApiGateTest {
String operationId = operation.path("operationId").asText("<missing-operationId>");
assertEquals("dedicated", operation.path("implementationStatus").asText(),
"Content/" + operationId + " 必须继续保持 dedicated");
if (APPROVED_CONTENT_COMPLETED_OPERATIONS.contains(operationId)) {
if ("completed".equals(operation.path("completionStatus").asText())) {
completed++;
assertEquals("completed", operation.path("completionStatus").asText(),
"Content/" + operationId + " 已获本轮批准后必须 completed");
} else {
needsVerification++;
assertEquals("needs_verification", operation.path("completionStatus").asText(),
"Content/" + operationId + " 未获本轮批准,必须继续 needs_verification");
}
if ("needs_verification".equals(operation.path("completionStatus").asText())) {
needsVerification++;
}
assertEquals("completed", operation.path("completionStatus").asText(),
"Content/" + operationId + " 已获用户批准后必须 completed");
}
assertEquals(14, completed, "Content Admin RiskAction completed approval 后只能推进 14 个 operation");
assertEquals(37, needsVerification, "Content 剩余 37 个 operation 必须继续 needs_verification");
assertEquals(51, completed, "Content 人工批准后必须有 51 个 operation completed");
assertEquals(0, needsVerification, "Content 人工批准后不能继续保留 needs_verification");
}
private JsonNode readMetaOperations() throws IOException {