oh-my-muse/docs/agent-specs/2026-06-11-P1RAccountCompletedApproval审阅版.md
zizi f18116a1f5 test(p1r): 收口 Account 第一批 completed approval 门禁
Account first-batch approval promotes only the 10 verified profile, entitlement, balance snapshot, and quota adjustment operations to completed while keeping the rest of Account in needs_verification.
2026-06-11 13:47:13 +08:00

411 lines
20 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 Account Completed Approval 审阅版
日期2026-06-11
## 结论
不建议把 Account 33 个 operation 一次性整域推进 `completed`
推荐把 Account Completed Approval 拆成 operation-level 或证据切片推进:先审批 Account 本域已经形成闭环的读写与审计切片New-API、FileService/download、call attribution 外部来源、Market purchase/license/publish projection 等跨 owner 链路继续保持 `dedicated / needs_verification`,直到有真实 runtime 或明确验收替代边界。
本审阅版只冻结 Account completed approval 的范围判断、证据缺口、推荐审批粒度和后续执行版要求。不修改 OpenAPI不修改 scanner不修改 coverage report不修改业务实现也不把 Account 或其它 domain 推进 `completed`
```mermaid
flowchart TB
Start["当前 coverage<br/>Account 33 dedicated / needs_verification"] --> Review["Account completed approval 审阅版<br/>冻结证据标准"]
Review --> Split{"是否整域 33/33 completed?"}
Split -->|否,推荐| OpLevel["按证据切片 operation-level approval"]
Split -->|是,不推荐| DomainLevel["domain-level approval<br/>需 New-API/FileService/Market/Attribution 全闭环"]
OpLevel --> Exec["执行版<br/>列出可审批 operation 与保留 needs_verification operation"]
Exec --> FreshReview["fresh spec/scope review<br/>fresh quality/feasibility review"]
FreshReview --> UserApproval{"用户明确批准<br/>Account 状态推进?"}
UserApproval -->|否| Stay["保持 Account 33 needs_verification"]
UserApproval -->|是| Change["最小修改 scanner/report/gates<br/>运行 focused + P1R + _test + XML 防空跑"]
```
## 当前事实状态
工作区:
```text
/Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0
```
当前分支与远端同步HEAD 为:
```text
df26bd9 test(p1r): 收口 Meta remaining 5 completed approval 门禁
```
当前 coverage summary
```text
total=233
completed=117
needsVerification=116
incomplete=0
genericPersistence=0
ssePlaceholder=0
```
当前按 domain 聚合:
```text
account total=33 completed=0 needsVerification=33
ai total=41 completed=41 needsVerification=0
content total=51 completed=0 needsVerification=51
events total=1 completed=1 needsVerification=0
knowledge total=59 completed=59 needsVerification=0
market total=32 completed=0 needsVerification=32
meta total=16 completed=16 needsVerification=0
```
Account 33 个 operation 当前全部为 `dedicated / needs_verification`
| operationId | Method | Path | 当前状态 |
|---|---|---|---|
| `adminCreateCallAttributionJob` | `POST` | `/admin-api/muse/account/call-attribution-jobs` | `dedicated / needs_verification` |
| `adminGetCallAttributionJob` | `GET` | `/admin-api/muse/account/call-attribution-jobs/{jobId}` | `dedicated / needs_verification` |
| `adminGetIntegrationCallByCorrelation` | `GET` | `/admin-api/muse/account/integration-calls/by-correlation/{correlationId}` | `dedicated / needs_verification` |
| `adminListNewApiBindings` | `GET` | `/admin-api/muse/account/new-api-bindings` | `dedicated / needs_verification` |
| `adminListPurchaseRecords` | `GET` | `/admin-api/muse/account/purchase-records` | `dedicated / needs_verification` |
| `adminListUsageRecords` | `GET` | `/admin-api/muse/account/usage-records` | `dedicated / needs_verification` |
| `adminListAccountUsers` | `GET` | `/admin-api/muse/account/users` | `dedicated / needs_verification` |
| `adminGetBalanceSnapshots` | `GET` | `/admin-api/muse/account/users/{userId}/balance-snapshots` | `dedicated / needs_verification` |
| `adminGetUserEntitlements` | `GET` | `/admin-api/muse/account/users/{userId}/entitlements` | `dedicated / needs_verification` |
| `adminCreateNewApiBinding` | `POST` | `/admin-api/muse/account/users/{userId}/new-api-binding` | `dedicated / needs_verification` |
| `adminListQuotaAdjustments` | `GET` | `/admin-api/muse/account/users/{userId}/quota-adjustments` | `dedicated / needs_verification` |
| `adminCreateQuotaAdjustment` | `POST` | `/admin-api/muse/account/users/{userId}/quota-adjustments` | `dedicated / needs_verification` |
| `adminCreateQuotaRequest` | `POST` | `/admin-api/muse/account/users/{userId}/quota-requests` | `dedicated / needs_verification` |
| `getAppBalanceSnapshots` | `GET` | `/app-api/muse/account/balance-snapshots` | `dedicated / needs_verification` |
| `appDownloadExport` | `GET` | `/app-api/muse/account/downloads/{credentialId}` | `dedicated / needs_verification` |
| `getAppEntitlements` | `GET` | `/app-api/muse/account/entitlements` | `dedicated / needs_verification` |
| `appCreateExportTask` | `POST` | `/app-api/muse/account/export-tasks` | `dedicated / needs_verification` |
| `appGetExportTask` | `GET` | `/app-api/muse/account/export-tasks/{taskId}` | `dedicated / needs_verification` |
| `appGetIntegrationCallByCorrelation` | `GET` | `/app-api/muse/account/integration-calls/by-correlation/{correlationId}` | `dedicated / needs_verification` |
| `appListLicenses` | `GET` | `/app-api/muse/account/licenses` | `dedicated / needs_verification` |
| `getAppNewApiBinding` | `GET` | `/app-api/muse/account/new-api-binding` | `dedicated / needs_verification` |
| `appRecheckNewApiBinding` | `POST` | `/app-api/muse/account/new-api-binding/recheck` | `dedicated / needs_verification` |
| `appListPublishRecords` | `GET` | `/app-api/muse/account/publish-records` | `dedicated / needs_verification` |
| `appListPurchases` | `GET` | `/app-api/muse/account/purchases` | `dedicated / needs_verification` |
| `appCreateQuotaRequest` | `POST` | `/app-api/muse/account/quota-requests` | `dedicated / needs_verification` |
| `appGetQuotaRequest` | `GET` | `/app-api/muse/account/quota-requests/{requestId}` | `dedicated / needs_verification` |
| `appListSecurityEvents` | `GET` | `/app-api/muse/account/security-events` | `dedicated / needs_verification` |
| `appGetSecurityEvent` | `GET` | `/app-api/muse/account/security-events/{eventId}` | `dedicated / needs_verification` |
| `appAcknowledgeSecurityEvent` | `POST` | `/app-api/muse/account/security-events/{eventId}/acknowledge` | `dedicated / needs_verification` |
| `getAppUsage` | `GET` | `/app-api/muse/account/usage` | `dedicated / needs_verification` |
| `getCurrentUser` | `GET` | `/app-api/muse/me` | `dedicated / needs_verification` |
| `getProfile` | `GET` | `/app-api/muse/profile` | `dedicated / needs_verification` |
| `updateProfile` | `PATCH` | `/app-api/muse/profile` | `dedicated / needs_verification` |
## 已验证实现证据
### Account owner 与入口
Account owner 当前位于 `muse-module-member` 的 Account 子域,没有独立 `muse-module-account`
现有 dedicated Controller 覆盖 Account 33 个 operation
- `AdminAccountNewApiController`
- `AdminAccountUserController`
- `AdminAccountUsageController`
- `AdminAccountPurchaseController`
- `AppAccountNewApiController`
- `AppAccountEntitlementController`
- `AppAccountMarketRecordController`
- `AppAccountExportController`
- `AppAccountSecurityController`
- `AppAccountProfileController`
这些 Controller 均通过 `AccountApiVersionGuard.requireVersion(...)` 校验 `X-API-Version`,并调用 Account 子域 Service不再走旧 `MuseContractPersistenceService` 兜底。
管理端入口使用 `@PreAuthorize` 绑定 `muse:account:*` 权限App 端入口使用 `getLoginUserId()` 作为当前 owner。
### Account 本域服务与持久化
Account 已有本域 Service / Guard / DAL
- `AccountProfileServiceImpl`
- `AccountEntitlementServiceImpl`
- `AccountQuotaServiceImpl`
- `AccountUsageServiceImpl`
- `AccountNewApiBindingServiceImpl`
- `AccountAttributionServiceImpl`
- `AccountMarketRecordServiceImpl`
- `AccountExportServiceImpl`
- `AccountSecurityServiceImpl`
- `AccountCommandServiceImpl`
- `AccountAuditServiceImpl`
- `AccountEventPublishOutboxServiceImpl`
- `AccountEventPublishWorker`
- `AccountApiVersionGuard`
- `AccountOwnerGuard`
- `AccountDownloadGuard`
- `AccountQuotaGuard`
- Account DO / Mapper / Convert 文件
P1R-3 已把 Account 从 `generic_persistence / incomplete` 推进为 `dedicated / needs_verification`,并删除旧 Account 合同兜底 Controller。
### 数据库与迁移证据
V11 Account Real API schema 已存在:
- `muse-cloud/sql/muse/V11__extend_account_real_api_schema.sql`
V11 追加 Account owner 自有事实,包括:
- `muse_account_command`
- `muse_account_audit`
- `muse_account_profile`
- `muse_account_balance_snapshot`
- `muse_account_quota_request`
- `muse_account_integration_call`
- `muse_account_call_attribution_job`
- `muse_account_call_attribution_item`
- `muse_account_export_task`
- `muse_account_download_credential`
- `muse_account_security_event_ack`
- `muse_account_record_projection`
历史留痕记录 V11 已在真实 PostgreSQL test 库通过 Flyway
```text
PostgreSQL 17.10
flyway_success=true
migrations_executed=11
target_schema_version=11
flyway_latest=11:extend account real api schema
v11_tables=12
account_index_count=47
```
V20 Account Events publish outbox 已存在:
- `muse-cloud/sql/muse/V20__extend_account_events_publish_outbox.sql`
历史留痕记录 V20 已在真实 `_test` 库通过 Flyway
```text
flyway_success=true
migrations_executed=20
successful_migration_count=20
target_schema_version=20
flyway_latest=20:extend account events publish outbox
v20_table=muse_account_event_publish_outbox
```
这些迁移证据证明 DDL / Flyway 可执行性和 outbox schema 约束,不等同于 Account 33 个 API 全部具备 completed-grade runtime 证据。
### P1R-7e Account quota alert 证据
P1R-7e 已形成 Account quota adjustment terminal fact 到 Events SSE 的 needs-verification evidence
```text
AccountQuotaServiceImpl.adminCreateQuotaAdjustment
-> muse_member_entitlement_audit_log(change_type=quota_adjustment)
-> muse_account_event_publish_outbox
-> AccountEventPublishWorker
-> EventsPublishApi
-> muse_unified_event
-> /app-api/muse/events 对 accountUserId 可见
```
历史验证包括:
- Member focused tests 36/36 pass。
- P1R mixed executable gates 73/73 pass。
- Account focused + P1R mixed XML 合计 109 testsfailures/errors/skipped 均为 0。
- `P1rAccountEventsPublishFlywayMigrationIT` 4/4 pass。
- Dependency tree gate 证明 Member server 依赖 `muse-module-events-api`,不依赖 `muse-module-events-server`
当前 worktree 可见的 Surefire XML 只覆盖部分 Account P1R gate
```text
P1rAccountRealApiGateTest 4/4
P1rAccountRouteOwnershipTest 4/4
P1rAccountEventsPublishMigrationSqlTest 3/3
P1rAccountEventsPublishDependencyTest 2/2
P1rAccountEventsPublishEndToEndTest 4/4
```
`P1rAccountEventsPublishFlywayMigrationIT` 与 Member focused tests 的 XML 是历史留痕证据,当前 worktree 不能直接引用为 fresh Account completed approval 证据。后续执行版必须重新运行并读取 XML不能复用历史 XML 口径。
该证据可支持后续把 `adminCreateQuotaAdjustment` 作为 Account operation-level completed approval 的第一候选,但不能自动覆盖全部 Account 33 个 operation。
## 关键缺口
### 缺口 1New-API runtime 未闭合
`NewApiAccountFacade` 定义了绑定和 recheck 的外部边界;默认 `UnavailableNewApiAccountFacade` 抛出 `ACCOUNT_NEW_API_UNAVAILABLE`,注释明确当前 worktree 没有真实 New-API runtime 配置,不能伪造绑定成功或重验任务。
因此以下 operation 不能仅凭当前 dedicated 实现直接 completed
- `adminListNewApiBindings`
- `adminCreateNewApiBinding`
- `getAppNewApiBinding`
- `appRecheckNewApiBinding`
- `adminCreateQuotaRequest`
- `appCreateQuotaRequest`
- `appGetQuotaRequest`
- `adminGetIntegrationCallByCorrelation`
- `appGetIntegrationCallByCorrelation`
其中读侧 operation 可能有本地投影读取证据,但 create/recheck/request/correlation 相关 completed approval 必须说明真实 New-API runtime、失败关闭、超时、重试、correlation 与 attribution 口径。
### 缺口 2FileService / 导出下载真实交付未闭合
`AccountFileServiceFacade` 默认返回 unavailable注释明确 Account 只定义任务、凭证和下载校验,不接管真实文件生成或存储。
`AccountExportServiceImpl` 已有 fail-closed 行为:
- 高敏导出缺少可信 step-up proof 时拒绝。
- FileService 异常收敛为 unavailable。
- completed 必须有 fileRef、downloadExpiresAt 和 Account HMAC secret。
- 下载凭证消费具备 owner、过期、撤销、consumed、sourceBlocked 原子门禁。
但这仍不能证明真实文件或对象存储交付。因此以下 operation 暂不应 completed
- `appCreateExportTask`
- `appGetExportTask`
- `appDownloadExport`
除非执行版补齐真实 FileService / 对象存储成功路径、失败路径、下载字节、凭证一次性消费和审计证据。
### 缺口 3Call attribution 外部来源未闭合
`AccountAttributionServiceImpl` 的 create 路径只建立 job 队列事实,并明确真实归因执行由后续 job/transition 路径接管。外部归因来源不可用时会形成失败或补偿建议,而不是 completed-grade 归因成功。
因此以下 operation 不能整批 completed
- `adminCreateCallAttributionJob`
- `adminGetCallAttributionJob`
执行版必须证明真实 attribution source 或明确 operation completed 口径只覆盖“创建 queued job + 可查询失败关闭状态”,否则应保持 `needs_verification`
### 缺口 4Market purchase/license/publish projection 依赖跨 owner 一致性
P1R-3 已固定 Account 视角使用 `muse_account_record_projection(record_type=purchase/license/publish)` 作为查询读模型;`muse_market_account_projection` 只是 Market 侧 sync/outbox 状态,不是 Account 查询读模型。
以下 operation 需要 Market 主流程和 Account projection 一致性证据:
- `adminListPurchaseRecords`
- `appListPurchases`
- `appListLicenses`
- `appListPublishRecords`
它们不能用 Market 事件传播或 Account projection 表存在来直接 completed。执行版必须证明 purchase/license/publish 上游 owner 写入、projection 同步、tenant/owner 隔离和 stale projection 风险。
### 缺口 5安全事件与高敏导出源事实不足
`MemberSecurityEventDO` 有读侧、详情、ack 和脱敏转换;但 P1R-7e 审阅已验证,高敏导出生产安全事件路径当前被 `normalizeRequest` fail-closed 阻断,不能作为第一切片 source fact。
以下 operation 若要 completed必须证明安全事件真实生产路径而不是只证明读侧和 ack
- `appListSecurityEvents`
- `appGetSecurityEvent`
- `appAcknowledgeSecurityEvent`
### 缺口 6缺少本轮 fresh Account completed approval gate
当前 `P1rAccountRealApiGateTest` 仍明确禁止 Account operation 标记为 `completed`,并要求 33 个 operation 保持 `dedicated / needs_verification`
当前 scanner 的 completed 白名单没有包含 Account domain 或 Account operation已批准范围仍限于 AI / Knowledge domain以及 Events / Meta 的 operation-level allowlist。未获批准的 Account completed 会被 scanner 拒绝。
后续执行版必须先明确用户批准范围,再把 gate 改成审批后口径:
- 仅允许 approved operation 从 `needs_verification` 变为 `completed`
- 未批准 operation 必须继续 `dedicated / needs_verification`
- Account 不能自动加入 domain-level completed allowlist。
- Market / Content 仍不能被连带推进。
## 推荐审批粒度
### 推荐Account operation-level approval
第一批候选不应超过以下本域闭合较强的 operation
```text
getCurrentUser
getProfile
updateProfile
adminListAccountUsers
adminGetUserEntitlements
getAppEntitlements
adminGetBalanceSnapshots
getAppBalanceSnapshots
getAppUsage
adminListUsageRecords
adminCreateQuotaAdjustment
adminListQuotaAdjustments
```
其中 `adminCreateQuotaAdjustment` 证据最强,因为 P1R-7e 已额外证明 quota adjustment terminal fact 可以进入 Account outbox 并发布到 Events。
但上述候选仍必须由执行版逐项验证 Controller、Service、DAL、权限、owner/tenant 隔离、幂等、审计、错误路径、XML 防空跑和真实 `_test` 证据。审阅版不直接批准这些 operation completed。
### 不推荐Account domain-level approval
除非执行版能一次性补齐:
- 真实 New-API binding / recheck / quota request runtime。
- 真实 FileService / 对象存储导出下载。
- 真实 call attribution source 或明确可验收替代口径。
- Market purchase/license/publish 到 Account projection 的端到端一致性。
- security event 生产路径和 ack 的 owner/tenant 证据。
否则 Account 33/33 domain-level completed 会把外部闭环缺口包装成已完成。
## 非目标
- 不修改 7 个 OpenAPI
- `docs/api-contracts/account/openapi.yaml`
- `docs/api-contracts/ai/openapi.yaml`
- `docs/api-contracts/content/openapi.yaml`
- `docs/api-contracts/events/openapi.yaml`
- `docs/api-contracts/knowledge/openapi.yaml`
- `docs/api-contracts/market/openapi.yaml`
- `docs/api-contracts/meta/openapi.yaml`
- 不修改 `muse-cloud/scripts/p1r-audit-api-coverage.py`
- 不修改 `docs/superpowers/reports/p1r-api-coverage.json`
- 不修改 `docs/superpowers/reports/p1r-api-coverage.md`
- 不修改 Account 业务实现。
- 不把 Account 33 个 operation 推进 `completed`
- 不把 Account 加入 domain-level completed allowlist。
- 不推进 Market / Content / 总 P1R completed。
- 不把 P1R-7e quota alert source owner evidence 当作 Account 整域 completed 证据。
## 后续执行版必须包含
1. Account 33 operation 的完整清单、当前状态和目标审批状态。
2. 第一批候选 operation 的逐项 evidence mapController、Service、DAL、权限、版本头、owner/tenant 隔离、审计、幂等、失败路径。
3. 明确哪些 operation 继续 `needs_verification`,以及原因。
4. scanner approval 模型:只允许 operation-level allowlist不允许 Account domain-level allowlist除非执行版证明 33/33 全闭环。
5. `P1rAccountRealApiGateTest` 从禁止 completed 到审批后 partial completed gate 的修改策略。
6. `P1rApiCoverageReportTest` summary 期望变更策略,必须只提升用户批准的 Account operation 数。
7. Account focused tests 的 required class 清单与最低 XML tests 数;执行版必须 fresh rerun `P1rAccountEventsPublishFlywayMigrationIT` 与 Member focused tests不能只引用历史留痕。
8. P1R mixed gates包含 Account gate、coverage report gate以及用于证明非目标 Market / Content 不被推进的 gate。
9. 真实 PostgreSQL `_test`:至少覆盖 V1-V20 clean migrate如新增 Account completed approval Flyway IT应验证 V11/V20 表、索引、约束、trigger、非法 insert 拒绝。
10. 外部 runtime 验收New-API / FileService / Market projection / attribution source 对应 operation 若不具备真实验收,必须保持 `needs_verification`
11. protected diff gate7 个 OpenAPI 在批准前后都必须保持空 diff。
12. allowed-diff gate覆盖 unstaged、staged、untracked并使用 `git -c core.quotePath=false`
13. rollback 策略:撤回 scanner allowlist、coverage report、gate test 和新增 memory恢复目标 operation 为 `dedicated / needs_verification`
## 验收标准
本审阅版可以视为完成的条件:
1. 文件写入 `docs/agent-specs/2026-06-11-P1RAccountCompletedApproval审阅版.md`
2. `.agent` 记录 Account completed approval 审阅版状态。
3. `git diff --check` 通过。
4. OpenAPI、scanner、coverage report 无 diff。
5. 文档只定义审阅路线,不进入执行版或实现。
6. fresh spec/scope review PASS。
7. fresh quality/feasibility review PASS。
## 待确认项
1. 是否确认 Account 第一轮不做 domain-level 33/33 completed approval。
2. 是否确认优先走 operation-level approval并从本域闭合较强的 profile / entitlement / usage / quota adjustment 切片开始。
3. 是否确认 New-API、FileService/download、call attribution external source、Market projection、安全事件生产路径在没有真实 runtime 证据前继续保持 `needs_verification`
4. 是否确认审阅版 fresh 双 review PASS 后,再写 Account completed approval 执行版。