# P1R Content Admin Read Completed Approval 执行版 > **For agentic workers:** REQUIRED SUB-SKILL: Use `superpowers:subagent-driven-development` to implement this plan task-by-task only after fresh execution review double PASS and explicit user approval. Steps use checkbox syntax for tracking. 日期:2026-06-13 ## 结论 本执行版只锁定 Content 管理后台只读模型 3 个 operation-level completed approval: ```text content:adminListWorks content:adminGetWork content:adminListChapters ``` 本轮不把 `content` 加入 domain-level completed allowlist,不推进 Content 51/51 completed,不修改 OpenAPI,不修改 Content 业务实现,不修改 SQL migration。 获批后目标 coverage summary 为: ```text total=233 completed=144 needsVerification=89 incomplete=0 genericPersistence=0 ssePlaceholder=0 ``` Content 域目标状态为: ```text content total=51 completed=13 needsVerification=38 ``` 当前阶段只允许写执行方案并进入 fresh execution review。执行版 review 双 PASS 后,仍必须由用户再次明确批准审批清单、operation-level 边界、allowed diff 和 mixed gate 同步范围,才允许实施。 ```mermaid flowchart TB Current["当前 Content
10 completed / 41 needs_verification"] --> Exec["执行版
锁定 Admin Read 3 ops"] Exec --> Review["fresh execution spec/scope review
fresh execution quality/testing review"] Review --> Approval{"用户明确批准
3 ops / operation-level / allowed diff / mixed gates"} Approval -->|否| Stay["保持当前 coverage
233/141/92"] Approval -->|是| Red["TDD RED
先改 gate 期望
旧 report 必须失败"] Red --> Green["TDD GREEN
scanner operation allowlist
regenerate report"] Green --> Runtime["Admin Read HTTP + real DB _test
RBAC + tenant + no body leak + no-write"] Runtime --> Verify["focused tests + P1R mixed gates
XML 防空跑 + protected diff"] Verify --> FreshReview["fresh implementation review"] ``` ## 当前事实 正确 worktree: ```text /Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0 ``` 当前 HEAD: ```text 2692af3 test(p1r): 收口 Content Planning completed approval 门禁 ``` 当前分支: ```text dev/1.0.0...origin/dev/1.0.0 ``` 当前 coverage summary: ```text 233 141 92 0 0 0 ``` 当前 domain 状态: ```text account completed=10 needsVerification=23 content completed=10 needsVerification=41 market completed=4 needsVerification=28 meta completed=16 needsVerification=0 ``` 当前 Content 状态: - Content total 为 51。 - 已有 10 个 operation 为 `dedicated / completed`:`listWorks`、`getWork`、`listChapters`、`getChapter`、`listBlocks`、`getBlock`、`saveBlock`、`getBlockSourceAttribution`、`getPlanning`、`savePlanningItem`。 - 本执行版目标 3 个 operation 当前为 `dedicated / needs_verification / requiresCommandId=false`。 - `content:adminRiskAction` 当前为 `dedicated / needs_verification / requiresCommandId=true`,不属于本执行版。 - `APPROVED_COMPLETED_DOMAINS` 当前只允许 `ai`、`knowledge`。 - `APPROVED_COMPLETED_OPERATIONS` 当前包含 Events streamEvents、Meta 16、Account 第一批 10、Market 第一批 4、Content 第一批 8、Content Planning 2。 已验证的只读实现事实: - `AdminContentController` 三个 admin read method 均使用 `@PreAuthorize("@ss.hasPermission('muse:content:query')")`。 - `AdminContentController` 三个 admin read method 均调用 `requireApiVersion()` 读取 `X-API-Version`。 - Controller-local mapping 为 `/muse/...`;对外 OpenAPI 路径为 `/admin-api/muse/...`,执行版必须用当前 Web 测试上下文证明最终 admin API 路径。 - `ContentAdminServiceImpl.listWorks` 通过 `riskFlag` 读取 governance action work ids,再按 status / keyword / riskWorkIds 分页读取 work,并聚合 risk flags。 - `ContentAdminServiceImpl.getWork` 读取 work、章节摘要、exception summary 和 governance history,不返回 block 正文。 - `ContentAdminServiceImpl.listChapters` 读取章节列表,聚合 `blockCount` 与 `wordCount`,不返回正文。 - `requireWork(workId)` 当前调用 `workMapper.selectById(workId)`,不是 app owner guard;admin read 的正确安全边界是 admin RBAC + tenant SQL interceptor + 正文不泄露。 - 现有 OpenAPI 明确 admin read 默认不返回用户私有正文全文。 - 现有 `AdminContentControllerTest` / `ContentAdminServiceTest` 只可作为辅助证据,不能替代 completed-grade HTTP + real PostgreSQL `_test`。 ## 执行边界 ### 必须先获用户明确批准 实现前必须同时获得以下 4 项批准: 1. 批准本轮只审批 `content:adminListWorks`、`content:adminGetWork`、`content:adminListChapters` 三个 operation。 2. 批准继续使用 operation-level approval,不把 `content` 加入 domain-level completed allowlist。 3. 批准按本执行版修改 scanner、coverage report、P1R gates、新增 Admin Read HTTP+DB `_test`、memory 和 `.agent`。 4. 批准同步 mixed gate 的 summary / Content / 非目标域防回退断言,目标为 `233/144/89/0/0/0` 与 Content `13 completed / 38 needs_verification`。 未获上述批准前,不得实施本执行版。 ### 本轮允许变更 获批后只允许修改以下路径: - `muse-cloud/scripts/p1r-audit-api-coverage.py` - `docs/superpowers/reports/p1r-api-coverage.json` - `docs/superpowers/reports/p1r-api-coverage.md` - `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rApiCoverageReportTest.java` - `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rContentRealApiGateTest.java` - `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rEventsRealApiGateTest.java` - `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rAiRealApiGateTest.java` - `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rKnowledgeRealApiGateTest.java` - `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rMarketRealApiGateTest.java` - `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rAccountRealApiGateTest.java` - `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rMetaRealApiGateTest.java` - `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rContentAdminReadCompletedApprovalIT.java` - `muse-cloud/muse-module-content/muse-module-content-server/src/test/java/cn/iocoder/muse/module/content/application/ContentAdminServiceTest.java`,仅限补充本执行版缺失的 focused behavior 证据。 - `muse-cloud/muse-module-content/muse-module-content-server/src/test/java/cn/iocoder/muse/module/content/controller/admin/AdminContentControllerTest.java`,仅限补充本执行版缺失的 controller contract 证据。 - `docs/agent-specs/.agent` - `docs/agent-specs/2026-06-13-P1RContentAdminReadCompletedApproval审阅版.md` - `docs/agent-specs/2026-06-13-P1RContentAdminReadCompletedApproval执行版.md` - `docs/memorys/2026-06-13-P1RContentAdminRead状态推进.md` 如 implementation 发现必须修改 Content 业务实现、OpenAPI、SQL migration、非批准 gate 或其它文件,必须停下说明原因并重新取得用户批准。 ### 本轮禁止变更 - 不修改 7 个 OpenAPI。 - 不修改 Content main/java 业务实现来掩盖 coverage 缺口。 - 不新增或修改 SQL migration。 - 不把 `content` 加入 domain-level completed allowlist。 - 不推进 Content 51/51 completed。 - 不推进 Account remaining 23、Market remaining 28、Content remaining 38 或总 P1R completed。 - 不推进 `content:adminRiskAction`、admin import/export task、Content 写命令、AI planning candidate、style check、Meta projection、dynamic fields、FileService、import/export/parse operation。 - 不把 dedicated gate PASS、review PASS、文档结论或已有 Mockito 单测直接等同 completed。 ## 审批清单 | operation key | Method | Path | 目标状态 | 完成证据边界 | |---|---|---|---|---| | `content:adminListWorks` | `GET` | `/admin-api/muse/content/works` | `dedicated / completed` | MockMvc HTTP + 真实 PostgreSQL `_test`,覆盖 API version、method security RBAC、分页、status / keyword / riskFlag true/false、riskFlag 空结果、治理摘要、tenant 隔离、正文不泄露、纯读 no-write | | `content:adminGetWork` | `GET` | `/admin-api/muse/content/works/{workId}` | `dedicated / completed` | MockMvc HTTP + 真实 PostgreSQL `_test`,覆盖存在、missing、cross tenant、章节摘要、异常摘要、治理历史、正文不泄露、纯读 no-write | | `content:adminListChapters` | `GET` | `/admin-api/muse/content/works/{workId}/chapters` | `dedicated / completed` | MockMvc HTTP + 真实 PostgreSQL `_test`,覆盖章节排序、blockCount、wordCount 聚合、空章节 / NULL wordCount、governance target scope、missing、cross tenant、正文不泄露、纯读 no-write | ## 保持 needs_verification 的 Content operation 以下 38 个 operation 必须保持 `dedicated / needs_verification`: ```text content:adminListExportTasks content:adminListImportTasks content:adminRiskAction content:confirmChapterParseResult content:rejectChapterParseResult content:downloadExportPackage content:getExportTask content:getImportTask content:getParseJob content:listParseJobChapters content:batchConfirmChapters content:retryParseJob content:createWork content:deleteWork content:updateWork content:deleteBlock content:mergeBlocks content:splitBlock content:mergeBlockSuggestion content:createChapter content:deleteChapter content:updateChapter content:createBlock content:reorderChapters content:validateDynamicFields content:exportWork content:createExportTask content:createImportTask content:listMetaProjections content:getMetaProjection content:createParseJob content:listPlanningCandidates content:createPlanningCandidate content:getPlanningCandidate content:confirmPlanningCandidate content:discardPlanningCandidate content:createStyleCheck content:getStyleCheckResult ``` ## 证据分层 | Evidence | 文件 / 测试 | 目的 | |---|---|---| | Operation inventory / coverage gate | `P1rApiCoverageReportTest`、`P1rContentRealApiGateTest` 和 mixed gates | 证明只推进获批 3 个 operation,非目标 domain 不回退 | | Admin HTTP+DB `_test` | 新增 `P1rContentAdminReadCompletedApprovalIT` | 证明 3 个 operation 经 MockMvc HTTP 入口访问真实 PostgreSQL `_test` 数据 | | Tenant / schema gate | `P1rContentAdminReadCompletedApprovalIT` 内验证 V1-V21 clean migrate 与 admin read 依赖表 | 证明 Work / Chapter / Block / GovernanceAction schema 和 tenant interceptor 真实可用 | | Method security gate | `P1rContentAdminReadCompletedApprovalIT` 内启用 method security 与 `ss` bean | 证明 admin RBAC 缺权限拒绝不是注解反射假证据 | | Focused unit/controller tests | `ContentAdminServiceTest`、`AdminContentControllerTest` | 支撑 service/controller contract,不替代 HTTP+DB `_test` | ## 共同验证规则 每个 Maven 验证任务必须: - 先 `rm -f` 目标 surefire XML,避免读旧 XML。 - 设置 `RUN_START_EPOCH=$(date +%s)`。 - Maven 完成后读取目标 XML,检查 `mtime >= RUN_START_EPOCH`。 - 检查 `tests >= 最低 tests`、`failures=0`、`errors=0`、`skipped=0`。 - 如果命令失败,保留失败输出和 XML,不得通过跳过测试或降低最低 tests 继续。 XML 防空跑脚本模板: ```bash python3 - <<'PY' import os import sys import xml.etree.ElementTree as ET from pathlib import Path run_start = int(os.environ["RUN_START_EPOCH"]) checks = [ # ("path/to/TEST-Example.xml", min_tests), ] failed = False for path, min_tests in checks: p = Path(path) if not p.exists(): print(f"missing_xml={path}") failed = True continue mtime = int(p.stat().st_mtime) if mtime < run_start: print(f"stale_xml={path} mtime={mtime} run_start={run_start}") failed = True root = ET.parse(p).getroot() tests = int(root.attrib.get("tests", "0")) failures = int(root.attrib.get("failures", "0")) errors = int(root.attrib.get("errors", "0")) skipped = int(root.attrib.get("skipped", "0")) print(path, tests, failures, errors, skipped) if tests < min_tests or failures or errors or skipped: failed = True if failed: sys.exit(1) PY ``` 执行具体任务时必须把 `checks` 替换成该任务表格内列出的 XML 路径和最低 tests。 ## 实施任务 ### Task 1:TDD RED,先改 gate 期望 获批后先修改: - `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rApiCoverageReportTest.java` - `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rContentRealApiGateTest.java` - `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rEventsRealApiGateTest.java` - `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rAiRealApiGateTest.java` - `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rKnowledgeRealApiGateTest.java` - `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rMarketRealApiGateTest.java` - `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rAccountRealApiGateTest.java` - `muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rMetaRealApiGateTest.java` RED 期望: - summary 期望 `completed=144`、`needsVerification=89`,但旧 report 仍是 `141/92`,必须失败。 - Content 13 个 approved operation 期望 `completed`,但 `adminListWorks`、`adminGetWork`、`adminListChapters` 在旧 report 仍是 `needs_verification`,必须失败。 - Content 38 个未批准 operation 继续期望 `needs_verification`,其中必须包含 `adminRiskAction`、`adminListImportTasks`、`adminListExportTasks`、`createWork`、`updateWork`、`createChapter`、`mergeBlockSuggestion`、`exportWork`、`listPlanningCandidates`、`createStyleCheck`。 - Account 仍为 `10 completed / 23 needs_verification`,Market 仍为 `4 completed / 28 needs_verification`,Meta 仍为 `16 completed / 0 needs_verification`,AI/Knowledge/Events 不回退。 运行: ```bash cd muse-cloud export RUN_START_EPOCH=$(date +%s) rm -f \ muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rApiCoverageReportTest.xml \ muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rContentRealApiGateTest.xml \ muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rEventsRealApiGateTest.xml \ muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rAiRealApiGateTest.xml \ muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rKnowledgeRealApiGateTest.xml \ muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rMarketRealApiGateTest.xml \ muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rAccountRealApiGateTest.xml \ muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rMetaRealApiGateTest.xml JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" \ mvn -o test -pl muse-server -am \ -Dtest=P1rApiCoverageReportTest,P1rContentRealApiGateTest,P1rEventsRealApiGateTest,P1rAiRealApiGateTest,P1rKnowledgeRealApiGateTest,P1rMarketRealApiGateTest,P1rAccountRealApiGateTest,P1rMetaRealApiGateTest \ -DfailIfNoTests=false \ -Dsurefire.failIfNoSpecifiedTests=false ``` 预期:至少一个失败点来自旧 report 的 `141/92` 或目标 3 个 admin read operation 尚未 completed。若直接通过,必须停止并排查假绿。 ### Task 2:TDD GREEN,最小 scanner/report 状态推进 只修改 `muse-cloud/scripts/p1r-audit-api-coverage.py`: - 不修改 `APPROVED_COMPLETED_DOMAINS`。 - 只向 `APPROVED_COMPLETED_OPERATIONS` 追加三个 `content:*` operation key。 - 保持 completed 必须仍是 `dedicated` 的校验。 生成 report: ```bash python3 muse-cloud/scripts/p1r-audit-api-coverage.py --check ``` 预期 summary: ```text total=233 completed=144 needsVerification=89 incomplete=0 genericPersistence=0 ssePlaceholder=0 ``` 预期 Content: ```text completed=13 needsVerification=38 ``` 预期 scanner 仍不包含 `content` domain-level allowlist: ```bash python3 - <<'PY' from pathlib import Path source = Path("muse-cloud/scripts/p1r-audit-api-coverage.py").read_text() assert 'APPROVED_COMPLETED_DOMAINS = {"ai", "knowledge"}' in source for key in ["content:adminListWorks", "content:adminGetWork", "content:adminListChapters"]: assert key in source print("content_admin_read_operation_level_allowlist=PASS") PY ``` ### Task 3:Focused Admin unit/controller verification 运行 Content admin focused tests: ```bash cd muse-cloud export RUN_START_EPOCH=$(date +%s) rm -f \ muse-module-content/muse-module-content-server/target/surefire-reports/TEST-cn.iocoder.muse.module.content.application.ContentAdminServiceTest.xml \ muse-module-content/muse-module-content-server/target/surefire-reports/TEST-cn.iocoder.muse.module.content.controller.admin.AdminContentControllerTest.xml JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" \ mvn -o test -pl muse-module-content/muse-module-content-server -am \ -Dtest=ContentAdminServiceTest,AdminContentControllerTest \ -Dsurefire.failIfNoSpecifiedTests=false ``` 必须读取以下 XML 并检查 `mtime >= RUN_START_EPOCH`、`failures=0`、`errors=0`、`skipped=0`: | Test class | 最低 tests | |---|---:| | `ContentAdminServiceTest` | 10 | | `AdminContentControllerTest` | 6 | Focused tests 必须至少支撑: - `listWorks` status / keyword / governance summary。 - `getWork` 不返回正文。 - `listChapters` 不返回正文,且 blockCount / wordCount 聚合正确。 - Controller 层 `X-API-Version`、CommonResult route、`@PreAuthorize` 注解合同。 Focused tests 只作为补充证据,不替代 Task 4 的 HTTP + real DB `_test`;尤其缺权限拒绝不能只靠 `@PreAuthorize` 反射断言。 ### Task 4:Admin Read HTTP + 真实 PostgreSQL `_test` completed gate 新增 `P1rContentAdminReadCompletedApprovalIT`,使用独立 `_test` 数据库、MockMvc HTTP 入口、真实 mapper/service、真实 PostgreSQL 数据。 测试上下文要求: - 只导入 admin read 必需 controller/service/mapper 与基础 Web/MyBatis/DataSource 自动配置,不做 Content 全包扫描。注意 `ContentAdminServiceImpl` 字段注入还包含 `ImportTaskMapper`、`ExportTaskMapper`、`ContentCommandService`、`ContentAuditService`;即使本切片不调用 import/export/risk 写路径,测试上下文也必须保证这些 `@Resource` 依赖可启动,避免 Spring 启动失败。 - 最小 Spring 配置必须复用 `P1rContentCoreCompletedApprovalIT` / `P1rContentPlanningCompletedApprovalIT` 的 Web/MyBatis/DataSource 模式:`JacksonAutoConfiguration`、`HttpMessageConvertersAutoConfiguration`、`DataSourceAutoConfiguration`、`DataSourceTransactionManagerAutoConfiguration`、`JdbcTemplateAutoConfiguration`、`TransactionAutoConfiguration`、`RestTemplateAutoConfiguration`、`WebMvcAutoConfiguration`、`MuseDataSourceAutoConfiguration`、`MuseMybatisAutoConfiguration`、`MybatisPlusAutoConfiguration`、`MybatisPlusJoinAutoConfiguration`、`MuseWebAutoConfiguration`。 - 导入 `AdminContentController`、`ContentAdminServiceImpl`。 - `ContentAdminServiceImpl` 字段依赖中包含 `ContentCommandService` 与 `ContentAuditService`。本切片只走读路径,不应调用它们;测试上下文必须提供真实 bean 或 fail-fast test stub 使 Spring 可启动,并在所有 admin read 用例后断言 fail-fast stub 未被调用。 - 提供 test-local `ApiErrorLogCommonApi` stub,返回 `CommonResult.success(true)`,满足 `MuseWebAutoConfiguration` / `GlobalExceptionHandler` 依赖。 - 注册 `TenantLineInnerInterceptor`,通过 `MyBatisUtils.addInterceptor(interceptor, new TenantLineInnerInterceptor(new TenantDatabaseInterceptor(new TenantProperties())), 0)` 接入 MyBatis Plus interceptor,确保 cross tenant 断言是真实 SQL tenant 隔离,不只是 seed 数据碰巧不可见。 - 启用 method security。可选方案是导入 `MuseWebSecurityConfigurerAdapter` 并提供最小安全依赖,或在 test configuration 上使用 `@EnableMethodSecurity(securedEnabled = true)`。 - 提供 `@Bean("ss")` 的 `SecurityFrameworkService` test double,按测试用例可控返回 `true/false`,并记录收到的 permission;授权成功用例必须断言调用了 `muse:content:query`。缺权限用例必须返回拒绝响应、不泄露 seed 数据,并保持 command/outbox/governance/work/chapter/block no-write;如要证明 service 未执行,可使用 spy bean 或 fail-fast wrapper,但不得把该证明建立在 `@PreAuthorize` 反射断言上。 - 使用 `WebApplicationContext + MockMvc` 访问 `/admin-api/muse/content/works`、`/admin-api/muse/content/works/{workId}`、`/admin-api/muse/content/works/{workId}/chapters`。 - 同时断言 controller-local `/muse/...` 不是 completed evidence 的唯一入口;最终证据必须来自 `/admin-api/muse/...`。 - 每个测试启动时设置 admin login user、tenant context,并在测试结束清理 `SecurityContextHolder` 与 `TenantContextHolder`。 - 每个测试前 `TRUNCATE muse_content_governance_action, muse_content_block, muse_content_chapter, muse_content_work, muse_content_command_log, muse_content_event_publish_outbox RESTART IDENTITY CASCADE`,再 seed 必需数据。Content audit snapshot 当前保存在 `muse_content_command_log.result_snapshot` 内,不存在独立 Content audit 表,执行版不得新增该表或把它作为 no-write 断言目标。 建库与运行: ```bash source ~/.config/muse-repo/infra.env export P1R_FLYWAY_PASSWORD="$MUSE_POSTGRES_PASSWORD" export P1R_CONTENT_COMPLETED_PASSWORD="$MUSE_POSTGRES_PASSWORD" export P1R_CONTENT_ADMIN_READ_COMPLETED_APPROVAL_TEST_DB=muse_p1r_content_admin_read_completed_approval_test PGPASSWORD="$MUSE_POSTGRES_PASSWORD" psql \ -h "$MUSE_POSTGRES_HOST" \ -p "$MUSE_POSTGRES_PORT" \ -U "$MUSE_POSTGRES_USERNAME" \ -d postgres \ -tc "SELECT 1 FROM pg_database WHERE datname = '$P1R_CONTENT_ADMIN_READ_COMPLETED_APPROVAL_TEST_DB'" | grep -q 1 || \ PGPASSWORD="$MUSE_POSTGRES_PASSWORD" psql \ -h "$MUSE_POSTGRES_HOST" \ -p "$MUSE_POSTGRES_PORT" \ -U "$MUSE_POSTGRES_USERNAME" \ -d postgres \ -c "CREATE DATABASE $P1R_CONTENT_ADMIN_READ_COMPLETED_APPROVAL_TEST_DB" cd muse-cloud export RUN_START_EPOCH=$(date +%s) rm -f muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rContentAdminReadCompletedApprovalIT.xml JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" \ mvn -o test -pl muse-server -am \ -Dtest=P1rContentAdminReadCompletedApprovalIT \ -Dflyway.postgresql.transactional.lock=false \ -Dp1r.flyway.locations=filesystem:sql/muse \ -Dp1r.flyway.url="jdbc:postgresql://$MUSE_POSTGRES_HOST:$MUSE_POSTGRES_PORT/$P1R_CONTENT_ADMIN_READ_COMPLETED_APPROVAL_TEST_DB" \ -Dp1r.flyway.user="$MUSE_POSTGRES_USERNAME" \ -Djava.net.useSystemProxies=false \ -DsocksProxyHost= -DsocksProxyPort= \ -Dhttp.proxyHost= -Dhttp.proxyPort= \ -Dhttps.proxyHost= -Dhttps.proxyPort= \ -Dsurefire.failIfNoSpecifiedTests=false ``` 必须检查 XML: | Test class | 最低 tests | |---|---:| | `P1rContentAdminReadCompletedApprovalIT` | 10 | 该 IT 必须覆盖以下 10 个测试: 1. 拒绝 JVM password system property 和 JDBC credential query,库名必须以 `_test` 结尾。 2. V1-V21 clean migrate 后验证 admin read 依赖 schema:`muse_content_work`、`muse_content_chapter`、`muse_content_block`、`muse_content_governance_action` 表、tenant_id、deleted、work/chapter/block 关联列、基础索引或查询所需列存在。 3. Method security 成功路径:`ss.hasPermission("muse:content:query")` 返回 true 时,`GET /admin-api/muse/content/works` 成功,并记录 permission 调用。 4. Method security 拒绝路径:`ss.hasPermission("muse:content:query")` 返回 false 时,admin read 请求被拒绝,不泄露 seed 数据,并保持 command/outbox/governance/work/chapter/block no-write;该证据必须来自启用 method security 的 HTTP 请求,不能只靠 `@PreAuthorize` 反射断言。 5. `adminListWorks` happy path:`status`、`keyword`、`riskFlag=false` 返回当前 tenant 普通分页、ownerId、wordCount、chapterCount、risk flags 和 lastGovernanceActionAt,且不泄露正文。 6. `adminListWorks` risk path:`riskFlag=true` 只返回当前 tenant 有 governance action 的 work;当前 tenant 无治理动作时返回空页;cross tenant governance action 不影响当前 tenant。 7. `adminGetWork` happy path:返回作品元信息、章节摘要、exception summary、governance history;不返回 `contentText`、`content`、`body` 等正文字段。 8. `adminGetWork` missing / cross tenant:返回统一错误或 not found 语义,不泄露其它 tenant 数据,且 no-write。 9. `adminListChapters` happy path:按 `orderNo` 升序返回章节摘要,blockCount 与真实 block 行数一致,wordCount 聚合当前 tenant 数据,空章节或 NULL wordCount 返回 0,governance target scope 对章节 risk flags 生效。 10. `adminListChapters` missing / cross tenant / missing API version:缺 `X-API-Version` 返回 CommonResult 错误;missing/cross tenant 不泄露数据;三类负路径均 no-write。 No-write assertion 必须至少覆盖: ```text muse_content_command_log muse_content_event_publish_outbox muse_content_governance_action muse_content_work muse_content_chapter muse_content_block ``` 正文不泄露 assertion 必须至少覆盖 JSON 字符串或 JSON path 中不存在: ```text contentText content body 正文全文 ``` 数据库与安全要求: - 密码只能从 `P1R_CONTENT_ADMIN_READ_COMPLETED_PASSWORD`、`P1R_CONTENT_COMPLETED_PASSWORD`、`P1R_FLYWAY_PASSWORD` 或 `MUSE_POSTGRES_PASSWORD` 环境变量读取,不能通过 JVM system property 传入。 - JDBC URL 不能携带 `user`、`username`、`password`、`pass`、`pwd`、`token`、`secret`、`api_key`、`bearer`、`access_token`、`refresh_token` 等凭据 query。 - 如果测试读取并脱敏 `p1r.flyway.url/user`,必须保存原始 system property 并在 `@AfterAll` 恢复。 - 测试输出和断言不得打印明文数据库密码;raw Surefire XML 只能作为本地证据,外发前需清洗 DB host/user。 ### Task 5:Admin Read + existing Content DB gates 组合验证 运行新增 Admin Read IT 与既有 Content DB gates,防止 Flyway system property、tenant interceptor 或 data source 配置互相污染: ```bash source ~/.config/muse-repo/infra.env export P1R_FLYWAY_PASSWORD="$MUSE_POSTGRES_PASSWORD" export P1R_CONTENT_COMPLETED_PASSWORD="$MUSE_POSTGRES_PASSWORD" export P1R_CONTENT_ADMIN_READ_COMPLETED_APPROVAL_TEST_DB=muse_p1r_content_admin_read_combined_test PGPASSWORD="$MUSE_POSTGRES_PASSWORD" psql \ -h "$MUSE_POSTGRES_HOST" \ -p "$MUSE_POSTGRES_PORT" \ -U "$MUSE_POSTGRES_USERNAME" \ -d postgres \ -tc "SELECT 1 FROM pg_database WHERE datname = '$P1R_CONTENT_ADMIN_READ_COMPLETED_APPROVAL_TEST_DB'" | grep -q 1 || \ PGPASSWORD="$MUSE_POSTGRES_PASSWORD" psql \ -h "$MUSE_POSTGRES_HOST" \ -p "$MUSE_POSTGRES_PORT" \ -U "$MUSE_POSTGRES_USERNAME" \ -d postgres \ -c "CREATE DATABASE $P1R_CONTENT_ADMIN_READ_COMPLETED_APPROVAL_TEST_DB" cd muse-cloud export RUN_START_EPOCH=$(date +%s) rm -f \ muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rContentAdminReadCompletedApprovalIT.xml \ muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rContentCoreCompletedApprovalIT.xml \ muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rContentPlanningCompletedApprovalIT.xml \ muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rContentEventsPublishFlywayMigrationIT.xml JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" \ mvn -o test -pl muse-server -am \ -Dtest=P1rContentAdminReadCompletedApprovalIT,P1rContentCoreCompletedApprovalIT,P1rContentPlanningCompletedApprovalIT,P1rContentEventsPublishFlywayMigrationIT \ -Dflyway.postgresql.transactional.lock=false \ -Dp1r.flyway.locations=filesystem:sql/muse \ -Dp1r.flyway.url="jdbc:postgresql://$MUSE_POSTGRES_HOST:$MUSE_POSTGRES_PORT/$P1R_CONTENT_ADMIN_READ_COMPLETED_APPROVAL_TEST_DB" \ -Dp1r.flyway.user="$MUSE_POSTGRES_USERNAME" \ -Djava.net.useSystemProxies=false \ -DsocksProxyHost= -DsocksProxyPort= \ -Dhttp.proxyHost= -Dhttp.proxyPort= \ -Dhttps.proxyHost= -Dhttps.proxyPort= \ -Dsurefire.failIfNoSpecifiedTests=false ``` 必须读取以下 XML: | Test class | 最低 tests | |---|---:| | `P1rContentAdminReadCompletedApprovalIT` | 10 | | `P1rContentCoreCompletedApprovalIT` | 12 | | `P1rContentPlanningCompletedApprovalIT` | 11 | | `P1rContentEventsPublishFlywayMigrationIT` | 4 | 总计最低 tests 为 37。 ### Task 6:P1R mixed gates 重新运行并 XML 防空跑: ```bash cd muse-cloud export RUN_START_EPOCH=$(date +%s) rm -f \ muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rApiCoverageReportTest.xml \ muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rContentRealApiGateTest.xml \ muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rEventsRealApiGateTest.xml \ muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rAiRealApiGateTest.xml \ muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rKnowledgeRealApiGateTest.xml \ muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rMarketRealApiGateTest.xml \ muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rAccountRealApiGateTest.xml \ muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rMetaRealApiGateTest.xml JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" \ mvn -o test -pl muse-server -am \ -Dtest=P1rApiCoverageReportTest,P1rContentRealApiGateTest,P1rEventsRealApiGateTest,P1rAiRealApiGateTest,P1rKnowledgeRealApiGateTest,P1rMarketRealApiGateTest,P1rAccountRealApiGateTest,P1rMetaRealApiGateTest \ -DfailIfNoTests=false \ -Dsurefire.failIfNoSpecifiedTests=false ``` 必须读取以下 XML: | Test class | 最低 tests | |---|---:| | `P1rApiCoverageReportTest` | 6 | | `P1rContentRealApiGateTest` | 5 | | `P1rEventsRealApiGateTest` | 7 | | `P1rAiRealApiGateTest` | 7 | | `P1rKnowledgeRealApiGateTest` | 8 | | `P1rMarketRealApiGateTest` | 6 | | `P1rAccountRealApiGateTest` | 5 | | `P1rMetaRealApiGateTest` | 5 | 总计最低 tests 为 49;如新增断言导致 tests 增加,XML 最低值可同步提高,但不能低于上表。 Gate 更新要求: - `P1rApiCoverageReportTest`:expected summary 改为 `completed=144`、`needsVerification=89`;approved Content completed set 改为 13;断言 `adminListWorks`、`adminGetWork`、`adminListChapters` completed;仍断言 `adminRiskAction`、`adminListImportTasks`、`adminListExportTasks`、`createWork`、`updateWork`、`createChapter`、`mergeBlockSuggestion`、`exportWork`、`listPlanningCandidates`、`createStyleCheck` 为 `needs_verification`。 - `P1rContentRealApiGateTest`:approved Content completed set 改为 13;Content count 改为 `13 completed / 38 needs_verification`;代表性未批准 operation 必须包含 `adminRiskAction`、admin import/export task、AI planning candidate / style check 相关 operation。 - `P1rEventsRealApiGateTest`、`P1rAiRealApiGateTest`、`P1rKnowledgeRealApiGateTest`、`P1rMarketRealApiGateTest`、`P1rAccountRealApiGateTest`、`P1rMetaRealApiGateTest`:同步 summary 文案和 Content count 到 `13/38`,并继续校验 Account `10/23`、Market `4/28`、Meta `16/0`、AI/Knowledge/Events 不回退。 ### Task 7:Coverage scanner final check 运行: ```bash python3 muse-cloud/scripts/p1r-audit-api-coverage.py --check jq -r '.summary | [.totalOperations,.completedOperations,.needsVerificationOperations,.incompleteOperations,.genericPersistenceOperations,.ssePlaceholderOperations] | @tsv' docs/superpowers/reports/p1r-api-coverage.json jq -r '.operations[] | select(.domain=="content") | [.operationId,.implementationStatus,.completionStatus,.requiresCommandId] | @tsv' docs/superpowers/reports/p1r-api-coverage.json ``` 预期: ```text 233 144 89 0 0 0 ``` Content 必须精确为 13 completed / 38 needs_verification,且 `APPROVED_COMPLETED_DOMAINS` 仍不包含 `content`。 ### Task 8:Diff gate 与文档留痕 - [ ] 更新 `.agent`,记录 implementation evidence、测试命令、XML 计数、protected diff、review 状态和 remaining boundary。 - [ ] 新增或更新 `docs/memorys/2026-06-13-P1RContentAdminRead状态推进.md`,只记录已验证事实,不把 review PASS 或 gate PASS 写成 Content 51/51 completed。 - [ ] 运行 whitespace gate: ```bash git diff --check ``` - [ ] 检查 OpenAPI protected diff 为空: ```bash git -c core.quotePath=false diff -- docs/api-contracts ``` - [ ] 检查 Content main/java 与 SQL migration diff 为空: ```bash git -c core.quotePath=false diff -- muse-cloud/muse-module-content/muse-module-content-server/src/main/java muse-cloud/sql/muse ``` - [ ] 检查 scanner/report/gate/test/doc diff 只落在 allowed list: ```bash git -c core.quotePath=false diff --name-only git -c core.quotePath=false ls-files --others --exclude-standard ``` 允许路径必须是本执行版“本轮允许变更”列出的路径。出现其它路径时必须停止并说明。 ### Task 9:Fresh implementation review gate 实现与验证完成后,必须重新派发两个 fresh reviewer: - fresh implementation spec/correctness reviewer。 - fresh implementation quality/data-integrity/testing reviewer。 两个 reviewer 都必须只读复核: - 正确 worktree 与 HEAD。 - coverage summary `233/144/89/0/0/0`。 - Content 精确为 `13 completed / 38 needs_verification`。 - `APPROVED_COMPLETED_DOMAINS` 未加入 `content`。 - scanner 只追加 `content:adminListWorks`、`content:adminGetWork`、`content:adminListChapters` 三个 operation-level allowlist。 - `adminRiskAction`、admin import/export task、Content 写命令、AI planning candidate / style check 仍为 `needs_verification`。 - OpenAPI、Content main/java、SQL migration diff 为空。 - `P1rContentAdminReadCompletedApprovalIT` HTTP + real DB `_test` 证据覆盖 admin RBAC、tenant interceptor、正文不泄露、riskFlag 聚合、missing/cross tenant、no-write。 - P1R mixed gates XML 防空跑成立。 fresh implementation review 双 PASS 前,不得提交、push 或宣称 `adminListWorks`、`adminGetWork`、`adminListChapters` completed approval 已收口。 ## 回滚策略 如任一 gate 失败: - 保留失败输出和 XML 事实,先定位是否是执行版遗漏、测试假设错误、实现缺口或环境问题。 - 不通过修改 OpenAPI、Content main/java 或 SQL migration 来绕过本轮 coverage 缺口。 - 如缺口证明当前实现不足以支撑 completed approval,回退本轮 scanner/report/gate 状态推进,只保留审阅版和执行版文档事实,向用户汇报阻塞。 如需要回退已实施的 operation-level approval: - 从 `APPROVED_COMPLETED_OPERATIONS` 移除 `content:adminListWorks`、`content:adminGetWork`、`content:adminListChapters`。 - 重新运行 `python3 muse-cloud/scripts/p1r-audit-api-coverage.py --check`,恢复 summary `233/141/92/0/0/0`。 - 恢复 P1R gate 对 Content `10 completed / 41 needs_verification` 的断言。 - 保留 memory 中的失败事实和回退原因,避免后续重复推进。 ## 自检清单 - [ ] 本执行版只覆盖 `content:adminListWorks`、`content:adminGetWork`、`content:adminListChapters`。 - [ ] 本执行版未要求把 `content` 加入 domain-level completed allowlist。 - [ ] 本执行版未要求修改 OpenAPI、Content main/java 或 SQL migration。 - [ ] 38 个保留 `needs_verification` operation 与审阅版一致。 - [ ] TDD RED 在 scanner/report 修改前发生。 - [ ] HTTP+DB `_test` 覆盖 admin RBAC、tenant interceptor、API version、admin list/detail/chapter read、riskFlag、正文不泄露和 no-write。 - [ ] Method security 缺权限拒绝不只靠 `@PreAuthorize` 反射断言。 - [ ] Mixed gates 明确包含 8 个类名,并覆盖 Account、Market、Meta 防回退。 - [ ] XML 防空跑有明确 mtime、tests、failures、errors、skipped 规则。 - [ ] 实现完成后仍需 fresh implementation review 双 PASS,才允许请求提交/push。