# P1R7c Knowledge Source Owner Propagation 真实链路 日期:2026-06-06 ## 结论 P1R-7c Knowledge source owner propagation 主体实现、V18 SQL、focused tests、P1R mixed executable gates、V18 Flyway `_test`、reactor build、隔离 coverage scanner 与 P2 增强后 fresh review 已推进到 `needs_verification` 证据层。 当前仍不能写 `completed`。Rawls correctness/spec review 与 Boole data-integrity/testing review 已双 PASS,但该 PASS 只代表 Knowledge source owner terminal event -> Knowledge outbox -> worker -> EventsPublishApi -> `muse_unified_event` -> SSE 可见链路 evidence 推进到 `needs_verification`,不代表 Events / P1R-7 / Knowledge / Market completed。 本轮未修改 OpenAPI、coverage scanner 或真实 coverage 报告。 ## 已验证事实 ### 工作区与保护文件 - 正确 worktree:`/Users/qingse/.config/superpowers/worktrees/oh-my-muse/dev-1.0.0`。 - 分支:`dev/1.0.0`。 - 受保护文件 diff 为空: - `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` ### 本轮实现范围 - Knowledge server 新增直接依赖 `muse-module-events-api`。 - 新增 Knowledge 本域 publish outbox: - `MuseKnowledgeEventPublishOutboxDO` - `MuseKnowledgeEventPublishOutboxMapper` - `MuseKnowledgeEventPublishOutboxService` - `MuseKnowledgeEventPublishOutboxServiceImpl` - `MuseKnowledgeEventPublishWorker` - `MuseKnowledgeEventsProperties` - `MuseKnowledgeEventsConfiguration` - `MuseKnowledgeSourceEventService` 在 canonical `triggerGlobalKBSourceEvent` 链路内创建 per target owner outbox,并将 `ownerFanoutSummary` 写入 projection task summary。 - `MuseKnowledgeSourceBindingProjectionMapper` 新增按 `kbId + lastEventId` fan-out target 查询与 owner audit summary 查询。 - 新增 V18 migration:`muse-cloud/sql/muse/V18__extend_knowledge_events_publish_outbox.sql`。 ### Focused tests 执行: ```bash JAVA_HOME=$(/usr/libexec/java_home -v 21) mvn -o test -pl muse-module-knowledge/muse-module-knowledge-server -Dtest=MuseKnowledgeEventPublishOutboxServiceTest,MuseKnowledgeEventPublishWorkerTest,MuseKnowledgeSourceEventServiceTest -Dsurefire.failIfNoSpecifiedTests=false ``` 结果:exit 0,15 tests pass,failures/errors/skipped 均为 0。 覆盖点: - per distinct target owner 创建 outbox。 - 不同 owner 的 `commandId/outboxId` 不相同。 - `document_deleted` 不写 outbox。 - invalid owner 只进入 audit summary,不进入 outbox。 - worker disabled 不 claim。 - accepted -> published。 - rejected / blocked -> dead_letter。 - API error -> retryable。 - last attempt exception -> dead_letter。 - terminal status update 必须携带本次 claim attempt ownership,避免过期 worker 覆盖新终态。 - terminal status update 返回 0 时必须记录 stale claim 诊断日志,包含 tenantId、targetOwnerUserId、outboxId、sourceEventId、attempt、targetStatus、errorCode。 - source event 集成写入 `ownerFanoutSummary`。 ### P1R mixed executable gates 执行: ```bash JAVA_HOME=$(/usr/libexec/java_home -v 21) mvn -o test -pl muse-server -am -Dtest=P1rKnowledgeEventsPublishMigrationSqlTest,P1rKnowledgeEventsPublishDependencyTest,P1rKnowledgeEventsPublishEndToEndTest,P1rApiCoverageReportTest,P1rEventsRealApiGateTest,P1rEventsRouteOwnershipTest,P1rAiRealApiGateTest,P1rAiRouteOwnershipTest -Dsurefire.failIfNoSpecifiedTests=false ``` 结果:exit 0,37 tests pass,failures/errors/skipped 均为 0。 覆盖点: - V18 SQL 静态 migration gate。 - Knowledge server 依赖 Events API,不依赖 Events server。 - Events server 不反向依赖 AI / Knowledge / Market / Member / Content server。 - Knowledge outbox -> worker -> EventsPublishServiceImpl -> `muse_unified_event` focused E2E。 - target owner 可见,owner 0 / 非 target owner 不可见。 - 同一 source event 不同 owner 不被合并。 - 同一 source event + owner replay 回放同一 event identity。 - stale claim terminal update 因 attempt 不匹配被忽略。 - blocked publish 进入 outbox dead_letter 且不可见。 ### Flyway IT 当前状态 新增: ```text muse-cloud/muse-server/src/test/java/cn/iocoder/muse/server/framework/api/P1rKnowledgeEventsPublishFlywayMigrationIT.java ``` 安全方法执行: ```bash JAVA_HOME=$(/usr/libexec/java_home -v 21) mvn -o test -pl muse-server -am -Dtest='P1rKnowledgeEventsPublishFlywayMigrationIT#should_rejectNonTestDatabaseWhenQueryContainsSlashTestSuffix+should_rejectCredentialQueryParameters' -Dsurefire.failIfNoSpecifiedTests=false ``` 结果:exit 0,2 tests pass。 真实库准备: - 测试库 `muse_p1r7c_events_publish_test` 已确认/创建。 - `psql` 可连接目标库,输出判断为 `psql_target_db_connect=true`。 真实 Flyway `_test`: ```bash JAVA_HOME=$(/usr/libexec/java_home -v 21) mvn -o test -pl muse-server -am -Dtest=P1rKnowledgeEventsPublishFlywayMigrationIT -Dflyway.postgresql.transactional.lock=false -Dp1r.flyway.locations=filesystem:sql/muse -Dp1r.flyway.url=jdbc:postgresql://:5433/muse_p1r7c_events_publish_test -Dp1r.flyway.user= -Djava.net.useSystemProxies=false -DsocksProxyHost= -DsocksProxyPort= -Dhttp.proxyHost= -Dhttp.proxyPort= -Dhttps.proxyHost= -Dhttps.proxyPort= -Dsurefire.failIfNoSpecifiedTests=false ``` 结果:exit 0,4 tests pass,failures/errors/skipped 均为 0。P2 修复后新增真实负向 insert 约束探针已纳入全量 Flyway IT。 关键输出: ```text flyway_success=true migrations_executed=18 successful_migration_count=18 target_schema_version=18 flyway_latest=18:extend knowledge events publish outbox v18_table=muse_knowledge_event_publish_outbox ``` JDBC EOF 根因: ```text psql_target_db_connect=true socksProxyHost_initial=127.0.0.1 jdbc_default=false ... cause=java.io.EOFException:null socksProxyHost_cleared=null jdbc_no_proxy=true db=muse_p1r7c_events_publish_test ``` 结论:V18 SQL 已通过真实 PostgreSQL / Flyway 验收;早前 EOF 是 Java 全局 SOCKS/HTTP/HTTPS 代理属性影响 PostgreSQL JDBC 连接链路,不是 V18 SQL 失败。 P2 增强: - `singleLiteralCheck` 已从 substring 判断改为精确单表达式匹配,避免未来误接受 `event_type='notification' OR ...`。 - `P1rKnowledgeEventsPublishFlywayMigrationIT` 新增真实 PostgreSQL 负向 insert 探针,验证 event_type、notification_type、publish_status、target_owner_user_id check 会拒绝非法行。 - 纯函数 RED/GREEN:`should_rejectBroadSingleLiteralConstraintExpression` 先失败,修复后 1/1 pass。 - Worker RED/GREEN:`should_logWhenAcceptedTerminalUpdateIsSkippedByStaleClaim` 先失败,修复后 1/1 pass。 - 一次并行 Maven 验证因两个命令同时触碰 Knowledge `target`,出现 testCompile 找不到已存在类;串行重跑 worker 测试通过,判定为并发构建污染,不作为代码缺陷。 ### Reactor build 执行: ```bash JAVA_HOME=$(/usr/libexec/java_home -v 21) mvn -o clean install -DskipTests -Dspring-boot.repackage.skip=true ``` 结果:exit 0,`BUILD SUCCESS`,62/62 modules success。 ### Coverage scanner scanner 只在隔离副本运行。 最终干净隔离副本: ```text /tmp/p1r7c-final-coverage-scan.2HXo1Z ``` 执行: ```bash python3 muse-cloud/scripts/p1r-audit-api-coverage.py --check ``` 结果: ```text coverage_exit=0 ``` 真实 worktree 受保护 coverage JSON/Markdown diff 仍为空。 ## 推断 基于 focused tests、P1R mixed executable gates、V18 Flyway `_test`、reactor build、隔离 coverage scanner、protected diff 以及 Rawls/Boole fresh review,可以判断 P1R-7c Knowledge source owner propagation 的应用层链路已具备收口到 `needs_verification` 的证据。 由于本轮证据只覆盖 Knowledge source owner propagation 第一批 canonical source status / projection summary 链路,不能推断 Events / P1R-7 / Knowledge / Market 已完成,也不能推进 completed。 ## 假设 - `~/.config/muse-repo/infra.env` 是当前项目允许用于本地 P1R `_test` 数据库准备的配置来源。 - 后续提交将按实现与测试/文档分组,避免把状态推进、coverage 口径和真实实现混成一笔。 ## 风险与未完成 - P2 增强后 focused / mixed / Flyway / reactor / coverage / protected diff 已重跑,fresh review 已重新派发并双 PASS:Rawls correctness/spec PASS,Boole data-integrity/testing PASS。 - fresh implementation review 历史:Sagan correctness PASS,Dalton testing evidence PASS,Halley data integrity FAIL。 - Halley 的 P1 已验证并修复:outbox claim 后终态回写原先缺少本次 claim 所有权保护,过期 worker 可能覆盖新 claim 终态;已先写 RED 测试 `should_guardTerminalStatusUpdatesWithClaimAttemptOwnership`,再把 `markPublished/markRetryable/markDeadLetter` 补为 `publish_status='running' AND attempt_count=#{claimedAttemptCount}`,并由 worker 传入 claim 返回的 `attemptCount`。 - 修复后 fresh review 第一轮:Kuhn correctness/spec PASS,Herschel data integrity PASS。Herschel 的两个 P2 已被纳入本轮增强,并已由 Rawls/Boole P2 后 fresh review 复核。 - Boole 非阻塞风险:V18 `ON CONFLICT DO NOTHING` 可能静默丢弃非法 duplicate source/owner 行,当前由 focused replay gate 覆盖第一批行为;worker 默认关闭,启用前仍需要运行配置与运维监控确认。 - 不得修改 OpenAPI、scanner、coverage report 来绕过缺口。 - 不得把 coverage `needs_verification` 改成 `completed`。 ## 下一步 1. 提交前复核 `git status --short --branch` 与 protected diff。 2. 按逻辑分组准备提交:实现一组,测试/规格/留痕一组。 3. 提交和 push 前仍不得推进 completed,不得修改 OpenAPI、scanner、coverage report。