# P1R Content Admin Read Completed Approval 审阅版
日期:2026-06-13
## 结论
推荐 Content 下一批只推进管理后台只读模型 3 个 operation 的 operation-level completed approval:
```text
content:adminListWorks
content:adminGetWork
content:adminListChapters
```
不推荐把 Content 剩余 41 个 operation 一次性推进 completed,也不推荐把 `content` 加入 domain-level completed allowlist。
这 3 个 operation 是 admin 侧读模型,只读取作品摘要、章节摘要和治理摘要,不写 command / audit / outbox,不依赖 FileService、AI candidate、Meta projection 或导入导出产物。它们的 completed approval 应独立成一个小切片,用真实 PostgreSQL `_test`、MockMvc HTTP 入口、admin RBAC、tenant 隔离、治理摘要聚合和正文不泄露证据闭合。
本审阅版只冻结候选范围、证据标准、风险边界和后续执行版要求。不修改 OpenAPI,不修改 scanner,不修改 coverage report,不修改业务实现,不推进任何 operation completed。
```mermaid
flowchart TB
Current["当前 Content
10 completed / 41 needs_verification"] --> Choose["选择下一批 evidence slice"]
Choose --> AdminRead["推荐:admin read
adminListWorks + adminGetWork + adminListChapters"]
Choose --> Wider["不推荐:Content 剩余 41 全量推进"]
AdminRead --> Boundary{"是否写入业务事实?"}
Boundary -->|否| Evidence["只读 evidence
RBAC + tenant + no body leak + no-write"]
Boundary -->|是| Defer["保持 needs_verification"]
Evidence --> Review["fresh spec/scope review
fresh quality/feasibility review"]
Review --> Exec["双 PASS 后写执行版"]
Exec --> Approval{"用户明确批准后才实现"}
Approval -->|否| Stay["保持 233/141/92"]
Approval -->|是| Target["目标 233/144/89
Content 13 completed / 38 needs_verification"]
```
## 当前事实状态
工作区:
```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
total=233
completed=141
needsVerification=92
incomplete=0
genericPersistence=0
ssePlaceholder=0
```
当前 domain 状态:
```text
account completed=10 needsVerification=23
content completed=10 needsVerification=41
market completed=4 needsVerification=28
meta completed=16 needsVerification=0
```
本审阅版推荐的下一批目标值只是后续获批后的执行目标:
```text
total=233
completed=144
needsVerification=89
incomplete=0
genericPersistence=0
ssePlaceholder=0
content total=51
completed=13
needsVerification=38
```
## 推荐候选
| operation key | Method | Path | 推荐原因 | 必补 completed-grade evidence |
|---|---|---|---|---|
| `content:adminListWorks` | `GET` | `/admin-api/muse/content/works` | admin 作品列表读模型,支持 status / keyword / riskFlag,返回治理摘要,不返回正文 | MockMvc HTTP + 真实 PostgreSQL `_test`,覆盖 API version、admin RBAC、分页过滤、riskFlag true/false、治理摘要、tenant 隔离、正文不泄露、纯读 no-write |
| `content:adminGetWork` | `GET` | `/admin-api/muse/content/works/{workId}` | admin 作品详情读模型,返回作品元信息、章节摘要、异常摘要和治理历史,不返回正文全文 | MockMvc HTTP + 真实 PostgreSQL `_test`,覆盖存在、missing、cross tenant、治理历史、章节摘要聚合、正文不泄露、纯读 no-write |
| `content:adminListChapters` | `GET` | `/admin-api/muse/content/works/{workId}/chapters` | admin 章节摘要列表读模型,按章节顺序返回 blockCount / wordCount / riskFlags,不返回 block 正文 | MockMvc HTTP + 真实 PostgreSQL `_test`,覆盖章节排序、blockCount、wordCount 聚合、治理 risk flags、missing、cross tenant、正文不泄露、纯读 no-write |
推荐理由:
- 3 个 operation 全部是 `GET`,当前 coverage `requiresCommandId=false`,与只读语义一致。
- Controller 已有 `@PreAuthorize("@ss.hasPermission('muse:content:query')")`,后续 completed evidence 应证明 admin RBAC 仍是入口门槛。
- Service 读模型只调用 Work / Chapter / Block / GovernanceAction mapper,不写 command、audit、outbox 或业务表。
- OpenAPI 已声明 admin read 不返回用户私有正文全文,现有 controller / service 单测也已有“不返回 content/body/contentText”方向的证据。
- 这 3 个 operation 可与 `adminRiskAction` 完全切开,避免把治理写命令的 commandId、expectedVersion、幂等、审计和行锁要求混入只读切片。
## 不纳入本批的 operation
以下 38 个 Content 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
```
排除原因:
- `adminRiskAction` 是治理写命令,当前 `requiresCommandId=true`,服务实现包含 command reserve、expectedVersion 校验、行锁、治理事实 insert、audit 和幂等 replay,必须单独做写路径切片。
- `adminListImportTasks` / `adminListExportTasks` 虽是 admin read,但读的是任务域,证据应覆盖导入导出任务状态、产物和 work 关联,不应夹入本轮作品/章节读模型。
- 创建、更新、删除、重排、拆分、合并等 Content 写命令仍有独立 OpenAPI / commandId / revision / no-write 负路径闭合风险。
- 导入、导出、解析、下载仍缺 FileService、任务产物和真实下载字节闭环 evidence。
- Meta projection、AI planning candidate、style check、suggestion 等能力依赖 Meta / AI / Knowledge 外部 owner closure 和运行时证据。
## 已有实现证据
### Controller 入口
`AdminContentController` 当前提供 3 个 admin read route:
```text
GET /muse/content/works
GET /muse/content/works/{workId}
GET /muse/content/works/{workId}/chapters
```
以上是 controller-local mapping;对外 OpenAPI 路径仍以 `/admin-api/muse/...` 为准。执行版必须通过当前项目既有 admin MockMvc / Web 测试上下文证明最终 admin API 路径可访问。
三者均调用 `requireApiVersion()`,并使用:
```text
@PreAuthorize("@ss.hasPermission('muse:content:query')")
```
这能作为后续执行版的入口证据来源,但不能替代 HTTP + real DB completed evidence。
### Service 读模型
`ContentAdminServiceImpl.listWorks`:
- `riskFlag=true` 时先按当前 tenant 查询 governance action 的 distinct work ids。
- 通过 `WorkMapper.selectAdminPage` 按 status、keyword、riskWorkIds 分页。
- 查询当前页作品的 governance actions,转换为 risk flags 和最后治理时间。
`ContentAdminServiceImpl.getWork`:
- 通过 `requireWork(workId)` 读取作品。
- 复用 `listChapters(workId)` 返回章节摘要。
- 查询治理动作,返回 exception summary 和 governance history。
- 返回作品元信息、ownerId、wordCount、chapterCount、createdAt、updatedAt,不返回 block 正文。
`ContentAdminServiceImpl.listChapters`:
- 通过 `requireWork(workId)` 确认作品存在。
- 查询 governance actions。
- 按 `ChapterMapper.selectListByWorkId` 顺序返回章节摘要。
- 通过 `BlockMapper.selectCountByChapterId` 和 `selectWordCountSumByChapterId` 聚合 block 数和字数,不返回正文。
### OpenAPI 合同
OpenAPI 当前 operationId:
```text
adminListWorks
adminGetWork
adminListChapters
```
OpenAPI 对 admin read 的核心约束是:
- 管理员查询作品列表和治理摘要。
- 管理员查看作品元信息、章节摘要、异常摘要。
- 管理员查看作品章节列表,不含正文全文。
- 默认不返回用户私有正文全文,确需查看必须另有合规访问设计。
本切片不需要修改 `docs/api-contracts/content/openapi.yaml`。
### 当前单元测试证据
现有 focused tests 可作为执行版辅助证据:
- `AdminContentControllerTest.should_requireRbacAnnotationsForAdminContentApis`
- `AdminContentControllerTest.should_rejectMissingApiVersion_when_listWorks`
- `AdminContentControllerTest.should_exposeAdminReadRoutesWithoutPrivateBody`
- `ContentAdminServiceTest.should_listWorksWithGovernanceSummary`
- `ContentAdminServiceTest.should_getWorkDetailWithoutPrivateBody`
- `ContentAdminServiceTest.should_listChaptersWithoutBody`
- `ContentAdminServiceTest.should_listChaptersWithAggregatedWordCountAndKeepBlockCount`
这些测试不能直接等同 completed。completed approval 仍需要新增或扩展 HTTP + real PostgreSQL `_test` 证据,证明 route、mapper、tenant 拦截、真实 schema 和 no-write 一起成立。
## 必补证据标准
后续执行版必须至少覆盖以下矩阵。
### Admin List Works
- 有 `X-API-Version` 的成功请求。
- 缺 `X-API-Version` 的统一错误响应。
- admin 权限 `muse:content:query` 存在,并有缺权限拒绝证据。
- `status` 过滤。
- `keyword` 过滤。
- `riskFlag=false` 返回普通作品分页。
- `riskFlag=true` 只返回存在治理动作的作品。
- `riskFlag=true` 且当前 tenant 无治理动作时返回空页。
- risk flags、lastGovernanceActionAt、ownerId、wordCount、chapterCount 等摘要字段正确。
- cross tenant 数据不可见。
- JSON 响应不含 block 正文、`contentText`、`content`、`body` 等私有正文字段。
- 请求前后 command、audit、outbox、governance action、work/chapter/block 行数不发生写入变化。
### Admin Get Work
- 存在作品时返回作品元信息、章节摘要、异常摘要、治理历史。
- missing work 返回统一错误。
- cross tenant work 返回不可见或 not found 语义,不泄露其它 tenant 数据。
- 章节摘要包含 order、blockCount、wordCount。
- governance history 按时间或实现定义顺序返回,risk summary 与治理动作一致。
- JSON 响应不含 block 正文、`contentText`、`content`、`body` 等私有正文字段。
- 纯读 no-write。
### Admin List Chapters
- 存在作品时按 `orderNo` 升序返回章节摘要。
- missing work 返回统一错误。
- cross tenant work 返回不可见或 not found 语义。
- blockCount 与真实 block 行数一致。
- wordCount 聚合使用当前 tenant 数据,空章节或 NULL 字数时返回 0。
- risk flags 与治理动作 target scope 语义一致。
- JSON 响应不含章节/Block 正文。
- 纯读 no-write。
### Flyway / schema
执行版不需要新增 migration,但必须证明当前 `_test` 库能从 V1 到当前目标版本 clean migrate,并且 admin read 依赖的表和索引真实存在:
```text
muse_content_work
muse_content_chapter
muse_content_block
muse_content_governance_action
```
如果复用 Content 既有 Flyway IT,执行版必须明确说明复用关系、目标 schema version、XML 防空跑方式和本切片新增断言;不能把历史 XML 当 fresh evidence。
## 风险和取舍
1. admin read 不是 app owner read。
本切片不能要求 `owner_user_id = loginUserId`。正确边界是 admin RBAC、tenant SQL 拦截、API version 和不泄露正文。执行版如果把 app owner guard 套到 admin read 上,会改变产品语义。
2. `requireWork(workId)` 依赖 mapper 和 tenant 拦截器。
Service 内 `requireWork` 当前调用 `workMapper.selectById(workId)`,不是显式 owner 查询。completed evidence 必须在真实 MyBatis + tenant interceptor 环境里证明 cross tenant 不可见,而不是只用 mock service。
3. riskFlag 证据不能扩写成 risk action completed。
`riskFlag` 只证明 governance action 读聚合;不证明 `adminRiskAction` 的 commandId、expectedVersion、幂等、行锁、审计和写入路径。
4. 正文字段泄露是本切片的硬风险。
admin read 合同明确默认不返回私有正文全文。执行版必须用 JSON path / JSON 字符串断言正文相关字段不存在,不能只检查 DTO 类名。
5. 只读 no-write 必须跨表断言。
这 3 个 operation 是 read completed approval。执行版必须对 command、audit、outbox、governance action、work、chapter、block 的写入污染做基线计数或关键字段快照断言。
## 后续执行版要求
后续执行版必须包含:
1. 精确目标 operation 清单:只包括 `adminListWorks`、`adminGetWork`、`adminListChapters`。
2. operation-level approval:不把 `content` 加入 domain allowlist。
3. 实施前 RED:旧 report 下 P1R coverage gate 必须因目标 3 ops 尚未 completed 而失败。
4. HTTP + real PostgreSQL `_test` gate:新增或独立扩展 `P1rContentAdminReadCompletedApprovalIT`。
5. Web/MyBatis/DataSource 测试上下文:必须启用真实 tenant interceptor、真实 mapper、真实 service 和 controller。
6. RBAC / API version / CommonResult 错误响应证据。
7. `adminListWorks`、`adminGetWork`、`adminListChapters` 的 happy、missing、cross tenant、正文不泄露、no-write matrix。
8. focused tests:运行 `ContentAdminServiceTest`、`AdminContentControllerTest` 并做 XML 防空跑。
9. P1R mixed gates:同步所有读取全局 summary、Content 状态或非目标 domain 防回退的 gate。
10. scanner/report 更新策略:只在用户批准后追加 3 个 `content:*` operation-level allowlist。
11. protected diff:OpenAPI、Content main/java、SQL migration 默认不得修改。
12. `.agent` 和 `docs/memorys` 留痕。
13. rollback:撤回 scanner operation keys、coverage report、P1R gate 目标值和新增 `_test`,恢复 3 个 operation 为 `needs_verification`。
## 审批前置条件
进入执行版前需要 fresh review 双 PASS:
- fresh spec/scope review:确认只覆盖 3 个 admin read operation,不夹带 `adminRiskAction`、import/export task、Content 写命令或 Content domain-level completed。
- fresh quality/feasibility/testing review:确认 admin RBAC、tenant 拦截、正文不泄露、riskFlag 聚合、no-write、XML 防空跑和 mixed gate 同步可落地。
执行版双 PASS 后,仍必须由用户明确批准以下事项后才允许实现:
1. 只审批 `content:adminListWorks`、`content:adminGetWork`、`content:adminListChapters`。
2. 继续 operation-level approval,不把 `content` 加入 domain allowlist。
3. 允许按执行版修改 scanner、coverage report、P1R gate tests、新增 HTTP+DB `_test` 和 memory。
4. 允许同步 P1R mixed gate 的 summary / Content / 非目标域防回退断言。
## 本审阅版验收标准
- 候选 operation 和目标值可由当前 report 机械推导。
- 非目标 38 个 Content operation 明确保持 `needs_verification`。
- admin read 与 app owner read、risk action 写命令、import/export task 读模型的边界清晰。
- evidence 标准包含 admin RBAC、tenant 隔离、正文不泄露、riskFlag 聚合、no-write 和 XML 防空跑。
- 未修改 OpenAPI、scanner、coverage report、业务实现、SQL migration 或 P1R gate。