oh-my-muse/docs/memorys/2026-06-07-P1R7eAccountSourceOwnerPropagation真实链路.md

14 KiB
Raw Blame History

P1R7e Account Source Owner Propagation 真实链路

日期2026-06-07

结论

P1R-7e Account/Member source owner propagation 主体实现、V20 SQL、Member focused tests、P1R Account Events publish gate tests、dependency tree gate 与 protected diff gate 已形成 needs_verification evidence。

当前仍不能写 completed。本轮证据只代表 Account quota adjustment terminal fact -> Account publish outbox -> Account worker -> EventsPublishApi -> muse_unified_event -> /app-api/muse/eventsaccountUserId 可见的链路推进到证据层,不代表 Events / P1R-7 / Account completed。

本轮未修改 OpenAPI、coverage scanner 或真实 coverage 报告。

已验证事实

工作区与保护文件

  • 正确 worktree/Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0
  • 分支:dev/1.0.0
  • 最新 migration 前置检查:当前 V19 后新增 V20未发现既有 V20+。
  • 受保护文件最终 staged / unstaged diff 均为 exit 0
    • docs/api-contracts/account/openapi.yaml
    • docs/api-contracts/market/openapi.yaml
    • docs/api-contracts/ai/openapi.yaml
    • docs/api-contracts/knowledge/openapi.yaml
    • docs/api-contracts/events/openapi.yaml
    • muse-cloud/scripts/p1r-audit-api-coverage.py
    • docs/superpowers/reports/p1r-api-coverage.json
    • docs/superpowers/reports/p1r-api-coverage.md

本轮实现范围

  • Member server 新增直接依赖 muse-module-events-api
  • 新增 Account 本域 publish outbox
    • AccountEventPublishOutboxDO
    • AccountEventPublishOutboxMapper
    • AccountEventPublishOutboxService
    • AccountEventPublishOutboxServiceImpl
    • AccountEventPayloads
    • AccountEventPublishWorker
    • MuseAccountEventsProperties
    • MuseAccountEventsConfiguration
  • AccountQuotaServiceImpl.adminCreateQuotaAdjustment 在每条 muse_member_entitlement_audit_log(change_type=quota_adjustment) insert 后,同事务创建 Account Events publish outbox。
  • command replay 不补历史 outbox。
  • 新增 V20 migrationmuse-cloud/sql/muse/V20__extend_account_events_publish_outbox.sql

合同边界

  • 每条 entitlement audit log 对应一条 outbox不做 command 聚合,不做历史 backfill。
  • Events source tuple
    • sourceOwner=account
    • sourceType=account_quota_adjustment
    • sourceId=auditLogId
    • sourceRevision=__none__
    • eventType=notification
  • notification type 固定为 quota_alert
  • sourceCommandId 优先使用原始 reqVO.getCommandId();历史 fallback 才从 idempotencyKey.lastIndexOf(':') 解析。
  • payload exact allowlist
    • 顶层只允许 type/message/resourceRef/timestamp
    • resourceRef 只允许 resourceType/resourceId
    • message 固定为 额度已调整
    • resourceRef.resourceId 保持 Number/Long 语义,值为 entitlement audit log id。
    • EventsPublishReqDTO.resourceId 仍按 Events DTO 合同使用 String。
  • 禁止发布 requestHash、reason 原文、operatorUserId、before/after snapshot、correlationId、external detail、error stack、credential。
  • timestamp 优先使用 audit log createTime,缺失时回退 outbox createTime
  • worker 默认配置关闭:muse.account.events.publish-worker.enabled=false
  • 终态回写使用 publish_status='running' AND attempt_count=#{claimedAttemptCount} 防止过期 claim 覆盖新终态;终态更新 0 行会记录 stale claim 诊断日志。

验证证据

Member focused tests

执行:

JAVA_HOME=$(/usr/libexec/java_home -v 21) PATH="$JAVA_HOME/bin:$PATH" mvn -pl muse-module-member/muse-module-member-server -Dtest=AccountEventPublishOutboxServiceTest,AccountEventPublishWorkerTest,AccountQuotaServiceTest -Dsurefire.failIfNoSpecifiedTests=false test

