oh-my-muse/docs/agent-specs/2026-06-13-P1RContentAdminRiskActionCompletedApproval审阅版.md

418 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# P1R Content Admin RiskAction Completed Approval 审阅版
日期2026-06-13
## 结论
推荐 Content 下一批只推进 1 个管理后台治理写命令的 operation-level completed approval
```text
content:adminRiskAction
```
不推荐把 Content 剩余 38 个 operation 一次性推进 completed也不推荐把 `content` 加入 domain-level completed allowlist。
`adminRiskAction` 与刚收口的 Admin Read 3 个只读 operation 相邻,但它不是读模型。它是治理写路径,必须证明 `commandId``expectedVersion`、行锁、目标归属、治理事实写入、command/audit envelope、幂等 replay、冲突拒绝、RBAC、API version、tenant 隔离和事务回滚全部闭合后,才允许进入 completed approval。
本审阅版只冻结候选范围、证据标准、风险边界和后续执行版要求。不修改 OpenAPI不修改 scanner不修改 coverage report不修改业务实现不推进任何 operation completed。
```mermaid
flowchart TB
Current["当前 Content<br/>13 completed / 38 needs_verification"] --> Candidate["下一包候选<br/>adminRiskAction"]
Candidate --> Kind{"路径类型"}
Kind -->|"POST 写命令"| Evidence["必须补 completed-grade write evidence"]
Evidence --> E1["RBAC + API version"]
Evidence --> E2["commandId + replay + conflict"]
Evidence --> E3["expectedVersion + row lock"]
Evidence --> E4["targetScope / targetIds 归属"]
Evidence --> E5["governance fact + audit snapshot"]
Evidence --> E6["错误路径 no-write / rollback"]
Evidence --> Review["fresh spec/scope review<br/>fresh quality/testing review"]
Review --> Exec["双 PASS 后写执行版"]
Exec --> Approval{"用户明确批准后才实现"}
Approval -->|"否"| Stay["保持 233/144/89"]
Approval -->|"是"| Target["目标 233/145/88<br/>Content 14 completed / 37 needs_verification"]
```
## 当前事实状态
工作区:
```text
/Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0
```
当前分支状态:
```text
dev/1.0.0...origin/dev/1.0.0
```
当前 HEAD
```text
b0b4b2c test(p1r): 收口 Content Admin Read completed approval 门禁
```
当前 coverage summary
```text
total=233
completed=144
needsVerification=89
incomplete=0
genericPersistence=0
ssePlaceholder=0
```
当前 domain 状态:
```text
account completed=10 needsVerification=23
content completed=13 needsVerification=38
market completed=4 needsVerification=28
meta completed=16 needsVerification=0
```
目标 operation 当前状态:
```text
adminRiskAction dedicated needs_verification requiresCommandId=true POST /admin-api/muse/content/works/{workId}/risk-actions
```
本审阅版推荐的下一批目标值只是后续获批后的执行目标:
```text
total=233
completed=145
needsVerification=88
incomplete=0
genericPersistence=0
ssePlaceholder=0
content total=51
completed=14
needsVerification=37
```
## 推荐候选
| operation key | Method | Path | 推荐原因 | 必补 completed-grade evidence |
|---|---|---|---|---|
| `content:adminRiskAction` | `POST` | `/admin-api/muse/content/works/{workId}/risk-actions` | admin 治理写命令,当前实现已有 command reserve、expectedVersion、行锁、治理事实和 audit envelope但仍缺 HTTP + 真实 DB completed approval 证据 | MockMvc HTTP + 真实 PostgreSQL `_test`,覆盖 RBAC、API version、commandId、expectedVersion、replay、command conflict、revision conflict、targetScope / targetIds 归属、治理事实、audit snapshot、tenant 隔离和 no-write / rollback |
推荐理由:
- 当前 coverage report 已识别 `adminRiskAction.requiresCommandId=true`,说明它天然属于写命令切片,不能和 admin read 混在一起。
- Controller 使用 `@PreAuthorize("@ss.hasPermission('muse:content:risk-action')")`,权限点与 Admin Read 的 `muse:content:query` 不同,必须单独证明。
- Service 使用 `@Transactional(rollbackFor = Exception.class)`,写路径应以事务内证据证明成功写入和失败回滚。
- Service 先 `reserveCommand`,再 `selectByIdForUpdate` 锁定作品行并校验 `expectedVersion`,适合单独验证幂等、冲突和并发边界。
- OpenAPI 已声明 `RiskActionRequest.required=[commandId, action, reason, expectedVersion]`,当前不需要为了本切片修改合同。
## 不纳入本批的 operation
以下 37 个 Content operation 必须继续 `dedicated / needs_verification`
```text
content:adminListExportTasks
content:adminListImportTasks
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
```
排除原因:
- `adminListImportTasks` / `adminListExportTasks` 是任务读模型,证据应覆盖导入导出任务状态、产物和 work 关联,不应夹入治理写命令。
- 创建、更新、删除、重排、拆分、合并等 Content 写命令有各自的 revision、source snapshot、outbox 和结构一致性边界,应独立切片。
- 导入、导出、解析、下载仍缺 FileService、任务产物和真实下载字节闭环 evidence。
- Meta projection、AI planning candidate、style check、suggestion 等能力依赖 Meta / AI / Knowledge 外部 owner closure 和运行时证据。
## 已有实现证据
### OpenAPI 合同
OpenAPI 当前 operation
```text
POST /admin-api/muse/content/works/{workId}/risk-actions
operationId: adminRiskAction
security: adminBearerAuth
```
请求体 `RiskActionRequest`
```text
required: commandId, action, reason, expectedVersion
action enum: warn, restrict, block_content, force_archive, notify_owner
targetScope enum: work, chapter, block
targetIds: chapter 或 block 粒度必填
expectedVersion: 作品当前版本号,用于乐观锁
duration: restrict 动作限制时长
```
响应体 `RiskActionResult`
```text
actionId
status: executed | pending_notification
affectedScope
auditLogId
```
本切片不需要修改 `docs/api-contracts/content/openapi.yaml`
### Controller 入口
`AdminContentController.adminRiskAction`
```text
POST /muse/content/works/{workId}/risk-actions
@PreAuthorize("@ss.hasPermission('muse:content:risk-action')")
requireApiVersion()
contentAdminService.adminRiskAction(getLoginUserId(), workId, reqVO)
```
说明:
- Controller-local mapping 是 `/muse/content/...`;对外 OpenAPI 路径仍以 `/admin-api/muse/...` 为准。
- 执行版必须用当前项目既有 admin MockMvc / Web 测试上下文证明最终 admin API 路径可访问。
- 权限证据必须来自启用 method security 的 HTTP 请求,不能只靠反射检查注解。
### Service 写链路
`ContentAdminServiceImpl.adminRiskAction` 当前链路:
1. 校验 `expectedVersion` 非空。
2. 用请求体和 `workId` 构造 scoped request hash。
3. `ContentCommandService.reserveCommand(commandId, "adminRiskAction", operatorUserId, "work", workId, requestHash)`
4. 如果 command 已存在且 hash / target 匹配,返回 `resultSnapshot` replay。
5. `WorkMapper.selectByIdForUpdate(workId, tenantId)` 锁定作品行。
6. 校验 `work.revision == expectedVersion`
7. 校验 action、targetScope、targetIds。
8. 对 chapter / block target 沿 `targetIds -> chapter/block -> work` 校验从属关系。
9. 插入 `muse_content_governance_action`
10. 构造 `RiskActionResultRespVO`
11. `ContentCommandAuditService.recordSucceededWithAudit(...)` 记录 command/audit/result snapshot。
关键语义:
- `notify_owner` 结果状态为 `pending_notification`
- 其它当前支持 action 结果状态为 `executed`
- `affectedScope` 对 work 粒度为 `work:{workId}`chapter/block 粒度为 `{targetScope}:{targetIds}`
- 成功审计 target 仍绑定业务目标 work不能改写成治理动作 id否则 command replay 会被判为跨目标冲突。
### Schema 证据来源
V9 当前定义:
```text
muse_content_governance_action
tenant_id
work_id
operator_user_id
action
reason
target_scope default work
target_ids jsonb
expected_version not null
status
audit_log_id
command_id not null
uk_muse_content_governance_action_command unique (tenant_id, command_id)
idx_muse_content_governance_action_work
trg_muse_content_governance_action_updated_at
```
执行版不需要新增 migration但必须 fresh 证明 `_test` 库从 V1 到当前版本 clean migrate。当前 Content 已有 V21 event publish outbox因此本切片的真实 schema gate 应至少证明 V1-V21 clean migrate 成功并断言治理动作表、唯一约束、work 索引、JSONB `target_ids``tenant_id` / `expected_version` / `command_id` 关键列、updated_at trigger 真实存在。
## 当前测试证据与缺口
已有 focused tests 可作为辅助证据:
- `AdminContentControllerTest.should_requireRbacAnnotationsForAdminContentApis`
- `AdminContentControllerTest.should_rejectRiskActionMissingReason`
- `AdminContentControllerTest.should_rejectRiskActionMissingExpectedVersionAtValidationLayer`
- `AdminContentControllerTest.should_createRiskActionWithCommonResult`
- `ContentAdminServiceTest.should_rejectRiskAction_when_expectedVersionMismatch`
- `ContentAdminServiceTest.should_rejectRiskAction_when_workMissing`
- `ContentAdminServiceTest.should_createRiskActionWithAudit`
- `ContentAdminServiceTest.should_rejectRiskAction_when_actionUnsupported`
- `ContentAdminServiceTest.should_rejectRiskAction_when_targetScopeUnsupported`
- `ContentAdminServiceTest.should_rejectRiskAction_when_chapterTargetIdsBelongToOtherWork`
- `ContentAdminServiceTest.should_rejectRiskAction_when_blockTargetIdsBelongToOtherWork`
- `ContentAdminServiceTest.should_replayRiskActionCommand`
这些测试不能直接等同 completed。缺口包括
- 没有 HTTP + 真实 PostgreSQL `_test` 的端到端证据。
- 缺 method security 真实拒绝路径证据。
- 缺真实 tenant interceptor 下的 cross tenant 不可见 / no-write 证据。
- 缺 command table、governance action、Content outbox、work/chapter/block 的全表快照或关键字段 no-write / rollback 证据。
- 缺 V1-V21 clean migrate 后 `muse_content_governance_action` / `muse_content_command_log` schema、唯一键、JSONB、trigger、tenant 关键列证据与 XML 防空跑。
- 缺 command replay / command conflict 的真实 DB 证据,尤其同 commandId 不同 action、reason、targetScope、targetIds、workId、expectedVersion。
- 缺并发/行锁语义的可接受代理证据,例如 `FOR UPDATE` SQL 与真实事务 revision stale / conflict 场景。
- 缺 P1R scanner/report/gate 在获批后从 `233/144/89` 推进到 `233/145/88` 的 RED/GREEN 证据。
## 必补证据标准
后续执行版必须至少覆盖以下矩阵。
### HTTP / 权限 / 版本
-`X-API-Version` 的成功请求。
- 缺或不支持 `X-API-Version` 的统一错误响应。
-`muse:content:risk-action` 权限时允许进入 service。
-`muse:content:risk-action` 权限时 403且不写 command、governance action、outbox 或业务表。
- 登录 operator user id 必须进入 `operator_user_id` 和 command/audit 事实。
- command/audit snapshot 必须显式断言 `operationId=adminRiskAction``side=admin``targetType=work``targetId=workId``status=succeeded``reason``requestSummary.action``requestSummary.targetScope``requestSummary.targetIds``requestSummary.expectedVersion``result.actionId/status/affectedScope/auditLogId`
### 成功写路径
- work 粒度 happy path写入 1 条 governance action写入 1 条 command/audit envelope返回 actionId/status/affectedScope/auditLogId。
- chapter 粒度 happy pathtargetIds 必须属于 URL work返回 chapter affected scope。
- block 粒度 happy pathtargetIds 必须沿 block -> chapter -> work 归属到 URL work。
- `notify_owner` 返回 `pending_notification`
- `block_content` / `warn` / `restrict` / `force_archive` 返回 `executed`
- 结果 snapshot 可被 replay 解析,重复同 commandId / 同请求返回同一结果,不重复插入治理事实。
### command / revision / target 负路径
-`commandId` validation 失败,不写任何事实。
-`expectedVersion` validation 失败,不写任何事实。
- `expectedVersion` 与 work revision 不一致,返回 revision conflict不写治理事实和 succeeded audit。
- 同 commandId 不同 action、reason、targetScope、targetIds、workId 或 expectedVersion 返回 command conflict不写第二条治理事实。
- 同 commandId 不同 workId 返回 command conflict 或目标冲突,不泄露目标数据。
- unsupported action 返回统一错误并 no-write。
- unsupported targetScope 返回统一错误并 no-write。
- chapter targetIds 为空、含 null、missing、属于其它 work、属于其它 tenant均拒绝并 no-write。
- block targetIds 为空、含 null、missing、属于其它 work、章节链路不匹配、属于其它 tenant均拒绝并 no-write。
- missing work / cross tenant work 返回不可见或 not found 语义,不写任何事实。
### no-write / rollback
错误路径必须对以下表做全表快照或关键字段快照,不只比较行数:
```text
muse_content_work
muse_content_chapter
muse_content_block
muse_content_governance_action
muse_content_command_log
muse_content_event_publish_outbox
```
说明:
- 成功写路径允许 governance action 与 command/audit 变化。
- 错误路径必须证明上述表没有 INSERT / DELETE / UPDATE 污染。
- 如果测试自身需要 seed 或清理,必须在 no-write baseline 采样之前完成。
### Flyway / schema
执行版必须 fresh 证明:
- `_test` 库只使用测试库名,禁止连接非 `_test`
- 密码只从环境变量读取,禁止通过 JVM system property 或 JDBC query 传入。
- V1-V21 clean migrate 成功。
- `muse_content_governance_action` 表、关键列、JSONB `target_ids`、unique command 约束、work 索引和 updated_at trigger 存在。
- duplicate `(tenant_id, command_id)` 被数据库唯一约束拒绝。
## 风险和取舍
1. `adminRiskAction` 不是 Admin Read 的延伸证据。
Admin Read 已证明治理事实可读它不能证明治理事实写入、command replay、expectedVersion、行锁和 audit snapshot。
2. `selectByIdForUpdate` 是本切片的核心边界。
执行版必须证明 expectedVersion 校验发生在同一事务的锁定作品行之后;否则 completed 证据不足以支撑并发写路径。
3. `targetIds` 归属不能只查目标 id 存在。
chapter 必须属于 URL workblock 必须同时满足 block.workId 与 block.chapterId 对应 chapter.workId 都属于 URL work。
4. command replay 不能只证明不报错。
必须证明 replay 返回原 `resultSnapshot`且没有重复插入治理事实、command/audit 或 outbox。
5. 不应新增 Content audit 表。
当前 Content audit snapshot 保存在 `muse_content_command_log.result_snapshot` / command audit envelope 中。执行版不得为了测试方便新增表或修改 schema。
6. 不把生成 DTO 当成唯一合同证据。
OpenAPI 已声明 `expectedVersion` required服务端 `RiskActionReqVO` 也有 `@NotNull` validation。后续执行版如果引用生成物或客户端 DTO必须说明其新鲜度和同步关系completed 证据应以 OpenAPI、服务端 VO validation、HTTP 请求和真实 DB 结果闭合。
## 后续执行版要求
后续执行版必须包含:
1. 精确目标 operation 清单:只包括 `content:adminRiskAction`
2. operation-level approval不把 `content` 加入 domain allowlist。
3. 实施前 RED旧 report 下 P1R coverage gate 必须因 `adminRiskAction` 尚未 completed 而失败。
4. HTTP + real PostgreSQL `_test` gate新增独立 `P1rContentAdminRiskActionCompletedApprovalIT` 或等价命名。
5. Web/MyBatis/DataSource 测试上下文:必须启用真实 tenant interceptor、真实 mapper、真实 service、真实 controller 和 method security。
6. RBAC / API version / CommonResult 错误响应证据。
7. happy / replay / command conflict / revision conflict / validation / missing / cross tenant / target mismatch / no-write matrix。
8. focused tests运行 `ContentAdminServiceTest``AdminContentControllerTest` 并做 XML 防空跑。
9. P1R mixed gates同步所有读取全局 summary、Content 状态或非目标 domain 防回退的 gate。
10. scanner/report 更新策略:只在用户批准后追加 1 个 `content:adminRiskAction` operation-level allowlist。
11. protected diffOpenAPI、Content main/java、SQL migration 默认不得修改。
12. `.agent``docs/memorys` 留痕。
13. rollback撤回 scanner operation key、coverage report、P1R gate 目标值和新增 `_test`,恢复 `adminRiskAction``needs_verification`
## 审批前置条件
进入执行版前需要 fresh review 双 PASS
- fresh spec/scope review确认只覆盖 `content:adminRiskAction`,不夹带 admin import/export task、Content CRUD 写命令、Content domain-level completed 或其它 domain。
- fresh quality/feasibility/testing review确认 RBAC、tenant 拦截、command replay、expectedVersion、targetScope / targetIds、no-write / rollback、schema gate、XML 防空跑和 mixed gate 同步可落地。
执行版双 PASS 后,仍必须由用户明确批准以下事项后才允许实现:
1. 只审批 `content:adminRiskAction`
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 机械推导。
- 非目标 37 个 Content operation 明确保持 `needs_verification`
- `adminRiskAction` 与 Admin Read、admin import/export task、Content CRUD 写命令的边界清晰。
- evidence 标准包含 RBAC、tenant 隔离、commandId、expectedVersion、行锁、target 归属、governance action、audit snapshot、replay、conflict、no-write / rollback 和 XML 防空跑。
- 未修改 OpenAPI、scanner、coverage report、业务实现、SQL migration 或 P1R gate。