42 KiB
P1R Content Completed Approval 执行版
For agentic workers: REQUIRED SUB-SKILL: Use
superpowers:subagent-driven-developmentto implement this plan task-by-task after the explicit approval gate. Steps use checkbox syntax for tracking.
日期:2026-06-12
结论
本执行版推荐第一轮只做 Content operation-level completed approval,不做 Content domain-level 51/51 completed。
第一轮精确审批 8 个用户端核心作品 / 章节 / Block / 来源归因 operation:
content:listWorks
content:getWork
content:listChapters
content:getChapter
content:listBlocks
content:getBlock
content:saveBlock
content:getBlockSourceAttribution
审批后目标 coverage summary 为:
total=233
completed=139
needsVerification=94
incomplete=0
genericPersistence=0
ssePlaceholder=0
Content 域目标状态为:
content total=51
completed=8
needsVerification=43
本执行版只定义实现前置批准项、允许变更范围、TDD 顺序、验证命令、XML 防空跑和回滚策略。当前不得直接实现,不得修改 OpenAPI、scanner、coverage report、业务实现或 gate test。
flowchart TB
Current["当前 Content<br/>51 dedicated / needs_verification"] --> Exec["执行版<br/>锁定第一批 8 个 operation"]
Exec --> Review["fresh execution spec/scope review<br/>fresh execution quality/feasibility review"]
Review --> Approval{"用户明确批准<br/>8 ops / operation-level / allowed diff / legacy gates"}
Approval -->|否| Stay["保持当前 coverage<br/>233/131/102"]
Approval -->|是| Red["TDD RED<br/>先改 Content/Coverage/legacy gates<br/>旧 report 必须失败"]
Red --> Green["TDD GREEN<br/>scanner operation allowlist + regenerate report"]
Green --> Runtime["Content HTTP+DB _test<br/>V21 Flyway + source/event gates"]
Runtime --> Verify["focused + P1R mixed + XML 防空跑<br/>allowed/protected diff"]
Verify --> FreshReview["fresh implementation review"]
当前事实
正确 worktree:
/Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0
当前 HEAD:
0032774 test(p1r): 收口 Market 第一批 completed approval 门禁
当前 coverage summary:
233 131 102 0 0 0
当前 Content 事实:
- Content 51 个 operation 全部为
dedicated / needs_verification。 APPROVED_COMPLETED_DOMAINS当前只包含ai、knowledge。APPROVED_COMPLETED_OPERATIONS当前包含events:streamEvents、Meta 16 个 operation、Account 第一批 10 个 operation、Market 第一批 4 个 operation。P1rContentRealApiGateTest当前明确禁止 Content operation 标记为completed。P1rApiCoverageReportTest当前断言 summarycompleted=131,并断言 Content 51 个 operation 继续needs_verification。P1rEventsRealApiGateTest、P1rAiRealApiGateTest、P1rKnowledgeRealApiGateTest、P1rMarketRealApiGateTest、P1rAccountRealApiGateTest、P1rMetaRealApiGateTest读取全局 summary 或非目标域状态;实现前必须把这些 mixed gate 同步列入单独批准项。- P1R-7f 已证明
saveBlock -> source attribution active -> Content outbox -> Events -> SSE owner visible的needs_verificationevidence,但该 evidence 不等同于saveBlockAPI operation completed。
执行边界
必须先获用户明确批准
实现前必须同时获得以下 4 项批准:
- 批准第一轮 Content completed operation 精确清单为本执行版列出的 8 个 operation。
- 批准只走 operation-level approval,不把
content加入 domain-level completed allowlist。 - 批准按本执行版修改 scanner、coverage report、Content/Coverage gate、必要 legacy mixed gate、Content HTTP+DB
_testIT、ContentEventsPublish gate 安全边界、memory 和.agent。 - 批准同步 6 个 mixed gate 文件的 summary / Content / 非目标域状态防回退断言:
muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rEventsRealApiGateTest.javamuse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rAiRealApiGateTest.javamuse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rKnowledgeRealApiGateTest.javamuse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rMarketRealApiGateTest.javamuse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rAccountRealApiGateTest.javamuse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rMetaRealApiGateTest.java
未获 4 项批准前,不得实施本执行版。
本轮允许变更
获批后只允许修改以下路径:
muse-cloud/scripts/p1r-audit-api-coverage.pydocs/superpowers/reports/p1r-api-coverage.jsondocs/superpowers/reports/p1r-api-coverage.mdmuse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rApiCoverageReportTest.javamuse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rContentRealApiGateTest.javamuse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rEventsRealApiGateTest.javamuse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rAiRealApiGateTest.javamuse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rKnowledgeRealApiGateTest.javamuse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rMarketRealApiGateTest.javamuse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rAccountRealApiGateTest.javamuse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rMetaRealApiGateTest.javamuse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rContentCoreCompletedApprovalIT.java,新增 Content 8 个 operation 的 MockMvc HTTP + 真实 PostgreSQL_test证据。muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rContentEventsPublishFlywayMigrationIT.java,仅限保存/恢复p1r.flyway.url/usersystem property 与组合顺序验证所需的安全边界增强;不得弱化 V21 schema 断言。muse-cloud/muse-module-content/muse-module-content-server/src/test/java/cn/iocoder/muse/module/content/application/ContentAppServiceTest.javamuse-cloud/muse-module-content/muse-module-content-server/src/test/java/cn/iocoder/muse/module/content/application/ContentSourceServiceTest.javamuse-cloud/muse-module-content/muse-module-content-server/src/test/java/cn/iocoder/muse/module/content/application/ContentEventPublishOutboxServiceTest.javamuse-cloud/muse-module-content/muse-module-content-server/src/test/java/cn/iocoder/muse/module/content/application/ContentEventPublishWorkerTest.javamuse-cloud/muse-module-content/muse-module-content-server/src/test/java/cn/iocoder/muse/module/content/controller/app/AppContentControllerTest.javamuse-cloud/muse-module-content/muse-module-content-server/src/test/java/cn/iocoder/muse/module/content/controller/app/AppContentSourceControllerTest.javadocs/agent-specs/.agentdocs/agent-specs/2026-06-11-P1RContentCompletedApproval审阅版.mddocs/agent-specs/2026-06-12-P1RContentCompletedApproval执行版.mddocs/memorys/2026-06-12-P1RContent状态推进.md
如 implementation 发现必须修改 Content 业务实现、OpenAPI、SQL migration、AI/Knowledge/Meta/FileService owner 实现、非批准 gate 或其它文件,必须停下说明原因并重新取得用户批准。
本轮禁止变更
- 不修改 7 个 OpenAPI。
- 不修改 Content 业务实现来掩盖 coverage 缺口。
- 不新增或修改 SQL migration。
- 不新增或修改 Content domain-level completed allowlist。
- 不推进 create/update/delete/structure edit operation。
- 不推进 import/export/parse/FileService operation。
- 不推进 Meta projection / dynamic fields operation。
- 不推进 AI planning candidate / style check / suggestion merge operation。
- 不推进 admin governance / admin read operation。
- 不推进 planning section operation。
- 不推进 Account remaining 23、Market remaining 28 或总 P1R completed。
第一轮审批清单
| operation key | Method | Path | 目标状态 | 完成证据边界 |
|---|---|---|---|---|
content:listWorks |
GET |
/app-api/muse/works |
dedicated / completed |
App 当前 owner,真实 DB 分页,有数据页、空页、同 owner 跨 tenant 不可见 |
content:getWork |
GET |
/app-api/muse/works/{workId} |
dedicated / completed |
App 当前 owner,存在、missing、跨 owner、跨 tenant,DTO 字段完整 |
content:listChapters |
GET |
/app-api/muse/works/{workId}/chapters |
dedicated / completed |
work owner guard,章节排序,有章节、空章节、work missing、跨 owner/tenant |
content:getChapter |
GET |
/app-api/muse/works/{workId}/chapters/{chapterId} |
dedicated / completed |
chapter 属于 path work,详情含 blocks,missing、wrong work、跨 owner/tenant |
content:listBlocks |
GET |
/app-api/muse/works/{workId}/chapters/{chapterId}/blocks |
dedicated / completed |
chapter 属于 path work,Block 排序,有数据、空列表、wrong work/chapter、跨 owner/tenant |
content:getBlock |
GET |
/app-api/muse/works/{workId}/blocks/{blockId} |
dedicated / completed |
block 属于 path work,存在、missing、wrong work、跨 owner/tenant |
content:saveBlock |
PUT |
/app-api/muse/works/{workId}/blocks/{blockId} |
dedicated / completed |
commandId、expectedRevision、sourceSnapshot、revision CAS、source attribution、Content outbox、replay、conflict/no-write、wrong work、跨 owner/tenant |
content:getBlockSourceAttribution |
GET |
/app-api/muse/works/{workId}/blocks/{blockId}/source-attribution |
dedicated / completed |
当前 Block revision 来源读模型,有来源、空来源、missing、wrong work、跨 owner/tenant,不泄露 attribution |
说明:本轮使用 MockMvc HTTP 入口 + real mapper/service + PostgreSQL _test 作为执行版要求的 HTTP 入口证据,不声明 socket 级 live servlet container 证据。
保持 needs_verification 的 Content operation
以下 43 个 operation 必须保持 dedicated / needs_verification:
content:adminListExportTasks
content:adminListImportTasks
content:adminListWorks
content:adminGetWork
content:adminListChapters
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:getPlanning
content:listPlanningCandidates
content:createPlanningCandidate
content:getPlanningCandidate
content:confirmPlanningCandidate
content:discardPlanningCandidate
content:createStyleCheck
content:getStyleCheckResult
content:savePlanningItem
保留原因:
- 写命令存在 OpenAPI / coverage
requiresCommandId与服务端 VO 口径不一致风险,不能夹带合同修正。 - 导入、导出、下载、解析确认依赖 FileService、AI、Knowledge owner 闭环。
- Meta projection、dynamic fields 依赖 Meta owner 解释与校验。
- AI planning candidate、style check、suggestion merge 依赖 AI owner runtime / projection / quality facts。
- admin read / governance 需要单独覆盖 RBAC、治理摘要、risk flags 和 admin DTO。
- formal planning section 虽属 Content 本域,但有 schemaVersion、projectionVersion、upsert CAS、command replay,应作为后续独立切片。
证据矩阵
| 证据类型 | 必跑或必查内容 | 目的 |
|---|---|---|
| Content focused tests | ContentAppServiceTest、ContentSourceServiceTest、ContentEventPublishOutboxServiceTest、ContentEventPublishWorkerTest、AppContentControllerTest、AppContentSourceControllerTest |
支撑本域读写、source attribution、outbox、controller contract 与错误码 |
Content HTTP+DB _test |
新增 P1rContentCoreCompletedApprovalIT |
证明 8 个 operation 经 MockMvc HTTP 入口访问真实 PostgreSQL _test 数据,覆盖 shadow-path matrix |
| Content source/event gates | P1rContentEventsPublishMigrationSqlTest、P1rContentEventsPublishDependencyTest、P1rContentEventsPublishEndToEndTest、P1rContentEventsPublishFlywayMigrationIT |
证明 saveBlock 的 source attribution / Content outbox / Events 前置证据仍成立 |
| P1R Content gates | P1rContentRealApiGateTest、P1rApiCoverageReportTest |
证明 only 8 Content operation completed,43 个继续 needs_verification |
| P1R mixed gates | Coverage、Content、Events、AI、Knowledge、Market、Account、Meta gates | 防止非目标 domain 被连带推进,并同步 legacy summary / Content 状态断言 |
Flyway _test |
P1rContentEventsPublishFlywayMigrationIT fresh rerun |
证明 V1-V21 clean migrate、V21 outbox 表/索引/约束/trigger、invalid insert 拒绝 |
| Coverage scanner | python3 muse-cloud/scripts/p1r-audit-api-coverage.py --check |
证明 scanner/report 与 operation-level allowlist 口径一致 |
| XML 防空跑 | 逐个读取 Surefire XML,检查 tests、mtime、failures、errors、skipped | 防止 Maven 未跑目标类或旧 XML 假绿 |
| Protected diff | 7 个 OpenAPI、Content 业务实现、SQL migration 必须无 diff | 证明没有通过改合同、实现或迁移掩盖缺口 |
| Allowed diff | unstaged、staged、untracked 均必须落在允许清单 | 证明没有顺手扩大 scope |
TDD 执行步骤
Task 0:实现前现场确认
- 确认 worktree:
pwd
git -c core.quotePath=false status --short --branch
git log --oneline -5
jq -r '.summary | [.totalOperations,.completedOperations,.needsVerificationOperations,.incompleteOperations,.genericPersistenceOperations,.ssePlaceholderOperations] | @tsv' docs/superpowers/reports/p1r-api-coverage.json
预期:
/Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0
233 131 102 0 0 0
- 确认 Content 51 个 operation 仍全部是
dedicated / needs_verification:
jq -r '.operations[] | select(.domain=="content") | [.operationId,.implementationStatus,.completionStatus,.requiresCommandId] | @tsv' docs/superpowers/reports/p1r-api-coverage.json
- 确认实施前只有文档 diff,没有 OpenAPI、scanner、coverage report、业务实现、SQL migration、P1R gate test diff:
git -c core.quotePath=false status --short --branch
git -c core.quotePath=false diff -- docs/api-contracts
git -c core.quotePath=false diff -- muse-cloud/scripts/p1r-audit-api-coverage.py docs/superpowers/reports
git -c core.quotePath=false diff -- muse-cloud/muse-module-content/muse-module-content-server/src/main/java muse-cloud/sql/muse
git -c core.quotePath=false diff -- muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api
XML 防空跑通用规则
除 TDD RED 失败验证外,所有 Maven test 验证命令都必须执行以下规则,不能只读取历史 Surefire XML:
- 命令前记录
export RUN_START_EPOCH=$(date +%s)。 - 命令前删除本任务要求检查的
target/surefire-reports/TEST-*.xml。 - 命令后逐个确认 XML 存在、
mtime >= RUN_START_EPOCH、tests不低于本执行版最低值、failures=0、errors=0、skipped=0。 - 任一 XML 缺失、mtime 早于运行开始时间、tests 低于最低值或存在失败/跳过,都必须视为验证失败。
TDD RED 失败验证必须同样删除目标 XML 并记录 RUN_START_EPOCH,但 RED 的预期是 Maven 失败;此时只校验失败发生在本次运行窗口内,并人工确认失败点来自旧 report mismatch,不要求 failures=0。
推荐校验脚本:
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 = {
"muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rApiCoverageReportTest.xml": 6,
}
failed = False
for path_text, min_tests in checks.items():
path = Path(path_text)
if not path.exists():
print(f"MISSING_XML {path}")
failed = True
continue
if int(path.stat().st_mtime) < run_start:
print(f"STALE_XML {path}")
failed = True
continue
root = ET.parse(path).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 期望
获批后先修改:
P1rApiCoverageReportTest.javaP1rContentRealApiGateTest.java- 必要的 6 个 mixed gate:
P1rEventsRealApiGateTest.javaP1rAiRealApiGateTest.javaP1rKnowledgeRealApiGateTest.javaP1rMarketRealApiGateTest.javaP1rAccountRealApiGateTest.javaP1rMetaRealApiGateTest.java
RED 期望:
- summary 期望
completed=139、needsVerification=94,但旧 report 仍是131/102,必须失败。 - Content 8 个 approved operation 期望
completed,但旧 report 仍是needs_verification,必须失败。 - Content 43 个未批准 operation 继续期望
needs_verification,其中必须包含createWork、updateWork、createChapter、mergeBlockSuggestion、exportWork、getPlanning、adminRiskAction。 - Account 仍为
10 completed / 23 needs_verification,Market 仍为4 completed / 28 needs_verification,Meta 仍为16 completed / 0 needs_verification,AI/Knowledge/Events 不回退。
运行:
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 \
-Dsurefire.failIfNoSpecifiedTests=false
预期:至少一个失败点来自旧 report 的 131/102 或 Content 8 个 operation 尚未 completed。若直接通过,必须停下排查假绿。
Task 2:TDD GREEN,最小 scanner/report 状态推进
只修改 muse-cloud/scripts/p1r-audit-api-coverage.py:
- 不修改
APPROVED_COMPLETED_DOMAINS。 - 只向
APPROVED_COMPLETED_OPERATIONS追加 8 个content:*operation key。 - 保持 completed 必须仍是
dedicated的校验。
生成 report:
python3 muse-cloud/scripts/p1r-audit-api-coverage.py --check
预期 summary:
total=233
completed=139
needsVerification=94
incomplete=0
genericPersistence=0
ssePlaceholder=0
预期 Content:
completed=8
needsVerification=43
预期 scanner 仍不包含 content domain-level allowlist:
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:listWorks", "content:getWork", "content:listChapters", "content:getChapter",
"content:listBlocks", "content:getBlock", "content:saveBlock", "content:getBlockSourceAttribution",
]:
assert key in source
print("content_operation_level_allowlist=PASS")
PY
Task 3:Content focused verification
运行 Content 本域 focused tests:
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.ContentAppServiceTest.xml \
muse-module-content/muse-module-content-server/target/surefire-reports/TEST-cn.iocoder.muse.module.content.application.ContentSourceServiceTest.xml \
muse-module-content/muse-module-content-server/target/surefire-reports/TEST-cn.iocoder.muse.module.content.application.ContentEventPublishOutboxServiceTest.xml \
muse-module-content/muse-module-content-server/target/surefire-reports/TEST-cn.iocoder.muse.module.content.application.ContentEventPublishWorkerTest.xml \
muse-module-content/muse-module-content-server/target/surefire-reports/TEST-cn.iocoder.muse.module.content.controller.app.AppContentControllerTest.xml \
muse-module-content/muse-module-content-server/target/surefire-reports/TEST-cn.iocoder.muse.module.content.controller.app.AppContentSourceControllerTest.xml \
muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rContentEventsPublishMigrationSqlTest.xml \
muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rContentEventsPublishDependencyTest.xml \
muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rContentEventsPublishEndToEndTest.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.P1rApiCoverageReportTest.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,muse-server -am \
-Dtest=ContentAppServiceTest,ContentSourceServiceTest,ContentEventPublishOutboxServiceTest,ContentEventPublishWorkerTest,AppContentControllerTest,AppContentSourceControllerTest,P1rContentEventsPublishMigrationSqlTest,P1rContentEventsPublishDependencyTest,P1rContentEventsPublishEndToEndTest,P1rContentRealApiGateTest,P1rApiCoverageReportTest \
-Dsurefire.failIfNoSpecifiedTests=false
必须读取以下 XML 并检查 mtime >= RUN_START_EPOCH、failures=0、errors=0、skipped=0:
| Test class | 最低 tests |
|---|---|
ContentAppServiceTest |
13 |
ContentSourceServiceTest |
23 |
ContentEventPublishOutboxServiceTest |
6 |
ContentEventPublishWorkerTest |
10 |
AppContentControllerTest |
5 |
AppContentSourceControllerTest |
5 |
P1rContentEventsPublishMigrationSqlTest |
3 |
P1rContentEventsPublishDependencyTest |
2 |
P1rContentEventsPublishEndToEndTest |
5 |
P1rContentRealApiGateTest |
5 |
P1rApiCoverageReportTest |
6 |
如实现修改测试数量,XML 检查的最低 tests 可高于上表,但不能低于上表。
Task 4:Content HTTP + 真实 PostgreSQL _test completed gate
新增 P1rContentCoreCompletedApprovalIT,使用独立 _test 数据库和真实 mapper/service 数据,不能使用生产库或非 _test 库:
source ~/.config/muse-repo/infra.env
export P1R_FLYWAY_PASSWORD="$MUSE_POSTGRES_PASSWORD"
export P1R_CONTENT_COMPLETED_APPROVAL_TEST_DB=muse_p1r_content_core_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_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_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.P1rContentCoreCompletedApprovalIT.xml
JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" \
mvn -o test -pl muse-server -am \
-Dtest=P1rContentCoreCompletedApprovalIT \
-Dflyway.postgresql.transactional.lock=false \
-Dp1r.flyway.locations=filesystem:sql/muse \
-Dp1r.flyway.url="jdbc:postgresql://$MUSE_POSTGRES_HOST:$MUSE_POSTGRES_PORT/$P1R_CONTENT_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
该 IT 必须至少覆盖以下 12 个测试,XML 最低 tests 为 12:
| Test class | 最低 tests |
|---|---|
P1rContentCoreCompletedApprovalIT |
12 |
必须证明:
GET /app-api/muse/works覆盖有数据分页、空作品页、同 owner 不同 tenant 不可见。GET /app-api/muse/works/{workId}覆盖存在、ID 不存在、跨 owner、跨 tenant。GET /app-api/muse/works/{workId}/chapters覆盖有章节、空章节、work missing、跨 owner、跨 tenant。GET /app-api/muse/works/{workId}/chapters/{chapterId}覆盖存在并返回 blocks、chapter missing、chapter 属于同 owner 另一个 work、跨 owner、跨 tenant。GET /app-api/muse/works/{workId}/chapters/{chapterId}/blocks覆盖有 Block、空列表、chapter 属于同 owner 另一个 work、跨 owner、跨 tenant。GET /app-api/muse/works/{workId}/blocks/{blockId}覆盖存在、block missing、block 属于同 owner 另一个 work、跨 owner、跨 tenant。PUT /app-api/muse/works/{workId}/blocks/{blockId}覆盖 happy、command replay、revision conflict、缺commandId、缺expectedRevision、缺sourceSnapshot、block 属于同 owner 另一个 work、跨 owner、跨 tenant。GET /app-api/muse/works/{workId}/blocks/{blockId}/source-attribution覆盖当前 revision 有来源、当前 revision 空来源、block missing、block 属于同 owner 另一个 work、跨 owner、跨 tenant,且 path mismatch 不泄露 attribution。- 每个路径必须断言 HTTP 状态、CommonResult 体、关键 DTO 字段和 DB 行数。
- 所有失败路径必须断言 block/source/outbox/command no-write 或事务回滚后的行数不变。
- 成功
saveBlock必须断言muse_content_block_source_attribution(source_status=active)、muse_content_event_publish_outbox、tenant_id、owner、blockRevision、sourceStatus、notificationType 和 commandId/outbox 唯一事实。 - 该 IT 必须在测试启动时校验库名以
_test结尾;密码只能从P1R_CONTENT_COMPLETED_PASSWORD、P1R_FLYWAY_PASSWORD或MUSE_POSTGRES_PASSWORD环境变量读取,不能通过 JVM system property 传入;日志和断言不得输出明文数据库密码。 - 该 IT 如果读取并脱敏
p1r.flyway.url/user,必须保存原始 system property 并在@AfterAll恢复。
Task 5:真实 PostgreSQL _test Flyway gate
fresh rerun 并增强 P1rContentEventsPublishFlywayMigrationIT。使用独立 _test 库,不能使用生产库或非 _test 库:
source ~/.config/muse-repo/infra.env
export P1R_FLYWAY_PASSWORD="$MUSE_POSTGRES_PASSWORD"
export P1R_CONTENT_EVENTS_TEST_DB=muse_p1r_content_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_EVENTS_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_EVENTS_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.P1rContentEventsPublishFlywayMigrationIT.xml
JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" \
mvn -o test -pl muse-server -am \
-Dtest=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_EVENTS_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 |
|---|---|
P1rContentEventsPublishFlywayMigrationIT |
4 |
必须保持或补齐以下 assertion:
- V1-V21 clean migrate。
target_schema_version=21。successful_migration_count=21。- V21
muse_content_event_publish_outbox表、索引、唯一约束、CHECK 约束、trigger 存在。 - invalid outbox insert 被 PostgreSQL 拒绝,至少覆盖非法
event_type、非法notification_type、source_status=deleted、非法publish_status、非法 owner/block/resource/attempt。 - 保存原始
p1r.flyway.url/user,脱敏后在@AfterAll恢复,避免同一 Surefire JVM 中污染其它 Flyway IT。
Task 6:Content completed IT 与 Content events Flyway IT 组合顺序验证
为证明 system property 脱敏不会污染同 JVM 后续测试,必须用同一个 _test 库做普通顺序与反序组合验证。
source ~/.config/muse-repo/infra.env
export P1R_FLYWAY_PASSWORD="$MUSE_POSTGRES_PASSWORD"
export P1R_CONTENT_COMBINED_TEST_DB=muse_p1r_content_combined_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_COMBINED_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_COMBINED_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.P1rContentCoreCompletedApprovalIT.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=P1rContentCoreCompletedApprovalIT,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_COMBINED_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
export RUN_START_EPOCH=$(date +%s)
rm -f \
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.P1rContentEventsPublishFlywayMigrationIT.xml
JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" \
mvn -o test -pl muse-server -am \
-Dtest=P1rContentCoreCompletedApprovalIT,P1rContentEventsPublishFlywayMigrationIT \
-Dsurefire.runOrder=reversealphabetical \
-Dflyway.postgresql.transactional.lock=false \
-Dp1r.flyway.locations=filesystem:sql/muse \
-Dp1r.flyway.url="jdbc:postgresql://$MUSE_POSTGRES_HOST:$MUSE_POSTGRES_PORT/$P1R_CONTENT_COMBINED_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
两次组合验证均必须满足:
| Test class | 最低 tests |
|---|---|
P1rContentCoreCompletedApprovalIT |
12 |
P1rContentEventsPublishFlywayMigrationIT |
4 |
Task 7:P1R mixed gate
运行 mixed gates:
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 \
-Dsurefire.failIfNoSpecifiedTests=false
必须读取以下 XML:
| Test class | 最低 tests |
|---|---|
P1rApiCoverageReportTest |
6 |
P1rContentRealApiGateTest |
5 |
P1rEventsRealApiGateTest |
6 |
P1rAiRealApiGateTest |
7 |
P1rKnowledgeRealApiGateTest |
8 |
P1rMarketRealApiGateTest |
6 |
P1rAccountRealApiGateTest |
4 |
P1rMetaRealApiGateTest |
4 |
每个 XML 均必须 mtime >= RUN_START_EPOCH、failures=0、errors=0、skipped=0。
这些 gate 必须共同证明:
- summary 只从
131/102推进到139/94。 - Content 只从
0/51推进到8/43。 - Account 仍保持
10 completed / 23 needs_verification。 - Market 仍保持
4 completed / 28 needs_verification。 - Meta 仍保持
16 completed / 0 needs_verification。 - AI 41、Knowledge 59、Events 1 仍为 completed,不回退。
Task 8:报告与 diff gate
检查 summary:
jq -r '.summary | [.totalOperations,.completedOperations,.needsVerificationOperations,.incompleteOperations,.genericPersistenceOperations,.ssePlaceholderOperations] | @tsv' docs/superpowers/reports/p1r-api-coverage.json
预期:
233 139 94 0 0 0
检查 Content 8/43:
python3 - <<'PY'
import json
from collections import Counter
from pathlib import Path
approved = {
"listWorks", "getWork", "listChapters", "getChapter",
"listBlocks", "getBlock", "saveBlock", "getBlockSourceAttribution",
}
data = json.loads(Path("docs/superpowers/reports/p1r-api-coverage.json").read_text())
content_ops = [op for op in data["operations"] if op["domain"] == "content"]
counter = Counter(op["completionStatus"] for op in content_ops)
print(counter)
assert counter == Counter({"needs_verification": 43, "completed": 8})
for op in content_ops:
expected = "completed" if op["operationId"] in approved else "needs_verification"
assert op["implementationStatus"] == "dedicated", op["operationId"]
assert op["completionStatus"] == expected, op["operationId"]
print("content_8_43=PASS")
PY
检查 protected diff:
git -c core.quotePath=false diff --name-only -- docs/api-contracts
git -c core.quotePath=false diff --cached --name-only -- docs/api-contracts
git -c core.quotePath=false diff --name-only -- muse-cloud/muse-module-content/muse-module-content-server/src/main/java muse-cloud/sql/muse
git -c core.quotePath=false diff --cached --name-only -- muse-cloud/muse-module-content/muse-module-content-server/src/main/java muse-cloud/sql/muse
输出必须为空。
检查 whitespace:
git diff --check
检查 allowed diff,必须覆盖 unstaged / staged / untracked:
python3 - <<'PY'
import subprocess
import sys
allowed = {
"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/P1rContentCoreCompletedApprovalIT.java",
"muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rContentEventsPublishFlywayMigrationIT.java",
"muse-cloud/muse-module-content/muse-module-content-server/src/test/java/cn/iocoder/muse/module/content/application/ContentAppServiceTest.java",
"muse-cloud/muse-module-content/muse-module-content-server/src/test/java/cn/iocoder/muse/module/content/application/ContentSourceServiceTest.java",
"muse-cloud/muse-module-content/muse-module-content-server/src/test/java/cn/iocoder/muse/module/content/application/ContentEventPublishOutboxServiceTest.java",
"muse-cloud/muse-module-content/muse-module-content-server/src/test/java/cn/iocoder/muse/module/content/application/ContentEventPublishWorkerTest.java",
"muse-cloud/muse-module-content/muse-module-content-server/src/test/java/cn/iocoder/muse/module/content/controller/app/AppContentControllerTest.java",
"muse-cloud/muse-module-content/muse-module-content-server/src/test/java/cn/iocoder/muse/module/content/controller/app/AppContentSourceControllerTest.java",
"docs/agent-specs/.agent",
"docs/agent-specs/2026-06-11-P1RContentCompletedApproval审阅版.md",
"docs/agent-specs/2026-06-12-P1RContentCompletedApproval执行版.md",
"docs/memorys/2026-06-12-P1RContent状态推进.md",
}
commands = [
["git", "-c", "core.quotePath=false", "diff", "--name-only"],
["git", "-c", "core.quotePath=false", "diff", "--cached", "--name-only"],
["git", "-c", "core.quotePath=false", "ls-files", "--others", "--exclude-standard"],
]
actual = set()
for command in commands:
output = subprocess.check_output(command, text=True)
actual.update(line for line in output.splitlines() if line)
unexpected = sorted(actual - allowed)
if unexpected:
print("UNEXPECTED_DIFF")
print("\n".join(unexpected))
sys.exit(1)
print("allowed_diff_gate=PASS")
PY
输出只能包含本执行版允许路径。若出现 OpenAPI、业务实现、SQL migration 或非批准 gate 文件,必须停止。
Task 9:memory 与 .agent
实现通过后新增:
docs/memorys/2026-06-12-P1RContent状态推进.md
内容必须记录:
- 批准的 8 个 Content operation。
- 保持
needs_verification的 43 个 Content operation 及原因。 - scanner/report/gate 修改范围。
- Content HTTP+DB
_test的数据库名、验证命令、XML 计数和 shadow-path matrix 覆盖点。 - ContentEventsPublish gate、V21 Flyway
_test、组合顺序验证的命令和结果。 - focused tests、P1R mixed gates、XML 防空跑、protected diff 和 allowed diff 结果。
- 明确说明不代表 Content 51/51 completed,不代表 Account remaining / Market remaining / 总 P1R completed。
同时更新 docs/agent-specs/.agent,但只能记录事实,不写未验证结论。
Task 10:fresh implementation review
实现、验证和文档留痕后,必须派发两类 fresh reviewer:
- spec/correctness reviewer:检查 8 个 operation 是否严格匹配本执行版,43 个 operation 是否仍 needs_verification,Content domain allowlist 是否未新增。
- quality/data-integrity/testing reviewer:检查 scanner/report/gate、legacy mixed gate 同步、HTTP+DB
_test、XML 防空跑、V21 Flyway_test、system property restore、allowed/protected diff、rollback 是否可靠。
双 PASS 前不得提交、push 或宣称 Content completed approval 已收口。
回滚策略
如实现后需要撤回:
- 从
APPROVED_COMPLETED_OPERATIONS移除 8 个content:*key。 - 重新运行:
python3 muse-cloud/scripts/p1r-audit-api-coverage.py --check
- 恢复 gate 期望:
summary completed=131
summary needsVerification=102
content completed=0
content needsVerification=51
- 删除或修订本轮 memory,保留失败原因。
- 重新运行 Content/P1R focused gates、
git diff --check、protected diff 和 allowed diff。
验收标准
执行版本身可以进入实现前批准点的条件:
- 本文件已写入
docs/agent-specs/2026-06-12-P1RContentCompletedApproval执行版.md。 .agent记录执行版当前状态。git diff --check通过。- OpenAPI、scanner、coverage report、业务实现、SQL migration、P1R gate test 当前无新增 diff。
- fresh execution spec/scope review PASS。
- fresh execution quality/feasibility review PASS。
实现完成条件必须等用户批准后另行满足,不由本执行版写入自动成立。