结果exit 036 tests passfailures/errors/skipped 均为 0。

Surefire XML

测试类 tests failures errors skipped
AccountQuotaServiceTest 17 0 0 0
AccountEventPublishOutboxServiceTest 8 0 0 0
AccountEventPublishWorkerTest 11 0 0 0

覆盖点:

  • quota adjustment 首次成功路径为每条 entitlement audit log 创建 outbox。
  • command replay 不创建 outbox。
  • 多 resourceType 产生多条不同 outbox。
  • invalid owner / missing audit log id / 非 quota_adjustment 不创建 outbox。
  • payload exact allowlist 与敏感字段负断言。
  • resourceRef.resourceId 是数值型 audit log id。
  • configured maxAttempt 生效。
  • timestamp 使用 audit log createTime,缺失时回退 outbox createTime
  • worker disabled 不 claim。
  • accepted / duplicate accepted -> published。
  • rejected / blocked -> dead_letter。
  • CommonResult error / exception -> retryable 或 retry exhausted dead_letter。
  • invalid owner / payload invalid -> dead_letter 且不调用 EventsPublishApi。
  • terminal update 具备 claim attempt ownership guard。
  • stale terminal update 记录诊断日志。

P1R mixed executable gates

执行:

JAVA_HOME=$(/usr/libexec/java_home -v 21) mvn -o test \
  -pl muse-server -am \
  -Dtest=P1rAccountEventsPublishMigrationSqlTest,P1rAccountEventsPublishDependencyTest,P1rAccountEventsPublishEndToEndTest,P1rAccountRealApiGateTest,P1rAccountRouteOwnershipTest,P1rMarketEventsPublishMigrationSqlTest,P1rMarketEventsPublishDependencyTest,P1rMarketEventsPublishEndToEndTest,P1rKnowledgeEventsPublishMigrationSqlTest,P1rKnowledgeEventsPublishDependencyTest,P1rKnowledgeEventsPublishEndToEndTest,P1rAiEventsPublishMigrationSqlTest,P1rAiEventsPublishDependencyTest,P1rAiEventsPublishEndToEndTest,P1rApiCoverageReportTest,P1rEventsRealApiGateTest,P1rEventsRouteOwnershipTest,P1rAiRealApiGateTest,P1rAiRouteOwnershipTest \
  -Dsurefire.failIfNoSpecifiedTests=false

结果exit 073 tests passfailures/errors/skipped 均为 0。

Surefire XML

测试类 tests failures errors skipped
P1rAccountEventsPublishMigrationSqlTest 3 0 0 0
P1rAccountEventsPublishDependencyTest 2 0 0 0
P1rAccountEventsPublishEndToEndTest 4 0 0 0
P1rAccountRealApiGateTest 4 0 0 0
P1rAccountRouteOwnershipTest 4 0 0 0
P1rMarketEventsPublishMigrationSqlTest 3 0 0 0
P1rMarketEventsPublishDependencyTest 2 0 0 0
P1rMarketEventsPublishEndToEndTest 4 0 0 0
P1rKnowledgeEventsPublishMigrationSqlTest 3 0 0 0
P1rKnowledgeEventsPublishDependencyTest 2 0 0 0
P1rKnowledgeEventsPublishEndToEndTest 5 0 0 0
P1rAiEventsPublishMigrationSqlTest 4 0 0 0
P1rAiEventsPublishDependencyTest 2 0 0 0
P1rAiEventsPublishEndToEndTest 4 0 0 0
P1rApiCoverageReportTest 5 0 0 0
P1rEventsRealApiGateTest 5 0 0 0
P1rEventsRouteOwnershipTest 4 0 0 0
P1rAiRealApiGateTest 6 0 0 0
P1rAiRouteOwnershipTest 7 0 0 0

覆盖点:

  • Member server 直接依赖 muse-module-events-api,不依赖 muse-module-events-server
  • Events server 不反向依赖 AI / Knowledge / Market / Member / Content server。
  • V20 SQL 静态断言覆盖字段、唯一约束、check 约束、索引、trigger、BaseDO/TenantBaseDO 审计列、敏感列和外键禁用。
  • focused E2E 证明 Account worker 调用真实 EventsPublishServiceImpl 后,quota_alert 只对 accountUserId 可见admin operator 不可见,非 owner 不可见。
  • 多条 quota alert 对同一 owner 可见。
  • rejected / dead_letter 后 SSE visible query 为空。
  • stale claim terminal update attempt mismatch 不覆盖当前 running outbox。
  • 同时回归 Account 真实 API gate、Account route ownership gate、AI/Knowledge/Market/Events 既有 P1R gates 与 coverage report gate。

Full reactor build

执行:

JAVA_HOME=$(/usr/libexec/java_home -v 21) mvn -o clean install -DskipTests -Dspring-boot.repackage.skip=true

结果exit 0日志保留在 /tmp/p1r7e-full-reactor-20260608022955.log;机器统计 reactor summary 为 62SUCCESS,包含 BUILD SUCCESSFinished at 2026-06-08T02:30:46+08:00

Surefire XML 计数核对

clean build 后已重新运行 focused tests、P1R mixed executable gates 与 Flyway _test,以保留最终 surefire XML。

结果Account focused + P1R mixed 目标 XML 合计 109 testsfailures=0、errors=0、skipped=0Flyway _test XML 单独保留 4/4failures=0、errors=0、skipped=0。

V20 Flyway _test

准备:

source ~/.config/muse-repo/infra.env
psql "host=$MUSE_POSTGRES_HOST port=$MUSE_POSTGRES_PORT user=$MUSE_POSTGRES_USERNAME dbname=postgres" -c 'CREATE DATABASE muse_p1r7e_account_events_publish_test'

已验证 muse_p1r7e_account_events_publish_test 存在。

执行:

source ~/.config/muse-repo/infra.env
export P1R_FLYWAY_PASSWORD="$MUSE_POSTGRES_PASSWORD"
JAVA_HOME=$(/usr/libexec/java_home -v 21) mvn -o test -pl muse-server -am \
  -Dtest=P1rAccountEventsPublishFlywayMigrationIT \
  -Dflyway.postgresql.transactional.lock=false \
  -Dp1r.flyway.locations=filesystem:sql/muse \
  -Dp1r.flyway.url="jdbc:postgresql://$MUSE_POSTGRES_HOST:$MUSE_POSTGRES_PORT/muse_p1r7e_account_events_publish_test" \
  -Dp1r.flyway.user="$MUSE_POSTGRES_USERNAME" \
  -Djava.net.useSystemProxies=false \
  -DsocksProxyHost= \
  -DsocksProxyPort= \
  -Dhttp.proxyHost= \
  -Dhttp.proxyPort= \
  -Dhttps.proxyHost= \
  -Dhttps.proxyPort= \
  -Dsurefire.failIfNoSpecifiedTests=false

结果exit 0P1rAccountEventsPublishFlywayMigrationIT 4 tests passfailures/errors/skipped 均为 0。

补证据clean build 后已重新运行该 Flyway ITmuse-cloud/muse-server/target/surefire-reports/TEST-cn.iocoder.muse.server.framework.api.P1rAccountEventsPublishFlywayMigrationIT.xml 已保留,机器校验为 tests=4、failures=0、errors=0、skipped=0。

关键输出:

flyway_success=true
flyway_url=jdbc:postgresql://<host>/muse_p1r7e_account_events_publish_test
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
v20_indexes=idx_muse_account_event_publish_outbox_claim,idx_muse_account_event_publish_outbox_owner_status,idx_muse_account_event_publish_outbox_audit_log
v20_triggers=trg_muse_account_event_publish_outbox_update_time

Flyway IT 覆盖:

  • 只允许 _test 数据库。
  • 拒绝 JDBC URL 携带 credential query。
  • V1-V20 clean migrate。
  • V20 表、索引、约束、trigger 存在。
  • event_typenotification_typepublish_statusaccount_user_idaudit_log_id/resource_ref_id 非法插入会被数据库拒绝。

Dependency tree gate

执行:

JAVA_HOME=$(/usr/libexec/java_home -v 21) mvn -o -pl muse-module-member/muse-module-member-server -DskipTests dependency:tree > /tmp/p1r7e-member-server-dependency-tree.txt
JAVA_HOME=$(/usr/libexec/java_home -v 21) mvn -o -pl muse-module-events/muse-module-events-server -DskipTests dependency:tree > /tmp/p1r7e-events-server-dependency-tree.txt

结果:

  • Member server tree 命中 muse-module-events-api
  • Member server tree 未命中 muse-module-events-server
  • Events server tree 对 AI / Knowledge / Market / Member / Content server 无命中输出。
  • 命令输出 dependency_gate=pass

Isolated coverage scanner

执行范围:只在 /tmp/p1r7e-coverage-scan.Ozo9Xm 隔离副本运行 scanner真实 worktree 的 docs/superpowers/reports/* 未被修改。

执行:

tmpdir=$(mktemp -d /tmp/p1r7e-coverage-scan.XXXXXX)
rsync -a --delete --exclude .git --exclude 'muse-cloud/**/target' ./ "$tmpdir"/
cd "$tmpdir"
python3 muse-cloud/scripts/p1r-audit-api-coverage.py --check

结果exit 0。

summary

{
  "totalOperations": 233,
  "completedOperations": 100,
  "needsVerificationOperations": 133,
  "incompleteOperations": 0,
  "genericPersistenceOperations": 0,
  "ssePlaceholderOperations": 0
}

边界核对:

  • Events streamEvents=dedicated / needs_verification
  • Account 33 operations 均为 dedicated / needs_verification
  • 未推进 completed。

Diff gates

执行:

git diff --check
git diff --quiet -- docs/api-contracts/account/openapi.yaml docs/api-contracts/market/openapi.yaml docs/api-contracts/ai/openapi.yaml docs/api-contracts/knowledge/openapi.yaml docs/api-contracts/events/openapi.yaml muse-cloud/scripts/p1r-audit-api-coverage.py docs/superpowers/reports/p1r-api-coverage.json docs/superpowers/reports/p1r-api-coverage.md
git diff --cached --quiet -- docs/api-contracts/account/openapi.yaml docs/api-contracts/market/openapi.yaml docs/api-contracts/ai/openapi.yaml docs/api-contracts/knowledge/openapi.yaml docs/api-contracts/events/openapi.yaml muse-cloud/scripts/p1r-audit-api-coverage.py docs/superpowers/reports/p1r-api-coverage.json docs/superpowers/reports/p1r-api-coverage.md

结果:

  • git diff --check exit 0。
  • protected unstaged diff exit 0。
  • protected staged diff exit 0。
  • protected 文件 diff name-only 为空。

风险与后续

  • 早前 implementer 用 127.0.0.1:5432/muse_p1r7e_events_publish_test 运行 Flyway IT 失败,原因是本地 PostgreSQL 服务不可达;该旧失败已被 controller 使用 ~/.config/muse-repo/infra.envmuse_p1r7e_account_events_publish_test 真实 _test 库的 4/4 PASS 覆盖。
  • 本轮没有修改 OpenAPI、coverage scanner 或真实 coverage report也没有推进 completed。
  • focused E2E 是内存 mapper + 真实 EventsPublishServiceImpl,不是 HTTP/SSE + 真实 DB 全链路controller 后续可补真实 controller/SSE 验证。
  • 最终 fresh implementation review 已双 PASSBanach correctness/spec PASS、Raman quality/data-integrity/testing PASS均无 P0/P1/P2/P3 blocker。
  • 双 PASS 只代表 P1R-7e Account quota adjustment source owner propagation evidence 可以进入提交整理,不代表 Events/P1R-7/Account completed。
  • 当前未 push提交整理仍不得推进 completed。